DevIchAc97.cpp revision 448f902e0dfb52e3e7b99e632203b14be8e46646
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * VBox ICH AC97 Audio Controller
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync * Copyright (C) 2006-2007 innotek GmbH
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.
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.
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync/*******************************************************************************
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync* Header Files *
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncextern "C" {
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync//#define USE_MIXER
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_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync/** Buffer Descriptor */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync#define BD_IOC BIT(31) /* Interrupt on Completion */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct BD
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t bdbar; /* rw 0, buffer descriptor list base address register */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint16_t picb; /* ro 0, position in current buffer */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Global Control (Bus Master Control Register) */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Global Status (Bus Master Control Register) */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Codec Access Semaphore Register (Bus Master Control Register) */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** Bus Master Control Registers for PCM in, PCM out, and Mic in */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** PCM in */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /** PCM out */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Mic in */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the device instance. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the connector of the attached audio driver. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the attached audio driver. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The base interface. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Base port of the I/O space region. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define ICHAC97STATE_2_DEVINS(pAC97) ((pAC97)->pDevIns)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define PCIDEV_2_ICHAC97STATE(pPciDev) ((PCIAC97LinkState *)(pPciDev))
fe554d9c0e3a6de4ba221610ac95a44c7d288e01vboxsync/** Fetch Buffer Descriptor at _CIV */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDMDevHlpPhysRead (pDevIns, r->bdbar + r->civ * 8, b, sizeof(b));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#error Please adapt the code (audio buffers are little endian)!
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync r->bd.ctl_len & 0xffff, (r->bd.ctl_len & 0xffff) << 1));
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync * Update the BM status register
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo is IRQ deasserted when only one of status bits is cleared? */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync else if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE))
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));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void voice_set_active (AC97LinkState *s, int bm_index, int on)
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;
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo do we need to do that? */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync Log (("ac97: mixer_store: index %d out of bounds %d\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync i, sizeof (s->mixer_data)));
3956d0151065a11e49d2213b38a5efdad46807e0vboxsyncstatic uint16_t mixer_load (AC97LinkState *s, uint32_t i)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: mixer_store: index %d out of bounds %d\n",
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync i, sizeof (s->mixer_data)));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic void open_voice (AC97LinkState *s, int index, int freq)
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->voice_pi = AUD_open_in (&s->card, s->voice_pi, "ac97.pi",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: open PI freq=%d (%s)\n", freq, s->voice_pi ? "ok" : "FAIL"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync s->voice_po = AUD_open_out (&s->card, s->voice_po, "ac97.po",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: open PO freq=%d (%s)\n", freq, s->voice_po ? "ok" : "FAIL"));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync s->voice_mc = AUD_open_in (&s->card, s->voice_mc, "ac97.mc",
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync LogRel(("AC97: open MC freq=%d (%s)\n", freq, s->voice_mc ? "ok" : "FAIL"));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AUD_set_active_out (s->voice_po, active[PO_INDEX]);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void set_volume (AC97LinkState *s, int index,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
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 * Linux ALSA depends on this behavior.
7c48fdac0546978ed14617c8096734ce2d18c8e5vboxsync val |= BIT(12) | BIT(11) | BIT(10) | BIT(9) | BIT(8);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic audrecsource_t ac97_to_aud_record_source (uint8_t i)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default: Log (("ac97: Unknown record source %d, using MIC\n", i));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic uint8_t aud_to_ac97_record_source (audrecsource_t rs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default: Log (("ac97: Unknown audio recording source %d using MIC\n", rs));
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsyncstatic void record_select (AC97LinkState *s, uint32_t val)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync audrecsource_t ars = ac97_to_aud_record_source (rs);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync audrecsource_t als = ac97_to_aud_record_source (ls);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Record_Select, rs | (ls << 8));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000);
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Sigmatel 9700 (STAC9700)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80);
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);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsyncstatic int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync PDMDevHlpPhysRead (pDevIns, addr, tmpbuf, to_copy);
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync Log (("ac97: write_audio max=%x to_copy=%x copied=%x\n",
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsyncstatic void write_bup (AC97LinkState *s, int elapsed)
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync unsigned int i;
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync unsigned int temp = audio_MIN ((unsigned int)elapsed, sizeof (s->silence));
8a54ed337392872c7cfcfb96f173468bbbb0f7fcvboxsync int copied = AUD_write (s->voice_po, s->silence, temp);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync PDMDevHlpPhysWrite (pDevIns, addr, tmpbuf, acquired);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic void transfer_audio (AC97LinkState *s, int index, int elapsed)
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync transfer_audio ((AC97LinkState*)opaque, PI_INDEX, avail);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync transfer_audio ((AC97LinkState*)opaque, MC_INDEX, avail);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync transfer_audio ((AC97LinkState*)opaque, PO_INDEX, free);
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for IN operations.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status code.
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.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97IOPortNABMRead (PPDMDEVINS pDevIns, void *pvUser,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Codec Access Semaphore Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Current Index Value Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: CIV[%d] -> %#x\n", GET_BM (index), *pu32));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync /* Last Valid Index Register */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync Log (("ac97: LVI[%d] -> %#x\n", GET_BM (index), *pu32));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync /* Prefetched Index Value Register */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: PIV[%d] -> %#x\n", GET_BM (index), *pu32));
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync /* Control Register */
e562a8bb17c0dfa1c316708e085a3a92fcc80521vboxsync Log (("ac97: CR[%d] -> %#x\n", GET_BM (index), *pu32));
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync /* Status Register (lower part) */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: SRb[%d] -> %#x\n", GET_BM (index), *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: U nabm readb %#x -> %#x\n", Port, *pu32));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Status Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: SR[%d] -> %#x\n", GET_BM (index), *pu32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Position in Current Buffer Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: PICB[%d] -> %#x\n", GET_BM (index), *pu32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nabm readw %#x -> %#x\n", Port, *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Buffer Descriptor Base Address Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: BMADDR[%d] -> %#x\n", GET_BM (index), *pu32));
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync /* 32-bit access: Current Index Value Register +
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Last Valid Index Register +
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Status Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* 32-bit access: Position in Current Buffer Register +
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Prefetched Index Value Register +
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Control Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Global Control */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Global Status */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nabm readl %#x -> %#x\n", Port, *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for OUT operations.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status code.
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.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNABMWrite (PPDMDEVINS pDevIns, void *pvUser,
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Last Valid Index */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: LVI[%d] <- %#x\n", GET_BM (index), u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Control Register */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: CR[%d] <- %#x (cr %#x)\n", GET_BM (index), u32, r->cr));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync /* Status Register */
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM (index), u32, r->sr));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nabm writeb %#x <- %#x\n", Port, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Status Register */
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync Log (("ac97: SR[%d] <- %#x (sr %#x)\n", GET_BM (index), u32, r->sr));
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync Log (("ac97: U nabm writew %#x <- %#x\n", Port, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Buffer Descriptor list Base Address Register */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Global Control */
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: glob_cnt <- %#x (glob_cnt %#x)\n", u32, s->glob_cnt));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync /* Global Status */
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 Log (("ac97: U nabm writel %#x <- %#x\n", Port, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for IN operations.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @returns VBox status code.
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.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNAMRead (PPDMDEVINS pDevIns, void *pvUser,
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: nam readw %#x -> %#x\n", Port, *pu32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * Port I/O Handler for OUT operations.
63e3a547845f7c31bb4e892a66684b560dc63611vboxsync * @returns VBox status code.
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.
63e3a547845f7c31bb4e892a66684b560dc63611vboxsyncstatic DECLCALLBACK(int) ichac97IOPortNAMWrite (PPDMDEVINS pDevIns, void *pvUser,
d5a801e98910a0c3c9c65cfc7cf8826f0b0b4450vboxsync Log (("ac97: U nam writeb %#x <- %#x\n", Port, u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: Attempt to write vendor ID to %#x\n", u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: Attempt to write extended audio ID to %#x\n", u32));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync Log (("ac97: Setting extended audio control to %#x\n", u32));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, u32);
3956d0151065a11e49d2213b38a5efdad46807e0vboxsync if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync Log (("ac97: Attempt to set front DAC rate to %d, "
04cdb3815f28f5dbf0e7dffc7957fec59260e76fvboxsync "but VRA is not set\n",
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM)
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync "but VRM is not set\n",
8742e4a4ddb7b62d21d96d56dd1baf01c9f22cecvboxsync if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
762a68c2bb3ccde807330e3d1cb05f8b244a5f72vboxsync Log (("ac97: Set front LR ADC rate to %d\n", u32));
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync Log (("ac97: Attempt to set LR ADC rate to %d, but VRA is not set\n",
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nam writew %#x <- %#x\n", Port, u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Log (("ac97: U nam writel %#x <- %#x\n", Port, u32));
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cb, u32));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Callback function for mapping a PCI I/O region.
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.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97IOPortMap (PPCIDEVICE pPciDev, int iRegion,
572f495840b063427930dbb6f5a81f3147286effvboxsync PCIAC97LinkState *pData = PCIDEV_2_ICHAC97STATE(pPciDev);
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync rc = PDMDevHlpIOPortRegister (pDevIns, Port, 256, pData,
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync rc = PDMDevHlpIOPortRegister (pDevIns, Port, 64, pData,
601d153b9b7960b2a58cc013b6ac3aa00b95bdeavboxsync * Saves a state of the AC'97 device.
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * @returns VBox status code.
3ebd5757516d21eccdad25ddd456d2913c2fb215vboxsync * @param pDevIns The device instance.
8287c906b9b1d215824d4cdf6c1eaf40681ebfa8vboxsync * @param pSSMHandle The handle to save the state to.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97SaveExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIAC97LinkState *pData = PDMINS2DATA(pDevIns, PCIAC97LinkState *);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i)
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsync SSMR3PutMem (pSSMHandle, s->mixer_data, sizeof (s->mixer_data));
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;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Loads a saved AC'97 device state.
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.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) ichac97LoadExec (PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCIAC97LinkState *pData = PDMINS2DATA(pDevIns, PCIAC97LinkState *);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (i = 0; i < sizeof (s->bm_regs) / sizeof (s->bm_regs[0]); ++i)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync SSMR3GetMem (pSSMHandle, s->mixer_data, sizeof (s->mixer_data));
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 * Reset notification.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pDevIns The device instance data.
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.
b2bc8de1367ae24e1b27b53921d0b32ee3df7acdvboxsyncstatic DECLCALLBACK(void) ac97Reset(PPDMDEVINS pDevIns)
switch (enmInterface)
case PDMINTERFACE_BASE:
return NULL;
int rc;
return rc;
return rc;
return rc;
return rc;
return rc;
if (!s->voice_pi)
if (!s->voice_mc)
if (!s->voice_po)
#ifndef __DARWIN__
bool fComma = false;
if (!s->voice_pi)
fComma = true;
if (!s->voice_po)
fComma = true;
if (!s->voice_mc)
return VINF_SUCCESS;
sizeof(PCIAC97LinkState),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,