VirtualBox

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

Last change on this file since 31042 was 31039, checked in by vboxsync, 15 years ago

Audio/HDA: size.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
1/* $Id: DevCodec.cpp 31039 2010-07-23 08:47:18Z vboxsync $ */
2/** @file
3 * DevCodec - VBox ICH Intel HD Audio Codec.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#define LOG_GROUP LOG_GROUP_DEV_AUDIO
18#include <VBox/pdmdev.h>
19#include <iprt/assert.h>
20#include <iprt/uuid.h>
21#include <iprt/string.h>
22#include <iprt/mem.h>
23#include <iprt/asm.h>
24
25#include "../Builtins.h"
26extern "C" {
27#include "audio.h"
28}
29#include "DevCodec.h"
30
31#define CODEC_CAD_MASK 0xF0000000
32#define CODEC_CAD_SHIFT 28
33#define CODEC_DIRECT_MASK RT_BIT(27)
34#define CODEC_NID_MASK 0x07F00000
35#define CODEC_NID_SHIFT 20
36#define CODEC_VERBDATA_MASK 0x000FFFFF
37#define CODEC_VERB_4BIT_CMD 0x000FFFF0
38#define CODEC_VERB_4BIT_DATA 0x0000000F
39#define CODEC_VERB_8BIT_CMD 0x000FFF00
40#define CODEC_VERB_8BIT_DATA 0x000000FF
41#define CODEC_VERB_16BIT_CMD 0x000F0000
42#define CODEC_VERB_16BIT_DATA 0x0000FFFF
43
44#define CODEC_CAD(cmd) ((cmd) & CODEC_CAD_MASK)
45#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK)
46#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT)
47#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK)
48#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x))
49#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4))
50#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8))
51#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16))
52
53#define CODEC_VERB_B_DIRECTION RT_BIT(15)
54#define CODEC_VERB_B_SIDE RT_BIT(13)
55#define CODEC_VERB_B_INDEX 0x7
56
57#define CODEC_B_DIRECTION(cmd) (((cmd) & CODEC_VERB_B_DIRECTION) >> 15)
58#define CODEC_B_SIDE(cmd) (((cmd) & CODEC_VERB_B_SIDE) >> 13)
59#define CODEC_B_INDEX(cmd) ((cmd) & CODEC_VERB_B_INDEX)
60
61#define CODEC_RESPONSE_UNSOLICITED RT_BIT_64(36)
62
63#define STAC9220_NODE_COUNT 0x1C
64
65#define STAC9220_IS_PORT_CMD(cmd) ( \
66 CODEC_NID(cmd) == 0xA \
67 || CODEC_NID(cmd) == 0xB \
68 || CODEC_NID(cmd) == 0xC \
69 || CODEC_NID(cmd) == 0xD \
70 || CODEC_NID(cmd) == 0xE \
71 || CODEC_NID(cmd) == 0xF \
72 )
73#define STAC9220_IS_DAC_CMD(cmd) ( \
74 CODEC_NID(cmd) == 0x2 \
75 || CODEC_NID(cmd) == 0x3 \
76 || CODEC_NID(cmd) == 0x4 \
77 || CODEC_NID(cmd) == 0x5)
78#define STAC9220_IS_ADCVOL_CMD(cmd) ( \
79 CODEC_NID(cmd) == 0x17 \
80 || CODEC_NID(cmd) == 0x18)
81#define STAC9220_IS_ADC_CMD(cmd) ( \
82 CODEC_NID(cmd) == 0x6 \
83 || CODEC_NID(cmd) == 0x7)
84#define STAC9220_IS_ADCMUX_CMD(cmd) ( \
85 CODEC_NID(cmd) == 0x12 \
86 || CODEC_NID(cmd) == 0x13)
87static int codecUnimplemented(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
88{
89 Log(("codecUnimplemented: cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
90 CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
91 if (CODEC_CAD(cmd) != 0)
92 *pResp = ((uint64_t)CODEC_CAD(cmd) << 4)| 0xFF;
93 else
94 *pResp = 0;
95 return VINF_SUCCESS;
96}
97
98static int codecBreak(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
99{
100 int rc;
101 rc = codecUnimplemented(pState, cmd, pResp);
102 *pResp |= CODEC_RESPONSE_UNSOLICITED;
103 return rc;
104}
105
106static int codecGetAmplifier(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
107{
108 Assert((CODEC_CAD(cmd) == 0));
109 PCODECNODE pNode = &pState->pNodes[CODEC_NID(cmd)];
110 if (STAC9220_IS_DAC_CMD(cmd))
111 *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
112 CODEC_B_DIRECTION(cmd),
113 CODEC_B_SIDE(cmd),
114 CODEC_B_INDEX(cmd));
115 else if (STAC9220_IS_ADCVOL_CMD(cmd))
116 *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
117 CODEC_B_DIRECTION(cmd),
118 CODEC_B_SIDE(cmd),
119 CODEC_B_INDEX(cmd));
120 else if (STAC9220_IS_ADCMUX_CMD(cmd))
121 *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
122 CODEC_B_DIRECTION(cmd),
123 CODEC_B_SIDE(cmd),
124 CODEC_B_INDEX(cmd));
125 else {
126 *pResp = 0;
127 AssertMsgReturn(0, ("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS);
128 }
129 return VINF_SUCCESS;
130}
131
132static int codecGetF00(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
133{
134 Assert((CODEC_CAD(cmd) == 0));
135 *pResp = pState->pNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
136 return VINF_SUCCESS;
137}
138static int stac9220GetPinCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
139{
140 if (STAC9220_IS_PORT_CMD(cmd))
141 {
142 *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F07_param;
143 }
144#if 0
145 else
146 AssertMsgFailed(("Unsupported"));
147#endif
148 return VINF_SUCCESS;
149}
150
151static int stac9220SetPinCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
152{
153 if (STAC9220_IS_PORT_CMD(cmd))
154 {
155 pState->pNodes[CODEC_NID(cmd)].port.u32F07_param &= ~CODEC_VERB_8BIT_DATA;
156 pState->pNodes[CODEC_NID(cmd)].port.u32F07_param |= cmd & CODEC_VERB_8BIT_DATA;
157 }
158 else
159 AssertMsgFailed(("Unsupported"));
160 *pResp = 0;
161 return VINF_SUCCESS;
162}
163static int codecGetF02(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
164{
165 Assert((CODEC_CAD(cmd) == 0));
166 *pResp = *(uint32_t *)&pState->pNodes[CODEC_NID(cmd)].node.au8F02_param[cmd & CODEC_VERB_8BIT_DATA];
167 return VINF_SUCCESS;
168}
169static int stac9220Set706(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
170{
171 Assert((CODEC_CAD(cmd) == 0));
172 if (STAC9220_IS_DAC_CMD(cmd))
173 {
174 pState->pNodes[CODEC_NID(cmd)].dac.u32F06_param &= ~CODEC_VERB_8BIT_DATA;
175 pState->pNodes[CODEC_NID(cmd)].dac.u32F06_param |= cmd & CODEC_VERB_8BIT_DATA;
176#if 0
177 if (cmd & ((0x5) << 4))
178 {
179 AUD_set_active_out()
180 }
181#endif
182 }
183 else if (STAC9220_IS_ADC_CMD(cmd))
184 {
185 pState->pNodes[CODEC_NID(cmd)].adc.u32F06_param &= ~CODEC_VERB_8BIT_DATA;
186 pState->pNodes[CODEC_NID(cmd)].adc.u32F06_param |= cmd & CODEC_VERB_8BIT_DATA;
187 }
188 else
189 AssertMsgFailed(("Unsupported"));
190 *pResp = 0;
191 return VINF_SUCCESS;
192}
193static int codecSetConverterFormat(struct CODECState *pState, uint32_t cmd, uint64_t *pResp)
194{
195 Assert((CODEC_CAD(cmd) == 0));
196 if (STAC9220_IS_DAC_CMD(cmd))
197 {
198 pState->pNodes[CODEC_NID(cmd)].dac.u32A_param &= ~CODEC_VERB_16BIT_DATA;
199 pState->pNodes[CODEC_NID(cmd)].dac.u32A_param |= cmd & CODEC_VERB_16BIT_DATA;
200 }
201 else if (STAC9220_IS_ADC_CMD(cmd))
202 {
203 pState->pNodes[CODEC_NID(cmd)].adc.u32A_param &= ~CODEC_VERB_16BIT_DATA;
204 pState->pNodes[CODEC_NID(cmd)].adc.u32A_param |= cmd & CODEC_VERB_16BIT_DATA;
205 }
206 else
207 AssertMsgFailed(("Unsupported"));
208 *pResp = 0;
209 return VINF_SUCCESS;
210}
211static int stac9220ResetNode(struct CODECState *pState, uint8_t nodenum, PCODECNODE pNode)
212{
213 pNode->node.id = nodenum;
214 switch (nodenum)
215 {
216 /* Root Node*/
217 case 0:
218 pNode->root.node.name = "Root";
219 //** @todo r=michaln: I fear the use of RT_MAKE_U32_FROM_U8() here makes the
220 // code much harder to read, not easier.
221 pNode->node.au32F00_param[0] = RT_MAKE_U32_FROM_U8(0x80, 0x76, 0x84, 0x83); /* VendorID = STAC9220/ DevId = 0x7680 */
222 pNode->node.au32F00_param[2] = RT_MAKE_U32_FROM_U8(0x1, 0x31, 0x10, 0x00); /* rev id */
223 pNode->node.au32F00_param[4] = RT_MAKE_U32_FROM_U8(0x1, 0x00, 0x01, 0x00); /* node info (start node: 1, start id = 1) */
224 break;
225 case 1:
226 pNode->afg.node.name = "AFG";
227 pNode->node.au32F00_param[4] = RT_MAKE_U32_FROM_U8(0x1a, 0x00, 0x02, 0x00);
228 pNode->node.au32F00_param[5] = RT_MAKE_U32_FROM_U8(0x1, 0x01, 0x00, 0x0);
229 pNode->node.au32F00_param[8] = RT_MAKE_U32_FROM_U8(0x0d, 0x0d, 0x01, 0x0); /* Capabilities */
230 //pNode->node.au32F00_param[0xa] = RT_BIT(19)|RT_BIT(18)|RT_BIT(17)|RT_BIT(10)|RT_BIT(9)|RT_BIT(8)|RT_BIT(7)|RT_BIT(6)|RT_BIT(5);
231 pNode->node.au32F00_param[0xa] = RT_BIT(17)|RT_BIT(5);
232 pNode->node.au32F00_param[0xb] = RT_BIT(0);
233 pNode->node.au32F00_param[0xd] = RT_BIT(31)|(0x5 << 16)|(0xE)<<8;
234 pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f;
235 pNode->afg.u32F05_param = RT_MAKE_U32_FROM_U8(0x02, 0x02, 0x00, 0x0); /* Power State */
236 pNode->afg.u32F08_param = 0;
237 break;
238 case 2:
239 pNode->dac.node.name = "DAC0";
240 goto dac_init;
241 case 3:
242 pNode->dac.node.name = "DAC1";
243 goto dac_init;
244 case 4:
245 pNode->dac.node.name = "DAC2";
246 goto dac_init;
247 case 5:
248 pNode->dac.node.name = "DAC3";
249 dac_init:
250 memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE);
251 pNode->dac.u32A_param = (0x3 << 4) | RT_BIT(0);
252
253 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
254 AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
255
256 pNode->dac.node.au32F00_param[9] = (0xd << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0);
257 pNode->dac.node.au32F00_param[5] = (0x3 << 4) | 0x3;
258 pNode->dac.u32F0c_param = 0;
259 break;
260 case 6:
261 pNode->adc.node.name = "ADC0";
262 pNode->node.au8F02_param[0] = 0x17;
263 goto adc_init;
264 case 7:
265 pNode->adc.node.name = "ADC1";
266 pNode->node.au8F02_param[0] = 0x18;
267 adc_init:
268 pNode->adc.u32A_param = (0x3<<4) | 0x1;
269 pNode->adc.node.au32F00_param[0xE] = RT_BIT(0);
270 pNode->adc.u32F03_param = RT_BIT(0);
271 pNode->adc.u32F05_param = (0x3 << 4) | 0x3;
272 pNode->adc.u32F06_param = 0;
273 pNode->adc.node.au32F00_param[9] = RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0);
274 break;
275 case 8:
276 pNode->spdifout.node.name = "SPDIFOut";
277 pNode->spdifout.u32A_param = (0x3<<4) | 0x1;
278 pNode->spdifout.node.au32F00_param[9] = (4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
279 //pNode->spdifout.node.au32F00_param[0xA] = RT_BIT(19)|RT_BIT(18)|RT_BIT(17)|RT_BIT(10)|RT_BIT(9)|RT_BIT(8)|RT_BIT(7)|RT_BIT(6);
280 pNode->node.au32F00_param[0xa] = RT_BIT(17)|RT_BIT(5);
281 pNode->spdifout.node.au32F00_param[0xB] = RT_BIT(2)|RT_BIT(0);
282 pNode->spdifout.u32F06_param = 0;
283 pNode->spdifout.u32F0d_param = 0;
284 break;
285 case 9:
286 pNode->node.name = "Reserved_0";
287 break;
288 case 0xA:
289 pNode->node.name = "PortA";
290 pNode->node.au32F00_param[0xC] = 0x173f;
291 *(uint32_t *)pNode->node.au8F02_param = 0x2;
292 pNode->port.u32F07_param = 0;
293 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02);
294 goto port_init;
295 case 0xB:
296 pNode->node.name = "PortB";
297 pNode->node.au32F00_param[0xC] = 0x1737;
298 *(uint32_t *)pNode->node.au8F02_param = 0x4;
299 pNode->port.u32F07_param = RT_BIT(5);
300 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01);
301 goto port_init;
302 case 0xC:
303 pNode->node.name = "PortC";
304 *(uint32_t *)pNode->node.au8F02_param = 0x3;
305 pNode->node.au32F00_param[0xC] = 0x1737;
306 pNode->port.u32F07_param = RT_BIT(5);
307 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01);
308 goto port_init;
309 case 0xD:
310 pNode->node.name = "PortD";
311 *(uint32_t *)pNode->node.au8F02_param = 0x2;
312 port_init:
313 pNode->port.u32F08_param = 0;
314 pNode->port.u32F09_param = 0x7fffffff;
315 pNode->node.au32F00_param[9] = (4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
316 pNode->node.au32F00_param[0xE] = 0x1;
317 break;
318 case 0xE:
319 pNode->node.name = "PortE";
320 pNode->node.au32F00_param[9] = (4 << 20)|RT_BIT(7)|RT_BIT(0);
321 pNode->port.u32F08_param = 0;
322 pNode->node.au32F00_param[0xC] = RT_BIT(5)|RT_BIT(2);
323 pNode->port.u32F07_param = RT_BIT(5);
324 pNode->port.u32F09_param = 0;
325 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x51, 0x30, 0x81, 0x01);
326 break;
327 case 0xF:
328 pNode->node.name = "PortF";
329 pNode->node.au32F00_param[9] = (4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
330 pNode->node.au32F00_param[0xC] = 0x37;
331 pNode->node.au32F00_param[0xE] = 0x1;
332 pNode->port.u32F08_param = 0;
333 pNode->port.u32F07_param = 0;
334 pNode->port.u32F1c_param = RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01);
335 pNode->node.au8F02_param[0] = 0x5;
336 pNode->port.u32F09_param = 0x7fffffff;
337 break;
338 case 0x10:
339 pNode->node.name = "DigOut_0";
340 pNode->node.au32F00_param[9] = RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
341 pNode->node.au32F00_param[0xC] = RT_BIT(4);
342 pNode->node.au32F00_param[0xE] = 0x3;
343 pNode->digout.u32F01_param = 0;
344 *(uint32_t *)pNode->node.au8F02_param = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0);
345 pNode->digout.u32F07_param = 0;
346 pNode->digout.u32F1c_param = RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
347 break;
348 case 0x11:
349 pNode->node.name = "DigIn_0";
350 pNode->node.au32F00_param[9] = (4 << 20)|(3<<16)|RT_BIT(10)|RT_BIT(9)|RT_BIT(7)|RT_BIT(0);
351 pNode->node.au32F00_param[0xC] = RT_BIT(16)|RT_BIT(5)|RT_BIT(2);
352 pNode->digin.u32F05_param = (3 << 4)|0x3;
353 pNode->digin.u32F07_param = 0;
354 pNode->digin.u32F08_param = 0;
355 pNode->digin.u32F09_param = 0;
356 pNode->digin.u32F0c_param = 0;
357 pNode->digin.u32F1c_param = RT_MAKE_U32_FROM_U8(0x60, 0x10, 0xc5, 0x1);
358 break;
359 case 0x12:
360 pNode->node.name = "ADCMux_0";
361 pNode->adcmux.u32F01_param = 0;
362 goto adcmux_init;
363 case 0x13:
364 pNode->node.name = "ADCMux_1";
365 pNode->adcmux.u32F01_param = 1;
366 adcmux_init:
367 pNode->node.au32F00_param[9] = (3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0);
368 pNode->node.au32F00_param[0xe] = 0x7;
369 pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8);
370 /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/
371 memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE);
372 *(uint32_t *)&pNode->node.au8F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb);
373 *(uint32_t *)&pNode->node.au8F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0);
374 break;
375 case 0x14:
376 pNode->node.name = "PCBEEP";
377 pNode->node.au32F00_param[9] = (7 << 20) | RT_BIT(3) | RT_BIT(2);
378 pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3;
379 pNode->pcbeep.u32F0a_param = 0;
380 memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
381 break;
382 case 0x15:
383 pNode->node.name = "CD";
384 pNode->node.au32F00_param[0x9] = (4 << 20)|RT_BIT(0);
385 pNode->node.au32F00_param[0xc] = RT_BIT(5);
386 pNode->cdnode.u32F07_param = 0;
387 pNode->cdnode.u32F1c_param = RT_MAKE_U32_FROM_U8(0x52, 0x0, 0x33, 0x90);
388 break;
389 case 0x16:
390 pNode->node.name = "VolumeKnob";
391 pNode->node.au32F00_param[0x9] = (0x6 << 20);
392 pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F;
393 pNode->node.au32F00_param[0xe] = 0x4;
394 *(uint32_t *)pNode->node.au8F02_param = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5);
395 pNode->volumeKnob.u32F08_param = 0;
396 pNode->volumeKnob.u32F0f_param = 0x7f;
397 break;
398 case 0x17:
399 pNode->node.name = "ADC0Vol";
400 *(uint32_t *)pNode->node.au8F02_param = 0x12;
401 goto adcvol_init;
402 case 0x18:
403 pNode->node.name = "ADC1Vol";
404 *(uint32_t *)pNode->node.au8F02_param = 0x13;
405 adcvol_init:
406 memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
407
408 pNode->node.au32F00_param[0x9] = (0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0);
409 pNode->node.au32F00_param[0xe] = 0x1;
410 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(1);
411 AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(1);
412 pNode->adcvol.u32F0c_param = 0;
413 default:
414 break;
415 }
416 return VINF_SUCCESS;
417}
418
419static CODECVERB STAC9220VERB[] =
420{
421/* verb | verb mask | callback */
422/* ----------- -------------------- ----------------------- */
423 {0x000F0000, CODEC_VERB_8BIT_CMD, codecGetF00},
424 {0x0007FF00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
425 {0x000FE700, CODEC_VERB_8BIT_CMD, codecUnimplemented},
426 {0x00070E70, CODEC_VERB_4BIT_CMD, codecUnimplemented},
427 {0x000F0500, CODEC_VERB_8BIT_CMD, codecUnimplemented},
428 {0x00070500, CODEC_VERB_8BIT_CMD, codecUnimplemented},
429 {0x000F0800, CODEC_VERB_8BIT_CMD, codecUnimplemented},
430 {0x00070800, CODEC_VERB_8BIT_CMD, codecUnimplemented},
431 {0x000F1500, CODEC_VERB_8BIT_CMD, codecUnimplemented},
432 {0x00071500, CODEC_VERB_8BIT_CMD, codecUnimplemented},
433 {0x000F1600, CODEC_VERB_8BIT_CMD, codecUnimplemented},
434 {0x00071600, CODEC_VERB_8BIT_CMD, codecUnimplemented},
435 {0x000F1700, CODEC_VERB_8BIT_CMD, codecUnimplemented},
436 {0x00071700, CODEC_VERB_8BIT_CMD, codecUnimplemented},
437 {0x000F1800, CODEC_VERB_8BIT_CMD, codecUnimplemented},
438 {0x00071800, CODEC_VERB_8BIT_CMD, codecUnimplemented},
439 {0x000F1900, CODEC_VERB_8BIT_CMD, codecUnimplemented},
440 {0x00071900, CODEC_VERB_8BIT_CMD, codecUnimplemented},
441 {0x000F1A00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
442 {0x00071A00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
443 {0x000F2000, CODEC_VERB_8BIT_CMD, codecUnimplemented},
444 {0x00072000, CODEC_VERB_8BIT_CMD, codecUnimplemented},
445 {0x00072100, CODEC_VERB_8BIT_CMD, codecUnimplemented},
446 {0x00072200, CODEC_VERB_8BIT_CMD, codecUnimplemented},
447 {0x00072300, CODEC_VERB_8BIT_CMD, codecUnimplemented},
448 {0x000A0000, CODEC_VERB_16BIT_CMD, codecUnimplemented},
449 {0x00020000, CODEC_VERB_16BIT_CMD, codecSetConverterFormat},
450 {0x000B0000, CODEC_VERB_16BIT_CMD, codecGetAmplifier },
451 {0x00030000, CODEC_VERB_16BIT_CMD, codecUnimplemented},
452 {0x000F0600, CODEC_VERB_8BIT_CMD, codecUnimplemented},
453 {0x00070600, CODEC_VERB_8BIT_CMD, stac9220Set706 },
454 {0x000F0C00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
455 {0x00070C00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
456 {0x000F0300, CODEC_VERB_8BIT_CMD, codecUnimplemented},
457 {0x00070300, CODEC_VERB_8BIT_CMD, codecUnimplemented},
458 {0x000F0D00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
459 {0x00070D00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
460 {0x00070E00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
461 {0x000F0700, CODEC_VERB_8BIT_CMD, stac9220SetPinCtrl},
462 {0x00070700, CODEC_VERB_8BIT_CMD, stac9220GetPinCtrl},
463 {0x000F0200, CODEC_VERB_8BIT_CMD, codecGetF02 },
464 {0x000F0900, CODEC_VERB_8BIT_CMD, codecUnimplemented},
465 {0x00070900, CODEC_VERB_8BIT_CMD, codecUnimplemented},
466 {0x000F1C00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
467 {0x00071C00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
468 {0x00071D00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
469 {0x00071E00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
470 {0x00071F00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
471 {0x000F0100, CODEC_VERB_8BIT_CMD, codecUnimplemented},
472 {0x00070100, CODEC_VERB_8BIT_CMD, codecUnimplemented},
473 {0x000F0A00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
474 {0x00070A00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
475 {0x000F0F00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
476 {0x00070F00, CODEC_VERB_8BIT_CMD, codecUnimplemented},
477 {0x0007E700, CODEC_VERB_8BIT_CMD, codecUnimplemented},
478};
479
480static int codecLookup(CODECState *pState, uint32_t cmd, PPFNCODECVERBPROCESSOR pfn)
481{
482 int rc = VERR_NOT_FOUND;
483 if ( CODEC_CAD(cmd) != 0
484 || CODEC_VERBDATA(cmd) == 0)
485 {
486 *pfn = CODEC_CAD(cmd) != 0 ? codecUnimplemented : codecBreak;
487 LogRel(("intelHD: cmd %x was ignored\n", cmd));
488 return VINF_SUCCESS;
489 }
490 for (int i = 0; i < pState->cVerbs; ++i)
491 {
492 if ((CODEC_VERBDATA(cmd) & pState->pVerbs[i].mask) == pState->pVerbs[i].verb)
493 {
494 *pfn = pState->pVerbs[i].pfn;
495 return VINF_SUCCESS;
496 }
497 }
498 LogRel(("intelHD: callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
499 return rc;
500}
501#define CODEC_FMT_BASE_FRQ_SHIFT (14)
502#define CODEC_FMT_BASE_FRQ_MASK (RT_BIT(CODEC_FMT_BASE_FRQ_SHIFT))
503#define CODEC_FMT_DIV_FRQ_SHIFT 8
504#define CODEC_FMT_DIV_FRQ_MASK ((0x7) << CODEC_FMT_DIV_FRQ_SHIFT)
505#define CODEC_FMT_MUL_FRQ_SHIFT 11
506#define CODEC_FMT_MUL_FRQ_MASK ((0x7) << CODEC_FMT_MUL_FRQ_SHIFT)
507#define CODEC_FMT_BASE_FRQ(fmt) ((fmt & CODEC_FMT_BASE_FRQ_MASK) >> CODEC_FMT_BASE_FRQ_SHIFT)
508#define CODEC_FMT_DIV_FRQ(fmt) ((fmt & CODEC_FMT_DIV_FRQ_MASK) >> CODEC_FMT_DIV_FRQ_SHIFT)
509#define CODEC_FMT_MUL_FRQ(fmt) ((fmt & CODEC_FMT_MUL_FRQ_MASK) >> CODEC_FMT_MUL_FRQ_SHIFT)
510#define CODEC_DAC_CHANELS(reg) (1 << ((reg) & 0x3))
511static int codecFrequencyCalculate(uint32_t dacFmt)
512{
513 uint32_t baseFrq = CODEC_FMT_BASE_FRQ(dacFmt);
514 uint32_t divFrq = CODEC_FMT_DIV_FRQ(dacFmt);
515 uint32_t multFrq = CODEC_FMT_MUL_FRQ(dacFmt);
516 switch (baseFrq)
517 {
518 case 0: baseFrq = 48000; break;
519 case 0x1: baseFrq = 44100; break;
520 default:
521 AssertMsgFailed(("Unsupported Freq."));
522 }
523 switch(multFrq)
524 {
525 case 0: multFrq = 1; break;
526 case 0x1: multFrq = 2; break;
527 case 0x3: multFrq = 4; break;
528 default:
529 AssertMsgFailed(("Unsupported Freq. multiplier"));
530 }
531 switch(divFrq)
532 {
533 case 0: divFrq = 1; break;
534 case 0x1: divFrq = 2; break;
535 case 0x2: divFrq = 3; break;
536 case 0x3: divFrq = 4; break;
537 case 0x4: divFrq = 5; break;
538 case 0x5: divFrq = 6; break;
539 case 0x6: divFrq = 7; break;
540 case 0x7: divFrq = 8; break;
541 }
542 return baseFrq * multFrq / divFrq;
543}
544static int codec_dac_to_aud(CODECState *pState, int dacnum, audsettings_t *paud)
545{
546 uint32_t dacfmt = pState->pNodes[dacnum].dac.u32A_param;
547 paud->freq = 44100;//codecFrequencyCalculate(dacfmt);
548 paud->nchannels = 2;//CODEC_DAC_CHANELS(dacfmt);
549 paud->fmt = AUD_FMT_U16;
550
551 paud->endianness = 0;
552 return VINF_SUCCESS;
553}
554
555static void pi_callback (void *opaque, int avail)
556{
557 CODECState *pState = (CODECState *)opaque;
558 pState->pfnTransfer(pState, PI_INDEX, avail);
559}
560
561static void po_callback (void *opaque, int avail)
562{
563 CODECState *pState = (CODECState *)opaque;
564 pState->pfnTransfer(pState, PO_INDEX, avail);
565}
566
567static void mc_callback (void *opaque, int avail)
568{
569 CODECState *pState = (CODECState *)opaque;
570 pState->pfnTransfer(pState, MC_INDEX, avail);
571}
572#define STAC9220_DAC_PI (0x2)
573#define STAC9220_DAC_MC (0x3)
574#define STAC9220_DAC_PO (0x4)
575int stac9220Construct(CODECState *pState)
576{
577 audsettings_t as;
578 pState->pVerbs = (CODECVERB *)&STAC9220VERB;
579 pState->cVerbs = sizeof(STAC9220VERB)/sizeof(CODECVERB);
580 pState->pfnLookup = codecLookup;
581 pState->pNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * STAC9220_NODE_COUNT);
582 uint8_t i;
583 for (i = 0; i < STAC9220_NODE_COUNT; ++i)
584 {
585 stac9220ResetNode(pState, i, &pState->pNodes[i]);
586 }
587 AUD_register_card ("ICH0", &pState->card);
588
589
590 codec_dac_to_aud(pState, STAC9220_DAC_PI, &as);
591 pState->voice_pi = AUD_open_in(&pState->card, pState->voice_pi, "hda.in", pState, pi_callback, &as);
592 codec_dac_to_aud(pState, STAC9220_DAC_PO, &as);
593 pState->voice_po = AUD_open_out(&pState->card, pState->voice_po, "hda.out", pState, po_callback, &as);
594 codec_dac_to_aud(pState, STAC9220_DAC_MC, &as);
595 pState->voice_mc = AUD_open_in(&pState->card, pState->voice_mc, "hda.mc", pState, mc_callback, &as);
596 if (!pState->voice_pi)
597 LogRel (("intelHD: WARNING: Unable to open PCM IN!\n"));
598 if (!pState->voice_mc)
599 LogRel (("intelHD: WARNING: Unable to open PCM MC!\n"));
600 if (!pState->voice_po)
601 LogRel (("intelHD: WARNING: Unable to open PCM OUT!\n"));
602 int mute = 0;
603 uint8_t lvol = 0x7f;
604 uint8_t rvol = 0x7f;
605 AUD_set_volume_out(pState->voice_po, mute, lvol, rvol);
606 return VINF_SUCCESS;
607}
608int stac9220Destruct(CODECState *pCodecState)
609{
610 RTMemFree(pCodecState->pNodes);
611 return VINF_SUCCESS;
612}
Note: See TracBrowser for help on using the repository browser.

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