diff options
Diffstat (limited to 'src/VBox/Devices/Audio')
23 files changed, 6569 insertions, 5996 deletions
diff --git a/src/VBox/Devices/Audio/DevCodec.cpp b/src/VBox/Devices/Audio/DevCodec.cpp deleted file mode 100644 index c17fbc54..00000000 --- a/src/VBox/Devices/Audio/DevCodec.cpp +++ /dev/null @@ -1,1985 +0,0 @@ -/* $Id: DevCodec.cpp $ */ -/** @file - * DevCodec - VBox ICH Intel HD Audio Codec. - */ - -/* - * Copyright (C) 2006-2011 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#define LOG_GROUP LOG_GROUP_DEV_AUDIO -#include <VBox/vmm/pdmdev.h> -#include <iprt/assert.h> -#include <iprt/uuid.h> -#include <iprt/string.h> -#include <iprt/mem.h> -#include <iprt/asm.h> -#include <iprt/cpp/utils.h> - -#include "VBoxDD.h" -extern "C" { -#include "audio.h" -} -#include "DevCodec.h" - - -/******************************************************************************* -* Structures and Typedefs * -*******************************************************************************/ -#define CODECNODE_F0_PARAM_LENGTH 0x14 -#define CODECNODE_F02_PARAM_LENGTH 16 - -typedef struct CODECCOMMONNODE -{ - uint8_t id; /* 7 - bit format */ - /** The node name. */ - char const *pszName; - /* RPM 5.3.6 */ - uint32_t au32F00_param[CODECNODE_F0_PARAM_LENGTH]; - uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH]; -} CODECCOMMONNODE, *PCODECCOMMONNODE; -AssertCompile(CODECNODE_F0_PARAM_LENGTH == 20); /* saved state */ -AssertCompile(CODECNODE_F02_PARAM_LENGTH == 16); /* saved state */ - -#define AssertNodeSize(a_Node, a_cParams) \ - AssertCompile((a_cParams) <= (60 + 6)); /* the max size - saved state */ \ - AssertCompile(sizeof(a_Node) - sizeof(CODECCOMMONNODE) == (((a_cParams) * sizeof(uint32_t) + sizeof(void *) - 1) & ~(sizeof(void *) - 1))) - -typedef struct ROOTCODECNODE -{ - CODECCOMMONNODE node; -} ROOTCODECNODE, *PROOTCODECNODE; -AssertNodeSize(ROOTCODECNODE, 0); - -#define AMPLIFIER_SIZE 60 -typedef uint32_t AMPLIFIER[AMPLIFIER_SIZE]; -#define AMPLIFIER_IN 0 -#define AMPLIFIER_OUT 1 -#define AMPLIFIER_LEFT 1 -#define AMPLIFIER_RIGHT 0 -#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)]) -typedef struct DACNODE -{ - CODECCOMMONNODE node; - uint32_t u32F0d_param; - uint32_t u32F04_param; - uint32_t u32F05_param; - uint32_t u32F06_param; - uint32_t u32F0c_param; - - uint32_t u32A_param; - AMPLIFIER B_params; - -} DACNODE, *PDACNODE; -AssertNodeSize(DACNODE, 6 + 60); - -typedef struct ADCNODE -{ - CODECCOMMONNODE node; - uint32_t u32F03_param; - uint32_t u32F05_param; - uint32_t u32F06_param; - uint32_t u32F09_param; - - uint32_t u32A_param; - uint32_t u32F01_param; - AMPLIFIER B_params; -} ADCNODE, *PADCNODE; -AssertNodeSize(DACNODE, 6 + 60); - -typedef struct SPDIFOUTNODE -{ - CODECCOMMONNODE node; - uint32_t u32F05_param; - uint32_t u32F06_param; - uint32_t u32F09_param; - uint32_t u32F0d_param; - - uint32_t u32A_param; - AMPLIFIER B_params; -} SPDIFOUTNODE, *PSPDIFOUTNODE; -AssertNodeSize(SPDIFOUTNODE, 5 + 60); - -typedef struct SPDIFINNODE -{ - CODECCOMMONNODE node; - uint32_t u32F05_param; - uint32_t u32F06_param; - uint32_t u32F09_param; - uint32_t u32F0d_param; - - uint32_t u32A_param; - AMPLIFIER B_params; -} SPDIFINNODE, *PSPDIFINNODE; -AssertNodeSize(SPDIFINNODE, 5 + 60); - -typedef struct AFGCODECNODE -{ - CODECCOMMONNODE node; - uint32_t u32F05_param; - uint32_t u32F08_param; - uint32_t u32F20_param; - uint32_t u32F17_param; -} AFGCODECNODE, *PAFGCODECNODE; -AssertNodeSize(AFGCODECNODE, 4); - -typedef struct PORTNODE -{ - CODECCOMMONNODE node; - uint32_t u32F07_param; - uint32_t u32F08_param; - uint32_t u32F09_param; - uint32_t u32F01_param; - uint32_t u32F1c_param; - AMPLIFIER B_params; -} PORTNODE, *PPORTNODE; -AssertNodeSize(PORTNODE, 5 + 60); - -typedef struct DIGOUTNODE -{ - CODECCOMMONNODE node; - uint32_t u32F01_param; - uint32_t u32F08_param; - uint32_t u32F07_param; - uint32_t u32F09_param; - uint32_t u32F1c_param; -} DIGOUTNODE, *PDIGOUTNODE; -AssertNodeSize(DIGOUTNODE, 5); - -typedef struct DIGINNODE -{ - CODECCOMMONNODE node; - uint32_t u32F05_param; - uint32_t u32F07_param; - uint32_t u32F08_param; - uint32_t u32F09_param; - uint32_t u32F0c_param; - uint32_t u32F1c_param; - uint32_t u32F1e_param; -} DIGINNODE, *PDIGINNODE; -AssertNodeSize(DIGINNODE, 7); - -typedef struct ADCMUXNODE -{ - CODECCOMMONNODE node; - uint32_t u32F01_param; - - uint32_t u32A_param; - AMPLIFIER B_params; -} ADCMUXNODE, *PADCMUXNODE; -AssertNodeSize(ADCMUXNODE, 2 + 60); - -typedef struct PCBEEPNODE -{ - CODECCOMMONNODE node; - uint32_t u32F07_param; - uint32_t u32F0a_param; - - uint32_t u32A_param; - AMPLIFIER B_params; - uint32_t u32F1c_param; -} PCBEEPNODE, *PPCBEEPNODE; -AssertNodeSize(PCBEEPNODE, 3 + 60 + 1); - -typedef struct CDNODE -{ - CODECCOMMONNODE node; - uint32_t u32F07_param; - uint32_t u32F1c_param; -} CDNODE, *PCDNODE; -AssertNodeSize(CDNODE, 2); - -typedef struct VOLUMEKNOBNODE -{ - CODECCOMMONNODE node; - uint32_t u32F08_param; - uint32_t u32F0f_param; -} VOLUMEKNOBNODE, *PVOLUMEKNOBNODE; -AssertNodeSize(VOLUMEKNOBNODE, 2); - -typedef struct ADCVOLNODE -{ - CODECCOMMONNODE node; - uint32_t u32F0c_param; - uint32_t u32F01_param; - uint32_t u32A_params; - AMPLIFIER B_params; -} ADCVOLNODE, *PADCVOLNODE; -AssertNodeSize(ADCVOLNODE, 3 + 60); - -typedef struct RESNODE -{ - CODECCOMMONNODE node; - uint32_t u32F05_param; - uint32_t u32F06_param; - uint32_t u32F07_param; - uint32_t u32F1c_param; -} RESNODE, *PRESNODE; -AssertNodeSize(RESNODE, 4); - -/** - * Used for the saved state. - */ -typedef struct CODECSAVEDSTATENODE -{ - CODECCOMMONNODE Core; - uint32_t au32Params[60 + 6]; -} CODECSAVEDSTATENODE; -AssertNodeSize(CODECSAVEDSTATENODE, 60 + 6); - -typedef union CODECNODE -{ - CODECCOMMONNODE node; - ROOTCODECNODE root; - AFGCODECNODE afg; - DACNODE dac; - ADCNODE adc; - SPDIFOUTNODE spdifout; - SPDIFINNODE spdifin; - PORTNODE port; - DIGOUTNODE digout; - DIGINNODE digin; - ADCMUXNODE adcmux; - PCBEEPNODE pcbeep; - CDNODE cdnode; - VOLUMEKNOBNODE volumeKnob; - ADCVOLNODE adcvol; - RESNODE reserved; - CODECSAVEDSTATENODE SavedState; -} CODECNODE, *PCODECNODE; -AssertNodeSize(CODECNODE, 60 + 6); - - -/******************************************************************************* -* Global Variables * -*******************************************************************************/ -/* STAC9220 - Referenced thru STAC9220WIDGET in the constructor below. */ -static uint8_t const g_abStac9220Ports[] = { 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}; -static uint8_t const g_abStac9220Dacs[] = { 0x2, 0x3, 0x4, 0x5, 0}; -static uint8_t const g_abStac9220Adcs[] = { 0x6, 0x7, 0}; -static uint8_t const g_abStac9220SpdifOuts[] = { 0x8, 0 }; -static uint8_t const g_abStac9220SpdifIns[] = { 0x9, 0 }; -static uint8_t const g_abStac9220DigOutPins[] = { 0x10, 0 }; -static uint8_t const g_abStac9220DigInPins[] = { 0x11, 0 }; -static uint8_t const g_abStac9220AdcVols[] = { 0x17, 0x18, 0}; -static uint8_t const g_abStac9220AdcMuxs[] = { 0x12, 0x13, 0}; -static uint8_t const g_abStac9220Pcbeeps[] = { 0x14, 0 }; -static uint8_t const g_abStac9220Cds[] = { 0x15, 0 }; -static uint8_t const g_abStac9220VolKnobs[] = { 0x16, 0 }; -static uint8_t const g_abStac9220Reserveds[] = { 0x9, 0x19, 0x1a, 0x1b, 0 }; - - -/** SSM description of a CODECNODE. */ -static SSMFIELD const g_aCodecNodeFields[] = -{ - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id), - SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3), - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param), - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param), - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params), - SSMFIELD_ENTRY_TERM() -}; - -/** Backward compatibility with v1 of the CODECNODE. */ -static SSMFIELD const g_aCodecNodeFieldsV1[] = -{ - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id), - SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7), - SSMFIELD_ENTRY_OLD_HCPTR(Core.name), - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param), - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param), - SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params), - SSMFIELD_ENTRY_TERM() -}; - - -/******************************************************************************* -* Internal Functions * -*******************************************************************************/ -static int stac9220ResetNode(struct CODECState *pState, uint8_t nodenum, PCODECNODE pNode); - - - -static int stac9220Construct(CODECState *pState) -{ - unconst(pState->cTotalNodes) = 0x1C; - pState->pfnCodecNodeReset = stac9220ResetNode; - pState->u16VendorId = 0x8384; - pState->u16DeviceId = 0x7680; - pState->u8BSKU = 0x76; - pState->u8AssemblyId = 0x80; - pState->pNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pState->cTotalNodes); - pState->fInReset = false; -#define STAC9220WIDGET(type) pState->au8##type##s = g_abStac9220##type##s - STAC9220WIDGET(Port); - STAC9220WIDGET(Dac); - STAC9220WIDGET(Adc); - STAC9220WIDGET(AdcVol); - STAC9220WIDGET(AdcMux); - STAC9220WIDGET(Pcbeep); - STAC9220WIDGET(SpdifIn); - STAC9220WIDGET(SpdifOut); - STAC9220WIDGET(DigInPin); - STAC9220WIDGET(DigOutPin); - STAC9220WIDGET(Cd); - STAC9220WIDGET(VolKnob); - STAC9220WIDGET(Reserved); -#undef STAC9220WIDGET - unconst(pState->u8AdcVolsLineIn) = 0x17; - unconst(pState->u8DacLineOut) = 0x2; - - return VINF_SUCCESS; -} - -static int stac9220ResetNode(struct CODECState *pState, uint8_t nodenum, PCODECNODE pNode) -{ - pNode->node.id = nodenum; - pNode->node.au32F00_param[0xF] = 0; /* Power statest Supported: are the same as AFG reports */ - switch (nodenum) - { - /* Root Node*/ - case 0: - pNode->node.au32F00_param[2] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */ - break; - case 1: - pNode->node.au32F00_param[8] = CODEC_MAKE_F00_08(1, 0xd, 0xd); - pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) - | CODEC_F00_0C_CAP_BALANCED_IO - | CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT - | CODEC_F00_0C_CAP_TRIGGER_REQUIRED - | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//(17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0); - pNode->node.au32F00_param[0xB] = CODEC_F00_0B_PCM; - pNode->node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(1, 0x5, 0xE, 0);//RT_BIT(31)|(0x5 << 16)|(0xE)<<8; - pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f; - pNode->node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);//0xc0000004; - pNode->node.au32F00_param[0xF] = CODEC_F00_0F_D3|CODEC_F00_0F_D2|CODEC_F00_0F_D1|CODEC_F00_0F_D0; - 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 */ - pNode->afg.u32F08_param = 0; - pNode->afg.u32F17_param = 0; - break; - case 2: - case 3: - case 4: - case 5: - memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE); - 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; /* 441000Hz/16bit/2ch */ - - AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7); - AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7); - - pNode->dac.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0xD, 0) - | CODEC_F00_09_CAP_L_R_SWAP - | CODEC_F00_09_CAP_POWER_CTRL - | CODEC_F00_09_CAP_OUT_AMP_PRESENT - | CODEC_F00_09_CAP_LSB;//(0xD << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0); - pNode->dac.u32F0c_param = 0; - pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3 */ - break; - case 6: - pNode->node.au32F02_param[0] = 0x17; - goto adc_init; - case 7: - pNode->node.au32F02_param[0] = 0x18; - adc_init: - 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; /* 441000Hz/16bit/2ch */ - pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0); - pNode->adc.u32F03_param = RT_BIT(0); - pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */ - pNode->adc.u32F06_param = 0; - pNode->adc.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0) - | CODEC_F00_09_CAP_POWER_CTRL - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_PROC_WIDGET - | CODEC_F00_09_CAP_LSB;//RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0); - break; - case 8: - 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; - pNode->spdifout.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x4, 0) - | CODEC_F00_09_CAP_DIGITAL - | CODEC_F00_09_CAP_FMT_OVERRIDE - | CODEC_F00_09_CAP_LSB;//(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1; - pNode->node.au32F00_param[0xa] = pState->pNodes[1].node.au32F00_param[0xA]; - pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM; - pNode->spdifout.u32F06_param = 0; - pNode->spdifout.u32F0d_param = 0; - break; - case 9: - 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; - pNode->spdifin.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0x4, 0) - | CODEC_F00_09_CAP_DIGITAL - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_FMT_OVERRIDE - | CODEC_F00_09_CAP_LSB;//(0x1 << 20)|(4 << 16) | RT_BIT(9)| RT_BIT(8)|RT_BIT(4)|0x1; - pNode->node.au32F00_param[0xA] = pState->pNodes[1].node.au32F00_param[0xA]; - pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0); - pNode->node.au32F02_param[0] = 0x11; - pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM; - pNode->spdifin.u32F06_param = 0; - pNode->spdifin.u32F0d_param = 0; - break; - case 0xA: - pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) - | CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_OUTPUT - | CODEC_F00_0C_CAP_HP - | CODEC_F00_0C_CAP_PRESENSE_DETECT - | CODEC_F00_0C_CAP_TRIGGER_REQUIRED - | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x173f; - pNode->node.au32F02_param[0] = 0x2; - pNode->port.u32F07_param = CODEC_F07_IN_ENABLE - | CODEC_F07_OUT_ENABLE; - pNode->port.u32F08_param = 0; - if (!pState->fInReset) - pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_FRONT, - CODEC_F1C_DEVICE_HP, - CODEC_F1C_CONNECTION_TYPE_1_8INCHES, - CODEC_F1C_COLOR_GREEN, - CODEC_F1C_MISC_JACK_DETECT, - 0x2, 0);//RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02); - goto port_init; - case 0xB: - pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) - | CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_OUTPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT - | CODEC_F00_0C_CAP_TRIGGER_REQUIRED - | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737; - pNode->node.au32F02_param[0] = 0x4; - pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; - if (!pState->fInReset) - pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR, - CODEC_F1C_DEVICE_SPEAKER, - CODEC_F1C_CONNECTION_TYPE_1_8INCHES, - CODEC_F1C_COLOR_BLACK, - CODEC_F1C_MISC_JACK_DETECT, - 0x1, 0x1);//RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01); - goto port_init; - case 0xC: - pNode->node.au32F02_param[0] = 0x3; - pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) - | CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_OUTPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT - | CODEC_F00_0C_CAP_TRIGGER_REQUIRED - | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737; - pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; - if (!pState->fInReset) - pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_REAR, - CODEC_F1C_DEVICE_SPEAKER, - CODEC_F1C_CONNECTION_TYPE_1_8INCHES, - CODEC_F1C_COLOR_GREEN, - 0x0, 0x1, 0x0);//RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01); - goto port_init; - case 0xD: - pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) - | CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_OUTPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT - | CODEC_F00_0C_CAP_TRIGGER_REQUIRED - | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737; - pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; - pNode->node.au32F02_param[0] = 0x2; - if (!pState->fInReset) - pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_FRONT, - CODEC_F1C_DEVICE_MIC, - CODEC_F1C_CONNECTION_TYPE_1_8INCHES, - CODEC_F1C_COLOR_PINK, - 0x0, 0x5, 0x0);//RT_MAKE_U32_FROM_U8(0x50, 0x90, 0xA1, 0x02); /* Microphone */ - port_init: - pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff; - pNode->port.u32F08_param = 0; - pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0) - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_UNSOL - | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0); - pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1; - break; - case 0xE: - pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0) - | CODEC_F00_09_CAP_UNSOL - | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(7)|RT_BIT(0); - pNode->port.u32F08_param = 0; - pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_OUTPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT;//0x34; - pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; - pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff; - if (!pState->fInReset) - pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_REAR, - CODEC_F1C_DEVICE_LINE_OUT, - CODEC_F1C_CONNECTION_TYPE_1_8INCHES, - CODEC_F1C_COLOR_BLUE, - 0x0, 0x4, 0x0);//0x01013040; /* Line Out */ - break; - case 0xF: - pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0) - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_UNSOL - | CODEC_F00_09_CAP_OUT_AMP_PRESENT - | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(2)|RT_BIT(0); - pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_OUTPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT - /* | CODEC_F00_0C_CAP_TRIGGER_REQUIRED - | CODEC_F00_0C_CAP_IMPENDANCE_SENSE */;//0x37; - pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1; - pNode->port.u32F08_param = 0; - pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE - | CODEC_F07_IN_ENABLE; - if (!pState->fInReset) - pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_INTERNAL, - CODEC_F1C_DEVICE_SPEAKER, - CODEC_F1C_CONNECTION_TYPE_1_8INCHES, - CODEC_F1C_COLOR_ORANGE, - 0x0, 0x1, 0x2);//RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01); - pNode->node.au32F02_param[0] = 0x5; - pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff; - break; - case 0x10: - pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0) - | CODEC_F00_09_CAP_DIGITAL - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_LSB;//(4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0); - pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//RT_BIT(4); - pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x3); - pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0); - if (!pState->fInReset) - pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_REAR, - CODEC_F1C_DEVICE_SPDIF_OUT, - CODEC_F1C_CONNECTION_TYPE_DIN, - CODEC_F1C_COLOR_BLACK, - 0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01); - break; - case 0x11: - pNode->node.au32F00_param[9] = (4 << 20)|(3<<16)|RT_BIT(10)|RT_BIT(9)|RT_BIT(7)|RT_BIT(0); - pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD - | CODEC_F00_0C_CAP_INPUT - | CODEC_F00_0C_CAP_PRESENSE_DETECT;//RT_BIT(16)| RT_BIT(5)|RT_BIT(2); - pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */ - pNode->digin.u32F07_param = 0; - pNode->digin.u32F08_param = 0; - pNode->digin.u32F09_param = 0; - pNode->digin.u32F0c_param = 0; - if (!pState->fInReset) - pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, - CODEC_F1C_LOCATION_REAR, - CODEC_F1C_DEVICE_SPDIF_IN, - CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL, - CODEC_F1C_COLOR_BLACK, - 0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60; - break; - case 0x12: - pNode->adcmux.u32F01_param = 0; - goto adcmux_init; - case 0x13: - pNode->adcmux.u32F01_param = 1; - adcmux_init: - pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0x0, 0) - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE - | CODEC_F00_09_CAP_OUT_AMP_PRESENT - | CODEC_F00_09_CAP_LSB;//(3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0); - pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x7); - pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8); - /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/ - memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE); - pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb); - pNode->node.au32F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0); - break; - case 0x14: - pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0) - | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE - | CODEC_F00_09_CAP_OUT_AMP_PRESENT;//(7 << 20) | RT_BIT(3) | RT_BIT(2); - pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3; - pNode->pcbeep.u32F0a_param = 0; - memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE); - break; - case 0x15: - pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0) - | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(0); - pNode->node.au32F00_param[0xc] = CODEC_F00_0C_CAP_INPUT;//RT_BIT(5); - if (!pState->fInReset) - pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED, - CODEC_F1C_LOCATION_INTERNAL, - CODEC_F1C_DEVICE_CD, - CODEC_F1C_CONNECTION_TYPE_ATAPI, - CODEC_F1C_COLOR_UNKNOWN, - 0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90); - break; - case 0x16: - pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0x0, 0x0);//(0x6 << 20); - pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F; - pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x4); - pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5); - pNode->volumeKnob.u32F08_param = 0; - pNode->volumeKnob.u32F0f_param = 0x7f; - break; - case 0x17: - pNode->node.au32F02_param[0] = 0x12; - goto adcvol_init; - case 0x18: - pNode->node.au32F02_param[0] = 0x13; - adcvol_init: - memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE); - - pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0) - | CODEC_F00_09_CAP_L_R_SWAP - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_IN_AMP_PRESENT - | CODEC_F00_09_CAP_LSB;//(0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0); - pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x1); - AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7); - AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7); - pNode->adcvol.u32F0c_param = 0; - break; - case 0x19: - pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0) - | CODEC_F00_09_CAP_DIGITAL - | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0); - break; - case 0x1A: - pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0) - | CODEC_F00_09_CAP_DIGITAL - | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0); - break; - case 0x1B: - pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0) - | CODEC_F00_09_CAP_DIGITAL - | CODEC_F00_09_CAP_CONNECTION_LIST - | CODEC_F00_09_CAP_LSB;//(0x4 << 20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0); - pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x1); - pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//0x10; - pNode->node.au32F02_param[0] = 0x1a; - pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS, - CODEC_F1C_LOCATION_NA, - CODEC_F1C_DEVICE_LINE_OUT, - CODEC_F1C_CONNECTION_TYPE_UNKNOWN, - CODEC_F1C_COLOR_UNKNOWN, - 0x0, 0x0, 0xf);//0x4000000f; - break; - default: - break; - } - return VINF_SUCCESS; -} - -/* generic */ - -#define DECLISNODEOFTYPE(type) \ - static inline int codecIs##type##Node(struct CODECState *pState, uint8_t cNode) \ - { \ - Assert(pState->au8##type##s); \ - for(int i = 0; pState->au8##type##s[i] != 0; ++i) \ - if (pState->au8##type##s[i] == cNode) \ - return 1; \ - return 0; \ - } -/* codecIsPortNode */ -DECLISNODEOFTYPE(Port) -/* codecIsDacNode */ -DECLISNODEOFTYPE(Dac) -/* codecIsAdcVolNode */ -DECLISNODEOFTYPE(AdcVol) -/* codecIsAdcNode */ -DECLISNODEOFTYPE(Adc) -/* codecIsAdcMuxNode */ -DECLISNODEOFTYPE(AdcMux) -/* codecIsPcbeepNode */ -DECLISNODEOFTYPE(Pcbeep) -/* codecIsSpdifOutNode */ -DECLISNODEOFTYPE(SpdifOut) -/* codecIsSpdifInNode */ -DECLISNODEOFTYPE(SpdifIn) -/* codecIsDigInPinNode */ -DECLISNODEOFTYPE(DigInPin) -/* codecIsDigOutPinNode */ -DECLISNODEOFTYPE(DigOutPin) -/* codecIsCdNode */ -DECLISNODEOFTYPE(Cd) -/* codecIsVolKnobNode */ -DECLISNODEOFTYPE(VolKnob) -/* codecIsReservedNode */ -DECLISNODEOFTYPE(Reserved) - -static int codecToAudVolume(AMPLIFIER *pAmp, audmixerctl_t mt); - -static inline void codecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask) -{ - Assert((pu32Reg && u8Offset < 32)); - *pu32Reg &= ~(mask << u8Offset); - *pu32Reg |= (u32Cmd & mask) << u8Offset; -} -static inline void codecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset) -{ - codecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA); -} - -static inline void codecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset) -{ - codecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA); -} - - -static int codecUnimplemented(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Log(("codecUnimplemented: cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd, - CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd))); - *pResp = 0; - return VINF_SUCCESS; -} - -static int codecBreak(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - int rc; - rc = codecUnimplemented(pState, cmd, pResp); - *pResp |= CODEC_RESPONSE_UNSOLICITED; - return rc; -} -/* B-- */ -static int codecGetAmplifier(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - /* HDA spec 7.3.3.7 Note A */ - /* @todo: if index out of range response should be 0 */ - uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd); - - PCODECNODE pNode = &pState->pNodes[CODEC_NID(cmd)]; - if (codecIsDacNode(pState, CODEC_NID(cmd))) - *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params, - CODEC_GET_AMP_DIRECTION(cmd), - CODEC_GET_AMP_SIDE(cmd), - u8Index); - else if (codecIsAdcVolNode(pState, CODEC_NID(cmd))) - *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params, - CODEC_GET_AMP_DIRECTION(cmd), - CODEC_GET_AMP_SIDE(cmd), - u8Index); - else if (codecIsAdcMuxNode(pState, CODEC_NID(cmd))) - *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params, - CODEC_GET_AMP_DIRECTION(cmd), - CODEC_GET_AMP_SIDE(cmd), - u8Index); - else if (codecIsPcbeepNode(pState, CODEC_NID(cmd))) - *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params, - CODEC_GET_AMP_DIRECTION(cmd), - CODEC_GET_AMP_SIDE(cmd), - u8Index); - else if (codecIsPortNode(pState, CODEC_NID(cmd))) - *pResp = AMPLIFIER_REGISTER(pNode->port.B_params, - CODEC_GET_AMP_DIRECTION(cmd), - CODEC_GET_AMP_SIDE(cmd), - u8Index); - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params, - CODEC_GET_AMP_DIRECTION(cmd), - CODEC_GET_AMP_SIDE(cmd), - u8Index); - else{ - AssertMsgReturn(0, ("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS); - } - return VINF_SUCCESS; -} -/* 3-- */ -static int codecSetAmplifier(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - AMPLIFIER *pAmplifier = NULL; - bool fIsLeft = false; - bool fIsRight = false; - bool fIsOut = false; - bool fIsIn = false; - uint8_t u8Index = 0; - Assert((CODEC_CAD(cmd) == pState->id)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - PCODECNODE pNode = &pState->pNodes[CODEC_NID(cmd)]; - if (codecIsDacNode(pState, CODEC_NID(cmd))) - pAmplifier = &pNode->dac.B_params; - else if (codecIsAdcVolNode(pState, CODEC_NID(cmd))) - pAmplifier = &pNode->adcvol.B_params; - else if (codecIsAdcMuxNode(pState, CODEC_NID(cmd))) - pAmplifier = &pNode->adcmux.B_params; - else if (codecIsPcbeepNode(pState, CODEC_NID(cmd))) - pAmplifier = &pNode->pcbeep.B_params; - else if (codecIsPortNode(pState, CODEC_NID(cmd))) - pAmplifier = &pNode->port.B_params; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - pAmplifier = &pNode->adc.B_params; - Assert(pAmplifier); - if (pAmplifier) - { - fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd); - fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd); - fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd); - fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd); - u8Index = CODEC_SET_AMP_INDEX(cmd); - if ( (!fIsLeft && !fIsRight) - || (!fIsOut && !fIsIn)) - return VINF_SUCCESS; - if (fIsIn) - { - if (fIsLeft) - codecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0); - if (fIsRight) - codecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0); - } - if (fIsOut) - { - if (fIsLeft) - codecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0); - if (fIsRight) - codecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0); - } - if (CODEC_NID(cmd) == pState->u8DacLineOut) - codecToAudVolume(pAmplifier, AUD_MIXER_VOLUME); - if (CODEC_NID(cmd) == pState->u8AdcVolsLineIn) /* Microphone */ - codecToAudVolume(pAmplifier, AUD_MIXER_LINE_IN); - } - return VINF_SUCCESS; -} - -static int codecGetParameter(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - Assert(((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F0_PARAM_LENGTH)); - if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F0_PARAM_LENGTH) - { - Log(("HDAcodec: invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA))); - return VINF_SUCCESS; - } - *pResp = 0; - *pResp = pState->pNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA]; - return VINF_SUCCESS; -} - -/* F01 */ -static int codecGetConSelectCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsAdcMuxNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adcmux.u32F01_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F01_param; - else if (codecIsPortNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F01_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F01_param; - else if (codecIsAdcVolNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adcvol.u32F01_param; - return VINF_SUCCESS; -} - -/* 701 */ -static int codecSetConSelectCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - uint32_t *pu32Reg = NULL; - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsAdcMuxNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adcmux.u32F01_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F01_param; - else if (codecIsPortNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F01_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adc.u32F01_param; - else if (codecIsAdcVolNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adcvol.u32F01_param; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -/* F07 */ -static int codecGetPinCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F07_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F07_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F07_param; - else if (codecIsCdNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].cdnode.u32F07_param; - else if (codecIsPcbeepNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].pcbeep.u32F07_param; - else if (codecIsReservedNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].reserved.u32F07_param; - else - AssertMsgFailed(("Unsupported")); - return VINF_SUCCESS; -} - -/* 707 */ -static int codecSetPinCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - uint32_t *pu32Reg = NULL; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F07_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F07_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F07_param; - else if (codecIsCdNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].cdnode.u32F07_param; - else if (codecIsPcbeepNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].pcbeep.u32F07_param; - else if ( codecIsReservedNode(pState, CODEC_NID(cmd)) - && CODEC_NID(cmd) == 0x1b) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].reserved.u32F07_param; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -/* F08 */ -static int codecGetUnsolicitedEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F08_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param; - else if ((cmd) == 1 /* AFG */) - *pResp = pState->pNodes[CODEC_NID(cmd)].afg.u32F08_param; - else if (codecIsVolKnobNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F08_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param; - else - AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd))); - return VINF_SUCCESS; -} - -/* 708 */ -static int codecSetUnsolicitedEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - uint32_t *pu32Reg = NULL; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F08_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param; - else if (CODEC_NID(cmd) == 1 /* AFG */) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].afg.u32F08_param; - else if (codecIsVolKnobNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F08_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F08_param; - else - AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd))); - Assert(pu32Reg); - if(pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -/* F09 */ -static int codecGetPinSense(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F09_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F09_param; - else - AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd))); - return VINF_SUCCESS; -} - -/* 709 */ -static int codecSetPinSense(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - uint32_t *pu32Reg = NULL; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F09_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F09_param; - Assert(pu32Reg); - if(pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -static int codecGetConnectionListEntry(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - *pResp = 0; - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH); - if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH) - { - Log(("HDAcodec: access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA))); - return VINF_SUCCESS; - } - *pResp = pState->pNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA]; - return VINF_SUCCESS; -} -/* F03 */ -static int codecGetProcessingState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsAdcNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F03_param; - return VINF_SUCCESS; -} - -/* 703 */ -static int codecSetProcessingState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsAdcNode(pState, CODEC_NID(cmd))) - { - codecSetRegisterU8(&pState->pNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0); - } - return VINF_SUCCESS; -} - -/* F0D */ -static int codecGetDigitalConverter(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32F0d_param; - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32F0d_param; - return VINF_SUCCESS; -} - -static int codecSetDigitalConverter(struct CODECState *pState, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - codecSetRegisterU8(&pState->pNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset); - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - codecSetRegisterU8(&pState->pNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset); - return VINF_SUCCESS; -} - -/* 70D */ -static int codecSetDigitalConverter1(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - return codecSetDigitalConverter(pState, cmd, 0, pResp); -} - -/* 70E */ -static int codecSetDigitalConverter2(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - return codecSetDigitalConverter(pState, cmd, 8, pResp); -} - -/* F20 */ -static int codecGetSubId(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (CODEC_NID(cmd) == 1 /* AFG */) - { - *pResp = pState->pNodes[CODEC_NID(cmd)].afg.u32F20_param; - } - return VINF_SUCCESS; -} - -static int codecSetSubIdX(struct CODECState *pState, uint32_t cmd, uint8_t u8Offset) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - uint32_t *pu32Reg = NULL; - if (CODEC_NID(cmd) == 0x1 /* AFG */) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].afg.u32F20_param; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, u8Offset); - return VINF_SUCCESS; -} -/* 720 */ -static int codecSetSubId0 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetSubIdX(pState, cmd, 0); -} - -/* 721 */ -static int codecSetSubId1 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetSubIdX(pState, cmd, 8); -} -/* 722 */ -static int codecSetSubId2 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetSubIdX(pState, cmd, 16); -} -/* 723 */ -static int codecSetSubId3 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetSubIdX(pState, cmd, 24); -} - -static int codecReset(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert(CODEC_NID(cmd) == 1 /* AFG */); - if( CODEC_NID(cmd) == 1 /* AFG */ - && pState->pfnCodecNodeReset) - { - uint8_t i; - Log(("HDAcodec: enters reset\n")); - Assert(pState->pfnCodecNodeReset); - for (i = 0; i < pState->cTotalNodes; ++i) - { - pState->pfnCodecNodeReset(pState, i, &pState->pNodes[i]); - } - pState->fInReset = false; - Log(("HDAcodec: exits reset\n")); - } - *pResp = 0; - return VINF_SUCCESS; -} - -/* F05 */ -static int codecGetPowerState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (CODEC_NID(cmd) == 1 /* AFG */) - *pResp = pState->pNodes[CODEC_NID(cmd)].afg.u32F05_param; - else if (codecIsDacNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32F05_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F05_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F05_param; - else if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32F05_param; - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32F05_param; - else if (codecIsReservedNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].reserved.u32F05_param; - return VINF_SUCCESS; -} - -/* 705 */ - -static inline void codecPropogatePowerState(uint32_t *pu32F05_param) -{ - Assert(pu32F05_param); - if (!pu32F05_param) - return; - bool fReset = CODEC_F05_IS_RESET(*pu32F05_param); - bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param); - uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param); - *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState); -} - -static int codecSetPowerState(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - uint32_t *pu32Reg = NULL; - *pResp = 0; - if (CODEC_NID(cmd) == 1 /* AFG */) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].afg.u32F05_param; - else if (codecIsDacNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].dac.u32F05_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F05_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adc.u32F05_param; - else if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].spdifout.u32F05_param; - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].spdifin.u32F05_param; - else if (codecIsReservedNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].reserved.u32F05_param; - Assert((pu32Reg)); - if (!pu32Reg) - return VINF_SUCCESS; - - bool fReset = CODEC_F05_IS_RESET(*pu32Reg); - bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg); - - if (CODEC_NID(cmd) != 1 /* AFG */) - { - /* - * We shouldn't propogate actual power state, which actual for AFG - */ - *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, - CODEC_F05_ACT(pState->pNodes[1].afg.u32F05_param), - CODEC_F05_SET(cmd)); - } - - /* Propagate next power state only if AFG is on or verb modifies AFG power state */ - if ( CODEC_NID(cmd) == 1 /* AFG */ - || !CODEC_F05_ACT(pState->pNodes[1].afg.u32F05_param)) - { - *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd)); - if ( CODEC_NID(cmd) == 1 /* AFG */ - && (CODEC_F05_SET(cmd)) == CODEC_F05_D0) - { - /* now we're powered on AFG and may propogate power states on nodes */ - const uint8_t *pu8NodeIndex = &pState->au8Dacs[0]; - while (*(++pu8NodeIndex)) - codecPropogatePowerState(&pState->pNodes[*pu8NodeIndex].dac.u32F05_param); - - pu8NodeIndex = &pState->au8Adcs[0]; - while (*(++pu8NodeIndex)) - codecPropogatePowerState(&pState->pNodes[*pu8NodeIndex].adc.u32F05_param); - - pu8NodeIndex = &pState->au8DigInPins[0]; - while (*(++pu8NodeIndex)) - codecPropogatePowerState(&pState->pNodes[*pu8NodeIndex].digin.u32F05_param); - } - } - return VINF_SUCCESS; -} - -static int codecGetStreamId(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsDacNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32F06_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32F06_param; - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32F06_param; - else if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32F06_param; - else if (CODEC_NID(cmd) == 0x1A) - *pResp = pState->pNodes[CODEC_NID(cmd)].reserved.u32F06_param; - return VINF_SUCCESS; -} -static int codecSetStreamId(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - uint32_t *pu32addr = NULL; - *pResp = 0; - if (codecIsDacNode(pState, CODEC_NID(cmd))) - pu32addr = &pState->pNodes[CODEC_NID(cmd)].dac.u32F06_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - pu32addr = &pState->pNodes[CODEC_NID(cmd)].adc.u32F06_param; - else if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - pu32addr = &pState->pNodes[CODEC_NID(cmd)].spdifout.u32F06_param; - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - pu32addr = &pState->pNodes[CODEC_NID(cmd)].spdifin.u32F06_param; - else if (codecIsReservedNode(pState, CODEC_NID(cmd))) - pu32addr = &pState->pNodes[CODEC_NID(cmd)].reserved.u32F06_param; - Assert((pu32addr)); - if (pu32addr) - codecSetRegisterU8(pu32addr, cmd, 0); - return VINF_SUCCESS; -} - -static int codecGetConverterFormat(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsDacNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32A_param; - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adc.u32A_param; - else if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifout.u32A_param; - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].spdifin.u32A_param; - return VINF_SUCCESS; -} - -static int codecSetConverterFormat(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsDacNode(pState, CODEC_NID(cmd))) - codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0); - else if (codecIsAdcNode(pState, CODEC_NID(cmd))) - codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0); - else if (codecIsSpdifOutNode(pState, CODEC_NID(cmd))) - codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0); - else if (codecIsSpdifInNode(pState, CODEC_NID(cmd))) - codecSetRegisterU16(&pState->pNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0); - return VINF_SUCCESS; -} - -/* F0C */ -static int codecGetEAPD_BTLEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsAdcVolNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].adcvol.u32F0c_param; - else if (codecIsDacNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].dac.u32F0c_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F0c_param; - return VINF_SUCCESS; -} - -/* 70C */ -static int codecSetEAPD_BTLEnabled(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - uint32_t *pu32Reg = NULL; - if (codecIsAdcVolNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].adcvol.u32F0c_param; - else if (codecIsDacNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].dac.u32F0c_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F0c_param; - *pResp = 0; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -/* F0F */ -static int codecGetVolumeKnobCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsVolKnobNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param; - return VINF_SUCCESS; -} - -/* 70F */ -static int codecSetVolumeKnobCtrl(struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - uint32_t *pu32Reg = NULL; - *pResp = 0; - if (codecIsVolKnobNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -/* F17 */ -static int codecGetGPIOUnsolisted (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - /* note: this is true for ALC885 */ - if (CODEC_NID(cmd) == 0x1 /* AFG */) - *pResp = pState->pNodes[1].afg.u32F17_param; - return VINF_SUCCESS; -} - -/* 717 */ -static int codecSetGPIOUnsolisted (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - uint32_t *pu32Reg = NULL; - *pResp = 0; - if (CODEC_NID(cmd) == 1 /* AFG */) - pu32Reg = &pState->pNodes[1].afg.u32F17_param; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, 0); - return VINF_SUCCESS; -} - -/* F1C */ -static int codecGetConfig (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - *pResp = 0; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].port.u32F1c_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digout.u32F1c_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].digin.u32F1c_param; - else if (codecIsPcbeepNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param; - else if (codecIsCdNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].cdnode.u32F1c_param; - else if (codecIsReservedNode(pState, CODEC_NID(cmd))) - *pResp = pState->pNodes[CODEC_NID(cmd)].reserved.u32F1c_param; - return VINF_SUCCESS; -} -static int codecSetConfigX(struct CODECState *pState, uint32_t cmd, uint8_t u8Offset) -{ - Assert((CODEC_CAD(cmd) == pState->id)); - Assert((CODEC_NID(cmd) < pState->cTotalNodes)); - if (CODEC_NID(cmd) >= pState->cTotalNodes) - { - Log(("HDAcodec: invalid node address %d\n", CODEC_NID(cmd))); - return VINF_SUCCESS; - } - uint32_t *pu32Reg = NULL; - if (codecIsPortNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].port.u32F1c_param; - else if (codecIsDigInPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digin.u32F1c_param; - else if (codecIsDigOutPinNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].digout.u32F1c_param; - else if (codecIsCdNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].cdnode.u32F1c_param; - else if (codecIsPcbeepNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param; - else if (codecIsReservedNode(pState, CODEC_NID(cmd))) - pu32Reg = &pState->pNodes[CODEC_NID(cmd)].reserved.u32F1c_param; - Assert((pu32Reg)); - if (pu32Reg) - codecSetRegisterU8(pu32Reg, cmd, u8Offset); - return VINF_SUCCESS; -} -/* 71C */ -static int codecSetConfig0 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetConfigX(pState, cmd, 0); -} -/* 71D */ -static int codecSetConfig1 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetConfigX(pState, cmd, 8); -} -/* 71E */ -static int codecSetConfig2 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetConfigX(pState, cmd, 16); -} -/* 71E */ -static int codecSetConfig3 (struct CODECState *pState, uint32_t cmd, uint64_t *pResp) -{ - *pResp = 0; - return codecSetConfigX(pState, cmd, 24); -} - - -static int codecToAudVolume(AMPLIFIER *pAmp, audmixerctl_t mt) -{ - uint32_t dir = AMPLIFIER_OUT; - switch (mt) - { - case AUD_MIXER_VOLUME: - case AUD_MIXER_PCM: - dir = AMPLIFIER_OUT; - break; - case AUD_MIXER_LINE_IN: - dir = AMPLIFIER_IN; - break; - } - int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7); - mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7); - mute >>=7; - mute &= 0x1; - uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f; - uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f; - AUD_set_volume(mt, &mute, &lVol, &rVol); - return VINF_SUCCESS; -} - -static CODECVERB CODECVERBS[] = -{ -/* verb | verb mask | callback */ -/* ----------- -------------------- ----------------------- */ - {0x000F0000, CODEC_VERB_8BIT_CMD , codecGetParameter }, - {0x000F0100, CODEC_VERB_8BIT_CMD , codecGetConSelectCtrl }, - {0x00070100, CODEC_VERB_8BIT_CMD , codecSetConSelectCtrl }, - {0x000F0600, CODEC_VERB_8BIT_CMD , codecGetStreamId }, - {0x00070600, CODEC_VERB_8BIT_CMD , codecSetStreamId }, - {0x000F0700, CODEC_VERB_8BIT_CMD , codecGetPinCtrl }, - {0x00070700, CODEC_VERB_8BIT_CMD , codecSetPinCtrl }, - {0x000F0800, CODEC_VERB_8BIT_CMD , codecGetUnsolicitedEnabled }, - {0x00070800, CODEC_VERB_8BIT_CMD , codecSetUnsolicitedEnabled }, - {0x000F0900, CODEC_VERB_8BIT_CMD , codecGetPinSense }, - {0x00070900, CODEC_VERB_8BIT_CMD , codecSetPinSense }, - {0x000F0200, CODEC_VERB_8BIT_CMD , codecGetConnectionListEntry }, - {0x000F0300, CODEC_VERB_8BIT_CMD , codecGetProcessingState }, - {0x00070300, CODEC_VERB_8BIT_CMD , codecSetProcessingState }, - {0x000F0D00, CODEC_VERB_8BIT_CMD , codecGetDigitalConverter }, - {0x00070D00, CODEC_VERB_8BIT_CMD , codecSetDigitalConverter1 }, - {0x00070E00, CODEC_VERB_8BIT_CMD , codecSetDigitalConverter2 }, - {0x000F2000, CODEC_VERB_8BIT_CMD , codecGetSubId }, - {0x00072000, CODEC_VERB_8BIT_CMD , codecSetSubId0 }, - {0x00072100, CODEC_VERB_8BIT_CMD , codecSetSubId1 }, - {0x00072200, CODEC_VERB_8BIT_CMD , codecSetSubId2 }, - {0x00072300, CODEC_VERB_8BIT_CMD , codecSetSubId3 }, - {0x0007FF00, CODEC_VERB_8BIT_CMD , codecReset }, - {0x000F0500, CODEC_VERB_8BIT_CMD , codecGetPowerState }, - {0x00070500, CODEC_VERB_8BIT_CMD , codecSetPowerState }, - {0x000F0C00, CODEC_VERB_8BIT_CMD , codecGetEAPD_BTLEnabled }, - {0x00070C00, CODEC_VERB_8BIT_CMD , codecSetEAPD_BTLEnabled }, - {0x000F0F00, CODEC_VERB_8BIT_CMD , codecGetVolumeKnobCtrl }, - {0x00070F00, CODEC_VERB_8BIT_CMD , codecSetVolumeKnobCtrl }, - {0x000F1700, CODEC_VERB_8BIT_CMD , codecGetGPIOUnsolisted }, - {0x00071700, CODEC_VERB_8BIT_CMD , codecSetGPIOUnsolisted }, - {0x000F1C00, CODEC_VERB_8BIT_CMD , codecGetConfig }, - {0x00071C00, CODEC_VERB_8BIT_CMD , codecSetConfig0 }, - {0x00071D00, CODEC_VERB_8BIT_CMD , codecSetConfig1 }, - {0x00071E00, CODEC_VERB_8BIT_CMD , codecSetConfig2 }, - {0x00071F00, CODEC_VERB_8BIT_CMD , codecSetConfig3 }, - {0x000A0000, CODEC_VERB_16BIT_CMD, codecGetConverterFormat }, - {0x00020000, CODEC_VERB_16BIT_CMD, codecSetConverterFormat }, - {0x000B0000, CODEC_VERB_16BIT_CMD, codecGetAmplifier }, - {0x00030000, CODEC_VERB_16BIT_CMD, codecSetAmplifier }, -}; - -static int codecLookup(CODECState *pState, uint32_t cmd, PPFNCODECVERBPROCESSOR pfn) -{ - int rc = VINF_SUCCESS; - Assert(CODEC_CAD(cmd) == pState->id); - if (codecIsReservedNode(pState, CODEC_NID(cmd))) - { - Log(("HDAcodec: cmd %x was addressed to reserved node\n", cmd)); - } - if ( CODEC_VERBDATA(cmd) == 0 - || CODEC_NID(cmd) >= pState->cTotalNodes) - { - *pfn = codecUnimplemented; - //** @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp) - Log(("HDAcodec: cmd %x was ignored\n", cmd)); - return VINF_SUCCESS; - } - for (int i = 0; i < pState->cVerbs; ++i) - { - if ((CODEC_VERBDATA(cmd) & pState->pVerbs[i].mask) == pState->pVerbs[i].verb) - { - *pfn = pState->pVerbs[i].pfn; - return VINF_SUCCESS; - } - } - *pfn = codecUnimplemented; - Log(("HDAcodec: callback for %x wasn't found\n", CODEC_VERBDATA(cmd))); - return rc; -} - -static void pi_callback (void *opaque, int avail) -{ - CODECState *pState = (CODECState *)opaque; - pState->pfnTransfer(pState, PI_INDEX, avail); -} - -static void po_callback (void *opaque, int avail) -{ - CODECState *pState = (CODECState *)opaque; - pState->pfnTransfer(pState, PO_INDEX, avail); -} - -/** - * - * routines open one of the voices (IN, OUT) with corresponding parameters. - * this routine could be called from HDA on setting/resseting sound format. - * - * @todo: probably passed settings should be verified (if AFG's declared proposed format) before enabling. - */ -int codecOpenVoice(CODECState *pState, ENMSOUNDSOURCE enmSoundSource, audsettings_t *pAudioSettings) -{ - int rc = 0; - Assert((pState && pAudioSettings)); - if ( !pState - || !pAudioSettings) - return -1; - switch (enmSoundSource) - { - case PI_INDEX: - pState->SwVoiceIn = AUD_open_in(&pState->card, pState->SwVoiceIn, "hda.in", pState, pi_callback, pAudioSettings); - rc = pState->SwVoiceIn ? 0 : 1; - break; - case PO_INDEX: - pState->SwVoiceOut = AUD_open_out(&pState->card, pState->SwVoiceOut, "hda.out", pState, po_callback, pAudioSettings); - rc = pState->SwVoiceOut ? 0 : 1; - break; - default: - return -1; - } - if (!rc) - LogRel(("HDAcodec: can't open %s fmt(freq: %d)\n", - enmSoundSource == PI_INDEX? "in" : "out", - pAudioSettings->freq)); - return rc; -} - -int codecConstruct(PPDMDEVINS pDevIns, CODECState *pState, PCFGMNODE pCfgHandle) -{ - audsettings_t as; - int rc; - pState->pVerbs = (CODECVERB *)&CODECVERBS; - pState->cVerbs = sizeof(CODECVERBS)/sizeof(CODECVERB); - pState->pfnLookup = codecLookup; - rc = stac9220Construct(pState); - AssertRC(rc); - /* common root node initializers */ - pState->pNodes[0].node.au32F00_param[0] = CODEC_MAKE_F00_00(pState->u16VendorId, pState->u16DeviceId); - pState->pNodes[0].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1); - /* common AFG node initializers */ - pState->pNodes[1].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x2, pState->cTotalNodes - 2); - pState->pNodes[1].node.au32F00_param[5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG); - pState->pNodes[1].afg.u32F20_param = CODEC_MAKE_F20(pState->u16VendorId, pState->u8BSKU, pState->u8AssemblyId); - - //** @todo r=michaln: Was this meant to be 'HDA' or something like that? (AC'97 was on ICH0) - AUD_register_card ("ICH0", &pState->card); - - /* 44.1 kHz */ - as.freq = 44100; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 0; - - pState->pNodes[1].node.au32F00_param[0xA] = CODEC_F00_0A_16_BIT; - codecOpenVoice(pState, PI_INDEX, &as); - codecOpenVoice(pState, PO_INDEX, &as); - pState->pNodes[1].node.au32F00_param[0xA] |= CODEC_F00_0A_44_1KHZ; - - uint8_t i; - Assert(pState->pNodes); - Assert(pState->pfnCodecNodeReset); - for (i = 0; i < pState->cTotalNodes; ++i) - { - pState->pfnCodecNodeReset(pState, i, &pState->pNodes[i]); - } - - codecToAudVolume(&pState->pNodes[pState->u8DacLineOut].dac.B_params, AUD_MIXER_VOLUME); - codecToAudVolume(&pState->pNodes[pState->u8AdcVolsLineIn].adcvol.B_params, AUD_MIXER_LINE_IN); - - /* If no host voices were created, then fallback to nul audio. */ - if (!AUD_is_host_voice_in_ok(pState->SwVoiceIn)) - LogRel (("HDA: WARNING: Unable to open PCM IN!\n")); - if (!AUD_is_host_voice_out_ok(pState->SwVoiceOut)) - LogRel (("HDA: WARNING: Unable to open PCM OUT!\n")); - - if ( !AUD_is_host_voice_in_ok(pState->SwVoiceIn) - && !AUD_is_host_voice_out_ok(pState->SwVoiceOut)) - { - /* Was not able initialize *any* voice. Select the NULL audio driver instead */ - AUD_close_in (&pState->card, pState->SwVoiceIn); - AUD_close_out (&pState->card, pState->SwVoiceOut); - pState->SwVoiceOut = NULL; - pState->SwVoiceIn = NULL; - AUD_init_null (); - - PDMDevHlpVMSetRuntimeError (pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", - N_ ("No audio devices could be opened. Selecting the NULL audio backend " - "with the consequence that no sound is audible")); - } - else if ( !AUD_is_host_voice_in_ok(pState->SwVoiceIn) - || !AUD_is_host_voice_out_ok(pState->SwVoiceOut)) - { - char szMissingVoices[128]; - size_t len = 0; - if (!AUD_is_host_voice_in_ok(pState->SwVoiceIn)) - len = RTStrPrintf (szMissingVoices, sizeof(szMissingVoices), "PCM_in"); - if (!AUD_is_host_voice_out_ok(pState->SwVoiceOut)) - len += RTStrPrintf (szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_out" : "PCM_out"); - - PDMDevHlpVMSetRuntimeError (pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", - N_ ("Some audio devices (%s) could not be opened. Guest applications generating audio " - "output or depending on audio input may hang. Make sure your host audio device " - "is working properly. Check the logfile for error messages of the audio " - "subsystem"), szMissingVoices); - } - - return VINF_SUCCESS; -} - -int codecDestruct(CODECState *pCodecState) -{ - RTMemFree(pCodecState->pNodes); - return VINF_SUCCESS; -} - -int codecSaveState(CODECState *pCodecState, PSSMHANDLE pSSM) -{ - AssertLogRelMsgReturn(pCodecState->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pCodecState->cTotalNodes), - VERR_INTERNAL_ERROR); - SSMR3PutU32(pSSM, pCodecState->cTotalNodes); - for (unsigned idxNode = 0; idxNode < pCodecState->cTotalNodes; ++idxNode) - SSMR3PutStructEx(pSSM, &pCodecState->pNodes[idxNode].SavedState, sizeof(pCodecState->pNodes[idxNode].SavedState), - 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/); - return VINF_SUCCESS; -} - - -int codecLoadState(CODECState *pCodecState, PSSMHANDLE pSSM, uint32_t uVersion) -{ - PCSSMFIELD pFields; - uint32_t fFlags; - switch (uVersion) - { - case HDA_SSM_VERSION_1: - AssertReturn(pCodecState->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR); - pFields = g_aCodecNodeFieldsV1; - fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED; - break; - - case HDA_SSM_VERSION_2: - case HDA_SSM_VERSION_3: - AssertReturn(pCodecState->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR); - pFields = g_aCodecNodeFields; - fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED; - break; - - case HDA_SSM_VERSION: - { - uint32_t cNodes; - int rc2 = SSMR3GetU32(pSSM, &cNodes); - AssertRCReturn(rc2, rc2); - if (cNodes != 0x1c) - return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; - AssertReturn(pCodecState->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR); - - pFields = g_aCodecNodeFields; - fFlags = 0; - break; - } - - default: - return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; - } - - for (unsigned idxNode = 0; idxNode < pCodecState->cTotalNodes; ++idxNode) - { - uint8_t idOld = pCodecState->pNodes[idxNode].SavedState.Core.id; - int rc = SSMR3GetStructEx(pSSM, &pCodecState->pNodes[idxNode].SavedState, - sizeof(pCodecState->pNodes[idxNode].SavedState), - fFlags, pFields, NULL); - if (RT_FAILURE(rc)) - return rc; - AssertLogRelMsgReturn(idOld == pCodecState->pNodes[idxNode].SavedState.Core.id, - ("loaded %#x, expected \n", pCodecState->pNodes[idxNode].SavedState.Core.id, idOld), - VERR_SSM_DATA_UNIT_FORMAT_CHANGED); - } - - /* - * Update stuff after changing the state. - */ - if (codecIsDacNode(pCodecState, pCodecState->u8DacLineOut)) - codecToAudVolume(&pCodecState->pNodes[pCodecState->u8DacLineOut].dac.B_params, AUD_MIXER_VOLUME); - else if (codecIsSpdifOutNode(pCodecState, pCodecState->u8DacLineOut)) - codecToAudVolume(&pCodecState->pNodes[pCodecState->u8DacLineOut].spdifout.B_params, AUD_MIXER_VOLUME); - codecToAudVolume(&pCodecState->pNodes[pCodecState->u8AdcVolsLineIn].adcvol.B_params, AUD_MIXER_LINE_IN); - - return VINF_SUCCESS; -} - diff --git a/src/VBox/Devices/Audio/DevCodec.h b/src/VBox/Devices/Audio/DevCodec.h deleted file mode 100644 index b43420f3..00000000 --- a/src/VBox/Devices/Audio/DevCodec.h +++ /dev/null @@ -1,546 +0,0 @@ -/* $Id: DevCodec.h $ */ -/** @file - * DevCodec - VBox ICH Intel HD Audio Codec. - */ - -/* - * Copyright (C) 2006-2008 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ -#ifndef DEV_CODEC_H -#define DEV_CODEC_H -struct CODECState; -struct INTELHDLinkState; - -typedef DECLCALLBACK(int) FNCODECVERBPROCESSOR(struct CODECState *pState, uint32_t cmd, uint64_t *pResp); -typedef FNCODECVERBPROCESSOR *PFNCODECVERBPROCESSOR; -typedef FNCODECVERBPROCESSOR **PPFNCODECVERBPROCESSOR; - -/* RPM 5.3.1 */ -#define CODEC_RESPONSE_UNSOLICITED RT_BIT_64(34) - -#define CODEC_CAD_MASK 0xF0000000 -#define CODEC_CAD_SHIFT 28 -#define CODEC_DIRECT_MASK RT_BIT(27) -#define CODEC_NID_MASK 0x07F00000 -#define CODEC_NID_SHIFT 20 -#define CODEC_VERBDATA_MASK 0x000FFFFF -#define CODEC_VERB_4BIT_CMD 0x000FFFF0 -#define CODEC_VERB_4BIT_DATA 0x0000000F -#define CODEC_VERB_8BIT_CMD 0x000FFF00 -#define CODEC_VERB_8BIT_DATA 0x000000FF -#define CODEC_VERB_16BIT_CMD 0x000F0000 -#define CODEC_VERB_16BIT_DATA 0x0000FFFF - -#define CODEC_CAD(cmd) ((cmd) & CODEC_CAD_MASK) -#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK) -#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT) -#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK) -#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x)) -#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4)) -#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8)) -#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16)) -#define CODEC_VERB_PAYLOAD4(cmd) ((cmd) & CODEC_VERB_4BIT_DATA) -#define CODEC_VERB_PAYLOAD8(cmd) ((cmd) & CODEC_VERB_8BIT_DATA) -#define CODEC_VERB_PAYLOAD16(cmd) ((cmd) & CODEC_VERB_16BIT_DATA) - -#define CODEC_VERB_GET_AMP_DIRECTION RT_BIT(15) -#define CODEC_VERB_GET_AMP_SIDE RT_BIT(13) -#define CODEC_VERB_GET_AMP_INDEX 0x7 - -/* HDA spec 7.3.3.7 NoteA */ -#define CODEC_GET_AMP_DIRECTION(cmd) (((cmd) & CODEC_VERB_GET_AMP_DIRECTION) >> 15) -#define CODEC_GET_AMP_SIDE(cmd) (((cmd) & CODEC_VERB_GET_AMP_SIDE) >> 13) -#define CODEC_GET_AMP_INDEX(cmd) (CODEC_GET_AMP_DIRECTION(cmd) ? 0 : ((cmd) & CODEC_VERB_GET_AMP_INDEX)) - -/* HDA spec 7.3.3.7 NoteC */ -#define CODEC_VERB_SET_AMP_OUT_DIRECTION RT_BIT(15) -#define CODEC_VERB_SET_AMP_IN_DIRECTION RT_BIT(14) -#define CODEC_VERB_SET_AMP_LEFT_SIDE RT_BIT(13) -#define CODEC_VERB_SET_AMP_RIGHT_SIDE RT_BIT(12) -#define CODEC_VERB_SET_AMP_INDEX (0x7 << 8) - -#define CODEC_SET_AMP_IS_OUT_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_OUT_DIRECTION) != 0) -#define CODEC_SET_AMP_IS_IN_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_IN_DIRECTION) != 0) -#define CODEC_SET_AMP_IS_LEFT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_LEFT_SIDE) != 0) -#define CODEC_SET_AMP_IS_RIGHT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_RIGHT_SIDE) != 0) -#define CODEC_SET_AMP_INDEX(cmd) (((cmd) & CODEC_VERB_SET_AMP_INDEX) >> 7) - -/* HDA spec 7.3.3.1 defines layout of configuration registers/verbs (0xF00) */ -/* VendorID (7.3.4.1) */ -#define CODEC_MAKE_F00_00(vendorID, deviceID) (((vendorID) << 16) | (deviceID)) -#define CODEC_F00_00_VENDORID(f00_00) (((f00_00) >> 16) & 0xFFFF) -#define CODEC_F00_00_DEVICEID(f00_00) ((f00_00) & 0xFFFF) -/* RevisionID (7.3.4.2)*/ -#define CODEC_MAKE_F00_02(MajRev, MinRev, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID)) -/* Subordinate node count (7.3.4.3)*/ -#define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF)) -#define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04) (((f00_04) >> 16) & 0xFF) -#define CODEC_F00_04_TO_NODE_COUNT(f00_04) ((f00_04) & 0xFF) -/* - * Function Group Type (7.3.4.4) - * 0 & [0x3-0x7f] are reserved types - * [0x80 - 0xff] are vendor defined function groups - */ -#define CODEC_MAKE_F00_05(UnSol, NodeType) (((UnSol) << 8)|(NodeType)) -#define CODEC_F00_05_UNSOL RT_BIT(8) -#define CODEC_F00_05_AFG (0x1) -#define CODEC_F00_05_MFG (0x2) -#define CODEC_F00_05_IS_UNSOL(f00_05) RT_BOOL((f00_05) & RT_BIT(8)) -#define CODEC_F00_05_GROUP(f00_05) ((f00_05) & 0xff) -/* Audio Function Group capabilities (7.3.4.5) */ -#define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF)) -#define CODEC_F00_08_BEEP_GEN(f00_08) ((f00_08) & RT_BIT(16) - -/* Widget Capabilities (7.3.4.6) */ -#define CODEC_MAKE_F00_09(type, delay, chanel_count) \ - ( (((type) & 0xF) << 20) \ - | (((delay) & 0xF) << 16) \ - | (((chanel_count) & 0xF) << 13)) -/* note: types 0x8-0xe are reserved */ -#define CODEC_F00_09_TYPE_AUDIO_OUTPUT (0x0) -#define CODEC_F00_09_TYPE_AUDIO_INPUT (0x1) -#define CODEC_F00_09_TYPE_AUDIO_MIXER (0x2) -#define CODEC_F00_09_TYPE_AUDIO_SELECTOR (0x3) -#define CODEC_F00_09_TYPE_PIN_COMPLEX (0x4) -#define CODEC_F00_09_TYPE_POWER_WIDGET (0x5) -#define CODEC_F00_09_TYPE_VOLUME_KNOB (0x6) -#define CODEC_F00_09_TYPE_BEEP_GEN (0x7) -#define CODEC_F00_09_TYPE_VENDOR_DEFINED (0xF) - -#define CODEC_F00_09_CAP_CP RT_BIT(12) -#define CODEC_F00_09_CAP_L_R_SWAP RT_BIT(11) -#define CODEC_F00_09_CAP_POWER_CTRL RT_BIT(10) -#define CODEC_F00_09_CAP_DIGITAL RT_BIT(9) -#define CODEC_F00_09_CAP_CONNECTION_LIST RT_BIT(8) -#define CODEC_F00_09_CAP_UNSOL RT_BIT(7) -#define CODEC_F00_09_CAP_PROC_WIDGET RT_BIT(6) -#define CODEC_F00_09_CAP_STRIPE RT_BIT(5) -#define CODEC_F00_09_CAP_FMT_OVERRIDE RT_BIT(4) -#define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE RT_BIT(3) -#define CODEC_F00_09_CAP_OUT_AMP_PRESENT RT_BIT(2) -#define CODEC_F00_09_CAP_IN_AMP_PRESENT RT_BIT(1) -#define CODEC_F00_09_CAP_LSB RT_BIT(0) - -#define CODEC_F00_09_TYPE(f00_09) (((f00_09) >> 20) & 0xF) - -#define CODEC_F00_09_IS_CAP_CP(f00_09) RT_BOOL((f00_09) & RT_BIT(12)) -#define CODEC_F00_09_IS_CAP_L_R_SWAP(f00_09) RT_BOOL((f00_09) & RT_BIT(11)) -#define CODEC_F00_09_IS_CAP_POWER_CTRL(f00_09) RT_BOOL((f00_09) & RT_BIT(10)) -#define CODEC_F00_09_IS_CAP_DIGITAL(f00_09) RT_BOOL((f00_09) & RT_BIT(9)) -#define CODEC_F00_09_IS_CAP_CONNECTION_LIST(f00_09) RT_BOOL((f00_09) & RT_BIT(8)) -#define CODEC_F00_09_IS_CAP_UNSOL(f00_09) RT_BOOL((f00_09) & RT_BIT(7)) -#define CODEC_F00_09_IS_CAP_PROC_WIDGET(f00_09) RT_BOOL((f00_09) & RT_BIT(6)) -#define CODEC_F00_09_IS_CAP_STRIPE(f00_09) RT_BOOL((f00_09) & RT_BIT(5)) -#define CODEC_F00_09_IS_CAP_FMT_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(4)) -#define CODEC_F00_09_IS_CAP_AMP_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(3)) -#define CODEC_F00_09_IS_CAP_OUT_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(2)) -#define CODEC_F00_09_IS_CAP_IN_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(1)) -#define CODEC_F00_09_IS_CAP_LSB(f00_09) RT_BOOL((f00_09) & RT_BIT(0)) - -/* Supported PCM size, rates (7.3.4.7) */ -#define CODEC_F00_0A_32_BIT RT_BIT(19) -#define CODEC_F00_0A_24_BIT RT_BIT(18) -#define CODEC_F00_0A_16_BIT RT_BIT(17) -#define CODEC_F00_0A_8_BIT RT_BIT(16) - -#define CODEC_F00_0A_48KHZ_MULT_8X RT_BIT(11) -#define CODEC_F00_0A_48KHZ_MULT_4X RT_BIT(10) -#define CODEC_F00_0A_44_1KHZ_MULT_4X RT_BIT(9) -#define CODEC_F00_0A_48KHZ_MULT_2X RT_BIT(8) -#define CODEC_F00_0A_44_1KHZ_MULT_2X RT_BIT(7) -#define CODEC_F00_0A_48KHZ RT_BIT(6) -#define CODEC_F00_0A_44_1KHZ RT_BIT(5) -/* 2/3 * 48kHz */ -#define CODEC_F00_0A_48KHZ_2_3X RT_BIT(4) -/* 1/2 * 44.1kHz */ -#define CODEC_F00_0A_44_1KHZ_1_2X RT_BIT(3) -/* 1/3 * 48kHz */ -#define CODEC_F00_0A_48KHZ_1_3X RT_BIT(2) -/* 1/4 * 44.1kHz */ -#define CODEC_F00_0A_44_1KHZ_1_4X RT_BIT(1) -/* 1/6 * 48kHz */ -#define CODEC_F00_0A_48KHZ_1_6X RT_BIT(0) - -/* Supported streams formats (7.3.4.8) */ -#define CODEC_F00_0B_AC3 RT_BIT(2) -#define CODEC_F00_0B_FLOAT32 RT_BIT(1) -#define CODEC_F00_0B_PCM RT_BIT(0) - -/* Pin Capabilities (7.3.4.9)*/ -#define CODEC_MAKE_F00_0C(vref_ctrl) (((vref_ctrl) & 0xFF) << 8) -#define CODEC_F00_0C_CAP_HBR RT_BIT(27) -#define CODEC_F00_0C_CAP_DP RT_BIT(24) -#define CODEC_F00_0C_CAP_EAPD RT_BIT(16) -#define CODEC_F00_0C_CAP_HDMI RT_BIT(7) -#define CODEC_F00_0C_CAP_BALANCED_IO RT_BIT(6) -#define CODEC_F00_0C_CAP_INPUT RT_BIT(5) -#define CODEC_F00_0C_CAP_OUTPUT RT_BIT(4) -#define CODEC_F00_0C_CAP_HP RT_BIT(3) -#define CODEC_F00_0C_CAP_PRESENSE_DETECT RT_BIT(2) -#define CODEC_F00_0C_CAP_TRIGGER_REQUIRED RT_BIT(1) -#define CODEC_F00_0C_CAP_IMPENDANCE_SENSE RT_BIT(0) - -#define CODEC_F00_0C_IS_CAP_HBR(f00_0c) ((f00_0c) & RT_BIT(27)) -#define CODEC_F00_0C_IS_CAP_DP(f00_0c) ((f00_0c) & RT_BIT(24)) -#define CODEC_F00_0C_IS_CAP_EAPD(f00_0c) ((f00_0c) & RT_BIT(16)) -#define CODEC_F00_0C_IS_CAP_HDMI(f00_0c) ((f00_0c) & RT_BIT(7)) -#define CODEC_F00_0C_IS_CAP_BALANCED_IO(f00_0c) ((f00_0c) & RT_BIT(6)) -#define CODEC_F00_0C_IS_CAP_INPUT(f00_0c) ((f00_0c) & RT_BIT(5)) -#define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c) ((f00_0c) & RT_BIT(4)) -#define CODEC_F00_0C_IS_CAP_HP(f00_0c) ((f00_0c) & RT_BIT(3)) -#define CODEC_F00_0C_IS_CAP_PRESENSE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2)) -#define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c) ((f00_0c) & RT_BIT(1)) -#define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c) ((f00_0c) & RT_BIT(0)) - -/* Input Amplifier capabilities (7.3.4.10) */ -#define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \ - ( (((mute_cap) & 0x1) << 31) \ - | (((step_size) & 0xFF) << 16) \ - | (((num_steps) & 0xFF) << 8) \ - | ((offset) & 0xFF)) - -/* Output Amplifier capabilities (7.3.4.10) */ -#define CODEC_MAKE_F00_12 CODEC_MAKE_F00_0D - -/* Connection list lenght (7.3.4.11) */ -#define CODEC_MAKE_F00_0E(long_form, length) \ - ( (((long_form) & 0x1) << 7) \ - | ((length) & 0x7F)) -#define CODEC_F00_0E_IS_LONG(f00_0e) RT_BOOL((f00_0e) & RT_BIT(7)) -#define CODEC_F00_0E_COUNT(f00_0e) ((f00_0e) & 0x7F) -/* Supported Power States (7.3.4.12) */ -#define CODEC_F00_0F_EPSS RT_BIT(31) -#define CODEC_F00_0F_CLKSTOP RT_BIT(30) -#define CODEC_F00_0F_S3D3 RT_BIT(29) -#define CODEC_F00_0F_D3COLD RT_BIT(4) -#define CODEC_F00_0F_D3 RT_BIT(3) -#define CODEC_F00_0F_D2 RT_BIT(2) -#define CODEC_F00_0F_D1 RT_BIT(1) -#define CODEC_F00_0F_D0 RT_BIT(0) - -/* Processing capabilities 7.3.4.13 */ -#define CODEC_MAKE_F00_10(num, benign) ((((num) & 0xFF) << 8) | ((benign) & 0x1)) -#define CODEC_F00_10_NUM(f00_10) (((f00_10) & (0xFF << 8)) >> 8) -#define CODEC_F00_10_BENING(f00_10) ((f00_10) & 0x1) - -/* CP/IO Count (7.3.4.14) */ -#define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \ - ( (((wake) & 0x1) << 31) \ - | (((unsol) & 0x1) << 30) \ - | (((numgpi) & 0xFF) << 16) \ - | (((numgpo) & 0xFF) << 8) \ - | ((numgpio) & 0xFF)) - -/* Processing States (7.3.3.4) */ -#define CODEC_F03_OFF (0) -#define CODEC_F03_ON RT_BIT(0) -#define CODEC_F03_BENING RT_BIT(1) -/* Power States (7.3.3.10) */ -#define CODEC_MAKE_F05(reset, stopok, error, act, set) \ - ( (((reset) & 0x1) << 10) \ - | (((stopok) & 0x1) << 9) \ - | (((error) & 0x1) << 8) \ - | (((act) & 0x7) << 4) \ - | ((set) & 0x7)) -#define CODEC_F05_D3COLD (4) -#define CODEC_F05_D3 (3) -#define CODEC_F05_D2 (2) -#define CODEC_F05_D1 (1) -#define CODEC_F05_D0 (0) - -#define CODEC_F05_IS_RESET(value) (((value) & RT_BIT(10)) != 0) -#define CODEC_F05_IS_STOPOK(value) (((value) & RT_BIT(9)) != 0) -#define CODEC_F05_IS_ERROR(value) (((value) & RT_BIT(8)) != 0) -#define CODEC_F05_ACT(value) (((value) & 0x7) >> 4) -#define CODEC_F05_SET(value) (((value) & 0x7)) - -#define CODEC_F05_GE(p0, p1) ((p0) <= (p1)) -#define CODEC_F05_LE(p0, p1) ((p0) >= (p1)) - -/* Pin Widged Control (7.3.3.13) */ -#define CODEC_F07_VREF_HIZ (0) -#define CODEC_F07_VREF_50 (0x1) -#define CODEC_F07_VREF_GROUND (0x2) -#define CODEC_F07_VREF_80 (0x4) -#define CODEC_F07_VREF_100 (0x5) -#define CODEC_F07_IN_ENABLE RT_BIT(5) -#define CODEC_F07_OUT_ENABLE RT_BIT(6) -#define CODEC_F07_OUT_H_ENABLE RT_BIT(7) - -/* Unsolicited enabled (7.3.3.14) */ -#define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F)) - -/* Converter formats (7.3.3.8) and (3.7.1) */ -#define CODEC_MAKE_A(fNonPCM, f44_1BaseRate, mult, div, bits, chan) \ - ( (((fNonPCM) & 0x1) << 15) \ - | (((f44_1BaseRate) & 0x1) << 14) \ - | (((mult) & 0x7) << 11) \ - | (((div) & 0x7) << 8) \ - | (((bits) & 0x7) << 4) \ - | ((chan) & 0xF)) - -#define CODEC_A_MULT_1X (0) -#define CODEC_A_MULT_2X (1) -#define CODEC_A_MULT_3X (2) -#define CODEC_A_MULT_4X (3) - -#define CODEC_A_DIV_1X (0) -#define CODEC_A_DIV_2X (1) -#define CODEC_A_DIV_3X (2) -#define CODEC_A_DIV_4X (3) -#define CODEC_A_DIV_5X (4) -#define CODEC_A_DIV_6X (5) -#define CODEC_A_DIV_7X (6) -#define CODEC_A_DIV_8X (7) - -#define CODEC_A_8_BIT (0) -#define CODEC_A_16_BIT (1) -#define CODEC_A_20_BIT (2) -#define CODEC_A_24_BIT (3) -#define CODEC_A_32_BIT (4) - -/* Pin Sense (7.3.3.15) */ -#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \ -( (((fPresent) & 0x1) << 31) \ - | (((impedance) & 0x7FFFFFFF))) -#define CODEC_F09_ANALOG_NA 0x7FFFFFFF -#define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \ -( (((fPresent) & 0x1) << 31) \ - | (((fELDValid) & 0x1) << 30)) - -#define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1)) -#define CODEC_FOC_IS_LRSWAP(f0c) RT_BOOL((f0c) & RT_BIT(2)) -#define CODEC_FOC_IS_EAPD(f0c) RT_BOOL((f0c) & RT_BIT(1)) -#define CODEC_FOC_IS_BTL(f0c) RT_BOOL((f0c) & RT_BIT(0)) -/* HDA spec 7.3.3.31 defines layout of configuration registers/verbs (0xF1C) */ -/* Configuration's port connection */ -#define CODEC_F1C_PORT_MASK (0x3) -#define CODEC_F1C_PORT_SHIFT (30) - -#define CODEC_F1C_PORT_COMPLEX (0x0) -#define CODEC_F1C_PORT_NO_PHYS (0x1) -#define CODEC_F1C_PORT_FIXED (0x2) -#define CODEC_F1C_BOTH (0x3) - -/* Configuration's location */ -#define CODEC_F1C_LOCATION_MASK (0x3F) -#define CODEC_F1C_LOCATION_SHIFT (24) -/* [4:5] bits of location region means chassis attachment */ -#define CODEC_F1C_LOCATION_PRIMARY_CHASSIS (0) -#define CODEC_F1C_LOCATION_INTERNAL RT_BIT(4) -#define CODEC_F1C_LOCATION_SECONDRARY_CHASSIS RT_BIT(5) -#define CODEC_F1C_LOCATION_OTHER (RT_BIT(5)) - -/* [0:3] bits of location region means geometry location attachment */ -#define CODEC_F1C_LOCATION_NA (0) -#define CODEC_F1C_LOCATION_REAR (0x1) -#define CODEC_F1C_LOCATION_FRONT (0x2) -#define CODEC_F1C_LOCATION_LEFT (0x3) -#define CODEC_F1C_LOCATION_RIGTH (0x4) -#define CODEC_F1C_LOCATION_TOP (0x5) -#define CODEC_F1C_LOCATION_BOTTOM (0x6) -#define CODEC_F1C_LOCATION_SPECIAL_0 (0x7) -#define CODEC_F1C_LOCATION_SPECIAL_1 (0x8) -#define CODEC_F1C_LOCATION_SPECIAL_2 (0x9) - -/* Configuration's devices */ -#define CODEC_F1C_DEVICE_MASK (0xF) -#define CODEC_F1C_DEVICE_SHIFT (20) -#define CODEC_F1C_DEVICE_LINE_OUT (0) -#define CODEC_F1C_DEVICE_SPEAKER (0x1) -#define CODEC_F1C_DEVICE_HP (0x2) -#define CODEC_F1C_DEVICE_CD (0x3) -#define CODEC_F1C_DEVICE_SPDIF_OUT (0x4) -#define CODEC_F1C_DEVICE_DIGITAL_OTHER_OUT (0x5) -#define CODEC_F1C_DEVICE_MODEM_LINE_SIDE (0x6) -#define CODEC_F1C_DEVICE_MODEM_HANDSET_SIDE (0x7) -#define CODEC_F1C_DEVICE_LINE_IN (0x8) -#define CODEC_F1C_DEVICE_AUX (0x9) -#define CODEC_F1C_DEVICE_MIC (0xA) -#define CODEC_F1C_DEVICE_PHONE (0xB) -#define CODEC_F1C_DEVICE_SPDIF_IN (0xC) -#define CODEC_F1C_DEVICE_RESERVED (0xE) -#define CODEC_F1C_DEVICE_OTHER (0xF) - -/* Configuration's Connection type */ -#define CODEC_F1C_CONNECTION_TYPE_MASK (0xF) -#define CODEC_F1C_CONNECTION_TYPE_SHIFT (16) - -#define CODEC_F1C_CONNECTION_TYPE_UNKNOWN (0) -#define CODEC_F1C_CONNECTION_TYPE_1_8INCHES (0x1) -#define CODEC_F1C_CONNECTION_TYPE_1_4INCHES (0x2) -#define CODEC_F1C_CONNECTION_TYPE_ATAPI (0x3) -#define CODEC_F1C_CONNECTION_TYPE_RCA (0x4) -#define CODEC_F1C_CONNECTION_TYPE_OPTICAL (0x5) -#define CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL (0x6) -#define CODEC_F1C_CONNECTION_TYPE_ANALOG (0x7) -#define CODEC_F1C_CONNECTION_TYPE_DIN (0x8) -#define CODEC_F1C_CONNECTION_TYPE_XLR (0x9) -#define CODEC_F1C_CONNECTION_TYPE_RJ_11 (0xA) -#define CODEC_F1C_CONNECTION_TYPE_COMBO (0xB) -#define CODEC_F1C_CONNECTION_TYPE_OTHER (0xF) - -/* Configuration's color */ -#define CODEC_F1C_COLOR_MASK (0xF) -#define CODEC_F1C_COLOR_SHIFT (12) -#define CODEC_F1C_COLOR_UNKNOWN (0) -#define CODEC_F1C_COLOR_BLACK (0x1) -#define CODEC_F1C_COLOR_GREY (0x2) -#define CODEC_F1C_COLOR_BLUE (0x3) -#define CODEC_F1C_COLOR_GREEN (0x4) -#define CODEC_F1C_COLOR_RED (0x5) -#define CODEC_F1C_COLOR_ORANGE (0x6) -#define CODEC_F1C_COLOR_YELLOW (0x7) -#define CODEC_F1C_COLOR_PURPLE (0x8) -#define CODEC_F1C_COLOR_PINK (0x9) -#define CODEC_F1C_COLOR_RESERVED_0 (0xA) -#define CODEC_F1C_COLOR_RESERVED_1 (0xB) -#define CODEC_F1C_COLOR_RESERVED_2 (0xC) -#define CODEC_F1C_COLOR_RESERVED_3 (0xD) -#define CODEC_F1C_COLOR_WHITE (0xE) -#define CODEC_F1C_COLOR_OTHER (0xF) - -/* Configuration's misc */ -#define CODEC_F1C_MISC_MASK (0xF) -#define CODEC_F1C_MISC_SHIFT (8) -#define CODEC_F1C_MISC_JACK_DETECT (0) -#define CODEC_F1C_MISC_RESERVED_0 (1) -#define CODEC_F1C_MISC_RESERVED_1 (2) -#define CODEC_F1C_MISC_RESERVED_2 (3) - -/* Configuration's association */ -#define CODEC_F1C_ASSOCIATION_MASK (0xF) -#define CODEC_F1C_ASSOCIATION_SHIFT (4) -/* Connection's sequence */ -#define CODEC_F1C_SEQ_MASK (0xF) -#define CODEC_F1C_SEQ_SHIFT (0) - -/* Implementation identification (7.3.3.30) */ -#define CODEC_MAKE_F20(bmid, bsku, aid) \ - ( (((bmid) & 0xFFFF) << 16) \ - | (((bsku) & 0xFF) << 8) \ - | (((aid) & 0xFF)) \ - ) - -/* macro definition helping in filling the configuration registers. */ -#define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence) \ - ( ((port_connectivity) << CODEC_F1C_PORT_SHIFT) \ - | ((location) << CODEC_F1C_LOCATION_SHIFT) \ - | ((device) << CODEC_F1C_DEVICE_SHIFT) \ - | ((connection_type) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \ - | ((color) << CODEC_F1C_COLOR_SHIFT) \ - | ((misc) << CODEC_F1C_MISC_SHIFT) \ - | ((association) << CODEC_F1C_ASSOCIATION_SHIFT) \ - | ((sequence))) - - -#ifndef VBOX_WITH_HDA_CODEC_EMU -typedef struct CODECVERB -{ - uint32_t verb; - /* operation bitness mask */ - uint32_t mask; - PFNCODECVERBPROCESSOR pfn; -} CODECVERB; -#endif - -#ifndef VBOX_WITH_HDA_CODEC_EMU -# define TYPE union -#else -# define TYPE struct -typedef struct CODECEMU CODECEMU; -typedef CODECEMU *PCODECEMU; -#endif -TYPE CODECNODE; -typedef TYPE CODECNODE CODECNODE; -typedef TYPE CODECNODE *PCODECNODE; - - -typedef enum -{ - PI_INDEX = 0, /* PCM in */ - PO_INDEX, /* PCM out */ - MC_INDEX, /* Mic in */ - LAST_INDEX -} ENMSOUNDSOURCE; - - -typedef struct CODECState -{ - uint16_t id; - uint16_t u16VendorId; - uint16_t u16DeviceId; - uint8_t u8BSKU; - uint8_t u8AssemblyId; -#ifndef VBOX_WITH_HDA_CODEC_EMU - CODECVERB *pVerbs; - int cVerbs; -#else - PCODECEMU pCodecBackend; -#endif - PCODECNODE pNodes; - QEMUSoundCard card; - /** PCM in */ - SWVoiceIn *SwVoiceIn; - /** PCM out */ - SWVoiceOut *SwVoiceOut; - void *pHDAState; - bool fInReset; -#ifndef VBOX_WITH_HDA_CODEC_EMU - const uint8_t cTotalNodes; - const uint8_t *au8Ports; - const uint8_t *au8Dacs; - const uint8_t *au8AdcVols; - const uint8_t *au8Adcs; - const uint8_t *au8AdcMuxs; - const uint8_t *au8Pcbeeps; - const uint8_t *au8SpdifIns; - const uint8_t *au8SpdifOuts; - const uint8_t *au8DigInPins; - const uint8_t *au8DigOutPins; - const uint8_t *au8Cds; - const uint8_t *au8VolKnobs; - const uint8_t *au8Reserveds; - const uint8_t u8AdcVolsLineIn; - const uint8_t u8DacLineOut; -#endif - DECLR3CALLBACKMEMBER(int, pfnProcess, (struct CODECState *)); - DECLR3CALLBACKMEMBER(void, pfnTransfer, (struct CODECState *pState, ENMSOUNDSOURCE, int avail)); - /* These callbacks are set by Codec implementation */ - DECLR3CALLBACKMEMBER(int, pfnLookup, (struct CODECState *pState, uint32_t verb, PPFNCODECVERBPROCESSOR)); - DECLR3CALLBACKMEMBER(int, pfnReset, (struct CODECState *pState)); - DECLR3CALLBACKMEMBER(int, pfnCodecNodeReset, (struct CODECState *pState, uint8_t, PCODECNODE)); - /* These callbacks are set by codec implementation to answer debugger requests */ - DECLR3CALLBACKMEMBER(void, pfnCodecDbgListNodes, (CODECState *pState, PCDBGFINFOHLP pHlp, const char *pszArgs)); - DECLR3CALLBACKMEMBER(void, pfnCodecDbgSelector, (CODECState *pState, PCDBGFINFOHLP pHlp, const char *pszArgs)); -} CODECState, *PCODECState; - -int codecConstruct(PPDMDEVINS pDevIns, CODECState *pCodecState, PCFGMNODE pCfgHandle); -int codecDestruct(CODECState *pCodecState); -int codecSaveState(CODECState *pCodecState, PSSMHANDLE pSSMHandle); -int codecLoadState(CODECState *pCodecState, PSSMHANDLE pSSMHandle, uint32_t uVersion); -int codecOpenVoice(CODECState *pCodecState, ENMSOUNDSOURCE enmSoundSource, audsettings_t *pAudioSettings); - -#define HDA_SSM_VERSION 4 -#define HDA_SSM_VERSION_1 1 -#define HDA_SSM_VERSION_2 2 -#define HDA_SSM_VERSION_3 3 - -# ifdef VBOX_WITH_HDA_CODEC_EMU -/* */ -struct CODECEMU -{ - DECLR3CALLBACKMEMBER(int, pfnCodecEmuConstruct, (PCODECState pState)); - DECLR3CALLBACKMEMBER(int, pfnCodecEmuDestruct, (PCODECState pState)); - DECLR3CALLBACKMEMBER(int, pfnCodecEmuReset, (PCODECState pState, bool fInit)); -}; -# endif -#endif diff --git a/src/VBox/Devices/Audio/DevIchAc97.cpp b/src/VBox/Devices/Audio/DevIchAc97.cpp index e6bba5a7..84ac678b 100644 --- a/src/VBox/Devices/Audio/DevIchAc97.cpp +++ b/src/VBox/Devices/Audio/DevIchAc97.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -30,50 +30,19 @@ extern "C" { #include "audio.h" } + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ #undef LOG_VOICES #ifndef VBOX //#define USE_MIXER #else -#define USE_MIXER +# define USE_MIXER #endif #define AC97_SSM_VERSION 1 -enum { - AC97_Reset = 0x00, - AC97_Master_Volume_Mute = 0x02, - AC97_Headphone_Volume_Mute = 0x04, - AC97_Master_Volume_Mono_Mute = 0x06, - AC97_Master_Tone_RL = 0x08, - AC97_PC_BEEP_Volume_Mute = 0x0A, - AC97_Phone_Volume_Mute = 0x0C, - AC97_Mic_Volume_Mute = 0x0E, - AC97_Line_In_Volume_Mute = 0x10, - AC97_CD_Volume_Mute = 0x12, - AC97_Video_Volume_Mute = 0x14, - AC97_Aux_Volume_Mute = 0x16, - AC97_PCM_Out_Volume_Mute = 0x18, - AC97_Record_Select = 0x1A, - AC97_Record_Gain_Mute = 0x1C, - AC97_Record_Gain_Mic_Mute = 0x1E, - AC97_General_Purpose = 0x20, - AC97_3D_Control = 0x22, - AC97_AC_97_RESERVED = 0x24, - AC97_Powerdown_Ctrl_Stat = 0x26, - AC97_Extended_Audio_ID = 0x28, - AC97_Extended_Audio_Ctrl_Stat = 0x2A, - AC97_PCM_Front_DAC_Rate = 0x2C, - AC97_PCM_Surround_DAC_Rate = 0x2E, - AC97_PCM_LFE_DAC_Rate = 0x30, - AC97_PCM_LR_ADC_Rate = 0x32, - AC97_MIC_ADC_Rate = 0x34, - AC97_6Ch_Vol_C_LFE_Mute = 0x36, - AC97_6Ch_Vol_L_R_Surround_Mute = 0x38, - AC97_Vendor_Reserved = 0x58, - AC97_Vendor_ID1 = 0x7c, - AC97_Vendor_ID2 = 0x7e -}; - #ifndef VBOX # define SOFT_VOLUME #else @@ -118,23 +87,25 @@ enum { #define GS_MOINT RT_BIT(2) /* ro */ #define GS_MIINT RT_BIT(1) /* ro */ #define GS_GSCI RT_BIT(0) /* rwc */ -#define GS_RO_MASK (GS_B3S12| \ - GS_B2S12| \ - GS_B1S12| \ - GS_S1CR| \ - GS_S0CR| \ - GS_MINT| \ - GS_POINT| \ - GS_PIINT| \ - GS_RSRVD| \ - GS_MOINT| \ +#define GS_RO_MASK (GS_B3S12 | \ + GS_B2S12 | \ + GS_B1S12 | \ + GS_S1CR | \ + GS_S0CR | \ + GS_MINT | \ + GS_POINT | \ + GS_PIINT | \ + GS_RSRVD | \ + GS_MOINT | \ GS_MIINT) #define GS_VALID_MASK (RT_BIT(18) - 1) #define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI) -/** Buffer Descriptor */ -#define BD_IOC RT_BIT(31) /* Interrupt on Completion */ -#define BD_BUP RT_BIT(30) /* Buffer Underrun Policy */ +/** @name Buffer Descriptor + * @{ */ +#define BD_IOC RT_BIT(31) /**< Interrupt on Completion */ +#define BD_BUP RT_BIT(30) /**< Buffer Underrun Policy */ +/** @} */ #define EACS_VRA 1 #define EACS_VRM 8 @@ -155,6 +126,46 @@ enum REC_PHONE }; +enum +{ + AC97_Reset = 0x00, + AC97_Master_Volume_Mute = 0x02, + AC97_Headphone_Volume_Mute = 0x04, + AC97_Master_Volume_Mono_Mute = 0x06, + AC97_Master_Tone_RL = 0x08, + AC97_PC_BEEP_Volume_Mute = 0x0A, + AC97_Phone_Volume_Mute = 0x0C, + AC97_Mic_Volume_Mute = 0x0E, + AC97_Line_In_Volume_Mute = 0x10, + AC97_CD_Volume_Mute = 0x12, + AC97_Video_Volume_Mute = 0x14, + AC97_Aux_Volume_Mute = 0x16, + AC97_PCM_Out_Volume_Mute = 0x18, + AC97_Record_Select = 0x1A, + AC97_Record_Gain_Mute = 0x1C, + AC97_Record_Gain_Mic_Mute = 0x1E, + AC97_General_Purpose = 0x20, + AC97_3D_Control = 0x22, + AC97_AC_97_RESERVED = 0x24, + AC97_Powerdown_Ctrl_Stat = 0x26, + AC97_Extended_Audio_ID = 0x28, + AC97_Extended_Audio_Ctrl_Stat = 0x2A, + AC97_PCM_Front_DAC_Rate = 0x2C, + AC97_PCM_Surround_DAC_Rate = 0x2E, + AC97_PCM_LFE_DAC_Rate = 0x30, + AC97_PCM_LR_ADC_Rate = 0x32, + AC97_MIC_ADC_Rate = 0x34, + AC97_6Ch_Vol_C_LFE_Mute = 0x36, + AC97_6Ch_Vol_L_R_Surround_Mute = 0x38, + AC97_Vendor_Reserved = 0x58, + AC97_Vendor_ID1 = 0x7c, + AC97_Vendor_ID2 = 0x7e +}; + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ typedef struct BD { uint32_t addr; @@ -163,20 +174,27 @@ typedef struct BD typedef struct AC97BusMasterRegs { - uint32_t bdbar; /* rw 0, buffer descriptor list base address register */ - uint8_t civ; /* ro 0, current index value */ - uint8_t lvi; /* rw 0, last valid index */ - uint16_t sr; /* rw 1, status register */ - uint16_t picb; /* ro 0, position in current buffer */ - uint8_t piv; /* ro 0, prefetched index value */ - uint8_t cr; /* rw 0, control register */ - int bd_valid; /* initialized? */ + uint32_t bdbar; /**< rw 0, buffer descriptor list base address register */ + uint8_t civ; /**< ro 0, current index value */ + uint8_t lvi; /**< rw 0, last valid index */ + uint16_t sr; /**< rw 1, status register */ + uint16_t picb; /**< ro 0, position in current buffer */ + uint8_t piv; /**< ro 0, prefetched index value */ + uint8_t cr; /**< rw 0, control register */ + int bd_valid; /**< initialized? */ BD bd; } AC97BusMasterRegs; +/** Pointer to a AC97 bus master register. */ +typedef AC97BusMasterRegs *PAC97BMREG; -typedef struct AC97LinkState +typedef struct AC97STATE { + /** The PCI device state. */ + PCIDevice PciDev; + + /** Audio stuff. */ QEMUSoundCard card; + /** Global Control (Bus Master Control Register) */ uint32_t glob_cnt; /** Global Status (Bus Master Control Register) */ @@ -188,11 +206,11 @@ typedef struct AC97LinkState AC97BusMasterRegs bm_regs[3]; uint8_t mixer_data[256]; /** PCM in */ - SWVoiceIn *voice_pi; + SWVoiceIn *voice_pi; /** PCM out */ - SWVoiceOut *voice_po; + SWVoiceOut *voice_po; /** Mic in */ - SWVoiceIn *voice_mc; + SWVoiceIn *voice_mc; uint8_t silence[128]; int bup_flag; /** Pointer to the device instance. */ @@ -205,10 +223,11 @@ typedef struct AC97LinkState PDMIBASE IBase; /** Base port of the I/O space region. */ RTIOPORT IOPortBase[2]; -} AC97LinkState; +} AC97STATE; +/** Pointer to the AC97 device state. */ +typedef AC97STATE *PAC97STATE; -#define ICHAC97STATE_2_DEVINS(pAC97) ((pAC97)->pDevIns) -#define PCIDEV_2_ICHAC97STATE(pPciDev) ((PCIAC97LinkState *)(pPciDev)) +#define ICHAC97STATE_2_DEVINS(a_pAC97) ((a_pAC97)->pDevIns) enum { @@ -216,12 +235,6 @@ enum BUP_LAST = RT_BIT(1) }; -typedef struct PCIAC97LinkState -{ - PCIDevice dev; - AC97LinkState ac97; -} PCIAC97LinkState; - #define MKREGS(prefix, start) \ enum { \ prefix ## _BDBAR = start, \ @@ -252,53 +265,53 @@ enum CAS = 0x34 }; -#define GET_BM(index) (((index) >> 4) & 3) +#define GET_BM(a_idx) ( ((a_idx) >> 4) & 3 ) -static void po_callback (void *opaque, int free); -static void pi_callback (void *opaque, int avail); -static void mc_callback (void *opaque, int avail); +static void po_callback(void *opaque, int free); +static void pi_callback(void *opaque, int avail); +static void mc_callback(void *opaque, int avail); -static void warm_reset (AC97LinkState *s) +static void warm_reset(PAC97STATE pThis) { - (void) s; + NOREF(pThis); } -static void cold_reset (AC97LinkState * s) +static void cold_reset(PAC97STATE pThis) { - (void) s; + NOREF(pThis); } /** Fetch Buffer Descriptor at _CIV */ -static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) +static void fetch_bd(PAC97STATE pThis, PAC97BMREG pReg) { - PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s); + PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis); uint8_t b[8]; - PDMDevHlpPhysRead (pDevIns, r->bdbar + r->civ * 8, b, sizeof(b)); - r->bd_valid = 1; + PDMDevHlpPhysRead(pDevIns, pReg->bdbar + pReg->civ * 8, b, sizeof(b)); + pReg->bd_valid = 1; #if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64) # error Please adapt the code (audio buffers are little endian)! #else - r->bd.addr = (*(uint32_t *) &b[0]) & ~3; - r->bd.ctl_len = (*(uint32_t *) &b[4]); + pReg->bd.addr = (*(uint32_t *) &b[0]) & ~3; + pReg->bd.ctl_len = (*(uint32_t *) &b[4]); #endif - r->picb = r->bd.ctl_len & 0xffff; - Log (("ac97: bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", - r->civ, r->bd.addr, r->bd.ctl_len >> 16, - r->bd.ctl_len & 0xffff, (r->bd.ctl_len & 0xffff) << 1)); + pReg->picb = pReg->bd.ctl_len & 0xffff; + Log(("ac97: bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", + pReg->civ, pReg->bd.addr, pReg->bd.ctl_len >> 16, + pReg->bd.ctl_len & 0xffff, (pReg->bd.ctl_len & 0xffff) << 1)); } /** * Update the BM status register */ -static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) +static void update_sr(PAC97STATE pThis, PAC97BMREG pReg, uint32_t new_sr) { - PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s); + PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis); int event = 0; int level = 0; uint32_t new_mask = new_sr & SR_INT_MASK; - uint32_t old_mask = r->sr & SR_INT_MASK; - uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT}; + uint32_t old_mask = pReg->sr & SR_INT_MASK; + static uint32_t const masks[] = { GS_PIINT, GS_POINT, GS_MINT }; if (new_mask ^ old_mask) { @@ -308,94 +321,91 @@ static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) event = 1; level = 0; } - else if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) + else if ((new_mask & SR_LVBCI) && (pReg->cr & CR_LVBIE)) { event = 1; level = 1; } - else if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) + else if ((new_mask & SR_BCIS) && (pReg->cr & CR_IOCE)) { event = 1; level = 1; } } - r->sr = new_sr; + pReg->sr = new_sr; - Log (("ac97: IOC%d LVB%d sr=%#x event=%d level=%d\n", - r->sr & SR_BCIS, r->sr & SR_LVBCI, r->sr, event, level)); + Log(("ac97: IOC%d LVB%d sr=%#x event=%d level=%d\n", + pReg->sr & SR_BCIS, pReg->sr & SR_LVBCI, pReg->sr, event, level)); if (event) { if (level) - s->glob_sta |= masks[r - s->bm_regs]; + pThis->glob_sta |= masks[pReg - pThis->bm_regs]; else - s->glob_sta &= ~masks[r - s->bm_regs]; + pThis->glob_sta &= ~masks[pReg - pThis->bm_regs]; - Log (("ac97: set irq level=%d\n", !!level)); - PDMDevHlpPCISetIrq (pDevIns, 0, !!level); + Log(("ac97: set irq level=%d\n", !!level)); + PDMDevHlpPCISetIrq(pDevIns, 0, !!level); } } -static void voice_set_active (AC97LinkState *s, int bm_index, int on) +static void voice_set_active(PAC97STATE pThis, int bm_index, int on) { switch (bm_index) { - case PI_INDEX: AUD_set_active_in (s->voice_pi, on); break; - case PO_INDEX: AUD_set_active_out(s->voice_po, on); break; - case MC_INDEX: AUD_set_active_in (s->voice_mc, on); break; - default: AssertFailed (); - break; + case PI_INDEX: AUD_set_active_in( pThis->voice_pi, on); break; + case PO_INDEX: AUD_set_active_out(pThis->voice_po, on); break; + case MC_INDEX: AUD_set_active_in( pThis->voice_mc, on); break; + default: AssertFailed (); break; } } -static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) +static void reset_bm_regs(PAC97STATE pThis, PAC97BMREG pReg) { - Log (("ac97: reset_bm_regs\n")); - r->bdbar = 0; - r->civ = 0; - r->lvi = 0; + Log(("ac97: reset_bm_regs\n")); + pReg->bdbar = 0; + pReg->civ = 0; + pReg->lvi = 0; /** @todo do we need to do that? */ - update_sr (s, r, SR_DCH); - r->picb = 0; - r->piv = 0; - r->cr = r->cr & CR_DONT_CLEAR_MASK; - r->bd_valid = 0; - - voice_set_active (s, r - s->bm_regs, 0); - memset (s->silence, 0, sizeof (s->silence)); + update_sr(pThis, pReg, SR_DCH); + pReg->picb = 0; + pReg->piv = 0; + pReg->cr = pReg->cr & CR_DONT_CLEAR_MASK; + pReg->bd_valid = 0; + + voice_set_active(pThis, pReg - pThis->bm_regs, 0); + memset(pThis->silence, 0, sizeof(pThis->silence)); } -static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) +static void mixer_store(PAC97STATE pThis, uint32_t i, uint16_t v) { - if (i + 2 > sizeof (s->mixer_data)) + if (i + 2 > sizeof(pThis->mixer_data)) { - Log (("ac97: mixer_store: index %d out of bounds %d\n", - i, sizeof (s->mixer_data))); + Log(("ac97: mixer_store: index %d out of bounds %d\n", i, sizeof(pThis->mixer_data))); return; } - s->mixer_data[i + 0] = v & 0xff; - s->mixer_data[i + 1] = v >> 8; + pThis->mixer_data[i + 0] = v & 0xff; + pThis->mixer_data[i + 1] = v >> 8; } -static uint16_t mixer_load (AC97LinkState *s, uint32_t i) +static uint16_t mixer_load(PAC97STATE pThis, uint32_t i) { uint16_t val; - if (i + 2 > sizeof (s->mixer_data)) + if (i + 2 > sizeof(pThis->mixer_data)) { - Log (("ac97: mixer_store: index %d out of bounds %d\n", - i, sizeof (s->mixer_data))); + Log(("ac97: mixer_store: index %d out of bounds %d\n", i, sizeof(pThis->mixer_data))); val = 0xffff; } else - val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8); + val = pThis->mixer_data[i + 0] | (pThis->mixer_data[i + 1] << 8); return val; } -static void open_voice (AC97LinkState *s, int index, int freq) +static void open_voice(PAC97STATE pThis, int index, int freq) { audsettings_t as; @@ -409,26 +419,23 @@ static void open_voice (AC97LinkState *s, int index, int freq) switch (index) { case PI_INDEX: /* PCM in */ - s->voice_pi = AUD_open_in (&s->card, s->voice_pi, "ac97.pi", - s, pi_callback, &as); + pThis->voice_pi = AUD_open_in(&pThis->card, pThis->voice_pi, "ac97.pi", pThis, pi_callback, &as); #ifdef LOG_VOICES - LogRel (("AC97: open PI freq=%d (%s)\n", freq, s->voice_pi ? "ok" : "FAIL")); + LogRel(("AC97: open PI freq=%d (%s)\n", freq, pThis->voice_pi ? "ok" : "FAIL")); #endif break; case PO_INDEX: /* PCM out */ - s->voice_po = AUD_open_out (&s->card, s->voice_po, "ac97.po", - s, po_callback, &as); + pThis->voice_po = AUD_open_out(&pThis->card, pThis->voice_po, "ac97.po", pThis, po_callback, &as); #ifdef LOG_VOICES - LogRel (("AC97: open PO freq=%d (%s)\n", freq, s->voice_po ? "ok" : "FAIL")); + LogRel(("AC97: open PO freq=%d (%s)\n", freq, pThis->voice_po ? "ok" : "FAIL")); #endif break; case MC_INDEX: /* Mic in */ - s->voice_mc = AUD_open_in (&s->card, s->voice_mc, "ac97.mc", - s, mc_callback, &as); + pThis->voice_mc = AUD_open_in(&pThis->card, pThis->voice_mc, "ac97.mc", pThis, mc_callback, &as); #ifdef LOG_VOICES - LogRel (("AC97: open MC freq=%d (%s)\n", freq, s->voice_mc ? "ok" : "FAIL")); + LogRel(("AC97: open MC freq=%d (%s)\n", freq, pThis->voice_mc ? "ok" : "FAIL")); #endif break; } @@ -438,53 +445,52 @@ static void open_voice (AC97LinkState *s, int index, int freq) switch (index) { case PI_INDEX: - AUD_close_in (&s->card, s->voice_pi); + AUD_close_in(&pThis->card, pThis->voice_pi); #ifdef LOG_VOICES - LogRel (("AC97: Closing PCM IN\n")); + LogRel(("AC97: Closing PCM IN\n")); #endif - s->voice_pi = NULL; + pThis->voice_pi = NULL; break; case PO_INDEX: - AUD_close_out (&s->card, s->voice_po); + AUD_close_out(&pThis->card, pThis->voice_po); #ifdef LOG_VOICES - LogRel (("AC97: Closing PCM OUT\n")); + LogRel(("AC97: Closing PCM OUT\n")); #endif - s->voice_po = NULL; + pThis->voice_po = NULL; break; case MC_INDEX: - AUD_close_in (&s->card, s->voice_mc); + AUD_close_in(&pThis->card, pThis->voice_mc); #ifdef LOG_VOICES - LogRel (("AC97: Closing MIC IN\n")); + LogRel(("AC97: Closing MIC IN\n")); #endif - s->voice_mc = NULL; + pThis->voice_mc = NULL; break; } } } -static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) +static void reset_voices(PAC97STATE pThis, uint8_t active[LAST_INDEX]) { uint16_t freq; - freq = mixer_load (s, AC97_PCM_LR_ADC_Rate); - open_voice (s, PI_INDEX, freq); - AUD_set_active_in (s->voice_pi, active[PI_INDEX]); + freq = mixer_load(pThis, AC97_PCM_LR_ADC_Rate); + open_voice(pThis, PI_INDEX, freq); + AUD_set_active_in(pThis->voice_pi, active[PI_INDEX]); - freq = mixer_load (s, AC97_PCM_Front_DAC_Rate); - open_voice (s, PO_INDEX, freq); - AUD_set_active_out (s->voice_po, active[PO_INDEX]); + freq = mixer_load(pThis, AC97_PCM_Front_DAC_Rate); + open_voice(pThis, PO_INDEX, freq); + AUD_set_active_out(pThis->voice_po, active[PO_INDEX]); - freq = mixer_load (s, AC97_MIC_ADC_Rate); - open_voice (s, MC_INDEX, freq); - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + freq = mixer_load(pThis, AC97_MIC_ADC_Rate); + open_voice(pThis, MC_INDEX, freq); + AUD_set_active_in(pThis->voice_mc, active[MC_INDEX]); } #ifdef USE_MIXER -static void set_volume (AC97LinkState *s, int index, - audmixerctl_t mt, uint32_t val) +static void set_volume(PAC97STATE pThis, int index, audmixerctl_t mt, uint32_t val) { int mute = (val >> MUTE_SHIFT) & 1; uint8_t rvol = VOL_MASK - (val & VOL_MASK); @@ -494,11 +500,11 @@ static void set_volume (AC97LinkState *s, int index, # ifdef SOFT_VOLUME if (index == AC97_Master_Volume_Mute) - AUD_set_volume_out (s->voice_po, mute, lvol, rvol); + AUD_set_volume_out(pThis->voice_po, mute, lvol, rvol); else - AUD_set_volume (mt, &mute, &lvol, &rvol); + AUD_set_volume(mt, &mute, &lvol, &rvol); # else - AUD_set_volume (mt, &mute, &lvol, &rvol); + AUD_set_volume(mt, &mute, &lvol, &rvol); # endif rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); @@ -517,10 +523,10 @@ static void set_volume (AC97LinkState *s, int index, if (val & RT_BIT(13)) val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8); - mixer_store (s, index, val); + mixer_store(pThis, index, val); } -static audrecsource_t ac97_to_aud_record_source (uint8_t i) +static audrecsource_t ac97_to_aud_record_source(uint8_t i) { switch (i) { @@ -530,12 +536,13 @@ static audrecsource_t ac97_to_aud_record_source (uint8_t i) case REC_AUX: return AUD_REC_AUX; case REC_LINE_IN: return AUD_REC_LINE_IN; case REC_PHONE: return AUD_REC_PHONE; - default: Log (("ac97: Unknown record source %d, using MIC\n", i)); - return AUD_REC_MIC; + default: + Log(("ac97: Unknown record source %d, using MIC\n", i)); + return AUD_REC_MIC; } } -static uint8_t aud_to_ac97_record_source (audrecsource_t rs) +static uint8_t aud_to_ac97_record_source(audrecsource_t rs) { switch (rs) { @@ -545,85 +552,85 @@ static uint8_t aud_to_ac97_record_source (audrecsource_t rs) case AUD_REC_AUX: return REC_AUX; case AUD_REC_LINE_IN: return REC_LINE_IN; case AUD_REC_PHONE: return REC_PHONE; - default: Log (("ac97: Unknown audio recording source %d using MIC\n", rs)); - return REC_MIC; + default: + Log(("ac97: Unknown audio recording source %d using MIC\n", rs)); + return REC_MIC; } } -static void record_select (AC97LinkState *s, uint32_t val) +static void record_select(PAC97STATE pThis, uint32_t val) { uint8_t rs = val & REC_MASK; uint8_t ls = (val >> 8) & REC_MASK; - audrecsource_t ars = ac97_to_aud_record_source (rs); - audrecsource_t als = ac97_to_aud_record_source (ls); - AUD_set_record_source (&als, &ars); - rs = aud_to_ac97_record_source (ars); - ls = aud_to_ac97_record_source (als); - mixer_store (s, AC97_Record_Select, rs | (ls << 8)); + audrecsource_t ars = ac97_to_aud_record_source(rs); + audrecsource_t als = ac97_to_aud_record_source(ls); + AUD_set_record_source(&als, &ars); + rs = aud_to_ac97_record_source(ars); + ls = aud_to_ac97_record_source(als); + mixer_store(pThis, AC97_Record_Select, rs | (ls << 8)); } #endif /* USE_MIXER */ -static void mixer_reset (AC97LinkState *s) +static void mixer_reset(PAC97STATE pThis) { uint8_t active[LAST_INDEX]; - Log (("ac97: mixer_reset\n")); - memset (s->mixer_data, 0, sizeof (s->mixer_data)); - memset (active, 0, sizeof (active)); - mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000); - mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - - mixer_store (s, AC97_Phone_Volume_Mute , 0x8008); - mixer_store (s, AC97_Mic_Volume_Mute , 0x8008); - mixer_store (s, AC97_CD_Volume_Mute , 0x8808); - mixer_store (s, AC97_Aux_Volume_Mute , 0x8808); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000); - mixer_store (s, AC97_General_Purpose , 0x0000); - mixer_store (s, AC97_3D_Control , 0x0000); - mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); + Log(("ac97: mixer_reset\n")); + memset(pThis->mixer_data, 0, sizeof(pThis->mixer_data)); + memset(active, 0, sizeof(active)); + mixer_store(pThis, AC97_Reset , 0x0000); /* 6940 */ + mixer_store(pThis, AC97_Master_Volume_Mono_Mute , 0x8000); + mixer_store(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000); + + mixer_store(pThis, AC97_Phone_Volume_Mute , 0x8008); + mixer_store(pThis, AC97_Mic_Volume_Mute , 0x8008); + mixer_store(pThis, AC97_CD_Volume_Mute , 0x8808); + mixer_store(pThis, AC97_Aux_Volume_Mute , 0x8808); + mixer_store(pThis, AC97_Record_Gain_Mic_Mute , 0x8000); + mixer_store(pThis, AC97_General_Purpose , 0x0000); + mixer_store(pThis, AC97_3D_Control , 0x0000); + mixer_store(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f); /* * Sigmatel 9700 (STAC9700) */ - mixer_store (s, AC97_Vendor_ID1 , 0x8384); - mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */ + mixer_store(pThis, AC97_Vendor_ID1 , 0x8384); + mixer_store(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */ - mixer_store (s, AC97_Extended_Audio_ID , 0x0809); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); - mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + mixer_store(pThis, AC97_Extended_Audio_ID , 0x0809); + mixer_store(pThis, AC97_Extended_Audio_Ctrl_Stat, 0x0009); + mixer_store(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80); + mixer_store(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80); + mixer_store(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80); + mixer_store(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80); + mixer_store(pThis, AC97_MIC_ADC_Rate , 0xbb80); #ifdef USE_MIXER - record_select (s, 0); - set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME, 0x8000); - set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808); - set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); + record_select(pThis, 0); + set_volume(pThis, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME, 0x8000); + set_volume(pThis, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808); + set_volume(pThis, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); #else - mixer_store (s, AC97_Record_Select, 0); - mixer_store (s, AC97_Master_Volume_Mute, 0x8000); - mixer_store (s, AC97_PCM_Out_Volume_Mute, 0x8808); - mixer_store (s, AC97_Line_In_Volume_Mute, 0x8808); + mixer_store(pThis, AC97_Record_Select, 0); + mixer_store(pThis, AC97_Master_Volume_Mute, 0x8000); + mixer_store(pThis, AC97_PCM_Out_Volume_Mute, 0x8808); + mixer_store(pThis, AC97_Line_In_Volume_Mute, 0x8808); #endif - reset_voices (s, active); + reset_voices(pThis, active); } -static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int write_audio(PAC97STATE pThis, PAC97BMREG pReg, int max, int *stop) { - PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s); - uint8_t tmpbuf[4096]; - uint32_t addr = r->bd.addr; - uint32_t temp = r->picb << 1; - uint32_t written = 0; - int to_copy = 0; - - temp = audio_MIN (temp, (uint32_t) max); + PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis); + uint8_t tmpbuf[4096]; + uint32_t addr = pReg->bd.addr; + uint32_t temp = pReg->picb << 1; + uint32_t written = 0; + int to_copy = 0; + + temp = audio_MIN(temp, (uint32_t)max); if (!temp) { *stop = 1; @@ -633,11 +640,10 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int copied; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); - PDMDevHlpPhysRead (pDevIns, addr, tmpbuf, to_copy); - copied = AUD_write (s->voice_po, tmpbuf, to_copy); - Log (("ac97: write_audio max=%x to_copy=%x copied=%x\n", - max, to_copy, copied)); + to_copy = audio_MIN(temp, sizeof(tmpbuf)); + PDMDevHlpPhysRead(pDevIns, addr, tmpbuf, to_copy); + copied = AUD_write(pThis->voice_po, tmpbuf, to_copy); + Log(("ac97: write_audio max=%x to_copy=%x copied=%x\n", max, to_copy, copied)); if (!copied) { *stop = 1; @@ -652,43 +658,43 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, { if (to_copy < 4) { - Log (("ac97: whoops\n")); - s->last_samp = 0; + Log(("ac97: whoops\n")); + pThis->last_samp = 0; } else - s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4]; + pThis->last_samp = *(uint32_t *)&tmpbuf[to_copy - 4]; } - r->bd.addr = addr; + pReg->bd.addr = addr; return written; } -static void write_bup (AC97LinkState *s, int elapsed) +static void write_bup(PAC97STATE pThis, int elapsed) { int written = 0; - Log (("ac97: write_bup\n")); - if (!(s->bup_flag & BUP_SET)) + Log(("ac97: write_bup\n")); + if (!(pThis->bup_flag & BUP_SET)) { - if (s->bup_flag & BUP_LAST) + if (pThis->bup_flag & BUP_LAST) { unsigned int i; - uint32_t *p = (uint32_t*)s->silence; - for (i = 0; i < sizeof (s->silence) / 4; i++) - *p++ = s->last_samp; + uint32_t *p = (uint32_t*)pThis->silence; + for (i = 0; i < sizeof(pThis->silence) / 4; i++) + *p++ = pThis->last_samp; } else - memset (s->silence, 0, sizeof (s->silence)); + memset(pThis->silence, 0, sizeof(pThis->silence)); - s->bup_flag |= BUP_SET; + pThis->bup_flag |= BUP_SET; } while (elapsed) { - unsigned int temp = audio_MIN ((unsigned int)elapsed, sizeof (s->silence)); + unsigned int temp = audio_MIN((unsigned int)elapsed, sizeof(pThis->silence)); while (temp) { - int copied = AUD_write (s->voice_po, s->silence, temp); + int copied = AUD_write(pThis->voice_po, pThis->silence, temp); if (!copied) return; temp -= copied; @@ -698,18 +704,17 @@ static void write_bup (AC97LinkState *s, int elapsed) } } -static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) +static int read_audio(PAC97STATE pThis, PAC97BMREG pReg, int max, int *stop) { - PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s); - uint8_t tmpbuf[4096]; - uint32_t addr = r->bd.addr; - uint32_t temp = r->picb << 1; - uint32_t nread = 0; - int to_copy = 0; - SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi; - - temp = audio_MIN (temp, (uint32_t) max); + PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis); + uint8_t tmpbuf[4096]; + uint32_t addr = pReg->bd.addr; + uint32_t temp = pReg->picb << 1; + uint32_t nread = 0; + int to_copy = 0; + SWVoiceIn *voice = (pReg - pThis->bm_regs) == MC_INDEX ? pThis->voice_mc : pThis->voice_pi; + + temp = audio_MIN(temp, (uint32_t)max); if (!temp) { *stop = 1; @@ -719,37 +724,38 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, while (temp) { int acquired; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); - acquired = AUD_read (voice, tmpbuf, to_copy); + to_copy = audio_MIN(temp, sizeof(tmpbuf)); + acquired = AUD_read(voice, tmpbuf, to_copy); if (!acquired) { *stop = 1; break; } - PDMDevHlpPhysWrite (pDevIns, addr, tmpbuf, acquired); + PDMDevHlpPCIPhysWrite(pDevIns, addr, tmpbuf, acquired); temp -= acquired; addr += acquired; nread += acquired; } - r->bd.addr = addr; + pReg->bd.addr = addr; return nread; } -static void transfer_audio (AC97LinkState *s, int index, int elapsed) +static void transfer_audio(PAC97STATE pThis, int index, int elapsed) { - AC97BusMasterRegs *r = &s->bm_regs[index]; - int written = 0, stop = 0; + PAC97BMREG pReg = &pThis->bm_regs[index]; + int written = 0; + int stop = 0; - if (r->sr & SR_DCH) + if (pReg->sr & SR_DCH) { - if (r->cr & CR_RPBM) + if (pReg->cr & CR_RPBM) { switch (index) { - case PO_INDEX: - write_bup (s, elapsed); - break; + case PO_INDEX: + write_bup(pThis, elapsed); + break; } } return; @@ -759,165 +765,154 @@ static void transfer_audio (AC97LinkState *s, int index, int elapsed) { int temp; - if (!r->bd_valid) + if (!pReg->bd_valid) { - Log (("ac97: invalid bd\n")); - fetch_bd (s, r); + Log(("ac97: invalid bd\n")); + fetch_bd(pThis, pReg); } - if (!r->picb) + if (!pReg->picb) { - Log (("ac97: fresh bd %d is empty %#x %#x, skipping\n", - r->civ, r->bd.addr, r->bd.ctl_len)); - if (r->civ == r->lvi) + Log(("ac97: fresh bd %d is empty %#x %#x, skipping\n", pReg->civ, pReg->bd.addr, pReg->bd.ctl_len)); + if (pReg->civ == pReg->lvi) { - r->sr |= SR_DCH; /* CELV? */ - s->bup_flag = 0; + pReg->sr |= SR_DCH; /* CELV? */ + pThis->bup_flag = 0; break; } - r->sr &= ~SR_CELV; - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + pReg->sr &= ~SR_CELV; + pReg->civ = pReg->piv; + pReg->piv = (pReg->piv + 1) % 32; + fetch_bd(pThis, pReg); continue; } switch (index) { case PO_INDEX: - temp = write_audio (s, r, elapsed, &stop); + temp = write_audio(pThis, pReg, elapsed, &stop); written += temp; elapsed -= temp; Assert((temp & 1) == 0); /* Else the following shift won't work */ - r->picb -= (temp >> 1); + pReg->picb -= (temp >> 1); break; case PI_INDEX: case MC_INDEX: - temp = read_audio (s, r, elapsed, &stop); + temp = read_audio(pThis, pReg, elapsed, &stop); elapsed -= temp; Assert((temp & 1) == 0); /* Else the following shift won't work */ - r->picb -= (temp >> 1); + pReg->picb -= (temp >> 1); break; } - Log (("r->picb = %d\n", r->picb)); + Log(("pReg->picb = %d\n", pReg->picb)); - if (!r->picb) + if (!pReg->picb) { - uint32_t new_sr = r->sr & ~SR_CELV; + uint32_t new_sr = pReg->sr & ~SR_CELV; - if (r->bd.ctl_len & BD_IOC) + if (pReg->bd.ctl_len & BD_IOC) new_sr |= SR_BCIS; - if (r->civ == r->lvi) + if (pReg->civ == pReg->lvi) { - Log (("ac97: Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi)); + Log(("ac97: Underrun civ (%d) == lvi (%d)\n", pReg->civ, pReg->lvi)); new_sr |= SR_LVBCI | SR_DCH | SR_CELV; stop = 1; - s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; + pThis->bup_flag = (pReg->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; } else { - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + pReg->civ = pReg->piv; + pReg->piv = (pReg->piv + 1) % 32; + fetch_bd(pThis, pReg); } - update_sr (s, r, new_sr); + update_sr(pThis, pReg, new_sr); } } } -static void pi_callback (void *opaque, int avail) +static void pi_callback(void *opaque, int avail) { - transfer_audio ((AC97LinkState*)opaque, PI_INDEX, avail); + transfer_audio((AC97STATE *)opaque, PI_INDEX, avail); } -static void mc_callback (void *opaque, int avail) +static void mc_callback(void *opaque, int avail) { - transfer_audio ((AC97LinkState*)opaque, MC_INDEX, avail); + transfer_audio((AC97STATE *)opaque, MC_INDEX, avail); } -static void po_callback (void *opaque, int free) +static void po_callback(void *opaque, int free) { - transfer_audio ((AC97LinkState*)opaque, PO_INDEX, free); + transfer_audio((AC97STATE *)opaque, PO_INDEX, free); } /** - * Port I/O Handler for IN operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument. - * @param uPort Port number used for the IN operation. - * @param pu32 Where to store the result. - * @param cb Number of bytes read. + * @callback_method_impl{FNIOMIOPORTIN} */ -static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t *pu32, unsigned cb) +static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) { - PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser; - AC97LinkState *s = &d->ac97; + PAC97STATE pThis = (PAC97STATE)pvUser; switch (cb) { case 1: { - AC97BusMasterRegs *r = NULL; - uint32_t index = Port - d->ac97.IOPortBase[1]; + PAC97BMREG pReg = NULL; + uint32_t index = Port - pThis->IOPortBase[1]; *pu32 = ~0U; switch (index) { case CAS: /* Codec Access Semaphore Register */ - Log (("ac97: CAS %d\n", s->cas)); - *pu32 = s->cas; - s->cas = 1; + Log(("ac97: CAS %d\n", pThis->cas)); + *pu32 = pThis->cas; + pThis->cas = 1; break; case PI_CIV: case PO_CIV: case MC_CIV: /* Current Index Value Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->civ; - Log (("ac97: CIV[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->civ; + Log(("ac97: CIV[%d] -> %#x\n", GET_BM(index), *pu32)); break; case PI_LVI: case PO_LVI: case MC_LVI: /* Last Valid Index Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->lvi; - Log (("ac97: LVI[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->lvi; + Log(("ac97: LVI[%d] -> %#x\n", GET_BM(index), *pu32)); break; case PI_PIV: case PO_PIV: case MC_PIV: /* Prefetched Index Value Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->piv; - Log (("ac97: PIV[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->piv; + Log(("ac97: PIV[%d] -> %#x\n", GET_BM(index), *pu32)); break; case PI_CR: case PO_CR: case MC_CR: /* Control Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->cr; - Log (("ac97: CR[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->cr; + Log(("ac97: CR[%d] -> %#x\n", GET_BM(index), *pu32)); break; case PI_SR: case PO_SR: case MC_SR: /* Status Register (lower part) */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->sr & 0xff; - Log (("ac97: SRb[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->sr & 0xff; + Log(("ac97: SRb[%d] -> %#x\n", GET_BM(index), *pu32)); break; default: - Log (("ac97: U nabm readb %#x -> %#x\n", Port, *pu32)); + Log(("ac97: U nabm readb %#x -> %#x\n", Port, *pu32)); break; } break; @@ -925,8 +920,8 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser case 2: { - AC97BusMasterRegs *r = NULL; - uint32_t index = Port - d->ac97.IOPortBase[1]; + PAC97BMREG pReg = NULL; + uint32_t index = Port - pThis->IOPortBase[1]; *pu32 = ~0U; switch (index) @@ -935,20 +930,20 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser case PO_SR: case MC_SR: /* Status Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->sr; - Log (("ac97: SR[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->sr; + Log(("ac97: SR[%d] -> %#x\n", GET_BM(index), *pu32)); break; case PI_PICB: case PO_PICB: case MC_PICB: /* Position in Current Buffer Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->picb; - Log (("ac97: PICB[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->picb; + Log(("ac97: PICB[%d] -> %#x\n", GET_BM(index), *pu32)); break; default: - Log (("ac97: U nabm readw %#x -> %#x\n", Port, *pu32)); + Log(("ac97: U nabm readw %#x -> %#x\n", Port, *pu32)); break; } break; @@ -956,8 +951,8 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser case 4: { - AC97BusMasterRegs *r = NULL; - uint32_t index = Port - d->ac97.IOPortBase[1]; + PAC97BMREG pReg = NULL; + uint32_t index = Port - pThis->IOPortBase[1]; *pu32 = ~0U; switch (index) @@ -966,9 +961,9 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser case PO_BDBAR: case MC_BDBAR: /* Buffer Descriptor Base Address Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->bdbar; - Log (("ac97: BMADDR[%d] -> %#x\n", GET_BM (index), *pu32)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->bdbar; + Log(("ac97: BMADDR[%d] -> %#x\n", GET_BM(index), *pu32)); break; case PI_CIV: case PO_CIV: @@ -976,10 +971,9 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser /* 32-bit access: Current Index Value Register + * Last Valid Index Register + * Status Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->civ | (r->lvi << 8) | (r->sr << 16); - Log (("ac97: CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index), - r->civ, r->lvi, r->sr)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->civ | (pReg->lvi << 8) | (pReg->sr << 16); + Log(("ac97: CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM(index), pReg->civ, pReg->lvi, pReg->sr)); break; case PI_PICB: case PO_PICB: @@ -987,23 +981,22 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser /* 32-bit access: Position in Current Buffer Register + * Prefetched Index Value Register + * Control Register */ - r = &s->bm_regs[GET_BM (index)]; - *pu32 = r->picb | (r->piv << 16) | (r->cr << 24); - Log (("ac97: PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index), - *pu32, r->picb, r->piv, r->cr)); + pReg = &pThis->bm_regs[GET_BM(index)]; + *pu32 = pReg->picb | (pReg->piv << 16) | (pReg->cr << 24); + Log(("ac97: PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM(index), *pu32, pReg->picb, pReg->piv, pReg->cr)); break; case GLOB_CNT: /* Global Control */ - *pu32 = s->glob_cnt; - Log (("ac97: glob_cnt -> %#x\n", *pu32)); + *pu32 = pThis->glob_cnt; + Log(("ac97: glob_cnt -> %#x\n", *pu32)); break; case GLOB_STA: /* Global Status */ - *pu32 = s->glob_sta | GS_S0CR; - Log (("ac97: glob_sta -> %#x\n", *pu32)); + *pu32 = pThis->glob_sta | GS_S0CR; + Log(("ac97: glob_sta -> %#x\n", *pu32)); break; default: - Log (("ac97: U nabm readl %#x -> %#x\n", Port, *pu32)); + Log(("ac97: U nabm readl %#x -> %#x\n", Port, *pu32)); break; } break; @@ -1016,81 +1009,72 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser } /** - * Port I/O Handler for OUT operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument. - * @param uPort Port number used for the IN operation. - * @param u32 The value to output. - * @param cb The value size in bytes. + * @callback_method_impl{FNIOMIOPORTOUT} */ -static DECLCALLBACK(int) ichac97IOPortNABMWrite (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t u32, unsigned cb) +static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) { - PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser; - AC97LinkState *s = &d->ac97; + PAC97STATE pThis = (PAC97STATE)pvUser; switch (cb) { case 1: { - AC97BusMasterRegs *r = NULL; - uint32_t index = Port - d->ac97.IOPortBase[1]; + PAC97BMREG pReg = NULL; + uint32_t index = Port - pThis->IOPortBase[1]; switch (index) { case PI_LVI: case PO_LVI: case MC_LVI: /* Last Valid Index */ - r = &s->bm_regs[GET_BM (index)]; - if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { - r->sr &= ~(SR_DCH | SR_CELV); - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); + pReg = &pThis->bm_regs[GET_BM(index)]; + if ((pReg->cr & CR_RPBM) && (pReg->sr & SR_DCH)) + { + pReg->sr &= ~(SR_DCH | SR_CELV); + pReg->civ = pReg->piv; + pReg->piv = (pReg->piv + 1) % 32; + fetch_bd(pThis, pReg); } - r->lvi = u32 % 32; - Log (("ac97: LVI[%d] <- %#x\n", GET_BM (index), u32)); + pReg->lvi = u32 % 32; + Log(("ac97: LVI[%d] <- %#x\n", GET_BM(index), u32)); break; case PI_CR: case PO_CR: case MC_CR: /* Control Register */ - r = &s->bm_regs[GET_BM (index)]; + pReg = &pThis->bm_regs[GET_BM(index)]; if (u32 & CR_RR) - reset_bm_regs (s, r); + reset_bm_regs(pThis, pReg); else { - r->cr = u32 & CR_VALID_MASK; - if (!(r->cr & CR_RPBM)) + pReg->cr = u32 & CR_VALID_MASK; + if (!(pReg->cr & CR_RPBM)) { - voice_set_active (s, r - s->bm_regs, 0); - r->sr |= SR_DCH; + voice_set_active(pThis, pReg - pThis->bm_regs, 0); + pReg->sr |= SR_DCH; } else { - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); - r->sr &= ~SR_DCH; - voice_set_active (s, r - s->bm_regs, 1); + pReg->civ = pReg->piv; + pReg->piv = (pReg->piv + 1) % 32; + fetch_bd(pThis, pReg); + pReg->sr &= ~SR_DCH; + voice_set_active(pThis, pReg - pThis->bm_regs, 1); } } - Log (("ac97: CR[%d] <- %#x (cr %#x)\n", GET_BM (index), u32, r->cr)); + Log(("ac97: CR[%d] <- %#x (cr %#x)\n", GET_BM(index), u32, pReg->cr)); break; case PI_SR: case PO_SR: case MC_SR: /* Status Register */ - r = &s->bm_regs[GET_BM (index)]; - r->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(u32 & SR_WCLEAR_MASK)); - Log (("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM (index), u32, r->sr)); + pReg = &pThis->bm_regs[GET_BM(index)]; + pReg->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK); + update_sr(pThis, pReg, pReg->sr & ~(u32 & SR_WCLEAR_MASK)); + Log(("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM(index), u32, pReg->sr)); break; default: - Log (("ac97: U nabm writeb %#x <- %#x\n", Port, u32)); + Log(("ac97: U nabm writeb %#x <- %#x\n", Port, u32)); break; } break; @@ -1098,21 +1082,21 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite (PPDMDEVINS pDevIns, void *pvUse case 2: { - AC97BusMasterRegs *r = NULL; - uint32_t index = Port - d->ac97.IOPortBase[1]; + PAC97BMREG pReg = NULL; + uint32_t index = Port - pThis->IOPortBase[1]; switch (index) { case PI_SR: case PO_SR: case MC_SR: /* Status Register */ - r = &s->bm_regs[GET_BM (index)]; - r->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(u32 & SR_WCLEAR_MASK)); - Log (("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM (index), u32, r->sr)); + pReg = &pThis->bm_regs[GET_BM(index)]; + pReg->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK); + update_sr(pThis, pReg, pReg->sr & ~(u32 & SR_WCLEAR_MASK)); + Log(("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM(index), u32, pReg->sr)); break; default: - Log (("ac97: U nabm writew %#x <- %#x\n", Port, u32)); + Log(("ac97: U nabm writew %#x <- %#x\n", Port, u32)); break; } break; @@ -1120,37 +1104,36 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite (PPDMDEVINS pDevIns, void *pvUse case 4: { - AC97BusMasterRegs *r = NULL; - uint32_t index = Port - d->ac97.IOPortBase[1]; + PAC97BMREG pReg = NULL; + uint32_t index = Port - pThis->IOPortBase[1]; switch (index) { case PI_BDBAR: case PO_BDBAR: case MC_BDBAR: /* Buffer Descriptor list Base Address Register */ - r = &s->bm_regs[GET_BM (index)]; - r->bdbar = u32 & ~3; - Log (("ac97: BDBAR[%d] <- %#x (bdbar %#x)\n", - GET_BM (index), u32, r->bdbar)); + pReg = &pThis->bm_regs[GET_BM(index)]; + pReg->bdbar = u32 & ~3; + Log(("ac97: BDBAR[%d] <- %#x (bdbar %#x)\n", GET_BM(index), u32, pReg->bdbar)); break; case GLOB_CNT: /* Global Control */ if (u32 & GC_WR) - warm_reset (s); + warm_reset(pThis); if (u32 & GC_CR) - cold_reset (s); + cold_reset(pThis); if (!(u32 & (GC_WR | GC_CR))) - s->glob_cnt = u32 & GC_VALID_MASK; - Log (("ac97: glob_cnt <- %#x (glob_cnt %#x)\n", u32, s->glob_cnt)); + pThis->glob_cnt = u32 & GC_VALID_MASK; + Log(("ac97: glob_cnt <- %#x (glob_cnt %#x)\n", u32, pThis->glob_cnt)); break; case GLOB_STA: /* Global Status */ - s->glob_sta &= ~(u32 & GS_WCLEAR_MASK); - s->glob_sta |= (u32 & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; - Log (("ac97: glob_sta <- %#x (glob_sta %#x)\n", u32, s->glob_sta)); + pThis->glob_sta &= ~(u32 & GS_WCLEAR_MASK); + pThis->glob_sta |= (u32 & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; + Log(("ac97: glob_sta <- %#x (glob_sta %#x)\n", u32, pThis->glob_sta)); break; default: - Log (("ac97: U nabm writel %#x <- %#x\n", Port, u32)); + Log(("ac97: U nabm writel %#x <- %#x\n", Port, u32)); break; } break; @@ -1164,51 +1147,41 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite (PPDMDEVINS pDevIns, void *pvUse } /** - * Port I/O Handler for IN operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument. - * @param uPort Port number used for the IN operation. - * @param pu32 Where to store the result. - * @param cb Number of bytes read. + * @callback_method_impl{FNIOMIOPORTIN} */ -static DECLCALLBACK(int) ichac97IOPortNAMRead (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t *pu32, unsigned cb) +static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb) { - PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser; - AC97LinkState *s = &d->ac97; + PAC97STATE pThis = (PAC97STATE)pvUser; switch (cb) { case 1: { - Log (("ac97: U nam readb %#x\n", Port)); - s->cas = 0; + Log(("ac97: U nam readb %#x\n", Port)); + pThis->cas = 0; *pu32 = ~0U; break; } case 2: { - uint32_t index = Port - d->ac97.IOPortBase[0]; + uint32_t index = Port - pThis->IOPortBase[0]; *pu32 = ~0U; - s->cas = 0; + pThis->cas = 0; switch (index) { - default: - *pu32 = mixer_load (s, index); - Log (("ac97: nam readw %#x -> %#x\n", Port, *pu32)); - break; + default: + *pu32 = mixer_load(pThis, index); + Log(("ac97: nam readw %#x -> %#x\n", Port, *pu32)); + break; } break; } case 4: { - Log (("ac97: U nam readl %#x\n", Port)); - s->cas = 0; + Log(("ac97: U nam readl %#x\n", Port)); + pThis->cas = 0; *pu32 = ~0U; break; } @@ -1220,133 +1193,112 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead (PPDMDEVINS pDevIns, void *pvUser, } /** - * Port I/O Handler for OUT operations. - * - * @returns VBox status code. - * - * @param pDevIns The device instance. - * @param pvUser User argument. - * @param uPort Port number used for the IN operation. - * @param u32 The value to output. - * @param cb The value size in bytes. + * @callback_method_impl{FNIOMIOPORTOUT} */ -static DECLCALLBACK(int) ichac97IOPortNAMWrite (PPDMDEVINS pDevIns, void *pvUser, - RTIOPORT Port, uint32_t u32, unsigned cb) +static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb) { - PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser; - AC97LinkState *s = &d->ac97; + PAC97STATE pThis = (PAC97STATE)pvUser; switch (cb) { case 1: { - Log (("ac97: U nam writeb %#x <- %#x\n", Port, u32)); - s->cas = 0; + Log(("ac97: U nam writeb %#x <- %#x\n", Port, u32)); + pThis->cas = 0; break; } case 2: { - uint32_t index = Port - d->ac97.IOPortBase[0]; - s->cas = 0; + uint32_t index = Port - pThis->IOPortBase[0]; + pThis->cas = 0; switch (index) { case AC97_Reset: - mixer_reset (s); + mixer_reset(pThis); break; case AC97_Powerdown_Ctrl_Stat: u32 &= ~0xf; - u32 |= mixer_load (s, index) & 0xf; - mixer_store (s, index, u32); + u32 |= mixer_load(pThis, index) & 0xf; + mixer_store(pThis, index, u32); break; #ifdef USE_MIXER case AC97_Master_Volume_Mute: - set_volume (s, index, AUD_MIXER_VOLUME, u32); + set_volume(pThis, index, AUD_MIXER_VOLUME, u32); break; case AC97_PCM_Out_Volume_Mute: - set_volume (s, index, AUD_MIXER_PCM, u32); + set_volume(pThis, index, AUD_MIXER_PCM, u32); break; case AC97_Line_In_Volume_Mute: - set_volume (s, index, AUD_MIXER_LINE_IN, u32); + set_volume(pThis, index, AUD_MIXER_LINE_IN, u32); break; case AC97_Record_Select: - record_select (s, u32); + record_select(pThis, u32); break; #else /* !USE_MIXER */ case AC97_Master_Volume_Mute: case AC97_PCM_Out_Volume_Mute: case AC97_Line_In_Volume_Mute: case AC97_Record_Select: - mixer_store (s, index, u32); + mixer_store(pThis, index, u32); break; #endif /* !USE_MIXER */ case AC97_Vendor_ID1: case AC97_Vendor_ID2: - Log (("ac97: Attempt to write vendor ID to %#x\n", u32)); + Log(("ac97: Attempt to write vendor ID to %#x\n", u32)); break; case AC97_Extended_Audio_ID: - Log (("ac97: Attempt to write extended audio ID to %#x\n", u32)); + Log(("ac97: Attempt to write extended audio ID to %#x\n", u32)); break; case AC97_Extended_Audio_Ctrl_Stat: if (!(u32 & EACS_VRA)) { - mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); - open_voice (s, PI_INDEX, 48000); - open_voice (s, PO_INDEX, 48000); + mixer_store(pThis, AC97_PCM_Front_DAC_Rate, 0xbb80); + mixer_store(pThis, AC97_PCM_LR_ADC_Rate, 0xbb80); + open_voice(pThis, PI_INDEX, 48000); + open_voice(pThis, PO_INDEX, 48000); } if (!(u32 & EACS_VRM)) { - mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); - open_voice (s, MC_INDEX, 48000); + mixer_store(pThis, AC97_MIC_ADC_Rate, 0xbb80); + open_voice(pThis, MC_INDEX, 48000); } - Log (("ac97: Setting extended audio control to %#x\n", u32)); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, u32); + Log(("ac97: Setting extended audio control to %#x\n", u32)); + mixer_store(pThis, AC97_Extended_Audio_Ctrl_Stat, u32); break; case AC97_PCM_Front_DAC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) + if (mixer_load(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, u32); + mixer_store(pThis, index, u32); Log(("ac97: Set front DAC rate to %d\n", u32)); - open_voice (s, PO_INDEX, u32); + open_voice(pThis, PO_INDEX, u32); } else - { - Log (("ac97: Attempt to set front DAC rate to %d, " - "but VRA is not set\n", - u32)); - } + Log(("ac97: Attempt to set front DAC rate to %d, but VRA is not set\n", u32)); break; case AC97_MIC_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) + if (mixer_load(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store (s, index, u32); - Log (("ac97: Set MIC ADC rate to %d\n", u32)); - open_voice (s, MC_INDEX, u32); + mixer_store(pThis, index, u32); + Log(("ac97: Set MIC ADC rate to %d\n", u32)); + open_voice(pThis, MC_INDEX, u32); } else - { - Log (("ac97: Attempt to set MIC ADC rate to %d, " - "but VRM is not set\n", - u32)); - } + Log(("ac97: Attempt to set MIC ADC rate to %d, but VRM is not set\n", u32)); break; case AC97_PCM_LR_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) + if (mixer_load(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, u32); - Log (("ac97: Set front LR ADC rate to %d\n", u32)); - open_voice (s, PI_INDEX, u32); + mixer_store(pThis, index, u32); + Log(("ac97: Set front LR ADC rate to %d\n", u32)); + open_voice(pThis, PI_INDEX, u32); } else - { - Log (("ac97: Attempt to set LR ADC rate to %d, but VRA is not set\n", - u32)); - } + Log(("ac97: Attempt to set LR ADC rate to %d, but VRA is not set\n", u32)); break; default: - Log (("ac97: U nam writew %#x <- %#x\n", Port, u32)); - mixer_store (s, index, u32); + Log(("ac97: U nam writew %#x <- %#x\n", Port, u32)); + mixer_store(pThis, index, u32); break; } break; @@ -1354,8 +1306,8 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite (PPDMDEVINS pDevIns, void *pvUser case 4: { - Log (("ac97: U nam writel %#x <- %#x\n", Port, u32)); - s->cas = 0; + Log(("ac97: U nam writel %#x <- %#x\n", Port, u32)); + pThis->cas = 0; break; } @@ -1366,196 +1318,170 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite (PPDMDEVINS pDevIns, void *pvUser return VINF_SUCCESS; } + /** - * Callback function for mapping a PCI I/O region. - * - * @return VBox status code. - * @param pPciDev Pointer to PCI device. - * Use pPciDev->pDevIns to get the device instance. - * @param iRegion The region number. - * @param GCPhysAddress Physical address of the region. - * If iType is PCI_ADDRESS_SPACE_IO, this is an - * I/O port, else it's a physical address. - * This address is *NOT* relative - * to pci_mem_base like earlier! - * @param enmType One of the PCI_ADDRESS_SPACE_* values. + * @callback_method_impl{FNPCIIOREGIONMAP} */ -static DECLCALLBACK(int) ichac97IOPortMap (PPCIDEVICE pPciDev, int iRegion, - RTGCPHYS GCPhysAddress, uint32_t cb, - PCIADDRESSSPACE enmType) +static DECLCALLBACK(int) ichac97IOPortMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, + PCIADDRESSSPACE enmType) { - int rc; PPDMDEVINS pDevIns = pPciDev->pDevIns; + PAC97STATE pThis = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev); RTIOPORT Port = (RTIOPORT)GCPhysAddress; - PCIAC97LinkState *pThis = PCIDEV_2_ICHAC97STATE(pPciDev); + int rc; Assert(enmType == PCI_ADDRESS_SPACE_IO); Assert(cb >= 0x20); if (iRegion == 0) - rc = PDMDevHlpIOPortRegister (pDevIns, Port, 256, pThis, - ichac97IOPortNAMWrite, ichac97IOPortNAMRead, - NULL, NULL, "ICHAC97 NAM"); + rc = PDMDevHlpIOPortRegister(pDevIns, Port, 256, pThis, + ichac97IOPortNAMWrite, ichac97IOPortNAMRead, + NULL, NULL, "ICHAC97 NAM"); else - rc = PDMDevHlpIOPortRegister (pDevIns, Port, 64, pThis, - ichac97IOPortNABMWrite, ichac97IOPortNABMRead, - NULL, NULL, "ICHAC97 NABM"); + rc = PDMDevHlpIOPortRegister(pDevIns, Port, 64, pThis, + ichac97IOPortNABMWrite, ichac97IOPortNABMRead, + NULL, NULL, "ICHAC97 NABM"); if (RT_FAILURE(rc)) return rc; - pThis->ac97.IOPortBase[iRegion] = Port; + pThis->IOPortBase[iRegion] = Port; return VINF_SUCCESS; } + /** - * Saves a state of the AC'97 device. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param pSSMHandle The handle to save the state to. + * @callback_method_impl{FNSSMDEVSAVEEXEC} */ -static DECLCALLBACK(int) ichac97SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle) +static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) { - PCIAC97LinkState *pThis = PDMINS_2_DATA(pDevIns, PCIAC97LinkState *); - size_t i; - uint8_t active[LAST_INDEX]; - AC97LinkState *s = &pThis->ac97; + PAC97STATE pThis = PDMINS_2_DATA(pDevIns, AC97STATE *); - SSMR3PutU32 (pSSMHandle, s->glob_cnt); - SSMR3PutU32 (pSSMHandle, s->glob_sta); - SSMR3PutU32 (pSSMHandle, s->cas); + SSMR3PutU32(pSSM, pThis->glob_cnt); + SSMR3PutU32(pSSM, pThis->glob_sta); + SSMR3PutU32(pSSM, pThis->cas); - for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) + for (unsigned i = 0; i < RT_ELEMENTS(pThis->bm_regs); i++) { - AC97BusMasterRegs *r = &s->bm_regs[i]; - SSMR3PutU32 (pSSMHandle, r->bdbar); - SSMR3PutU8 (pSSMHandle, r->civ); - SSMR3PutU8 (pSSMHandle, r->lvi); - SSMR3PutU16 (pSSMHandle, r->sr); - SSMR3PutU16 (pSSMHandle, r->picb); - SSMR3PutU8 (pSSMHandle, r->piv); - SSMR3PutU8 (pSSMHandle, r->cr); - SSMR3PutS32 (pSSMHandle, r->bd_valid); - SSMR3PutU32 (pSSMHandle, r->bd.addr); - SSMR3PutU32 (pSSMHandle, r->bd.ctl_len); + PAC97BMREG pReg = &pThis->bm_regs[i]; + SSMR3PutU32(pSSM, pReg->bdbar); + SSMR3PutU8( pSSM, pReg->civ); + SSMR3PutU8( pSSM, pReg->lvi); + SSMR3PutU16(pSSM, pReg->sr); + SSMR3PutU16(pSSM, pReg->picb); + SSMR3PutU8( pSSM, pReg->piv); + SSMR3PutU8( pSSM, pReg->cr); + SSMR3PutS32(pSSM, pReg->bd_valid); + SSMR3PutU32(pSSM, pReg->bd.addr); + SSMR3PutU32(pSSM, pReg->bd.ctl_len); } - SSMR3PutMem (pSSMHandle, s->mixer_data, sizeof (s->mixer_data)); + SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data)); - active[PI_INDEX] = AUD_is_active_in (s->voice_pi) ? 1 : 0; - active[PO_INDEX] = AUD_is_active_out (s->voice_po) ? 1 : 0; - active[MC_INDEX] = AUD_is_active_in (s->voice_mc) ? 1 : 0; - SSMR3PutMem (pSSMHandle, active, sizeof (active)); + uint8_t active[LAST_INDEX]; + active[PI_INDEX] = AUD_is_active_in( pThis->voice_pi) ? 1 : 0; + active[PO_INDEX] = AUD_is_active_out(pThis->voice_po) ? 1 : 0; + active[MC_INDEX] = AUD_is_active_in( pThis->voice_mc) ? 1 : 0; + SSMR3PutMem(pSSM, active, sizeof(active)); return VINF_SUCCESS; } + /** - * Loads a saved AC'97 device state. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param pSSMHandle The handle to the saved state. - * @param uVersion The data unit version number. - * @param uPass The data pass. + * @callback_method_impl{FNSSMDEVLOADEXEC} */ -static DECLCALLBACK(int) ichac97LoadExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, - uint32_t uVersion, uint32_t uPass) +static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) { - PCIAC97LinkState *pThis = PDMINS_2_DATA(pDevIns, PCIAC97LinkState *); - AC97LinkState *s = &pThis->ac97; - uint8_t active[LAST_INDEX]; - size_t i; + PAC97STATE pThis = PDMINS_2_DATA(pDevIns, AC97STATE *); AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%d\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION); - Assert (uPass == SSM_PASS_FINAL); NOREF(uPass); + Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); - SSMR3GetU32 (pSSMHandle, &s->glob_cnt); - SSMR3GetU32 (pSSMHandle, &s->glob_sta); - SSMR3GetU32 (pSSMHandle, &s->cas); + SSMR3GetU32(pSSM, &pThis->glob_cnt); + SSMR3GetU32(pSSM, &pThis->glob_sta); + SSMR3GetU32(pSSM, &pThis->cas); - for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i) + for (unsigned i = 0; i < RT_ELEMENTS(pThis->bm_regs); i++) { - AC97BusMasterRegs *r = &s->bm_regs[i]; - SSMR3GetU32 (pSSMHandle, &r->bdbar); - SSMR3GetU8 (pSSMHandle, &r->civ); - SSMR3GetU8 (pSSMHandle, &r->lvi); - SSMR3GetU16 (pSSMHandle, &r->sr); - SSMR3GetU16 (pSSMHandle, &r->picb); - SSMR3GetU8 (pSSMHandle, &r->piv); - SSMR3GetU8 (pSSMHandle, &r->cr); - SSMR3GetS32 (pSSMHandle, &r->bd_valid); - SSMR3GetU32 (pSSMHandle, &r->bd.addr); - SSMR3GetU32 (pSSMHandle, &r->bd.ctl_len); + PAC97BMREG pReg = &pThis->bm_regs[i]; + SSMR3GetU32(pSSM, &pReg->bdbar); + SSMR3GetU8( pSSM, &pReg->civ); + SSMR3GetU8( pSSM, &pReg->lvi); + SSMR3GetU16(pSSM, &pReg->sr); + SSMR3GetU16(pSSM, &pReg->picb); + SSMR3GetU8( pSSM, &pReg->piv); + SSMR3GetU8( pSSM, &pReg->cr); + SSMR3GetS32(pSSM, &pReg->bd_valid); + SSMR3GetU32(pSSM, &pReg->bd.addr); + SSMR3GetU32(pSSM, &pReg->bd.ctl_len); } - SSMR3GetMem (pSSMHandle, s->mixer_data, sizeof (s->mixer_data)); - SSMR3GetMem (pSSMHandle, active, sizeof (active)); + + SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data)); + uint8_t active[LAST_INDEX]; + SSMR3GetMem(pSSM, active, sizeof(active)); #ifdef USE_MIXER - record_select (s, mixer_load (s, AC97_Record_Select)); -# define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) - V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); - V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); - V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); + record_select(pThis, mixer_load(pThis, AC97_Record_Select)); +# define V_(a, b) set_volume(pThis, a, b, mixer_load(pThis, a)) + V_(AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); + V_(AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); + V_(AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); # undef V_ #endif /* USE_MIXER */ - reset_voices (s, active); + reset_voices(pThis, active); - s->bup_flag = 0; - s->last_samp = 0; + pThis->bup_flag = 0; + pThis->last_samp = 0; return VINF_SUCCESS; } + /** - * Reset notification. - * - * @returns VBox status. - * @param pDevIns The device instance data. + * @interface_method_impl{PDMIBASE,pfnQueryInterface} + */ +static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, const char *pszIID) +{ + PAC97STATE pThis = RT_FROM_MEMBER(pInterface, AC97STATE, IBase); + Assert(&pThis->IBase == pInterface); + + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase); + return NULL; +} + + +/** + * @interface_method_impl{PDMDEVREG,pfnReset} * - * @remark The original sources didn't install a reset handler, but it seems to + * @remarks The original sources didn't install a reset handler, but it seems to * make sense to me so we'll do it. */ -static DECLCALLBACK(void) ac97Reset (PPDMDEVINS pDevIns) +static DECLCALLBACK(void) ac97Reset(PPDMDEVINS pDevIns) { - PCIAC97LinkState *pThis = PDMINS_2_DATA(pDevIns, PCIAC97LinkState *); + PAC97STATE pThis = PDMINS_2_DATA(pDevIns, AC97STATE *); /* * Reset the device state (will need pDrv later). */ - reset_bm_regs (&pThis->ac97, &pThis->ac97.bm_regs[0]); - reset_bm_regs (&pThis->ac97, &pThis->ac97.bm_regs[1]); - reset_bm_regs (&pThis->ac97, &pThis->ac97.bm_regs[2]); + reset_bm_regs(pThis, &pThis->bm_regs[0]); + reset_bm_regs(pThis, &pThis->bm_regs[1]); + reset_bm_regs(pThis, &pThis->bm_regs[2]); /* * Reset the mixer too. The Windows XP driver seems to rely on * this. At least it wants to read the vendor id before it resets * the codec manually. */ - mixer_reset (&pThis->ac97); + mixer_reset(pThis); } -/** - * @interface_method_impl{PDMIBASE,pfnQueryInterface} - */ -static DECLCALLBACK(void *) ichac97QueryInterface (struct PDMIBASE *pInterface, - const char *pszIID) -{ - PCIAC97LinkState *pThis = RT_FROM_MEMBER(pInterface, PCIAC97LinkState, ac97.IBase); - Assert(&pThis->ac97.IBase == pInterface); - - PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->ac97.IBase); - return NULL; -} /** * @interface_method_impl{PDMDEVREG,pfnConstruct} */ -static DECLCALLBACK(int) ichac97Construct (PPDMDEVINS pDevIns, int iInstance, - PCFGMNODE pCfgHandle) +static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { - PCIAC97LinkState *pThis = PDMINS_2_DATA(pDevIns, PCIAC97LinkState *); - AC97LinkState *s = &pThis->ac97; - int rc; + AC97STATE *pThis = PDMINS_2_DATA(pDevIns, AC97STATE *); + int rc; Assert(iInstance == 0); PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); @@ -1563,119 +1489,115 @@ static DECLCALLBACK(int) ichac97Construct (PPDMDEVINS pDevIns, int iInstance, /* * Validations. */ - if (!CFGMR3AreValuesValid (pCfgHandle, "\0")) - return PDMDEV_SET_ERROR (pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, - N_ ("Invalid configuration for the AC97 device")); + if (!CFGMR3AreValuesValid(pCfg, "\0")) + return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, + N_("Invalid configuration for the AC97 device")); /* * Initialize data (most of it anyway). */ - s->pDevIns = pDevIns; + pThis->pDevIns = pDevIns; /* IBase */ - s->IBase.pfnQueryInterface = ichac97QueryInterface; + pThis->IBase.pfnQueryInterface = ichac97QueryInterface; /* PCI Device (the assertions will be removed later) */ - PCIDevSetVendorId (&pThis->dev, 0x8086); /* 00 ro - intel. */ Assert (pThis->dev.config[0x00] == 0x86); Assert (pThis->dev.config[0x01] == 0x80); - PCIDevSetDeviceId (&pThis->dev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */Assert (pThis->dev.config[0x02] == 0x15); Assert (pThis->dev.config[0x03] == 0x24); - PCIDevSetCommand (&pThis->dev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert (pThis->dev.config[0x04] == 0x00); Assert (pThis->dev.config[0x05] == 0x00); - PCIDevSetStatus (&pThis->dev, - VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */ Assert (pThis->dev.config[0x06] == 0x80); Assert (pThis->dev.config[0x07] == 0x02); - PCIDevSetRevisionId (&pThis->dev, 0x01); /* 08 ro - rid. */ Assert (pThis->dev.config[0x08] == 0x01); - PCIDevSetClassProg (&pThis->dev, 0x00); /* 09 ro - pi. */ Assert (pThis->dev.config[0x09] == 0x00); - PCIDevSetClassSub (&pThis->dev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert (pThis->dev.config[0x0a] == 0x01); - PCIDevSetClassBase (&pThis->dev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert (pThis->dev.config[0x0b] == 0x04); - PCIDevSetHeaderType (&pThis->dev, 0x00); /* 0e ro - headtyp. */ Assert (pThis->dev.config[0x0e] == 0x00); - PCIDevSetBaseAddress (&pThis->dev, 0, /* 10 rw - nambar - native audio mixer base. */ - true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert (pThis->dev.config[0x10] == 0x01); Assert (pThis->dev.config[0x11] == 0x00); Assert (pThis->dev.config[0x12] == 0x00); Assert (pThis->dev.config[0x13] == 0x00); - PCIDevSetBaseAddress (&pThis->dev, 1, /* 14 rw - nabmbar - native audio bus mastering. */ - true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert (pThis->dev.config[0x14] == 0x01); Assert (pThis->dev.config[0x15] == 0x00); Assert (pThis->dev.config[0x16] == 0x00); Assert (pThis->dev.config[0x17] == 0x00); - PCIDevSetSubSystemVendorId (&pThis->dev, 0x8086); /* 2c ro - intel.) */ Assert (pThis->dev.config[0x2c] == 0x86); Assert (pThis->dev.config[0x2d] == 0x80); - PCIDevSetSubSystemId (&pThis->dev, 0x0000); /* 2e ro. */ Assert (pThis->dev.config[0x2e] == 0x00); Assert (pThis->dev.config[0x2f] == 0x00); - PCIDevSetInterruptLine (&pThis->dev, 0x00); /* 3c rw. */ Assert (pThis->dev.config[0x3c] == 0x00); - PCIDevSetInterruptPin (&pThis->dev, 0x01); /* 3d ro - INTA#. */ Assert (pThis->dev.config[0x3d] == 0x01); + PCIDevSetVendorId (&pThis->PciDev, 0x8086); /* 00 ro - intel. */ Assert(pThis->PciDev.config[0x00] == 0x86); Assert(pThis->PciDev.config[0x01] == 0x80); + PCIDevSetDeviceId (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pThis->PciDev.config[0x02] == 0x15); Assert(pThis->PciDev.config[0x03] == 0x24); + PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pThis->PciDev.config[0x04] == 0x00); Assert(pThis->PciDev.config[0x05] == 0x00); + PCIDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */ Assert(pThis->PciDev.config[0x06] == 0x80); Assert(pThis->PciDev.config[0x07] == 0x02); + PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ Assert(pThis->PciDev.config[0x08] == 0x01); + PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ Assert(pThis->PciDev.config[0x09] == 0x00); + PCIDevSetClassSub (&pThis->PciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pThis->PciDev.config[0x0a] == 0x01); + PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.config[0x0b] == 0x04); + PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ Assert(pThis->PciDev.config[0x0e] == 0x00); + PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - nambar - native audio mixer base. */ + true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.config[0x10] == 0x01); Assert(pThis->PciDev.config[0x11] == 0x00); Assert(pThis->PciDev.config[0x12] == 0x00); Assert(pThis->PciDev.config[0x13] == 0x00); + PCIDevSetBaseAddress (&pThis->PciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */ + true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.config[0x14] == 0x01); Assert(pThis->PciDev.config[0x15] == 0x00); Assert(pThis->PciDev.config[0x16] == 0x00); Assert(pThis->PciDev.config[0x17] == 0x00); + PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x8086); /* 2c ro - intel.) */ Assert(pThis->PciDev.config[0x2c] == 0x86); Assert(pThis->PciDev.config[0x2d] == 0x80); + PCIDevSetSubSystemId (&pThis->PciDev, 0x0000); /* 2e ro. */ Assert(pThis->PciDev.config[0x2e] == 0x00); Assert(pThis->PciDev.config[0x2f] == 0x00); + PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.config[0x3c] == 0x00); + PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.config[0x3d] == 0x01); /* * Register the PCI device, it's I/O regions, the timer and the * saved state item. */ - rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev); + rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev); if (RT_FAILURE (rc)) return rc; - rc = PDMDevHlpPCIIORegionRegister (pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO, - ichac97IOPortMap); + rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap); if (RT_FAILURE (rc)) return rc; - rc = PDMDevHlpPCIIORegionRegister (pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO, - ichac97IOPortMap); + rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap); if (RT_FAILURE (rc)) return rc; - rc = PDMDevHlpSSMRegister (pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec); + rc = PDMDevHlpSSMRegister(pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec); if (RT_FAILURE (rc)) return rc; /* * Attach driver. */ - rc = PDMDevHlpDriverAttach (pDevIns, 0, &s->IBase, - &s->pDrvBase, "Audio Driver Port"); + rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port"); if (rc == VERR_PDM_NO_ATTACHED_DRIVER) - Log (("ac97: No attached driver!\n")); - else if (RT_FAILURE (rc)) + Log(("ac97: No attached driver!\n")); + else if (RT_FAILURE(rc)) { - AssertMsgFailed (("Failed to attach AC97 LUN #0! rc=%Rrc\n", rc)); + AssertMsgFailed(("Failed to attach AC97 LUN #0! rc=%Rrc\n", rc)); return rc; } - AUD_register_card ("ICH0", &s->card); + AUD_register_card("ICH0", &pThis->card); - ac97Reset (pDevIns); + ac97Reset(pDevIns); - if (!AUD_is_host_voice_in_ok(s->voice_pi)) - LogRel (("AC97: WARNING: Unable to open PCM IN!\n")); - if (!AUD_is_host_voice_in_ok(s->voice_mc)) - LogRel (("AC97: WARNING: Unable to open PCM MC!\n")); - if (!AUD_is_host_voice_out_ok(s->voice_po)) - LogRel (("AC97: WARNING: Unable to open PCM OUT!\n")); + if (!AUD_is_host_voice_in_ok(pThis->voice_pi)) + LogRel(("AC97: WARNING: Unable to open PCM IN!\n")); + if (!AUD_is_host_voice_in_ok(pThis->voice_mc)) + LogRel(("AC97: WARNING: Unable to open PCM MC!\n")); + if (!AUD_is_host_voice_out_ok(pThis->voice_po)) + LogRel(("AC97: WARNING: Unable to open PCM OUT!\n")); - if ( !AUD_is_host_voice_in_ok(s->voice_pi) - && !AUD_is_host_voice_out_ok(s->voice_po) - && !AUD_is_host_voice_in_ok(s->voice_mc)) + if ( !AUD_is_host_voice_in_ok( pThis->voice_pi) + && !AUD_is_host_voice_out_ok(pThis->voice_po) + && !AUD_is_host_voice_in_ok( pThis->voice_mc)) { /* Was not able initialize *any* voice. Select the NULL audio driver instead */ - AUD_close_in (&s->card, s->voice_pi); - AUD_close_out (&s->card, s->voice_po); - AUD_close_in (&s->card, s->voice_mc); - s->voice_po = NULL; - s->voice_pi = NULL; - s->voice_mc = NULL; - AUD_init_null (); - ac97Reset (pDevIns); - - PDMDevHlpVMSetRuntimeError (pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", - N_ ("No audio devices could be opened. Selecting the NULL audio backend " - "with the consequence that no sound is audible")); + AUD_close_in( &pThis->card, pThis->voice_pi); + AUD_close_out(&pThis->card, pThis->voice_po); + AUD_close_in( &pThis->card, pThis->voice_mc); + pThis->voice_po = NULL; + pThis->voice_pi = NULL; + pThis->voice_mc = NULL; + AUD_init_null(); + ac97Reset(pDevIns); + + PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", + N_("No audio devices could be opened. Selecting the NULL audio backend " + "with the consequence that no sound is audible")); } - else if ( !AUD_is_host_voice_in_ok(s->voice_pi) - || !AUD_is_host_voice_out_ok(s->voice_po) - || !AUD_is_host_voice_in_ok(s->voice_mc)) + else if ( !AUD_is_host_voice_in_ok( pThis->voice_pi) + || !AUD_is_host_voice_out_ok(pThis->voice_po) + || !AUD_is_host_voice_in_ok( pThis->voice_mc)) { char szMissingVoices[128]; size_t len = 0; - if (!AUD_is_host_voice_in_ok(s->voice_pi)) - len = RTStrPrintf (szMissingVoices, sizeof(szMissingVoices), "PCM_in"); - if (!AUD_is_host_voice_out_ok(s->voice_po)) - len += RTStrPrintf (szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_out" : "PCM_out"); - if (!AUD_is_host_voice_in_ok(s->voice_mc)) - len += RTStrPrintf (szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_mic" : "PCM_mic"); - - PDMDevHlpVMSetRuntimeError (pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", - N_ ("Some audio devices (%s) could not be opened. Guest applications generating audio " - "output or depending on audio input may hang. Make sure your host audio device " - "is working properly. Check the logfile for error messages of the audio " - "subsystem"), szMissingVoices); + if (!AUD_is_host_voice_in_ok(pThis->voice_pi)) + len = RTStrPrintf(szMissingVoices, sizeof(szMissingVoices), "PCM_in"); + if (!AUD_is_host_voice_out_ok(pThis->voice_po)) + len += RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_out" : "PCM_out"); + if (!AUD_is_host_voice_in_ok(pThis->voice_mc)) + len += RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_mic" : "PCM_mic"); + + PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", + N_("Some audio devices (%s) could not be opened. Guest applications generating audio " + "output or depending on audio input may hang. Make sure your host audio device " + "is working properly. Check the logfile for error messages of the audio " + "subsystem"), szMissingVoices); } return VINF_SUCCESS; @@ -1703,14 +1625,14 @@ const PDMDEVREG g_DeviceICHAC97 = /* cMaxInstances */ 1, /* cbInstance */ - sizeof(PCIAC97LinkState), + sizeof(AC97STATE), /* pfnConstruct */ ichac97Construct, /* pfnDestruct */ NULL, /* pfnRelocate */ NULL, - /* pfnIOCtl */ + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, diff --git a/src/VBox/Devices/Audio/DevIchHda.cpp b/src/VBox/Devices/Audio/DevIchHda.cpp new file mode 100644 index 00000000..dd8c84a8 --- /dev/null +++ b/src/VBox/Devices/Audio/DevIchHda.cpp @@ -0,0 +1,3176 @@ +/* $Id: DevIchHda.cpp $ */ +/** @file + * DevIchHda - VBox ICH Intel HD Audio Controller. + * + * Implemented against the specifications found in "High Definition Audio + * Specification", Revision 1.0a June 17, 2010, and "Intel I/O Controller + * HUB 6 (ICH6) Family, Datasheet", document number 301473-002. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP LOG_GROUP_DEV_AUDIO +#include <VBox/vmm/pdmdev.h> +#include <VBox/version.h> + +#include <iprt/assert.h> +#include <iprt/asm.h> +#include <iprt/asm-math.h> +#ifdef IN_RING3 +# include <iprt/uuid.h> +# include <iprt/string.h> +# include <iprt/mem.h> +#endif + +#include "VBoxDD.h" + +extern "C" { +#include "audio.h" +} +#include "DevIchHdaCodec.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +//#define HDA_AS_PCI_EXPRESS +#define VBOX_WITH_INTEL_HDA + +#if defined(VBOX_WITH_HP_HDA) +/* HP Pavilion dv4t-1300 */ +# define HDA_PCI_VENDOR_ID 0x103c +# define HDA_PCI_DEVICE_ID 0x30f7 +#elif defined(VBOX_WITH_INTEL_HDA) +/* Intel HDA controller */ +# define HDA_PCI_VENDOR_ID 0x8086 +# define HDA_PCI_DEVICE_ID 0x2668 +#elif defined(VBOX_WITH_NVIDIA_HDA) +/* nVidia HDA controller */ +# define HDA_PCI_VENDOR_ID 0x10de +# define HDA_PCI_DEVICE_ID 0x0ac0 +#else +# error "Please specify your HDA device vendor/device IDs" +#endif + +/** @todo r=bird: Looking at what the linux driver (accidentally?) does when + * updating CORBWP, I belive that the ICH6 datahsheet is wrong and that CORBRP + * is read only except for bit 15 like the HDA spec states. + * + * Btw. the CORBRPRST implementation is incomplete according to both docs (sw + * writes 1, hw sets it to 1 (after completion), sw reads 1, sw writes 0). */ +#define BIRD_THINKS_CORBRP_IS_MOSTLY_RO + +#define HDA_NREGS 112 +/* Registers */ +#define HDA_REG_IND_NAME(x) ICH6_HDA_REG_##x +#define HDA_REG_FIELD_NAME(reg, x) ICH6_HDA_##reg##_##x +#define HDA_REG_FIELD_MASK(reg, x) ICH6_HDA_##reg##_##x##_MASK +#define HDA_REG_FIELD_FLAG_MASK(reg, x) RT_BIT(ICH6_HDA_##reg##_##x##_SHIFT) +#define HDA_REG_FIELD_SHIFT(reg, x) ICH6_HDA_##reg##_##x##_SHIFT +#define HDA_REG_IND(pThis, x) ((pThis)->au32Regs[(x)]) +#define HDA_REG(pThis, x) (HDA_REG_IND((pThis), HDA_REG_IND_NAME(x))) +#define HDA_REG_VALUE(pThis, reg, val) (HDA_REG((pThis),reg) & (((HDA_REG_FIELD_MASK(reg, val))) << (HDA_REG_FIELD_SHIFT(reg, val)))) +#define HDA_REG_FLAG_VALUE(pThis, reg, val) (HDA_REG((pThis),reg) & (((HDA_REG_FIELD_FLAG_MASK(reg, val))))) +#define HDA_REG_SVALUE(pThis, reg, val) (HDA_REG_VALUE(pThis, reg, val) >> (HDA_REG_FIELD_SHIFT(reg, val))) + +#define ICH6_HDA_REG_GCAP 0 /* range 0x00-0x01*/ +#define GCAP(pThis) (HDA_REG((pThis), GCAP)) +/* GCAP HDASpec 3.3.2 This macro encodes the following information about HDA in a compact manner: + * oss (15:12) - number of output streams supported + * iss (11:8) - number of input streams supported + * bss (7:3) - number of bidirectional streams supported + * bds (2:1) - number of serial data out signals supported + * b64sup (0) - 64 bit addressing supported. + */ +#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \ + ( (((oss) & 0xF) << 12) \ + | (((iss) & 0xF) << 8) \ + | (((bss) & 0x1F) << 3) \ + | (((bds) & 0x3) << 2) \ + | ((b64sup) & 1)) +#define ICH6_HDA_REG_VMIN 1 /* range 0x02 */ +#define VMIN(pThis) (HDA_REG((pThis), VMIN)) + +#define ICH6_HDA_REG_VMAJ 2 /* range 0x03 */ +#define VMAJ(pThis) (HDA_REG((pThis), VMAJ)) + +#define ICH6_HDA_REG_OUTPAY 3 /* range 0x04-0x05 */ +#define OUTPAY(pThis) (HDA_REG((pThis), OUTPAY)) + +#define ICH6_HDA_REG_INPAY 4 /* range 0x06-0x07 */ +#define INPAY(pThis) (HDA_REG((pThis), INPAY)) + +#define ICH6_HDA_REG_GCTL (5) +#define ICH6_HDA_GCTL_RST_SHIFT (0) +#define ICH6_HDA_GCTL_FSH_SHIFT (1) +#define ICH6_HDA_GCTL_UR_SHIFT (8) +#define GCTL(pThis) (HDA_REG((pThis), GCTL)) + +#define ICH6_HDA_REG_WAKEEN 6 /* 0x0C */ +#define WAKEEN(pThis) (HDA_REG((pThis), WAKEEN)) + +#define ICH6_HDA_REG_STATESTS 7 /* range 0x0E */ +#define STATESTS(pThis) (HDA_REG((pThis), STATESTS)) +#define ICH6_HDA_STATES_SCSF 0x7 + +#define ICH6_HDA_REG_GSTS 8 /* range 0x10-0x11*/ +#define ICH6_HDA_GSTS_FSH_SHIFT (1) +#define GSTS(pThis) (HDA_REG(pThis, GSTS)) + +#define ICH6_HDA_REG_INTCTL 9 /* 0x20 */ +#define ICH6_HDA_INTCTL_GIE_SHIFT 31 +#define ICH6_HDA_INTCTL_CIE_SHIFT 30 +#define ICH6_HDA_INTCTL_S0_SHIFT (0) +#define ICH6_HDA_INTCTL_S1_SHIFT (1) +#define ICH6_HDA_INTCTL_S2_SHIFT (2) +#define ICH6_HDA_INTCTL_S3_SHIFT (3) +#define ICH6_HDA_INTCTL_S4_SHIFT (4) +#define ICH6_HDA_INTCTL_S5_SHIFT (5) +#define ICH6_HDA_INTCTL_S6_SHIFT (6) +#define ICH6_HDA_INTCTL_S7_SHIFT (7) +#define INTCTL(pThis) (HDA_REG((pThis), INTCTL)) +#define INTCTL_GIE(pThis) (HDA_REG_FLAG_VALUE(pThis, INTCTL, GIE)) +#define INTCTL_CIE(pThis) (HDA_REG_FLAG_VALUE(pThis, INTCTL, CIE)) +#define INTCTL_SX(pThis, X) (HDA_REG_FLAG_VALUE((pThis), INTCTL, S##X)) +#define INTCTL_SALL(pThis) (INTCTL((pThis)) & 0xFF) + +/* Note: The HDA specification defines a SSYNC register at offset 0x38. The + * ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches + * the datasheet. + */ +#define ICH6_HDA_REG_SSYNC 12 /* 0x34 */ +#define SSYNC(pThis) (HDA_REG((pThis), SSYNC)) + +#define ICH6_HDA_REG_INTSTS 10 /* 0x24 */ +#define ICH6_HDA_INTSTS_GIS_SHIFT (31) +#define ICH6_HDA_INTSTS_CIS_SHIFT (30) +#define ICH6_HDA_INTSTS_S0_SHIFT (0) +#define ICH6_HDA_INTSTS_S1_SHIFT (1) +#define ICH6_HDA_INTSTS_S2_SHIFT (2) +#define ICH6_HDA_INTSTS_S3_SHIFT (3) +#define ICH6_HDA_INTSTS_S4_SHIFT (4) +#define ICH6_HDA_INTSTS_S5_SHIFT (5) +#define ICH6_HDA_INTSTS_S6_SHIFT (6) +#define ICH6_HDA_INTSTS_S7_SHIFT (7) +#define ICH6_HDA_INTSTS_S_MASK(num) RT_BIT(HDA_REG_FIELD_SHIFT(S##num)) +#define INTSTS(pThis) (HDA_REG((pThis), INTSTS)) +#define INTSTS_GIS(pThis) (HDA_REG_FLAG_VALUE((pThis), INTSTS, GIS) +#define INTSTS_CIS(pThis) (HDA_REG_FLAG_VALUE((pThis), INTSTS, CIS) +#define INTSTS_SX(pThis, X) (HDA_REG_FLAG_VALUE(pThis), INTSTS, S##X) +#define INTSTS_SANY(pThis) (INTSTS((pThis)) & 0xFF) + +#define ICH6_HDA_REG_CORBLBASE 13 /* 0x40 */ +#define CORBLBASE(pThis) (HDA_REG((pThis), CORBLBASE)) +#define ICH6_HDA_REG_CORBUBASE 14 /* 0x44 */ +#define CORBUBASE(pThis) (HDA_REG((pThis), CORBUBASE)) +#define ICH6_HDA_REG_CORBWP 15 /* 48 */ +#define ICH6_HDA_REG_CORBRP 16 /* 4A */ +#define ICH6_HDA_CORBRP_RST_SHIFT 15 +#define ICH6_HDA_CORBRP_WP_SHIFT 0 +#define ICH6_HDA_CORBRP_WP_MASK 0xFF + +#define CORBRP(pThis) (HDA_REG(pThis, CORBRP)) +#define CORBWP(pThis) (HDA_REG(pThis, CORBWP)) + +#define ICH6_HDA_REG_CORBCTL 17 /* 0x4C */ +#define ICH6_HDA_CORBCTL_DMA_SHIFT (1) +#define ICH6_HDA_CORBCTL_CMEIE_SHIFT (0) + +#define CORBCTL(pThis) (HDA_REG(pThis, CORBCTL)) + + +#define ICH6_HDA_REG_CORBSTS 18 /* 0x4D */ +#define CORBSTS(pThis) (HDA_REG(pThis, CORBSTS)) +#define ICH6_HDA_CORBSTS_CMEI_SHIFT (0) + +#define ICH6_HDA_REG_CORBSIZE 19 /* 0x4E */ +#define ICH6_HDA_CORBSIZE_SZ_CAP 0xF0 +#define ICH6_HDA_CORBSIZE_SZ 0x3 +#define CORBSIZE_SZ(pThis) (HDA_REG(pThis, ICH6_HDA_REG_CORBSIZE) & ICH6_HDA_CORBSIZE_SZ) +#define CORBSIZE_SZ_CAP(pThis) (HDA_REG(pThis, ICH6_HDA_REG_CORBSIZE) & ICH6_HDA_CORBSIZE_SZ_CAP) +/* till ich 10 sizes of CORB and RIRB are hardcoded to 256 in real hw */ + +#define ICH6_HDA_REG_RIRLBASE 20 /* 0x50 */ +#define RIRLBASE(pThis) (HDA_REG((pThis), RIRLBASE)) + +#define ICH6_HDA_REG_RIRUBASE 21 /* 0x54 */ +#define RIRUBASE(pThis) (HDA_REG((pThis), RIRUBASE)) + +#define ICH6_HDA_REG_RIRBWP 22 /* 0x58 */ +#define ICH6_HDA_RIRBWP_RST_SHIFT (15) +#define ICH6_HDA_RIRBWP_WP_MASK 0xFF +#define RIRBWP(pThis) (HDA_REG(pThis, RIRBWP)) + +#define ICH6_HDA_REG_RINTCNT 23 /* 0x5A */ +#define RINTCNT(pThis) (HDA_REG((pThis), RINTCNT)) +#define RINTCNT_N(pThis) (RINTCNT((pThis)) & 0xff) + +#define ICH6_HDA_REG_RIRBCTL 24 /* 0x5C */ +#define ICH6_HDA_RIRBCTL_RIC_SHIFT (0) +#define ICH6_HDA_RIRBCTL_DMA_SHIFT (1) +#define ICH6_HDA_ROI_DMA_SHIFT (2) +#define RIRBCTL(pThis) (HDA_REG((pThis), RIRBCTL)) +#define RIRBCTL_RIRB_RIC(pThis) (HDA_REG_FLAG_VALUE(pThis, RIRBCTL, RIC)) +#define RIRBCTL_RIRB_DMA(pThis) (HDA_REG_FLAG_VALUE((pThis), RIRBCTL, DMA) +#define RIRBCTL_ROI(pThis) (HDA_REG_FLAG_VALUE((pThis), RIRBCTL, ROI)) + +#define ICH6_HDA_REG_RIRBSTS 25 /* 0x5D */ +#define ICH6_HDA_RIRBSTS_RINTFL_SHIFT (0) +#define ICH6_HDA_RIRBSTS_RIRBOIS_SHIFT (2) +#define RIRBSTS(pThis) (HDA_REG(pThis, RIRBSTS)) +#define RIRBSTS_RINTFL(pThis) (HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)) +#define RIRBSTS_RIRBOIS(pThis) (HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)) + +#define ICH6_HDA_REG_RIRBSIZE 26 /* 0x5E */ +#define ICH6_HDA_RIRBSIZE_SZ_CAP 0xF0 +#define ICH6_HDA_RIRBSIZE_SZ 0x3 + +#define RIRBSIZE_SZ(pThis) (HDA_REG(pThis, ICH6_HDA_REG_RIRBSIZE) & ICH6_HDA_RIRBSIZE_SZ) +#define RIRBSIZE_SZ_CAP(pThis) (HDA_REG(pThis, ICH6_HDA_REG_RIRBSIZE) & ICH6_HDA_RIRBSIZE_SZ_CAP) + + +#define ICH6_HDA_REG_IC 27 /* 0x60 */ +#define IC(pThis) (HDA_REG(pThis, IC)) +#define ICH6_HDA_REG_IR 28 /* 0x64 */ +#define IR(pThis) (HDA_REG(pThis, IR)) +#define ICH6_HDA_REG_IRS 29 /* 0x68 */ +#define ICH6_HDA_IRS_ICB_SHIFT (0) +#define ICH6_HDA_IRS_IRV_SHIFT (1) +#define IRS(pThis) (HDA_REG(pThis, IRS)) +#define IRS_ICB(pThis) (HDA_REG_FLAG_VALUE(pThis, IRS, ICB)) +#define IRS_IRV(pThis) (HDA_REG_FLAG_VALUE(pThis, IRS, IRV)) + +#define ICH6_HDA_REG_DPLBASE 30 /* 0x70 */ +#define DPLBASE(pThis) (HDA_REG((pThis), DPLBASE)) +#define ICH6_HDA_REG_DPUBASE 31 /* 0x74 */ +#define DPUBASE(pThis) (HDA_REG((pThis), DPUBASE)) +#define DPBASE_ENABLED 1 +#define DPBASE_ADDR_MASK (~(uint64_t)0x7f) + +#define HDA_STREAM_REG_DEF(name, num) (ICH6_HDA_REG_SD##num##name) +#define HDA_STREAM_REG(pThis, name, num) (HDA_REG((pThis), N_(HDA_STREAM_REG_DEF(name, num)))) +/* Note: sdnum here _MUST_ be stream reg number [0,7] */ +#define HDA_STREAM_REG2(pThis, name, sdnum) (HDA_REG_IND((pThis), ICH6_HDA_REG_SD0##name + (sdnum) * 10)) + +#define ICH6_HDA_REG_SD0CTL 32 /* 0x80 */ +#define ICH6_HDA_REG_SD1CTL (HDA_STREAM_REG_DEF(CTL, 0) + 10) /* 0xA0 */ +#define ICH6_HDA_REG_SD2CTL (HDA_STREAM_REG_DEF(CTL, 0) + 20) /* 0xC0 */ +#define ICH6_HDA_REG_SD3CTL (HDA_STREAM_REG_DEF(CTL, 0) + 30) /* 0xE0 */ +#define ICH6_HDA_REG_SD4CTL (HDA_STREAM_REG_DEF(CTL, 0) + 40) /* 0x100 */ +#define ICH6_HDA_REG_SD5CTL (HDA_STREAM_REG_DEF(CTL, 0) + 50) /* 0x120 */ +#define ICH6_HDA_REG_SD6CTL (HDA_STREAM_REG_DEF(CTL, 0) + 60) /* 0x140 */ +#define ICH6_HDA_REG_SD7CTL (HDA_STREAM_REG_DEF(CTL, 0) + 70) /* 0x160 */ + +#define SD(func, num) SD##num##func +#define SDCTL(pThis, num) HDA_REG((pThis), SD(CTL, num)) +#define SDCTL_NUM(pThis, num) ((SDCTL((pThis), num) & HDA_REG_FIELD_MASK(SDCTL,NUM)) >> HDA_REG_FIELD_SHIFT(SDCTL, NUM)) +#define ICH6_HDA_SDCTL_NUM_MASK (0xF) +#define ICH6_HDA_SDCTL_NUM_SHIFT (20) +#define ICH6_HDA_SDCTL_DIR_SHIFT (19) +#define ICH6_HDA_SDCTL_TP_SHIFT (18) +#define ICH6_HDA_SDCTL_STRIPE_MASK (0x3) +#define ICH6_HDA_SDCTL_STRIPE_SHIFT (16) +#define ICH6_HDA_SDCTL_DEIE_SHIFT (4) +#define ICH6_HDA_SDCTL_FEIE_SHIFT (3) +#define ICH6_HDA_SDCTL_ICE_SHIFT (2) +#define ICH6_HDA_SDCTL_RUN_SHIFT (1) +#define ICH6_HDA_SDCTL_SRST_SHIFT (0) + +#define ICH6_HDA_REG_SD0STS 33 /* 0x83 */ +#define ICH6_HDA_REG_SD1STS (HDA_STREAM_REG_DEF(STS, 0) + 10) /* 0xA3 */ +#define ICH6_HDA_REG_SD2STS (HDA_STREAM_REG_DEF(STS, 0) + 20) /* 0xC3 */ +#define ICH6_HDA_REG_SD3STS (HDA_STREAM_REG_DEF(STS, 0) + 30) /* 0xE3 */ +#define ICH6_HDA_REG_SD4STS (HDA_STREAM_REG_DEF(STS, 0) + 40) /* 0x103 */ +#define ICH6_HDA_REG_SD5STS (HDA_STREAM_REG_DEF(STS, 0) + 50) /* 0x123 */ +#define ICH6_HDA_REG_SD6STS (HDA_STREAM_REG_DEF(STS, 0) + 60) /* 0x143 */ +#define ICH6_HDA_REG_SD7STS (HDA_STREAM_REG_DEF(STS, 0) + 70) /* 0x163 */ + +#define SDSTS(pThis, num) HDA_REG((pThis), SD(STS, num)) +#define ICH6_HDA_SDSTS_FIFORDY_SHIFT (5) +#define ICH6_HDA_SDSTS_DE_SHIFT (4) +#define ICH6_HDA_SDSTS_FE_SHIFT (3) +#define ICH6_HDA_SDSTS_BCIS_SHIFT (2) + +#define ICH6_HDA_REG_SD0LPIB 34 /* 0x84 */ +#define ICH6_HDA_REG_SD1LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 10) /* 0xA4 */ +#define ICH6_HDA_REG_SD2LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 20) /* 0xC4 */ +#define ICH6_HDA_REG_SD3LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 30) /* 0xE4 */ +#define ICH6_HDA_REG_SD4LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 40) /* 0x104 */ +#define ICH6_HDA_REG_SD5LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 50) /* 0x124 */ +#define ICH6_HDA_REG_SD6LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 60) /* 0x144 */ +#define ICH6_HDA_REG_SD7LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 70) /* 0x164 */ + +#define SDLPIB(pThis, num) HDA_REG((pThis), SD(LPIB, num)) + +#define ICH6_HDA_REG_SD0CBL 35 /* 0x88 */ +#define ICH6_HDA_REG_SD1CBL (HDA_STREAM_REG_DEF(CBL, 0) + 10) /* 0xA8 */ +#define ICH6_HDA_REG_SD2CBL (HDA_STREAM_REG_DEF(CBL, 0) + 20) /* 0xC8 */ +#define ICH6_HDA_REG_SD3CBL (HDA_STREAM_REG_DEF(CBL, 0) + 30) /* 0xE8 */ +#define ICH6_HDA_REG_SD4CBL (HDA_STREAM_REG_DEF(CBL, 0) + 40) /* 0x108 */ +#define ICH6_HDA_REG_SD5CBL (HDA_STREAM_REG_DEF(CBL, 0) + 50) /* 0x128 */ +#define ICH6_HDA_REG_SD6CBL (HDA_STREAM_REG_DEF(CBL, 0) + 60) /* 0x148 */ +#define ICH6_HDA_REG_SD7CBL (HDA_STREAM_REG_DEF(CBL, 0) + 70) /* 0x168 */ + +#define SDLCBL(pThis, num) HDA_REG((pThis), SD(CBL, num)) + +#define ICH6_HDA_REG_SD0LVI 36 /* 0x8C */ +#define ICH6_HDA_REG_SD1LVI (HDA_STREAM_REG_DEF(LVI, 0) + 10) /* 0xAC */ +#define ICH6_HDA_REG_SD2LVI (HDA_STREAM_REG_DEF(LVI, 0) + 20) /* 0xCC */ +#define ICH6_HDA_REG_SD3LVI (HDA_STREAM_REG_DEF(LVI, 0) + 30) /* 0xEC */ +#define ICH6_HDA_REG_SD4LVI (HDA_STREAM_REG_DEF(LVI, 0) + 40) /* 0x10C */ +#define ICH6_HDA_REG_SD5LVI (HDA_STREAM_REG_DEF(LVI, 0) + 50) /* 0x12C */ +#define ICH6_HDA_REG_SD6LVI (HDA_STREAM_REG_DEF(LVI, 0) + 60) /* 0x14C */ +#define ICH6_HDA_REG_SD7LVI (HDA_STREAM_REG_DEF(LVI, 0) + 70) /* 0x16C */ + +#define SDLVI(pThis, num) HDA_REG((pThis), SD(LVI, num)) + +#define ICH6_HDA_REG_SD0FIFOW 37 /* 0x8E */ +#define ICH6_HDA_REG_SD1FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 10) /* 0xAE */ +#define ICH6_HDA_REG_SD2FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 20) /* 0xCE */ +#define ICH6_HDA_REG_SD3FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 30) /* 0xEE */ +#define ICH6_HDA_REG_SD4FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 40) /* 0x10E */ +#define ICH6_HDA_REG_SD5FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 50) /* 0x12E */ +#define ICH6_HDA_REG_SD6FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 60) /* 0x14E */ +#define ICH6_HDA_REG_SD7FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 70) /* 0x16E */ + +/* + * ICH6 datasheet defined limits for FIFOW values (18.2.38) + */ +#define HDA_SDFIFOW_8B (0x2) +#define HDA_SDFIFOW_16B (0x3) +#define HDA_SDFIFOW_32B (0x4) +#define SDFIFOW(pThis, num) HDA_REG((pThis), SD(FIFOW, num)) + +#define ICH6_HDA_REG_SD0FIFOS 38 /* 0x90 */ +#define ICH6_HDA_REG_SD1FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 10) /* 0xB0 */ +#define ICH6_HDA_REG_SD2FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 20) /* 0xD0 */ +#define ICH6_HDA_REG_SD3FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 30) /* 0xF0 */ +#define ICH6_HDA_REG_SD4FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 40) /* 0x110 */ +#define ICH6_HDA_REG_SD5FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 50) /* 0x130 */ +#define ICH6_HDA_REG_SD6FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 60) /* 0x150 */ +#define ICH6_HDA_REG_SD7FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 70) /* 0x170 */ + +/* + * ICH6 datasheet defines limits for FIFOS registers (18.2.39) + * formula: size - 1 + * Other values not listed are not supported. + */ +#define HDA_SDONFIFO_16B (0x0F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ +#define HDA_SDONFIFO_32B (0x1F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ +#define HDA_SDONFIFO_64B (0x3F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ +#define HDA_SDONFIFO_128B (0x7F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ +#define HDA_SDONFIFO_192B (0xBF) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ +#define HDA_SDONFIFO_256B (0xFF) /* 20-, 24-bit Output Streams */ +#define HDA_SDINFIFO_120B (0x77) /* 8-, 16-, 20-, 24-, 32-bit Input Streams */ +#define HDA_SDINFIFO_160B (0x9F) /* 20-, 24-bit Input Streams Streams */ +#define SDFIFOS(pThis, num) HDA_REG((pThis), SD(FIFOS, num)) + +#define ICH6_HDA_REG_SD0FMT 39 /* 0x92 */ +#define ICH6_HDA_REG_SD1FMT (HDA_STREAM_REG_DEF(FMT, 0) + 10) /* 0xB2 */ +#define ICH6_HDA_REG_SD2FMT (HDA_STREAM_REG_DEF(FMT, 0) + 20) /* 0xD2 */ +#define ICH6_HDA_REG_SD3FMT (HDA_STREAM_REG_DEF(FMT, 0) + 30) /* 0xF2 */ +#define ICH6_HDA_REG_SD4FMT (HDA_STREAM_REG_DEF(FMT, 0) + 40) /* 0x112 */ +#define ICH6_HDA_REG_SD5FMT (HDA_STREAM_REG_DEF(FMT, 0) + 50) /* 0x132 */ +#define ICH6_HDA_REG_SD6FMT (HDA_STREAM_REG_DEF(FMT, 0) + 60) /* 0x152 */ +#define ICH6_HDA_REG_SD7FMT (HDA_STREAM_REG_DEF(FMT, 0) + 70) /* 0x172 */ + +#define SDFMT(pThis, num) (HDA_REG((pThis), SD(FMT, num))) +#define ICH6_HDA_SDFMT_BASE_RATE_SHIFT (14) +#define ICH6_HDA_SDFMT_MULT_SHIFT (11) +#define ICH6_HDA_SDFMT_MULT_MASK (0x7) +#define ICH6_HDA_SDFMT_DIV_SHIFT (8) +#define ICH6_HDA_SDFMT_DIV_MASK (0x7) +#define ICH6_HDA_SDFMT_BITS_SHIFT (4) +#define ICH6_HDA_SDFMT_BITS_MASK (0x7) +#define SDFMT_BASE_RATE(pThis, num) ((SDFMT(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE)) +#define SDFMT_MULT(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT)) +#define SDFMT_DIV(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV)) + +#define ICH6_HDA_REG_SD0BDPL 40 /* 0x98 */ +#define ICH6_HDA_REG_SD1BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 10) /* 0xB8 */ +#define ICH6_HDA_REG_SD2BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 20) /* 0xD8 */ +#define ICH6_HDA_REG_SD3BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 30) /* 0xF8 */ +#define ICH6_HDA_REG_SD4BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 40) /* 0x118 */ +#define ICH6_HDA_REG_SD5BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 50) /* 0x138 */ +#define ICH6_HDA_REG_SD6BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 60) /* 0x158 */ +#define ICH6_HDA_REG_SD7BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 70) /* 0x178 */ + +#define SDBDPL(pThis, num) HDA_REG((pThis), SD(BDPL, num)) + +#define ICH6_HDA_REG_SD0BDPU 41 /* 0x9C */ +#define ICH6_HDA_REG_SD1BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 10) /* 0xBC */ +#define ICH6_HDA_REG_SD2BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 20) /* 0xDC */ +#define ICH6_HDA_REG_SD3BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 30) /* 0xFC */ +#define ICH6_HDA_REG_SD4BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 40) /* 0x11C */ +#define ICH6_HDA_REG_SD5BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 50) /* 0x13C */ +#define ICH6_HDA_REG_SD6BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 60) /* 0x15C */ +#define ICH6_HDA_REG_SD7BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 70) /* 0x17C */ + +#define SDBDPU(pThis, num) HDA_REG((pThis), SD(BDPU, num)) + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +typedef struct HDABDLEDESC +{ + uint64_t u64BdleCviAddr; + uint32_t u32BdleMaxCvi; + uint32_t u32BdleCvi; + uint32_t u32BdleCviLen; + uint32_t u32BdleCviPos; + bool fBdleCviIoc; + uint32_t cbUnderFifoW; + uint8_t au8HdaBuffer[HDA_SDONFIFO_256B + 1]; +} HDABDLEDESC, *PHDABDLEDESC; + +typedef struct HDASTREAMTRANSFERDESC +{ + uint64_t u64BaseDMA; + uint32_t u32Ctl; + uint32_t *pu32Sts; + uint8_t u8Strm; + uint32_t *pu32Lpib; + uint32_t u32Cbl; + uint32_t u32Fifos; +} HDASTREAMTRANSFERDESC, *PHDASTREAMTRANSFERDESC; + +/** + * ICH Intel HD Audio Controller state. + */ +typedef struct HDASTATE +{ + /** The PCI device structure. */ + PCIDevice PciDev; + /** R3 Pointer to the device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** R0 Pointer to the device instance. */ + PPDMDEVINSR0 pDevInsR0; + /** R0 Pointer to the device instance. */ + PPDMDEVINSRC pDevInsRC; + + uint32_t u32Padding; + + /** Pointer to the connector of the attached audio driver. */ + R3PTRTYPE(PPDMIAUDIOCONNECTOR) pDrv; + /** Pointer to the attached audio driver. */ + R3PTRTYPE(PPDMIBASE) pDrvBase; + /** The base interface for LUN\#0. */ + PDMIBASE IBase; + RTGCPHYS MMIOBaseAddr; + uint32_t au32Regs[HDA_NREGS]; + HDABDLEDESC StInBdle; + HDABDLEDESC StOutBdle; + HDABDLEDESC StMicBdle; + uint64_t u64CORBBase; + uint64_t u64RIRBBase; + uint64_t u64DPBase; + /** pointer to CORB buf */ + R3PTRTYPE(uint32_t *) pu32CorbBuf; + /** size in bytes of CORB buf */ + uint32_t cbCorbBuf; + uint32_t u32Padding2; + /** pointer on RIRB buf */ + R3PTRTYPE(uint64_t *) pu64RirbBuf; + /** size in bytes of RIRB buf */ + uint32_t cbRirbBuf; + /** indicates if HDA in reset. */ + bool fInReset; + /** Interrupt on completion */ + bool fCviIoc; + /** Flag whether the R0 part is enabled. */ + bool fR0Enabled; + /** Flag whether the RC part is enabled. */ + bool fRCEnabled; + /** The HDA codec state. */ + R3PTRTYPE(PHDACODEC) pCodec; + uint64_t u64BaseTS; + /** 1.2.3.4.5.6.7. - someone please tell me what I'm counting! - .8.9.10... */ + uint8_t u8Counter; + uint8_t au8Padding[7]; +} HDASTATE; +/** Pointer to the ICH Intel HD Audio Controller state. */ +typedef HDASTATE *PHDASTATE; + +#define ISD0FMT_TO_AUDIO_SELECTOR(pThis) \ + ( AUDIO_FORMAT_SELECTOR((pThis)->pCodec, In, SDFMT_BASE_RATE(pThis, 0), SDFMT_MULT(pThis, 0), SDFMT_DIV(pThis, 0)) ) +#define OSD0FMT_TO_AUDIO_SELECTOR(pThis) \ + ( AUDIO_FORMAT_SELECTOR((pThis)->pCodec, Out, SDFMT_BASE_RATE(pThis, 4), SDFMT_MULT(pThis, 4), SDFMT_DIV(pThis, 4)) ) + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ +#ifndef VBOX_DEVICE_STRUCT_TESTCASE +static FNPDMDEVRESET hdaReset; + +static int hdaRegReadUnimplemented(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteUnimplemented(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegReadGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegReadSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegReadGCAP(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegReadSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); + +static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); +static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); +static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); +static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value); + +#ifdef IN_RING3 +DECLINLINE(void) hdaInitTransferDescriptor(PHDASTATE pThis, PHDABDLEDESC pBdle, uint8_t u8Strm, + PHDASTREAMTRANSFERDESC pStreamDesc); +static void hdaFetchBdle(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc); +#ifdef LOG_ENABLED +static void dump_bd(PHDASTATE pThis, PHDABDLEDESC pBdle, uint64_t u64BaseDMA); +#endif +#endif + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/* see 302349 p 6.2*/ +static const struct HDAREGDESC +{ + /** Register offset in the register space. */ + uint32_t offset; + /** Size in bytes. Registers of size > 4 are in fact tables. */ + uint32_t size; + /** Readable bits. */ + uint32_t readable; + /** Writable bits. */ + uint32_t writable; + /** Read callback. */ + int (*pfnRead)(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); + /** Write callback. */ + int (*pfnWrite)(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); + /** Abbreviated name. */ + const char *abbrev; + /** Full name. */ + const char *name; +} g_aHdaRegMap[HDA_NREGS] = +{ + /* offset size read mask write mask read callback write callback abbrev full name */ + /*------- ------- ---------- ---------- ----------------------- ------------------------ ---------- ------------------------------*/ + { 0x00000, 0x00002, 0x0000FFFB, 0x00000000, hdaRegReadGCAP , hdaRegWriteUnimplemented, "GCAP" , "Global Capabilities" }, + { 0x00002, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "VMIN" , "Minor Version" }, + { 0x00003, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "VMAJ" , "Major Version" }, + { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimplemented, "OUTPAY" , "Output Payload Capabilities" }, + { 0x00006, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimplemented, "INPAY" , "Input Payload Capabilities" }, + { 0x00008, 0x00004, 0x00000103, 0x00000103, hdaRegReadGCTL , hdaRegWriteGCTL , "GCTL" , "Global Control" }, + { 0x0000c, 0x00002, 0x00007FFF, 0x00007FFF, hdaRegReadU16 , hdaRegWriteU16 , "WAKEEN" , "Wake Enable" }, + { 0x0000e, 0x00002, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteSTATESTS , "STATESTS" , "State Change Status" }, + { 0x00010, 0x00002, 0xFFFFFFFF, 0x00000000, hdaRegReadUnimplemented, hdaRegWriteUnimplemented, "GSTS" , "Global Status" }, + { 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, hdaRegReadU32 , hdaRegWriteU32 , "INTCTL" , "Interrupt Control" }, + { 0x00024, 0x00004, 0xC00000FF, 0x00000000, hdaRegReadINTSTS , hdaRegWriteUnimplemented, "INTSTS" , "Interrupt Status" }, + { 0x00030, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadWALCLK , hdaRegWriteUnimplemented, "WALCLK" , "Wall Clock Counter" }, + /// @todo r=michaln: Doesn't the SSYNC register need to actually stop the stream(s)? + { 0x00034, 0x00004, 0x000000FF, 0x000000FF, hdaRegReadU32 , hdaRegWriteU32 , "SSYNC" , "Stream Synchronization" }, + { 0x00040, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteBase , "CORBLBASE" , "CORB Lower Base Address" }, + { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , "CORBUBASE" , "CORB Upper Base Address" }, + { 0x00048, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteCORBWP , "CORBWP" , "CORB Write Pointer" }, +#ifdef OLD_REGISTER_TABLE + { 0x0004A, 0x00002, 0x000000FF, 0x000080FF, hdaRegReadU8 , hdaRegWriteCORBRP , "CORBRP" , "CORB Read Pointer" }, +#else /** @todo 18.2.17 indicates that the 15th bit can be read as well as and written. hdaRegReadU8 is wrong, a special reader should be used. */ + { 0x0004A, 0x00002, 0x000080FF, 0x000080FF, hdaRegReadU16 , hdaRegWriteCORBRP , "CORBRP" , "CORB Read Pointer" }, +#endif + { 0x0004C, 0x00001, 0x00000003, 0x00000003, hdaRegReadU8 , hdaRegWriteCORBCTL , "CORBCTL" , "CORB Control" }, + { 0x0004D, 0x00001, 0x00000001, 0x00000001, hdaRegReadU8 , hdaRegWriteCORBSTS , "CORBSTS" , "CORB Status" }, + { 0x0004E, 0x00001, 0x000000F3, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "CORBSIZE" , "CORB Size" }, + { 0x00050, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteBase , "RIRBLBASE" , "RIRB Lower Base Address" }, + { 0x00054, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , "RIRBUBASE" , "RIRB Upper Base Address" }, + { 0x00058, 0x00002, 0x000000FF, 0x00008000, hdaRegReadU8 , hdaRegWriteRIRBWP , "RIRBWP" , "RIRB Write Pointer" }, + { 0x0005A, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteU16 , "RINTCNT" , "Response Interrupt Count" }, + { 0x0005C, 0x00001, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteU8 , "RIRBCTL" , "RIRB Control" }, + { 0x0005D, 0x00001, 0x00000005, 0x00000005, hdaRegReadU8 , hdaRegWriteRIRBSTS , "RIRBSTS" , "RIRB Status" }, + { 0x0005E, 0x00001, 0x000000F3, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "RIRBSIZE" , "RIRB Size" }, + { 0x00060, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "IC" , "Immediate Command" }, + { 0x00064, 0x00004, 0x00000000, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteUnimplemented, "IR" , "Immediate Response" }, +#ifdef OLD_REGISTER_TABLE + { 0x00068, 0x00004, 0x00000002, 0x00000002, hdaRegReadIRS , hdaRegWriteIRS , "IRS" , "Immediate Command Status" }, +#else /* 18.2.30 as well as the table says 16-bit. Linux accesses it as a 16-bit register. */ + { 0x00068, 0x00002, 0x00000002, 0x00000002, hdaRegReadIRS , hdaRegWriteIRS , "IRS" , "Immediate Command Status" }, +#endif + { 0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, hdaRegReadU32 , hdaRegWriteBase , "DPLBASE" , "DMA Position Lower Base" }, + { 0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , "DPUBASE" , "DMA Position Upper Base" }, + + { 0x00080, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD0CTL" , "Input Stream Descriptor 0 (ICD0) Control" }, + { 0x00083, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD0STS" , "ISD0 Status" }, + { 0x00084, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD0LPIB" , "ISD0 Link Position In Buffer" }, + { 0x00088, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD0CBL" , "ISD0 Cyclic Buffer Length" }, + { 0x0008C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD0LVI" , "ISD0 Last Valid Index" }, + { 0x0008E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "ISD0FIFOW", "ISD0 FIFO Watermark" }, + { 0x00090, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD0FIFOS", "ISD0 FIFO Size" }, + { 0x00092, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD0FMT" , "ISD0 Format" }, + { 0x00098, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD0BDPL" , "ISD0 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x0009C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD0BDPU" , "ISD0 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x000A0, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD1CTL" , "Input Stream Descriptor 1 (ISD1) Control" }, + { 0x000A3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD1STS" , "ISD1 Status" }, + { 0x000A4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD1LPIB" , "ISD1 Link Position In Buffer" }, + { 0x000A8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD1CBL" , "ISD1 Cyclic Buffer Length" }, + { 0x000AC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD1LVI" , "ISD1 Last Valid Index" }, + { 0x000AE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "ISD1FIFOW", "ISD1 FIFO Watermark" }, + { 0x000B0, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD1FIFOS", "ISD1 FIFO Size" }, + { 0x000B2, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD1FMT" , "ISD1 Format" }, + { 0x000B8, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD1BDPL" , "ISD1 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x000BC, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD1BDPU" , "ISD1 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x000C0, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD2CTL" , "Input Stream Descriptor 2 (ISD2) Control" }, + { 0x000C3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD2STS" , "ISD2 Status" }, + { 0x000C4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD2LPIB" , "ISD2 Link Position In Buffer" }, + { 0x000C8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD2CBL" , "ISD2 Cyclic Buffer Length" }, + { 0x000CC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD2LVI" , "ISD2 Last Valid Index" }, + { 0x000CE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "ISD2FIFOW", "ISD2 FIFO Watermark" }, + { 0x000D0, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD2FIFOS", "ISD2 FIFO Size" }, + { 0x000D2, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD2FMT" , "ISD2 Format" }, + { 0x000D8, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD2BDPL" , "ISD2 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x000DC, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD2BDPU" , "ISD2 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x000E0, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD3CTL" , "Input Stream Descriptor 3 (ISD3) Control" }, + { 0x000E3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD3STS" , "ISD3 Status" }, + { 0x000E4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD3LPIB" , "ISD3 Link Position In Buffer" }, + { 0x000E8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD3CBL" , "ISD3 Cyclic Buffer Length" }, + { 0x000EC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD3LVI" , "ISD3 Last Valid Index" }, + { 0x000EE, 0x00002, 0x00000005, 0x00000005, hdaRegReadU16 , hdaRegWriteU16 , "ISD3FIFOW", "ISD3 FIFO Watermark" }, + { 0x000F0, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD3FIFOS", "ISD3 FIFO Size" }, + { 0x000F2, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD3FMT" , "ISD3 Format" }, + { 0x000F8, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD3BDPL" , "ISD3 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x000FC, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD3BDPU" , "ISD3 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x00100, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadSDCTL , hdaRegWriteSDCTL , "OSD0CTL" , "Input Stream Descriptor 0 (OSD0) Control" }, + { 0x00103, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD0STS" , "OSD0 Status" }, + { 0x00104, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD0LPIB" , "OSD0 Link Position In Buffer" }, + { 0x00108, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD0CBL" , "OSD0 Cyclic Buffer Length" }, + { 0x0010C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD0LVI" , "OSD0 Last Valid Index" }, + { 0x0010E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD0FIFOW", "OSD0 FIFO Watermark" }, + { 0x00110, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD0FIFOS", "OSD0 FIFO Size" }, + { 0x00112, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD0FMT" , "OSD0 Format" }, + { 0x00118, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD0BDPL" , "OSD0 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x0011C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD0BDPU" , "OSD0 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x00120, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "OSD1CTL" , "Input Stream Descriptor 0 (OSD1) Control" }, + { 0x00123, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD1STS" , "OSD1 Status" }, + { 0x00124, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD1LPIB" , "OSD1 Link Position In Buffer" }, + { 0x00128, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD1CBL" , "OSD1 Cyclic Buffer Length" }, + { 0x0012C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD1LVI" , "OSD1 Last Valid Index" }, + { 0x0012E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD1FIFOW", "OSD1 FIFO Watermark" }, + { 0x00130, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD1FIFOS", "OSD1 FIFO Size" }, + { 0x00132, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD1FMT" , "OSD1 Format" }, + { 0x00138, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD1BDPL" , "OSD1 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x0013C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD1BDPU" , "OSD1 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x00140, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "OSD2CTL" , "Input Stream Descriptor 0 (OSD2) Control" }, + { 0x00143, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD2STS" , "OSD2 Status" }, + { 0x00144, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD2LPIB" , "OSD2 Link Position In Buffer" }, + { 0x00148, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD2CBL" , "OSD2 Cyclic Buffer Length" }, + { 0x0014C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD2LVI" , "OSD2 Last Valid Index" }, + { 0x0014E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD2FIFOW", "OSD2 FIFO Watermark" }, + { 0x00150, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD2FIFOS", "OSD2 FIFO Size" }, + { 0x00152, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD2FMT" , "OSD2 Format" }, + { 0x00158, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD2BDPL" , "OSD2 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x0015C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD2BDPU" , "OSD2 Buffer Descriptor List Pointer-Upper Base Address" }, + + { 0x00160, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "OSD3CTL" , "Input Stream Descriptor 0 (OSD3) Control" }, + { 0x00163, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD3STS" , "OSD3 Status" }, + { 0x00164, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD3LPIB" , "OSD3 Link Position In Buffer" }, + { 0x00168, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD3CBL" , "OSD3 Cyclic Buffer Length" }, + { 0x0016C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD3LVI" , "OSD3 Last Valid Index" }, + { 0x0016E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD3FIFOW", "OSD3 FIFO Watermark" }, + { 0x00170, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD3FIFOS", "OSD3 FIFO Size" }, + { 0x00172, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD3FMT" , "OSD3 Format" }, + { 0x00178, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD3BDPL" , "OSD3 Buffer Descriptor List Pointer-Lower Base Address" }, + { 0x0017C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD3BDPU" , "OSD3 Buffer Descriptor List Pointer-Upper Base Address" }, +}; + +/** + * HDA register aliases (HDA spec 3.3.45). + * @remarks Sorted by offReg. + */ +static const struct +{ + /** The alias register offset. */ + uint32_t offReg; + /** The register index. */ + int idxAlias; +} g_aHdaRegAliases[] = +{ + { 0x2084, HDA_REG_IND_NAME(SD0LPIB) }, + { 0x20a4, HDA_REG_IND_NAME(SD1LPIB) }, + { 0x20c4, HDA_REG_IND_NAME(SD2LPIB) }, + { 0x20e4, HDA_REG_IND_NAME(SD3LPIB) }, + { 0x2104, HDA_REG_IND_NAME(SD4LPIB) }, + { 0x2124, HDA_REG_IND_NAME(SD5LPIB) }, + { 0x2144, HDA_REG_IND_NAME(SD6LPIB) }, + { 0x2164, HDA_REG_IND_NAME(SD7LPIB) }, +}; + +#ifdef IN_RING3 +/** HDABDLEDESC field descriptors the v3+ saved state. */ +static SSMFIELD const g_aHdaBDLEDescFields[] = +{ + SSMFIELD_ENTRY( HDABDLEDESC, u64BdleCviAddr), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleMaxCvi), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCvi), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviLen), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviPos), + SSMFIELD_ENTRY( HDABDLEDESC, fBdleCviIoc), + SSMFIELD_ENTRY( HDABDLEDESC, cbUnderFifoW), + SSMFIELD_ENTRY( HDABDLEDESC, au8HdaBuffer), + SSMFIELD_ENTRY_TERM() +}; + +/** HDABDLEDESC field descriptors the v1 and v2 saved state. */ +static SSMFIELD const g_aHdaBDLEDescFieldsOld[] = +{ + SSMFIELD_ENTRY( HDABDLEDESC, u64BdleCviAddr), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleMaxCvi), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCvi), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviLen), + SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviPos), + SSMFIELD_ENTRY( HDABDLEDESC, fBdleCviIoc), + SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3), + SSMFIELD_ENTRY( HDABDLEDESC, cbUnderFifoW), + SSMFIELD_ENTRY( HDABDLEDESC, au8HdaBuffer), + SSMFIELD_ENTRY_TERM() +}; +#endif + +/** + * 32-bit size indexed masks, i.e. g_afMasks[2 bytes] = 0xffff. + */ +static uint32_t const g_afMasks[5] = +{ + UINT32_C(0), UINT32_C(0x000000ff), UINT32_C(0x0000ffff), UINT32_C(0x00ffffff), UINT32_C(0xffffffff) +}; + +#ifdef IN_RING3 +DECLINLINE(void) hdaUpdatePosBuf(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc) +{ + if (pThis->u64DPBase & DPBASE_ENABLED) + PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), + (pThis->u64DPBase & DPBASE_ADDR_MASK) + pStreamDesc->u8Strm * 8, + pStreamDesc->pu32Lpib, sizeof(uint32_t)); +} +#endif + +DECLINLINE(uint32_t) hdaFifoWToSz(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc) +{ +#if 0 + switch(HDA_STREAM_REG2(pThis, FIFOW, pStreamDesc->u8Strm)) + { + case HDA_SDFIFOW_8B: return 8; + case HDA_SDFIFOW_16B: return 16; + case HDA_SDFIFOW_32B: return 32; + default: + AssertMsgFailed(("hda: unsupported value (%x) in SDFIFOW(,%d)\n", HDA_REG_IND(pThis, pStreamDesc->u8Strm), pStreamDesc->u8Strm)); + } +#endif + return 0; +} + +static int hdaProcessInterrupt(PHDASTATE pThis) +{ +#define IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, num) \ + ( INTCTL_SX((pThis), num) \ + && (SDSTS(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) + bool fIrq = false; + if ( INTCTL_CIE(pThis) + && ( RIRBSTS_RINTFL(pThis) + || RIRBSTS_RIRBOIS(pThis) + || (STATESTS(pThis) & WAKEEN(pThis)))) + fIrq = true; + + if ( IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 0) + || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4)) + fIrq = true; + + if (INTCTL_GIE(pThis)) + { + Log(("hda: irq %s\n", fIrq ? "asserted" : "deasserted")); + PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , fIrq); + } + return VINF_SUCCESS; +} + +/** + * Looks up a register at the exact offset given by @a offReg. + * + * @returns Register index on success, -1 if not found. + * @param pThis The HDA device state. + * @param offReg The register offset. + */ +static int hdaRegLookup(PHDASTATE pThis, uint32_t offReg) +{ + /* + * Aliases. + */ + if (offReg >= g_aHdaRegAliases[0].offReg) + { + for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++) + if (offReg == g_aHdaRegAliases[i].offReg) + return g_aHdaRegAliases[i].idxAlias; + Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].offset < offReg); + return -1; + } + + /* + * Binary search the + */ + int idxEnd = RT_ELEMENTS(g_aHdaRegMap); + int idxLow = 0; + for (;;) + { + int idxMiddle = idxLow + (idxEnd - idxLow) / 2; + if (offReg < g_aHdaRegMap[idxMiddle].offset) + { + if (idxLow == idxMiddle) + break; + idxEnd = idxMiddle; + } + else if (offReg > g_aHdaRegMap[idxMiddle].offset) + { + idxLow = idxMiddle + 1; + if (idxLow >= idxEnd) + break; + } + else + return idxMiddle; + } + +#ifdef RT_STRICT + for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++) + Assert(g_aHdaRegMap[i].offset != offReg); +#endif + return -1; +} + +/** + * Looks up a register covering the offset given by @a offReg. + * + * @returns Register index on success, -1 if not found. + * @param pThis The HDA device state. + * @param offReg The register offset. + */ +static int hdaRegLookupWithin(PHDASTATE pThis, uint32_t offReg) +{ + /* + * Aliases. + */ + if (offReg >= g_aHdaRegAliases[0].offReg) + { + for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++) + { + uint32_t off = offReg - g_aHdaRegAliases[i].offReg; + if (off < 4 && off < g_aHdaRegMap[g_aHdaRegAliases[i].idxAlias].size) + return g_aHdaRegAliases[i].idxAlias; + } + Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].offset < offReg); + return -1; + } + + /* + * Binary search the + */ + int idxEnd = RT_ELEMENTS(g_aHdaRegMap); + int idxLow = 0; + for (;;) + { + int idxMiddle = idxLow + (idxEnd - idxLow) / 2; + if (offReg < g_aHdaRegMap[idxMiddle].offset) + { + if (idxLow == idxMiddle) + break; + idxEnd = idxMiddle; + } + else if (offReg >= g_aHdaRegMap[idxMiddle].offset + g_aHdaRegMap[idxMiddle].size) + { + idxLow = idxMiddle + 1; + if (idxLow >= idxEnd) + break; + } + else + return idxMiddle; + } + +#ifdef RT_STRICT + for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++) + Assert(offReg - g_aHdaRegMap[i].offset >= g_aHdaRegMap[i].size); +#endif + return -1; +} + +#ifdef IN_RING3 +static int hdaCmdSync(PHDASTATE pThis, bool fLocal) +{ + int rc = VINF_SUCCESS; + if (fLocal) + { + Assert((HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA))); + rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); +#ifdef DEBUG_CMD_BUFFER + uint8_t i = 0; + do + { + Log(("hda: corb%02x: ", i)); + uint8_t j = 0; + do + { + const char *prefix; + if ((i + j) == CORBRP(pThis)) + prefix = "[R]"; + else if ((i + j) == CORBWP(pThis)) + prefix = "[W]"; + else + prefix = " "; /* three spaces */ + Log(("%s%08x", prefix, pThis->pu32CorbBuf[i + j])); + j++; + } while (j < 8); + Log(("\n")); + i += 8; + } while(i != 0); +#endif + } + else + { + Assert((HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA))); + rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); +#ifdef DEBUG_CMD_BUFFER + uint8_t i = 0; + do { + Log(("hda: rirb%02x: ", i)); + uint8_t j = 0; + do { + const char *prefix; + if ((i + j) == RIRBWP(pThis)) + prefix = "[W]"; + else + prefix = " "; + Log((" %s%016lx", prefix, pThis->pu64RirbBuf[i + j])); + } while (++j < 8); + Log(("\n")); + i += 8; + } while (i != 0); +#endif + } + return rc; +} + +static int hdaCORBCmdProcess(PHDASTATE pThis) +{ + int rc; + uint8_t corbRp; + uint8_t corbWp; + uint8_t rirbWp; + + PFNHDACODECVERBPROCESSOR pfn = (PFNHDACODECVERBPROCESSOR)NULL; + + rc = hdaCmdSync(pThis, true); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + corbRp = CORBRP(pThis); + corbWp = CORBWP(pThis); + rirbWp = RIRBWP(pThis); + Assert((corbWp != corbRp)); + Log(("hda: CORB(RP:%x, WP:%x) RIRBWP:%x\n", CORBRP(pThis), CORBWP(pThis), RIRBWP(pThis))); + while (corbRp != corbWp) + { + uint32_t cmd; + uint64_t resp; + pfn = NULL; + corbRp++; + cmd = pThis->pu32CorbBuf[corbRp]; + rc = pThis->pCodec->pfnLookup(pThis->pCodec, cmd, &pfn); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + Assert(pfn); + (rirbWp)++; + + if (RT_LIKELY(pfn)) + rc = pfn(pThis->pCodec, cmd, &resp); + else + rc = VERR_INVALID_FUNCTION; + + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + Log(("hda: verb:%08x->%016lx\n", cmd, resp)); + if ( (resp & CODEC_RESPONSE_UNSOLICITED) + && !HDA_REG_FLAG_VALUE(pThis, GCTL, UR)) + { + Log(("hda: unexpected unsolicited response.\n")); + pThis->au32Regs[ICH6_HDA_REG_CORBRP] = corbRp; + return rc; + } + pThis->pu64RirbBuf[rirbWp] = resp; + pThis->u8Counter++; + if (pThis->u8Counter == RINTCNT_N(pThis)) + break; + } + pThis->au32Regs[ICH6_HDA_REG_CORBRP] = corbRp; + pThis->au32Regs[ICH6_HDA_REG_RIRBWP] = rirbWp; + rc = hdaCmdSync(pThis, false); + Log(("hda: CORB(RP:%x, WP:%x) RIRBWP:%x\n", CORBRP(pThis), CORBWP(pThis), RIRBWP(pThis))); + if (RIRBCTL_RIRB_RIC(pThis)) + { + RIRBSTS((pThis)) |= HDA_REG_FIELD_FLAG_MASK(RIRBSTS,RINTFL); + pThis->u8Counter = 0; + rc = hdaProcessInterrupt(pThis); + } + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + return rc; +} +#endif + +static void hdaStreamReset(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, uint8_t u8Strm) +{ + Log(("hda: reset of stream (%d) started\n", u8Strm)); + Assert(( pThis + && pBdle + && pStreamDesc + && u8Strm <= 7)); + memset(pBdle, 0, sizeof(HDABDLEDESC)); + *pStreamDesc->pu32Lpib = 0; + *pStreamDesc->pu32Sts = 0; + /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20 + * bits are reserved for stream number 18.2.33, resets SDnCTL except SRCT bit */ + HDA_STREAM_REG2(pThis, CTL, u8Strm) = 0x40000 | (HDA_STREAM_REG2(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST)); + + /* ICH6 defines default values (0x77 for input and 0xBF for output descriptors) of FIFO size. 18.2.39 */ + HDA_STREAM_REG2(pThis, FIFOS, u8Strm) = u8Strm < 4 ? HDA_SDINFIFO_120B : HDA_SDONFIFO_192B; + HDA_STREAM_REG2(pThis, FIFOW, u8Strm) = u8Strm < 4 ? HDA_SDFIFOW_8B : HDA_SDFIFOW_32B; + HDA_STREAM_REG2(pThis, CBL, u8Strm) = 0; + HDA_STREAM_REG2(pThis, LVI, u8Strm) = 0; + HDA_STREAM_REG2(pThis, FMT, u8Strm) = 0; + HDA_STREAM_REG2(pThis, BDPU, u8Strm) = 0; + HDA_STREAM_REG2(pThis, BDPL, u8Strm) = 0; + Log(("hda: reset of stream (%d) finished\n", u8Strm)); +} + +/* Register access handlers. */ + +static int hdaRegReadUnimplemented(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + *pu32Value = 0; + return VINF_SUCCESS; +} + +static int hdaRegWriteUnimplemented(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + return VINF_SUCCESS; +} + +/* U8 */ +static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + Assert(((pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0); + return hdaRegReadU32(pThis, iReg, pu32Value); +} + +static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + Assert((u32Value & 0xffffff00) == 0); + return hdaRegWriteU32(pThis, iReg, u32Value); +} + +/* U16 */ +static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + Assert(((pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable) & 0xffff0000) == 0); + return hdaRegReadU32(pThis, iReg, pu32Value); +} + +static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + Assert((u32Value & 0xffff0000) == 0); + return hdaRegWriteU32(pThis, iReg, u32Value); +} + +/* U24 */ +static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + Assert(((pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable) & 0xff000000) == 0); + return hdaRegReadU32(pThis, iReg, pu32Value); +} + +static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + Assert((u32Value & 0xff000000) == 0); + return hdaRegWriteU32(pThis, iReg, u32Value); +} + +/* U32 */ +static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + *pu32Value = pThis->au32Regs[iReg] & g_aHdaRegMap[iReg].readable; + return VINF_SUCCESS; +} + +static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + pThis->au32Regs[iReg] = (u32Value & g_aHdaRegMap[iReg].writable) + | (pThis->au32Regs[iReg] & ~g_aHdaRegMap[iReg].writable); + return VINF_SUCCESS; +} + +static int hdaRegReadGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + return hdaRegReadU32(pThis, iReg, pu32Value); +} + +static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, RST)) + { + /* exit reset state */ + GCTL(pThis) |= HDA_REG_FIELD_FLAG_MASK(GCTL, RST); + pThis->fInReset = false; + } + else + { +#ifdef IN_RING3 + /* enter reset state*/ + if ( HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) + || HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA)) + { + Log(("hda: HDA enters in reset with DMA(RIRB:%s, CORB:%s)\n", + HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) ? "on" : "off", + HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA) ? "on" : "off")); + } + hdaReset(pThis->CTX_SUFF(pDevIns)); + GCTL(pThis) &= ~HDA_REG_FIELD_FLAG_MASK(GCTL, RST); + pThis->fInReset = true; +#else + return VINF_IOM_R3_MMIO_WRITE; +#endif + } + if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, FSH)) + { + /* Flush: GSTS:1 set, see 6.2.6*/ + GSTS(pThis) |= HDA_REG_FIELD_FLAG_MASK(GSTS, FSH); /* set the flush state */ + /* DPLBASE and DPUBASE should be initialized with initial value (see 6.2.6)*/ + } + return VINF_SUCCESS; +} + +static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + uint32_t v = pThis->au32Regs[iReg]; + uint32_t nv = u32Value & ICH6_HDA_STATES_SCSF; + pThis->au32Regs[iReg] &= ~(v & nv); /* write of 1 clears corresponding bit */ + return VINF_SUCCESS; +} + +static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + uint32_t v = 0; + if ( RIRBSTS_RIRBOIS(pThis) + || RIRBSTS_RINTFL(pThis) + || HDA_REG_FLAG_VALUE(pThis, CORBSTS, CMEI) + || STATESTS(pThis)) + v |= RT_BIT(30); +#define HDA_IS_STREAM_EVENT(pThis, stream) \ + ( (SDSTS((pThis),stream) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)) \ + || (SDSTS((pThis),stream) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)) \ + || (SDSTS((pThis),stream) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) +#define MARK_STREAM(pThis, stream, v) do { (v) |= HDA_IS_STREAM_EVENT((pThis),stream) ? RT_BIT((stream)) : 0; } while(0) + MARK_STREAM(pThis, 0, v); + MARK_STREAM(pThis, 1, v); + MARK_STREAM(pThis, 2, v); + MARK_STREAM(pThis, 3, v); + MARK_STREAM(pThis, 4, v); + MARK_STREAM(pThis, 5, v); + MARK_STREAM(pThis, 6, v); + MARK_STREAM(pThis, 7, v); + v |= v ? RT_BIT(31) : 0; + *pu32Value = v; + return VINF_SUCCESS; +} + +static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */ + *pu32Value = (uint32_t)ASMMultU64ByU32DivByU32(PDMDevHlpTMTimeVirtGetNano(pThis->CTX_SUFF(pDevIns)) + - pThis->u64BaseTS, 24, 1000); + return VINF_SUCCESS; +} + +static int hdaRegReadGCAP(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + return hdaRegReadU16(pThis, iReg, pu32Value); +} + +static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + if (u32Value & HDA_REG_FIELD_FLAG_MASK(CORBRP, RST)) + CORBRP(pThis) = 0; +#ifndef BIRD_THINKS_CORBRP_IS_MOSTLY_RO + else + return hdaRegWriteU8(pThis, iReg, u32Value); +#endif + return VINF_SUCCESS; +} + +static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ +#ifdef IN_RING3 + int rc = hdaRegWriteU8(pThis, iReg, u32Value); + AssertRC(rc); + if ( CORBWP(pThis) != CORBRP(pThis) + && HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) != 0) + return hdaCORBCmdProcess(pThis); + return rc; +#else + return VINF_IOM_R3_MMIO_WRITE; +#endif +} + +static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + uint32_t v = CORBSTS(pThis); + CORBSTS(pThis) &= ~(v & u32Value); + return VINF_SUCCESS; +} + +static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ +#ifdef IN_RING3 + int rc; + rc = hdaRegWriteU16(pThis, iReg, u32Value); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + if (CORBWP(pThis) == CORBRP(pThis)) + return VINF_SUCCESS; + if (!HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)) + return VINF_SUCCESS; + rc = hdaCORBCmdProcess(pThis); + return rc; +#else + return VINF_IOM_R3_MMIO_WRITE; +#endif +} + +static int hdaRegReadSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + return hdaRegReadU24(pThis, iReg, pu32Value); +} + +static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + bool fRun = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)); + bool fInRun = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)); + bool fReset = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST)); + bool fInReset = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST)); + + if (fInReset) + { + /* + * Assert!!! Guest is resetting HDA's stream, we're expecting guest will mark stream as exit + * from reset + */ + Assert((!fReset)); + Log(("hda: guest initiated exit of stream reset.\n")); + } + else if (fReset) + { +#ifdef IN_RING3 + /* + * Assert!!! ICH6 datasheet 18.2.33 says that RUN bit should be cleared before initiation of reset. + */ + uint8_t u8Strm = 0; + PHDABDLEDESC pBdle = NULL; + HDASTREAMTRANSFERDESC StreamDesc; + Assert((!fInRun && !fRun)); + switch (iReg) + { + case ICH6_HDA_REG_SD0CTL: + u8Strm = 0; + pBdle = &pThis->StInBdle; + break; + case ICH6_HDA_REG_SD4CTL: + u8Strm = 4; + pBdle = &pThis->StOutBdle; + break; + default: + Log(("hda: changing SRST bit on non-attached stream\n")); + return hdaRegWriteU24(pThis, iReg, u32Value); + } + Log(("hda: guest initiated enter to stream reset.\n")); + hdaInitTransferDescriptor(pThis, pBdle, u8Strm, &StreamDesc); + hdaStreamReset(pThis, pBdle, &StreamDesc, u8Strm); +#else + return VINF_IOM_R3_MMIO_WRITE; +#endif + } + else + { +#ifdef IN_RING3 + /* we enter here to change DMA states only */ + if ( (fInRun && !fRun) + || (fRun && !fInRun)) + { + Assert((!fReset && !fInReset)); + switch (iReg) + { + case ICH6_HDA_REG_SD0CTL: + AUD_set_active_in(pThis->pCodec->SwVoiceIn, fRun); + break; + case ICH6_HDA_REG_SD4CTL: + AUD_set_active_out(pThis->pCodec->SwVoiceOut, fRun); + break; + default: + Log(("hda: changing RUN bit on non-attached stream\n")); + break; + } + } +#else + return VINF_IOM_R3_MMIO_WRITE; +#endif + } + + return hdaRegWriteU24(pThis, iReg, u32Value); +} + +static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + uint32_t v = HDA_REG_IND(pThis, iReg); + v &= ~(u32Value & v); + HDA_REG_IND(pThis, iReg) = v; + hdaProcessInterrupt(pThis); + return VINF_SUCCESS; +} + +static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + int rc = hdaRegWriteU32(pThis, iReg, u32Value); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, VINF_SUCCESS); + return rc; +} + +static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + switch (u32Value) + { + case HDA_SDFIFOW_8B: + case HDA_SDFIFOW_16B: + case HDA_SDFIFOW_32B: + return hdaRegWriteU16(pThis, iReg, u32Value); + default: + Log(("hda: Attempt to store unsupported value(%x) in SDFIFOW\n", u32Value)); + return hdaRegWriteU16(pThis, iReg, HDA_SDFIFOW_32B); + } + return VINF_SUCCESS; +} + +/** + * @note This method could be called for changing value on Output Streams + * only (ICH6 datasheet 18.2.39) + */ +static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + switch (iReg) + { + /* SDInFIFOS is RO, n=0-3 */ + case ICH6_HDA_REG_SD0FIFOS: + case ICH6_HDA_REG_SD1FIFOS: + case ICH6_HDA_REG_SD2FIFOS: + case ICH6_HDA_REG_SD3FIFOS: + Log(("hda: Guest tries change value of FIFO size of Input Stream\n")); + return VINF_SUCCESS; + case ICH6_HDA_REG_SD4FIFOS: + case ICH6_HDA_REG_SD5FIFOS: + case ICH6_HDA_REG_SD6FIFOS: + case ICH6_HDA_REG_SD7FIFOS: + switch(u32Value) + { + case HDA_SDONFIFO_16B: + case HDA_SDONFIFO_32B: + case HDA_SDONFIFO_64B: + case HDA_SDONFIFO_128B: + case HDA_SDONFIFO_192B: + return hdaRegWriteU16(pThis, iReg, u32Value); + + case HDA_SDONFIFO_256B: + Log(("hda: 256-bit is unsupported, HDA is switched into 192-bit mode\n")); + default: + return hdaRegWriteU16(pThis, iReg, HDA_SDONFIFO_192B); + } + return VINF_SUCCESS; + default: + AssertMsgFailed(("Something weird happened with register lookup routine")); + } + return VINF_SUCCESS; +} + +#ifdef IN_RING3 +static void hdaSdFmtToAudSettings(uint32_t u32SdFmt, audsettings_t *pAudSetting) +{ + Assert((pAudSetting)); +#define EXTRACT_VALUE(v, mask, shift) ((v & ((mask) << (shift))) >> (shift)) + uint32_t u32Hz = (u32SdFmt & ICH6_HDA_SDFMT_BASE_RATE_SHIFT) ? 44100 : 48000; + uint32_t u32HzMult = 1; + uint32_t u32HzDiv = 1; + switch (EXTRACT_VALUE(u32SdFmt, ICH6_HDA_SDFMT_MULT_MASK, ICH6_HDA_SDFMT_MULT_SHIFT)) + { + case 0: u32HzMult = 1; break; + case 1: u32HzMult = 2; break; + case 2: u32HzMult = 3; break; + case 3: u32HzMult = 4; break; + default: + Log(("hda: unsupported multiplier %x\n", u32SdFmt)); + } + switch (EXTRACT_VALUE(u32SdFmt, ICH6_HDA_SDFMT_DIV_MASK, ICH6_HDA_SDFMT_DIV_SHIFT)) + { + case 0: u32HzDiv = 1; break; + case 1: u32HzDiv = 2; break; + case 2: u32HzDiv = 3; break; + case 3: u32HzDiv = 4; break; + case 4: u32HzDiv = 5; break; + case 5: u32HzDiv = 6; break; + case 6: u32HzDiv = 7; break; + case 7: u32HzDiv = 8; break; + } + pAudSetting->freq = u32Hz * u32HzMult / u32HzDiv; + + switch (EXTRACT_VALUE(u32SdFmt, ICH6_HDA_SDFMT_BITS_MASK, ICH6_HDA_SDFMT_BITS_SHIFT)) + { + case 0: + Log(("hda: %s requested 8-bit\n", __FUNCTION__)); + pAudSetting->fmt = AUD_FMT_S8; + break; + case 1: + Log(("hda: %s requested 16-bit\n", __FUNCTION__)); + pAudSetting->fmt = AUD_FMT_S16; + break; + case 2: + Log(("hda: %s requested 20-bit\n", __FUNCTION__)); + break; + case 3: + Log(("hda: %s requested 24-bit\n", __FUNCTION__)); + break; + case 4: + Log(("hda: %s requested 32-bit\n", __FUNCTION__)); + pAudSetting->fmt = AUD_FMT_S32; + break; + default: + AssertMsgFailed(("Unsupported")); + } + pAudSetting->nchannels = (u32SdFmt & 0xf) + 1; + pAudSetting->fmt = AUD_FMT_S16; + pAudSetting->endianness = 0; +#undef EXTRACT_VALUE +} +#endif + +static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ +#ifdef IN_RING3 +# ifdef VBOX_WITH_HDA_CODEC_EMU + /** @todo a bit more investigation is required here. */ + int rc = 0; + audsettings_t as; + /* no reason to reopen voice with same settings */ + if (u32Value == HDA_REG_IND(pThis, iReg)) + return VINF_SUCCESS; + hdaSdFmtToAudSettings(u32Value, &as); + switch (iReg) + { + case ICH6_HDA_REG_SD0FMT: + rc = hdaCodecOpenVoice(pThis->pCodec, PI_INDEX, &as); + break; + case ICH6_HDA_REG_SD4FMT: + rc = hdaCodecOpenVoice(pThis->pCodec, PO_INDEX, &as); + break; + default: + Log(("HDA: attempt to change format on %d\n", iReg)); + rc = 0; + } + return hdaRegWriteU16(pThis, iReg, u32Value); +# else + return hdaRegWriteU16(pThis, iReg, u32Value); +# endif +#else + return VINF_IOM_R3_MMIO_WRITE; +#endif +} + +static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + int rc = hdaRegWriteU32(pThis, iReg, u32Value); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, VINF_SUCCESS); + return rc; +} + +static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + int rc = hdaRegWriteU32(pThis, iReg, u32Value); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, VINF_SUCCESS); + return rc; +} + +static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value) +{ + int rc = VINF_SUCCESS; + /* regarding 3.4.3 we should mark IRS as busy in case CORB is active */ + if ( CORBWP(pThis) != CORBRP(pThis) + || HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)) + IRS(pThis) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */ + + rc = hdaRegReadU32(pThis, iReg, pu32Value); + return rc; +} + +static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + int rc = VINF_SUCCESS; + + /* + * if guest set the ICB bit of IRS register, HDA should process the verb in IC register, + * write the response to IR register, and set the IRV (valid in case of success) bit of IRS register. + */ + if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, ICB) + && !IRS_ICB(pThis)) + { +#ifdef IN_RING3 + PFNHDACODECVERBPROCESSOR pfn = NULL; + uint64_t resp; + uint32_t cmd = IC(pThis); + if (CORBWP(pThis) != CORBRP(pThis)) + { + /* + * 3.4.3 defines behavior of immediate Command status register. + */ + LogRel(("hda: guest attempted process immediate verb (%x) with active CORB\n", cmd)); + return rc; + } + IRS(pThis) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */ + Log(("hda: IC:%x\n", cmd)); + rc = pThis->pCodec->pfnLookup(pThis->pCodec, cmd, &pfn); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + rc = pfn(pThis->pCodec, cmd, &resp); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + IR(pThis) = (uint32_t)resp; + Log(("hda: IR:%x\n", IR(pThis))); + IRS(pThis) = HDA_REG_FIELD_FLAG_MASK(IRS, IRV); /* result is ready */ + IRS(pThis) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy is clear */ +#else + rc = VINF_IOM_R3_MMIO_WRITE; +#endif + return rc; + } + /* + * Once the guest read the response, it should clean the IRV bit of the IRS register. + */ + if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, IRV) + && IRS_IRV(pThis)) + IRS(pThis) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, IRV); + return rc; +} + +static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + if (u32Value & HDA_REG_FIELD_FLAG_MASK(RIRBWP, RST)) + { + RIRBWP(pThis) = 0; + } + /* The remaining bits are O, see 6.2.22 */ + return VINF_SUCCESS; +} + +static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + int rc = hdaRegWriteU32(pThis, iReg, u32Value); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + switch(iReg) + { + case ICH6_HDA_REG_CORBLBASE: + pThis->u64CORBBase &= UINT64_C(0xFFFFFFFF00000000); + pThis->u64CORBBase |= pThis->au32Regs[iReg]; + break; + case ICH6_HDA_REG_CORBUBASE: + pThis->u64CORBBase &= UINT64_C(0x00000000FFFFFFFF); + pThis->u64CORBBase |= ((uint64_t)pThis->au32Regs[iReg] << 32); + break; + case ICH6_HDA_REG_RIRLBASE: + pThis->u64RIRBBase &= UINT64_C(0xFFFFFFFF00000000); + pThis->u64RIRBBase |= pThis->au32Regs[iReg]; + break; + case ICH6_HDA_REG_RIRUBASE: + pThis->u64RIRBBase &= UINT64_C(0x00000000FFFFFFFF); + pThis->u64RIRBBase |= ((uint64_t)pThis->au32Regs[iReg] << 32); + break; + case ICH6_HDA_REG_DPLBASE: + /** @todo: first bit has special meaning */ + pThis->u64DPBase &= UINT64_C(0xFFFFFFFF00000000); + pThis->u64DPBase |= pThis->au32Regs[iReg]; + break; + case ICH6_HDA_REG_DPUBASE: + pThis->u64DPBase &= UINT64_C(0x00000000FFFFFFFF); + pThis->u64DPBase |= ((uint64_t)pThis->au32Regs[iReg] << 32); + break; + default: + AssertMsgFailed(("Invalid index")); + } + Log(("hda: CORB base:%llx RIRB base: %llx DP base: %llx\n", pThis->u64CORBBase, pThis->u64RIRBBase, pThis->u64DPBase)); + return rc; +} + +static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value) +{ + uint8_t v = RIRBSTS(pThis); + RIRBSTS(pThis) &= ~(v & u32Value); + + return hdaProcessInterrupt(pThis); +} + +#ifdef IN_RING3 +#ifdef LOG_ENABLED +static void dump_bd(PHDASTATE pThis, PHDABDLEDESC pBdle, uint64_t u64BaseDMA) +{ +#if 0 + uint64_t addr; + uint32_t len; + uint32_t ioc; + uint8_t bdle[16]; + uint32_t counter; + uint32_t i; + uint32_t sum = 0; + Assert(pBdle && pBdle->u32BdleMaxCvi); + for (i = 0; i <= pBdle->u32BdleMaxCvi; ++i) + { + PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + i*16, bdle, 16); + addr = *(uint64_t *)bdle; + len = *(uint32_t *)&bdle[8]; + ioc = *(uint32_t *)&bdle[12]; + Log(("hda: %s bdle[%d] a:%llx, len:%d, ioc:%d\n", (i == pBdle->u32BdleCvi? "[C]": " "), i, addr, len, ioc & 0x1)); + sum += len; + } + Log(("hda: sum: %d\n", sum)); + for (i = 0; i < 8; ++i) + { + PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), (pThis->u64DPBase & DPBASE_ADDR_MASK) + i*8, &counter, sizeof(&counter)); + Log(("hda: %s stream[%d] counter=%x\n", i == SDCTL_NUM(pThis, 4) || i == SDCTL_NUM(pThis, 0)? "[C]": " ", + i , counter)); + } +#endif +} +#endif + +static void hdaFetchBdle(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc) +{ + uint8_t bdle[16]; + Assert(( pStreamDesc->u64BaseDMA + && pBdle + && pBdle->u32BdleMaxCvi)); + PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pStreamDesc->u64BaseDMA + pBdle->u32BdleCvi*16, bdle, 16); + pBdle->u64BdleCviAddr = *(uint64_t *)bdle; + pBdle->u32BdleCviLen = *(uint32_t *)&bdle[8]; + pBdle->fBdleCviIoc = (*(uint32_t *)&bdle[12]) & 0x1; +#ifdef LOG_ENABLED + dump_bd(pThis, pBdle, pStreamDesc->u64BaseDMA); +#endif +} + +DECLINLINE(uint32_t) hdaCalculateTransferBufferLength(PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, + uint32_t u32SoundBackendBufferBytesAvail, uint32_t u32CblLimit) +{ + uint32_t cb2Copy; + /* + * Number of bytes depends on the current position in buffer (u32BdleCviLen-u32BdleCviPos) + */ + Assert((pBdle->u32BdleCviLen >= pBdle->u32BdleCviPos)); /* sanity */ + cb2Copy = pBdle->u32BdleCviLen - pBdle->u32BdleCviPos; + /* + * we may increase the counter in range of [0, FIFOS + 1] + */ + cb2Copy = RT_MIN(cb2Copy, pStreamDesc->u32Fifos + 1); + Assert((u32SoundBackendBufferBytesAvail > 0)); + + /* sanity check to avoid overriding the backend audio buffer */ + cb2Copy = RT_MIN(cb2Copy, u32SoundBackendBufferBytesAvail); + cb2Copy = RT_MIN(cb2Copy, u32CblLimit); + + if (cb2Copy <= pBdle->cbUnderFifoW) + return 0; + cb2Copy -= pBdle->cbUnderFifoW; /* forcibly reserve the amount of unreported bytes to copy */ + return cb2Copy; +} + +DECLINLINE(void) hdaBackendWriteTransferReported(PHDABDLEDESC pBdle, uint32_t cbArranged2Copy, uint32_t cbCopied, + uint32_t *pu32DMACursor, uint32_t *pu32BackendBufferCapacity) +{ + Log(("hda:hdaBackendWriteTransferReported: cbArranged2Copy: %d, cbCopied: %d, pu32DMACursor: %d, pu32BackendBufferCapacity:%d\n", + cbArranged2Copy, cbCopied, pu32DMACursor ? *pu32DMACursor : 0, pu32BackendBufferCapacity ? *pu32BackendBufferCapacity : 0)); + Assert((cbCopied)); + Assert((pu32BackendBufferCapacity && *pu32BackendBufferCapacity)); + /* Assertion!!! Fewer than cbUnderFifoW bytes were copied. + * Probably we need to move the buffer, but it is rather hard to imagine a situation + * where it might happen. + */ + Assert((cbCopied == pBdle->cbUnderFifoW + cbArranged2Copy)); /* we assume that we write the entire buffer including unreported bytes */ + if ( pBdle->cbUnderFifoW + && pBdle->cbUnderFifoW <= cbCopied) + Log(("hda:hdaBackendWriteTransferReported: CVI resetting cbUnderFifoW:%d(pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); + + pBdle->cbUnderFifoW -= RT_MIN(pBdle->cbUnderFifoW, cbCopied); + Assert((!pBdle->cbUnderFifoW)); /* Assert!!! Incorrect assumption */ + + /* We always increment the position of DMA buffer counter because we're always reading into an intermediate buffer */ + pBdle->u32BdleCviPos += cbArranged2Copy; + + Assert((pBdle->u32BdleCviLen >= pBdle->u32BdleCviPos && *pu32BackendBufferCapacity >= cbCopied)); /* sanity */ + /* We report all bytes (including previously unreported bytes) */ + *pu32DMACursor += cbCopied; + /* Decrease the backend counter by the number of bytes we copied to the backend */ + *pu32BackendBufferCapacity -= cbCopied; + Log(("hda:hdaBackendWriteTransferReported: CVI(pos:%d, len:%d), pu32DMACursor: %d, pu32BackendBufferCapacity:%d\n", + pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, *pu32DMACursor, *pu32BackendBufferCapacity)); +} + +DECLINLINE(void) hdaBackendReadTransferReported(PHDABDLEDESC pBdle, uint32_t cbArranged2Copy, uint32_t cbCopied, + uint32_t *pu32DMACursor, uint32_t *pu32BackendBufferCapacity) +{ + Assert((cbCopied, cbArranged2Copy)); + *pu32BackendBufferCapacity -= cbCopied; + pBdle->u32BdleCviPos += cbCopied; + Log(("hda:hdaBackendReadTransferReported: CVI resetting cbUnderFifoW:%d(pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); + *pu32DMACursor += cbCopied + pBdle->cbUnderFifoW; + pBdle->cbUnderFifoW = 0; + Log(("hda:hdaBackendReadTransferReported: CVI(pos:%d, len:%d), pu32DMACursor: %d, pu32BackendBufferCapacity:%d\n", + pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, pu32DMACursor ? *pu32DMACursor : 0, pu32BackendBufferCapacity ? *pu32BackendBufferCapacity : 0)); +} + +DECLINLINE(void) hdaBackendTransferUnreported(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, + uint32_t cbCopied, uint32_t *pu32BackendBufferCapacity) +{ + Log(("hda:hdaBackendTransferUnreported: CVI (cbUnderFifoW:%d, pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); + pBdle->u32BdleCviPos += cbCopied; + pBdle->cbUnderFifoW += cbCopied; + /* In case of a read transaction we're always copying from the backend buffer */ + if (pu32BackendBufferCapacity) + *pu32BackendBufferCapacity -= cbCopied; + Log(("hda:hdaBackendTransferUnreported: CVI (cbUnderFifoW:%d, pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); + Assert((pBdle->cbUnderFifoW <= hdaFifoWToSz(pThis, pStreamDesc))); +} + +DECLINLINE(bool) hdaIsTransferCountersOverlapped(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc) +{ + bool fOnBufferEdge = ( *pStreamDesc->pu32Lpib == pStreamDesc->u32Cbl + || pBdle->u32BdleCviPos == pBdle->u32BdleCviLen); + + Assert((*pStreamDesc->pu32Lpib <= pStreamDesc->u32Cbl)); + + if (*pStreamDesc->pu32Lpib == pStreamDesc->u32Cbl) + *pStreamDesc->pu32Lpib -= pStreamDesc->u32Cbl; + hdaUpdatePosBuf(pThis, pStreamDesc); + + /* don't touch BdleCvi counter on uninitialized descriptor */ + if ( pBdle->u32BdleCviPos + && pBdle->u32BdleCviPos == pBdle->u32BdleCviLen) + { + pBdle->u32BdleCviPos = 0; + pBdle->u32BdleCvi++; + if (pBdle->u32BdleCvi == pBdle->u32BdleMaxCvi + 1) + pBdle->u32BdleCvi = 0; + } + return fOnBufferEdge; +} + +DECLINLINE(void) hdaStreamCounterUpdate(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, + uint32_t cbInc) +{ + /* + * if we're below the FIFO Watermark, it's expected that HDA doesn't fetch anything. + * (ICH6 datasheet 18.2.38) + */ + if (!pBdle->cbUnderFifoW) + { + *pStreamDesc->pu32Lpib += cbInc; + + /* + * Assert. The buffer counters should never overlap. + */ + Assert((*pStreamDesc->pu32Lpib <= pStreamDesc->u32Cbl)); + + hdaUpdatePosBuf(pThis, pStreamDesc); + + } +} + +static bool hdaDoNextTransferCycle(PHDASTATE pThis, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc) +{ + bool fDoNextTransferLoop = true; + if ( pBdle->u32BdleCviPos == pBdle->u32BdleCviLen + || *pStreamDesc->pu32Lpib == pStreamDesc->u32Cbl) + { + if ( !pBdle->cbUnderFifoW + && pBdle->fBdleCviIoc) + { + /** + * @todo - more carefully investigate BCIS flag. + * Speech synthesis works fine on Mac Guest if this bit isn't set + * but in general sound quality gets worse. + */ + *pStreamDesc->pu32Sts |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS); + + /* + * we should generate the interrupt if ICE bit of SDCTL register is set. + */ + if (pStreamDesc->u32Ctl & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE)) + hdaProcessInterrupt(pThis); + } + fDoNextTransferLoop = false; + } + return fDoNextTransferLoop; +} + +/* + * hdaReadAudio - copies samples from audio backend to DMA. + * Note: this function writes to the DMA buffer immediately, but "reports bytes" when all conditions are met (FIFOW) + */ +static uint32_t hdaReadAudio(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t *pu32Avail, bool *fStop, uint32_t u32CblLimit) +{ + PHDABDLEDESC pBdle = &pThis->StInBdle; + uint32_t cbTransferred = 0; + uint32_t cb2Copy = 0; + uint32_t cbBackendCopy = 0; + + Log(("hda:ra: CVI(pos:%d, len:%d)\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); + + cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pu32Avail, u32CblLimit); + if (!cb2Copy) + /* if we enter here we can't report "unreported bits" */ + *fStop = true; + else + { + /* + * read from backend input line to the last unreported position or at the begining. + */ + cbBackendCopy = AUD_read(pThis->pCodec->SwVoiceIn, pBdle->au8HdaBuffer, cb2Copy); + /* + * write the HDA DMA buffer + */ + PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos, pBdle->au8HdaBuffer, cbBackendCopy); + + /* Don't see any reason why cb2Copy would differ from cbBackendCopy */ + Assert((cbBackendCopy == cb2Copy && (*pu32Avail) >= cb2Copy)); /* sanity */ + + if (pBdle->cbUnderFifoW + cbBackendCopy > hdaFifoWToSz(pThis, 0)) + hdaBackendReadTransferReported(pBdle, cb2Copy, cbBackendCopy, &cbTransferred, pu32Avail); + else + { + hdaBackendTransferUnreported(pThis, pBdle, pStreamDesc, cbBackendCopy, pu32Avail); + *fStop = true; + } + } + + Assert((cbTransferred <= (SDFIFOS(pThis, 0) + 1))); + Log(("hda:ra: CVI(pos:%d, len:%d) cbTransferred: %d\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransferred)); + return cbTransferred; +} + +static uint32_t hdaWriteAudio(PHDASTATE pThis, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t *pu32Avail, bool *fStop, uint32_t u32CblLimit) +{ + PHDABDLEDESC pBdle = &pThis->StOutBdle; + uint32_t cbTransferred = 0; + uint32_t cb2Copy = 0; /* local byte counter (on local buffer) */ + uint32_t cbBackendCopy = 0; /* local byte counter, how many bytes copied to backend */ + + Log(("hda:wa: CVI(cvi:%d, pos:%d, len:%d)\n", pBdle->u32BdleCvi, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); + + cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pu32Avail, u32CblLimit); + + /* + * Copy from DMA to the corresponding hdaBuffer (if there are any bytes from the + * previous unreported transfer we write at offset 'pBdle->cbUnderFifoW'). + */ + if (!cb2Copy) + *fStop = true; + else + { + PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos, pBdle->au8HdaBuffer + pBdle->cbUnderFifoW, cb2Copy); + /* + * Write to audio backend. we should ensure that we have enough bytes to copy to the backend. + */ + if (cb2Copy + pBdle->cbUnderFifoW >= hdaFifoWToSz(pThis, pStreamDesc)) + { + /* + * Feed the newly fetched samples, including unreported ones, to the backend. + */ + cbBackendCopy = AUD_write (pThis->pCodec->SwVoiceOut, pBdle->au8HdaBuffer, cb2Copy + pBdle->cbUnderFifoW); + hdaBackendWriteTransferReported(pBdle, cb2Copy, cbBackendCopy, &cbTransferred, pu32Avail); + } + else + { + /* Not enough bytes to be processed and reported, we'll try our luck next time around */ + hdaBackendTransferUnreported(pThis, pBdle, pStreamDesc, cb2Copy, NULL); + *fStop = true; + } + } + + Assert(cbTransferred <= SDFIFOS(pThis, 4) + 1); + Log(("hda:wa: CVI(pos:%d, len:%d, cbTransferred:%d)\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransferred)); + return cbTransferred; +} + +/** + * @interface_method_impl{HDACODEC,pfnReset} + */ +DECLCALLBACK(int) hdaCodecReset(PHDACODEC pCodec) +{ + PHDASTATE pThis = (PHDASTATE)pCodec->pvHDAState; + NOREF(pThis); + return VINF_SUCCESS; +} + +DECLINLINE(void) hdaInitTransferDescriptor(PHDASTATE pThis, PHDABDLEDESC pBdle, uint8_t u8Strm, + PHDASTREAMTRANSFERDESC pStreamDesc) +{ + Assert(pThis); Assert(pBdle); Assert(pStreamDesc); Assert(u8Strm <= 7); + + memset(pStreamDesc, 0, sizeof(HDASTREAMTRANSFERDESC)); + pStreamDesc->u8Strm = u8Strm; + pStreamDesc->u32Ctl = HDA_STREAM_REG2(pThis, CTL, u8Strm); + pStreamDesc->u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG2(pThis, BDPL, u8Strm), + HDA_STREAM_REG2(pThis, BDPU, u8Strm)); + pStreamDesc->pu32Lpib = &HDA_STREAM_REG2(pThis, LPIB, u8Strm); + pStreamDesc->pu32Sts = &HDA_STREAM_REG2(pThis, STS, u8Strm); + pStreamDesc->u32Cbl = HDA_STREAM_REG2(pThis, CBL, u8Strm); + pStreamDesc->u32Fifos = HDA_STREAM_REG2(pThis, FIFOS, u8Strm); + + pBdle->u32BdleMaxCvi = HDA_STREAM_REG2(pThis, LVI, u8Strm); + +#ifdef LOG_ENABLED + if ( pBdle + && pBdle->u32BdleMaxCvi) + { + Log(("Initialization of transfer descriptor:\n")); + dump_bd(pThis, pBdle, pStreamDesc->u64BaseDMA); + } +#endif +} + + +/** + * @interface_method_impl{HDACODEC,pfnTransfer} + */ +static DECLCALLBACK(void) hdaTransfer(PHDACODEC pCodec, ENMSOUNDSOURCE src, int avail) +{ + PHDASTATE pThis = (PHDASTATE)pCodec->pvHDAState; + uint8_t u8Strm = 0; + PHDABDLEDESC pBdle = NULL; + + switch (src) + { + case PO_INDEX: + { + u8Strm = 4; + pBdle = &pThis->StOutBdle; + break; + } + case PI_INDEX: + { + u8Strm = 0; + pBdle = &pThis->StInBdle; + break; + } + default: + return; + } + + HDASTREAMTRANSFERDESC StreamDesc; + hdaInitTransferDescriptor(pThis, pBdle, u8Strm, &StreamDesc); + + bool fStop = false; + while (avail && !fStop) + { + Assert( (StreamDesc.u32Ctl & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)) + && avail + && StreamDesc.u64BaseDMA); + + /* Fetch the Buffer Descriptor Entry (BDE). */ + + if (hdaIsTransferCountersOverlapped(pThis, pBdle, &StreamDesc)) + hdaFetchBdle(pThis, pBdle, &StreamDesc); + *StreamDesc.pu32Sts |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY); + Assert((avail >= 0 && (StreamDesc.u32Cbl >= (*StreamDesc.pu32Lpib)))); /* sanity */ + uint32_t u32CblLimit = StreamDesc.u32Cbl - (*StreamDesc.pu32Lpib); + Assert((u32CblLimit > hdaFifoWToSz(pThis, &StreamDesc))); + Log(("hda: CBL=%d, LPIB=%d\n", StreamDesc.u32Cbl, *StreamDesc.pu32Lpib)); + uint32_t cb; + switch (src) + { + case PO_INDEX: + cb = hdaWriteAudio(pThis, &StreamDesc, (uint32_t *)&avail, &fStop, u32CblLimit); + break; + case PI_INDEX: + cb = hdaReadAudio(pThis, &StreamDesc, (uint32_t *)&avail, &fStop, u32CblLimit); + break; + default: + cb = 0; + fStop = true; + AssertMsgFailed(("Unsupported")); + } + Assert(cb <= StreamDesc.u32Fifos + 1); + *StreamDesc.pu32Sts &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY); + + /* Process end of buffer condition. */ + hdaStreamCounterUpdate(pThis, pBdle, &StreamDesc, cb); + fStop = !fStop ? !hdaDoNextTransferCycle(pThis, pBdle, &StreamDesc) : fStop; + } +} +#endif + +/* MMIO callbacks */ + +/** + * @callback_method_impl{FNIOMMMIOREAD, Looks up and calls the appropriate handler.} + * + * @note During implementation, we discovered so-called "forgotten" or "hole" + * registers whose description is not listed in the RPM, datasheet, or + * spec. + */ +PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + int rc; + + /* + * Look up and log. + */ + uint32_t offReg = GCPhysAddr - pThis->MMIOBaseAddr; + int idxReg = hdaRegLookup(pThis, offReg); +#ifdef LOG_ENABLED + unsigned const cbLog = cb; + uint32_t offRegLog = offReg; +#endif + + Log(("hdaMMIORead: offReg=%#x cb=%#x\n", offReg, cb)); +#define NEW_READ_CODE +#ifdef NEW_READ_CODE + Assert(cb == 4); Assert((offReg & 3) == 0); + + if (pThis->fInReset && idxReg != ICH6_HDA_REG_GCTL) + Log(("hda: access to registers except GCTL is blocked while reset\n")); + + if (idxReg == -1) + LogRel(("hda: Invalid read access @0x%x(of bytes:%d)\n", offReg, cb)); + + if (idxReg != -1) + { + /* ASSUMES gapless DWORD at end of map. */ + if (g_aHdaRegMap[idxReg].size == 4) + { + /* + * Straight forward DWORD access. + */ + rc = g_aHdaRegMap[idxReg].pfnRead(pThis, idxReg, (uint32_t *)pv); + Log(("hda: read %s => %x (%Rrc)\n", g_aHdaRegMap[idxReg].abbrev, *(uint32_t *)pv, rc)); + } + else + { + /* + * Multi register read (unless there are trailing gaps). + * ASSUMES that only DWORD reads have sideeffects. + */ + uint32_t u32Value = 0; + unsigned cbLeft = 4; + do + { + uint32_t const cbReg = g_aHdaRegMap[idxReg].size; + uint32_t u32Tmp = 0; + + rc = g_aHdaRegMap[idxReg].pfnRead(pThis, idxReg, &u32Tmp); + Log(("hda: read %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxReg].abbrev, cbReg, u32Tmp, rc)); + if (rc != VINF_SUCCESS) + break; + u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8); + + cbLeft -= cbReg; + offReg += cbReg; + idxReg++; + } while (cbLeft > 0 && g_aHdaRegMap[idxReg].offset == offReg); + + if (rc == VINF_SUCCESS) + *(uint32_t *)pv = u32Value; + else + Assert(!IOM_SUCCESS(rc)); + } + } + else + { + rc = VINF_IOM_MMIO_UNUSED_FF; + Log(("hda: hole at %x is accessed for read\n", offReg)); + } +#else + if (idxReg != -1) + { + /** @todo r=bird: Accesses crossing register boundraries aren't handled + * right from what I can tell? If they are, please explain + * what the rules are. */ + uint32_t mask = 0; + uint32_t shift = (g_aHdaRegMap[idxReg].offset - offReg) % sizeof(uint32_t) * 8; + uint32_t u32Value = 0; + switch(cb) + { + case 1: mask = 0x000000ff; break; + case 2: mask = 0x0000ffff; break; + case 4: + /* 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word */ + case 8: + mask = 0xffffffff; + cb = 4; + break; + } +#if 0 + /* Cross-register access. Mac guest hits this assert doing assumption 4 byte access to 3 byte registers e.g. {I,O}SDnCTL + */ + //Assert((cb <= g_aHdaRegMap[idxReg].size - (offReg - g_aHdaRegMap[idxReg].offset))); + if (cb > g_aHdaRegMap[idxReg].size - (offReg - g_aHdaRegMap[idxReg].offset)) + { + int off = cb - (g_aHdaRegMap[idxReg].size - (offReg - g_aHdaRegMap[idxReg].offset)); + rc = hdaMMIORead(pDevIns, pvUser, GCPhysAddr + cb - off, (char *)pv + cb - off, off); + if (RT_FAILURE(rc)) + AssertRCReturn (rc, rc); + } + //Assert(((offReg - g_aHdaRegMap[idxReg].offset) == 0)); +#endif + mask <<= shift; + rc = g_aHdaRegMap[idxReg].pfnRead(pThis, idxReg, &u32Value); + *(uint32_t *)pv |= (u32Value & mask); + Log(("hda: read %s[%x/%x]\n", g_aHdaRegMap[idxReg].abbrev, u32Value, *(uint32_t *)pv)); + } + else + { + *(uint32_t *)pv = 0xFF; + Log(("hda: hole at %x is accessed for read\n", offReg)); + rc = VINF_SUCCESS; + } +#endif + + /* + * Log the outcome. + */ +#ifdef LOG_ENABLED + if (cbLog == 4) + Log(("hdaMMIORead: @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc)); + else if (cbLog == 2) + Log(("hdaMMIORead: @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc)); + else if (cbLog == 1) + Log(("hdaMMIORead: @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc)); +#endif + return rc; +} + + +DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxReg, uint32_t u32Value, char const *pszLog) +{ + if (pThis->fInReset && idxReg != ICH6_HDA_REG_GCTL) + Log(("hda: access to registers except GCTL is blocked while reset\n")); /** @todo where is this enforced? */ + +#ifdef LOG_ENABLED + uint32_t const u32CurValue = pThis->au32Regs[idxReg]; +#endif + int rc = g_aHdaRegMap[idxReg].pfnWrite(pThis, idxReg, u32Value); + Log(("hda: write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxReg].abbrev, + g_aHdaRegMap[idxReg].size, u32CurValue, pThis->au32Regs[idxReg], pszLog)); + return rc; +} + + +/** + * @callback_method_impl{FNIOMMMIOWRITE, Looks up and calls the appropriate handler.} + */ +PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + int rc; + + /* + * The behavior of accesses that aren't aligned on natural boundraries is + * undefined. Just reject them out right. + */ + /** @todo IOM could check this, it could also split the 8 byte accesses for us. */ + Assert(cb == 1 || cb == 2 || cb == 4 || cb == 8); + if (GCPhysAddr & (cb - 1)) + return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "misaligned write access: GCPhysAddr=%RGp cb=%u\n", GCPhysAddr, cb); + + /* + * Lookup and log the access. + */ + uint32_t offReg = GCPhysAddr - pThis->MMIOBaseAddr; + int idxReg = hdaRegLookup(pThis, offReg); + uint64_t u64Value; + if (cb == 4) u64Value = *(uint32_t const *)pv; + else if (cb == 2) u64Value = *(uint16_t const *)pv; + else if (cb == 1) u64Value = *(uint8_t const *)pv; + else if (cb == 8) u64Value = *(uint64_t const *)pv; + else + { + u64Value = 0; /* shut up gcc. */ + AssertReleaseMsgFailed(("%d\n", cb)); + } + +#ifdef LOG_ENABLED + uint32_t const u32LogOldValue = idxReg != -1 ? pThis->au32Regs[idxReg] : UINT32_MAX; + uint32_t const offRegLog = offReg; + int const idxRegLog = idxReg; + if (idxReg == -1) + Log(("hdaMMIOWrite: @%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb)); + else if (cb == 4) + Log(("hdaMMIOWrite: @%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxReg].abbrev)); + else if (cb == 2) + Log(("hdaMMIOWrite: @%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxReg].abbrev)); + else if (cb == 1) + Log(("hdaMMIOWrite: @%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxReg].abbrev)); + if (idxReg != -1 && g_aHdaRegMap[idxReg].size != cb) + Log(("hdaMMIOWrite: size=%d != cb=%d!!\n", g_aHdaRegMap[idxReg].size, cb)); +#endif + +#define NEW_WRITE_CODE +#ifdef NEW_WRITE_CODE + /* + * Try for a direct hit first. + */ + if (idxReg != -1 && g_aHdaRegMap[idxReg].size == cb) + rc = hdaWriteReg(pThis, idxReg, u64Value, ""); + /* + * Partial or multiple register access, loop thru the requested memory. + */ + else + { + /* If it's an access beyond the start of the register, shift the input + value and fill in missing bits. Natural alignment rules means we + will only see 1 or 2 byte accesses of this kind, so no risk of + shifting out input values. */ + if (idxReg == -1 && (idxReg = hdaRegLookupWithin(pThis, offReg)) != -1) + { + uint32_t const cbBefore = offReg - g_aHdaRegMap[idxReg].offset; Assert(cbBefore > 0 && cbBefore < 4); + offReg -= cbBefore; + u64Value <<= cbBefore * 8; + u64Value |= pThis->au32Regs[idxReg] & g_afMasks[cbBefore]; + Log(("hdaMMIOWrite: Within register, supplied %u leading bits: %#llx -> %#llx ...\n", + cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value)); + } + + /* Loop thru the write area, it may covert multiple registers. */ + rc = VINF_SUCCESS; + for (;;) + { + uint32_t cbReg; + if (idxReg != -1) + { + cbReg = g_aHdaRegMap[idxReg].size; + if (cb < cbReg) + { + u64Value |= pThis->au32Regs[idxReg] & g_afMasks[cbReg] & ~g_afMasks[cb]; + Log(("hdaMMIOWrite: Supplying missing bits (%#x): %#llx -> %#llx ...\n", + g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value)); + } + rc = hdaWriteReg(pThis, idxReg, u64Value, "*"); + } + else + { + LogRel(("hda: Invalid write access @0x%x!\n", offReg)); + cbReg = 1; + } + if (rc != VINF_SUCCESS) + break; + if (cbReg >= cb) + break; + + /* advance */ + offReg += cbReg; + cb -= cbReg; + u64Value >>= cbReg * 8; + if (idxReg == -1) + idxReg = hdaRegLookup(pThis, offReg); + else + { + idxReg++; + if ( (unsigned)idxReg >= RT_ELEMENTS(g_aHdaRegMap) + || g_aHdaRegMap[idxReg].offset != offReg) + idxReg = -1; + } + } + } +#else + if (idxReg != -1) + { + /** @todo r=bird: This looks like code for handling unaligned register + * accesses. If it isn't, then add a comment explaining what you're + * trying to do here. OTOH, if it is then it has the following + * issues: + * -# You're calculating the wrong new value for the register. + * -# You're not handling cross register accesses. Imagine a + * 4-byte write starting at CORBCTL, or a 8-byte write. + * + * PS! consider dropping the 'offset' argument to pfnWrite/pfnRead as + * nobody seems to be using it and it just adds complexity when reading + * the code. + * + */ + uint32_t u32CurValue = pThis->au32Regs[idxReg]; + uint32_t u32NewValue; + uint32_t mask; + switch (cb) + { + case 1: + u32NewValue = *(uint8_t const *)pv; + mask = 0xff; + break; + case 2: + u32NewValue = *(uint16_t const *)pv; + mask = 0xffff; + break; + case 4: + case 8: + /* 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word */ + u32NewValue = *(uint32_t const *)pv; + mask = 0xffffffff; + cb = 4; + break; + default: + AssertFailedReturn(VERR_INTERNAL_ERROR_4); /* shall not happen. */ + } + /* cross-register access, see corresponding comment in hdaMMIORead */ + uint32_t shift = (g_aHdaRegMap[idxReg].offset - offReg) % sizeof(uint32_t) * 8; + mask <<= shift; + u32NewValue <<= shift; + u32NewValue &= mask; + u32NewValue |= (u32CurValue & ~mask); + + rc = g_aHdaRegMap[idxReg].pfnWrite(pThis, idxReg, u32NewValue); + Log(("hda: write %s:(%x) %x => %x\n", g_aHdaRegMap[idxReg].abbrev, u32NewValue, + u32CurValue, pThis->au32Regs[idxReg])); + } + else + rc = VINF_SUCCESS; +#endif + Log(("hdaMMIOWrite: @%#05x %#x -> %#x\n", offRegLog, u32LogOldValue, + idxRegLog != -1 ? pThis->au32Regs[idxRegLog] : UINT32_MAX)); + return rc; +} + + +/* PCI callback. */ + +#ifdef IN_RING3 +/** + * @callback_method_impl{FNPCIIOREGIONMAP} + */ +static DECLCALLBACK(int) hdaPciIoRegionMap(PPCIDEVICE pPciDev, int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, + PCIADDRESSSPACE enmType) +{ + PPDMDEVINS pDevIns = pPciDev->pDevIns; + PHDASTATE pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev); + RTIOPORT Port = (RTIOPORT)GCPhysAddress; + int rc; + + /* + * 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word. + * + * Let IOM talk DWORDs when reading, saves a lot of complications. On + * writing though, we have to do it all ourselves because of sideeffects. + */ + Assert(enmType == PCI_ADDRESS_SPACE_MEM); + rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/, +#ifdef NEW_READ_CODE + IOMMMIO_FLAGS_READ_DWORD | +#else + IOMMMIO_FLAGS_READ_PASSTHRU | +#endif + IOMMMIO_FLAGS_WRITE_PASSTHRU, + hdaMMIOWrite, hdaMMIORead, "ICH6_HDA"); + + if (RT_FAILURE(rc)) + return rc; + + if (pThis->fR0Enabled) + { + rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/, + "hdaMMIOWrite", "hdaMMIORead"); + if (RT_FAILURE(rc)) + return rc; + } + + if (pThis->fRCEnabled) + { + rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/, + "hdaMMIOWrite", "hdaMMIORead"); + if (RT_FAILURE(rc)) + return rc; + } + + pThis->MMIOBaseAddr = GCPhysAddress; + return VINF_SUCCESS; +} + + +/* Saved state callbacks. */ + +/** + * @callback_method_impl{FNSSMDEVSAVEEXEC} + */ +static DECLCALLBACK(int) hdaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + /* Save Codec nodes states */ + hdaCodecSaveState(pThis->pCodec, pSSM); + + /* Save MMIO registers */ + AssertCompile(RT_ELEMENTS(pThis->au32Regs) == 112); + SSMR3PutU32(pSSM, RT_ELEMENTS(pThis->au32Regs)); + SSMR3PutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs)); + + /* Save HDA dma counters */ + SSMR3PutStructEx(pSSM, &pThis->StOutBdle, sizeof(pThis->StOutBdle), 0 /*fFlags*/, g_aHdaBDLEDescFields, NULL); + SSMR3PutStructEx(pSSM, &pThis->StMicBdle, sizeof(pThis->StMicBdle), 0 /*fFlags*/, g_aHdaBDLEDescFields, NULL); + SSMR3PutStructEx(pSSM, &pThis->StInBdle, sizeof(pThis->StInBdle), 0 /*fFlags*/, g_aHdaBDLEDescFields, NULL); + return VINF_SUCCESS; +} + + +/** + * @callback_method_impl{FNSSMDEVLOADEXEC} + */ +static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + + Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); + + /* + * Load Codec nodes states. + */ + int rc = hdaCodecLoadState(pThis->pCodec, pSSM, uVersion); + if (RT_FAILURE(rc)) + return rc; + + /* + * Load MMIO registers. + */ + uint32_t cRegs; + switch (uVersion) + { + case HDA_SSM_VERSION_1: + /* Starting with r71199, we would save 112 instead of 113 + registers due to some code cleanups. This only affected trunk + builds in the 4.1 development period. */ + cRegs = 113; + if (SSMR3HandleRevision(pSSM) >= 71199) + { + uint32_t uVer = SSMR3HandleVersion(pSSM); + if ( VBOX_FULL_VERSION_GET_MAJOR(uVer) == 4 + && VBOX_FULL_VERSION_GET_MINOR(uVer) == 0 + && VBOX_FULL_VERSION_GET_BUILD(uVer) >= 51) + cRegs = 112; + } + break; + + case HDA_SSM_VERSION_2: + case HDA_SSM_VERSION_3: + cRegs = 112; + AssertCompile(RT_ELEMENTS(pThis->au32Regs) == 112); + break; + + case HDA_SSM_VERSION: + rc = SSMR3GetU32(pSSM, &cRegs); AssertRCReturn(rc, rc); + AssertLogRelMsgReturn(cRegs == RT_ELEMENTS(pThis->au32Regs), + ("cRegs is %d, expected %d\n", cRegs, RT_ELEMENTS(pThis->au32Regs)), + VERR_SSM_DATA_UNIT_FORMAT_CHANGED); + break; + + default: + return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; + } + + if (cRegs >= RT_ELEMENTS(pThis->au32Regs)) + { + SSMR3GetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs)); + SSMR3Skip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs))); + } + else + { + RT_ZERO(pThis->au32Regs); + SSMR3GetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs); + } + + /* + * Load HDA dma counters. + */ + uint32_t fFlags = uVersion <= HDA_SSM_VERSION_2 ? SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED : 0; + PCSSMFIELD paFields = uVersion <= HDA_SSM_VERSION_2 ? g_aHdaBDLEDescFieldsOld : g_aHdaBDLEDescFields; + SSMR3GetStructEx(pSSM, &pThis->StOutBdle, sizeof(pThis->StOutBdle), fFlags, paFields, NULL); + SSMR3GetStructEx(pSSM, &pThis->StMicBdle, sizeof(pThis->StMicBdle), fFlags, paFields, NULL); + rc = SSMR3GetStructEx(pSSM, &pThis->StInBdle, sizeof(pThis->StInBdle), fFlags, paFields, NULL); + AssertRCReturn(rc, rc); + + /* + * Update stuff after the state changes. + */ + AUD_set_active_in(pThis->pCodec->SwVoiceIn, SDCTL(pThis, 0) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)); + AUD_set_active_out(pThis->pCodec->SwVoiceOut, SDCTL(pThis, 4) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)); + + pThis->u64CORBBase = RT_MAKE_U64(CORBLBASE(pThis), CORBUBASE(pThis)); + pThis->u64RIRBBase = RT_MAKE_U64(RIRLBASE(pThis), RIRUBASE(pThis)); + pThis->u64DPBase = RT_MAKE_U64(DPLBASE(pThis), DPUBASE(pThis)); + return VINF_SUCCESS; +} + + +/* Debug and log type formatters. */ + +/** + * @callback_method_impl{FNRTSTRFORMATTYPE} + */ +static DECLCALLBACK(size_t) +hdaFormatStrmCtl(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char *pszType, void const *pvValue, + int cchWidth, int cchPrecision, unsigned fFlags, + void *pvUser) +{ + uint32_t sdCtl = (uint32_t)(uintptr_t)pvValue; + return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, + "SDCTL(raw: %#x, strm:%#x, dir:%RTbool, tp:%RTbool strip:%x, deie:%RTbool, ioce:%RTbool, run:%RTbool, srst:%RTbool)", + sdCtl, + (sdCtl & HDA_REG_FIELD_MASK(SDCTL, NUM)) >> ICH6_HDA_SDCTL_NUM_SHIFT, + RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, DIR)), + RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, TP)), + (sdCtl & HDA_REG_FIELD_MASK(SDCTL, STRIPE)) >> ICH6_HDA_SDCTL_STRIPE_SHIFT, + RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, DEIE)), + RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE)), + RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)), + RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST))); +} + +/** + * @callback_method_impl{FNRTSTRFORMATTYPE} + */ +static DECLCALLBACK(size_t) +hdaFormatStrmFifos(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char *pszType, void const *pvValue, + int cchWidth, int cchPrecision, unsigned fFlags, + void *pvUser) +{ + uint32_t uSdFifos = (uint32_t)(uintptr_t)pvValue; + uint32_t cb; + switch (uSdFifos) + { + case HDA_SDONFIFO_16B: cb = 16; break; + case HDA_SDONFIFO_32B: cb = 32; break; + case HDA_SDONFIFO_64B: cb = 64; break; + case HDA_SDONFIFO_128B: cb = 128; break; + case HDA_SDONFIFO_192B: cb = 192; break; + case HDA_SDONFIFO_256B: cb = 256; break; + case HDA_SDINFIFO_120B: cb = 120; break; + case HDA_SDINFIFO_160B: cb = 160; break; + default: cb = 0; break; + } + return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw: %#x, sdfifos:%u B)", uSdFifos, cb); +} + +/** + * @callback_method_impl{FNRTSTRFORMATTYPE} + */ +static DECLCALLBACK(size_t) +hdaFormatStrmFifow(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char *pszType, void const *pvValue, + int cchWidth, int cchPrecision, unsigned fFlags, + void *pvUser) +{ + uint32_t uSdFifos = (uint32_t)(uintptr_t)pvValue; + uint32_t cb; + switch (uSdFifos) + { + case HDA_SDFIFOW_8B: cb = 8; break; + case HDA_SDFIFOW_16B: cb = 16; break; + case HDA_SDFIFOW_32B: cb = 32; break; + default: cb = 0; break; + } + return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSdFifos, cb); +} + +/** + * @callback_method_impl{FNRTSTRFORMATTYPE} + */ +static DECLCALLBACK(size_t) +hdaFormatStrmSts(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, + const char *pszType, void const *pvValue, + int cchWidth, int cchPrecision, unsigned fFlags, + void *pvUser) +{ + uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue; + return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, + "SDSTS(raw: %#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)", + uSdSts, + RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY)), + RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)), + RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)), + RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))); +} + + +static int hdaLookUpRegisterByName(PHDASTATE pThis, const char *pszArgs) +{ + int iReg = 0; + for (; iReg < HDA_NREGS; ++iReg) + if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs)) + return iReg; + return -1; +} + + +static void hdaDbgPrintRegister(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex) +{ + Assert( pThis + && iHdaIndex >= 0 + && iHdaIndex < HDA_NREGS); + pHlp->pfnPrintf(pHlp, "hda: %s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[iHdaIndex]); +} + + +/** + * @callback_method_impl{FNDBGFHANDLERDEV} + */ +static DECLCALLBACK(void) hdaInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + int iHdaRegisterIndex = hdaLookUpRegisterByName(pThis, pszArgs); + if (iHdaRegisterIndex != -1) + hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex); + else + for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NREGS; ++iHdaRegisterIndex) + hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex); +} + + +static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaStrmIndex) +{ + Assert( pThis + && iHdaStrmIndex >= 0 + && iHdaStrmIndex < 7); + pHlp->pfnPrintf(pHlp, "Dump of %d HDA Stream:\n", iHdaStrmIndex); + pHlp->pfnPrintf(pHlp, "SD%dCTL: %R[sdctl]\n", iHdaStrmIndex, HDA_STREAM_REG2(pThis, CTL, iHdaStrmIndex)); + pHlp->pfnPrintf(pHlp, "SD%dCTS: %R[sdsts]\n", iHdaStrmIndex, HDA_STREAM_REG2(pThis, STS, iHdaStrmIndex)); + pHlp->pfnPrintf(pHlp, "SD%dFIFOS: %R[sdfifos]\n", iHdaStrmIndex, HDA_STREAM_REG2(pThis, FIFOS, iHdaStrmIndex)); + pHlp->pfnPrintf(pHlp, "SD%dFIFOW: %R[sdfifow]\n", iHdaStrmIndex, HDA_STREAM_REG2(pThis, FIFOW, iHdaStrmIndex)); +} + + +static int hdaLookUpStreamIndex(PHDASTATE pThis, const char *pszArgs) +{ + /* todo: add args parsing */ + return -1; +} + + +/** + * @callback_method_impl{FNDBGFHANDLERDEV} + */ +static DECLCALLBACK(void) hdaInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + int iHdaStrmIndex = hdaLookUpStreamIndex(pThis, pszArgs); + if (iHdaStrmIndex != -1) + hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex); + else + for(iHdaStrmIndex = 0; iHdaStrmIndex < 7; ++iHdaStrmIndex) + hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex); +} + +/** + * @callback_method_impl{FNDBGFHANDLERDEV} + */ +static DECLCALLBACK(void) hdaInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + if (pThis->pCodec->pfnCodecDbgListNodes) + pThis->pCodec->pfnCodecDbgListNodes(pThis->pCodec, pHlp, pszArgs); + else + pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback.\n"); +} + + +/** + * @callback_method_impl{FNDBGFHANDLERDEV} + */ +static DECLCALLBACK(void) hdaInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + if (pThis->pCodec->pfnCodecDbgSelector) + pThis->pCodec->pfnCodecDbgSelector(pThis->pCodec, pHlp, pszArgs); + else + pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback.\n"); +} + + +/* PDMIBASE */ + +/** + * @interface_method_impl{PDMIBASE,pfnQueryInterface} + */ +static DECLCALLBACK(void *) hdaQueryInterface(struct PDMIBASE *pInterface, const char *pszIID) +{ + PHDASTATE pThis = RT_FROM_MEMBER(pInterface, HDASTATE, IBase); + Assert(&pThis->IBase == pInterface); + + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase); + return NULL; +} + + +/* PDMDEVREG */ + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remark The original sources didn't install a reset handler, but it seems to + * make sense to me so we'll do it. + */ +static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + GCAP(pThis) = HDA_MAKE_GCAP(4,4,0,0,1); /* see 6.2.1 */ + VMIN(pThis) = 0x00; /* see 6.2.2 */ + VMAJ(pThis) = 0x01; /* see 6.2.3 */ + VMAJ(pThis) = 0x01; /* see 6.2.3 */ + OUTPAY(pThis) = 0x003C; /* see 6.2.4 */ + INPAY(pThis) = 0x001D; /* see 6.2.5 */ + pThis->au32Regs[ICH6_HDA_REG_CORBSIZE] = 0x42; /* see 6.2.1 */ + pThis->au32Regs[ICH6_HDA_REG_RIRBSIZE] = 0x42; /* see 6.2.1 */ + CORBRP(pThis) = 0x0; + RIRBWP(pThis) = 0x0; + + Log(("hda: inter HDA reset.\n")); + pThis->cbCorbBuf = 256 * sizeof(uint32_t); + + if (pThis->pu32CorbBuf) + memset(pThis->pu32CorbBuf, 0, pThis->cbCorbBuf); + else + pThis->pu32CorbBuf = (uint32_t *)RTMemAllocZ(pThis->cbCorbBuf); + + pThis->cbRirbBuf = 256 * sizeof(uint64_t); + if (pThis->pu64RirbBuf) + memset(pThis->pu64RirbBuf, 0, pThis->cbRirbBuf); + else + pThis->pu64RirbBuf = (uint64_t *)RTMemAllocZ(pThis->cbRirbBuf); + + pThis->u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns); + + HDABDLEDESC StEmptyBdle; + for (uint8_t u8Strm = 0; u8Strm < 8; ++u8Strm) + { + HDASTREAMTRANSFERDESC StreamDesc; + PHDABDLEDESC pBdle = NULL; + if (u8Strm == 0) + pBdle = &pThis->StInBdle; + else if(u8Strm == 4) + pBdle = &pThis->StOutBdle; + else + { + memset(&StEmptyBdle, 0, sizeof(HDABDLEDESC)); + pBdle = &StEmptyBdle; + } + hdaInitTransferDescriptor(pThis, pBdle, u8Strm, &StreamDesc); + /* hdaStreamReset prevents changing the SRST bit, so we force it to zero here. */ + HDA_STREAM_REG2(pThis, CTL, u8Strm) = 0; + hdaStreamReset(pThis, pBdle, &StreamDesc, u8Strm); + } + + /* emulation of codec "wake up" (HDA spec 5.5.1 and 6.5)*/ + STATESTS(pThis) = 0x1; + + Log(("hda: reset finished\n")); +} + + +/** + * @interface_method_impl{PDMDEVREG,pfnDestruct} + */ +static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + + if (pThis->pCodec) + { + int rc = hdaCodecDestruct(pThis->pCodec); + AssertRC(rc); + + RTMemFree(pThis->pCodec); + pThis->pCodec = NULL; + } + + RTMemFree(pThis->pu32CorbBuf); + pThis->pu32CorbBuf = NULL; + + RTMemFree(pThis->pu64RirbBuf); + pThis->pu64RirbBuf = NULL; + + return VINF_SUCCESS; +} + +/** + * @interface_method_impl{PDMDEVREG,pfnConstruct} + */ +static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle) +{ + PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE); + int rc; + + Assert(iInstance == 0); + PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); + + /* + * Validations. + */ + if (!CFGMR3AreValuesValid(pCfgHandle, "R0Enabled\0" + "RCEnabled\0")) + return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, + N_ ("Invalid configuration for the Intel HDA device")); + + rc = CFGMR3QueryBoolDef(pCfgHandle, "RCEnabled", &pThis->fRCEnabled, false); + if (RT_FAILURE(rc)) + return PDMDEV_SET_ERROR(pDevIns, rc, + N_("HDA configuration error: failed to read RCEnabled as boolean")); + rc = CFGMR3QueryBoolDef(pCfgHandle, "R0Enabled", &pThis->fR0Enabled, false); + if (RT_FAILURE(rc)) + return PDMDEV_SET_ERROR(pDevIns, rc, + N_("HDA configuration error: failed to read R0Enabled as boolean")); + + /* + * Initialize data (most of it anyway). + */ + pThis->pDevInsR3 = pDevIns; + pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); + pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); + /* IBase */ + pThis->IBase.pfnQueryInterface = hdaQueryInterface; + + /* PCI Device */ + PCIDevSetVendorId (&pThis->PciDev, HDA_PCI_VENDOR_ID); /* nVidia */ + PCIDevSetDeviceId (&pThis->PciDev, HDA_PCI_DEVICE_ID); /* HDA */ + + PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ + PCIDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */ + PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ + PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ + PCIDevSetClassSub (&pThis->PciDev, 0x03); /* 0a ro - scc; 03 == HDA. */ + PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ + PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ + PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - MMIO */ + false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000); + PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ + PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ + +#if defined(HDA_AS_PCI_EXPRESS) + PCIDevSetCapabilityList (&pThis->PciDev, 0x80); +#elif defined(VBOX_WITH_MSI_DEVICES) + PCIDevSetCapabilityList (&pThis->PciDev, 0x60); +#else + PCIDevSetCapabilityList (&pThis->PciDev, 0x50); /* ICH6 datasheet 18.1.16 */ +#endif + + /// @todo r=michaln: If there are really no PCIDevSetXx for these, the meaning + /// of these values needs to be properly documented! + /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */ + PCIDevSetByte(&pThis->PciDev, 0x40, 0x01); + + /* Power Management */ + PCIDevSetByte(&pThis->PciDev, 0x50 + 0, VBOX_PCI_CAP_ID_PM); + PCIDevSetByte(&pThis->PciDev, 0x50 + 1, 0x0); /* next */ + PCIDevSetWord(&pThis->PciDev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ ); + +#ifdef HDA_AS_PCI_EXPRESS + /* PCI Express */ + PCIDevSetByte(&pThis->PciDev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */ + PCIDevSetByte(&pThis->PciDev, 0x80 + 1, 0x60); /* next */ + /* Device flags */ + PCIDevSetWord(&pThis->PciDev, 0x80 + 2, + /* version */ 0x1 | + /* Root Complex Integrated Endpoint */ (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) | + /* MSI */ (100) << 9 ); + /* Device capabilities */ + PCIDevSetDWord(&pThis->PciDev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET); + /* Device control */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 8, 0); + /* Device status */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 10, 0); + /* Link caps */ + PCIDevSetDWord(&pThis->PciDev, 0x80 + 12, 0); + /* Link control */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 16, 0); + /* Link status */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 18, 0); + /* Slot capabilities */ + PCIDevSetDWord(&pThis->PciDev, 0x80 + 20, 0); + /* Slot control */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 24, 0); + /* Slot status */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 26, 0); + /* Root control */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 28, 0); + /* Root capabilities */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 30, 0); + /* Root status */ + PCIDevSetDWord(&pThis->PciDev, 0x80 + 32, 0); + /* Device capabilities 2 */ + PCIDevSetDWord(&pThis->PciDev, 0x80 + 36, 0); + /* Device control 2 */ + PCIDevSetQWord(&pThis->PciDev, 0x80 + 40, 0); + /* Link control 2 */ + PCIDevSetQWord(&pThis->PciDev, 0x80 + 48, 0); + /* Slot control 2 */ + PCIDevSetWord( &pThis->PciDev, 0x80 + 56, 0); +#endif + + /* + * Register the PCI device. + */ + rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev); + if (RT_FAILURE(rc)) + return rc; + + rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaPciIoRegionMap); + if (RT_FAILURE(rc)) + return rc; + +#ifdef VBOX_WITH_MSI_DEVICES + PDMMSIREG MsiReg; + RT_ZERO(MsiReg); + MsiReg.cMsiVectors = 1; + MsiReg.iMsiCapOffset = 0x60; + MsiReg.iMsiNextOffset = 0x50; + rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg); + if (RT_FAILURE(rc)) + { + LogRel(("Chipset cannot do MSI: %Rrc\n", rc)); + PCIDevSetCapabilityList(&pThis->PciDev, 0x50); + } +#endif + + rc = PDMDevHlpSSMRegister(pDevIns, HDA_SSM_VERSION, sizeof(*pThis), hdaSaveExec, hdaLoadExec); + if (RT_FAILURE(rc)) + return rc; + + /* + * Attach driver. + */ + rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port"); + if (rc == VERR_PDM_NO_ATTACHED_DRIVER) + Log(("hda: No attached driver!\n")); + else if (RT_FAILURE(rc)) + { + AssertMsgFailed(("Failed to attach Intel HDA LUN #0! rc=%Rrc\n", rc)); + return rc; + } + + /* Construct codec state. */ + pThis->pCodec = (PHDACODEC)RTMemAllocZ(sizeof(HDACODEC)); + if (!pThis->pCodec) + return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("HDA: Out of memory allocating codec state")); + + pThis->pCodec->pvHDAState = pThis; + rc = hdaCodecConstruct(pDevIns, pThis->pCodec, pCfgHandle); + if (RT_FAILURE(rc)) + AssertRCReturn(rc, rc); + + /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for + verb F20 should provide device/codec recognition. */ + Assert(pThis->pCodec->u16VendorId); + Assert(pThis->pCodec->u16DeviceId); + PCIDevSetSubSystemVendorId(&pThis->PciDev, pThis->pCodec->u16VendorId); /* 2c ro - intel.) */ + PCIDevSetSubSystemId( &pThis->PciDev, pThis->pCodec->u16DeviceId); /* 2e ro. */ + + hdaReset(pDevIns); + pThis->pCodec->id = 0; + pThis->pCodec->pfnTransfer = hdaTransfer; + pThis->pCodec->pfnReset = hdaCodecReset; + + /* + * 18.2.6,7 defines that values of this registers might be cleared on power on/reset + * hdaReset shouldn't affects these registers. + */ + WAKEEN(pThis) = 0x0; + STATESTS(pThis) = 0x0; + + /* + * Debug and string formatter types. + */ + PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA info. (hda [register case-insensitive])", hdaInfo); + PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm", "HDA stream info. (hdastrm [stream number])", hdaInfoStream); + PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaInfoCodecNodes); + PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaInfoCodecSelector); + + rc = RTStrFormatTypeRegister("sdctl", hdaFormatStrmCtl, NULL); + AssertRC(rc); + rc = RTStrFormatTypeRegister("sdsts", hdaFormatStrmSts, NULL); + AssertRC(rc); + rc = RTStrFormatTypeRegister("sdfifos", hdaFormatStrmFifos, NULL); + AssertRC(rc); + rc = RTStrFormatTypeRegister("sdfifow", hdaFormatStrmFifow, NULL); + AssertRC(rc); +#if 0 + rc = RTStrFormatTypeRegister("sdfmt", printHdaStrmFmt, NULL); + AssertRC(rc); +#endif + + /* + * Some debug assertions. + */ + for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++) + { + struct HDAREGDESC const *pReg = &g_aHdaRegMap[i]; + struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL; + + /* binary search order. */ + AssertReleaseMsg(!pNextReg || pReg->offset + pReg->size <= pNextReg->offset, + ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n", + i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size)); + + /* alignment. */ + AssertReleaseMsg( pReg->size == 1 + || (pReg->size == 2 && (pReg->offset & 1) == 0) + || (pReg->size == 3 && (pReg->offset & 3) == 0) + || (pReg->size == 4 && (pReg->offset & 3) == 0), + ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size)); + + /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */ + AssertRelease(((pReg->offset + pReg->size) & 3) == 0 || pNextReg); + if (pReg->offset & 3) + { + struct HDAREGDESC const *pPrevReg = i > 0 ? &g_aHdaRegMap[i - 1] : NULL; + AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size)); + if (pPrevReg) + AssertReleaseMsg(pPrevReg->offset + pPrevReg->size == pReg->offset, + ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n", + i - 1, pPrevReg->offset, pPrevReg->size, i + 1, pReg->offset, pReg->size)); + } +#if 0 + if ((pReg->offset + pReg->size) & 3) + { + AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size)); + if (pNextReg) + AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset, + ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n", + i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size)); + } +#endif + + /* The final entry is a full dword, no gaps! Allows shortcuts. */ + AssertReleaseMsg(pNextReg || ((pReg->offset + pReg->size) & 3) == 0, + ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size)); + } + + return VINF_SUCCESS; +} + +/** + * The device registration structure. + */ +const PDMDEVREG g_DeviceICH6_HDA = +{ + /* u32Version */ + PDM_DEVREG_VERSION, + /* szName */ + "hda", + /* szRCMod */ + "VBoxDDGC.gc", + /* szR0Mod */ + "VBoxDDR0.r0", + /* pszDescription */ + "Intel HD Audio Controller", + /* fFlags */ + PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0, + /* fClass */ + PDM_DEVREG_CLASS_AUDIO, + /* cMaxInstances */ + 1, + /* cbInstance */ + sizeof(HDASTATE), + /* pfnConstruct */ + hdaConstruct, + /* pfnDestruct */ + hdaDestruct, + /* pfnRelocate */ + NULL, + /* pfnMemSetup */ + NULL, + /* pfnPowerOn */ + NULL, + /* pfnReset */ + hdaReset, + /* pfnSuspend */ + NULL, + /* pfnResume */ + NULL, + /* pfnAttach */ + NULL, + /* pfnDetach */ + NULL, + /* pfnQueryInterface. */ + NULL, + /* pfnInitComplete */ + NULL, + /* pfnPowerOff */ + NULL, + /* pfnSoftReset */ + NULL, + /* u32VersionEnd */ + PDM_DEVREG_VERSION +}; + +#endif /* IN_RING3 */ +#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */ diff --git a/src/VBox/Devices/Audio/DevIchHdaCodec.cpp b/src/VBox/Devices/Audio/DevIchHdaCodec.cpp new file mode 100644 index 00000000..6689f92e --- /dev/null +++ b/src/VBox/Devices/Audio/DevIchHdaCodec.cpp @@ -0,0 +1,2444 @@ +/* $Id: DevIchHdaCodec.cpp $ */ +/** @file + * DevIchHdaCodec - VBox ICH Intel HD Audio Codec. + * + * Implemented against "Intel I/O Controller Hub 6 (ICH6) High Definition + * Audio / AC '97 - Programmer's Reference Manual (PRM)", document number + * 302349-003. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP LOG_GROUP_DEV_AUDIO +#include <VBox/vmm/pdmdev.h> +#include <iprt/assert.h> +#include <iprt/uuid.h> +#include <iprt/string.h> +#include <iprt/mem.h> +#include <iprt/asm.h> +#include <iprt/cpp/utils.h> + +#include "VBoxDD.h" +extern "C" { +#include "audio.h" +} +#include "DevIchHdaCodec.h" + + +/******************************************************************************* +* Defined Constants And Macros * +*******************************************************************************/ +/* PRM 5.3.1 */ +#define CODEC_CAD_MASK 0xF0000000 +#define CODEC_CAD_SHIFT 28 +#define CODEC_DIRECT_MASK RT_BIT(27) +#define CODEC_NID_MASK 0x07F00000 +#define CODEC_NID_SHIFT 20 +#define CODEC_VERBDATA_MASK 0x000FFFFF +#define CODEC_VERB_4BIT_CMD 0x000FFFF0 +#define CODEC_VERB_4BIT_DATA 0x0000000F +#define CODEC_VERB_8BIT_CMD 0x000FFF00 +#define CODEC_VERB_8BIT_DATA 0x000000FF +#define CODEC_VERB_16BIT_CMD 0x000F0000 +#define CODEC_VERB_16BIT_DATA 0x0000FFFF + +#define CODEC_CAD(cmd) ((cmd) & CODEC_CAD_MASK) +#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK) +#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT) +#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK) +#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x)) +#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4)) +#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8)) +#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16)) +#define CODEC_VERB_PAYLOAD4(cmd) ((cmd) & CODEC_VERB_4BIT_DATA) +#define CODEC_VERB_PAYLOAD8(cmd) ((cmd) & CODEC_VERB_8BIT_DATA) +#define CODEC_VERB_PAYLOAD16(cmd) ((cmd) & CODEC_VERB_16BIT_DATA) + +#define CODEC_VERB_GET_AMP_DIRECTION RT_BIT(15) +#define CODEC_VERB_GET_AMP_SIDE RT_BIT(13) +#define CODEC_VERB_GET_AMP_INDEX 0x7 + +/* HDA spec 7.3.3.7 NoteA */ +#define CODEC_GET_AMP_DIRECTION(cmd) (((cmd) & CODEC_VERB_GET_AMP_DIRECTION) >> 15) +#define CODEC_GET_AMP_SIDE(cmd) (((cmd) & CODEC_VERB_GET_AMP_SIDE) >> 13) +#define CODEC_GET_AMP_INDEX(cmd) (CODEC_GET_AMP_DIRECTION(cmd) ? 0 : ((cmd) & CODEC_VERB_GET_AMP_INDEX)) + +/* HDA spec 7.3.3.7 NoteC */ +#define CODEC_VERB_SET_AMP_OUT_DIRECTION RT_BIT(15) +#define CODEC_VERB_SET_AMP_IN_DIRECTION RT_BIT(14) +#define CODEC_VERB_SET_AMP_LEFT_SIDE RT_BIT(13) +#define CODEC_VERB_SET_AMP_RIGHT_SIDE RT_BIT(12) +#define CODEC_VERB_SET_AMP_INDEX (0x7 << 8) + +#define CODEC_SET_AMP_IS_OUT_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_OUT_DIRECTION) != 0) +#define CODEC_SET_AMP_IS_IN_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_IN_DIRECTION) != 0) +#define CODEC_SET_AMP_IS_LEFT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_LEFT_SIDE) != 0) +#define CODEC_SET_AMP_IS_RIGHT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_RIGHT_SIDE) != 0) +#define CODEC_SET_AMP_INDEX(cmd) (((cmd) & CODEC_VERB_SET_AMP_INDEX) >> 7) + +/* HDA spec 7.3.3.1 defines layout of configuration registers/verbs (0xF00) */ +/* VendorID (7.3.4.1) */ +#define CODEC_MAKE_F00_00(vendorID, deviceID) (((vendorID) << 16) | (deviceID)) +#define CODEC_F00_00_VENDORID(f00_00) (((f00_00) >> 16) & 0xFFFF) +#define CODEC_F00_00_DEVICEID(f00_00) ((f00_00) & 0xFFFF) +/* RevisionID (7.3.4.2)*/ +#define CODEC_MAKE_F00_02(MajRev, MinRev, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID)) +/* Subordinate node count (7.3.4.3)*/ +#define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF)) +#define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04) (((f00_04) >> 16) & 0xFF) +#define CODEC_F00_04_TO_NODE_COUNT(f00_04) ((f00_04) & 0xFF) +/* + * Function Group Type (7.3.4.4) + * 0 & [0x3-0x7f] are reserved types + * [0x80 - 0xff] are vendor defined function groups + */ +#define CODEC_MAKE_F00_05(UnSol, NodeType) (((UnSol) << 8)|(NodeType)) +#define CODEC_F00_05_UNSOL RT_BIT(8) +#define CODEC_F00_05_AFG (0x1) +#define CODEC_F00_05_MFG (0x2) +#define CODEC_F00_05_IS_UNSOL(f00_05) RT_BOOL((f00_05) & RT_BIT(8)) +#define CODEC_F00_05_GROUP(f00_05) ((f00_05) & 0xff) +/* Audio Function Group capabilities (7.3.4.5) */ +#define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF)) +#define CODEC_F00_08_BEEP_GEN(f00_08) ((f00_08) & RT_BIT(16) + +/* Widget Capabilities (7.3.4.6) */ +#define CODEC_MAKE_F00_09(type, delay, chanel_count) \ + ( (((type) & 0xF) << 20) \ + | (((delay) & 0xF) << 16) \ + | (((chanel_count) & 0xF) << 13)) +/* note: types 0x8-0xe are reserved */ +#define CODEC_F00_09_TYPE_AUDIO_OUTPUT (0x0) +#define CODEC_F00_09_TYPE_AUDIO_INPUT (0x1) +#define CODEC_F00_09_TYPE_AUDIO_MIXER (0x2) +#define CODEC_F00_09_TYPE_AUDIO_SELECTOR (0x3) +#define CODEC_F00_09_TYPE_PIN_COMPLEX (0x4) +#define CODEC_F00_09_TYPE_POWER_WIDGET (0x5) +#define CODEC_F00_09_TYPE_VOLUME_KNOB (0x6) +#define CODEC_F00_09_TYPE_BEEP_GEN (0x7) +#define CODEC_F00_09_TYPE_VENDOR_DEFINED (0xF) + +#define CODEC_F00_09_CAP_CP RT_BIT(12) +#define CODEC_F00_09_CAP_L_R_SWAP RT_BIT(11) +#define CODEC_F00_09_CAP_POWER_CTRL RT_BIT(10) +#define CODEC_F00_09_CAP_DIGITAL RT_BIT(9) +#define CODEC_F00_09_CAP_CONNECTION_LIST RT_BIT(8) +#define CODEC_F00_09_CAP_UNSOL RT_BIT(7) +#define CODEC_F00_09_CAP_PROC_WIDGET RT_BIT(6) +#define CODEC_F00_09_CAP_STRIPE RT_BIT(5) +#define CODEC_F00_09_CAP_FMT_OVERRIDE RT_BIT(4) +#define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE RT_BIT(3) +#define CODEC_F00_09_CAP_OUT_AMP_PRESENT RT_BIT(2) +#define CODEC_F00_09_CAP_IN_AMP_PRESENT RT_BIT(1) +#define CODEC_F00_09_CAP_LSB RT_BIT(0) + +#define CODEC_F00_09_TYPE(f00_09) (((f00_09) >> 20) & 0xF) + +#define CODEC_F00_09_IS_CAP_CP(f00_09) RT_BOOL((f00_09) & RT_BIT(12)) +#define CODEC_F00_09_IS_CAP_L_R_SWAP(f00_09) RT_BOOL((f00_09) & RT_BIT(11)) +#define CODEC_F00_09_IS_CAP_POWER_CTRL(f00_09) RT_BOOL((f00_09) & RT_BIT(10)) +#define CODEC_F00_09_IS_CAP_DIGITAL(f00_09) RT_BOOL((f00_09) & RT_BIT(9)) +#define CODEC_F00_09_IS_CAP_CONNECTION_LIST(f00_09) RT_BOOL((f00_09) & RT_BIT(8)) +#define CODEC_F00_09_IS_CAP_UNSOL(f00_09) RT_BOOL((f00_09) & RT_BIT(7)) +#define CODEC_F00_09_IS_CAP_PROC_WIDGET(f00_09) RT_BOOL((f00_09) & RT_BIT(6)) +#define CODEC_F00_09_IS_CAP_STRIPE(f00_09) RT_BOOL((f00_09) & RT_BIT(5)) +#define CODEC_F00_09_IS_CAP_FMT_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(4)) +#define CODEC_F00_09_IS_CAP_AMP_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(3)) +#define CODEC_F00_09_IS_CAP_OUT_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(2)) +#define CODEC_F00_09_IS_CAP_IN_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(1)) +#define CODEC_F00_09_IS_CAP_LSB(f00_09) RT_BOOL((f00_09) & RT_BIT(0)) + +/* Supported PCM size, rates (7.3.4.7) */ +#define CODEC_F00_0A_32_BIT RT_BIT(19) +#define CODEC_F00_0A_24_BIT RT_BIT(18) +#define CODEC_F00_0A_16_BIT RT_BIT(17) +#define CODEC_F00_0A_8_BIT RT_BIT(16) + +#define CODEC_F00_0A_48KHZ_MULT_8X RT_BIT(11) +#define CODEC_F00_0A_48KHZ_MULT_4X RT_BIT(10) +#define CODEC_F00_0A_44_1KHZ_MULT_4X RT_BIT(9) +#define CODEC_F00_0A_48KHZ_MULT_2X RT_BIT(8) +#define CODEC_F00_0A_44_1KHZ_MULT_2X RT_BIT(7) +#define CODEC_F00_0A_48KHZ RT_BIT(6) +#define CODEC_F00_0A_44_1KHZ RT_BIT(5) +/* 2/3 * 48kHz */ +#define CODEC_F00_0A_48KHZ_2_3X RT_BIT(4) +/* 1/2 * 44.1kHz */ +#define CODEC_F00_0A_44_1KHZ_1_2X RT_BIT(3) +/* 1/3 * 48kHz */ +#define CODEC_F00_0A_48KHZ_1_3X RT_BIT(2) +/* 1/4 * 44.1kHz */ +#define CODEC_F00_0A_44_1KHZ_1_4X RT_BIT(1) +/* 1/6 * 48kHz */ +#define CODEC_F00_0A_48KHZ_1_6X RT_BIT(0) + +/* Supported streams formats (7.3.4.8) */ +#define CODEC_F00_0B_AC3 RT_BIT(2) +#define CODEC_F00_0B_FLOAT32 RT_BIT(1) +#define CODEC_F00_0B_PCM RT_BIT(0) + +/* Pin Capabilities (7.3.4.9)*/ +#define CODEC_MAKE_F00_0C(vref_ctrl) (((vref_ctrl) & 0xFF) << 8) +#define CODEC_F00_0C_CAP_HBR RT_BIT(27) +#define CODEC_F00_0C_CAP_DP RT_BIT(24) +#define CODEC_F00_0C_CAP_EAPD RT_BIT(16) +#define CODEC_F00_0C_CAP_HDMI RT_BIT(7) +#define CODEC_F00_0C_CAP_BALANCED_IO RT_BIT(6) +#define CODEC_F00_0C_CAP_INPUT RT_BIT(5) +#define CODEC_F00_0C_CAP_OUTPUT RT_BIT(4) +#define CODEC_F00_0C_CAP_HP RT_BIT(3) +#define CODEC_F00_0C_CAP_PRESENSE_DETECT RT_BIT(2) +#define CODEC_F00_0C_CAP_TRIGGER_REQUIRED RT_BIT(1) +#define CODEC_F00_0C_CAP_IMPENDANCE_SENSE RT_BIT(0) + +#define CODEC_F00_0C_IS_CAP_HBR(f00_0c) ((f00_0c) & RT_BIT(27)) +#define CODEC_F00_0C_IS_CAP_DP(f00_0c) ((f00_0c) & RT_BIT(24)) +#define CODEC_F00_0C_IS_CAP_EAPD(f00_0c) ((f00_0c) & RT_BIT(16)) +#define CODEC_F00_0C_IS_CAP_HDMI(f00_0c) ((f00_0c) & RT_BIT(7)) +#define CODEC_F00_0C_IS_CAP_BALANCED_IO(f00_0c) ((f00_0c) & RT_BIT(6)) +#define CODEC_F00_0C_IS_CAP_INPUT(f00_0c) ((f00_0c) & RT_BIT(5)) +#define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c) ((f00_0c) & RT_BIT(4)) +#define CODEC_F00_0C_IS_CAP_HP(f00_0c) ((f00_0c) & RT_BIT(3)) +#define CODEC_F00_0C_IS_CAP_PRESENSE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2)) +#define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c) ((f00_0c) & RT_BIT(1)) +#define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c) ((f00_0c) & RT_BIT(0)) + +/* Input Amplifier capabilities (7.3.4.10) */ +#define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \ + ( (((mute_cap) & 0x1) << 31) \ + | (((step_size) & 0xFF) << 16) \ + | (((num_steps) & 0xFF) << 8) \ + | ((offset) & 0xFF)) + +/* Output Amplifier capabilities (7.3.4.10) */ +#define CODEC_MAKE_F00_12 CODEC_MAKE_F00_0D + +/* Connection list lenght (7.3.4.11) */ +#define CODEC_MAKE_F00_0E(long_form, length) \ + ( (((long_form) & 0x1) << 7) \ + | ((length) & 0x7F)) +#define CODEC_F00_0E_IS_LONG(f00_0e) RT_BOOL((f00_0e) & RT_BIT(7)) +#define CODEC_F00_0E_COUNT(f00_0e) ((f00_0e) & 0x7F) +/* Supported Power States (7.3.4.12) */ +#define CODEC_F00_0F_EPSS RT_BIT(31) +#define CODEC_F00_0F_CLKSTOP RT_BIT(30) +#define CODEC_F00_0F_S3D3 RT_BIT(29) +#define CODEC_F00_0F_D3COLD RT_BIT(4) +#define CODEC_F00_0F_D3 RT_BIT(3) +#define CODEC_F00_0F_D2 RT_BIT(2) +#define CODEC_F00_0F_D1 RT_BIT(1) +#define CODEC_F00_0F_D0 RT_BIT(0) + +/* Processing capabilities 7.3.4.13 */ +#define CODEC_MAKE_F00_10(num, benign) ((((num) & 0xFF) << 8) | ((benign) & 0x1)) +#define CODEC_F00_10_NUM(f00_10) (((f00_10) & (0xFF << 8)) >> 8) +#define CODEC_F00_10_BENING(f00_10) ((f00_10) & 0x1) + +/* CP/IO Count (7.3.4.14) */ +#define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \ + ( (((wake) & 0x1) << 31) \ + | (((unsol) & 0x1) << 30) \ + | (((numgpi) & 0xFF) << 16) \ + | (((numgpo) & 0xFF) << 8) \ + | ((numgpio) & 0xFF)) + +/* Processing States (7.3.3.4) */ +#define CODEC_F03_OFF (0) +#define CODEC_F03_ON RT_BIT(0) +#define CODEC_F03_BENING RT_BIT(1) +/* Power States (7.3.3.10) */ +#define CODEC_MAKE_F05(reset, stopok, error, act, set) \ + ( (((reset) & 0x1) << 10) \ + | (((stopok) & 0x1) << 9) \ + | (((error) & 0x1) << 8) \ + | (((act) & 0x7) << 4) \ + | ((set) & 0x7)) +#define CODEC_F05_D3COLD (4) +#define CODEC_F05_D3 (3) +#define CODEC_F05_D2 (2) +#define CODEC_F05_D1 (1) +#define CODEC_F05_D0 (0) + +#define CODEC_F05_IS_RESET(value) (((value) & RT_BIT(10)) != 0) +#define CODEC_F05_IS_STOPOK(value) (((value) & RT_BIT(9)) != 0) +#define CODEC_F05_IS_ERROR(value) (((value) & RT_BIT(8)) != 0) +#define CODEC_F05_ACT(value) (((value) & 0x7) >> 4) +#define CODEC_F05_SET(value) (((value) & 0x7)) + +#define CODEC_F05_GE(p0, p1) ((p0) <= (p1)) +#define CODEC_F05_LE(p0, p1) ((p0) >= (p1)) + +/* Pin Widged Control (7.3.3.13) */ +#define CODEC_F07_VREF_HIZ (0) +#define CODEC_F07_VREF_50 (0x1) +#define CODEC_F07_VREF_GROUND (0x2) +#define CODEC_F07_VREF_80 (0x4) +#define CODEC_F07_VREF_100 (0x5) +#define CODEC_F07_IN_ENABLE RT_BIT(5) +#define CODEC_F07_OUT_ENABLE RT_BIT(6) +#define CODEC_F07_OUT_H_ENABLE RT_BIT(7) + +/* Unsolicited enabled (7.3.3.14) */ +#define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F)) + +/* Converter formats (7.3.3.8) and (3.7.1) */ +#define CODEC_MAKE_A(fNonPCM, f44_1BaseRate, mult, div, bits, chan) \ + ( (((fNonPCM) & 0x1) << 15) \ + | (((f44_1BaseRate) & 0x1) << 14) \ + | (((mult) & 0x7) << 11) \ + | (((div) & 0x7) << 8) \ + | (((bits) & 0x7) << 4) \ + | ((chan) & 0xF)) + +#define CODEC_A_MULT_1X (0) +#define CODEC_A_MULT_2X (1) +#define CODEC_A_MULT_3X (2) +#define CODEC_A_MULT_4X (3) + +#define CODEC_A_DIV_1X (0) +#define CODEC_A_DIV_2X (1) +#define CODEC_A_DIV_3X (2) +#define CODEC_A_DIV_4X (3) +#define CODEC_A_DIV_5X (4) +#define CODEC_A_DIV_6X (5) +#define CODEC_A_DIV_7X (6) +#define CODEC_A_DIV_8X (7) + +#define CODEC_A_8_BIT (0) +#define CODEC_A_16_BIT (1) +#define CODEC_A_20_BIT (2) +#define CODEC_A_24_BIT (3) +#define CODEC_A_32_BIT (4) + +/* Pin Sense (7.3.3.15) */ +#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \ +( (((fPresent) & 0x1) << 31) \ + | (((impedance) & 0x7FFFFFFF))) +#define CODEC_F09_ANALOG_NA 0x7FFFFFFF +#define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \ +( (((fPresent) & 0x1) << 31) \ + | (((fELDValid) & 0x1) << 30)) + +#define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1)) +#define CODEC_FOC_IS_LRSWAP(f0c) RT_BOOL((f0c) & RT_BIT(2)) +#define CODEC_FOC_IS_EAPD(f0c) RT_BOOL((f0c) & RT_BIT(1)) +#define CODEC_FOC_IS_BTL(f0c) RT_BOOL((f0c) & RT_BIT(0)) +/* HDA spec 7.3.3.31 defines layout of configuration registers/verbs (0xF1C) */ +/* Configuration's port connection */ +#define CODEC_F1C_PORT_MASK (0x3) +#define CODEC_F1C_PORT_SHIFT (30) + +#define CODEC_F1C_PORT_COMPLEX (0x0) +#define CODEC_F1C_PORT_NO_PHYS (0x1) +#define CODEC_F1C_PORT_FIXED (0x2) +#define CODEC_F1C_BOTH (0x3) + +/* Configuration's location */ +#define CODEC_F1C_LOCATION_MASK (0x3F) +#define CODEC_F1C_LOCATION_SHIFT (24) +/* [4:5] bits of location region means chassis attachment */ +#define CODEC_F1C_LOCATION_PRIMARY_CHASSIS (0) +#define CODEC_F1C_LOCATION_INTERNAL RT_BIT(4) +#define CODEC_F1C_LOCATION_SECONDRARY_CHASSIS RT_BIT(5) +#define CODEC_F1C_LOCATION_OTHER (RT_BIT(5)) + +/* [0:3] bits of location region means geometry location attachment */ +#define CODEC_F1C_LOCATION_NA (0) +#define CODEC_F1C_LOCATION_REAR (0x1) +#define CODEC_F1C_LOCATION_FRONT (0x2) +#define CODEC_F1C_LOCATION_LEFT (0x3) +#define CODEC_F1C_LOCATION_RIGTH (0x4) +#define CODEC_F1C_LOCATION_TOP (0x5) +#define CODEC_F1C_LOCATION_BOTTOM (0x6) +#define CODEC_F1C_LOCATION_SPECIAL_0 (0x7) +#define CODEC_F1C_LOCATION_SPECIAL_1 (0x8) +#define CODEC_F1C_LOCATION_SPECIAL_2 (0x9) + +/* Configuration's devices */ +#define CODEC_F1C_DEVICE_MASK (0xF) +#define CODEC_F1C_DEVICE_SHIFT (20) +#define CODEC_F1C_DEVICE_LINE_OUT (0) +#define CODEC_F1C_DEVICE_SPEAKER (0x1) +#define CODEC_F1C_DEVICE_HP (0x2) +#define CODEC_F1C_DEVICE_CD (0x3) +#define CODEC_F1C_DEVICE_SPDIF_OUT (0x4) +#define CODEC_F1C_DEVICE_DIGITAL_OTHER_OUT (0x5) +#define CODEC_F1C_DEVICE_MODEM_LINE_SIDE (0x6) +#define CODEC_F1C_DEVICE_MODEM_HANDSET_SIDE (0x7) +#define CODEC_F1C_DEVICE_LINE_IN (0x8) +#define CODEC_F1C_DEVICE_AUX (0x9) +#define CODEC_F1C_DEVICE_MIC (0xA) +#define CODEC_F1C_DEVICE_PHONE (0xB) +#define CODEC_F1C_DEVICE_SPDIF_IN (0xC) +#define CODEC_F1C_DEVICE_RESERVED (0xE) +#define CODEC_F1C_DEVICE_OTHER (0xF) + +/* Configuration's Connection type */ +#define CODEC_F1C_CONNECTION_TYPE_MASK (0xF) +#define CODEC_F1C_CONNECTION_TYPE_SHIFT (16) + +#define CODEC_F1C_CONNECTION_TYPE_UNKNOWN (0) +#define CODEC_F1C_CONNECTION_TYPE_1_8INCHES (0x1) +#define CODEC_F1C_CONNECTION_TYPE_1_4INCHES (0x2) +#define CODEC_F1C_CONNECTION_TYPE_ATAPI (0x3) +#define CODEC_F1C_CONNECTION_TYPE_RCA (0x4) +#define CODEC_F1C_CONNECTION_TYPE_OPTICAL (0x5) +#define CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL (0x6) +#define CODEC_F1C_CONNECTION_TYPE_ANALOG (0x7) +#define CODEC_F1C_CONNECTION_TYPE_DIN (0x8) +#define CODEC_F1C_CONNECTION_TYPE_XLR (0x9) +#define CODEC_F1C_CONNECTION_TYPE_RJ_11 (0xA) +#define CODEC_F1C_CONNECTION_TYPE_COMBO (0xB) +#define CODEC_F1C_CONNECTION_TYPE_OTHER (0xF) + +/* Configuration's color */ +#define CODEC_F1C_COLOR_MASK (0xF) +#define CODEC_F1C_COLOR_SHIFT (12) +#define CODEC_F1C_COLOR_UNKNOWN (0) +#define CODEC_F1C_COLOR_BLACK (0x1) +#define CODEC_F1C_COLOR_GREY (0x2) +#define CODEC_F1C_COLOR_BLUE (0x3) +#define CODEC_F1C_COLOR_GREEN (0x4) +#define CODEC_F1C_COLOR_RED (0x5) +#define CODEC_F1C_COLOR_ORANGE (0x6) +#define CODEC_F1C_COLOR_YELLOW (0x7) +#define CODEC_F1C_COLOR_PURPLE (0x8) +#define CODEC_F1C_COLOR_PINK (0x9) +#define CODEC_F1C_COLOR_RESERVED_0 (0xA) +#define CODEC_F1C_COLOR_RESERVED_1 (0xB) +#define CODEC_F1C_COLOR_RESERVED_2 (0xC) +#define CODEC_F1C_COLOR_RESERVED_3 (0xD) +#define CODEC_F1C_COLOR_WHITE (0xE) +#define CODEC_F1C_COLOR_OTHER (0xF) + +/* Configuration's misc */ +#define CODEC_F1C_MISC_MASK (0xF) +#define CODEC_F1C_MISC_SHIFT (8) +#define CODEC_F1C_MISC_JACK_DETECT (0) +#define CODEC_F1C_MISC_RESERVED_0 (1) +#define CODEC_F1C_MISC_RESERVED_1 (2) +#define CODEC_F1C_MISC_RESERVED_2 (3) + +/* Configuration's association */ +#define CODEC_F1C_ASSOCIATION_MASK (0xF) +#define CODEC_F1C_ASSOCIATION_SHIFT (4) +/* Connection's sequence */ +#define CODEC_F1C_SEQ_MASK (0xF) +#define CODEC_F1C_SEQ_SHIFT (0) + +/* Implementation identification (7.3.3.30) */ +#define CODEC_MAKE_F20(bmid, bsku, aid) \ + ( (((bmid) & 0xFFFF) << 16) \ + | (((bsku) & 0xFF) << 8) \ + | (((aid) & 0xFF)) \ + ) + +/* macro definition helping in filling the configuration registers. */ +#define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence) \ + ( ((port_connectivity) << CODEC_F1C_PORT_SHIFT) \ + | ((location) << CODEC_F1C_LOCATION_SHIFT) \ + | ((device) << CODEC_F1C_DEVICE_SHIFT) \ + | ((connection_type) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \ + | ((color) << CODEC_F1C_COLOR_SHIFT) \ + | ((misc) << CODEC_F1C_MISC_SHIFT) \ + | ((association) << CODEC_F1C_ASSOCIATION_SHIFT) \ + | ((sequence))) + + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** The F00 parameter length (in dwords). */ +#define CODECNODE_F00_PARAM_LENGTH 20 +/** The F02 parameter length (in dwords). */ +#define CODECNODE_F02_PARAM_LENGTH 16 + +/** + * Common (or core) codec node structure. + */ +typedef struct CODECCOMMONNODE +{ + /** Node id - 7 bit format */ + uint8_t id; + /** The node name. */ + char const *pszName; + /* PRM 5.3.6 */ + uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH]; + uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH]; +} CODECCOMMONNODE; +typedef CODECCOMMONNODE *PCODECCOMMONNODE; +AssertCompile(CODECNODE_F00_PARAM_LENGTH == 20); /* saved state */ +AssertCompile(CODECNODE_F02_PARAM_LENGTH == 16); /* saved state */ + +/** + * Compile time assertion on the expected node size. + */ +#define AssertNodeSize(a_Node, a_cParams) \ + AssertCompile((a_cParams) <= (60 + 6)); /* the max size - saved state */ \ + AssertCompile( sizeof(a_Node) - sizeof(CODECCOMMONNODE) \ + == (((a_cParams) * sizeof(uint32_t) + sizeof(void *) - 1) & ~(sizeof(void *) - 1)) ) + +typedef struct ROOTCODECNODE +{ + CODECCOMMONNODE node; +} ROOTCODECNODE, *PROOTCODECNODE; +AssertNodeSize(ROOTCODECNODE, 0); + +#define AMPLIFIER_SIZE 60 +typedef uint32_t AMPLIFIER[AMPLIFIER_SIZE]; +#define AMPLIFIER_IN 0 +#define AMPLIFIER_OUT 1 +#define AMPLIFIER_LEFT 1 +#define AMPLIFIER_RIGHT 0 +#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)]) +typedef struct DACNODE +{ + CODECCOMMONNODE node; + uint32_t u32F0d_param; + uint32_t u32F04_param; + uint32_t u32F05_param; + uint32_t u32F06_param; + uint32_t u32F0c_param; + + uint32_t u32A_param; + AMPLIFIER B_params; + +} DACNODE, *PDACNODE; +AssertNodeSize(DACNODE, 6 + 60); + +typedef struct ADCNODE +{ + CODECCOMMONNODE node; + uint32_t u32F03_param; + uint32_t u32F05_param; + uint32_t u32F06_param; + uint32_t u32F09_param; + + uint32_t u32A_param; + uint32_t u32F01_param; + AMPLIFIER B_params; +} ADCNODE, *PADCNODE; +AssertNodeSize(DACNODE, 6 + 60); + +typedef struct SPDIFOUTNODE +{ + CODECCOMMONNODE node; + uint32_t u32F05_param; + uint32_t u32F06_param; + uint32_t u32F09_param; + uint32_t u32F0d_param; + + uint32_t u32A_param; + AMPLIFIER B_params; +} SPDIFOUTNODE, *PSPDIFOUTNODE; +AssertNodeSize(SPDIFOUTNODE, 5 + 60); + +typedef struct SPDIFINNODE +{ + CODECCOMMONNODE node; + uint32_t u32F05_param; + uint32_t u32F06_param; + uint32_t u32F09_param; + uint32_t u32F0d_param; + + uint32_t u32A_param; + AMPLIFIER B_params; +} SPDIFINNODE, *PSPDIFINNODE; +AssertNodeSize(SPDIFINNODE, 5 + 60); + +typedef struct AFGCODECNODE +{ + CODECCOMMONNODE node; + uint32_t u32F05_param; + uint32_t u32F08_param; + uint32_t u32F20_param; + uint32_t u32F17_param; +} AFGCODECNODE, *PAFGCODECNODE; +AssertNodeSize(AFGCODECNODE, 4); + +typedef struct PORTNODE +{ + CODECCOMMONNODE node; + uint32_t u32F07_param; + uint32_t u32F08_param; + uint32_t u32F09_param; + uint32_t u32F01_param; + uint32_t u32F1c_param; + AMPLIFIER B_params; +} PORTNODE, *PPORTNODE; +AssertNodeSize(PORTNODE, 5 + 60); + +typedef struct DIGOUTNODE +{ + CODECCOMMONNODE node; + uint32_t u32F01_param; + uint32_t u32F08_param; + uint32_t u32F07_param; + uint32_t u32F09_param; + uint32_t u32F1c_param; +} DIGOUTNODE, *PDIGOUTNODE; +AssertNodeSize(DIGOUTNODE, 5); + +typedef struct DIGINNODE +{ + CODECCOMMONNODE node; + uint32_t u32F05_param; + uint32_t u32F07_param; + uint32_t u32F08_param; + uint32_t u32F09_param; + uint32_t u32F0c_param; + uint32_t u32F1c_param; + uint32_t u32F1e_param; +} DIGINNODE, *PDIGINNODE; +AssertNodeSize(DIGINNODE, 7); + +typedef struct ADCMUXNODE +{ + CODECCOMMONNODE node; + uint32_t u32F01_param; + + uint32_t u32A_param; + AMPLIFIER B_params; +} ADCMUXNODE, *PADCMUXNODE; +AssertNodeSize(ADCMUXNODE, 2 + 60); + +typedef struct PCBEEPNODE +{ + CODECCOMMONNODE node; + uint32_t u32F07_param; + uint32_t u32F0a_param; + + uint32_t u32A_param; + AMPLIFIER B_params; + uint32_t u32F1c_param; +} PCBEEPNODE, *PPCBEEPNODE; +AssertNodeSize(PCBEEPNODE, 3 + 60 + 1); + +typedef struct CDNODE +{ + CODECCOMMONNODE node; + uint32_t u32F07_param; + uint32_t u32F1c_param; +} CDNODE, *PCDNODE; +AssertNodeSize(CDNODE, 2); + +typedef struct VOLUMEKNOBNODE +{ + CODECCOMMONNODE node; + uint32_t u32F08_param; + uint32_t u32F0f_param; +} VOLUMEKNOBNODE, *PVOLUMEKNOBNODE; +AssertNodeSize(VOLUMEKNOBNODE, 2); + +typedef struct ADCVOLNODE +{ + CODECCOMMONNODE node; + uint32_t u32F0c_param; + uint32_t u32F01_param; + uint32_t u32A_params; + AMPLIFIER B_params; +} ADCVOLNODE, *PADCVOLNODE; +AssertNodeSize(ADCVOLNODE, 3 + 60); + +typedef struct RESNODE +{ + CODECCOMMONNODE node; + uint32_t u32F05_param; + uint32_t u32F06_param; + uint32_t u32F07_param; + uint32_t u32F1c_param; +} RESNODE, *PRESNODE; +AssertNodeSize(RESNODE, 4); + +/** + * Used for the saved state. + */ +typedef struct CODECSAVEDSTATENODE +{ + CODECCOMMONNODE Core; + uint32_t au32Params[60 + 6]; +} CODECSAVEDSTATENODE; +AssertNodeSize(CODECSAVEDSTATENODE, 60 + 6); + +typedef union CODECNODE +{ + CODECCOMMONNODE node; + ROOTCODECNODE root; + AFGCODECNODE afg; + DACNODE dac; + ADCNODE adc; + SPDIFOUTNODE spdifout; + SPDIFINNODE spdifin; + PORTNODE port; + DIGOUTNODE digout; + DIGINNODE digin; + ADCMUXNODE adcmux; + PCBEEPNODE pcbeep; + CDNODE cdnode; + VOLUMEKNOBNODE volumeKnob; + ADCVOLNODE adcvol; + RESNODE reserved; + CODECSAVEDSTATENODE SavedState; +} CODECNODE, *PCODECNODE; +AssertNodeSize(CODECNODE, 60 + 6); + + +/******************************************************************************* +* Global Variables * +*******************************************************************************/ +/* STAC9220 - Referenced thru STAC9220WIDGET in the constructor below. */ +static uint8_t const g_abStac9220Ports[] = { 0x0A, 0xB, 0xC, 0xD, 0xE, 0xF, 0}; +static uint8_t const g_abStac9220Dacs[] = { 0x02, 0x3, 0x4, 0x5, 0}; +static uint8_t const g_abStac9220Adcs[] = { 0x06, 0x7, 0}; +static uint8_t const g_abStac9220SpdifOuts[] = { 0x08, 0 }; +static uint8_t const g_abStac9220SpdifIns[] = { 0x09, 0 }; +static uint8_t const g_abStac9220DigOutPins[] = { 0x10, 0 }; +static uint8_t const g_abStac9220DigInPins[] = { 0x11, 0 }; +static uint8_t const g_abStac9220AdcVols[] = { 0x17, 0x18, 0}; +static uint8_t const g_abStac9220AdcMuxs[] = { 0x12, 0x13, 0}; +static uint8_t const g_abStac9220Pcbeeps[] = { 0x14, 0 }; +static uint8_t const g_abStac9220Cds[] = { 0x15, 0 }; +static uint8_t const g_abStac9220VolKnobs[] = { 0x16, 0 }; +static uint8_t const g_abStac9220Reserveds[] = { 0x09, 0x19, 0x1a, 0x1b, 0 }; + + +/** SSM description of a CODECNODE. */ +static SSMFIELD const g_aCodecNodeFields[] = +{ + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id), + SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3), + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param), + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param), + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params), + SSMFIELD_ENTRY_TERM() +}; + +/** Backward compatibility with v1 of the CODECNODE. */ +static SSMFIELD const g_aCodecNodeFieldsV1[] = +{ + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id), + SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7), + SSMFIELD_ENTRY_OLD_HCPTR(Core.name), + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param), + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param), + SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params), + SSMFIELD_ENTRY_TERM() +}; + + + + +static int stac9220ResetNode(PHDACODEC pThis, uint8_t nodenum, PCODECNODE pNode) +{ + pNode->node.id = nodenum; + pNode->node.au32F00_param[0xF] = 0; /* Power statest Supported: are the same as AFG reports */ + switch (nodenum) + { + /* Root Node*/ + case 0: + pNode->node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */ + break; + case 1: + pNode->node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd); + pNode->node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17) + | CODEC_F00_0C_CAP_BALANCED_IO + | CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT + | CODEC_F00_0C_CAP_TRIGGER_REQUIRED + | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//(17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0); + pNode->node.au32F00_param[0x0B] = CODEC_F00_0B_PCM; + pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(1, 0x5, 0xE, 0);//RT_BIT(31)|(0x5 << 16)|(0xE)<<8; + pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f; + pNode->node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);//0xc0000004; + pNode->node.au32F00_param[0x0F] = CODEC_F00_0F_D3|CODEC_F00_0F_D2|CODEC_F00_0F_D1|CODEC_F00_0F_D0; + 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 */ + pNode->afg.u32F08_param = 0; + pNode->afg.u32F17_param = 0; + break; + case 2: + case 3: + case 4: + case 5: + memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE); + 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; /* 441000Hz/16bit/2ch */ + + AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7); + AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7); + + pNode->dac.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0xD, 0) + | CODEC_F00_09_CAP_L_R_SWAP + | CODEC_F00_09_CAP_POWER_CTRL + | CODEC_F00_09_CAP_OUT_AMP_PRESENT + | CODEC_F00_09_CAP_LSB;//(0xD << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0); + pNode->dac.u32F0c_param = 0; + pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3 */ + break; + case 6: + pNode->node.au32F02_param[0] = 0x17; + goto adc_init; + case 7: + pNode->node.au32F02_param[0] = 0x18; + adc_init: + 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; /* 441000Hz/16bit/2ch */ + pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0); + pNode->adc.u32F03_param = RT_BIT(0); + pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */ + pNode->adc.u32F06_param = 0; + pNode->adc.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0) + | CODEC_F00_09_CAP_POWER_CTRL + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_PROC_WIDGET + | CODEC_F00_09_CAP_LSB;//RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0); + break; + case 8: + 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; + pNode->spdifout.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x4, 0) + | CODEC_F00_09_CAP_DIGITAL + | CODEC_F00_09_CAP_FMT_OVERRIDE + | CODEC_F00_09_CAP_LSB;//(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1; + pNode->node.au32F00_param[0xa] = pThis->paNodes[1].node.au32F00_param[0xA]; + pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM; + pNode->spdifout.u32F06_param = 0; + pNode->spdifout.u32F0d_param = 0; + break; + case 9: + 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; + pNode->spdifin.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0x4, 0) + | CODEC_F00_09_CAP_DIGITAL + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_FMT_OVERRIDE + | CODEC_F00_09_CAP_LSB;//(0x1 << 20)|(4 << 16) | RT_BIT(9)| RT_BIT(8)|RT_BIT(4)|0x1; + pNode->node.au32F00_param[0xA] = pThis->paNodes[1].node.au32F00_param[0xA]; + pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0); + pNode->node.au32F02_param[0] = 0x11; + pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM; + pNode->spdifin.u32F06_param = 0; + pNode->spdifin.u32F0d_param = 0; + break; + case 0xA: + pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) + | CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_OUTPUT + | CODEC_F00_0C_CAP_HP + | CODEC_F00_0C_CAP_PRESENSE_DETECT + | CODEC_F00_0C_CAP_TRIGGER_REQUIRED + | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x173f; + pNode->node.au32F02_param[0] = 0x2; + pNode->port.u32F07_param = CODEC_F07_IN_ENABLE + | CODEC_F07_OUT_ENABLE; + pNode->port.u32F08_param = 0; + if (!pThis->fInReset) + pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_FRONT, + CODEC_F1C_DEVICE_HP, + CODEC_F1C_CONNECTION_TYPE_1_8INCHES, + CODEC_F1C_COLOR_GREEN, + CODEC_F1C_MISC_JACK_DETECT, + 0x2, 0);//RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02); + goto port_init; + case 0xB: + pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) + | CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_OUTPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT + | CODEC_F00_0C_CAP_TRIGGER_REQUIRED + | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737; + pNode->node.au32F02_param[0] = 0x4; + pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; + if (!pThis->fInReset) + pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR, + CODEC_F1C_DEVICE_SPEAKER, + CODEC_F1C_CONNECTION_TYPE_1_8INCHES, + CODEC_F1C_COLOR_BLACK, + CODEC_F1C_MISC_JACK_DETECT, + 0x1, 0x1);//RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01); + goto port_init; + case 0xC: + pNode->node.au32F02_param[0] = 0x3; + pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) + | CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_OUTPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT + | CODEC_F00_0C_CAP_TRIGGER_REQUIRED + | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737; + pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; + if (!pThis->fInReset) + pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_REAR, + CODEC_F1C_DEVICE_SPEAKER, + CODEC_F1C_CONNECTION_TYPE_1_8INCHES, + CODEC_F1C_COLOR_GREEN, + 0x0, 0x1, 0x0);//RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01); + goto port_init; + case 0xD: + pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17) + | CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_OUTPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT + | CODEC_F00_0C_CAP_TRIGGER_REQUIRED + | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737; + pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; + pNode->node.au32F02_param[0] = 0x2; + if (!pThis->fInReset) + pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_FRONT, + CODEC_F1C_DEVICE_MIC, + CODEC_F1C_CONNECTION_TYPE_1_8INCHES, + CODEC_F1C_COLOR_PINK, + 0x0, 0x5, 0x0);//RT_MAKE_U32_FROM_U8(0x50, 0x90, 0xA1, 0x02); /* Microphone */ + port_init: + pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff; + pNode->port.u32F08_param = 0; + pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0) + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_UNSOL + | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0); + pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1; + break; + case 0xE: + pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0) + | CODEC_F00_09_CAP_UNSOL + | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(7)|RT_BIT(0); + pNode->port.u32F08_param = 0; + pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_OUTPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT;//0x34; + pNode->port.u32F07_param = CODEC_F07_IN_ENABLE; + pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff; + if (!pThis->fInReset) + pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_REAR, + CODEC_F1C_DEVICE_LINE_OUT, + CODEC_F1C_CONNECTION_TYPE_1_8INCHES, + CODEC_F1C_COLOR_BLUE, + 0x0, 0x4, 0x0);//0x01013040; /* Line Out */ + break; + case 0xF: + pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0) + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_UNSOL + | CODEC_F00_09_CAP_OUT_AMP_PRESENT + | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(2)|RT_BIT(0); + pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_OUTPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT + /* | CODEC_F00_0C_CAP_TRIGGER_REQUIRED + | CODEC_F00_0C_CAP_IMPENDANCE_SENSE */;//0x37; + pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1; + pNode->port.u32F08_param = 0; + pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE + | CODEC_F07_IN_ENABLE; + if (!pThis->fInReset) + pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_INTERNAL, + CODEC_F1C_DEVICE_SPEAKER, + CODEC_F1C_CONNECTION_TYPE_1_8INCHES, + CODEC_F1C_COLOR_ORANGE, + 0x0, 0x1, 0x2);//RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01); + pNode->node.au32F02_param[0] = 0x5; + pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff; + break; + case 0x10: + pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0) + | CODEC_F00_09_CAP_DIGITAL + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_LSB;//(4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0); + pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//RT_BIT(4); + pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x3); + pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0); + if (!pThis->fInReset) + pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_REAR, + CODEC_F1C_DEVICE_SPDIF_OUT, + CODEC_F1C_CONNECTION_TYPE_DIN, + CODEC_F1C_COLOR_BLACK, + 0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01); + break; + case 0x11: + pNode->node.au32F00_param[9] = (4 << 20) | (3 << 16) | RT_BIT(10) | RT_BIT(9) | RT_BIT(7) | RT_BIT(0); + pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD + | CODEC_F00_0C_CAP_INPUT + | CODEC_F00_0C_CAP_PRESENSE_DETECT;//RT_BIT(16)| RT_BIT(5)|RT_BIT(2); + pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */ + pNode->digin.u32F07_param = 0; + pNode->digin.u32F08_param = 0; + pNode->digin.u32F09_param = 0; + pNode->digin.u32F0c_param = 0; + if (!pThis->fInReset) + pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX, + CODEC_F1C_LOCATION_REAR, + CODEC_F1C_DEVICE_SPDIF_IN, + CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL, + CODEC_F1C_COLOR_BLACK, + 0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60; + break; + case 0x12: + pNode->adcmux.u32F01_param = 0; + goto adcmux_init; + case 0x13: + pNode->adcmux.u32F01_param = 1; + adcmux_init: + pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0x0, 0) + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE + | CODEC_F00_09_CAP_OUT_AMP_PRESENT + | CODEC_F00_09_CAP_LSB;//(3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0); + pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x7); + pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8); + /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/ + memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE); + pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb); + pNode->node.au32F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0); + break; + case 0x14: + pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0) + | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE + | CODEC_F00_09_CAP_OUT_AMP_PRESENT;//(7 << 20) | RT_BIT(3) | RT_BIT(2); + pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3; + pNode->pcbeep.u32F0a_param = 0; + memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE); + break; + case 0x15: + pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0) + | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(0); + pNode->node.au32F00_param[0xc] = CODEC_F00_0C_CAP_INPUT;//RT_BIT(5); + if (!pThis->fInReset) + pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED, + CODEC_F1C_LOCATION_INTERNAL, + CODEC_F1C_DEVICE_CD, + CODEC_F1C_CONNECTION_TYPE_ATAPI, + CODEC_F1C_COLOR_UNKNOWN, + 0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90); + break; + case 0x16: + pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0x0, 0x0);//(0x6 << 20); + pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F; + pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x4); + pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5); + pNode->volumeKnob.u32F08_param = 0; + pNode->volumeKnob.u32F0f_param = 0x7f; + break; + case 0x17: + pNode->node.au32F02_param[0] = 0x12; + goto adcvol_init; + case 0x18: + pNode->node.au32F02_param[0] = 0x13; + adcvol_init: + memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE); + + pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0) + | CODEC_F00_09_CAP_L_R_SWAP + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_IN_AMP_PRESENT + | CODEC_F00_09_CAP_LSB;//(0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0); + pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x1); + AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7); + AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7); + pNode->adcvol.u32F0c_param = 0; + break; + case 0x19: + pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0) + | CODEC_F00_09_CAP_DIGITAL + | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0); + break; + case 0x1A: + pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0) + | CODEC_F00_09_CAP_DIGITAL + | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0); + break; + case 0x1B: + pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0) + | CODEC_F00_09_CAP_DIGITAL + | CODEC_F00_09_CAP_CONNECTION_LIST + | CODEC_F00_09_CAP_LSB;//(0x4 << 20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0); + pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x1); + pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//0x10; + pNode->node.au32F02_param[0] = 0x1a; + pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS, + CODEC_F1C_LOCATION_NA, + CODEC_F1C_DEVICE_LINE_OUT, + CODEC_F1C_CONNECTION_TYPE_UNKNOWN, + CODEC_F1C_COLOR_UNKNOWN, + 0x0, 0x0, 0xf);//0x4000000f; + break; + default: + break; + } + return VINF_SUCCESS; +} + + +static int stac9220Construct(PHDACODEC pThis) +{ + unconst(pThis->cTotalNodes) = 0x1C; + pThis->pfnCodecNodeReset = stac9220ResetNode; + pThis->u16VendorId = 0x8384; + pThis->u16DeviceId = 0x7680; + pThis->u8BSKU = 0x76; + pThis->u8AssemblyId = 0x80; + pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes); + pThis->fInReset = false; +#define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s + STAC9220WIDGET(Port); + STAC9220WIDGET(Dac); + STAC9220WIDGET(Adc); + STAC9220WIDGET(AdcVol); + STAC9220WIDGET(AdcMux); + STAC9220WIDGET(Pcbeep); + STAC9220WIDGET(SpdifIn); + STAC9220WIDGET(SpdifOut); + STAC9220WIDGET(DigInPin); + STAC9220WIDGET(DigOutPin); + STAC9220WIDGET(Cd); + STAC9220WIDGET(VolKnob); + STAC9220WIDGET(Reserved); +#undef STAC9220WIDGET + unconst(pThis->u8AdcVolsLineIn) = 0x17; + unconst(pThis->u8DacLineOut) = 0x2; + + return VINF_SUCCESS; +} + + +/* + * Some generic predicate functions. + */ + +#define DECLISNODEOFTYPE(type) \ + DECLINLINE(int) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \ + { \ + Assert(pThis->au8##type##s); \ + for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \ + if (pThis->au8##type##s[i] == cNode) \ + return 1; \ + return 0; \ + } +/* hdaCodecIsPortNode */ +DECLISNODEOFTYPE(Port) +/* hdaCodecIsDacNode */ +DECLISNODEOFTYPE(Dac) +/* hdaCodecIsAdcVolNode */ +DECLISNODEOFTYPE(AdcVol) +/* hdaCodecIsAdcNode */ +DECLISNODEOFTYPE(Adc) +/* hdaCodecIsAdcMuxNode */ +DECLISNODEOFTYPE(AdcMux) +/* hdaCodecIsPcbeepNode */ +DECLISNODEOFTYPE(Pcbeep) +/* hdaCodecIsSpdifOutNode */ +DECLISNODEOFTYPE(SpdifOut) +/* hdaCodecIsSpdifInNode */ +DECLISNODEOFTYPE(SpdifIn) +/* hdaCodecIsDigInPinNode */ +DECLISNODEOFTYPE(DigInPin) +/* hdaCodecIsDigOutPinNode */ +DECLISNODEOFTYPE(DigOutPin) +/* hdaCodecIsCdNode */ +DECLISNODEOFTYPE(Cd) +/* hdaCodecIsVolKnobNode */ +DECLISNODEOFTYPE(VolKnob) +/* hdaCodecIsReservedNode */ +DECLISNODEOFTYPE(Reserved) + + +/* + * Misc helpers. + */ + +static int hdaCodecToAudVolume(AMPLIFIER *pAmp, audmixerctl_t mt) +{ + uint32_t dir = AMPLIFIER_OUT; + switch (mt) + { + case AUD_MIXER_VOLUME: + case AUD_MIXER_PCM: + dir = AMPLIFIER_OUT; + break; + case AUD_MIXER_LINE_IN: + dir = AMPLIFIER_IN; + break; + } + int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7); + mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7); + mute >>=7; + mute &= 0x1; + uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f; + uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f; + AUD_set_volume(mt, &mute, &lVol, &rVol); + return VINF_SUCCESS; +} + +DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask) +{ + Assert((pu32Reg && u8Offset < 32)); + *pu32Reg &= ~(mask << u8Offset); + *pu32Reg |= (u32Cmd & mask) << u8Offset; +} + +DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset) +{ + hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA); +} + +DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset) +{ + hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA); +} + + +/* + * Verb processor functions. + */ + +static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Log(("vrbProcUnimplemented: cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd, + CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd))); + *pResp = 0; + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + int rc; + rc = vrbProcUnimplemented(pThis, cmd, pResp); + *pResp |= CODEC_RESPONSE_UNSOLICITED; + return rc; +} + +/* B-- */ +static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + /* HDA spec 7.3.3.7 Note A */ + /** @todo: if index out of range response should be 0 */ + uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd); + + PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)]; + if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params, + CODEC_GET_AMP_DIRECTION(cmd), + CODEC_GET_AMP_SIDE(cmd), + u8Index); + else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd))) + *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params, + CODEC_GET_AMP_DIRECTION(cmd), + CODEC_GET_AMP_SIDE(cmd), + u8Index); + else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd))) + *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params, + CODEC_GET_AMP_DIRECTION(cmd), + CODEC_GET_AMP_SIDE(cmd), + u8Index); + else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd))) + *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params, + CODEC_GET_AMP_DIRECTION(cmd), + CODEC_GET_AMP_SIDE(cmd), + u8Index); + else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + *pResp = AMPLIFIER_REGISTER(pNode->port.B_params, + CODEC_GET_AMP_DIRECTION(cmd), + CODEC_GET_AMP_SIDE(cmd), + u8Index); + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params, + CODEC_GET_AMP_DIRECTION(cmd), + CODEC_GET_AMP_SIDE(cmd), + u8Index); + else + AssertMsgFailedReturn(("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS); + return VINF_SUCCESS; +} + +/* 3-- */ +static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + bool fIsLeft = false; + bool fIsRight = false; + bool fIsOut = false; + bool fIsIn = false; + uint8_t u8Index = 0; + Assert(CODEC_CAD(cmd) == pThis->id); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)]; + AMPLIFIER *pAmplifier; + if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + pAmplifier = &pNode->dac.B_params; + else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd))) + pAmplifier = &pNode->adcvol.B_params; + else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd))) + pAmplifier = &pNode->adcmux.B_params; + else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd))) + pAmplifier = &pNode->pcbeep.B_params; + else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + pAmplifier = &pNode->port.B_params; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + pAmplifier = &pNode->adc.B_params; + else + AssertFailedReturn(VINF_SUCCESS); + + fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd); + fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd); + fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd); + fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd); + u8Index = CODEC_SET_AMP_INDEX(cmd); + if ( (!fIsLeft && !fIsRight) + || (!fIsOut && !fIsIn)) + return VINF_SUCCESS; + if (fIsIn) + { + if (fIsLeft) + hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0); + if (fIsRight) + hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0); + } + if (fIsOut) + { + if (fIsLeft) + hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0); + if (fIsRight) + hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0); + } + if (CODEC_NID(cmd) == pThis->u8DacLineOut) + hdaCodecToAudVolume(pAmplifier, AUD_MIXER_VOLUME); + if (CODEC_NID(cmd) == pThis->u8AdcVolsLineIn) /* Microphone */ + hdaCodecToAudVolume(pAmplifier, AUD_MIXER_LINE_IN); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH); + if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH) + { + Log(("HdaCodec: invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA))); + return VINF_SUCCESS; + } + *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA]; + return VINF_SUCCESS; +} + +/* F01 */ +static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param; + else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param; + else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param; + return VINF_SUCCESS; +} + +/* 701 */ +static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + uint32_t *pu32Reg; + if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param; + else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param; + else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param; + else + AssertFailedReturn(VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + return VINF_SUCCESS; +} + +/* F07 */ +static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param; + else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param; + else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param; + else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param; + else + AssertMsgFailed(("Unsupported")); + return VINF_SUCCESS; +} + +/* 707 */ +static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + uint32_t *pu32Reg; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param; + else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param; + else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param; + else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)) + && CODEC_NID(cmd) == 0x1b) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param; + else + AssertFailedReturn(VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + return VINF_SUCCESS; +} + +/* F08 */ +static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param; + else if ((cmd) == 1 /* AFG */) + *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param; + else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param; + else + AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd))); + return VINF_SUCCESS; +} + +/* 708 */ +static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + uint32_t *pu32Reg; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param; + else if (CODEC_NID(cmd) == 1 /* AFG */) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param; + else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param; + else + AssertMsgFailedReturn(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)), VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + return VINF_SUCCESS; +} + +/* F09 */ +static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param; + else + AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd))); + return VINF_SUCCESS; +} + +/* 709 */ +static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + uint32_t *pu32Reg; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param; + else + AssertFailedReturn(VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + *pResp = 0; + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH); + if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH) + { + Log(("HdaCodec: access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA))); + return VINF_SUCCESS; + } + *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA]; + return VINF_SUCCESS; +} + +/* F03 */ +static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param; + return VINF_SUCCESS; +} + +/* 703 */ +static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0); + return VINF_SUCCESS; +} + +/* F0D */ +static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param; + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param; + return VINF_SUCCESS; +} + +static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset); + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset); + return VINF_SUCCESS; +} + +/* 70D */ +static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + return codecSetDigitalConverter(pThis, cmd, 0, pResp); +} + +/* 70E */ +static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + return codecSetDigitalConverter(pThis, cmd, 8, pResp); +} + +/* F20 */ +static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + if (CODEC_NID(cmd) == 1 /* AFG */) + *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param; + else + *pResp = 0; + return VINF_SUCCESS; +} + +static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + uint32_t *pu32Reg; + if (CODEC_NID(cmd) == 0x1 /* AFG */) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param; + else + AssertFailedReturn(VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset); + return VINF_SUCCESS; +} + +/* 720 */ +static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetSubIdX(pThis, cmd, 0); +} + +/* 721 */ +static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetSubIdX(pThis, cmd, 8); +} + +/* 722 */ +static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetSubIdX(pThis, cmd, 16); +} + +/* 723 */ +static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetSubIdX(pThis, cmd, 24); +} + +static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) == 1 /* AFG */); + if ( CODEC_NID(cmd) == 1 /* AFG */ + && pThis->pfnCodecNodeReset) + { + uint8_t i; + Log(("HdaCodec: enters reset\n")); + Assert(pThis->pfnCodecNodeReset); + for (i = 0; i < pThis->cTotalNodes; ++i) + { + pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]); + } + pThis->fInReset = false; + Log(("HdaCodec: exits reset\n")); + } + *pResp = 0; + return VINF_SUCCESS; +} + +/* F05 */ +static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (CODEC_NID(cmd) == 1 /* AFG */) + *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param; + else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param; + else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param; + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param; + else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param; + return VINF_SUCCESS; +} + +/* 705 */ + +DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param) +{ + Assert(pu32F05_param); + if (!pu32F05_param) + return; + bool fReset = CODEC_F05_IS_RESET(*pu32F05_param); + bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param); + uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param); + *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState); +} + +static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + uint32_t *pu32Reg; + if (CODEC_NID(cmd) == 1 /* AFG */) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param; + else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param; + else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param; + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param; + else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param; + else + AssertFailedReturn(VINF_SUCCESS); + + bool fReset = CODEC_F05_IS_RESET(*pu32Reg); + bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg); + + if (CODEC_NID(cmd) != 1 /* AFG */) + { + /* + * We shouldn't propogate actual power state, which actual for AFG + */ + *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, + CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param), + CODEC_F05_SET(cmd)); + } + + /* Propagate next power state only if AFG is on or verb modifies AFG power state */ + if ( CODEC_NID(cmd) == 1 /* AFG */ + || !CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param)) + { + *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd)); + if ( CODEC_NID(cmd) == 1 /* AFG */ + && (CODEC_F05_SET(cmd)) == CODEC_F05_D0) + { + /* now we're powered on AFG and may propogate power states on nodes */ + const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0]; + while (*(++pu8NodeIndex)) + codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].dac.u32F05_param); + + pu8NodeIndex = &pThis->au8Adcs[0]; + while (*(++pu8NodeIndex)) + codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].adc.u32F05_param); + + pu8NodeIndex = &pThis->au8DigInPins[0]; + while (*(++pu8NodeIndex)) + codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].digin.u32F05_param); + } + } + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param; + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param; + else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param; + else if (CODEC_NID(cmd) == 0x1A) + *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param; + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + uint32_t *pu32addr; + if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + pu32addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + pu32addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param; + else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param; + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param; + else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + pu32addr = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param; + else + AssertFailedReturn(VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32addr, cmd, 0); + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param; + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param; + else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param; + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param; + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0); + else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0); + else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0); + else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd))) + hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0); + return VINF_SUCCESS; +} + +/* F0C */ +static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param; + else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param; + return VINF_SUCCESS; +} + +/* 70C */ +static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + + *pResp = 0; + uint32_t *pu32Reg; + if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param; + else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param; + else + AssertFailedReturn(VINF_SUCCESS); + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + + return VINF_SUCCESS; +} + +/* F0F */ +static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param; + return VINF_SUCCESS; +} + +/* 70F */ +static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + uint32_t *pu32Reg = NULL; + *pResp = 0; + if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param; + Assert(pu32Reg); + if (pu32Reg) + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + return VINF_SUCCESS; +} + +/* F17 */ +static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + /* note: this is true for ALC885 */ + if (CODEC_NID(cmd) == 0x1 /* AFG */) + *pResp = pThis->paNodes[1].afg.u32F17_param; + return VINF_SUCCESS; +} + +/* 717 */ +static DECLCALLBACK(int) vrbProcSetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + uint32_t *pu32Reg = NULL; + *pResp = 0; + if (CODEC_NID(cmd) == 1 /* AFG */) + pu32Reg = &pThis->paNodes[1].afg.u32F17_param; + Assert(pu32Reg); + if (pu32Reg) + hdaCodecSetRegisterU8(pu32Reg, cmd, 0); + return VINF_SUCCESS; +} + +/* F1C */ +static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + *pResp = 0; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param; + else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param; + else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param; + else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param; + return VINF_SUCCESS; +} + +static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + Assert(CODEC_NID(cmd) < pThis->cTotalNodes); + if (CODEC_NID(cmd) >= pThis->cTotalNodes) + { + Log(("HdaCodec: invalid node address %d\n", CODEC_NID(cmd))); + return VINF_SUCCESS; + } + uint32_t *pu32Reg = NULL; + if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param; + else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param; + else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param; + else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param; + else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param; + else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param; + Assert(pu32Reg); + if (pu32Reg) + hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset); + return VINF_SUCCESS; +} + +/* 71C */ +static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetConfigX(pThis, cmd, 0); +} + +/* 71D */ +static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetConfigX(pThis, cmd, 8); +} + +/* 71E */ +static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetConfigX(pThis, cmd, 16); +} + +/* 71E */ +static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp) +{ + *pResp = 0; + return codecSetConfigX(pThis, cmd, 24); +} + + +/** + * HDA codec verb map. + * @todo Any reason not to use binary search here? + */ +static const CODECVERB g_aCodecVerbs[] = +{ +/* verb | verb mask | callback */ +/* ----------- -------------------- ----------------------- */ + { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter }, + { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl }, + { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl }, + { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId }, + { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId }, + { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl }, + { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl }, + { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled }, + { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled }, + { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense }, + { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense }, + { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry }, + { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState }, + { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState }, + { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter }, + { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 }, + { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 }, + { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId }, + { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 }, + { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 }, + { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 }, + { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 }, + { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset }, + { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState }, + { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState }, + { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled }, + { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled }, + { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl }, + { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl }, + { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted }, + { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted }, + { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig }, + { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 }, + { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 }, + { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 }, + { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 }, + { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat }, + { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat }, + { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier }, + { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier }, +}; + +static int codecLookup(PHDACODEC pThis, uint32_t cmd, PPFNHDACODECVERBPROCESSOR pfn) +{ + Assert(CODEC_CAD(cmd) == pThis->id); + if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))) + Log(("HdaCodec: cmd %x was addressed to reserved node\n", cmd)); + + if ( CODEC_VERBDATA(cmd) == 0 + || CODEC_NID(cmd) >= pThis->cTotalNodes) + { + *pfn = vrbProcUnimplemented; + /// @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp) + Log(("HdaCodec: cmd %x was ignored\n", cmd)); + return VINF_SUCCESS; + } + + for (int i = 0; i < pThis->cVerbs; ++i) + { + if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb) + { + *pfn = pThis->paVerbs[i].pfn; + return VINF_SUCCESS; + } + } + + *pfn = vrbProcUnimplemented; + Log(("HdaCodec: callback for %x wasn't found\n", CODEC_VERBDATA(cmd))); + return VINF_SUCCESS; +} + +static void pi_callback(void *opaque, int avail) +{ + PHDACODEC pThis = (PHDACODEC)opaque; + pThis->pfnTransfer(pThis, PI_INDEX, avail); +} + +static void po_callback(void *opaque, int avail) +{ + PHDACODEC pThis = (PHDACODEC)opaque; + pThis->pfnTransfer(pThis, PO_INDEX, avail); +} + + + +/* + * APIs exposed to DevHDA. + */ + + +/** + * + * routines open one of the voices (IN, OUT) with corresponding parameters. + * this routine could be called from HDA on setting/resseting sound format. + * + * @todo Probably passed settings should be verified (if AFG's declared proposed + * format) before enabling. + */ +int hdaCodecOpenVoice(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, audsettings_t *pAudioSettings) +{ + int rc; + Assert(pThis && pAudioSettings); + if ( !pThis + || !pAudioSettings) + return -1; + switch (enmSoundSource) + { + case PI_INDEX: + pThis->SwVoiceIn = AUD_open_in(&pThis->card, pThis->SwVoiceIn, "hda.in", pThis, pi_callback, pAudioSettings); + rc = pThis->SwVoiceIn ? 0 : 1; + break; + case PO_INDEX: + pThis->SwVoiceOut = AUD_open_out(&pThis->card, pThis->SwVoiceOut, "hda.out", pThis, po_callback, pAudioSettings); + rc = pThis->SwVoiceOut ? 0 : 1; + break; + default: + return -1; + } + if (!rc) + LogRel(("HdaCodec: can't open %s fmt(freq: %d)\n", enmSoundSource == PI_INDEX? "in" : "out", pAudioSettings->freq)); + return rc; +} + + +int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM) +{ + AssertLogRelMsgReturn(pThis->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes), + VERR_INTERNAL_ERROR); + SSMR3PutU32(pSSM, pThis->cTotalNodes); + for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode) + SSMR3PutStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState), + 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/); + return VINF_SUCCESS; +} + + +int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion) +{ + PCSSMFIELD pFields; + uint32_t fFlags; + switch (uVersion) + { + case HDA_SSM_VERSION_1: + AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR); + pFields = g_aCodecNodeFieldsV1; + fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED; + break; + + case HDA_SSM_VERSION_2: + case HDA_SSM_VERSION_3: + AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR); + pFields = g_aCodecNodeFields; + fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED; + break; + + case HDA_SSM_VERSION: + { + uint32_t cNodes; + int rc2 = SSMR3GetU32(pSSM, &cNodes); + AssertRCReturn(rc2, rc2); + if (cNodes != 0x1c) + return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; + AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR); + + pFields = g_aCodecNodeFields; + fFlags = 0; + break; + } + + default: + return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; + } + + for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode) + { + uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.id; + int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, + sizeof(pThis->paNodes[idxNode].SavedState), + fFlags, pFields, NULL); + if (RT_FAILURE(rc)) + return rc; + AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.id, + ("loaded %#x, expected \n", pThis->paNodes[idxNode].SavedState.Core.id, idOld), + VERR_SSM_DATA_UNIT_FORMAT_CHANGED); + } + + /* + * Update stuff after changing the state. + */ + if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut)) + hdaCodecToAudVolume(&pThis->paNodes[pThis->u8DacLineOut].dac.B_params, AUD_MIXER_VOLUME); + else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut)) + hdaCodecToAudVolume(&pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, AUD_MIXER_VOLUME); + hdaCodecToAudVolume(&pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, AUD_MIXER_LINE_IN); + + return VINF_SUCCESS; +} + + +int hdaCodecDestruct(PHDACODEC pThis) +{ + RTMemFree(pThis->paNodes); + pThis->paNodes = NULL; + return VINF_SUCCESS; +} + + +int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, PCFGMNODE pCfg) +{ + pThis->paVerbs = &g_aCodecVerbs[0]; + pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs); + pThis->pfnLookup = codecLookup; + int rc = stac9220Construct(pThis); + AssertRC(rc); + + /* common root node initializers */ + pThis->paNodes[0].node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId); + pThis->paNodes[0].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1); + /* common AFG node initializers */ + pThis->paNodes[1].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2); + pThis->paNodes[1].node.au32F00_param[5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG); + pThis->paNodes[1].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId); + + /// @todo r=michaln: Was this meant to be 'HDA' or something like that? (AC'97 was on ICH0) + AUD_register_card ("ICH0", &pThis->card); + + /* 44.1 kHz */ + audsettings_t as; + as.freq = 44100; + as.nchannels = 2; + as.fmt = AUD_FMT_S16; + as.endianness = 0; + + pThis->paNodes[1].node.au32F00_param[0xA] = CODEC_F00_0A_16_BIT; + hdaCodecOpenVoice(pThis, PI_INDEX, &as); + hdaCodecOpenVoice(pThis, PO_INDEX, &as); + pThis->paNodes[1].node.au32F00_param[0xA] |= CODEC_F00_0A_44_1KHZ; + + uint8_t i; + Assert(pThis->paNodes); + Assert(pThis->pfnCodecNodeReset); + for (i = 0; i < pThis->cTotalNodes; ++i) + { + pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]); + } + + hdaCodecToAudVolume(&pThis->paNodes[pThis->u8DacLineOut].dac.B_params, AUD_MIXER_VOLUME); + hdaCodecToAudVolume(&pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, AUD_MIXER_LINE_IN); + + /* If no host voices were created, then fallback to nul audio. */ + if (!AUD_is_host_voice_in_ok(pThis->SwVoiceIn)) + LogRel (("HDA: WARNING: Unable to open PCM IN!\n")); + if (!AUD_is_host_voice_out_ok(pThis->SwVoiceOut)) + LogRel (("HDA: WARNING: Unable to open PCM OUT!\n")); + + if ( !AUD_is_host_voice_in_ok(pThis->SwVoiceIn) + && !AUD_is_host_voice_out_ok(pThis->SwVoiceOut)) + { + /* Was not able initialize *any* voice. Select the NULL audio driver instead */ + AUD_close_in (&pThis->card, pThis->SwVoiceIn); + AUD_close_out (&pThis->card, pThis->SwVoiceOut); + pThis->SwVoiceOut = NULL; + pThis->SwVoiceIn = NULL; + AUD_init_null (); + + PDMDevHlpVMSetRuntimeError (pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", + N_ ("No audio devices could be opened. Selecting the NULL audio backend " + "with the consequence that no sound is audible")); + } + else if ( !AUD_is_host_voice_in_ok(pThis->SwVoiceIn) + || !AUD_is_host_voice_out_ok(pThis->SwVoiceOut)) + { + char szMissingVoices[128]; + size_t len = 0; + if (!AUD_is_host_voice_in_ok(pThis->SwVoiceIn)) + len = RTStrPrintf (szMissingVoices, sizeof(szMissingVoices), "PCM_in"); + if (!AUD_is_host_voice_out_ok(pThis->SwVoiceOut)) + len += RTStrPrintf (szMissingVoices + len, sizeof(szMissingVoices) - len, len ? ", PCM_out" : "PCM_out"); + + PDMDevHlpVMSetRuntimeError (pDevIns, 0 /*fFlags*/, "HostAudioNotResponding", + N_ ("Some audio devices (%s) could not be opened. Guest applications generating audio " + "output or depending on audio input may hang. Make sure your host audio device " + "is working properly. Check the logfile for error messages of the audio " + "subsystem"), szMissingVoices); + } + + return VINF_SUCCESS; +} + diff --git a/src/VBox/Devices/Audio/DevIchHdaCodec.h b/src/VBox/Devices/Audio/DevIchHdaCodec.h new file mode 100644 index 00000000..384bef93 --- /dev/null +++ b/src/VBox/Devices/Audio/DevIchHdaCodec.h @@ -0,0 +1,137 @@ +/* $Id: DevIchHdaCodec.h $ */ +/** @file + * DevIchHdaCodec - VBox ICH Intel HD Audio Codec. + */ + +/* + * Copyright (C) 2006-2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef DEV_CODEC_H +#define DEV_CODEC_H + +/** The ICH HDA (Intel) codec state. */ +typedef struct HDACODEC HDACODEC; +/** Pointer to the Intel ICH HDA codec state. */ +typedef HDACODEC *PHDACODEC; + +/** + * Verb processor method. + */ +typedef DECLCALLBACK(int) FNHDACODECVERBPROCESSOR(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp); +typedef FNHDACODECVERBPROCESSOR *PFNHDACODECVERBPROCESSOR; +typedef FNHDACODECVERBPROCESSOR **PPFNHDACODECVERBPROCESSOR; + +/* PRM 5.3.1 */ +#define CODEC_RESPONSE_UNSOLICITED RT_BIT_64(34) + + +#ifndef VBOX_WITH_HDA_CODEC_EMU +typedef struct CODECVERB +{ + uint32_t verb; + /* operation bitness mask */ + uint32_t mask; + PFNHDACODECVERBPROCESSOR pfn; +} CODECVERB; +#endif + +#ifndef VBOX_WITH_HDA_CODEC_EMU +# define TYPE union +#else +# define TYPE struct +typedef struct CODECEMU CODECEMU; +typedef CODECEMU *PCODECEMU; +#endif +TYPE CODECNODE; +typedef TYPE CODECNODE CODECNODE; +typedef TYPE CODECNODE *PCODECNODE; + +typedef enum +{ + PI_INDEX = 0, /* PCM in */ + PO_INDEX, /* PCM out */ + MC_INDEX, /* Mic in */ + LAST_INDEX +} ENMSOUNDSOURCE; + + +typedef struct HDACODEC +{ + uint16_t id; + uint16_t u16VendorId; + uint16_t u16DeviceId; + uint8_t u8BSKU; + uint8_t u8AssemblyId; +#ifndef VBOX_WITH_HDA_CODEC_EMU + CODECVERB const *paVerbs; + int cVerbs; +#else + PCODECEMU pCodecBackend; +#endif + PCODECNODE paNodes; + QEMUSoundCard card; + /** PCM in */ + SWVoiceIn *SwVoiceIn; + /** PCM out */ + SWVoiceOut *SwVoiceOut; + void *pvHDAState; + bool fInReset; +#ifndef VBOX_WITH_HDA_CODEC_EMU + const uint8_t cTotalNodes; + const uint8_t *au8Ports; + const uint8_t *au8Dacs; + const uint8_t *au8AdcVols; + const uint8_t *au8Adcs; + const uint8_t *au8AdcMuxs; + const uint8_t *au8Pcbeeps; + const uint8_t *au8SpdifIns; + const uint8_t *au8SpdifOuts; + const uint8_t *au8DigInPins; + const uint8_t *au8DigOutPins; + const uint8_t *au8Cds; + const uint8_t *au8VolKnobs; + const uint8_t *au8Reserveds; + const uint8_t u8AdcVolsLineIn; + const uint8_t u8DacLineOut; +#endif + DECLR3CALLBACKMEMBER(int, pfnProcess, (PHDACODEC pCodec)); + DECLR3CALLBACKMEMBER(void, pfnTransfer, (PHDACODEC pCodec, ENMSOUNDSOURCE, int avail)); + /* These callbacks are set by Codec implementation. */ + DECLR3CALLBACKMEMBER(int, pfnLookup, (PHDACODEC pThis, uint32_t verb, PPFNHDACODECVERBPROCESSOR)); + DECLR3CALLBACKMEMBER(int, pfnReset, (PHDACODEC pThis)); + DECLR3CALLBACKMEMBER(int, pfnCodecNodeReset, (PHDACODEC pThis, uint8_t, PCODECNODE)); + /* These callbacks are set by codec implementation to answer debugger requests. */ + DECLR3CALLBACKMEMBER(void, pfnCodecDbgListNodes, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)); + DECLR3CALLBACKMEMBER(void, pfnCodecDbgSelector, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)); +} CODECState; + +int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, PCFGMNODE pCfg); +int hdaCodecDestruct(PHDACODEC pThis); +int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM); +int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion); +int hdaCodecOpenVoice(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, audsettings_t *pAudioSettings); + +#define HDA_SSM_VERSION 4 +#define HDA_SSM_VERSION_1 1 +#define HDA_SSM_VERSION_2 2 +#define HDA_SSM_VERSION_3 3 + +# ifdef VBOX_WITH_HDA_CODEC_EMU +/* */ +struct CODECEMU +{ + DECLR3CALLBACKMEMBER(int, pfnCodecEmuConstruct,(PHDACODEC pThis)); + DECLR3CALLBACKMEMBER(int, pfnCodecEmuDestruct,(PHDACODEC pThis)); + DECLR3CALLBACKMEMBER(int, pfnCodecEmuReset,(PHDACODEC pThis, bool fInit)); +}; +# endif +#endif diff --git a/src/VBox/Devices/Audio/DevIchIntelHDA.cpp b/src/VBox/Devices/Audio/DevIchIntelHDA.cpp deleted file mode 100644 index 30a220fe..00000000 --- a/src/VBox/Devices/Audio/DevIchIntelHDA.cpp +++ /dev/null @@ -1,2735 +0,0 @@ -/* $Id: DevIchIntelHDA.cpp $ */ -/** @file - * DevIchIntelHD - VBox ICH Intel HD Audio Controller. - */ - -/* - * Copyright (C) 2006-2010 Oracle Corporation - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -/******************************************************************************* -* Header Files * -*******************************************************************************/ -#define LOG_GROUP LOG_GROUP_DEV_AUDIO -#include <VBox/vmm/pdmdev.h> -#include <VBox/version.h> - -#include <iprt/assert.h> -#include <iprt/uuid.h> -#include <iprt/string.h> -#include <iprt/mem.h> -#include <iprt/asm.h> -#include <iprt/asm-math.h> - -#include "VBoxDD.h" - -extern "C" { -#include "audio.h" -} -#include "DevCodec.h" - -#define VBOX_WITH_INTEL_HDA - -#if defined(VBOX_WITH_HP_HDA) -/* HP Pavilion dv4t-1300 */ -# define HDA_PCI_VENDOR_ID 0x103c -# define HDA_PCI_DEICE_ID 0x30f7 -#elif defined(VBOX_WITH_INTEL_HDA) -/* Intel HDA controller */ -# define HDA_PCI_VENDOR_ID 0x8086 -# define HDA_PCI_DEICE_ID 0x2668 -#elif defined(VBOX_WITH_NVIDIA_HDA) -/* nVidia HDA controller */ -# define HDA_PCI_VENDOR_ID 0x10de -# define HDA_PCI_DEICE_ID 0x0ac0 -#else -# error "Please specify your HDA device vendor/device IDs" -#endif - -PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb); -PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb); -static DECLCALLBACK(void) hdaReset (PPDMDEVINS pDevIns); - -#define HDA_NREGS 112 -/* Registers */ -#define HDA_REG_IND_NAME(x) ICH6_HDA_REG_##x -#define HDA_REG_FIELD_NAME(reg, x) ICH6_HDA_##reg##_##x -#define HDA_REG_FIELD_MASK(reg, x) ICH6_HDA_##reg##_##x##_MASK -#define HDA_REG_FIELD_FLAG_MASK(reg, x) RT_BIT(ICH6_HDA_##reg##_##x##_SHIFT) -#define HDA_REG_FIELD_SHIFT(reg, x) ICH6_HDA_##reg##_##x##_SHIFT -#define HDA_REG_IND(pState, x) ((pState)->au32Regs[(x)]) -#define HDA_REG(pState, x) (HDA_REG_IND((pState), HDA_REG_IND_NAME(x))) -#define HDA_REG_VALUE(pState, reg, val) (HDA_REG((pState),reg) & (((HDA_REG_FIELD_MASK(reg, val))) << (HDA_REG_FIELD_SHIFT(reg, val)))) -#define HDA_REG_FLAG_VALUE(pState, reg, val) (HDA_REG((pState),reg) & (((HDA_REG_FIELD_FLAG_MASK(reg, val))))) -#define HDA_REG_SVALUE(pState, reg, val) (HDA_REG_VALUE(pState, reg, val) >> (HDA_REG_FIELD_SHIFT(reg, val))) - -#define ICH6_HDA_REG_GCAP 0 /* range 0x00-0x01*/ -#define GCAP(pState) (HDA_REG((pState), GCAP)) -/* GCAP HDASpec 3.3.2 This macro compact following information about HDA - * oss (15:12) - number of output streams supported - * iss (11:8) - number of input streams supported - * bss (7:3) - number of bidirection streams suppoted - * bds (2:1) - number of serial data out signals supported - * b64sup (0) - 64 bit addressing supported. - */ -#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \ - ( (((oss) & 0xF) << 12) \ - | (((iss) & 0xF) << 8) \ - | (((bss) & 0x1F) << 3) \ - | (((bds) & 0x3) << 2) \ - | ((b64sup) & 1)) -#define ICH6_HDA_REG_VMIN 1 /* range 0x02 */ -#define VMIN(pState) (HDA_REG((pState), VMIN)) - -#define ICH6_HDA_REG_VMAJ 2 /* range 0x03 */ -#define VMAJ(pState) (HDA_REG((pState), VMAJ)) - -#define ICH6_HDA_REG_OUTPAY 3 /* range 0x04-0x05 */ -#define OUTPAY(pState) (HDA_REG((pState), OUTPAY)) - -#define ICH6_HDA_REG_INPAY 4 /* range 0x06-0x07 */ -#define INPAY(pState) (HDA_REG((pState), INPAY)) - -#define ICH6_HDA_REG_GCTL (5) -#define ICH6_HDA_GCTL_RST_SHIFT (0) -#define ICH6_HDA_GCTL_FSH_SHIFT (1) -#define ICH6_HDA_GCTL_UR_SHIFT (8) -#define GCTL(pState) (HDA_REG((pState), GCTL)) - -#define ICH6_HDA_REG_WAKEEN 6 /* 0x0C */ -#define WAKEEN(pState) (HDA_REG((pState), WAKEEN)) - -#define ICH6_HDA_REG_STATESTS 7 /* range 0x0E */ -#define STATESTS(pState) (HDA_REG((pState), STATESTS)) -#define ICH6_HDA_STATES_SCSF 0x7 - -#define ICH6_HDA_REG_GSTS 8 /* range 0x10-0x11*/ -#define ICH6_HDA_GSTS_FSH_SHIFT (1) -#define GSTS(pState) (HDA_REG(pState, GSTS)) - -#define ICH6_HDA_REG_INTCTL 9 /* 0x20 */ -#define ICH6_HDA_INTCTL_GIE_SHIFT 31 -#define ICH6_HDA_INTCTL_CIE_SHIFT 30 -#define ICH6_HDA_INTCTL_S0_SHIFT (0) -#define ICH6_HDA_INTCTL_S1_SHIFT (1) -#define ICH6_HDA_INTCTL_S2_SHIFT (2) -#define ICH6_HDA_INTCTL_S3_SHIFT (3) -#define ICH6_HDA_INTCTL_S4_SHIFT (4) -#define ICH6_HDA_INTCTL_S5_SHIFT (5) -#define ICH6_HDA_INTCTL_S6_SHIFT (6) -#define ICH6_HDA_INTCTL_S7_SHIFT (7) -#define INTCTL(pState) (HDA_REG((pState), INTCTL)) -#define INTCTL_GIE(pState) (HDA_REG_FLAG_VALUE(pState, INTCTL, GIE)) -#define INTCTL_CIE(pState) (HDA_REG_FLAG_VALUE(pState, INTCTL, CIE)) -#define INTCTL_SX(pState, X) (HDA_REG_FLAG_VALUE((pState), INTCTL, S##X)) -#define INTCTL_SALL(pState) (INTCTL((pState)) & 0xFF) - -/* Note: The HDA specification defines a SSYNC register at offset 0x38. The - * ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches - * the datasheet. - */ -#define ICH6_HDA_REG_SSYNC 12 /* 0x34 */ -#define SSYNC(pState) (HDA_REG((pState), SSYNC)) - -#define ICH6_HDA_REG_INTSTS 10 /* 0x24 */ -#define ICH6_HDA_INTSTS_GIS_SHIFT (31) -#define ICH6_HDA_INTSTS_CIS_SHIFT (30) -#define ICH6_HDA_INTSTS_S0_SHIFT (0) -#define ICH6_HDA_INTSTS_S1_SHIFT (1) -#define ICH6_HDA_INTSTS_S2_SHIFT (2) -#define ICH6_HDA_INTSTS_S3_SHIFT (3) -#define ICH6_HDA_INTSTS_S4_SHIFT (4) -#define ICH6_HDA_INTSTS_S5_SHIFT (5) -#define ICH6_HDA_INTSTS_S6_SHIFT (6) -#define ICH6_HDA_INTSTS_S7_SHIFT (7) -#define ICH6_HDA_INTSTS_S_MASK(num) RT_BIT(HDA_REG_FIELD_SHIFT(S##num)) -#define INTSTS(pState) (HDA_REG((pState), INTSTS)) -#define INTSTS_GIS(pState) (HDA_REG_FLAG_VALUE((pState), INTSTS, GIS) -#define INTSTS_CIS(pState) (HDA_REG_FLAG_VALUE((pState), INTSTS, CIS) -#define INTSTS_SX(pState, X) (HDA_REG_FLAG_VALUE(pState), INTSTS, S##X) -#define INTSTS_SANY(pState) (INTSTS((pState)) & 0xFF) - -#define ICH6_HDA_REG_CORBLBASE 13 /* 0x40 */ -#define CORBLBASE(pState) (HDA_REG((pState), CORBLBASE)) -#define ICH6_HDA_REG_CORBUBASE 14 /* 0x44 */ -#define CORBUBASE(pState) (HDA_REG((pState), CORBUBASE)) -#define ICH6_HDA_REG_CORBWP 15 /* 48 */ -#define ICH6_HDA_REG_CORBRP 16 /* 4A */ -#define ICH6_HDA_CORBRP_RST_SHIFT 15 -#define ICH6_HDA_CORBRP_WP_SHIFT 0 -#define ICH6_HDA_CORBRP_WP_MASK 0xFF - -#define CORBRP(pState) (HDA_REG(pState, CORBRP)) -#define CORBWP(pState) (HDA_REG(pState, CORBWP)) - -#define ICH6_HDA_REG_CORBCTL 17 /* 0x4C */ -#define ICH6_HDA_CORBCTL_DMA_SHIFT (1) -#define ICH6_HDA_CORBCTL_CMEIE_SHIFT (0) - -#define CORBCTL(pState) (HDA_REG(pState, CORBCTL)) - - -#define ICH6_HDA_REG_CORBSTS 18 /* 0x4D */ -#define CORBSTS(pState) (HDA_REG(pState, CORBSTS)) -#define ICH6_HDA_CORBSTS_CMEI_SHIFT (0) - -#define ICH6_HDA_REG_CORBSIZE 19 /* 0x4E */ -#define ICH6_HDA_CORBSIZE_SZ_CAP 0xF0 -#define ICH6_HDA_CORBSIZE_SZ 0x3 -#define CORBSIZE_SZ(pState) (HDA_REG(pState, ICH6_HDA_REG_CORBSIZE) & ICH6_HDA_CORBSIZE_SZ) -#define CORBSIZE_SZ_CAP(pState) (HDA_REG(pState, ICH6_HDA_REG_CORBSIZE) & ICH6_HDA_CORBSIZE_SZ_CAP) -/* till ich 10 sizes of CORB and RIRB are hardcoded to 256 in real hw */ - -#define ICH6_HDA_REG_RIRLBASE 20 /* 0x50 */ -#define RIRLBASE(pState) (HDA_REG((pState), RIRLBASE)) - -#define ICH6_HDA_REG_RIRUBASE 21 /* 0x54 */ -#define RIRUBASE(pState) (HDA_REG((pState), RIRUBASE)) - -#define ICH6_HDA_REG_RIRBWP 22 /* 0x58 */ -#define ICH6_HDA_RIRBWP_RST_SHIFT (15) -#define ICH6_HDA_RIRBWP_WP_MASK 0xFF -#define RIRBWP(pState) (HDA_REG(pState, RIRBWP)) - -#define ICH6_HDA_REG_RINTCNT 23 /* 0x5A */ -#define RINTCNT(pState) (HDA_REG((pState), RINTCNT)) -#define RINTCNT_N(pState) (RINTCNT((pState)) & 0xff) - -#define ICH6_HDA_REG_RIRBCTL 24 /* 0x5C */ -#define ICH6_HDA_RIRBCTL_RIC_SHIFT (0) -#define ICH6_HDA_RIRBCTL_DMA_SHIFT (1) -#define ICH6_HDA_ROI_DMA_SHIFT (2) -#define RIRBCTL(pState) (HDA_REG((pState), RIRBCTL)) -#define RIRBCTL_RIRB_RIC(pState) (HDA_REG_FLAG_VALUE(pState, RIRBCTL, RIC)) -#define RIRBCTL_RIRB_DMA(pState) (HDA_REG_FLAG_VALUE((pState), RIRBCTL, DMA) -#define RIRBCTL_ROI(pState) (HDA_REG_FLAG_VALUE((pState), RIRBCTL, ROI)) - -#define ICH6_HDA_REG_RIRBSTS 25 /* 0x5D */ -#define ICH6_HDA_RIRBSTS_RINTFL_SHIFT (0) -#define ICH6_HDA_RIRBSTS_RIRBOIS_SHIFT (2) -#define RIRBSTS(pState) (HDA_REG(pState, RIRBSTS)) -#define RIRBSTS_RINTFL(pState) (HDA_REG_FLAG_VALUE(pState, RIRBSTS, RINTFL)) -#define RIRBSTS_RIRBOIS(pState) (HDA_REG_FLAG_VALUE(pState, RIRBSTS, RIRBOIS)) - -#define ICH6_HDA_REG_RIRBSIZE 26 /* 0x5E */ -#define ICH6_HDA_RIRBSIZE_SZ_CAP 0xF0 -#define ICH6_HDA_RIRBSIZE_SZ 0x3 - -#define RIRBSIZE_SZ(pState) (HDA_REG(pState, ICH6_HDA_REG_RIRBSIZE) & ICH6_HDA_RIRBSIZE_SZ) -#define RIRBSIZE_SZ_CAP(pState) (HDA_REG(pState, ICH6_HDA_REG_RIRBSIZE) & ICH6_HDA_RIRBSIZE_SZ_CAP) - - -#define ICH6_HDA_REG_IC 27 /* 0x60 */ -#define IC(pState) (HDA_REG(pState, IC)) -#define ICH6_HDA_REG_IR 28 /* 0x64 */ -#define IR(pState) (HDA_REG(pState, IR)) -#define ICH6_HDA_REG_IRS 29 /* 0x68 */ -#define ICH6_HDA_IRS_ICB_SHIFT (0) -#define ICH6_HDA_IRS_IRV_SHIFT (1) -#define IRS(pState) (HDA_REG(pState, IRS)) -#define IRS_ICB(pState) (HDA_REG_FLAG_VALUE(pState, IRS, ICB)) -#define IRS_IRV(pState) (HDA_REG_FLAG_VALUE(pState, IRS, IRV)) - -#define ICH6_HDA_REG_DPLBASE 30 /* 0x70 */ -#define DPLBASE(pState) (HDA_REG((pState), DPLBASE)) -#define ICH6_HDA_REG_DPUBASE 31 /* 0x74 */ -#define DPUBASE(pState) (HDA_REG((pState), DPUBASE)) -#define DPBASE_ENABLED 1 -#define DPBASE_ADDR_MASK (~0x7f) - -#define HDA_STREAM_REG_DEF(name, num) (ICH6_HDA_REG_SD##num##name) -#define HDA_STREAM_REG(pState, name, num) (HDA_REG((pState), N_(HDA_STREAM_REG_DEF(name, num)))) -/* Note: sdnum here _MUST_ be stream reg number [0,7] */ -#define HDA_STREAM_REG2(pState, name, sdnum) (HDA_REG_IND((pState), ICH6_HDA_REG_SD0##name + (sdnum) * 10)) - -#define ICH6_HDA_REG_SD0CTL 32 /* 0x80 */ -#define ICH6_HDA_REG_SD1CTL (HDA_STREAM_REG_DEF(CTL, 0) + 10) /* 0xA0 */ -#define ICH6_HDA_REG_SD2CTL (HDA_STREAM_REG_DEF(CTL, 0) + 20) /* 0xC0 */ -#define ICH6_HDA_REG_SD3CTL (HDA_STREAM_REG_DEF(CTL, 0) + 30) /* 0xE0 */ -#define ICH6_HDA_REG_SD4CTL (HDA_STREAM_REG_DEF(CTL, 0) + 40) /* 0x100 */ -#define ICH6_HDA_REG_SD5CTL (HDA_STREAM_REG_DEF(CTL, 0) + 50) /* 0x120 */ -#define ICH6_HDA_REG_SD6CTL (HDA_STREAM_REG_DEF(CTL, 0) + 60) /* 0x140 */ -#define ICH6_HDA_REG_SD7CTL (HDA_STREAM_REG_DEF(CTL, 0) + 70) /* 0x160 */ - -#define SD(func, num) SD##num##func -#define SDCTL(pState, num) HDA_REG((pState), SD(CTL, num)) -#define SDCTL_NUM(pState, num) ((SDCTL((pState), num) & HDA_REG_FIELD_MASK(SDCTL,NUM)) >> HDA_REG_FIELD_SHIFT(SDCTL, NUM)) -#define ICH6_HDA_SDCTL_NUM_MASK (0xF) -#define ICH6_HDA_SDCTL_NUM_SHIFT (20) -#define ICH6_HDA_SDCTL_DIR_SHIFT (19) -#define ICH6_HDA_SDCTL_TP_SHIFT (18) -#define ICH6_HDA_SDCTL_STRIPE_MASK (0x3) -#define ICH6_HDA_SDCTL_STRIPE_SHIFT (16) -#define ICH6_HDA_SDCTL_DEIE_SHIFT (4) -#define ICH6_HDA_SDCTL_FEIE_SHIFT (3) -#define ICH6_HDA_SDCTL_ICE_SHIFT (2) -#define ICH6_HDA_SDCTL_RUN_SHIFT (1) -#define ICH6_HDA_SDCTL_SRST_SHIFT (0) - -#define ICH6_HDA_REG_SD0STS 33 /* 0x83 */ -#define ICH6_HDA_REG_SD1STS (HDA_STREAM_REG_DEF(STS, 0) + 10) /* 0xA3 */ -#define ICH6_HDA_REG_SD2STS (HDA_STREAM_REG_DEF(STS, 0) + 20) /* 0xC3 */ -#define ICH6_HDA_REG_SD3STS (HDA_STREAM_REG_DEF(STS, 0) + 30) /* 0xE3 */ -#define ICH6_HDA_REG_SD4STS (HDA_STREAM_REG_DEF(STS, 0) + 40) /* 0x103 */ -#define ICH6_HDA_REG_SD5STS (HDA_STREAM_REG_DEF(STS, 0) + 50) /* 0x123 */ -#define ICH6_HDA_REG_SD6STS (HDA_STREAM_REG_DEF(STS, 0) + 60) /* 0x143 */ -#define ICH6_HDA_REG_SD7STS (HDA_STREAM_REG_DEF(STS, 0) + 70) /* 0x163 */ - -#define SDSTS(pState, num) HDA_REG((pState), SD(STS, num)) -#define ICH6_HDA_SDSTS_FIFORDY_SHIFT (5) -#define ICH6_HDA_SDSTS_DE_SHIFT (4) -#define ICH6_HDA_SDSTS_FE_SHIFT (3) -#define ICH6_HDA_SDSTS_BCIS_SHIFT (2) - -#define ICH6_HDA_REG_SD0LPIB 34 /* 0x84 */ -#define ICH6_HDA_REG_SD1LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 10) /* 0xA4 */ -#define ICH6_HDA_REG_SD2LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 20) /* 0xC4 */ -#define ICH6_HDA_REG_SD3LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 30) /* 0xE4 */ -#define ICH6_HDA_REG_SD4LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 40) /* 0x104 */ -#define ICH6_HDA_REG_SD5LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 50) /* 0x124 */ -#define ICH6_HDA_REG_SD6LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 60) /* 0x144 */ -#define ICH6_HDA_REG_SD7LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 70) /* 0x164 */ - -#define SDLPIB(pState, num) HDA_REG((pState), SD(LPIB, num)) - -#define ICH6_HDA_REG_SD0CBL 35 /* 0x88 */ -#define ICH6_HDA_REG_SD1CBL (HDA_STREAM_REG_DEF(CBL, 0) + 10) /* 0xA8 */ -#define ICH6_HDA_REG_SD2CBL (HDA_STREAM_REG_DEF(CBL, 0) + 20) /* 0xC8 */ -#define ICH6_HDA_REG_SD3CBL (HDA_STREAM_REG_DEF(CBL, 0) + 30) /* 0xE8 */ -#define ICH6_HDA_REG_SD4CBL (HDA_STREAM_REG_DEF(CBL, 0) + 40) /* 0x108 */ -#define ICH6_HDA_REG_SD5CBL (HDA_STREAM_REG_DEF(CBL, 0) + 50) /* 0x128 */ -#define ICH6_HDA_REG_SD6CBL (HDA_STREAM_REG_DEF(CBL, 0) + 60) /* 0x148 */ -#define ICH6_HDA_REG_SD7CBL (HDA_STREAM_REG_DEF(CBL, 0) + 70) /* 0x168 */ - -#define SDLCBL(pState, num) HDA_REG((pState), SD(CBL, num)) - -#define ICH6_HDA_REG_SD0LVI 36 /* 0x8C */ -#define ICH6_HDA_REG_SD1LVI (HDA_STREAM_REG_DEF(LVI, 0) + 10) /* 0xAC */ -#define ICH6_HDA_REG_SD2LVI (HDA_STREAM_REG_DEF(LVI, 0) + 20) /* 0xCC */ -#define ICH6_HDA_REG_SD3LVI (HDA_STREAM_REG_DEF(LVI, 0) + 30) /* 0xEC */ -#define ICH6_HDA_REG_SD4LVI (HDA_STREAM_REG_DEF(LVI, 0) + 40) /* 0x10C */ -#define ICH6_HDA_REG_SD5LVI (HDA_STREAM_REG_DEF(LVI, 0) + 50) /* 0x12C */ -#define ICH6_HDA_REG_SD6LVI (HDA_STREAM_REG_DEF(LVI, 0) + 60) /* 0x14C */ -#define ICH6_HDA_REG_SD7LVI (HDA_STREAM_REG_DEF(LVI, 0) + 70) /* 0x16C */ - -#define SDLVI(pState, num) HDA_REG((pState), SD(LVI, num)) - -#define ICH6_HDA_REG_SD0FIFOW 37 /* 0x8E */ -#define ICH6_HDA_REG_SD1FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 10) /* 0xAE */ -#define ICH6_HDA_REG_SD2FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 20) /* 0xCE */ -#define ICH6_HDA_REG_SD3FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 30) /* 0xEE */ -#define ICH6_HDA_REG_SD4FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 40) /* 0x10E */ -#define ICH6_HDA_REG_SD5FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 50) /* 0x12E */ -#define ICH6_HDA_REG_SD6FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 60) /* 0x14E */ -#define ICH6_HDA_REG_SD7FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 70) /* 0x16E */ - -/* - * ICH6 datasheet defined limits for FIFOW values (18.2.38) - */ -#define HDA_SDFIFOW_8B (0x2) -#define HDA_SDFIFOW_16B (0x3) -#define HDA_SDFIFOW_32B (0x4) -#define SDFIFOW(pState, num) HDA_REG((pState), SD(FIFOW, num)) - -#define ICH6_HDA_REG_SD0FIFOS 38 /* 0x90 */ -#define ICH6_HDA_REG_SD1FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 10) /* 0xB0 */ -#define ICH6_HDA_REG_SD2FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 20) /* 0xD0 */ -#define ICH6_HDA_REG_SD3FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 30) /* 0xF0 */ -#define ICH6_HDA_REG_SD4FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 40) /* 0x110 */ -#define ICH6_HDA_REG_SD5FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 50) /* 0x130 */ -#define ICH6_HDA_REG_SD6FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 60) /* 0x150 */ -#define ICH6_HDA_REG_SD7FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 70) /* 0x170 */ - -/* - * ICH6 datasheet defines limits for FIFOS registers (18.2.39) - * formula: size - 1 - * Other values not listed are not supported. - */ -#define HDA_SDONFIFO_16B (0xF) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ -#define HDA_SDONFIFO_32B (0x1F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ -#define HDA_SDONFIFO_64B (0x3F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ -#define HDA_SDONFIFO_128B (0x7F) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ -#define HDA_SDONFIFO_192B (0xBF) /* 8-, 16-, 20-, 24-, 32-bit Output Streams */ -#define HDA_SDONFIFO_256B (0xFF) /* 20-, 24-bit Output Streams */ -#define HDA_SDINFIFO_120B (0x77) /* 8-, 16-, 20-, 24-, 32-bit Input Streams */ -#define HDA_SDINFIFO_160B (0x9F) /* 20-, 24-bit Input Streams Streams */ -#define SDFIFOS(pState, num) HDA_REG((pState), SD(FIFOS, num)) - -#define ICH6_HDA_REG_SD0FMT 39 /* 0x92 */ -#define ICH6_HDA_REG_SD1FMT (HDA_STREAM_REG_DEF(FMT, 0) + 10) /* 0xB2 */ -#define ICH6_HDA_REG_SD2FMT (HDA_STREAM_REG_DEF(FMT, 0) + 20) /* 0xD2 */ -#define ICH6_HDA_REG_SD3FMT (HDA_STREAM_REG_DEF(FMT, 0) + 30) /* 0xF2 */ -#define ICH6_HDA_REG_SD4FMT (HDA_STREAM_REG_DEF(FMT, 0) + 40) /* 0x112 */ -#define ICH6_HDA_REG_SD5FMT (HDA_STREAM_REG_DEF(FMT, 0) + 50) /* 0x132 */ -#define ICH6_HDA_REG_SD6FMT (HDA_STREAM_REG_DEF(FMT, 0) + 60) /* 0x152 */ -#define ICH6_HDA_REG_SD7FMT (HDA_STREAM_REG_DEF(FMT, 0) + 70) /* 0x172 */ - -#define SDFMT(pState, num) (HDA_REG((pState), SD(FMT, num))) -#define ICH6_HDA_SDFMT_BASE_RATE_SHIFT (14) -#define ICH6_HDA_SDFMT_MULT_SHIFT (11) -#define ICH6_HDA_SDFMT_MULT_MASK (0x7) -#define ICH6_HDA_SDFMT_DIV_SHIFT (8) -#define ICH6_HDA_SDFMT_DIV_MASK (0x7) -#define ICH6_HDA_SDFMT_BITS_SHIFT (4) -#define ICH6_HDA_SDFMT_BITS_MASK (0x7) -#define SDFMT_BASE_RATE(pState, num) ((SDFMT(pState, num) & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE)) -#define SDFMT_MULT(pState, num) ((SDFMT((pState), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT)) -#define SDFMT_DIV(pState, num) ((SDFMT((pState), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV)) - -#define ICH6_HDA_REG_SD0BDPL 40 /* 0x98 */ -#define ICH6_HDA_REG_SD1BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 10) /* 0xB8 */ -#define ICH6_HDA_REG_SD2BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 20) /* 0xD8 */ -#define ICH6_HDA_REG_SD3BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 30) /* 0xF8 */ -#define ICH6_HDA_REG_SD4BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 40) /* 0x118 */ -#define ICH6_HDA_REG_SD5BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 50) /* 0x138 */ -#define ICH6_HDA_REG_SD6BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 60) /* 0x158 */ -#define ICH6_HDA_REG_SD7BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 70) /* 0x178 */ - -#define SDBDPL(pState, num) HDA_REG((pState), SD(BDPL, num)) - -#define ICH6_HDA_REG_SD0BDPU 41 /* 0x9C */ -#define ICH6_HDA_REG_SD1BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 10) /* 0xBC */ -#define ICH6_HDA_REG_SD2BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 20) /* 0xDC */ -#define ICH6_HDA_REG_SD3BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 30) /* 0xFC */ -#define ICH6_HDA_REG_SD4BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 40) /* 0x11C */ -#define ICH6_HDA_REG_SD5BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 50) /* 0x13C */ -#define ICH6_HDA_REG_SD6BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 60) /* 0x15C */ -#define ICH6_HDA_REG_SD7BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 70) /* 0x17C */ - -#define SDBDPU(pState, num) HDA_REG((pState), SD(BDPU, num)) - - -typedef struct HDABDLEDESC -{ - uint64_t u64BdleCviAddr; - uint32_t u32BdleMaxCvi; - uint32_t u32BdleCvi; - uint32_t u32BdleCviLen; - uint32_t u32BdleCviPos; - bool fBdleCviIoc; - uint32_t cbUnderFifoW; - uint8_t au8HdaBuffer[HDA_SDONFIFO_256B + 1]; -} HDABDLEDESC, *PHDABDLEDESC; - - -/** HDABDLEDESC field descriptors the v3+ saved state. */ -static SSMFIELD const g_aHdaBDLEDescFields[] = -{ - SSMFIELD_ENTRY( HDABDLEDESC, u64BdleCviAddr), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleMaxCvi), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCvi), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviLen), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviPos), - SSMFIELD_ENTRY( HDABDLEDESC, fBdleCviIoc), - SSMFIELD_ENTRY( HDABDLEDESC, cbUnderFifoW), - SSMFIELD_ENTRY( HDABDLEDESC, au8HdaBuffer), - SSMFIELD_ENTRY_TERM() -}; - -/** HDABDLEDESC field descriptors the v1 and v2 saved state. */ -static SSMFIELD const g_aHdaBDLEDescFieldsOld[] = -{ - SSMFIELD_ENTRY( HDABDLEDESC, u64BdleCviAddr), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleMaxCvi), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCvi), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviLen), - SSMFIELD_ENTRY( HDABDLEDESC, u32BdleCviPos), - SSMFIELD_ENTRY( HDABDLEDESC, fBdleCviIoc), - SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3), - SSMFIELD_ENTRY( HDABDLEDESC, cbUnderFifoW), - SSMFIELD_ENTRY( HDABDLEDESC, au8HdaBuffer), - SSMFIELD_ENTRY_TERM() -}; - -typedef struct HDASTREAMTRANSFERDESC -{ - uint64_t u64BaseDMA; - uint32_t u32Ctl; - uint32_t *pu32Sts; - uint8_t u8Strm; - uint32_t *pu32Lpib; - uint32_t u32Cbl; - uint32_t u32Fifos; -} HDASTREAMTRANSFERDESC, *PHDASTREAMTRANSFERDESC; - -typedef struct INTELHDLinkState -{ - /** Pointer to the device instance. */ - PPDMDEVINSR3 pDevIns; - /** Pointer to the connector of the attached audio driver. */ - PPDMIAUDIOCONNECTOR pDrv; - /** Pointer to the attached audio driver. */ - PPDMIBASE pDrvBase; - /** The base interface for LUN\#0. */ - PDMIBASE IBase; - RTGCPHYS addrMMReg; - uint32_t au32Regs[HDA_NREGS]; - HDABDLEDESC stInBdle; - HDABDLEDESC stOutBdle; - HDABDLEDESC stMicBdle; - /* Interrupt on completion */ - bool fCviIoc; - uint64_t u64CORBBase; - uint64_t u64RIRBBase; - uint64_t u64DPBase; - /* pointer on CORB buf */ - uint32_t *pu32CorbBuf; - /* size in bytes of CORB buf */ - uint32_t cbCorbBuf; - /* pointer on RIRB buf */ - uint64_t *pu64RirbBuf; - /* size in bytes of RIRB buf */ - uint32_t cbRirbBuf; - /* indicates if HDA in reset. */ - bool fInReset; - CODECState Codec; - uint8_t u8Counter; - uint64_t u64BaseTS; -} INTELHDLinkState, *PINTELHDLinkState; - -#define ICH6_HDASTATE_2_DEVINS(pINTELHD) ((pINTELHD)->pDevIns) -#define PCIDEV_2_ICH6_HDASTATE(pPciDev) ((PCIINTELHDLinkState *)(pPciDev)) - -#define ISD0FMT_TO_AUDIO_SELECTOR(pState) (AUDIO_FORMAT_SELECTOR(&(pState)->Codec, In, \ - SDFMT_BASE_RATE(pState, 0), SDFMT_MULT(pState, 0), SDFMT_DIV(pState, 0))) -#define OSD0FMT_TO_AUDIO_SELECTOR(pState) (AUDIO_FORMAT_SELECTOR(&(pState)->Codec, Out, \ - SDFMT_BASE_RATE(pState, 4), SDFMT_MULT(pState, 4), SDFMT_DIV(pState, 4))) - - - - -typedef struct PCIINTELHDLinkState -{ - PCIDevice dev; - INTELHDLinkState hda; -} PCIINTELHDLinkState; - - -/** @todo r=bird: Why aren't these static? And why use DECLCALLBACK for - * internal functions? */ -DECLCALLBACK(int) hdaRegReadUnimplemented(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteUnimplemented(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegReadGCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteGCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegReadSTATESTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteSTATESTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegReadGCAP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegReadINTSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegReadWALCLK(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteINTSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegWriteCORBWP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegWriteCORBRP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteCORBCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteCORBSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteRIRBWP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegWriteRIRBSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteIRS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegReadIRS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteSDCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegReadSDCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); - -DECLCALLBACK(int) hdaRegWriteSDSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteSDLVI(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteSDFIFOW(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteSDFIFOS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteSDFMT(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteSDBDPL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteSDBDPU(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegWriteBase(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); -DECLCALLBACK(int) hdaRegReadU32(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteU32(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegReadU24(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteU24(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegReadU16(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteU16(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); -DECLCALLBACK(int) hdaRegReadU8(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); -DECLCALLBACK(int) hdaRegWriteU8(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t pu32Value); - -DECLINLINE(void) hdaInitTransferDescriptor(PINTELHDLinkState pState, PHDABDLEDESC pBdle, uint8_t u8Strm, PHDASTREAMTRANSFERDESC pStreamDesc); -static int hdaMMIORegLookup(INTELHDLinkState* pState, uint32_t u32Offset); -static void hdaFetchBdle(INTELHDLinkState *pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc); -#ifdef LOG_ENABLED -static void dump_bd(INTELHDLinkState *pState, PHDABDLEDESC pBdle, uint64_t u64BaseDMA); -#endif - - -/* see 302349 p 6.2*/ -const static struct stIchIntelHDRegMap -{ - /** Register offset in the register space. */ - uint32_t offset; - /** Size in bytes. Registers of size > 4 are in fact tables. */ - uint32_t size; - /** Readable bits. */ - uint32_t readable; - /** Writable bits. */ - uint32_t writable; - /** Read callback. */ - int (*pfnRead)(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value); - /** Write callback. */ - int (*pfnWrite)(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value); - /** Abbreviated name. */ - const char *abbrev; - /** Full name. */ - const char *name; -} s_ichIntelHDRegMap[HDA_NREGS] = -{ - /* offset size read mask write mask read callback write callback abbrev full name */ - /*------- ------- ---------- ---------- ----------------------- ------------------------ ---------- ------------------------------*/ - { 0x00000, 0x00002, 0x0000FFFB, 0x00000000, hdaRegReadGCAP , hdaRegWriteUnimplemented, "GCAP" , "Global Capabilities" }, - { 0x00002, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "VMIN" , "Minor Version" }, - { 0x00003, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "VMAJ" , "Major Version" }, - { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimplemented, "OUTPAY" , "Output Payload Capabilities" }, - { 0x00006, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimplemented, "INPAY" , "Input Payload Capabilities" }, - { 0x00008, 0x00004, 0x00000103, 0x00000103, hdaRegReadGCTL , hdaRegWriteGCTL , "GCTL" , "Global Control" }, - { 0x0000c, 0x00002, 0x00007FFF, 0x00007FFF, hdaRegReadU16 , hdaRegWriteU16 , "WAKEEN" , "Wake Enable" }, - { 0x0000e, 0x00002, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteSTATESTS , "STATESTS" , "State Change Status" }, - { 0x00010, 0x00002, 0xFFFFFFFF, 0x00000000, hdaRegReadUnimplemented, hdaRegWriteUnimplemented, "GSTS" , "Global Status" }, - { 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, hdaRegReadU32 , hdaRegWriteU32 , "INTCTL" , "Interrupt Control" }, - { 0x00024, 0x00004, 0xC00000FF, 0x00000000, hdaRegReadINTSTS , hdaRegWriteUnimplemented, "INTSTS" , "Interrupt Status" }, - { 0x00030, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadWALCLK , hdaRegWriteUnimplemented, "WALCLK" , "Wall Clock Counter" }, - /// @todo r=michaln: Doesn't the SSYNC register need to actually stop the stream(s)? - { 0x00034, 0x00004, 0x000000FF, 0x000000FF, hdaRegReadU32 , hdaRegWriteU32 , "SSYNC" , "Stream Synchronization" }, - { 0x00040, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteBase , "CORBLBASE" , "CORB Lower Base Address" }, - { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , "CORBUBASE" , "CORB Upper Base Address" }, - { 0x00048, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteCORBWP , "CORBWP" , "CORB Write Pointer" }, - { 0x0004A, 0x00002, 0x000000FF, 0x000080FF, hdaRegReadU8 , hdaRegWriteCORBRP , "CORBRP" , "CORB Read Pointer" }, - { 0x0004C, 0x00001, 0x00000003, 0x00000003, hdaRegReadU8 , hdaRegWriteCORBCTL , "CORBCTL" , "CORB Control" }, - { 0x0004D, 0x00001, 0x00000001, 0x00000001, hdaRegReadU8 , hdaRegWriteCORBSTS , "CORBSTS" , "CORB Status" }, - { 0x0004E, 0x00001, 0x000000F3, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "CORBSIZE" , "CORB Size" }, - { 0x00050, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteBase , "RIRBLBASE" , "RIRB Lower Base Address" }, - { 0x00054, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , "RIRBUBASE" , "RIRB Upper Base Address" }, - { 0x00058, 0x00002, 0x000000FF, 0x00008000, hdaRegReadU8, hdaRegWriteRIRBWP , "RIRBWP" , "RIRB Write Pointer" }, - { 0x0005A, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteU16 , "RINTCNT" , "Response Interrupt Count" }, - { 0x0005C, 0x00001, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteU8 , "RIRBCTL" , "RIRB Control" }, - { 0x0005D, 0x00001, 0x00000005, 0x00000005, hdaRegReadU8 , hdaRegWriteRIRBSTS , "RIRBSTS" , "RIRB Status" }, - { 0x0005E, 0x00001, 0x000000F3, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimplemented, "RIRBSIZE" , "RIRB Size" }, - { 0x00060, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "IC" , "Immediate Command" }, - { 0x00064, 0x00004, 0x00000000, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteUnimplemented, "IR" , "Immediate Response" }, - { 0x00068, 0x00004, 0x00000002, 0x00000002, hdaRegReadIRS , hdaRegWriteIRS , "IRS" , "Immediate Command Status" }, - { 0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, hdaRegReadU32 , hdaRegWriteBase , "DPLBASE" , "DMA Position Lower Base" }, - { 0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , "DPUBASE" , "DMA Position Upper Base" }, - - { 0x00080, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD0CTL" , "Input Stream Descriptor 0 (ICD0) Control" }, - { 0x00083, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD0STS" , "ISD0 Status" }, - { 0x00084, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD0LPIB" , "ISD0 Link Position In Buffer" }, - { 0x00088, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD0CBL" , "ISD0 Cyclic Buffer Length" }, - { 0x0008C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD0LVI" , "ISD0 Last Valid Index" }, - { 0x0008E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "ISD0FIFOW", "ISD0 FIFO Watermark" }, - { 0x00090, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD0FIFOS", "ISD0 FIFO Size" }, - { 0x00092, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD0FMT" , "ISD0 Format" }, - { 0x00098, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD0BDPL" , "ISD0 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x0009C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD0BDPU" , "ISD0 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x000A0, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD1CTL" , "Input Stream Descriptor 1 (ISD1) Control" }, - { 0x000A3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD1STS" , "ISD1 Status" }, - { 0x000A4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD1LPIB" , "ISD1 Link Position In Buffer" }, - { 0x000A8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD1CBL" , "ISD1 Cyclic Buffer Length" }, - { 0x000AC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD1LVI" , "ISD1 Last Valid Index" }, - { 0x000AE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "ISD1FIFOW", "ISD1 FIFO Watermark" }, - { 0x000B0, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD1FIFOS", "ISD1 FIFO Size" }, - { 0x000B2, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD1FMT" , "ISD1 Format" }, - { 0x000B8, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD1BDPL" , "ISD1 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x000BC, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD1BDPU" , "ISD1 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x000C0, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD2CTL" , "Input Stream Descriptor 2 (ISD2) Control" }, - { 0x000C3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD2STS" , "ISD2 Status" }, - { 0x000C4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD2LPIB" , "ISD2 Link Position In Buffer" }, - { 0x000C8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD2CBL" , "ISD2 Cyclic Buffer Length" }, - { 0x000CC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD2LVI" , "ISD2 Last Valid Index" }, - { 0x000CE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "ISD2FIFOW", "ISD2 FIFO Watermark" }, - { 0x000D0, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD2FIFOS", "ISD2 FIFO Size" }, - { 0x000D2, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD2FMT" , "ISD2 Format" }, - { 0x000D8, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD2BDPL" , "ISD2 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x000DC, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD2BDPU" , "ISD2 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x000E0, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "ISD3CTL" , "Input Stream Descriptor 3 (ISD3) Control" }, - { 0x000E3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "ISD3STS" , "ISD3 Status" }, - { 0x000E4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "ISD3LPIB" , "ISD3 Link Position In Buffer" }, - { 0x000E8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "ISD3CBL" , "ISD3 Cyclic Buffer Length" }, - { 0x000EC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "ISD3LVI" , "ISD3 Last Valid Index" }, - { 0x000EE, 0x00002, 0x00000005, 0x00000005, hdaRegReadU16 , hdaRegWriteU16 , "ISD3FIFOW", "ISD3 FIFO Watermark" }, - { 0x000F0, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , "ISD3FIFOS", "ISD3 FIFO Size" }, - { 0x000F2, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "ISD3FMT" , "ISD3 Format" }, - { 0x000F8, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "ISD3BDPL" , "ISD3 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x000FC, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "ISD3BDPU" , "ISD3 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x00100, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadSDCTL , hdaRegWriteSDCTL , "OSD0CTL" , "Input Stream Descriptor 0 (OSD0) Control" }, - { 0x00103, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD0STS" , "OSD0 Status" }, - { 0x00104, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD0LPIB" , "OSD0 Link Position In Buffer" }, - { 0x00108, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD0CBL" , "OSD0 Cyclic Buffer Length" }, - { 0x0010C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD0LVI" , "OSD0 Last Valid Index" }, - { 0x0010E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD0FIFOW", "OSD0 FIFO Watermark" }, - { 0x00110, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD0FIFOS", "OSD0 FIFO Size" }, - { 0x00112, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD0FMT" , "OSD0 Format" }, - { 0x00118, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD0BDPL" , "OSD0 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x0011C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD0BDPU" , "OSD0 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x00120, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "OSD1CTL" , "Input Stream Descriptor 0 (OSD1) Control" }, - { 0x00123, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD1STS" , "OSD1 Status" }, - { 0x00124, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD1LPIB" , "OSD1 Link Position In Buffer" }, - { 0x00128, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD1CBL" , "OSD1 Cyclic Buffer Length" }, - { 0x0012C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD1LVI" , "OSD1 Last Valid Index" }, - { 0x0012E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD1FIFOW", "OSD1 FIFO Watermark" }, - { 0x00130, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD1FIFOS", "OSD1 FIFO Size" }, - { 0x00132, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD1FMT" , "OSD1 Format" }, - { 0x00138, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD1BDPL" , "OSD1 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x0013C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD1BDPU" , "OSD1 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x00140, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "OSD2CTL" , "Input Stream Descriptor 0 (OSD2) Control" }, - { 0x00143, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD2STS" , "OSD2 Status" }, - { 0x00144, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD2LPIB" , "OSD2 Link Position In Buffer" }, - { 0x00148, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD2CBL" , "OSD2 Cyclic Buffer Length" }, - { 0x0014C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD2LVI" , "OSD2 Last Valid Index" }, - { 0x0014E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD2FIFOW", "OSD2 FIFO Watermark" }, - { 0x00150, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD2FIFOS", "OSD2 FIFO Size" }, - { 0x00152, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD2FMT" , "OSD2 Format" }, - { 0x00158, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD2BDPL" , "OSD2 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x0015C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD2BDPU" , "OSD2 Buffer Descriptor List Pointer-Upper Base Address" }, - - { 0x00160, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , "OSD3CTL" , "Input Stream Descriptor 0 (OSD3) Control" }, - { 0x00163, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , "OSD3STS" , "OSD3 Status" }, - { 0x00164, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadU32 , hdaRegWriteU32 , "OSD3LPIB" , "OSD3 Link Position In Buffer" }, - { 0x00168, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , "OSD3CBL" , "OSD3 Cyclic Buffer Length" }, - { 0x0016C, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16 , hdaRegWriteSDLVI , "OSD3LVI" , "OSD3 Last Valid Index" }, - { 0x0016E, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16 , hdaRegWriteSDFIFOW , "OSD3FIFOW", "OSD3 FIFO Watermark" }, - { 0x00170, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteSDFIFOS , "OSD3FIFOS", "OSD3 FIFO Size" }, - { 0x00172, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16 , hdaRegWriteSDFMT , "OSD3FMT" , "OSD3 Format" }, - { 0x00178, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteSDBDPL , "OSD3BDPL" , "OSD3 Buffer Descriptor List Pointer-Lower Base Address" }, - { 0x0017C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteSDBDPU , "OSD3BDPU" , "OSD3 Buffer Descriptor List Pointer-Upper Base Address" }, -}; - -static void inline hdaUpdatePosBuf(INTELHDLinkState *pState, PHDASTREAMTRANSFERDESC pStreamDesc) -{ - if (pState->u64DPBase & DPBASE_ENABLED) - PDMDevHlpPhysWrite(ICH6_HDASTATE_2_DEVINS(pState), - (pState->u64DPBase & DPBASE_ADDR_MASK) + pStreamDesc->u8Strm*8, pStreamDesc->pu32Lpib, sizeof(uint32_t)); -} -static uint32_t inline hdaFifoWToSz(INTELHDLinkState *pState, PHDASTREAMTRANSFERDESC pStreamDesc) -{ -#if 0 - switch(HDA_STREAM_REG2(pState, FIFOW, pStreamDesc->u8Strm)) - { - case HDA_SDFIFOW_8B: return 8; - case HDA_SDFIFOW_16B: return 16; - case HDA_SDFIFOW_32B: return 32; - default: - AssertMsgFailed(("hda: unsupported value (%x) in SDFIFOW(,%d)\n", HDA_REG_IND(pState, pStreamDesc->u8Strm), pStreamDesc->u8Strm)); - } -#endif - return 0; -} - -static int hdaProcessInterrupt(INTELHDLinkState* pState) -{ -#define IS_INTERRUPT_OCCURED_AND_ENABLED(pState, num) \ - ( INTCTL_SX((pState), num) \ - && (SDSTS(pState, num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) - bool fIrq = false; - if ( INTCTL_CIE(pState) - && ( RIRBSTS_RINTFL(pState) - || RIRBSTS_RIRBOIS(pState) - || (STATESTS(pState) & WAKEEN(pState)))) - fIrq = true; - - if ( IS_INTERRUPT_OCCURED_AND_ENABLED(pState, 0) - || IS_INTERRUPT_OCCURED_AND_ENABLED(pState, 4)) - fIrq = true; - - if (INTCTL_GIE(pState)) - { - Log(("hda: irq %s\n", fIrq ? "asserted" : "deasserted")); - PDMDevHlpPCISetIrq(ICH6_HDASTATE_2_DEVINS(pState), 0 , fIrq); - } - return VINF_SUCCESS; -} - -static int hdaMMIORegLookup(INTELHDLinkState* pState, uint32_t u32Offset) -{ - int idxMiddle; - int idxHigh = RT_ELEMENTS(s_ichIntelHDRegMap); - int idxLow = 0; - /* Aliases HDA spec 3.3.45 */ - switch(u32Offset) - { - case 0x2084: - return HDA_REG_IND_NAME(SD0LPIB); - case 0x20A4: - return HDA_REG_IND_NAME(SD1LPIB); - case 0x20C4: - return HDA_REG_IND_NAME(SD2LPIB); - case 0x20E4: - return HDA_REG_IND_NAME(SD3LPIB); - case 0x2104: - return HDA_REG_IND_NAME(SD4LPIB); - case 0x2124: - return HDA_REG_IND_NAME(SD5LPIB); - case 0x2144: - return HDA_REG_IND_NAME(SD6LPIB); - case 0x2164: - return HDA_REG_IND_NAME(SD7LPIB); - } - while (1) - { -#ifdef DEBUG_vvl - Assert(( idxHigh >= 0 - && idxLow >= 0)); -#endif - if ( idxHigh < idxLow - || idxHigh < 0) - break; - idxMiddle = idxLow + (idxHigh - idxLow)/2; - if (u32Offset < s_ichIntelHDRegMap[idxMiddle].offset) - { - idxHigh = idxMiddle - 1; - continue; - } - if (u32Offset >= s_ichIntelHDRegMap[idxMiddle].offset + s_ichIntelHDRegMap[idxMiddle].size) - { - idxLow = idxMiddle + 1; - continue; - } - if ( u32Offset >= s_ichIntelHDRegMap[idxMiddle].offset - && u32Offset < s_ichIntelHDRegMap[idxMiddle].offset + s_ichIntelHDRegMap[idxMiddle].size) - return idxMiddle; - } - return -1; -} - -static int hdaCmdSync(INTELHDLinkState *pState, bool fLocal) -{ - int rc = VINF_SUCCESS; - if (fLocal) - { - Assert((HDA_REG_FLAG_VALUE(pState, CORBCTL, DMA))); - rc = PDMDevHlpPhysRead(ICH6_HDASTATE_2_DEVINS(pState), pState->u64CORBBase, pState->pu32CorbBuf, pState->cbCorbBuf); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); -#ifdef DEBUG_CMD_BUFFER - uint8_t i = 0; - do - { - Log(("hda: corb%02x: ", i)); - uint8_t j = 0; - do - { - const char *prefix; - if ((i + j) == CORBRP(pState)) - prefix = "[R]"; - else if ((i + j) == CORBWP(pState)) - prefix = "[W]"; - else - prefix = " "; /* three spaces */ - Log(("%s%08x", prefix, pState->pu32CorbBuf[i + j])); - j++; - } while (j < 8); - Log(("\n")); - i += 8; - } while(i != 0); -#endif - } - else - { - Assert((HDA_REG_FLAG_VALUE(pState, RIRBCTL, DMA))); - rc = PDMDevHlpPhysWrite(ICH6_HDASTATE_2_DEVINS(pState), pState->u64RIRBBase, pState->pu64RirbBuf, pState->cbRirbBuf); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); -#ifdef DEBUG_CMD_BUFFER - uint8_t i = 0; - do { - Log(("hda: rirb%02x: ", i)); - uint8_t j = 0; - do { - const char *prefix; - if ((i + j) == RIRBWP(pState)) - prefix = "[W]"; - else - prefix = " "; - Log((" %s%016lx", prefix, pState->pu64RirbBuf[i + j])); - } while (++j < 8); - Log(("\n")); - i += 8; - } while (i != 0); -#endif - } - return rc; -} - -static int hdaCORBCmdProcess(INTELHDLinkState *pState) -{ - int rc; - uint8_t corbRp; - uint8_t corbWp; - uint8_t rirbWp; - - PFNCODECVERBPROCESSOR pfn = (PFNCODECVERBPROCESSOR)NULL; - - rc = hdaCmdSync(pState, true); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - corbRp = CORBRP(pState); - corbWp = CORBWP(pState); - rirbWp = RIRBWP(pState); - Assert((corbWp != corbRp)); - Log(("hda: CORB(RP:%x, WP:%x) RIRBWP:%x\n", CORBRP(pState), CORBWP(pState), RIRBWP(pState))); - while (corbRp != corbWp) - { - uint32_t cmd; - uint64_t resp; - pfn = (PFNCODECVERBPROCESSOR)NULL; - corbRp++; - cmd = pState->pu32CorbBuf[corbRp]; - rc = (pState)->Codec.pfnLookup(&pState->Codec, cmd, &pfn); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - Assert(pfn); - (rirbWp)++; - - if (RT_LIKELY(pfn)) - rc = pfn(&pState->Codec, cmd, &resp); - else - rc = VERR_INVALID_FUNCTION; - - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - Log(("hda: verb:%08x->%016lx\n", cmd, resp)); - if ( (resp & CODEC_RESPONSE_UNSOLICITED) - && !HDA_REG_FLAG_VALUE(pState, GCTL, UR)) - { - Log(("hda: unexpected unsolicited response.\n")); - pState->au32Regs[ICH6_HDA_REG_CORBRP] = corbRp; - return rc; - } - pState->pu64RirbBuf[rirbWp] = resp; - pState->u8Counter++; - if (pState->u8Counter == RINTCNT_N(pState)) - break; - } - pState->au32Regs[ICH6_HDA_REG_CORBRP] = corbRp; - pState->au32Regs[ICH6_HDA_REG_RIRBWP] = rirbWp; - rc = hdaCmdSync(pState, false); - Log(("hda: CORB(RP:%x, WP:%x) RIRBWP:%x\n", CORBRP(pState), CORBWP(pState), RIRBWP(pState))); - if (RIRBCTL_RIRB_RIC(pState)) - { - RIRBSTS((pState)) |= HDA_REG_FIELD_FLAG_MASK(RIRBSTS,RINTFL); - pState->u8Counter = 0; - rc = hdaProcessInterrupt(pState); - } - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - return rc; -} - -static void hdaStreamReset(INTELHDLinkState *pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, uint8_t u8Strm) -{ - Log(("hda: reset of stream (%d) started\n", u8Strm)); - Assert(( pState - && pBdle - && pStreamDesc - && u8Strm <= 7)); - memset(pBdle, 0, sizeof(HDABDLEDESC)); - *pStreamDesc->pu32Lpib = 0; - *pStreamDesc->pu32Sts = 0; - /* According to ICH6 datasheet, 0x40000 is default value for stream descriptor register 23:20 - * bits are reserved for stream number 18.2.33, resets SDnCTL except SRCT bit */ - HDA_STREAM_REG2(pState, CTL, u8Strm) = 0x40000 | (HDA_STREAM_REG2(pState, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST)); - - /* ICH6 defines default values (0x77 for input and 0xBF for output descriptors) of FIFO size. 18.2.39 */ - HDA_STREAM_REG2(pState, FIFOS, u8Strm) = u8Strm < 4 ? HDA_SDINFIFO_120B : HDA_SDONFIFO_192B; - HDA_STREAM_REG2(pState, FIFOW, u8Strm) = u8Strm < 4 ? HDA_SDFIFOW_8B : HDA_SDFIFOW_32B; - HDA_STREAM_REG2(pState, CBL, u8Strm) = 0; - HDA_STREAM_REG2(pState, LVI, u8Strm) = 0; - HDA_STREAM_REG2(pState, FMT, u8Strm) = 0; - HDA_STREAM_REG2(pState, BDPU, u8Strm) = 0; - HDA_STREAM_REG2(pState, BDPL, u8Strm) = 0; - Log(("hda: reset of stream (%d) finished\n", u8Strm)); -} - - -DECLCALLBACK(int) hdaRegReadUnimplemented(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - *pu32Value = 0; - return VINF_SUCCESS; -} -DECLCALLBACK(int) hdaRegWriteUnimplemented(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - return VINF_SUCCESS; -} -/* U8 */ -DECLCALLBACK(int) hdaRegReadU8(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - Assert(((pState->au32Regs[index] & s_ichIntelHDRegMap[index].readable) & 0xffffff00) == 0); - return hdaRegReadU32(pState, offset, index, pu32Value); -} - -DECLCALLBACK(int) hdaRegWriteU8(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - Assert(((u32Value & 0xffffff00) == 0)); - return hdaRegWriteU32(pState, offset, index, u32Value); -} -/* U16 */ -DECLCALLBACK(int) hdaRegReadU16(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - Assert(((pState->au32Regs[index] & s_ichIntelHDRegMap[index].readable) & 0xffff0000) == 0); - return hdaRegReadU32(pState, offset, index, pu32Value); -} - -DECLCALLBACK(int) hdaRegWriteU16(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - Assert(((u32Value & 0xffff0000) == 0)); - return hdaRegWriteU32(pState, offset, index, u32Value); -} - -/* U24 */ -DECLCALLBACK(int) hdaRegReadU24(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - Assert(((pState->au32Regs[index] & s_ichIntelHDRegMap[index].readable) & 0xff000000) == 0); - return hdaRegReadU32(pState, offset, index, pu32Value); -} - -DECLCALLBACK(int) hdaRegWriteU24(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - Assert(((u32Value & 0xff000000) == 0)); - return hdaRegWriteU32(pState, offset, index, u32Value); -} -/* U32 */ -DECLCALLBACK(int) hdaRegReadU32(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - *pu32Value = pState->au32Regs[index] & s_ichIntelHDRegMap[index].readable; - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegWriteU32(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - pState->au32Regs[index] = (u32Value & s_ichIntelHDRegMap[index].writable) - | (pState->au32Regs[index] & ~s_ichIntelHDRegMap[index].writable); - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegReadGCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - return hdaRegReadU32(pState, offset, index, pu32Value); -} - -DECLCALLBACK(int) hdaRegWriteGCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, RST)) - { - /* exit reset state */ - GCTL(pState) |= HDA_REG_FIELD_FLAG_MASK(GCTL, RST); - pState->fInReset = false; - } - else - { - /* enter reset state*/ - if ( HDA_REG_FLAG_VALUE(pState, CORBCTL, DMA) - || HDA_REG_FLAG_VALUE(pState, RIRBCTL, DMA)) - { - Log(("hda: HDA enters in reset with DMA(RIRB:%s, CORB:%s)\n", - HDA_REG_FLAG_VALUE(pState, CORBCTL, DMA) ? "on" : "off", - HDA_REG_FLAG_VALUE(pState, RIRBCTL, DMA) ? "on" : "off")); - } - hdaReset(ICH6_HDASTATE_2_DEVINS(pState)); - GCTL(pState) &= ~HDA_REG_FIELD_FLAG_MASK(GCTL, RST); - pState->fInReset = true; - } - if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, FSH)) - { - /* Flush: GSTS:1 set, see 6.2.6*/ - GSTS(pState) |= HDA_REG_FIELD_FLAG_MASK(GSTS, FSH); /* set the flush state */ - /* DPLBASE and DPUBASE, should be initialized with initial value (see 6.2.6)*/ - } - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegWriteSTATESTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - uint32_t v = pState->au32Regs[index]; - uint32_t nv = u32Value & ICH6_HDA_STATES_SCSF; - pState->au32Regs[index] &= ~(v & nv); /* write of 1 clears corresponding bit */ - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegReadINTSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - uint32_t v = 0; - if ( RIRBSTS_RIRBOIS(pState) - || RIRBSTS_RINTFL(pState) - || HDA_REG_FLAG_VALUE(pState, CORBSTS, CMEI) - || STATESTS(pState)) - v |= RT_BIT(30); -#define HDA_IS_STREAM_EVENT(pState, stream) \ - ( (SDSTS((pState),stream) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)) \ - || (SDSTS((pState),stream) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)) \ - || (SDSTS((pState),stream) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) -#define MARK_STREAM(pState, stream, v) do {(v) |= HDA_IS_STREAM_EVENT((pState),stream) ? RT_BIT((stream)) : 0;}while(0) - MARK_STREAM(pState, 0, v); - MARK_STREAM(pState, 1, v); - MARK_STREAM(pState, 2, v); - MARK_STREAM(pState, 3, v); - MARK_STREAM(pState, 4, v); - MARK_STREAM(pState, 5, v); - MARK_STREAM(pState, 6, v); - MARK_STREAM(pState, 7, v); - v |= v ? RT_BIT(31) : 0; - *pu32Value = v; - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegReadWALCLK(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */ - *pu32Value = (uint32_t)ASMMultU64ByU32DivByU32(PDMDevHlpTMTimeVirtGetNano(ICH6_HDASTATE_2_DEVINS(pState)) - pState->u64BaseTS, 24, 1000); - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegReadGCAP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - return hdaRegReadU16(pState, offset, index, pu32Value); -} - -DECLCALLBACK(int) hdaRegWriteCORBRP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - if (u32Value & HDA_REG_FIELD_FLAG_MASK(CORBRP, RST)) - CORBRP(pState) = 0; - else - return hdaRegWriteU8(pState, offset, index, u32Value); - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegWriteCORBCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc = hdaRegWriteU8(pState, offset, index, u32Value); - AssertRC(rc); - if ( CORBWP(pState) != CORBRP(pState) - && HDA_REG_FLAG_VALUE(pState, CORBCTL, DMA) != 0) - return hdaCORBCmdProcess(pState); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteCORBSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - uint32_t v = CORBSTS(pState); - CORBSTS(pState) &= ~(v & u32Value); - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegWriteCORBWP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc; - rc = hdaRegWriteU16(pState, offset, index, u32Value); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - if (CORBWP(pState) == CORBRP(pState)) - return VINF_SUCCESS; - if (!HDA_REG_FLAG_VALUE(pState, CORBCTL, DMA)) - return VINF_SUCCESS; - rc = hdaCORBCmdProcess(pState); - return rc; -} - -DECLCALLBACK(int) hdaRegReadSDCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - return hdaRegReadU24(pState, offset, index, pu32Value); -} - -DECLCALLBACK(int) hdaRegWriteSDCTL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - bool fRun = RT_BOOL((u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))); - bool fInRun = RT_BOOL((HDA_REG_IND(pState, index) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))); - bool fReset = RT_BOOL((u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST))); - bool fInReset = RT_BOOL((HDA_REG_IND(pState, index) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST))); - int rc = VINF_SUCCESS; - if (fInReset) - { - /* Assert!!! Guest is resetting HDA's stream, we're expecting guest will mark stream as exit - * from reset - */ - Assert((!fReset)); - Log(("hda: guest initiate exit of stream reset.\n")); - goto done; - } - else if (fReset) - { - /* - * Assert!!! ICH6 datasheet 18.2.33 says that RUN bit should be cleared before initiation of reset. - */ - uint8_t u8Strm = 0; - PHDABDLEDESC pBdle = NULL; - HDASTREAMTRANSFERDESC stStreamDesc; - Assert((!fInRun && !fRun)); - switch (index) - { - case ICH6_HDA_REG_SD0CTL: - u8Strm = 0; - pBdle = &pState->stInBdle; - break; - case ICH6_HDA_REG_SD4CTL: - u8Strm = 4; - pBdle = &pState->stOutBdle; - break; - default: - Log(("hda: changing SRST bit on non-attached stream\n")); - goto done; - } - Log(("hda: guest initiate enter to stream reset.\n")); - hdaInitTransferDescriptor(pState, pBdle, u8Strm, &stStreamDesc); - hdaStreamReset(pState, pBdle, &stStreamDesc, u8Strm); - goto done; - } - - /* we enter here to change DMA states only */ - if ( (fInRun && !fRun) - || (fRun && !fInRun)) - { - Assert((!fReset && !fInReset)); - switch (index) - { - case ICH6_HDA_REG_SD0CTL: - AUD_set_active_in(pState->Codec.SwVoiceIn, fRun); - break; - case ICH6_HDA_REG_SD4CTL: - AUD_set_active_out(pState->Codec.SwVoiceOut, fRun); - break; - default: - Log(("hda: changing RUN bit on non-attached stream\n")); - goto done; - } - } - - done: - rc = hdaRegWriteU24(pState, offset, index, u32Value); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, VINF_SUCCESS); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteSDSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - uint32_t v = HDA_REG_IND(pState, index); - v &= ~(u32Value & v); - HDA_REG_IND(pState, index) = v; - hdaProcessInterrupt(pState); - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegWriteSDLVI(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc = hdaRegWriteU32(pState, offset, index, u32Value); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, VINF_SUCCESS); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteSDFIFOW(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - switch (u32Value) - { - case HDA_SDFIFOW_8B: - case HDA_SDFIFOW_16B: - case HDA_SDFIFOW_32B: - return hdaRegWriteU16(pState, offset, index, u32Value); - default: - Log(("hda: Attempt to store unsupported value(%x) in SDFIFOW\n", u32Value)); - return hdaRegWriteU16(pState, offset, index, HDA_SDFIFOW_32B); - } - return VINF_SUCCESS; -} -/* - * Note this method could be called for changing value on Output Streams only (ICH6 datacheet 18.2.39) - * - */ -DECLCALLBACK(int) hdaRegWriteSDFIFOS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - switch (index) - { - /* SDInFIFOS is RO, n=0-3 */ - case ICH6_HDA_REG_SD0FIFOS: - case ICH6_HDA_REG_SD1FIFOS: - case ICH6_HDA_REG_SD2FIFOS: - case ICH6_HDA_REG_SD3FIFOS: - Log(("hda: Guest tries change value of FIFO size of Input Stream\n")); - return VINF_SUCCESS; - case ICH6_HDA_REG_SD4FIFOS: - case ICH6_HDA_REG_SD5FIFOS: - case ICH6_HDA_REG_SD6FIFOS: - case ICH6_HDA_REG_SD7FIFOS: - switch(u32Value) - { - case HDA_SDONFIFO_16B: - case HDA_SDONFIFO_32B: - case HDA_SDONFIFO_64B: - case HDA_SDONFIFO_128B: - case HDA_SDONFIFO_192B: - return hdaRegWriteU16(pState, offset, index, u32Value); - - case HDA_SDONFIFO_256B: - Log(("hda: 256 bit is unsupported, HDA is switched into 192B mode\n")); - default: - return hdaRegWriteU16(pState, offset, index, HDA_SDONFIFO_192B); - } - return VINF_SUCCESS; - default: - AssertMsgFailed(("Something wierd happens with register lookup routine")); - } - return VINF_SUCCESS; -} - -static void inline hdaSdFmtToAudSettings(uint32_t u32SdFmt, audsettings_t *pAudSetting) -{ - Assert((pAudSetting)); -#define EXTRACT_VALUE(v, mask, shift) ((v & ((mask) << (shift))) >> (shift)) - uint32_t u32Hz = (u32SdFmt & ICH6_HDA_SDFMT_BASE_RATE_SHIFT) ? 44100 : 48000; - uint32_t u32HzMult = 1; - uint32_t u32HzDiv = 1; - switch (EXTRACT_VALUE(u32SdFmt, ICH6_HDA_SDFMT_MULT_MASK, ICH6_HDA_SDFMT_MULT_SHIFT)) - { - case 0: u32HzMult = 1; break; - case 1: u32HzMult = 2; break; - case 2: u32HzMult = 3; break; - case 3: u32HzMult = 4; break; - default: - Log(("hda: unsupported multiplier %x\n", u32SdFmt)); - } - switch (EXTRACT_VALUE(u32SdFmt, ICH6_HDA_SDFMT_DIV_MASK, ICH6_HDA_SDFMT_DIV_SHIFT)) - { - case 0: u32HzDiv = 1; break; - case 1: u32HzDiv = 2; break; - case 2: u32HzDiv = 3; break; - case 3: u32HzDiv = 4; break; - case 4: u32HzDiv = 5; break; - case 5: u32HzDiv = 6; break; - case 6: u32HzDiv = 7; break; - case 7: u32HzDiv = 8; break; - } - pAudSetting->freq = u32Hz * u32HzMult / u32HzDiv; - - switch (EXTRACT_VALUE(u32SdFmt, ICH6_HDA_SDFMT_BITS_MASK, ICH6_HDA_SDFMT_BITS_SHIFT)) - { - case 0: - Log(("hda: %s requested 8 bit\n", __FUNCTION__)); - pAudSetting->fmt = AUD_FMT_S8; - break; - case 1: - Log(("hda: %s requested 16 bit\n", __FUNCTION__)); - pAudSetting->fmt = AUD_FMT_S16; - break; - case 2: - Log(("hda: %s requested 20 bit\n", __FUNCTION__)); - break; - case 3: - Log(("hda: %s requested 24 bit\n", __FUNCTION__)); - break; - case 4: - Log(("hda: %s requested 32 bit\n", __FUNCTION__)); - pAudSetting->fmt = AUD_FMT_S32; - break; - default: - AssertMsgFailed(("Unsupported")); - } - pAudSetting->nchannels = (u32SdFmt & 0xf) + 1; - pAudSetting->fmt = AUD_FMT_S16; - pAudSetting->endianness = 0; -#undef EXTRACT_VALUE -} - -DECLCALLBACK(int) hdaRegWriteSDFMT(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ -#ifdef VBOX_WITH_HDA_CODEC_EMU - /* @todo here some more investigations are required. */ - int rc = 0; - audsettings_t as; - /* no reason to reopen voice with same settings */ - if (u32Value == HDA_REG_IND(pState, index)) - return VINF_SUCCESS; - hdaSdFmtToAudSettings(u32Value, &as); - switch (index) - { - case ICH6_HDA_REG_SD0FMT: - rc = codecOpenVoice(&pState->Codec, PI_INDEX, &as); - break; - case ICH6_HDA_REG_SD4FMT: - rc = codecOpenVoice(&pState->Codec, PO_INDEX, &as); - break; - default: - Log(("HDA: attempt to change format on %d\n", index)); - rc = 0; - } - return hdaRegWriteU16(pState, offset, index, u32Value); -#else - return hdaRegWriteU16(pState, offset, index, u32Value); -#endif -} - -DECLCALLBACK(int) hdaRegWriteSDBDPL(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc = hdaRegWriteU32(pState, offset, index, u32Value); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, VINF_SUCCESS); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteSDBDPU(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc = hdaRegWriteU32(pState, offset, index, u32Value); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, VINF_SUCCESS); - return rc; -} - -DECLCALLBACK(int) hdaRegReadIRS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t *pu32Value) -{ - int rc = VINF_SUCCESS; - /* regarding 3.4.3 we should mark IRS as busy in case CORB is active */ - if ( CORBWP(pState) != CORBRP(pState) - || HDA_REG_FLAG_VALUE(pState, CORBCTL, DMA)) - IRS(pState) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */ - - rc = hdaRegReadU32(pState, offset, index, pu32Value); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteIRS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc = VINF_SUCCESS; - uint64_t resp; - PFNCODECVERBPROCESSOR pfn = (PFNCODECVERBPROCESSOR)NULL; - /* - * if guest set ICB bit of IRS register HDA should process verb in IC register and - * writes response in IR register and set IRV (valid in case of success) bit of IRS register. - */ - if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, ICB) - && !IRS_ICB(pState)) - { - uint32_t cmd = IC(pState); - if (CORBWP(pState) != CORBRP(pState)) - { - /* - * 3.4.3 defines behaviour of immediate Command status register. - */ - LogRel(("hda: guest has tried process immediate verb (%x) with active CORB\n", cmd)); - return rc; - } - IRS(pState) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */ - Log(("hda: IC:%x\n", cmd)); - rc = pState->Codec.pfnLookup(&pState->Codec, cmd, &pfn); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - rc = pfn(&pState->Codec, cmd, &resp); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - IR(pState) = (uint32_t)resp; - Log(("hda: IR:%x\n", IR(pState))); - IRS(pState) = HDA_REG_FIELD_FLAG_MASK(IRS, IRV); /* result is ready */ - IRS(pState) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy is clear */ - return rc; - } - /* - * when guest's read the response it should clean the IRV bit of the IRS register. - */ - if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, IRV) - && IRS_IRV(pState)) - IRS(pState) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, IRV); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteRIRBWP(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - if (u32Value & HDA_REG_FIELD_FLAG_MASK(RIRBWP, RST)) - { - RIRBWP(pState) = 0; - } - /*The rest of bits are O, see 6.2.22 */ - return VINF_SUCCESS; -} - -DECLCALLBACK(int) hdaRegWriteBase(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - int rc = hdaRegWriteU32(pState, offset, index, u32Value); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - switch(index) - { - case ICH6_HDA_REG_CORBLBASE: - pState->u64CORBBase &= 0xFFFFFFFF00000000ULL; - pState->u64CORBBase |= pState->au32Regs[index]; - break; - case ICH6_HDA_REG_CORBUBASE: - pState->u64CORBBase &= 0x00000000FFFFFFFFULL; - pState->u64CORBBase |= ((uint64_t)pState->au32Regs[index] << 32); - break; - case ICH6_HDA_REG_RIRLBASE: - pState->u64RIRBBase &= 0xFFFFFFFF00000000ULL; - pState->u64RIRBBase |= pState->au32Regs[index]; - break; - case ICH6_HDA_REG_RIRUBASE: - pState->u64RIRBBase &= 0x00000000FFFFFFFFULL; - pState->u64RIRBBase |= ((uint64_t)pState->au32Regs[index] << 32); - break; - case ICH6_HDA_REG_DPLBASE: - /* @todo: first bit has special meaning */ - pState->u64DPBase &= 0xFFFFFFFF00000000ULL; - pState->u64DPBase |= pState->au32Regs[index]; - break; - case ICH6_HDA_REG_DPUBASE: - pState->u64DPBase &= 0x00000000FFFFFFFFULL; - pState->u64DPBase |= ((uint64_t)pState->au32Regs[index] << 32); - break; - default: - AssertMsgFailed(("Invalid index")); - } - Log(("hda: CORB base:%llx RIRB base: %llx DP base: %llx\n", pState->u64CORBBase, pState->u64RIRBBase, pState->u64DPBase)); - return rc; -} - -DECLCALLBACK(int) hdaRegWriteRIRBSTS(INTELHDLinkState* pState, uint32_t offset, uint32_t index, uint32_t u32Value) -{ - uint8_t v = RIRBSTS(pState); - RIRBSTS(pState) &= ~(v & u32Value); - - return hdaProcessInterrupt(pState); -} - -#ifdef LOG_ENABLED -static void dump_bd(INTELHDLinkState *pState, PHDABDLEDESC pBdle, uint64_t u64BaseDMA) -{ -#if 0 - uint64_t addr; - uint32_t len; - uint32_t ioc; - uint8_t bdle[16]; - uint32_t counter; - uint32_t i; - uint32_t sum = 0; - Assert(pBdle && pBdle->u32BdleMaxCvi); - for (i = 0; i <= pBdle->u32BdleMaxCvi; ++i) - { - PDMDevHlpPhysRead(ICH6_HDASTATE_2_DEVINS(pState), u64BaseDMA + i*16, bdle, 16); - addr = *(uint64_t *)bdle; - len = *(uint32_t *)&bdle[8]; - ioc = *(uint32_t *)&bdle[12]; - Log(("hda: %s bdle[%d] a:%llx, len:%d, ioc:%d\n", (i == pBdle->u32BdleCvi? "[C]": " "), i, addr, len, ioc & 0x1)); - sum += len; - } - Log(("hda: sum: %d\n", sum)); - for (i = 0; i < 8; ++i) - { - PDMDevHlpPhysRead(ICH6_HDASTATE_2_DEVINS(pState), (pState->u64DPBase & DPBASE_ADDR_MASK) + i*8, &counter, sizeof(&counter)); - Log(("hda: %s stream[%d] counter=%x\n", i == SDCTL_NUM(pState, 4) || i == SDCTL_NUM(pState, 0)? "[C]": " ", - i , counter)); - } -#endif -} -#endif - -static void hdaFetchBdle(INTELHDLinkState *pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc) -{ - uint8_t bdle[16]; - Assert(( pStreamDesc->u64BaseDMA - && pBdle - && pBdle->u32BdleMaxCvi)); - PDMDevHlpPhysRead(ICH6_HDASTATE_2_DEVINS(pState), pStreamDesc->u64BaseDMA + pBdle->u32BdleCvi*16, bdle, 16); - pBdle->u64BdleCviAddr = *(uint64_t *)bdle; - pBdle->u32BdleCviLen = *(uint32_t *)&bdle[8]; - pBdle->fBdleCviIoc = (*(uint32_t *)&bdle[12]) & 0x1; -#ifdef LOG_ENABLED - dump_bd(pState, pBdle, pStreamDesc->u64BaseDMA); -#endif -} - -static inline uint32_t hdaCalculateTransferBufferLength(PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t u32SoundBackendBufferBytesAvail, uint32_t u32CblLimit) -{ - uint32_t cb2Copy; - /* - * Amounts of bytes depends on current position in buffer (u32BdleCviLen-u32BdleCviPos) - */ - Assert((pBdle->u32BdleCviLen >= pBdle->u32BdleCviPos)); /* sanity */ - cb2Copy = pBdle->u32BdleCviLen - pBdle->u32BdleCviPos; - /* - * we may increase the counter in range of [0, FIFOS + 1] - */ - cb2Copy = RT_MIN(cb2Copy, pStreamDesc->u32Fifos + 1); - Assert((u32SoundBackendBufferBytesAvail > 0)); - - /* sanity check to avoid overriding sound backend buffer */ - cb2Copy = RT_MIN(cb2Copy, u32SoundBackendBufferBytesAvail); - cb2Copy = RT_MIN(cb2Copy, u32CblLimit); - - if (cb2Copy <= pBdle->cbUnderFifoW) - return 0; - cb2Copy -= pBdle->cbUnderFifoW; /* forcely reserve amount of ureported bytes to copy */ - return cb2Copy; -} - -DECLINLINE(void) hdaBackendWriteTransferReported(PHDABDLEDESC pBdle, uint32_t cbArranged2Copy, uint32_t cbCopied, uint32_t *pu32DMACursor, uint32_t *pu32BackendBufferCapacity) -{ - Log(("hda:hdaBackendWriteTransferReported: cbArranged2Copy: %d, cbCopied: %d, pu32DMACursor: %d, pu32BackendBufferCapacity:%d\n", - cbArranged2Copy, cbCopied, pu32DMACursor ? *pu32DMACursor : 0, pu32BackendBufferCapacity ? *pu32BackendBufferCapacity : 0)); - Assert((cbCopied)); - Assert((pu32BackendBufferCapacity && *pu32BackendBufferCapacity)); - /* Assertion!!! It was copied less than cbUnderFifoW - * Probably we need to move the buffer, but it rather hard to imagine situation - * why it may happen. - */ - Assert((cbCopied == pBdle->cbUnderFifoW + cbArranged2Copy)); /* we assume that we write whole buffer including not reported bytes */ - if ( pBdle->cbUnderFifoW - && pBdle->cbUnderFifoW <= cbCopied) - Log(("hda:hdaBackendWriteTransferReported: CVI resetting cbUnderFifoW:%d(pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); - - pBdle->cbUnderFifoW -= RT_MIN(pBdle->cbUnderFifoW, cbCopied); - Assert((!pBdle->cbUnderFifoW)); /* Assert!!! Assumption failed */ - - /* We always increment position on DMA buffer counter because we're always reading to intermediate buffer */ - pBdle->u32BdleCviPos += cbArranged2Copy; - - Assert((pBdle->u32BdleCviLen >= pBdle->u32BdleCviPos && *pu32BackendBufferCapacity >= cbCopied)); /* sanity */ - /* We reports all bytes (including unreported previously) */ - *pu32DMACursor += cbCopied; - /* reducing backend counter on amount of bytes we copied to backend */ - *pu32BackendBufferCapacity -= cbCopied; - Log(("hda:hdaBackendWriteTransferReported: CVI(pos:%d, len:%d), pu32DMACursor: %d, pu32BackendBufferCapacity:%d\n", - pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, *pu32DMACursor, *pu32BackendBufferCapacity)); -} - -DECLINLINE(void) hdaBackendReadTransferReported(PHDABDLEDESC pBdle, uint32_t cbArranged2Copy, uint32_t cbCopied, uint32_t *pu32DMACursor, uint32_t *pu32BackendBufferCapacity) -{ - Assert((cbCopied, cbArranged2Copy)); - *pu32BackendBufferCapacity -= cbCopied; - pBdle->u32BdleCviPos += cbCopied; - Log(("hda:hdaBackendReadTransferReported: CVI resetting cbUnderFifoW:%d(pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); - *pu32DMACursor += cbCopied + pBdle->cbUnderFifoW; - pBdle->cbUnderFifoW = 0; - Log(("hda:hdaBackendReadTransferReported: CVI(pos:%d, len:%d), pu32DMACursor: %d, pu32BackendBufferCapacity:%d\n", - pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, pu32DMACursor ? *pu32DMACursor : 0, pu32BackendBufferCapacity ? *pu32BackendBufferCapacity : 0)); -} - -DECLINLINE(void) hdaBackendTransferUnreported(INTELHDLinkState *pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t cbCopied, uint32_t *pu32BackendBufferCapacity) -{ - Log(("hda:hdaBackendTransferUnreported: CVI (cbUnderFifoW:%d, pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); - pBdle->u32BdleCviPos += cbCopied; - pBdle->cbUnderFifoW += cbCopied; - /* In case of read transaction we're always coping from backend buffer */ - if (pu32BackendBufferCapacity) - *pu32BackendBufferCapacity -= cbCopied; - Log(("hda:hdaBackendTransferUnreported: CVI (cbUnderFifoW:%d, pos:%d, len:%d)\n", pBdle->cbUnderFifoW, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); - Assert((pBdle->cbUnderFifoW <= hdaFifoWToSz(pState, pStreamDesc))); -} -static inline bool hdaIsTransferCountersOverlapped(PINTELHDLinkState pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc) -{ - bool fOnBufferEdge = ( *pStreamDesc->pu32Lpib == pStreamDesc->u32Cbl - || pBdle->u32BdleCviPos == pBdle->u32BdleCviLen); - - Assert((*pStreamDesc->pu32Lpib <= pStreamDesc->u32Cbl)); - - if (*pStreamDesc->pu32Lpib == pStreamDesc->u32Cbl) - *pStreamDesc->pu32Lpib -= pStreamDesc->u32Cbl; - hdaUpdatePosBuf(pState, pStreamDesc); - - /* don't touch BdleCvi counter on uninitialized descriptor */ - if ( pBdle->u32BdleCviPos - && pBdle->u32BdleCviPos == pBdle->u32BdleCviLen) - { - pBdle->u32BdleCviPos = 0; - pBdle->u32BdleCvi++; - if (pBdle->u32BdleCvi == pBdle->u32BdleMaxCvi + 1) - pBdle->u32BdleCvi = 0; - } - return fOnBufferEdge; -} - -DECLINLINE(void) hdaStreamCounterUpdate(PINTELHDLinkState pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t cbInc) -{ - /* - * if we're under FIFO Watermark it's expected that HDA doesn't fetch anything. - * (ICH6 datasheet 18.2.38) - */ - if (!pBdle->cbUnderFifoW) - { - *pStreamDesc->pu32Lpib += cbInc; - - /* - * Assert. Overlapping of buffer counter shouldn't happen. - */ - Assert((*pStreamDesc->pu32Lpib <= pStreamDesc->u32Cbl)); - - hdaUpdatePosBuf(pState, pStreamDesc); - - } -} - -static inline bool hdaDoNextTransferCycle(PINTELHDLinkState pState, PHDABDLEDESC pBdle, PHDASTREAMTRANSFERDESC pStreamDesc) -{ - bool fDoNextTransferLoop = true; - if ( pBdle->u32BdleCviPos == pBdle->u32BdleCviLen - || *pStreamDesc->pu32Lpib == pStreamDesc->u32Cbl) - { - if ( !pBdle->cbUnderFifoW - && pBdle->fBdleCviIoc) - { - /* - * @todo - more carefully investigate BCIS flag. - * Speech synthesis works fine on Mac Guest if this bit isn't set - * but in general sound quality becomes lesser. - */ - *pStreamDesc->pu32Sts |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS); - - /* - * we should generate the interrupt if ICE bit of SDCTL register is set. - */ - if (pStreamDesc->u32Ctl & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE)) - hdaProcessInterrupt(pState); - } - fDoNextTransferLoop = false; - } - return fDoNextTransferLoop; -} - -/* - * hdaReadAudio - copies samples from Qemu Sound back-end to DMA. - * Note: this function writes immediately to DMA buffer, but "reports bytes" when all conditions meet (FIFOW) - */ -static uint32_t hdaReadAudio(INTELHDLinkState *pState, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t *pu32Avail, bool *fStop, uint32_t u32CblLimit) -{ - PHDABDLEDESC pBdle = &pState->stInBdle; - uint32_t cbTransfered = 0; - uint32_t cb2Copy = 0; - uint32_t cbBackendCopy = 0; - - Log(("hda:ra: CVI(pos:%d, len:%d)\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); - - cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pu32Avail, u32CblLimit); - if (!cb2Copy) - { - /* if we enter here we can't report "unreported bits" */ - *fStop = true; - goto done; - } - - - /* - * read from backend input line to last ureported position or at the begining. - */ - cbBackendCopy = AUD_read (pState->Codec.SwVoiceIn, pBdle->au8HdaBuffer, cb2Copy); - /* - * write on the HDA DMA - */ - PDMDevHlpPhysWrite(ICH6_HDASTATE_2_DEVINS(pState), pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos, pBdle->au8HdaBuffer, cbBackendCopy); - - /* Don't see reasons why cb2Copy could differ from cbBackendCopy */ - Assert((cbBackendCopy == cb2Copy && (*pu32Avail) >= cb2Copy)); /* sanity */ - - if (pBdle->cbUnderFifoW + cbBackendCopy > hdaFifoWToSz(pState, 0)) - hdaBackendReadTransferReported(pBdle, cb2Copy, cbBackendCopy, &cbTransfered, pu32Avail); - else - { - hdaBackendTransferUnreported(pState, pBdle, pStreamDesc, cbBackendCopy, pu32Avail); - *fStop = true; - } - done: - Assert((cbTransfered <= (SDFIFOS(pState, 0) + 1))); - Log(("hda:ra: CVI(pos:%d, len:%d) cbTransfered: %d\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransfered)); - return cbTransfered; -} - -static uint32_t hdaWriteAudio(INTELHDLinkState *pState, PHDASTREAMTRANSFERDESC pStreamDesc, uint32_t *pu32Avail, bool *fStop, uint32_t u32CblLimit) -{ - PHDABDLEDESC pBdle = &pState->stOutBdle; - uint32_t cbTransfered = 0; - uint32_t cb2Copy = 0; /* local byte counter (on local buffer) */ - uint32_t cbBackendCopy = 0; /* local byte counter, how many bytes copied to backend */ - - Log(("hda:wa: CVI(cvi:%d, pos:%d, len:%d)\n", pBdle->u32BdleCvi, pBdle->u32BdleCviPos, pBdle->u32BdleCviLen)); - - cb2Copy = hdaCalculateTransferBufferLength(pBdle, pStreamDesc, *pu32Avail, u32CblLimit); - - /* - * Copy from DMA to the corresponding hdaBuffer (if there exists some bytes from the previous not reported transfer we write to ''pBdle->cbUnderFifoW'' offset) - */ - if (!cb2Copy) - { - *fStop = true; - goto done; - } - - PDMDevHlpPhysRead(ICH6_HDASTATE_2_DEVINS(pState), pBdle->u64BdleCviAddr + pBdle->u32BdleCviPos, pBdle->au8HdaBuffer + pBdle->cbUnderFifoW, cb2Copy); - /* - * Write to audio backend. we should be sure whether we have enought bytes to copy to Audio backend. - */ - if (cb2Copy + pBdle->cbUnderFifoW >= hdaFifoWToSz(pState, pStreamDesc)) - { - /* - * We feed backend with new portion of fetched samples including not reported. - */ - cbBackendCopy = AUD_write (pState->Codec.SwVoiceOut, pBdle->au8HdaBuffer, cb2Copy + pBdle->cbUnderFifoW); - hdaBackendWriteTransferReported(pBdle, cb2Copy, cbBackendCopy, &cbTransfered, pu32Avail); - } - else - { - /* Not enough bytes to be processed and reported, check luck on next enterence */ - hdaBackendTransferUnreported(pState, pBdle, pStreamDesc, cb2Copy, NULL); - *fStop = true; - } - - done: - Assert((cbTransfered <= (SDFIFOS(pState, 4) + 1))); - Log(("hda:wa: CVI(pos:%d, len:%d, cbTransfered:%d)\n", pBdle->u32BdleCviPos, pBdle->u32BdleCviLen, cbTransfered)); - return cbTransfered; -} - -DECLCALLBACK(int) hdaCodecReset(CODECState *pCodecState) -{ - INTELHDLinkState *pState = (INTELHDLinkState *)pCodecState->pHDAState; - return VINF_SUCCESS; -} - -DECLINLINE(void) hdaInitTransferDescriptor(PINTELHDLinkState pState, PHDABDLEDESC pBdle, uint8_t u8Strm, PHDASTREAMTRANSFERDESC pStreamDesc) -{ - Assert(( pState - && pBdle - && pStreamDesc - && u8Strm <= 7)); - memset(pStreamDesc, 0, sizeof(HDASTREAMTRANSFERDESC)); - pStreamDesc->u8Strm = u8Strm; - pStreamDesc->u32Ctl = HDA_STREAM_REG2(pState, CTL, u8Strm); - pStreamDesc->u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG2(pState, BDPL, u8Strm), - HDA_STREAM_REG2(pState, BDPU, u8Strm)); - pStreamDesc->pu32Lpib = &HDA_STREAM_REG2(pState, LPIB, u8Strm); - pStreamDesc->pu32Sts = &HDA_STREAM_REG2(pState, STS, u8Strm); - pStreamDesc->u32Cbl = HDA_STREAM_REG2(pState, CBL, u8Strm); - pStreamDesc->u32Fifos = HDA_STREAM_REG2(pState, FIFOS, u8Strm); - - pBdle->u32BdleMaxCvi = HDA_STREAM_REG2(pState, LVI, u8Strm); -#ifdef LOG_ENABLED - if ( pBdle - && pBdle->u32BdleMaxCvi) - { - Log(("Initialization of transfer descriptor:\n")); - dump_bd(pState, pBdle, pStreamDesc->u64BaseDMA); - } -#endif -} - -DECLCALLBACK(void) hdaTransfer(CODECState *pCodecState, ENMSOUNDSOURCE src, int avail) -{ - bool fStop = false; - uint8_t u8Strm = 0; - PHDABDLEDESC pBdle = NULL; - INTELHDLinkState *pState = (INTELHDLinkState *)pCodecState->pHDAState; - HDASTREAMTRANSFERDESC stStreamDesc; - uint32_t nBytes; - switch (src) - { - case PO_INDEX: - { - u8Strm = 4; - pBdle = &pState->stOutBdle; - break; - } - case PI_INDEX: - { - u8Strm = 0; - pBdle = &pState->stInBdle; - break; - } - default: - return; - } - hdaInitTransferDescriptor(pState, pBdle, u8Strm, &stStreamDesc); - while( avail && !fStop) - { - Assert ( (stStreamDesc.u32Ctl & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)) - && avail - && stStreamDesc.u64BaseDMA); - - /* Fetch the Buffer Descriptor Entry (BDE). */ - - if (hdaIsTransferCountersOverlapped(pState, pBdle, &stStreamDesc)) - hdaFetchBdle(pState, pBdle, &stStreamDesc); - *stStreamDesc.pu32Sts |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY); - Assert((avail >= 0 && (stStreamDesc.u32Cbl >= (*stStreamDesc.pu32Lpib)))); /* sanity */ - uint32_t u32CblLimit = stStreamDesc.u32Cbl - (*stStreamDesc.pu32Lpib); - Assert((u32CblLimit > hdaFifoWToSz(pState, &stStreamDesc))); - Log(("hda: CBL=%d, LPIB=%d\n", stStreamDesc.u32Cbl, *stStreamDesc.pu32Lpib)); - switch (src) - { - case PO_INDEX: - nBytes = hdaWriteAudio(pState, &stStreamDesc, (uint32_t *)&avail, &fStop, u32CblLimit); - break; - case PI_INDEX: - nBytes = hdaReadAudio(pState, &stStreamDesc, (uint32_t *)&avail, &fStop, u32CblLimit); - break; - default: - nBytes = 0; - fStop = true; - AssertMsgFailed(("Unsupported")); - } - Assert(nBytes <= (stStreamDesc.u32Fifos + 1)); - *stStreamDesc.pu32Sts &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY); - - /* Process end of buffer condition. */ - hdaStreamCounterUpdate(pState, pBdle, &stStreamDesc, nBytes); - fStop = !fStop ? !hdaDoNextTransferCycle(pState, pBdle, &stStreamDesc) : fStop; - } -} - -/** - * Handle register read operation. - * - * Looks up and calls appropriate handler. - * - * @note: while implementation was detected so called "forgotten" or "hole" registers - * which description is missed in RPM, datasheet or spec. - * - * @returns VBox status code. - * - * @param pState The device state structure. - * @param uOffset Register offset in memory-mapped frame. - * @param pv Where to fetch the value. - * @param cb Number of bytes to write. - * @thread EMT - */ -PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) -{ - int rc = VINF_SUCCESS; - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - uint32_t offReg = GCPhysAddr - pThis->hda.addrMMReg; - int idxReg = hdaMMIORegLookup(&pThis->hda, offReg); - if (pThis->hda.fInReset && idxReg != ICH6_HDA_REG_GCTL) - Log(("hda: access to registers except GCTL is blocked while reset\n")); - - if (idxReg == -1) - LogRel(("hda: Invalid read access @0x%x(of bytes:%d)\n", offReg, cb)); - - if (idxReg != -1) - { - /** @todo r=bird: Accesses crossing register boundraries aren't handled - * right from what I can tell? If they are, please explain - * what the rules are. */ - uint32_t mask = 0; - uint32_t shift = (s_ichIntelHDRegMap[idxReg].offset - offReg) % sizeof(uint32_t) * 8; - uint32_t u32Value = 0; - switch(cb) - { - case 1: mask = 0x000000ff; break; - case 2: mask = 0x0000ffff; break; - case 4: - /* 18.2 of ICH6 datasheet defines wideness of the accesses byte, word and double word */ - case 8: - mask = 0xffffffff; - cb = 4; - break; - } -#if 0 - /* cross register access. Mac guest hit this assert doing assumption 4 byte access to 3 byte registers e.g. {I,O}SDnCTL - */ - //Assert((cb <= s_ichIntelHDRegMap[idxReg].size - (offReg - s_ichIntelHDRegMap[idxReg].offset))); - if (cb > s_ichIntelHDRegMap[idxReg].size - (offReg - s_ichIntelHDRegMap[idxReg].offset)) - { - int off = cb - (s_ichIntelHDRegMap[idxReg].size - (offReg - s_ichIntelHDRegMap[idxReg].offset)); - rc = hdaMMIORead(pDevIns, pvUser, GCPhysAddr + cb - off, (char *)pv + cb - off, off); - if (RT_FAILURE(rc)) - AssertRCReturn (rc, rc); - } - //Assert(((offReg - s_ichIntelHDRegMap[idxReg].offset) == 0)); -#endif - mask <<= shift; - rc = s_ichIntelHDRegMap[idxReg].pfnRead(&pThis->hda, offReg, idxReg, &u32Value); - *(uint32_t *)pv |= (u32Value & mask); - Log(("hda: read %s[%x/%x]\n", s_ichIntelHDRegMap[idxReg].abbrev, u32Value, *(uint32_t *)pv)); - return rc; - } - *(uint32_t *)pv = 0xFF; - Log(("hda: hole at %x is accessed for read\n", offReg)); - return rc; -} - -/** - * Handle register write operation. - * - * Looks up and calls appropriate handler. - * - * @returns VBox status code. - * - * @param pState The device state structure. - * @param uOffset Register offset in memory-mapped frame. - * @param pv Where to fetch the value. - * @param cb Number of bytes to write. - * @thread EMT - */ -PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - uint32_t offReg = GCPhysAddr - pThis->hda.addrMMReg; - int idxReg = hdaMMIORegLookup(&pThis->hda, offReg); - int rc = VINF_SUCCESS; - - if (pThis->hda.fInReset && idxReg != ICH6_HDA_REG_GCTL) - Log(("hda: access to registers except GCTL is blocked while reset\n")); - - if ( idxReg == -1 - || cb > 4) - LogRel(("hda: Invalid write access @0x%x(of bytes:%d)\n", offReg, cb)); - - if (idxReg != -1) - { - /** @todo r=bird: This looks like code for handling unalinged register - * accesses. If it isn't then, add a comment explaing what you're - * trying to do here. OTOH, if it is then it has the following - * issues: - * -# You're calculating the wrong new value for the register. - * -# You're not handling cross register accesses. Imagine a - * 4-byte write starting at CORBCTL, or a 8-byte write. - * - * PS! consider dropping the 'offset' argument to pfnWrite/pfnRead as - * nobody seems to be using it and it just add complexity when reading - * the code. - * - */ - uint32_t u32CurValue = pThis->hda.au32Regs[idxReg]; - uint32_t u32NewValue; - uint32_t mask; - switch (cb) - { - case 1: - u32NewValue = *(uint8_t const *)pv; - mask = 0xff; - break; - case 2: - u32NewValue = *(uint16_t const *)pv; - mask = 0xffff; - break; - case 4: - case 8: - /* 18.2 of ICH6 datasheet defines wideness of the accesses byte, word and double word */ - u32NewValue = *(uint32_t const *)pv; - mask = 0xffffffff; - cb = 4; - break; - default: - AssertFailedReturn(VERR_INTERNAL_ERROR_4); /* shall not happen. */ - } - /* cross register access, see corresponding comment in hdaMMIORead */ -#if 0 - if (cb > s_ichIntelHDRegMap[idxReg].size - (offReg - s_ichIntelHDRegMap[idxReg].offset)) - { - int off = cb - (s_ichIntelHDRegMap[idxReg].size - (offReg - s_ichIntelHDRegMap[idxReg].offset)); - rc = hdaMMIOWrite(pDevIns, pvUser, GCPhysAddr + cb - off, (char *)pv + cb - off, off); - if (RT_FAILURE(rc)) - AssertRCReturn (rc, rc); - } -#endif - uint32_t shift = (s_ichIntelHDRegMap[idxReg].offset - offReg) % sizeof(uint32_t) * 8; - mask <<= shift; - u32NewValue <<= shift; - u32NewValue &= mask; - u32NewValue |= (u32CurValue & ~mask); - - rc = s_ichIntelHDRegMap[idxReg].pfnWrite(&pThis->hda, offReg, idxReg, u32NewValue); - Log(("hda: write %s:(%x) %x => %x\n", s_ichIntelHDRegMap[idxReg].abbrev, u32NewValue, - u32CurValue, pThis->hda.au32Regs[idxReg])); - return rc; - } - - Log(("hda: hole at %x is accessed for write\n", offReg)); - return rc; -} - -/** - * Callback function for mapping a PCI I/O region. - * - * @return VBox status code. - * @param pPciDev Pointer to PCI device. - * Use pPciDev->pDevIns to get the device instance. - * @param iRegion The region number. - * @param GCPhysAddress Physical address of the region. - * If iType is PCI_ADDRESS_SPACE_IO, this is an - * I/O port, else it's a physical address. - * This address is *NOT* relative - * to pci_mem_base like earlier! - * @param enmType One of the PCI_ADDRESS_SPACE_* values. - */ -static DECLCALLBACK(int) hdaMap(PPCIDEVICE pPciDev, int iRegion, - RTGCPHYS GCPhysAddress, uint32_t cb, - PCIADDRESSSPACE enmType) -{ - int rc; - PPDMDEVINS pDevIns = pPciDev->pDevIns; - RTIOPORT Port = (RTIOPORT)GCPhysAddress; - PCIINTELHDLinkState *pThis = PCIDEV_2_ICH6_HDASTATE(pPciDev); - - Assert(enmType == PCI_ADDRESS_SPACE_MEM); - rc = PDMDevHlpMMIORegister(pPciDev->pDevIns, GCPhysAddress, cb, NULL /*pvUser*/, - IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU, - hdaMMIOWrite, hdaMMIORead, "ICH6_HDA"); - - if (RT_FAILURE(rc)) - return rc; - - pThis->hda.addrMMReg = GCPhysAddress; - return VINF_SUCCESS; -} - -/** - * Saves a state of the HDA device. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param pSSM The handle to save the state to. - */ -static DECLCALLBACK(int) hdaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - /* Save Codec nodes states */ - codecSaveState(&pThis->hda.Codec, pSSM); - - /* Save MMIO registers */ - AssertCompile(RT_ELEMENTS(pThis->hda.au32Regs) == 112); - SSMR3PutU32(pSSM, RT_ELEMENTS(pThis->hda.au32Regs)); - SSMR3PutMem(pSSM, pThis->hda.au32Regs, sizeof(pThis->hda.au32Regs)); - - /* Save HDA dma counters */ - SSMR3PutStructEx(pSSM, &pThis->hda.stOutBdle, sizeof(pThis->hda.stOutBdle), 0 /*fFlags*/, g_aHdaBDLEDescFields, NULL); - SSMR3PutStructEx(pSSM, &pThis->hda.stMicBdle, sizeof(pThis->hda.stMicBdle), 0 /*fFlags*/, g_aHdaBDLEDescFields, NULL); - SSMR3PutStructEx(pSSM, &pThis->hda.stInBdle, sizeof(pThis->hda.stInBdle), 0 /*fFlags*/, g_aHdaBDLEDescFields, NULL); - return VINF_SUCCESS; -} - -/** - * Loads a saved HDA device state. - * - * @returns VBox status code. - * @param pDevIns The device instance. - * @param pSSM The handle to the saved state. - * @param uVersion The data unit version number. - * @param uPass The data pass. - */ -static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - - Assert(uPass == SSM_PASS_FINAL); NOREF(uPass); - - /* - * Load Codec nodes states. - */ - int rc = codecLoadState(&pThis->hda.Codec, pSSM, uVersion); - if (RT_FAILURE(rc)) - return rc; - - /* - * Load MMIO registers. - */ - uint32_t cRegs; - switch (uVersion) - { - case HDA_SSM_VERSION_1: - /* Starting with r71199, we would save 112 instead of 113 - registers due to some code cleanups. This only affects trunk - builds in the 4.1 development period. */ - cRegs = 113; - if (SSMR3HandleRevision(pSSM) >= 71199) - { - uint32_t uVer = SSMR3HandleVersion(pSSM); - if ( VBOX_FULL_VERSION_GET_MAJOR(uVer) == 4 - && VBOX_FULL_VERSION_GET_MINOR(uVer) == 0 - && VBOX_FULL_VERSION_GET_BUILD(uVer) >= 51) - cRegs = 112; - } - break; - - case HDA_SSM_VERSION_2: - case HDA_SSM_VERSION_3: - cRegs = 112; - AssertCompile(RT_ELEMENTS(pThis->hda.au32Regs) == 112); - break; - - case HDA_SSM_VERSION: - rc = SSMR3GetU32(pSSM, &cRegs); AssertRCReturn(rc, rc); - AssertLogRelMsgReturn(cRegs == RT_ELEMENTS(pThis->hda.au32Regs), - ("cRegs is %d, expected %d\n", cRegs, RT_ELEMENTS(pThis->hda.au32Regs)), - VERR_SSM_DATA_UNIT_FORMAT_CHANGED); - break; - - default: - return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; - } - - if (cRegs >= RT_ELEMENTS(pThis->hda.au32Regs)) - { - SSMR3GetMem(pSSM, pThis->hda.au32Regs, sizeof(pThis->hda.au32Regs)); - SSMR3Skip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->hda.au32Regs))); - } - else - { - RT_ZERO(pThis->hda.au32Regs); - SSMR3GetMem(pSSM, pThis->hda.au32Regs, sizeof(uint32_t) * cRegs); - } - - /* - * Load HDA dma counters. - */ - uint32_t fFlags = uVersion <= HDA_SSM_VERSION_2 ? SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED : 0; - PCSSMFIELD paFields = uVersion <= HDA_SSM_VERSION_2 ? g_aHdaBDLEDescFieldsOld : g_aHdaBDLEDescFields; - SSMR3GetStructEx(pSSM, &pThis->hda.stOutBdle, sizeof(pThis->hda.stOutBdle), fFlags, paFields, NULL); - SSMR3GetStructEx(pSSM, &pThis->hda.stMicBdle, sizeof(pThis->hda.stMicBdle), fFlags, paFields, NULL); - rc = SSMR3GetStructEx(pSSM, &pThis->hda.stInBdle, sizeof(pThis->hda.stInBdle), fFlags, paFields, NULL); - AssertRCReturn(rc, rc); - - /* - * Update stuff after the state changes. - */ - AUD_set_active_in(pThis->hda.Codec.SwVoiceIn, SDCTL(&pThis->hda, 0) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)); - AUD_set_active_out(pThis->hda.Codec.SwVoiceOut, SDCTL(&pThis->hda, 4) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)); - - pThis->hda.u64CORBBase = RT_MAKE_U64(CORBLBASE(&pThis->hda), CORBUBASE(&pThis->hda)); - pThis->hda.u64RIRBBase = RT_MAKE_U64(RIRLBASE(&pThis->hda), RIRUBASE(&pThis->hda)); - pThis->hda.u64DPBase = RT_MAKE_U64(DPLBASE(&pThis->hda), DPUBASE(&pThis->hda)); - return VINF_SUCCESS; -} - -/** - * Reset notification. - * - * @returns VBox status. - * @param pDevIns The device instance data. - * - * @remark The original sources didn't install a reset handler, but it seems to - * make sense to me so we'll do it. - */ -static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - GCAP(&pThis->hda) = HDA_MAKE_GCAP(4,4,0,0,1); /* see 6.2.1 */ - VMIN(&pThis->hda) = 0x00; /* see 6.2.2 */ - VMAJ(&pThis->hda) = 0x01; /* see 6.2.3 */ - VMAJ(&pThis->hda) = 0x01; /* see 6.2.3 */ - OUTPAY(&pThis->hda) = 0x003C; /* see 6.2.4 */ - INPAY(&pThis->hda) = 0x001D; /* see 6.2.5 */ - pThis->hda.au32Regs[ICH6_HDA_REG_CORBSIZE] = 0x42; /* see 6.2.1 */ - pThis->hda.au32Regs[ICH6_HDA_REG_RIRBSIZE] = 0x42; /* see 6.2.1 */ - CORBRP(&pThis->hda) = 0x0; - RIRBWP(&pThis->hda) = 0x0; - - Log(("hda: inter HDA reset.\n")); - pThis->hda.cbCorbBuf = 256 * sizeof(uint32_t); - - if (pThis->hda.pu32CorbBuf) - memset(pThis->hda.pu32CorbBuf, 0, pThis->hda.cbCorbBuf); - else - pThis->hda.pu32CorbBuf = (uint32_t *)RTMemAllocZ(pThis->hda.cbCorbBuf); - - pThis->hda.cbRirbBuf = 256 * sizeof(uint64_t); - if (pThis->hda.pu64RirbBuf) - memset(pThis->hda.pu64RirbBuf, 0, pThis->hda.cbRirbBuf); - else - pThis->hda.pu64RirbBuf = (uint64_t *)RTMemAllocZ(pThis->hda.cbRirbBuf); - - pThis->hda.u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns); - - HDABDLEDESC stEmptyBdle; - for(uint8_t u8Strm = 0; u8Strm < 8; ++u8Strm) - { - HDASTREAMTRANSFERDESC stStreamDesc; - PHDABDLEDESC pBdle = NULL; - if (u8Strm == 0) - pBdle = &pThis->hda.stInBdle; - else if(u8Strm == 4) - pBdle = &pThis->hda.stOutBdle; - else - { - memset(&stEmptyBdle, 0, sizeof(HDABDLEDESC)); - pBdle = &stEmptyBdle; - } - hdaInitTransferDescriptor(&pThis->hda, pBdle, u8Strm, &stStreamDesc); - /* hdaStreamReset prevents changing SRST bit, so we zerro it here forcely. */ - HDA_STREAM_REG2(&pThis->hda, CTL, u8Strm) = 0; - hdaStreamReset(&pThis->hda, pBdle, &stStreamDesc, u8Strm); - } - - /* emulateion of codec "wake up" HDA spec (5.5.1 and 6.5)*/ - STATESTS(&pThis->hda) = 0x1; - - Log(("hda: reset finished\n")); -} - -/** - * @interface_method_impl{PDMIBASE,pfnQueryInterface} - */ -static DECLCALLBACK(void *) hdaQueryInterface (struct PDMIBASE *pInterface, - const char *pszIID) -{ - PCIINTELHDLinkState *pThis = RT_FROM_MEMBER(pInterface, PCIINTELHDLinkState, hda.IBase); - Assert(&pThis->hda.IBase == pInterface); - - PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->hda.IBase); - return NULL; -} - -DECLINLINE(int) hdaLookUpRegisterByName(INTELHDLinkState *pState, const char *pszArgs) -{ - int iReg = 0; - for (; iReg < HDA_NREGS; ++iReg) - if (!RTStrICmp(s_ichIntelHDRegMap[iReg].abbrev, pszArgs)) - return iReg; - return -1; -} -DECLINLINE(void) hdaDbgPrintRegister(INTELHDLinkState *pState, PCDBGFINFOHLP pHlp, int iHdaIndex) -{ - Assert( pState - && iHdaIndex >= 0 - && iHdaIndex < HDA_NREGS); - pHlp->pfnPrintf(pHlp, "hda: %s: 0x%x\n", s_ichIntelHDRegMap[iHdaIndex].abbrev, pState->au32Regs[iHdaIndex]); -} -static DECLCALLBACK(void) hdaDbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - INTELHDLinkState *hda = &pThis->hda; - int iHdaRegisterIndex = hdaLookUpRegisterByName(hda, pszArgs); - if (iHdaRegisterIndex != -1) - hdaDbgPrintRegister(hda, pHlp, iHdaRegisterIndex); - else - for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NREGS; ++iHdaRegisterIndex) - hdaDbgPrintRegister(hda, pHlp, iHdaRegisterIndex); -} - -DECLINLINE(void) hdaDbgPrintStream(INTELHDLinkState *pState, PCDBGFINFOHLP pHlp, int iHdaStrmIndex) -{ - Assert( pState - && iHdaStrmIndex >= 0 - && iHdaStrmIndex < 7); - pHlp->pfnPrintf(pHlp, "Dump of %d Hda Stream:\n", iHdaStrmIndex); - pHlp->pfnPrintf(pHlp, "SD%dCTL: %R[sdctl]\n", iHdaStrmIndex, HDA_STREAM_REG2(pState, CTL, iHdaStrmIndex)); - pHlp->pfnPrintf(pHlp, "SD%dCTS: %R[sdsts]\n", iHdaStrmIndex, HDA_STREAM_REG2(pState, STS, iHdaStrmIndex)); - pHlp->pfnPrintf(pHlp, "SD%dFIFOS: %R[sdfifos]\n", iHdaStrmIndex, HDA_STREAM_REG2(pState, FIFOS, iHdaStrmIndex)); - pHlp->pfnPrintf(pHlp, "SD%dFIFOW: %R[sdfifow]\n", iHdaStrmIndex, HDA_STREAM_REG2(pState, FIFOW, iHdaStrmIndex)); -} - -DECLINLINE(int) hdaLookUpStreamIndex(INTELHDLinkState *pState, const char *pszArgs) -{ - /* todo: add args parsing */ - return -1; -} -static DECLCALLBACK(void) hdaDbgStreamInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - INTELHDLinkState *hda = &pThis->hda; - int iHdaStrmIndex = hdaLookUpStreamIndex(hda, pszArgs); - if (iHdaStrmIndex != -1) - hdaDbgPrintStream(hda, pHlp, iHdaStrmIndex); - else - for(iHdaStrmIndex = 0; iHdaStrmIndex < 7; ++iHdaStrmIndex) - hdaDbgPrintStream(hda, pHlp, iHdaStrmIndex); -} - -/* Codec debugger interface */ -static DECLCALLBACK(void) hdaCodecDbgNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - INTELHDLinkState *hda = &pThis->hda; - if (hda->Codec.pfnCodecDbgListNodes) - hda->Codec.pfnCodecDbgListNodes(&hda->Codec, pHlp, pszArgs); - else - pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback.\n"); -} - -static DECLCALLBACK(void) hdaCodecDbgSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - INTELHDLinkState *hda = &pThis->hda; - if (hda->Codec.pfnCodecDbgSelector) - hda->Codec.pfnCodecDbgSelector(&hda->Codec, pHlp, pszArgs); - else - pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback.\n"); -} - -//#define HDA_AS_PCI_EXPRESS -/* Misc routines */ -static inline bool printHdaIsValid(const char *pszType, const char *pszExpectedFlag) -{ - return (RTStrCmp(pszType, pszExpectedFlag) == 0); -} -static const char *printHdaYesNo(bool fFlag) -{ - return fFlag ? "yes" : "no"; -} -static DECLCALLBACK(size_t) -printHdaStrmCtl(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, - const char *pszType, void const *pvValue, - int cchWidth, int cchPrecision, unsigned fFlags, - void *pvUser) -{ - uint32_t sdCtl = (uint32_t)(uintptr_t)pvValue; - size_t cb = 0; - if (!printHdaIsValid(pszType, "sdctl")) - return cb; - cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, - "SDCTL(raw: %#0x, strm:0x%x, dir:%s, tp:%s strip:%x, deie:%s, ioce:%s, run:%s, srst:%s)", - sdCtl, - ((sdCtl & HDA_REG_FIELD_MASK(SDCTL, NUM)) >> ICH6_HDA_SDCTL_NUM_SHIFT), - printHdaYesNo(RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, DIR))), - printHdaYesNo(RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, TP))), - ((sdCtl & HDA_REG_FIELD_MASK(SDCTL, STRIPE)) >> ICH6_HDA_SDCTL_STRIPE_SHIFT), - printHdaYesNo(RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, DEIE))), - printHdaYesNo(RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))), - printHdaYesNo(RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN))), - printHdaYesNo(RT_BOOL(sdCtl & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST)))); - return cb; -} - -static DECLCALLBACK(size_t) -printHdaStrmFifos(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, - const char *pszType, void const *pvValue, - int cchWidth, int cchPrecision, unsigned fFlags, - void *pvUser) -{ - uint32_t sdFifos = (uint32_t)(uintptr_t)pvValue; - uint32_t u32Bytes = 0; - size_t cb = 0; - if (!printHdaIsValid(pszType, "sdfifos")) - return cb; - switch(sdFifos) - { - case HDA_SDONFIFO_16B: u32Bytes = 16; break; - case HDA_SDONFIFO_32B: u32Bytes = 32; break; - case HDA_SDONFIFO_64B: u32Bytes = 64; break; - case HDA_SDONFIFO_128B: u32Bytes = 128; break; - case HDA_SDONFIFO_192B: u32Bytes = 192; break; - case HDA_SDONFIFO_256B: u32Bytes = 256; break; - case HDA_SDINFIFO_120B: u32Bytes = 120; break; - case HDA_SDINFIFO_160B: u32Bytes = 160; break; - default:; - } - cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, - "SDFIFOS(raw: %#0x, sdfifos:%d B)", - sdFifos, - u32Bytes); - return cb; -} - -static DECLCALLBACK(size_t) -printHdaStrmFifow(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, - const char *pszType, void const *pvValue, - int cchWidth, int cchPrecision, unsigned fFlags, - void *pvUser) -{ - uint32_t sdFifow = (uint32_t)(uintptr_t)pvValue; - uint32_t u32Bytes = 0; - size_t cb = 0; - if (!printHdaIsValid(pszType, "sdfifow")) - return cb; - switch(sdFifow) - { - case HDA_SDFIFOW_8B: u32Bytes = 8; break; - case HDA_SDFIFOW_16B: u32Bytes = 16; break; - case HDA_SDFIFOW_32B: u32Bytes = 32; break; - } - cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, - "SDFIFOW(raw: %#0x, sdfifow:%d B)", - sdFifow, - u32Bytes); - return cb; -} - -static DECLCALLBACK(size_t) -printHdaStrmSts(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput, - const char *pszType, void const *pvValue, - int cchWidth, int cchPrecision, unsigned fFlags, - void *pvUser) -{ - uint32_t sdSts = (uint32_t)(uintptr_t)pvValue; - size_t cb = 0; - if (!printHdaIsValid(pszType, "sdsts")) - return cb; - cb += RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, - "SDSTS(raw: %#0x, fifordy:%s, dese:%s, fifoe:%s, bcis:%s)", - sdSts, - printHdaYesNo(RT_BOOL(sdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY))), - printHdaYesNo(RT_BOOL(sdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE))), - printHdaYesNo(RT_BOOL(sdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE))), - printHdaYesNo(RT_BOOL(sdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))); - return cb; -} -/** - * This routine registers debugger info extensions and custom printf formatters - */ -DECLINLINE(int) hdaInitMisc(PPDMDEVINS pDevIns) -{ - int rc; - PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA info. (hda [register case-insensitive])", hdaDbgInfo); - PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm", "HDA stream info. (hdastrm [stream number])", hdaDbgStreamInfo); - PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaCodecDbgNodes); - PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaCodecDbgSelector); - rc = RTStrFormatTypeRegister("sdctl", printHdaStrmCtl, NULL); - AssertRC(rc); - rc = RTStrFormatTypeRegister("sdsts", printHdaStrmSts, NULL); - AssertRC(rc); - rc = RTStrFormatTypeRegister("sdfifos", printHdaStrmFifos, NULL); - AssertRC(rc); - rc = RTStrFormatTypeRegister("sdfifow", printHdaStrmFifow, NULL); - AssertRC(rc); -#if 0 - rc = RTStrFormatTypeRegister("sdfmt", printHdaStrmFmt, NULL); - AssertRC(rc); -#endif - return rc; -} - -/** - * @interface_method_impl{PDMDEVREG,pfnConstruct} - */ -static DECLCALLBACK(int) hdaConstruct (PPDMDEVINS pDevIns, int iInstance, - PCFGMNODE pCfgHandle) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - INTELHDLinkState *s = &pThis->hda; - int rc; - - Assert(iInstance == 0); - PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); - - /* - * Validations. - */ - if (!CFGMR3AreValuesValid (pCfgHandle, "\0")) - return PDMDEV_SET_ERROR (pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, - N_ ("Invalid configuration for the INTELHD device")); - - // ** @todo r=michaln: This device may need R0/RC enabling, especially if guests - // poll some register(s). - - /* - * Initialize data (most of it anyway). - */ - s->pDevIns = pDevIns; - /* IBase */ - s->IBase.pfnQueryInterface = hdaQueryInterface; - - /* PCI Device (the assertions will be removed later) */ - PCIDevSetVendorId (&pThis->dev, HDA_PCI_VENDOR_ID); /* nVidia */ - PCIDevSetDeviceId (&pThis->dev, HDA_PCI_DEICE_ID); /* HDA */ - - PCIDevSetCommand (&pThis->dev, 0x0000); /* 04 rw,ro - pcicmd. */ - PCIDevSetStatus (&pThis->dev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */ - PCIDevSetRevisionId (&pThis->dev, 0x01); /* 08 ro - rid. */ - PCIDevSetClassProg (&pThis->dev, 0x00); /* 09 ro - pi. */ - PCIDevSetClassSub (&pThis->dev, 0x03); /* 0a ro - scc; 03 == HDA. */ - PCIDevSetClassBase (&pThis->dev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ - PCIDevSetHeaderType (&pThis->dev, 0x00); /* 0e ro - headtyp. */ - PCIDevSetBaseAddress (&pThis->dev, 0, /* 10 rw - MMIO */ - false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000); - PCIDevSetInterruptLine (&pThis->dev, 0x00); /* 3c rw. */ - PCIDevSetInterruptPin (&pThis->dev, 0x01); /* 3d ro - INTA#. */ - -#if defined(HDA_AS_PCI_EXPRESS) - PCIDevSetCapabilityList (&pThis->dev, 0x80); -#elif defined(VBOX_WITH_MSI_DEVICES) - PCIDevSetCapabilityList (&pThis->dev, 0x60); -#else - PCIDevSetCapabilityList (&pThis->dev, 0x50); /* ICH6 datasheet 18.1.16 */ -#endif - - /// @todo r=michaln: If there are really no PCIDevSetXx for these, the meaning - // of these values needs to be properly documented! - /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */ - PCIDevSetByte(&pThis->dev, 0x40, 0x01); - - /* Power Management */ - PCIDevSetByte(&pThis->dev, 0x50 + 0, VBOX_PCI_CAP_ID_PM); - PCIDevSetByte(&pThis->dev, 0x50 + 1, 0x0); /* next */ - PCIDevSetWord(&pThis->dev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ ); - -#ifdef HDA_AS_PCI_EXPRESS - /* PCI Express */ - PCIDevSetByte (&pThis->dev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */ - PCIDevSetByte (&pThis->dev, 0x80 + 1, 0x60); /* next */ - /* Device flags */ - PCIDevSetWord (&pThis->dev, 0x80 + 2, - /* version */ 0x1 | - /* Root Complex Integrated Endpoint */ (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) | - /* MSI */ (100) << 9 - ); - /* Device capabilities */ - PCIDevSetDWord (&pThis->dev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET); - /* Device control */ - PCIDevSetWord (&pThis->dev, 0x80 + 8, 0); - /* Device status */ - PCIDevSetWord (&pThis->dev, 0x80 + 10, 0); - /* Link caps */ - PCIDevSetDWord (&pThis->dev, 0x80 + 12, 0); - /* Link control */ - PCIDevSetWord (&pThis->dev, 0x80 + 16, 0); - /* Link status */ - PCIDevSetWord (&pThis->dev, 0x80 + 18, 0); - /* Slot capabilities */ - PCIDevSetDWord (&pThis->dev, 0x80 + 20, 0); - /* Slot control */ - PCIDevSetWord (&pThis->dev, 0x80 + 24, 0); - /* Slot status */ - PCIDevSetWord (&pThis->dev, 0x80 + 26, 0); - /* Root control */ - PCIDevSetWord (&pThis->dev, 0x80 + 28, 0); - /* Root capabilities */ - PCIDevSetWord (&pThis->dev, 0x80 + 30, 0); - /* Root status */ - PCIDevSetDWord (&pThis->dev, 0x80 + 32, 0); - /* Device capabilities 2 */ - PCIDevSetDWord (&pThis->dev, 0x80 + 36, 0); - /* Device control 2 */ - PCIDevSetQWord (&pThis->dev, 0x80 + 40, 0); - /* Link control 2 */ - PCIDevSetQWord (&pThis->dev, 0x80 + 48, 0); - /* Slot control 2 */ - PCIDevSetWord (&pThis->dev, 0x80 + 56, 0); -#endif - - /* - * Register the PCI device. - */ - rc = PDMDevHlpPCIRegister (pDevIns, &pThis->dev); - if (RT_FAILURE (rc)) - return rc; - - rc = PDMDevHlpPCIIORegionRegister (pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, - hdaMap); - if (RT_FAILURE (rc)) - return rc; - -#ifdef VBOX_WITH_MSI_DEVICES - PDMMSIREG aMsiReg; - - RT_ZERO(aMsiReg); - aMsiReg.cMsiVectors = 1; - aMsiReg.iMsiCapOffset = 0x60; - aMsiReg.iMsiNextOffset = 0x50; - rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg); - if (RT_FAILURE (rc)) - { - LogRel(("Chipset cannot do MSI: %Rrc\n", rc)); - PCIDevSetCapabilityList (&pThis->dev, 0x50); - } -#endif - - rc = PDMDevHlpSSMRegister (pDevIns, HDA_SSM_VERSION, sizeof(*pThis), hdaSaveExec, hdaLoadExec); - if (RT_FAILURE (rc)) - return rc; - - /* - * Attach driver. - */ - rc = PDMDevHlpDriverAttach (pDevIns, 0, &s->IBase, - &s->pDrvBase, "Audio Driver Port"); - if (rc == VERR_PDM_NO_ATTACHED_DRIVER) - Log (("hda: No attached driver!\n")); - else if (RT_FAILURE (rc)) - { - AssertMsgFailed (("Failed to attach INTELHD LUN #0! rc=%Rrc\n", rc)); - return rc; - } - - - - pThis->hda.Codec.pHDAState = (void *)&pThis->hda; - rc = codecConstruct(pDevIns, &pThis->hda.Codec, pCfgHandle); - if (RT_FAILURE(rc)) - AssertRCReturn(rc, rc); - - /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for - verb F20 should provide device/codec recognition. */ - Assert(pThis->hda.Codec.u16VendorId); - Assert(pThis->hda.Codec.u16DeviceId); - PCIDevSetSubSystemVendorId (&pThis->dev, pThis->hda.Codec.u16VendorId); /* 2c ro - intel.) */ - PCIDevSetSubSystemId (&pThis->dev, pThis->hda.Codec.u16DeviceId); /* 2e ro. */ - - hdaReset (pDevIns); - pThis->hda.Codec.id = 0; - pThis->hda.Codec.pfnTransfer = hdaTransfer; - pThis->hda.Codec.pfnReset = hdaCodecReset; - /* - * 18.2.6,7 defines that values of this registers might be cleared on power on/reset - * hdaReset shouldn't affects these registers. - */ - WAKEEN(&pThis->hda) = 0x0; - STATESTS(&pThis->hda) = 0x0; - hdaInitMisc(pDevIns); - - return VINF_SUCCESS; -} - -/** - * @interface_method_impl{PDMDEVREG,pfnDestruct} - */ -static DECLCALLBACK(int) hdaDestruct (PPDMDEVINS pDevIns) -{ - PCIINTELHDLinkState *pThis = PDMINS_2_DATA(pDevIns, PCIINTELHDLinkState *); - - int rc = codecDestruct(&pThis->hda.Codec); - AssertRC(rc); - if (pThis->hda.pu32CorbBuf) - RTMemFree(pThis->hda.pu32CorbBuf); - if (pThis->hda.pu64RirbBuf) - RTMemFree(pThis->hda.pu64RirbBuf); - return VINF_SUCCESS; -} - -/** - * The device registration structure. - */ -const PDMDEVREG g_DeviceICH6_HDA = -{ - /* u32Version */ - PDM_DEVREG_VERSION, - /* szName */ - "hda", - /* szRCMod */ - "", - /* szR0Mod */ - "", - /* pszDescription */ - "ICH IntelHD Audio Controller", - /* fFlags */ - PDM_DEVREG_FLAGS_DEFAULT_BITS, - /* fClass */ - PDM_DEVREG_CLASS_AUDIO, - /* cMaxInstances */ - 1, - /* cbInstance */ - sizeof(PCIINTELHDLinkState), - /* pfnConstruct */ - hdaConstruct, - /* pfnDestruct */ - hdaDestruct, - /* pfnRelocate */ - NULL, - /* pfnIOCtl */ - NULL, - /* pfnPowerOn */ - NULL, - /* pfnReset */ - hdaReset, - /* pfnSuspend */ - NULL, - /* pfnResume */ - NULL, - /* pfnAttach */ - NULL, - /* pfnDetach */ - NULL, - /* pfnQueryInterface. */ - NULL, - /* pfnInitComplete */ - NULL, - /* pfnPowerOff */ - NULL, - /* pfnSoftReset */ - NULL, - /* u32VersionEnd */ - PDM_DEVREG_VERSION -}; diff --git a/src/VBox/Devices/Audio/DevSB16.cpp b/src/VBox/Devices/Audio/DevSB16.cpp index 00345f16..d0570f05 100644 --- a/src/VBox/Devices/Audio/DevSB16.cpp +++ b/src/VBox/Devices/Audio/DevSB16.cpp @@ -1989,7 +1989,7 @@ const PDMDEVREG g_DeviceSB16 = NULL, /* pfnRelocate */ NULL, - /* pfnIOCtl */ + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, diff --git a/src/VBox/Devices/Audio/alsa_mangling.h b/src/VBox/Devices/Audio/alsa_mangling.h new file mode 100644 index 00000000..647721f4 --- /dev/null +++ b/src/VBox/Devices/Audio/alsa_mangling.h @@ -0,0 +1,55 @@ +/** @file + * + * Mangle libasound symbols. This is necessary on hosts which don't + * support the -fvisibility gcc switch. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef AUDIO_ALSA_MANGLING_H +#define AUDIO_ALSA_MANGLING_H + +#define ALSA_MANGLER(symbol) VBox_##symbol + +#define snd_pcm_hw_params_any ALSA_MANGLER(snd_pcm_hw_params_any) +#define snd_pcm_close ALSA_MANGLER(snd_pcm_close) +#define snd_pcm_avail_update ALSA_MANGLER(snd_pcm_avail_update) +#define snd_pcm_hw_params_set_channels_near ALSA_MANGLER(snd_pcm_hw_params_set_channels_near) +#define snd_pcm_hw_params_set_period_time_near ALSA_MANGLER(snd_pcm_hw_params_set_period_time_near) +#define snd_pcm_prepare ALSA_MANGLER(snd_pcm_prepare) +#define snd_pcm_sw_params_sizeof ALSA_MANGLER(snd_pcm_sw_params_sizeof) +#define snd_pcm_hw_params_set_period_size_near ALSA_MANGLER(snd_pcm_hw_params_set_period_size_near) +#define snd_pcm_hw_params_get_period_size ALSA_MANGLER(snd_pcm_hw_params_get_period_size) +#define snd_pcm_hw_params ALSA_MANGLER(snd_pcm_hw_params) +#define snd_pcm_hw_params_sizeof ALSA_MANGLER(snd_pcm_hw_params_sizeof) +#define snd_pcm_state ALSA_MANGLER(snd_pcm_state) +#define snd_pcm_open ALSA_MANGLER(snd_pcm_open) +#define snd_lib_error_set_handler ALSA_MANGLER(snd_lib_error_set_handler) +#define snd_pcm_sw_params ALSA_MANGLER(snd_pcm_sw_params) +#define snd_pcm_hw_params_get_period_size_min ALSA_MANGLER(snd_pcm_hw_params_get_period_size_min) +#define snd_pcm_writei ALSA_MANGLER(snd_pcm_writei) +#define snd_pcm_readi ALSA_MANGLER(snd_pcm_readi) +#define snd_strerror ALSA_MANGLER(snd_strerror) +#define snd_pcm_drop ALSA_MANGLER(snd_pcm_drop) +#define snd_pcm_resume ALSA_MANGLER(snd_pcm_resume) +#define snd_pcm_hw_params_get_buffer_size ALSA_MANGLER(snd_pcm_hw_params_get_buffer_size) +#define snd_pcm_hw_params_set_rate_near ALSA_MANGLER(snd_pcm_hw_params_set_rate_near) +#define snd_pcm_hw_params_set_access ALSA_MANGLER(snd_pcm_hw_params_set_access) +#define snd_pcm_hw_params_set_buffer_time_near ALSA_MANGLER(snd_pcm_hw_params_set_buffer_time_near) +#define snd_pcm_hw_params_set_buffer_size_near ALSA_MANGLER(snd_pcm_hw_params_set_buffer_size_near) +#define snd_pcm_hw_params_get_buffer_size_min ALSA_MANGLER(snd_pcm_hw_params_get_buffer_size_min) +#define snd_pcm_hw_params_set_format ALSA_MANGLER(snd_pcm_hw_params_set_format) +#define snd_pcm_sw_params_current ALSA_MANGLER(snd_pcm_sw_params_current) +#define snd_pcm_sw_params_set_start_threshold ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold) + +#endif /* !AUDIO_ALSA_MANGLING_H */ diff --git a/src/VBox/Devices/Audio/alsa_stubs.c b/src/VBox/Devices/Audio/alsa_stubs.c index 4428d890..b2928bf7 100644 --- a/src/VBox/Devices/Audio/alsa_stubs.c +++ b/src/VBox/Devices/Audio/alsa_stubs.c @@ -30,7 +30,8 @@ #define PROXY_STUB(function, rettype, signature, shortsig) \ static rettype (*pfn_ ## function) signature; \ \ - rettype function signature \ + rettype VBox_##function signature; \ + rettype VBox_##function signature \ { \ return pfn_ ## function shortsig; \ } diff --git a/src/VBox/Devices/Audio/alsa_stubs.h b/src/VBox/Devices/Audio/alsa_stubs.h index 7baf1b37..bfb650ad 100644 --- a/src/VBox/Devices/Audio/alsa_stubs.h +++ b/src/VBox/Devices/Audio/alsa_stubs.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Devices/Audio/alsaaudio.c b/src/VBox/Devices/Audio/alsaaudio.c index 913d400b..92db38f0 100644 --- a/src/VBox/Devices/Audio/alsaaudio.c +++ b/src/VBox/Devices/Audio/alsaaudio.c @@ -29,14 +29,16 @@ #include <VBox/log.h> #endif +#ifdef VBOX +# include "alsa_stubs.h" +# include "alsa_mangling.h" +#endif + #include <alsa/asoundlib.h> #include "VBoxDD.h" #include "vl_vbox.h" #include "audio.h" -#ifdef VBOX -#include "alsa_stubs.h" -#endif #include <iprt/alloc.h> #define AUDIO_CAP "alsa" diff --git a/src/VBox/Devices/Audio/audio.c b/src/VBox/Devices/Audio/audio.c index 4720c7da..784d84ba 100644 --- a/src/VBox/Devices/Audio/audio.c +++ b/src/VBox/Devices/Audio/audio.c @@ -472,7 +472,7 @@ static void audio_process_options (PCFGMNODE pCfgHandle, const char *prefix, */ if(pCfgHandle != NULL) { /* If its audio general setting, need to traverse to one child node. - * /Devices/ihac97/0/LUN#0/Config/Audio + * /Devices/ichac97/0/LUN#0/Config/Audio */ if(!strncmp(prefix, "AUDIO", 5)) { pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle); @@ -484,7 +484,7 @@ static void audio_process_options (PCFGMNODE pCfgHandle, const char *prefix, { /* If its driver specific configuration , then need to traverse two level deep child * child nodes. for eg. in case of DirectSoundConfiguration item - * /Devices/ihac97/0/LUN#0/Config/Audio/DirectSoundConfig + * /Devices/ichac97/0/LUN#0/Config/Audio/DirectSoundConfig */ pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle); if (pCfgChildHandle) { @@ -1562,7 +1562,7 @@ static struct audio_option audio_options[] = { "Number of voices for ADC", NULL, 0}, /* Misc */ - {"TimreFreq", AUD_OPT_INT, &conf.period.hz, + {"TimerFreq", AUD_OPT_INT, &conf.period.hz, "Timer frequency in Hz (0 - use lowest possible)", NULL, 0}, {"PLIVE", AUD_OPT_BOOL, &conf.plive, diff --git a/src/VBox/Devices/Audio/audiosniffer.c b/src/VBox/Devices/Audio/audiosniffer.c index 7cff38cd..9f9bc318 100644 --- a/src/VBox/Devices/Audio/audiosniffer.c +++ b/src/VBox/Devices/Audio/audiosniffer.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2010 Oracle Corporation + * Copyright (C) 2006-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -653,7 +653,7 @@ const PDMDEVREG g_DeviceAudioSniffer = audioSnifferR3Destruct, /* pfnRelocate */ NULL, - /* pfnIOCtl */ + /* pfnMemSetup */ NULL, /* pfnPowerOn */ NULL, diff --git a/src/VBox/Devices/Audio/coreaudio.c b/src/VBox/Devices/Audio/coreaudio.c index 5b945210..ef9c7bdd 100644 --- a/src/VBox/Devices/Audio/coreaudio.c +++ b/src/VBox/Devices/Audio/coreaudio.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Devices/Audio/dsoundaudio.c b/src/VBox/Devices/Audio/dsoundaudio.c index eb6bea91..7f73058a 100644 --- a/src/VBox/Devices/Audio/dsoundaudio.c +++ b/src/VBox/Devices/Audio/dsoundaudio.c @@ -36,6 +36,7 @@ #include "vl_vbox.h" #include "audio.h" #include <iprt/alloc.h> +#include <iprt/uuid.h> #include <VBox/log.h> @@ -53,6 +54,8 @@ static struct { int bufsize_out; audsettings_t settings; int latency_millis; + char *device_guid_out; + char *device_guid_in; } conf = { 1, 1, @@ -65,7 +68,9 @@ static struct { 2, AUD_FMT_S16 }, - 10 + 10, + NULL, + NULL }; typedef struct { @@ -1016,6 +1021,8 @@ static void *dsound_audio_init (void) int err; HRESULT hr; dsound *s = &glob_dsound; + RTUUID devguid; + LPCGUID devguidp; hr = CoInitializeEx (NULL, COINIT_MULTITHREADED); if (FAILED (hr)) { @@ -1046,7 +1053,16 @@ static void *dsound_audio_init (void) return NULL; } - hr = IDirectSound_Initialize (s->dsound, NULL); + if (conf.device_guid_out) { + hr = RTUuidFromStr(&devguid, conf.device_guid_out); + if (FAILED (hr)) { + LogRel(("DSound: Could not parse DirectSound output device GUID\n")); + } + devguidp = (LPCGUID)&devguid; + } else { + devguidp = NULL; + } + hr = IDirectSound_Initialize (s->dsound, devguidp); if (FAILED (hr)) { #ifndef VBOX dsound_logerr (hr, "Could not initialize DirectSound\n"); @@ -1080,7 +1096,16 @@ static void *dsound_audio_init (void) #endif } else { - hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); + if (conf.device_guid_in) { + hr = RTUuidFromStr(&devguid, conf.device_guid_in); + if (FAILED (hr)) { + LogRel(("DSound: Could not parse DirectSound input device GUID\n")); + } + devguidp = (LPCGUID)&devguid; + } else { + devguidp = NULL; + } + hr = IDirectSoundCapture_Initialize (s->dsound_capture, devguidp); if (FAILED (hr)) { #ifndef VBOX dsound_logerr (hr, "Could not initialize DirectSoundCapture\n"); @@ -1128,6 +1153,10 @@ static struct audio_option dsound_options[] = { "(undocumented)", NULL, 0}, {"BufsizeIn", AUD_OPT_INT, &conf.bufsize_in, "(undocumented)", NULL, 0}, + {"DeviceGuidOut", AUD_OPT_STR, &conf.device_guid_out, + "DirectSound output device GUID", NULL, 0}, + {"DeviceGuidIn", AUD_OPT_STR, &conf.device_guid_in, + "DirectSound input device GUID", NULL, 0}, {NULL, 0, NULL, NULL, NULL, 0} }; diff --git a/src/VBox/Devices/Audio/filteraudio.c b/src/VBox/Devices/Audio/filteraudio.c index fe64e48c..9c3a2e3f 100644 --- a/src/VBox/Devices/Audio/filteraudio.c +++ b/src/VBox/Devices/Audio/filteraudio.c @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2010 Oracle Corporation + * Copyright (C) 2010-2011 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Devices/Audio/pulse_mangling.h b/src/VBox/Devices/Audio/pulse_mangling.h new file mode 100644 index 00000000..57ba2ed4 --- /dev/null +++ b/src/VBox/Devices/Audio/pulse_mangling.h @@ -0,0 +1,69 @@ +/** @file + * + * Mangle libpulse symbols. This is necessary on hosts which don't + * support the -fvisibility gcc switch. + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef AUDIO_PULSE_MANGLING_H +#define AUDIO_PULSE_MANGLING_H + +#define PULSE_MANGLER(symbol) VBox_##symbol + +#define pa_stream_connect_playback PULSE_MANGLER(pa_stream_connect_playback) +#define pa_stream_connect_record PULSE_MANGLER(pa_stream_connect_record) +#define pa_stream_disconnect PULSE_MANGLER(pa_stream_disconnect) +#define pa_stream_get_sample_spec PULSE_MANGLER(pa_stream_get_sample_spec) +#define pa_stream_set_latency_update_callback PULSE_MANGLER(pa_stream_set_latency_update_callback) +#define pa_stream_write PULSE_MANGLER(pa_stream_write) +#define pa_stream_unref PULSE_MANGLER(pa_stream_unref) +#define pa_stream_get_state PULSE_MANGLER(pa_stream_get_state) +#define pa_stream_set_state_callback PULSE_MANGLER(pa_stream_set_state_callback) +#define pa_stream_flush PULSE_MANGLER(pa_stream_flush) +#define pa_stream_drain PULSE_MANGLER(pa_stream_drain) +#define pa_stream_trigger PULSE_MANGLER(pa_stream_trigger) +#define pa_stream_new PULSE_MANGLER(pa_stream_new) +#define pa_stream_get_buffer_attr PULSE_MANGLER(pa_stream_get_buffer_attr) +#define pa_stream_peek PULSE_MANGLER(pa_stream_peek) +#define pa_stream_cork PULSE_MANGLER(pa_stream_cork) +#define pa_stream_drop PULSE_MANGLER(pa_stream_drop) +#define pa_stream_writable_size PULSE_MANGLER(pa_stream_writable_size) +#define pa_context_connect PULSE_MANGLER(pa_context_connect) +#define pa_context_disconnect PULSE_MANGLER(pa_context_disconnect) +#define pa_context_get_state PULSE_MANGLER(pa_context_get_state) +#define pa_context_unref PULSE_MANGLER(pa_context_unref) +#define pa_context_errno PULSE_MANGLER(pa_context_errno) +#define pa_context_new PULSE_MANGLER(pa_context_new) +#define pa_context_set_state_callback PULSE_MANGLER(pa_context_set_state_callback) +#define pa_threaded_mainloop_stop PULSE_MANGLER(pa_threaded_mainloop_stop) +#define pa_threaded_mainloop_get_api PULSE_MANGLER(pa_threaded_mainloop_get_api) +#define pa_threaded_mainloop_free PULSE_MANGLER(pa_threaded_mainloop_free) +#define pa_threaded_mainloop_signal PULSE_MANGLER(pa_threaded_mainloop_signal) +#define pa_threaded_mainloop_unlock PULSE_MANGLER(pa_threaded_mainloop_unlock) +#define pa_threaded_mainloop_new PULSE_MANGLER(pa_threaded_mainloop_new) +#define pa_threaded_mainloop_wait PULSE_MANGLER(pa_threaded_mainloop_wait) +#define pa_threaded_mainloop_start PULSE_MANGLER(pa_threaded_mainloop_start) +#define pa_threaded_mainloop_lock PULSE_MANGLER(pa_threaded_mainloop_lock) +#define pa_bytes_per_second PULSE_MANGLER(pa_bytes_per_second) +#define pa_frame_size PULSE_MANGLER(pa_frame_size) +#define pa_sample_format_to_string PULSE_MANGLER(pa_sample_format_to_string) +#define pa_sample_spec_valid PULSE_MANGLER(pa_sample_spec_valid) +#define pa_channel_map_init_auto PULSE_MANGLER(pa_channel_map_init_auto) +#define pa_operation_unref PULSE_MANGLER(pa_operation_unref) +#define pa_operation_get_state PULSE_MANGLER(pa_operation_get_state) +#define pa_operation_cancel PULSE_MANGLER(pa_operation_cancel) +#define pa_strerror PULSE_MANGLER(pa_strerror) +#define pa_stream_readable_size PULSE_MANGLER(pa_stream_readable_size) + +#endif /* !AUDIO_PULSE_MANGLING_H */ diff --git a/src/VBox/Devices/Audio/pulse_stubs.c b/src/VBox/Devices/Audio/pulse_stubs.c index 4fdb2bdc..028f1900 100644 --- a/src/VBox/Devices/Audio/pulse_stubs.c +++ b/src/VBox/Devices/Audio/pulse_stubs.c @@ -30,7 +30,8 @@ #define PROXY_STUB(function, rettype, signature, shortsig) \ static rettype (*g_pfn_ ## function) signature; \ \ - rettype function signature \ + rettype VBox_##function signature; \ + rettype VBox_##function signature \ { \ return g_pfn_ ## function shortsig; \ } @@ -38,7 +39,8 @@ #define PROXY_STUB_VOID(function, signature, shortsig) \ static void (*g_pfn_ ## function) signature; \ \ - void function signature \ + void VBox_##function signature; \ + void VBox_##function signature \ { \ g_pfn_ ## function shortsig; \ } diff --git a/src/VBox/Devices/Audio/pulse_stubs.h b/src/VBox/Devices/Audio/pulse_stubs.h index 83b16ae0..8262ed89 100644 --- a/src/VBox/Devices/Audio/pulse_stubs.h +++ b/src/VBox/Devices/Audio/pulse_stubs.h @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/Devices/Audio/pulseaudio.c b/src/VBox/Devices/Audio/pulseaudio.c index eb70fadd..af78018c 100644 --- a/src/VBox/Devices/Audio/pulseaudio.c +++ b/src/VBox/Devices/Audio/pulseaudio.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -23,8 +23,9 @@ #include <VBox/log.h> #include <iprt/mem.h> -#include <pulse/pulseaudio.h> +#include "pulse_mangling.h" #include "pulse_stubs.h" +#include <pulse/pulseaudio.h> #include "vl_vbox.h" #include "audio.h" diff --git a/src/VBox/Devices/Audio/solaudio.c b/src/VBox/Devices/Audio/solaudio.c index ef8b7763..6998eead 100644 --- a/src/VBox/Devices/Audio/solaudio.c +++ b/src/VBox/Devices/Audio/solaudio.c @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -139,7 +139,7 @@ static char *solaudio_getdevice (void) * This is for multiple audio devices where env. var determines current one, * otherwise else we fallback to default. */ - const char *pszAudioDev = RTEnvDupEx(RTENV_DEFAULT, "AUDIODEV"); + char *pszAudioDev = RTEnvDupEx(RTENV_DEFAULT, "AUDIODEV"); if (!pszAudioDev) pszAudioDev = RTStrDup("/dev/audio"); return pszAudioDev; @@ -407,7 +407,8 @@ static int solaudio_run_out (HWVoiceOut *hw) { solaudioVoiceOut *pSol = (solaudioVoiceOut *) hw; int csLive, csDecr, csSamples, csToWrite, csAvail; - size_t cbAvail, cbToWrite, cbWritten; + size_t cbAvail, cbToWrite; + ssize_t cbWritten; uint8_t *pu8Dst; st_sample_t *psSrc; diff --git a/src/VBox/Devices/Audio/winaudio.c b/src/VBox/Devices/Audio/winaudio.c index 5d0532d1..9cf226e5 100644 --- a/src/VBox/Devices/Audio/winaudio.c +++ b/src/VBox/Devices/Audio/winaudio.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; |
