DevIchAc97.cpp revision 448f902e0dfb52e3e7b99e632203b14be8e46646
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** @file
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * VBox ICH AC97 Audio Controller
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Copyright (C) 2006-2007 innotek GmbH
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * available from http://www.virtualbox.org. This file is free software;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * General Public License as published by the Free Software Foundation,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync * If you received this file as part of a commercial VirtualBox
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * distribution, then only the terms of your commercial VirtualBox
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * license agreement apply instead of the previous paragraph.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync/*******************************************************************************
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync* Header Files *
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define LOG_GROUP LOG_GROUP_DEV_AUDIO
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include <VBox/pdm.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/err.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync#include <VBox/log.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <iprt/assert.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <iprt/uuid.h>
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include <iprt/string.h>
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#include <VBox/mm.h>
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include "Builtins.h"
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncextern "C" {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include "audio.h"
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#undef LOG_VOICES
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync#ifndef VBOX
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync//#define USE_MIXER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define USE_MIXER
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync#endif
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync#define AC97_SSM_VERSION 1
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncenum {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Reset = 0x00,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Master_Volume_Mute = 0x02,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Headphone_Volume_Mute = 0x04,
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AC97_Master_Volume_Mono_Mute = 0x06,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Master_Tone_RL = 0x08,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync AC97_PC_BEEP_Volume_Mute = 0x0A,
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync AC97_Phone_Volume_Mute = 0x0C,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync AC97_Mic_Volume_Mute = 0x0E,
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AC97_Line_In_Volume_Mute = 0x10,
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync AC97_CD_Volume_Mute = 0x12,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Video_Volume_Mute = 0x14,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Aux_Volume_Mute = 0x16,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_PCM_Out_Volume_Mute = 0x18,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Record_Select = 0x1A,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Record_Gain_Mute = 0x1C,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Record_Gain_Mic_Mute = 0x1E,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_General_Purpose = 0x20,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_3D_Control = 0x22,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_AC_97_RESERVED = 0x24,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Powerdown_Ctrl_Stat = 0x26,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Extended_Audio_ID = 0x28,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Extended_Audio_Ctrl_Stat = 0x2A,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_PCM_Front_DAC_Rate = 0x2C,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_PCM_Surround_DAC_Rate = 0x2E,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_PCM_LFE_DAC_Rate = 0x30,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_PCM_LR_ADC_Rate = 0x32,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_MIC_ADC_Rate = 0x34,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_6Ch_Vol_C_LFE_Mute = 0x36,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Vendor_Reserved = 0x58,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Vendor_ID1 = 0x7c,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97_Vendor_ID2 = 0x7e
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync};
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#ifndef VBOX
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define SOFT_VOLUME
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#undef SOFT_VOLUME
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define SR_FIFOE BIT(4) /* rwc, fifo error */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define SR_BCIS BIT(3) /* rwc, buffer completion interrupt status */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define SR_LVBCI BIT(2) /* rwc, last valid buffer completion interrupt */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define SR_CELV BIT(1) /* ro, current equals last valid */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define SR_DCH BIT(0) /* ro, controller halted */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define SR_VALID_MASK (BIT(5) - 1)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define SR_RO_MASK (SR_DCH | SR_CELV)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define CR_IOCE BIT(4) /* rw */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define CR_FEIE BIT(3) /* rw */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define CR_LVBIE BIT(2) /* rw */
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync#define CR_RR BIT(1) /* rw */
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync#define CR_RPBM BIT(0) /* rw */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define CR_VALID_MASK (BIT(5) - 1)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync#define GC_WR 4 /* rw */
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync#define GC_CR 2 /* rw */
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync#define GC_VALID_MASK (BIT(6) - 1)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define GS_MD3 BIT(17) /* rw */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync#define GS_AD3 BIT(16) /* rw */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define GS_RCS BIT(15) /* rwc */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define GS_B3S12 BIT(14) /* ro */
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync#define GS_B2S12 BIT(13) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_B1S12 BIT(12) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_S1R1 BIT(11) /* rwc */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_S0R1 BIT(10) /* rwc */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_S1CR BIT(9) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_S0CR BIT(8) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_MINT BIT(7) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_POINT BIT(6) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_PIINT BIT(5) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_RSRVD (BIT(4)|BIT(3))
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_MOINT BIT(2) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_MIINT BIT(1) /* ro */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_GSCI BIT(0) /* rwc */
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync#define GS_RO_MASK (GS_B3S12| \
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync GS_B2S12| \
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync GS_B1S12| \
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync GS_S1CR| \
c060166f65b9dd2f1ed53e6e4cffdad948e01722vboxsync GS_S0CR| \
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync GS_MINT| \
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync GS_POINT| \
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync GS_PIINT| \
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync GS_RSRVD| \
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync GS_MOINT| \
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync GS_MIINT)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define GS_VALID_MASK (BIT(18) - 1)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync/** Buffer Descriptor */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define BD_IOC BIT(31) /* Interrupt on Completion */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define BD_BUP BIT(30) /* Buffer Underrun Policy */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define EACS_VRA 1
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define EACS_VRM 8
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define VOL_MASK 0x1f
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define MUTE_SHIFT 15
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define REC_MASK 7
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsyncenum
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync{
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync REC_MIC = 0,
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync REC_CD,
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync REC_VIDEO,
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync REC_AUX,
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync REC_LINE_IN,
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync REC_STEREO_MIX,
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync REC_MONO_MIX,
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync REC_PHONE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync};
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct BD
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t addr;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t ctl_len;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} BD;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct AC97BusMasterRegs
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t bdbar; /* rw 0, buffer descriptor list base address register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t civ; /* ro 0, current index value */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t lvi; /* rw 0, last valid index */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint16_t sr; /* rw 1, status register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint16_t picb; /* ro 0, position in current buffer */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t piv; /* ro 0, prefetched index value */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t cr; /* rw 0, control register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int bd_valid; /* initialized? */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync BD bd;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync} AC97BusMasterRegs;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct AC97LinkState
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync QEMUSoundCard card;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Global Control (Bus Master Control Register) */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync uint32_t glob_cnt;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Global Status (Bus Master Control Register) */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync uint32_t glob_sta;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Codec Access Semaphore Register (Bus Master Control Register) */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync uint32_t cas;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t last_samp;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Bus Master Control Registers for PCM in, PCM out, and Mic in */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97BusMasterRegs bm_regs[3];
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync uint8_t mixer_data[256];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** PCM in */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync SWVoiceIn *voice_pi;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** PCM out */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync SWVoiceOut *voice_po;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Mic in */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync SWVoiceIn *voice_mc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t silence[128];
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync int bup_flag;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PPDMDEVINS pDevIns;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the connector of the attached audio driver. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PPDMIAUDIOCONNECTOR pDrv;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the attached audio driver. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PPDMIBASE pDrvBase;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The base interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDMIBASE IBase;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Base port of the I/O space region. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTIOPORT IOPortBase[2];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} AC97LinkState;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define ICHAC97STATE_2_DEVINS(pAC97) ((pAC97)->pDevIns)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define PCIDEV_2_ICHAC97STATE(pPciDev) ((PCIAC97LinkState *)(pPciDev))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncenum
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync BUP_SET = BIT(0),
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync BUP_LAST = BIT(1)
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync};
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsynctypedef struct PCIAC97LinkState
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIDevice dev;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync AC97LinkState ac97;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync} PCIAC97LinkState;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define MKREGS(prefix, start) \
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsyncenum { \
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync prefix ## _BDBAR = start, \
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync prefix ## _CIV = start + 4, \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync prefix ## _LVI = start + 5, \
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync prefix ## _SR = start + 6, \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync prefix ## _PICB = start + 8, \
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync prefix ## _PIV = start + 10, \
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync prefix ## _CR = start + 11 \
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync}
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsyncenum
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PI_INDEX = 0, /* PCM in */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PO_INDEX, /* PCM out */
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync MC_INDEX, /* Mic in */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync LAST_INDEX
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync};
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncMKREGS (PI, PI_INDEX * 16);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncMKREGS (PO, PO_INDEX * 16);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncMKREGS (MC, MC_INDEX * 16);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsyncenum
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync{
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync GLOB_CNT = 0x2c,
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync GLOB_STA = 0x30,
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync CAS = 0x34
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync};
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync#define GET_BM(index) (((index) >> 4) & 3)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsyncstatic void po_callback (void *opaque, int free);
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsyncstatic void pi_callback (void *opaque, int avail);
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsyncstatic void mc_callback (void *opaque, int avail);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void warm_reset (AC97LinkState *s)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (void) s;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void cold_reset (AC97LinkState * s)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync (void) s;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync/** Fetch Buffer Descriptor at _CIV */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t b[8];
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDMDevHlpPhysRead (pDevIns, r->bdbar + r->civ * 8, b, sizeof(b));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bd_valid = 1;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#if !defined(__X86__) && !defined(__AMD64__)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#error Please adapt the code (audio buffers are little endian)!
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bd.addr = (*(uint32_t *) &b[0]) & ~3;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bd.ctl_len = (*(uint32_t *) &b[4]);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->picb = r->bd.ctl_len & 0xffff;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->civ, r->bd.addr, r->bd.ctl_len >> 16,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bd.ctl_len & 0xffff, (r->bd.ctl_len & 0xffff) << 1));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync/**
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Update the BM status register
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int event = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int level = 0;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync uint32_t new_mask = new_sr & SR_INT_MASK;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync uint32_t old_mask = r->sr & SR_INT_MASK;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (new_mask ^ old_mask)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo is IRQ deasserted when only one of status bits is cleared? */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!new_mask)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync {
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync event = 1;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync level = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync else if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync event = 1;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync level = 1;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync event = 1;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync level = 1;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->sr = new_sr;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: IOC%d LVB%d sr=%#x event=%d level=%d\n",
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync r->sr & SR_BCIS, r->sr & SR_LVBCI, r->sr, event, level));
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync if (event)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->glob_sta |= masks[r - s->bm_regs];
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: set irq level=%d\n", !!level));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDMDevHlpPCISetIrq (pDevIns, 0, !!level);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void voice_set_active (AC97LinkState *s, int bm_index, int on)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync switch (bm_index)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case PI_INDEX: AUD_set_active_in (s->voice_pi, on); break;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case PO_INDEX: AUD_set_active_out(s->voice_po, on); break;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case MC_INDEX: AUD_set_active_in (s->voice_mc, on); break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default: AssertFailed ();
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: reset_bm_regs\n"));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bdbar = 0;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->civ = 0;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->lvi = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo do we need to do that? */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync update_sr (s, r, SR_DCH);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->picb = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->piv = 0;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->cr = r->cr & CR_DONT_CLEAR_MASK;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bd_valid = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync voice_set_active (s, r - s->bm_regs, 0);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync memset (s->silence, 0, sizeof (s->silence));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync}
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (i + 2 > sizeof (s->mixer_data))
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync {
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync Log (("ac97: mixer_store: index %d out of bounds %d\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync i, sizeof (s->mixer_data)));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->mixer_data[i + 0] = v & 0xff;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync s->mixer_data[i + 1] = v >> 8;
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
3956d0151065a11e49d2213b38a5efdad46807e0vboxsyncstatic uint16_t mixer_load (AC97LinkState *s, uint32_t i)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync{
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync uint16_t val;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (i + 2 > sizeof (s->mixer_data))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: mixer_store: index %d out of bounds %d\n",
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync i, sizeof (s->mixer_data)));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync val = 0xffff;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync }
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return val;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic void open_voice (AC97LinkState *s, int index, int freq)
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync{
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync audsettings_t as;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync if (freq)
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync {
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync as.freq = freq;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync as.nchannels = 2;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync as.fmt = AUD_FMT_S16;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync as.endianness = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
3b1aa24d99d0f9cc157cf72ca76444b2feca3277vboxsync switch (index)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync case PI_INDEX: /* PCM in */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->voice_pi = AUD_open_in (&s->card, s->voice_pi, "ac97.pi",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s, pi_callback, &as);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#ifdef LOG_VOICES
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: open PI freq=%d (%s)\n", freq, s->voice_pi ? "ok" : "FAIL"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#endif
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_INDEX: /* PCM out */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->voice_po = AUD_open_out (&s->card, s->voice_po, "ac97.po",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s, po_callback, &as);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#ifdef LOG_VOICES
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: open PO freq=%d (%s)\n", freq, s->voice_po ? "ok" : "FAIL"));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync break;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync case MC_INDEX: /* Mic in */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->voice_mc = AUD_open_in (&s->card, s->voice_mc, "ac97.mc",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s, mc_callback, &as);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#ifdef LOG_VOICES
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: open MC freq=%d (%s)\n", freq, s->voice_mc ? "ok" : "FAIL"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync else
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (index)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case PI_INDEX:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AUD_close_in (&s->card, s->voice_pi);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#ifdef LOG_VOICES
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync LogRel(("AC97: Closing PCM IN\n"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->voice_pi = NULL;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case PO_INDEX:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AUD_close_out (&s->card, s->voice_po);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#ifdef LOG_VOICES
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: Closing PCM OUT\n"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->voice_po = NULL;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_INDEX:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AUD_close_in (&s->card, s->voice_mc);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#ifdef LOG_VOICES
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: Closing MIC IN\n"));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->voice_mc = NULL;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint16_t freq;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync open_voice (s, PI_INDEX, freq);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AUD_set_active_in (s->voice_pi, active[PI_INDEX]);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync open_voice (s, PO_INDEX, freq);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AUD_set_active_out (s->voice_po, active[PO_INDEX]);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync freq = mixer_load (s, AC97_MIC_ADC_Rate);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync open_voice (s, MC_INDEX, freq);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#ifdef USE_MIXER
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void set_volume (AC97LinkState *s, int index,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync audmixerctl_t mt, uint32_t val)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync{
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync int mute = (val >> MUTE_SHIFT) & 1;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync uint8_t rvol = VOL_MASK - (val & VOL_MASK);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync rvol = 255 * rvol / VOL_MASK;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync lvol = 255 * lvol / VOL_MASK;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#ifdef SOFT_VOLUME
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync if (index == AC97_Master_Volume_Mute)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AUD_set_volume (mt, &mute, &lvol, &rvol);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AUD_set_volume (mt, &mute, &lvol, &rvol);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#ifdef VBOX
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /*
067712a8118321d460f98b437ecafb6b8dbce301vboxsync * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * all lower 5 bits will read ones whenever these bits are set to `1.'"
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync *
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Linux ALSA depends on this behavior.
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync */
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync if (val & BIT(5))
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync val |= BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (val & BIT(13))
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync val |= BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync mixer_store (s, index, val);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync}
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic audrecsource_t ac97_to_aud_record_source (uint8_t i)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (i)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync case REC_MIC: return AUD_REC_MIC;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case REC_CD: return AUD_REC_CD;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case REC_VIDEO: return AUD_REC_VIDEO;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case REC_AUX: return AUD_REC_AUX;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case REC_LINE_IN: return AUD_REC_LINE_IN;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case REC_PHONE: return AUD_REC_PHONE;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default: Log (("ac97: Unknown record source %d, using MIC\n", i));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return AUD_REC_MIC;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic uint8_t aud_to_ac97_record_source (audrecsource_t rs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (rs)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AUD_REC_MIC: return REC_MIC;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AUD_REC_CD: return REC_CD;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case AUD_REC_VIDEO: return REC_VIDEO;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case AUD_REC_AUX: return REC_AUX;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case AUD_REC_LINE_IN: return REC_LINE_IN;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case AUD_REC_PHONE: return REC_PHONE;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default: Log (("ac97: Unknown audio recording source %d using MIC\n", rs));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return REC_MIC;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsyncstatic void record_select (AC97LinkState *s, uint32_t val)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync{
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync uint8_t rs = val & REC_MASK;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync uint8_t ls = (val >> 8) & REC_MASK;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync audrecsource_t ars = ac97_to_aud_record_source (rs);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync audrecsource_t als = ac97_to_aud_record_source (ls);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AUD_set_record_source (&als, &ars);
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync rs = aud_to_ac97_record_source (ars);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync ls = aud_to_ac97_record_source (als);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Record_Select, rs | (ls << 8));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsyncstatic void mixer_reset (AC97LinkState *s)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync uint8_t active[LAST_INDEX];
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: mixer_reset\n"));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync memset (s->mixer_data, 0, sizeof (s->mixer_data));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync memset (active, 0, sizeof (active));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Reset , 0x0000); /* 6940 */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Phone_Volume_Mute , 0x8008);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Mic_Volume_Mute , 0x8008);
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync mixer_store (s, AC97_CD_Volume_Mute , 0x8808);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Aux_Volume_Mute , 0x8808);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_General_Purpose , 0x0000);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_3D_Control , 0x0000);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Sigmatel 9700 (STAC9700)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Vendor_ID1 , 0x8384);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync mixer_store (s, AC97_Extended_Audio_ID , 0x0809);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#ifdef USE_MIXER
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync record_select (s, 0);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME, 0x8000);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Record_Select, 0);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync mixer_store (s, AC97_Master_Volume_Mute, 0x8000);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PCM_Out_Volume_Mute, 0x8808);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Line_In_Volume_Mute, 0x8808);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
3b1aa24d99d0f9cc157cf72ca76444b2feca3277vboxsync reset_voices (s, active);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync}
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsyncstatic int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync int max, int *stop)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync{
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync uint8_t tmpbuf[4096];
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync uint32_t addr = r->bd.addr;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync uint32_t temp = r->picb << 1;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync uint32_t written = 0;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync int to_copy = 0;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync temp = audio_MIN (temp, (uint32_t) max);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync if (!temp)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync *stop = 1;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync return 0;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync while (temp)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync int copied;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync to_copy = audio_MIN (temp, sizeof (tmpbuf));
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync PDMDevHlpPhysRead (pDevIns, addr, tmpbuf, to_copy);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync copied = AUD_write (s->voice_po, tmpbuf, to_copy);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync Log (("ac97: write_audio max=%x to_copy=%x copied=%x\n",
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync max, to_copy, copied));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync if (!copied)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync *stop = 1;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync break;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync temp -= copied;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync addr += copied;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync written += copied;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync if (!temp)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync if (to_copy < 4)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: whoops\n"));
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync s->last_samp = 0;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync }
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync else
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4];
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync r->bd.addr = addr;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync return written;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync}
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsyncstatic void write_bup (AC97LinkState *s, int elapsed)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync{
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync int written = 0;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync Log (("ac97: write_bup\n"));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync if (!(s->bup_flag & BUP_SET))
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync if (s->bup_flag & BUP_LAST)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync unsigned int i;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync uint32_t *p = (uint32_t*)s->silence;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync for (i = 0; i < sizeof (s->silence) / 4; i++)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync *p++ = s->last_samp;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync else
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync memset (s->silence, 0, sizeof (s->silence));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync s->bup_flag |= BUP_SET;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync }
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync while (elapsed)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync unsigned int temp = audio_MIN ((unsigned int)elapsed, sizeof (s->silence));
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync while (temp)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync {
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync int copied = AUD_write (s->voice_po, s->silence, temp);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync if (!copied)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync return;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync temp -= copied;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync elapsed -= copied;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync written += copied;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync int max, int *stop)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(s);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint8_t tmpbuf[4096];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint32_t addr = r->bd.addr;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync uint32_t temp = r->picb << 1;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync uint32_t nread = 0;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync int to_copy = 0;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync temp = audio_MIN (temp, (uint32_t) max);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync if (!temp)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *stop = 1;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (temp)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int acquired;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync to_copy = audio_MIN (temp, sizeof (tmpbuf));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync acquired = AUD_read (voice, tmpbuf, to_copy);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if (!acquired)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *stop = 1;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync break;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMDevHlpPhysWrite (pDevIns, addr, tmpbuf, acquired);
3614117c1132a61599e6190939e775cafe549411vboxsync temp -= acquired;
034f0367d3b0431c6346b1a3af3abb435ee50d4evboxsync addr += acquired;
3614117c1132a61599e6190939e775cafe549411vboxsync nread += acquired;
3614117c1132a61599e6190939e775cafe549411vboxsync }
3614117c1132a61599e6190939e775cafe549411vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->bd.addr = addr;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return nread;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void transfer_audio (AC97LinkState *s, int index, int elapsed)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AC97BusMasterRegs *r = &s->bm_regs[index];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync int written = 0, stop = 0;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync if (r->sr & SR_DCH)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync if (r->cr & CR_RPBM)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_INDEX:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync write_bup (s, elapsed);
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync while ((elapsed >> 1) && !stop)
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync {
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync int temp;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!r->bd_valid)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: invalid bd\n"));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync fetch_bd (s, r);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!r->picb)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: fresh bd %d is empty %#x %#x\n",
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync r->civ, r->bd.addr, r->bd.ctl_len));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (r->civ == r->lvi)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->sr |= SR_DCH; /* CELV? */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->bup_flag = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->sr &= ~SR_CELV;
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync r->civ = r->piv;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->piv = (r->piv + 1) % 32;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync fetch_bd (s, r);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync return;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync switch (index)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case PO_INDEX:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync temp = write_audio (s, r, elapsed, &stop);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync written += temp;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync elapsed -= temp;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->picb -= (temp >> 1);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case PI_INDEX:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case MC_INDEX:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync temp = read_audio (s, r, elapsed, &stop);
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync elapsed -= temp;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->picb -= (temp >> 1);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log(("r->picb = %d\n", r->picb));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (!r->picb)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t new_sr = r->sr & ~SR_CELV;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (r->bd.ctl_len & BD_IOC)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync new_sr |= SR_BCIS;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (r->civ == r->lvi)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync stop = 1;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->civ = r->piv;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->piv = (r->piv + 1) % 32;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync fetch_bd (s, r);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync update_sr (s, r, new_sr);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync}
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsyncstatic void pi_callback (void *opaque, int avail)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync transfer_audio ((AC97LinkState*)opaque, PI_INDEX, avail);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void mc_callback (void *opaque, int avail)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync transfer_audio ((AC97LinkState*)opaque, MC_INDEX, avail);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void po_callback (void *opaque, int free)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync transfer_audio ((AC97LinkState*)opaque, PO_INDEX, free);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/**
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for IN operations.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status code.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pDevIns The device instance.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pvUser User argument.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param uPort Port number used for the IN operation.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pu32 Where to store the result.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param cb Number of bytes read.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync RTIOPORT Port, uint32_t *pu32, unsigned cb)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync{
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AC97LinkState *s = &d->ac97;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (cb)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case 1:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97BusMasterRegs *r = NULL;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint32_t index = Port - d->ac97.IOPortBase[1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = ~0U;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync switch (index)
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case CAS:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Codec Access Semaphore Register */
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync Log (("ac97: CAS %d\n", s->cas));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = s->cas;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->cas = 1;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case PI_CIV:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_CIV:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_CIV:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Current Index Value Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync *pu32 = r->civ;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: CIV[%d] -> %#x\n", GET_BM (index), *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PI_LVI:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PO_LVI:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case MC_LVI:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync /* Last Valid Index Register */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync r = &s->bm_regs[GET_BM (index)];
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync *pu32 = r->lvi;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync Log (("ac97: LVI[%d] -> %#x\n", GET_BM (index), *pu32));
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case PI_PIV:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PO_PIV:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case MC_PIV:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync /* Prefetched Index Value Register */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync r = &s->bm_regs[GET_BM (index)];
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync *pu32 = r->piv;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: PIV[%d] -> %#x\n", GET_BM (index), *pu32));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync break;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PI_CR:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PO_CR:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case MC_CR:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync /* Control Register */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync r = &s->bm_regs[GET_BM (index)];
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync *pu32 = r->cr;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: CR[%d] -> %#x\n", GET_BM (index), *pu32));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync break;
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PI_SR:
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PO_SR:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case MC_SR:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync /* Status Register (lower part) */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync r = &s->bm_regs[GET_BM (index)];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = r->sr & 0xff;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: SRb[%d] -> %#x\n", GET_BM (index), *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: U nabm readb %#x -> %#x\n", Port, *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
009d969fa3276b108ddb99a9c1a7a26c003438a7vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case 2:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97BusMasterRegs *r = NULL;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t index = Port - d->ac97.IOPortBase[1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = ~0U;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PI_SR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_SR:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case MC_SR:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Status Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = r->sr;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: SR[%d] -> %#x\n", GET_BM (index), *pu32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PI_PICB:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case PO_PICB:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case MC_PICB:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Position in Current Buffer Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync *pu32 = r->picb;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: PICB[%d] -> %#x\n", GET_BM (index), *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nabm readw %#x -> %#x\n", Port, *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync }
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case 4:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync AC97BusMasterRegs *r = NULL;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint32_t index = Port - d->ac97.IOPortBase[1];
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync *pu32 = ~0U;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync case PI_BDBAR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_BDBAR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_BDBAR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Buffer Descriptor Base Address Register */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync r = &s->bm_regs[GET_BM (index)];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = r->bdbar;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: BMADDR[%d] -> %#x\n", GET_BM (index), *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PI_CIV:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case PO_CIV:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_CIV:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync /* 32-bit access: Current Index Value Register +
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Last Valid Index Register +
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Status Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync *pu32 = r->civ | (r->lvi << 8) | (r->sr << 16);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync r->civ, r->lvi, r->sr));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case PI_PICB:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case PO_PICB:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case MC_PICB:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* 32-bit access: Position in Current Buffer Register +
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Prefetched Index Value Register +
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Control Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = r->picb | (r->piv << 16) | (r->cr << 24);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32, r->picb, r->piv, r->cr));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case GLOB_CNT:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Global Control */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = s->glob_cnt;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: glob_cnt -> %#x\n", *pu32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case GLOB_STA:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Global Status */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = s->glob_sta | GS_S0CR;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: glob_sta -> %#x\n", *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nabm readl %#x -> %#x\n", Port, *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VERR_IOM_IOPORT_UNUSED;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return VINF_SUCCESS;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/**
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for OUT operations.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status code.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pDevIns The device instance.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pvUser User argument.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param uPort Port number used for the IN operation.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param u32 The value to output.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param cb The value size in bytes.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNABMWrite (PPDMDEVINS pDevIns, void *pvUser,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTIOPORT Port, uint32_t u32, unsigned cb)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AC97LinkState *s = &d->ac97;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (cb)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync case 1:
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync {
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AC97BusMasterRegs *r = NULL;
7697e43970d863558b6c168a55e8948ccb18d8d1vboxsync uint32_t index = Port - d->ac97.IOPortBase[1];
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync case PI_LVI:
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync case PO_LVI:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_LVI:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Last Valid Index */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r = &s->bm_regs[GET_BM (index)];
9b7ab382b3f9667e8847020e1e58f7143c4d2334vboxsync if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->sr &= ~(SR_DCH | SR_CELV);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->civ = r->piv;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->piv = (r->piv + 1) % 32;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync fetch_bd (s, r);
af5224eb6b6676bc892a3f5abeb21f602547d31cvboxsync }
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync r->lvi = u32 % 32;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: LVI[%d] <- %#x\n", GET_BM (index), u32));
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync break;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync case PI_CR:
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync case PO_CR:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case MC_CR:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Control Register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r = &s->bm_regs[GET_BM (index)];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (u32 & CR_RR)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync reset_bm_regs (s, r);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->cr = u32 & CR_VALID_MASK;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!(r->cr & CR_RPBM))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync voice_set_active (s, r - s->bm_regs, 0);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->sr |= SR_DCH;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->civ = r->piv;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->piv = (r->piv + 1) % 32;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync fetch_bd (s, r);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->sr &= ~SR_DCH;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync voice_set_active (s, r - s->bm_regs, 1);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: CR[%d] <- %#x (cr %#x)\n", GET_BM (index), u32, r->cr));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case PI_SR:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case PO_SR:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case MC_SR:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Status Register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r = &s->bm_regs[GET_BM (index)];
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync r->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync update_sr (s, r, r->sr & ~(u32 & SR_WCLEAR_MASK));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM (index), u32, r->sr));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nabm writeb %#x <- %#x\n", Port, u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case 2:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AC97BusMasterRegs *r = NULL;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t index = Port - d->ac97.IOPortBase[1];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PI_SR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_SR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_SR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Status Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->sr |= u32 & ~(SR_RO_MASK | SR_WCLEAR_MASK);
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync update_sr (s, r, r->sr & ~(u32 & SR_WCLEAR_MASK));
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync Log (("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM (index), u32, r->sr));
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync break;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync default:
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync Log (("ac97: U nabm writew %#x <- %#x\n", Port, u32));
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync break;
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case 4:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AC97BusMasterRegs *r = NULL;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint32_t index = Port - d->ac97.IOPortBase[1];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PI_BDBAR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case PO_BDBAR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case MC_BDBAR:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Buffer Descriptor list Base Address Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r = &s->bm_regs[GET_BM (index)];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync r->bdbar = u32 & ~3;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: BDBAR[%d] <- %#x (bdbar %#x)\n",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync GET_BM (index), u32, r->bdbar));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case GLOB_CNT:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Global Control */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (u32 & GC_WR)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync warm_reset (s);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (u32 & GC_CR)
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync cold_reset (s);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync if (!(u32 & (GC_WR | GC_CR)))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->glob_cnt = u32 & GC_VALID_MASK;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: glob_cnt <- %#x (glob_cnt %#x)\n", u32, s->glob_cnt));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case GLOB_STA:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Global Status */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->glob_sta &= ~(u32 & GS_WCLEAR_MASK);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->glob_sta |= (u32 & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: glob_sta <- %#x (glob_sta %#x)\n", u32, s->glob_sta));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: U nabm writel %#x <- %#x\n", Port, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync }
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync return VINF_SUCCESS;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/**
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for IN operations.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status code.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pDevIns The device instance.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pvUser User argument.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param uPort Port number used for the IN operation.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pu32 Where to store the result.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param cb Number of bytes read.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNAMRead (PPDMDEVINS pDevIns, void *pvUser,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync RTIOPORT Port, uint32_t *pu32, unsigned cb)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync{
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AC97LinkState *s = &d->ac97;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (cb)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case 1:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: U nam readb %#x\n", Port));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->cas = 0;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = ~0U;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case 2:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync uint32_t index = Port - d->ac97.IOPortBase[0];
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = ~0U;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->cas = 0;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync switch (index)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = mixer_load (s, index);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: nam readw %#x -> %#x\n", Port, *pu32));
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync break;
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync }
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case 4:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: U nam readl %#x\n", Port));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->cas = 0;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *pu32 = ~0U;
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync default:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return VERR_IOM_IOPORT_UNUSED;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return VINF_SUCCESS;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync}
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync/**
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for OUT operations.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync *
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync * @returns VBox status code.
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync *
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pDevIns The device instance.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pvUser User argument.
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync * @param uPort Port number used for the IN operation.
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync * @param u32 The value to output.
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync * @param cb The value size in bytes.
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync */
63e3a547845f7c31bb4e892a66684b560dc63611vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNAMWrite (PPDMDEVINS pDevIns, void *pvUser,
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync RTIOPORT Port, uint32_t u32, unsigned cb)
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync{
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync PCIAC97LinkState *d = (PCIAC97LinkState*)pvUser;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync AC97LinkState *s = &d->ac97;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync switch (cb)
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync {
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync case 1:
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync {
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync Log (("ac97: U nam writeb %#x <- %#x\n", Port, u32));
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync s->cas = 0;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync break;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync }
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync case 2:
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync {
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync uint32_t index = Port - d->ac97.IOPortBase[0];
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync s->cas = 0;
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync switch (index)
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync {
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync case AC97_Reset:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync mixer_reset (s);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case AC97_Powerdown_Ctrl_Stat:
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync u32 &= ~0xf;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync u32 |= mixer_load (s, index) & 0xf;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync mixer_store (s, index, u32);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync#ifdef USE_MIXER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Master_Volume_Mute:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync set_volume (s, index, AUD_MIXER_VOLUME, u32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_PCM_Out_Volume_Mute:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync set_volume (s, index, AUD_MIXER_PCM, u32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Line_In_Volume_Mute:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync set_volume (s, index, AUD_MIXER_LINE_IN, u32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync case AC97_Record_Select:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync record_select (s, u32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Master_Volume_Mute:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_PCM_Out_Volume_Mute:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Line_In_Volume_Mute:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Record_Select:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, index, u32);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync case AC97_Vendor_ID1:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Vendor_ID2:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: Attempt to write vendor ID to %#x\n", u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case AC97_Extended_Audio_ID:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: Attempt to write extended audio ID to %#x\n", u32));
3614117c1132a61599e6190939e775cafe549411vboxsync break;
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync case AC97_Extended_Audio_Ctrl_Stat:
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync if (!(u32 & EACS_VRA))
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync {
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80);
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync open_voice (s, PI_INDEX, 48000);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync open_voice (s, PO_INDEX, 48000);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync }
601d153b9b7960b2a58cc013b6ac3aa00b95bdeavboxsync if (!(u32 & EACS_VRM))
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80);
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync open_voice (s, MC_INDEX, 48000);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: Setting extended audio control to %#x\n", u32));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, u32);
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync break;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync case AC97_PCM_Front_DAC_Rate:
3956d0151065a11e49d2213b38a5efdad46807e0vboxsync if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, index, u32);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log(("ac97: Set front DAC rate to %d\n", u32));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync open_voice (s, PO_INDEX, u32);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync Log (("ac97: Attempt to set front DAC rate to %d, "
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync "but VRA is not set\n",
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync u32));
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync }
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync break;
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync case AC97_MIC_ADC_Rate:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync {
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync mixer_store (s, index, u32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: Set MIC ADC rate to %d\n", u32));
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync open_voice (s, MC_INDEX, u32);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync }
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync else
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync {
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync Log (("ac97: Attempt to set MIC ADC rate to %d, "
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync "but VRM is not set\n",
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync u32));
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync }
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync break;
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync case AC97_PCM_LR_ADC_Rate:
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync mixer_store (s, index, u32);
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync Log (("ac97: Set front LR ADC rate to %d\n", u32));
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync open_voice (s, PI_INDEX, u32);
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync }
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync else
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync {
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: Attempt to set LR ADC rate to %d, but VRA is not set\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nam writew %#x <- %#x\n", Port, u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, index, u32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync case 4:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nam writel %#x <- %#x\n", Port, u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->cas = 0;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default:
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Callback function for mapping a PCI I/O region.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @return VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pPciDev Pointer to PCI device.
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Use pPciDev->pDevIns to get the device instance.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param iRegion The region number.
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * @param GCPhysAddress Physical address of the region.
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * If iType is PCI_ADDRESS_SPACE_IO, this is an
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * I/O port, else it's a physical address.
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync * This address is *NOT* relative
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * to pci_mem_base like earlier!
572f495840b063427930dbb6f5a81f3147286effvboxsync * @param enmType One of the PCI_ADDRESS_SPACE_* values.
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97IOPortMap (PPCIDEVICE pPciDev, int iRegion,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTGCPHYS GCPhysAddress, uint32_t cb,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIADDRESSSPACE enmType)
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync{
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync int rc;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync PPDMDEVINS pDevIns = pPciDev->pDevIns;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync RTIOPORT Port = (RTIOPORT)GCPhysAddress;
572f495840b063427930dbb6f5a81f3147286effvboxsync PCIAC97LinkState *pData = PCIDEV_2_ICHAC97STATE(pPciDev);
572f495840b063427930dbb6f5a81f3147286effvboxsync
572f495840b063427930dbb6f5a81f3147286effvboxsync Assert(enmType == PCI_ADDRESS_SPACE_IO);
572f495840b063427930dbb6f5a81f3147286effvboxsync Assert(cb >= 0x20);
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync if (iRegion == 0)
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync rc = PDMDevHlpIOPortRegister (pDevIns, Port, 256, pData,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ichac97IOPortNAMWrite, ichac97IOPortNAMRead,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync NULL, NULL, "ICHAC97 NAM");
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync else
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync rc = PDMDevHlpIOPortRegister (pDevIns, Port, 64, pData,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync ichac97IOPortNABMWrite, ichac97IOPortNABMRead,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync NULL, NULL, "ICHAC97 NABM");
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync if (VBOX_FAILURE(rc))
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync return rc;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync pData->ac97.IOPortBase[iRegion] = Port;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync return VINF_SUCCESS;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync}
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync
601d153b9b7960b2a58cc013b6ac3aa00b95bdeavboxsync/**
601d153b9b7960b2a58cc013b6ac3aa00b95bdeavboxsync * Saves a state of the AC'97 device.
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync *
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * @returns VBox status code.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pDevIns The device instance.
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * @param pSSMHandle The handle to save the state to.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIAC97LinkState *pData = PDMINS2DATA(pDevIns, PCIAC97LinkState *);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync size_t i;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync uint8_t active[LAST_INDEX];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97LinkState *s = &pData->ac97;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync SSMR3PutU32 (pSSMHandle, s->glob_cnt);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU32 (pSSMHandle, s->glob_sta);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU32 (pSSMHandle, s->cas);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97BusMasterRegs *r = &s->bm_regs[i];
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync SSMR3PutU32 (pSSMHandle, r->bdbar);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU8 (pSSMHandle, r->civ);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU8 (pSSMHandle, r->lvi);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU16 (pSSMHandle, r->sr);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU16 (pSSMHandle, r->picb);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU8 (pSSMHandle, r->piv);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync SSMR3PutU8 (pSSMHandle, r->cr);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutS32 (pSSMHandle, r->bd_valid);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3PutU32 (pSSMHandle, r->bd.addr);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync SSMR3PutU32 (pSSMHandle, r->bd.ctl_len);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync SSMR3PutMem (pSSMHandle, s->mixer_data, sizeof (s->mixer_data));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync active[PI_INDEX] = AUD_is_active_in (s->voice_pi) ? 1 : 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync active[PO_INDEX] = AUD_is_active_out (s->voice_po) ? 1 : 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync active[MC_INDEX] = AUD_is_active_in (s->voice_mc) ? 1 : 0;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync SSMR3PutMem (pSSMHandle, active, sizeof (active));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Loads a saved AC'97 device state.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pDevIns The device instance.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pSSMHandle The handle to the saved state.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param u32Version The data unit version number.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97LoadExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t u32Version)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIAC97LinkState *pData = PDMINS2DATA(pDevIns, PCIAC97LinkState *);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t i;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint8_t active[LAST_INDEX];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97LinkState *s = &pData->ac97;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (u32Version != AC97_SSM_VERSION)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertFailed();
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU32 (pSSMHandle, &s->glob_cnt);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU32 (pSSMHandle, &s->glob_sta);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU32 (pSSMHandle, &s->cas);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AC97BusMasterRegs *r = &s->bm_regs[i];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU32 (pSSMHandle, &r->bdbar);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU8 (pSSMHandle, &r->civ);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU8 (pSSMHandle, &r->lvi);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU16 (pSSMHandle, &r->sr);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU16 (pSSMHandle, &r->picb);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU8 (pSSMHandle, &r->piv);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU8 (pSSMHandle, &r->cr);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetS32 (pSSMHandle, &r->bd_valid);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU32 (pSSMHandle, &r->bd.addr);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetU32 (pSSMHandle, &r->bd.ctl_len);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetMem (pSSMHandle, s->mixer_data, sizeof (s->mixer_data));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetMem (pSSMHandle, active, sizeof (active));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#ifdef USE_MIXER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync record_select (s, mixer_load (s, AC97_Record_Select));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define V_(a, b) set_volume (s, a, b, mixer_load (s, a))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#undef V_
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync reset_voices (s, active);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->bup_flag = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->last_samp = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Reset notification.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pDevIns The device instance data.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @remark The original sources didn't install a reset handler, but it seems to
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * make sense to me so we'll do it.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic DECLCALLBACK(void) ac97Reset(PPDMDEVINS pDevIns)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
PCIAC97LinkState *pData = PDMINS2DATA(pDevIns, PCIAC97LinkState *);
/*
* Reset the device state (will need pDrv later).
*/
reset_bm_regs (&pData->ac97, &pData->ac97.bm_regs[0]);
reset_bm_regs (&pData->ac97, &pData->ac97.bm_regs[1]);
reset_bm_regs (&pData->ac97, &pData->ac97.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(&pData->ac97);
}
/**
* Queries an interface to the driver.
*
* @returns Pointer to interface.
* @returns NULL if the interface was not supported by the driver.
* @param pInterface Pointer to this interface structure.
* @param enmInterface The requested interface identification.
* @thread Any thread.
*/
static DECLCALLBACK(void *) ichac97QueryInterface (struct PDMIBASE *pInterface,
PDMINTERFACE enmInterface)
{
PCIAC97LinkState *pData =
(PCIAC97LinkState *)((uintptr_t)pInterface
- RT_OFFSETOF(PCIAC97LinkState, ac97.IBase));
Assert(&pData->ac97.IBase == pInterface);
switch (enmInterface)
{
case PDMINTERFACE_BASE:
return &pData->ac97.IBase;
default:
return NULL;
}
}
/**
* Construct a device instance for a VM.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* If the registration structure is needed,
* pDevIns->pDevReg points to it.
* @param iInstance Instance number. Use this to figure out which
* registers and such to use.
* The device number is also found in pDevIns->iInstance,
* but since it's likely to be freqently used PDM passes
* it as parameter.
* @param pCfgHandle Configuration node handle for the device.
* Use this to obtain the configuration
* of the device instance. It's also found in
* pDevIns->pCfgHandle, but like iInstance it's expected
* to be used a bit in this function.
*/
static DECLCALLBACK(int) ichac97Construct (PPDMDEVINS pDevIns, int iInstance,
PCFGMNODE pCfgHandle)
{
PCIAC97LinkState *pData = PDMINS2DATA(pDevIns, PCIAC97LinkState *);
AC97LinkState *s = &pData->ac97;
int rc;
Assert(iInstance == 0);
/*
* Initialize data (most of it anyway).
*/
s->pDevIns = pDevIns;
/* IBase */
s->IBase.pfnQueryInterface = ichac97QueryInterface;
/* PCI Device */
pData->dev.config[0x00] = 0x86; /* vid vendor id intel ro */
pData->dev.config[0x01] = 0x80; /* intel */
pData->dev.config[0x02] = 0x15; /* did device id 82801 ro */
pData->dev.config[0x03] = 0x24; /* 82801aa */
pData->dev.config[0x04] = 0x00; /* pcicmd pci command rw, ro */
pData->dev.config[0x05] = 0x00;
pData->dev.config[0x06] = 0x80; /* pcists pci status rwc, ro */
pData->dev.config[0x07] = 0x02;
pData->dev.config[0x08] = 0x01; /* rid revision ro */
pData->dev.config[0x09] = 0x00; /* pi programming interface ro */
pData->dev.config[0x0a] = 0x01; /* scc sub class code ro */
pData->dev.config[0x0b] = 0x04; /* bcc base class code ro */
pData->dev.config[0x0e] = 0x00; /* headtyp header type ro */
pData->dev.config[0x10] = 0x01; /* nambar native audio mixer base
* address rw */
pData->dev.config[0x11] = 0x00;
pData->dev.config[0x12] = 0x00;
pData->dev.config[0x13] = 0x00;
pData->dev.config[0x14] = 0x01; /* nabmbar native audio bus mastering
* base address rw */
pData->dev.config[0x15] = 0x00;
pData->dev.config[0x16] = 0x00;
pData->dev.config[0x17] = 0x00;
pData->dev.config[0x2c] = 0x86; /* svid subsystem vendor id rwo */
pData->dev.config[0x2d] = 0x80;
pData->dev.config[0x2e] = 0x00; /* sid subsystem id rwo */
pData->dev.config[0x2f] = 0x00;
pData->dev.config[0x3c] = 0x00; /* intr_ln interrupt line rw */
pData->dev.config[0x3d] = 0x01; /* intr_pn interrupt pin ro */
/*
* Register the PCI device, it's I/O regions, the timer and the
* saved state item.
*/
rc = PDMDevHlpPCIRegister (pDevIns, &pData->dev);
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpPCIIORegionRegister (pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO,
ichac97IOPortMap);
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpPCIIORegionRegister (pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO,
ichac97IOPortMap);
if (VBOX_FAILURE(rc))
return rc;
rc = PDMDevHlpSSMRegister (pDevIns, pDevIns->pDevReg->szDeviceName,
iInstance, AC97_SSM_VERSION, sizeof(*pData),
NULL, ichac97SaveExec, NULL,
NULL, ichac97LoadExec, NULL);
if (VBOX_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 (("ac97: No attached driver!\n"));
else if (VBOX_FAILURE(rc))
{
AssertMsgFailed(("Failed to attach AC97 LUN #0! rc=%Vrc\n", rc));
return rc;
}
AUD_register_card ("ICH0", &s->card);
ac97Reset(pDevIns);
#ifndef __DARWIN__ /* coreaudio doesn't supply these. */
if (!s->voice_pi)
LogRel(("AC97: WARNING: Unable to open PCM IN!\n"));
if (!s->voice_mc)
LogRel(("AC97: WARNING: Unable to open PCM MC!\n"));
#endif
if (!s->voice_po)
LogRel(("AC97: WARNING: Unable to open PCM OUT!\n"));
if (!s->voice_pi && !s->voice_po && !s->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, false, "HostAudioNotResponding",
N_("No audio devices could not be opened. Selecting the NULL audio backend "
"with the consequence that no sound is audible."));
}
#ifndef __DARWIN__
else if (!s->voice_pi || !s->voice_po || !s->voice_mc)
{
char szMissingVoices[128];
size_t len = 0;
bool fComma = false;
if (!s->voice_pi)
{
len = RTStrPrintf(szMissingVoices, sizeof(szMissingVoices), "PCM_in");
fComma = true;
}
if (!s->voice_po)
{
len = RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices)-len, "%sPCM_out",
fComma ? ", " : "");
fComma = true;
}
if (!s->voice_mc)
{
len = RTStrPrintf(szMissingVoices + len, sizeof(szMissingVoices)-len, "%sPCM_mic",
fComma ? ", " : "");
}
PDMDevHlpVMSetRuntimeError(pDevIns, false, "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);
}
#endif
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceICHAC97 =
{
/* u32Version */
PDM_DEVREG_VERSION,
/* szDeviceName */
"ichac97",
/* szGCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"ICH AC'97 Audio Controller",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
/* fClass */
PDM_DEVREG_CLASS_AUDIO,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(PCIAC97LinkState),
/* pfnConstruct */
ichac97Construct,
/* pfnDestruct */
NULL,
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
ac97Reset,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL
};