From bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 Mon Sep 17 00:00:00 2001 From: RajithaY Date: Tue, 25 Apr 2017 03:31:15 -0700 Subject: Adding qemu as a submodule of KVMFORNFV This Patch includes the changes to add qemu as a submodule to kvmfornfv repo and make use of the updated latest qemu for the execution of all testcase Change-Id: I1280af507a857675c7f81d30c95255635667bdd7 Signed-off-by:RajithaY --- qemu/hw/audio/Makefile.objs | 18 - qemu/hw/audio/ac97.c | 1431 ------------------------------------- qemu/hw/audio/adlib.c | 386 ---------- qemu/hw/audio/cs4231.c | 187 ----- qemu/hw/audio/cs4231a.c | 715 ------------------- qemu/hw/audio/es1370.c | 1080 ---------------------------- qemu/hw/audio/fmopl.c | 1391 ------------------------------------ qemu/hw/audio/fmopl.h | 174 ----- qemu/hw/audio/gus.c | 321 --------- qemu/hw/audio/gusemu.h | 104 --- qemu/hw/audio/gusemu_hal.c | 555 --------------- qemu/hw/audio/gusemu_mixer.c | 241 ------- qemu/hw/audio/gustate.h | 132 ---- qemu/hw/audio/hda-codec-common.h | 456 ------------ qemu/hw/audio/hda-codec.c | 732 ------------------- qemu/hw/audio/intel-hda-defs.h | 717 ------------------- qemu/hw/audio/intel-hda.c | 1344 ----------------------------------- qemu/hw/audio/intel-hda.h | 72 -- qemu/hw/audio/lm4549.c | 335 --------- qemu/hw/audio/lm4549.h | 43 -- qemu/hw/audio/marvell_88w8618.c | 307 -------- qemu/hw/audio/milkymist-ac97.c | 349 --------- qemu/hw/audio/pcspk.c | 214 ------ qemu/hw/audio/pl041.c | 650 ----------------- qemu/hw/audio/pl041.h | 135 ---- qemu/hw/audio/pl041.hx | 81 --- qemu/hw/audio/sb16.c | 1436 -------------------------------------- qemu/hw/audio/wm8750.c | 723 ------------------- 28 files changed, 14329 deletions(-) delete mode 100644 qemu/hw/audio/Makefile.objs delete mode 100644 qemu/hw/audio/ac97.c delete mode 100644 qemu/hw/audio/adlib.c delete mode 100644 qemu/hw/audio/cs4231.c delete mode 100644 qemu/hw/audio/cs4231a.c delete mode 100644 qemu/hw/audio/es1370.c delete mode 100644 qemu/hw/audio/fmopl.c delete mode 100644 qemu/hw/audio/fmopl.h delete mode 100644 qemu/hw/audio/gus.c delete mode 100644 qemu/hw/audio/gusemu.h delete mode 100644 qemu/hw/audio/gusemu_hal.c delete mode 100644 qemu/hw/audio/gusemu_mixer.c delete mode 100644 qemu/hw/audio/gustate.h delete mode 100644 qemu/hw/audio/hda-codec-common.h delete mode 100644 qemu/hw/audio/hda-codec.c delete mode 100644 qemu/hw/audio/intel-hda-defs.h delete mode 100644 qemu/hw/audio/intel-hda.c delete mode 100644 qemu/hw/audio/intel-hda.h delete mode 100644 qemu/hw/audio/lm4549.c delete mode 100644 qemu/hw/audio/lm4549.h delete mode 100644 qemu/hw/audio/marvell_88w8618.c delete mode 100644 qemu/hw/audio/milkymist-ac97.c delete mode 100644 qemu/hw/audio/pcspk.c delete mode 100644 qemu/hw/audio/pl041.c delete mode 100644 qemu/hw/audio/pl041.h delete mode 100644 qemu/hw/audio/pl041.hx delete mode 100644 qemu/hw/audio/sb16.c delete mode 100644 qemu/hw/audio/wm8750.c (limited to 'qemu/hw/audio') diff --git a/qemu/hw/audio/Makefile.objs b/qemu/hw/audio/Makefile.objs deleted file mode 100644 index 7ce85a2e8..000000000 --- a/qemu/hw/audio/Makefile.objs +++ /dev/null @@ -1,18 +0,0 @@ -# Sound -common-obj-$(CONFIG_SB16) += sb16.o -common-obj-$(CONFIG_ES1370) += es1370.o -common-obj-$(CONFIG_AC97) += ac97.o -common-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o -common-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o -common-obj-$(CONFIG_CS4231A) += cs4231a.o -common-obj-$(CONFIG_HDA) += intel-hda.o hda-codec.o - -common-obj-$(CONFIG_PCSPK) += pcspk.o -common-obj-$(CONFIG_WM8750) += wm8750.o -common-obj-$(CONFIG_PL041) += pl041.o lm4549.o - -common-obj-$(CONFIG_CS4231) += cs4231.o -common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o -common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o - -$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0 diff --git a/qemu/hw/audio/ac97.c b/qemu/hw/audio/ac97.c deleted file mode 100644 index cbd959e0b..000000000 --- a/qemu/hw/audio/ac97.c +++ /dev/null @@ -1,1431 +0,0 @@ -/* - * Copyright (C) 2006 InnoTek Systemberatung GmbH - * - * This file is part of VirtualBox Open Source Edition (OSE), as - * available from http://www.virtualbox.org. This file is free software; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License as published by the Free Software Foundation, - * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE - * distribution. VirtualBox OSE is distributed in the hope that it will - * be useful, but WITHOUT ANY WARRANTY of any kind. - * - * If you received this file as part of a commercial VirtualBox - * distribution, then only the terms of your commercial VirtualBox - * license agreement apply instead of the previous paragraph. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "hw/pci/pci.h" -#include "sysemu/dma.h" - -enum { - AC97_Reset = 0x00, - AC97_Master_Volume_Mute = 0x02, - AC97_Headphone_Volume_Mute = 0x04, - AC97_Master_Volume_Mono_Mute = 0x06, - AC97_Master_Tone_RL = 0x08, - AC97_PC_BEEP_Volume_Mute = 0x0A, - AC97_Phone_Volume_Mute = 0x0C, - AC97_Mic_Volume_Mute = 0x0E, - AC97_Line_In_Volume_Mute = 0x10, - AC97_CD_Volume_Mute = 0x12, - AC97_Video_Volume_Mute = 0x14, - AC97_Aux_Volume_Mute = 0x16, - AC97_PCM_Out_Volume_Mute = 0x18, - AC97_Record_Select = 0x1A, - AC97_Record_Gain_Mute = 0x1C, - AC97_Record_Gain_Mic_Mute = 0x1E, - AC97_General_Purpose = 0x20, - AC97_3D_Control = 0x22, - AC97_AC_97_RESERVED = 0x24, - AC97_Powerdown_Ctrl_Stat = 0x26, - AC97_Extended_Audio_ID = 0x28, - AC97_Extended_Audio_Ctrl_Stat = 0x2A, - AC97_PCM_Front_DAC_Rate = 0x2C, - AC97_PCM_Surround_DAC_Rate = 0x2E, - AC97_PCM_LFE_DAC_Rate = 0x30, - AC97_PCM_LR_ADC_Rate = 0x32, - AC97_MIC_ADC_Rate = 0x34, - AC97_6Ch_Vol_C_LFE_Mute = 0x36, - AC97_6Ch_Vol_L_R_Surround_Mute = 0x38, - AC97_Vendor_Reserved = 0x58, - AC97_Sigmatel_Analog = 0x6c, /* We emulate a Sigmatel codec */ - AC97_Sigmatel_Dac2Invert = 0x6e, /* We emulate a Sigmatel codec */ - AC97_Vendor_ID1 = 0x7c, - AC97_Vendor_ID2 = 0x7e -}; - -#define SOFT_VOLUME -#define SR_FIFOE 16 /* rwc */ -#define SR_BCIS 8 /* rwc */ -#define SR_LVBCI 4 /* rwc */ -#define SR_CELV 2 /* ro */ -#define SR_DCH 1 /* ro */ -#define SR_VALID_MASK ((1 << 5) - 1) -#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI) -#define SR_RO_MASK (SR_DCH | SR_CELV) -#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI) - -#define CR_IOCE 16 /* rw */ -#define CR_FEIE 8 /* rw */ -#define CR_LVBIE 4 /* rw */ -#define CR_RR 2 /* rw */ -#define CR_RPBM 1 /* rw */ -#define CR_VALID_MASK ((1 << 5) - 1) -#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE) - -#define GC_WR 4 /* rw */ -#define GC_CR 2 /* rw */ -#define GC_VALID_MASK ((1 << 6) - 1) - -#define GS_MD3 (1<<17) /* rw */ -#define GS_AD3 (1<<16) /* rw */ -#define GS_RCS (1<<15) /* rwc */ -#define GS_B3S12 (1<<14) /* ro */ -#define GS_B2S12 (1<<13) /* ro */ -#define GS_B1S12 (1<<12) /* ro */ -#define GS_S1R1 (1<<11) /* rwc */ -#define GS_S0R1 (1<<10) /* rwc */ -#define GS_S1CR (1<<9) /* ro */ -#define GS_S0CR (1<<8) /* ro */ -#define GS_MINT (1<<7) /* ro */ -#define GS_POINT (1<<6) /* ro */ -#define GS_PIINT (1<<5) /* ro */ -#define GS_RSRVD ((1<<4)|(1<<3)) -#define GS_MOINT (1<<2) /* ro */ -#define GS_MIINT (1<<1) /* ro */ -#define GS_GSCI 1 /* rwc */ -#define GS_RO_MASK (GS_B3S12| \ - GS_B2S12| \ - GS_B1S12| \ - GS_S1CR| \ - GS_S0CR| \ - GS_MINT| \ - GS_POINT| \ - GS_PIINT| \ - GS_RSRVD| \ - GS_MOINT| \ - GS_MIINT) -#define GS_VALID_MASK ((1 << 18) - 1) -#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI) - -#define BD_IOC (1<<31) -#define BD_BUP (1<<30) - -#define EACS_VRA 1 -#define EACS_VRM 8 - -#define MUTE_SHIFT 15 - -#define REC_MASK 7 -enum { - REC_MIC = 0, - REC_CD, - REC_VIDEO, - REC_AUX, - REC_LINE_IN, - REC_STEREO_MIX, - REC_MONO_MIX, - REC_PHONE -}; - -typedef struct BD { - uint32_t addr; - uint32_t ctl_len; -} BD; - -typedef struct AC97BusMasterRegs { - uint32_t bdbar; /* rw 0 */ - uint8_t civ; /* ro 0 */ - uint8_t lvi; /* rw 0 */ - uint16_t sr; /* rw 1 */ - uint16_t picb; /* ro 0 */ - uint8_t piv; /* ro 0 */ - uint8_t cr; /* rw 0 */ - unsigned int bd_valid; - BD bd; -} AC97BusMasterRegs; - -typedef struct AC97LinkState { - PCIDevice dev; - QEMUSoundCard card; - uint32_t use_broken_id; - uint32_t glob_cnt; - uint32_t glob_sta; - uint32_t cas; - uint32_t last_samp; - AC97BusMasterRegs bm_regs[3]; - uint8_t mixer_data[256]; - SWVoiceIn *voice_pi; - SWVoiceOut *voice_po; - SWVoiceIn *voice_mc; - int invalid_freq[3]; - uint8_t silence[128]; - int bup_flag; - MemoryRegion io_nam; - MemoryRegion io_nabm; -} AC97LinkState; - -enum { - BUP_SET = 1, - BUP_LAST = 2 -}; - -#ifdef DEBUG_AC97 -#define dolog(...) AUD_log ("ac97", __VA_ARGS__) -#else -#define dolog(...) -#endif - -#define MKREGS(prefix, start) \ -enum { \ - prefix ## _BDBAR = start, \ - prefix ## _CIV = start + 4, \ - prefix ## _LVI = start + 5, \ - prefix ## _SR = start + 6, \ - prefix ## _PICB = start + 8, \ - prefix ## _PIV = start + 10, \ - prefix ## _CR = start + 11 \ -} - -enum { - PI_INDEX = 0, - PO_INDEX, - MC_INDEX, - LAST_INDEX -}; - -MKREGS (PI, PI_INDEX * 16); -MKREGS (PO, PO_INDEX * 16); -MKREGS (MC, MC_INDEX * 16); - -enum { - GLOB_CNT = 0x2c, - GLOB_STA = 0x30, - CAS = 0x34 -}; - -#define GET_BM(index) (((index) >> 4) & 3) - -static void po_callback (void *opaque, int free); -static void pi_callback (void *opaque, int avail); -static void mc_callback (void *opaque, int avail); - -static void warm_reset (AC97LinkState *s) -{ - (void) s; -} - -static void cold_reset (AC97LinkState * s) -{ - (void) s; -} - -static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r) -{ - uint8_t b[8]; - - pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8); - r->bd_valid = 1; - r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3; - r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]); - r->picb = r->bd.ctl_len & 0xffff; - dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n", - r->civ, r->bd.addr, r->bd.ctl_len >> 16, - r->bd.ctl_len & 0xffff, - (r->bd.ctl_len & 0xffff) << 1); -} - -static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr) -{ - int event = 0; - int level = 0; - uint32_t new_mask = new_sr & SR_INT_MASK; - uint32_t old_mask = r->sr & SR_INT_MASK; - uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT}; - - if (new_mask ^ old_mask) { - /** @todo is IRQ deasserted when only one of status bits is cleared? */ - if (!new_mask) { - event = 1; - level = 0; - } - else { - if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) { - event = 1; - level = 1; - } - if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) { - event = 1; - level = 1; - } - } - } - - r->sr = new_sr; - - dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n", - r->sr & SR_BCIS, r->sr & SR_LVBCI, - r->sr, - event, level); - - if (!event) - return; - - if (level) { - s->glob_sta |= masks[r - s->bm_regs]; - dolog ("set irq level=1\n"); - pci_irq_assert(&s->dev); - } - else { - s->glob_sta &= ~masks[r - s->bm_regs]; - dolog ("set irq level=0\n"); - pci_irq_deassert(&s->dev); - } -} - -static void voice_set_active (AC97LinkState *s, int bm_index, int on) -{ - switch (bm_index) { - case PI_INDEX: - AUD_set_active_in (s->voice_pi, on); - break; - - case PO_INDEX: - AUD_set_active_out (s->voice_po, on); - break; - - case MC_INDEX: - AUD_set_active_in (s->voice_mc, on); - break; - - default: - AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index); - break; - } -} - -static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r) -{ - dolog ("reset_bm_regs\n"); - r->bdbar = 0; - r->civ = 0; - r->lvi = 0; - /** todo do we need to do that? */ - update_sr (s, r, SR_DCH); - r->picb = 0; - r->piv = 0; - r->cr = r->cr & CR_DONT_CLEAR_MASK; - r->bd_valid = 0; - - voice_set_active (s, r - s->bm_regs, 0); - memset (s->silence, 0, sizeof (s->silence)); -} - -static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v) -{ - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); - return; - } - - s->mixer_data[i + 0] = v & 0xff; - s->mixer_data[i + 1] = v >> 8; -} - -static uint16_t mixer_load (AC97LinkState *s, uint32_t i) -{ - uint16_t val = 0xffff; - - if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_load: index %d out of bounds %zd\n", - i, sizeof (s->mixer_data)); - } - else { - val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8); - } - - return val; -} - -static void open_voice (AC97LinkState *s, int index, int freq) -{ - struct audsettings as; - - as.freq = freq; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 0; - - if (freq > 0) { - s->invalid_freq[index] = 0; - switch (index) { - case PI_INDEX: - s->voice_pi = AUD_open_in ( - &s->card, - s->voice_pi, - "ac97.pi", - s, - pi_callback, - &as - ); - break; - - case PO_INDEX: - s->voice_po = AUD_open_out ( - &s->card, - s->voice_po, - "ac97.po", - s, - po_callback, - &as - ); - break; - - case MC_INDEX: - s->voice_mc = AUD_open_in ( - &s->card, - s->voice_mc, - "ac97.mc", - s, - mc_callback, - &as - ); - break; - } - } - else { - s->invalid_freq[index] = freq; - switch (index) { - case PI_INDEX: - AUD_close_in (&s->card, s->voice_pi); - s->voice_pi = NULL; - break; - - case PO_INDEX: - AUD_close_out (&s->card, s->voice_po); - s->voice_po = NULL; - break; - - case MC_INDEX: - AUD_close_in (&s->card, s->voice_mc); - s->voice_mc = NULL; - break; - } - } -} - -static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) -{ - uint16_t freq; - - freq = mixer_load (s, AC97_PCM_LR_ADC_Rate); - open_voice (s, PI_INDEX, freq); - AUD_set_active_in (s->voice_pi, active[PI_INDEX]); - - freq = mixer_load (s, AC97_PCM_Front_DAC_Rate); - open_voice (s, PO_INDEX, freq); - AUD_set_active_out (s->voice_po, active[PO_INDEX]); - - freq = mixer_load (s, AC97_MIC_ADC_Rate); - open_voice (s, MC_INDEX, freq); - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); -} - -static void get_volume (uint16_t vol, uint16_t mask, int inverse, - int *mute, uint8_t *lvol, uint8_t *rvol) -{ - *mute = (vol >> MUTE_SHIFT) & 1; - *rvol = (255 * (vol & mask)) / mask; - *lvol = (255 * ((vol >> 8) & mask)) / mask; - - if (inverse) { - *rvol = 255 - *rvol; - *lvol = 255 - *lvol; - } -} - -static void update_combined_volume_out (AC97LinkState *s) -{ - uint8_t lvol, rvol, plvol, prvol; - int mute, pmute; - - get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, - &mute, &lvol, &rvol); - get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1, - &pmute, &plvol, &prvol); - - mute = mute | pmute; - lvol = (lvol * plvol) / 255; - rvol = (rvol * prvol) / 255; - - AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -} - -static void update_volume_in (AC97LinkState *s) -{ - uint8_t lvol, rvol; - int mute; - - get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, - &mute, &lvol, &rvol); - - AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); -} - -static void set_volume (AC97LinkState *s, int index, uint32_t val) -{ - switch (index) { - case AC97_Master_Volume_Mute: - val &= 0xbf3f; - mixer_store (s, index, val); - update_combined_volume_out (s); - break; - case AC97_PCM_Out_Volume_Mute: - val &= 0x9f1f; - mixer_store (s, index, val); - update_combined_volume_out (s); - break; - case AC97_Record_Gain_Mute: - val &= 0x8f0f; - mixer_store (s, index, val); - update_volume_in (s); - break; - } -} - -static void record_select (AC97LinkState *s, uint32_t val) -{ - uint8_t rs = val & REC_MASK; - uint8_t ls = (val >> 8) & REC_MASK; - mixer_store (s, AC97_Record_Select, rs | (ls << 8)); -} - -static void mixer_reset (AC97LinkState *s) -{ - uint8_t active[LAST_INDEX]; - - dolog ("mixer_reset\n"); - memset (s->mixer_data, 0, sizeof (s->mixer_data)); - memset (active, 0, sizeof (active)); - mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Headphone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000); - mixer_store (s, AC97_Master_Tone_RL, 0x0000); - mixer_store (s, AC97_PC_BEEP_Volume_Mute , 0x0000); - mixer_store (s, AC97_Phone_Volume_Mute , 0x0000); - mixer_store (s, AC97_Mic_Volume_Mute , 0x0000); - mixer_store (s, AC97_Line_In_Volume_Mute , 0x0000); - mixer_store (s, AC97_CD_Volume_Mute , 0x0000); - mixer_store (s, AC97_Video_Volume_Mute , 0x0000); - mixer_store (s, AC97_Aux_Volume_Mute , 0x0000); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x0000); - mixer_store (s, AC97_General_Purpose , 0x0000); - mixer_store (s, AC97_3D_Control , 0x0000); - mixer_store (s, AC97_Powerdown_Ctrl_Stat , 0x000f); - - /* - * Sigmatel 9700 (STAC9700) - */ - mixer_store (s, AC97_Vendor_ID1 , 0x8384); - mixer_store (s, AC97_Vendor_ID2 , 0x7600); /* 7608 */ - - mixer_store (s, AC97_Extended_Audio_ID , 0x0809); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009); - mixer_store (s, AC97_PCM_Front_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_Surround_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LFE_DAC_Rate , 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); - - record_select (s, 0); - set_volume (s, AC97_Master_Volume_Mute, 0x8000); - set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); - set_volume (s, AC97_Record_Gain_Mute, 0x8808); - - reset_voices (s, active); -} - -/** - * Native audio mixer - * I/O Reads - */ -static uint32_t nam_readb (void *opaque, uint32_t addr) -{ - AC97LinkState *s = opaque; - dolog ("U nam readb %#x\n", addr); - s->cas = 0; - return ~0U; -} - -static uint32_t nam_readw (void *opaque, uint32_t addr) -{ - AC97LinkState *s = opaque; - uint32_t val = ~0U; - uint32_t index = addr; - s->cas = 0; - val = mixer_load (s, index); - return val; -} - -static uint32_t nam_readl (void *opaque, uint32_t addr) -{ - AC97LinkState *s = opaque; - dolog ("U nam readl %#x\n", addr); - s->cas = 0; - return ~0U; -} - -/** - * Native audio mixer - * I/O Writes - */ -static void nam_writeb (void *opaque, uint32_t addr, uint32_t val) -{ - AC97LinkState *s = opaque; - dolog ("U nam writeb %#x <- %#x\n", addr, val); - s->cas = 0; -} - -static void nam_writew (void *opaque, uint32_t addr, uint32_t val) -{ - AC97LinkState *s = opaque; - uint32_t index = addr; - s->cas = 0; - switch (index) { - case AC97_Reset: - mixer_reset (s); - break; - case AC97_Powerdown_Ctrl_Stat: - val &= ~0x800f; - val |= mixer_load (s, index) & 0xf; - mixer_store (s, index, val); - break; - case AC97_PCM_Out_Volume_Mute: - case AC97_Master_Volume_Mute: - case AC97_Record_Gain_Mute: - set_volume (s, index, val); - break; - case AC97_Record_Select: - record_select (s, val); - break; - case AC97_Vendor_ID1: - case AC97_Vendor_ID2: - dolog ("Attempt to write vendor ID to %#x\n", val); - break; - case AC97_Extended_Audio_ID: - dolog ("Attempt to write extended audio ID to %#x\n", val); - break; - case AC97_Extended_Audio_Ctrl_Stat: - if (!(val & EACS_VRA)) { - mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80); - mixer_store (s, AC97_PCM_LR_ADC_Rate, 0xbb80); - open_voice (s, PI_INDEX, 48000); - open_voice (s, PO_INDEX, 48000); - } - if (!(val & EACS_VRM)) { - mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); - open_voice (s, MC_INDEX, 48000); - } - dolog ("Setting extended audio control to %#x\n", val); - mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val); - break; - case AC97_PCM_Front_DAC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front DAC rate to %d\n", val); - open_voice (s, PO_INDEX, val); - } - else { - dolog ("Attempt to set front DAC rate to %d, " - "but VRA is not set\n", - val); - } - break; - case AC97_MIC_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) { - mixer_store (s, index, val); - dolog ("Set MIC ADC rate to %d\n", val); - open_voice (s, MC_INDEX, val); - } - else { - dolog ("Attempt to set MIC ADC rate to %d, " - "but VRM is not set\n", - val); - } - break; - case AC97_PCM_LR_ADC_Rate: - if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) { - mixer_store (s, index, val); - dolog ("Set front LR ADC rate to %d\n", val); - open_voice (s, PI_INDEX, val); - } - else { - dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n", - val); - } - break; - case AC97_Headphone_Volume_Mute: - case AC97_Master_Volume_Mono_Mute: - case AC97_Master_Tone_RL: - case AC97_PC_BEEP_Volume_Mute: - case AC97_Phone_Volume_Mute: - case AC97_Mic_Volume_Mute: - case AC97_Line_In_Volume_Mute: - case AC97_CD_Volume_Mute: - case AC97_Video_Volume_Mute: - case AC97_Aux_Volume_Mute: - case AC97_Record_Gain_Mic_Mute: - case AC97_General_Purpose: - case AC97_3D_Control: - case AC97_Sigmatel_Analog: - case AC97_Sigmatel_Dac2Invert: - /* None of the features in these regs are emulated, so they are RO */ - break; - default: - dolog ("U nam writew %#x <- %#x\n", addr, val); - mixer_store (s, index, val); - break; - } -} - -static void nam_writel (void *opaque, uint32_t addr, uint32_t val) -{ - AC97LinkState *s = opaque; - dolog ("U nam writel %#x <- %#x\n", addr, val); - s->cas = 0; -} - -/** - * Native audio bus master - * I/O Reads - */ -static uint32_t nabm_readb (void *opaque, uint32_t addr) -{ - AC97LinkState *s = opaque; - AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - uint32_t val = ~0U; - - switch (index) { - case CAS: - dolog ("CAS %d\n", s->cas); - val = s->cas; - s->cas = 1; - break; - case PI_CIV: - case PO_CIV: - case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; - val = r->civ; - dolog ("CIV[%d] -> %#x\n", GET_BM (index), val); - break; - case PI_LVI: - case PO_LVI: - case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; - val = r->lvi; - dolog ("LVI[%d] -> %#x\n", GET_BM (index), val); - break; - case PI_PIV: - case PO_PIV: - case MC_PIV: - r = &s->bm_regs[GET_BM (index)]; - val = r->piv; - dolog ("PIV[%d] -> %#x\n", GET_BM (index), val); - break; - case PI_CR: - case PO_CR: - case MC_CR: - r = &s->bm_regs[GET_BM (index)]; - val = r->cr; - dolog ("CR[%d] -> %#x\n", GET_BM (index), val); - break; - case PI_SR: - case PO_SR: - case MC_SR: - r = &s->bm_regs[GET_BM (index)]; - val = r->sr & 0xff; - dolog ("SRb[%d] -> %#x\n", GET_BM (index), val); - break; - default: - dolog ("U nabm readb %#x -> %#x\n", addr, val); - break; - } - return val; -} - -static uint32_t nabm_readw (void *opaque, uint32_t addr) -{ - AC97LinkState *s = opaque; - AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - uint32_t val = ~0U; - - switch (index) { - case PI_SR: - case PO_SR: - case MC_SR: - r = &s->bm_regs[GET_BM (index)]; - val = r->sr; - dolog ("SR[%d] -> %#x\n", GET_BM (index), val); - break; - case PI_PICB: - case PO_PICB: - case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; - val = r->picb; - dolog ("PICB[%d] -> %#x\n", GET_BM (index), val); - break; - default: - dolog ("U nabm readw %#x -> %#x\n", addr, val); - break; - } - return val; -} - -static uint32_t nabm_readl (void *opaque, uint32_t addr) -{ - AC97LinkState *s = opaque; - AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - uint32_t val = ~0U; - - switch (index) { - case PI_BDBAR: - case PO_BDBAR: - case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; - val = r->bdbar; - dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val); - break; - case PI_CIV: - case PO_CIV: - case MC_CIV: - r = &s->bm_regs[GET_BM (index)]; - val = r->civ | (r->lvi << 8) | (r->sr << 16); - dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index), - r->civ, r->lvi, r->sr); - break; - case PI_PICB: - case PO_PICB: - case MC_PICB: - r = &s->bm_regs[GET_BM (index)]; - val = r->picb | (r->piv << 16) | (r->cr << 24); - dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index), - val, r->picb, r->piv, r->cr); - break; - case GLOB_CNT: - val = s->glob_cnt; - dolog ("glob_cnt -> %#x\n", val); - break; - case GLOB_STA: - val = s->glob_sta | GS_S0CR; - dolog ("glob_sta -> %#x\n", val); - break; - default: - dolog ("U nabm readl %#x -> %#x\n", addr, val); - break; - } - return val; -} - -/** - * Native audio bus master - * I/O Writes - */ -static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val) -{ - AC97LinkState *s = opaque; - AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { - case PI_LVI: - case PO_LVI: - case MC_LVI: - r = &s->bm_regs[GET_BM (index)]; - if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) { - r->sr &= ~(SR_DCH | SR_CELV); - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); - } - r->lvi = val % 32; - dolog ("LVI[%d] <- %#x\n", GET_BM (index), val); - break; - case PI_CR: - case PO_CR: - case MC_CR: - r = &s->bm_regs[GET_BM (index)]; - if (val & CR_RR) { - reset_bm_regs (s, r); - } - else { - r->cr = val & CR_VALID_MASK; - if (!(r->cr & CR_RPBM)) { - voice_set_active (s, r - s->bm_regs, 0); - r->sr |= SR_DCH; - } - else { - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); - r->sr &= ~SR_DCH; - voice_set_active (s, r - s->bm_regs, 1); - } - } - dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr); - break; - case PI_SR: - case PO_SR: - case MC_SR: - r = &s->bm_regs[GET_BM (index)]; - r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); - break; - default: - dolog ("U nabm writeb %#x <- %#x\n", addr, val); - break; - } -} - -static void nabm_writew (void *opaque, uint32_t addr, uint32_t val) -{ - AC97LinkState *s = opaque; - AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { - case PI_SR: - case PO_SR: - case MC_SR: - r = &s->bm_regs[GET_BM (index)]; - r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK); - update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK)); - dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr); - break; - default: - dolog ("U nabm writew %#x <- %#x\n", addr, val); - break; - } -} - -static void nabm_writel (void *opaque, uint32_t addr, uint32_t val) -{ - AC97LinkState *s = opaque; - AC97BusMasterRegs *r = NULL; - uint32_t index = addr; - switch (index) { - case PI_BDBAR: - case PO_BDBAR: - case MC_BDBAR: - r = &s->bm_regs[GET_BM (index)]; - r->bdbar = val & ~3; - dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n", - GET_BM (index), val, r->bdbar); - break; - case GLOB_CNT: - if (val & GC_WR) - warm_reset (s); - if (val & GC_CR) - cold_reset (s); - if (!(val & (GC_WR | GC_CR))) - s->glob_cnt = val & GC_VALID_MASK; - dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt); - break; - case GLOB_STA: - s->glob_sta &= ~(val & GS_WCLEAR_MASK); - s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK; - dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta); - break; - default: - dolog ("U nabm writel %#x <- %#x\n", addr, val); - break; - } -} - -static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) -{ - uint8_t tmpbuf[4096]; - uint32_t addr = r->bd.addr; - uint32_t temp = r->picb << 1; - uint32_t written = 0; - int to_copy = 0; - temp = audio_MIN (temp, max); - - if (!temp) { - *stop = 1; - return 0; - } - - while (temp) { - int copied; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); - pci_dma_read (&s->dev, addr, tmpbuf, to_copy); - copied = AUD_write (s->voice_po, tmpbuf, to_copy); - dolog ("write_audio max=%x to_copy=%x copied=%x\n", - max, to_copy, copied); - if (!copied) { - *stop = 1; - break; - } - temp -= copied; - addr += copied; - written += copied; - } - - if (!temp) { - if (to_copy < 4) { - dolog ("whoops\n"); - s->last_samp = 0; - } - else { - s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4]; - } - } - - r->bd.addr = addr; - return written; -} - -static void write_bup (AC97LinkState *s, int elapsed) -{ - dolog ("write_bup\n"); - if (!(s->bup_flag & BUP_SET)) { - if (s->bup_flag & BUP_LAST) { - int i; - uint8_t *p = s->silence; - for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) { - *(uint32_t *) p = s->last_samp; - } - } - else { - memset (s->silence, 0, sizeof (s->silence)); - } - s->bup_flag |= BUP_SET; - } - - while (elapsed) { - int temp = audio_MIN (elapsed, sizeof (s->silence)); - while (temp) { - int copied = AUD_write (s->voice_po, s->silence, temp); - if (!copied) - return; - temp -= copied; - elapsed -= copied; - } - } -} - -static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r, - int max, int *stop) -{ - uint8_t tmpbuf[4096]; - uint32_t addr = r->bd.addr; - uint32_t temp = r->picb << 1; - uint32_t nread = 0; - int to_copy = 0; - SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi; - - temp = audio_MIN (temp, max); - - if (!temp) { - *stop = 1; - return 0; - } - - while (temp) { - int acquired; - to_copy = audio_MIN (temp, sizeof (tmpbuf)); - acquired = AUD_read (voice, tmpbuf, to_copy); - if (!acquired) { - *stop = 1; - break; - } - pci_dma_write (&s->dev, addr, tmpbuf, acquired); - temp -= acquired; - addr += acquired; - nread += acquired; - } - - r->bd.addr = addr; - return nread; -} - -static void transfer_audio (AC97LinkState *s, int index, int elapsed) -{ - AC97BusMasterRegs *r = &s->bm_regs[index]; - int stop = 0; - - if (s->invalid_freq[index]) { - AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n", - index, s->invalid_freq[index]); - return; - } - - if (r->sr & SR_DCH) { - if (r->cr & CR_RPBM) { - switch (index) { - case PO_INDEX: - write_bup (s, elapsed); - break; - } - } - return; - } - - while ((elapsed >> 1) && !stop) { - int temp; - - if (!r->bd_valid) { - dolog ("invalid bd\n"); - fetch_bd (s, r); - } - - if (!r->picb) { - dolog ("fresh bd %d is empty %#x %#x\n", - r->civ, r->bd.addr, r->bd.ctl_len); - if (r->civ == r->lvi) { - r->sr |= SR_DCH; /* CELV? */ - s->bup_flag = 0; - break; - } - r->sr &= ~SR_CELV; - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); - return; - } - - switch (index) { - case PO_INDEX: - temp = write_audio (s, r, elapsed, &stop); - elapsed -= temp; - r->picb -= (temp >> 1); - break; - - case PI_INDEX: - case MC_INDEX: - temp = read_audio (s, r, elapsed, &stop); - elapsed -= temp; - r->picb -= (temp >> 1); - break; - } - - if (!r->picb) { - uint32_t new_sr = r->sr & ~SR_CELV; - - if (r->bd.ctl_len & BD_IOC) { - new_sr |= SR_BCIS; - } - - if (r->civ == r->lvi) { - dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi); - - new_sr |= SR_LVBCI | SR_DCH | SR_CELV; - stop = 1; - s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0; - } - else { - r->civ = r->piv; - r->piv = (r->piv + 1) % 32; - fetch_bd (s, r); - } - - update_sr (s, r, new_sr); - } - } -} - -static void pi_callback (void *opaque, int avail) -{ - transfer_audio (opaque, PI_INDEX, avail); -} - -static void mc_callback (void *opaque, int avail) -{ - transfer_audio (opaque, MC_INDEX, avail); -} - -static void po_callback (void *opaque, int free) -{ - transfer_audio (opaque, PO_INDEX, free); -} - -static const VMStateDescription vmstate_ac97_bm_regs = { - .name = "ac97_bm_regs", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32 (bdbar, AC97BusMasterRegs), - VMSTATE_UINT8 (civ, AC97BusMasterRegs), - VMSTATE_UINT8 (lvi, AC97BusMasterRegs), - VMSTATE_UINT16 (sr, AC97BusMasterRegs), - VMSTATE_UINT16 (picb, AC97BusMasterRegs), - VMSTATE_UINT8 (piv, AC97BusMasterRegs), - VMSTATE_UINT8 (cr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs), - VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs), - VMSTATE_END_OF_LIST () - } -}; - -static int ac97_post_load (void *opaque, int version_id) -{ - uint8_t active[LAST_INDEX]; - AC97LinkState *s = opaque; - - record_select (s, mixer_load (s, AC97_Record_Select)); - set_volume (s, AC97_Master_Volume_Mute, - mixer_load (s, AC97_Master_Volume_Mute)); - set_volume (s, AC97_PCM_Out_Volume_Mute, - mixer_load (s, AC97_PCM_Out_Volume_Mute)); - set_volume (s, AC97_Record_Gain_Mute, - mixer_load (s, AC97_Record_Gain_Mute)); - - active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); - active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); - active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); - reset_voices (s, active); - - s->bup_flag = 0; - s->last_samp = 0; - return 0; -} - -static bool is_version_2 (void *opaque, int version_id) -{ - return version_id == 2; -} - -static const VMStateDescription vmstate_ac97 = { - .name = "ac97", - .version_id = 3, - .minimum_version_id = 2, - .post_load = ac97_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE (dev, AC97LinkState), - VMSTATE_UINT32 (glob_cnt, AC97LinkState), - VMSTATE_UINT32 (glob_sta, AC97LinkState), - VMSTATE_UINT32 (cas, AC97LinkState), - VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1, - vmstate_ac97_bm_regs, AC97BusMasterRegs), - VMSTATE_BUFFER (mixer_data, AC97LinkState), - VMSTATE_UNUSED_TEST (is_version_2, 3), - VMSTATE_END_OF_LIST () - } -}; - -static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size) -{ - if ((addr / size) > 256) { - return -1; - } - - switch (size) { - case 1: - return nam_readb(opaque, addr); - case 2: - return nam_readw(opaque, addr); - case 4: - return nam_readl(opaque, addr); - default: - return -1; - } -} - -static void nam_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - if ((addr / size) > 256) { - return; - } - - switch (size) { - case 1: - nam_writeb(opaque, addr, val); - break; - case 2: - nam_writew(opaque, addr, val); - break; - case 4: - nam_writel(opaque, addr, val); - break; - } -} - -static const MemoryRegionOps ac97_io_nam_ops = { - .read = nam_read, - .write = nam_write, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size) -{ - if ((addr / size) > 64) { - return -1; - } - - switch (size) { - case 1: - return nabm_readb(opaque, addr); - case 2: - return nabm_readw(opaque, addr); - case 4: - return nabm_readl(opaque, addr); - default: - return -1; - } -} - -static void nabm_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - if ((addr / size) > 64) { - return; - } - - switch (size) { - case 1: - nabm_writeb(opaque, addr, val); - break; - case 2: - nabm_writew(opaque, addr, val); - break; - case 4: - nabm_writel(opaque, addr, val); - break; - } -} - - -static const MemoryRegionOps ac97_io_nabm_ops = { - .read = nabm_read, - .write = nabm_write, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static void ac97_on_reset (DeviceState *dev) -{ - AC97LinkState *s = container_of(dev, AC97LinkState, dev.qdev); - - reset_bm_regs (s, &s->bm_regs[0]); - reset_bm_regs (s, &s->bm_regs[1]); - reset_bm_regs (s, &s->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 (s); -} - -static void ac97_realize(PCIDevice *dev, Error **errp) -{ - AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev); - uint8_t *c = s->dev.config; - - /* TODO: no need to override */ - c[PCI_COMMAND] = 0x00; /* pcicmd pci command rw, ro */ - c[PCI_COMMAND + 1] = 0x00; - - /* TODO: */ - c[PCI_STATUS] = PCI_STATUS_FAST_BACK; /* pcists pci status rwc, ro */ - c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8; - - c[PCI_CLASS_PROG] = 0x00; /* pi programming interface ro */ - - /* TODO set when bar is registered. no need to override. */ - /* nabmar native audio mixer base address rw */ - c[PCI_BASE_ADDRESS_0] = PCI_BASE_ADDRESS_SPACE_IO; - c[PCI_BASE_ADDRESS_0 + 1] = 0x00; - c[PCI_BASE_ADDRESS_0 + 2] = 0x00; - c[PCI_BASE_ADDRESS_0 + 3] = 0x00; - - /* TODO set when bar is registered. no need to override. */ - /* nabmbar native audio bus mastering base address rw */ - c[PCI_BASE_ADDRESS_0 + 4] = PCI_BASE_ADDRESS_SPACE_IO; - c[PCI_BASE_ADDRESS_0 + 5] = 0x00; - c[PCI_BASE_ADDRESS_0 + 6] = 0x00; - c[PCI_BASE_ADDRESS_0 + 7] = 0x00; - - if (s->use_broken_id) { - c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86; - c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80; - c[PCI_SUBSYSTEM_ID] = 0x00; - c[PCI_SUBSYSTEM_ID + 1] = 0x00; - } - - c[PCI_INTERRUPT_LINE] = 0x00; /* intr_ln interrupt line rw */ - c[PCI_INTERRUPT_PIN] = 0x01; /* intr_pn interrupt pin ro */ - - memory_region_init_io (&s->io_nam, OBJECT(s), &ac97_io_nam_ops, s, - "ac97-nam", 1024); - memory_region_init_io (&s->io_nabm, OBJECT(s), &ac97_io_nabm_ops, s, - "ac97-nabm", 256); - pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam); - pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm); - AUD_register_card ("ac97", &s->card); - ac97_on_reset (&s->dev.qdev); -} - -static int ac97_init (PCIBus *bus) -{ - pci_create_simple (bus, -1, "AC97"); - return 0; -} - -static Property ac97_properties[] = { - DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0), - DEFINE_PROP_END_OF_LIST (), -}; - -static void ac97_class_init (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); - - k->realize = ac97_realize; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5; - k->revision = 0x01; - k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "Intel 82801AA AC97 Audio"; - dc->vmsd = &vmstate_ac97; - dc->props = ac97_properties; - dc->reset = ac97_on_reset; -} - -static const TypeInfo ac97_info = { - .name = "AC97", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (AC97LinkState), - .class_init = ac97_class_init, -}; - -static void ac97_register_types (void) -{ - type_register_static (&ac97_info); - pci_register_soundhw("ac97", "Intel 82801AA AC97 Audio", ac97_init); -} - -type_init (ac97_register_types) diff --git a/qemu/hw/audio/adlib.c b/qemu/hw/audio/adlib.c deleted file mode 100644 index 7836446fc..000000000 --- a/qemu/hw/audio/adlib.c +++ /dev/null @@ -1,386 +0,0 @@ -/* - * QEMU Proxy for OPL2/3 emulation by MAME team - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "hw/isa/isa.h" - -//#define DEBUG - -#define ADLIB_KILL_TIMERS 1 - -#ifdef HAS_YMF262 -#define ADLIB_DESC "Yamaha YMF262 (OPL3)" -#else -#define ADLIB_DESC "Yamaha YM3812 (OPL2)" -#endif - -#ifdef DEBUG -#include "qemu/timer.h" -#endif - -#define dolog(...) AUD_log ("adlib", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif - -#ifdef HAS_YMF262 -#include "ymf262.h" -void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); -#define SHIFT 2 -#else -#include "fmopl.h" -#define SHIFT 1 -#endif - -#define TYPE_ADLIB "adlib" -#define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB) - -typedef struct { - ISADevice parent_obj; - - QEMUSoundCard card; - uint32_t freq; - uint32_t port; - int ticking[2]; - int enabled; - int active; - int bufpos; -#ifdef DEBUG - int64_t exp[2]; -#endif - int16_t *mixbuf; - uint64_t dexp[2]; - SWVoiceOut *voice; - int left, pos, samples; - QEMUAudioTimeStamp ats; -#ifndef HAS_YMF262 - FM_OPL *opl; -#endif - PortioList port_list; -} AdlibState; - -static AdlibState *glob_adlib; - -static void adlib_stop_opl_timer (AdlibState *s, size_t n) -{ -#ifdef HAS_YMF262 - YMF262TimerOver (0, n); -#else - OPLTimerOver (s->opl, n); -#endif - s->ticking[n] = 0; -} - -static void adlib_kill_timers (AdlibState *s) -{ - size_t i; - - for (i = 0; i < 2; ++i) { - if (s->ticking[i]) { - uint64_t delta; - - delta = AUD_get_elapsed_usec_out (s->voice, &s->ats); - ldebug ( - "delta = %f dexp = %f expired => %d\n", - delta / 1000000.0, - s->dexp[i] / 1000000.0, - delta >= s->dexp[i] - ); - if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) { - adlib_stop_opl_timer (s, i); - AUD_init_time_stamp_out (s->voice, &s->ats); - } - } - } -} - -static void adlib_write(void *opaque, uint32_t nport, uint32_t val) -{ - AdlibState *s = opaque; - int a = nport & 3; - - s->active = 1; - AUD_set_active_out (s->voice, 1); - - adlib_kill_timers (s); - -#ifdef HAS_YMF262 - YMF262Write (0, a, val); -#else - OPLWrite (s->opl, a, val); -#endif -} - -static uint32_t adlib_read(void *opaque, uint32_t nport) -{ - AdlibState *s = opaque; - uint8_t data; - int a = nport & 3; - - adlib_kill_timers (s); - -#ifdef HAS_YMF262 - data = YMF262Read (0, a); -#else - data = OPLRead (s->opl, a); -#endif - return data; -} - -static void timer_handler (int c, double interval_Sec) -{ - AdlibState *s = glob_adlib; - unsigned n = c & 1; -#ifdef DEBUG - double interval; - int64_t exp; -#endif - - if (interval_Sec == 0.0) { - s->ticking[n] = 0; - return; - } - - s->ticking[n] = 1; -#ifdef DEBUG - interval = NANOSECONDS_PER_SECOND * interval_Sec; - exp = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + interval; - s->exp[n] = exp; -#endif - - s->dexp[n] = interval_Sec * 1000000.0; - AUD_init_time_stamp_out (s->voice, &s->ats); -} - -static int write_audio (AdlibState *s, int samples) -{ - int net = 0; - int pos = s->pos; - - while (samples) { - int nbytes, wbytes, wsampl; - - nbytes = samples << SHIFT; - wbytes = AUD_write ( - s->voice, - s->mixbuf + (pos << (SHIFT - 1)), - nbytes - ); - - if (wbytes) { - wsampl = wbytes >> SHIFT; - - samples -= wsampl; - pos = (pos + wsampl) % s->samples; - - net += wsampl; - } - else { - break; - } - } - - return net; -} - -static void adlib_callback (void *opaque, int free) -{ - AdlibState *s = opaque; - int samples, net = 0, to_play, written; - - samples = free >> SHIFT; - if (!(s->active && s->enabled) || !samples) { - return; - } - - to_play = audio_MIN (s->left, samples); - while (to_play) { - written = write_audio (s, to_play); - - if (written) { - s->left -= written; - samples -= written; - to_play -= written; - s->pos = (s->pos + written) % s->samples; - } - else { - return; - } - } - - samples = audio_MIN (samples, s->samples - s->pos); - if (!samples) { - return; - } - -#ifdef HAS_YMF262 - YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples); -#else - YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples); -#endif - - while (samples) { - written = write_audio (s, samples); - - if (written) { - net += written; - samples -= written; - s->pos = (s->pos + written) % s->samples; - } - else { - s->left = samples; - return; - } - } -} - -static void Adlib_fini (AdlibState *s) -{ -#ifdef HAS_YMF262 - YMF262Shutdown (); -#else - if (s->opl) { - OPLDestroy (s->opl); - s->opl = NULL; - } -#endif - - g_free(s->mixbuf); - - s->active = 0; - s->enabled = 0; - AUD_remove_card (&s->card); -} - -static MemoryRegionPortio adlib_portio_list[] = { - { 0, 4, 1, .read = adlib_read, .write = adlib_write, }, - { 0, 2, 1, .read = adlib_read, .write = adlib_write, }, - { 0x388, 4, 1, .read = adlib_read, .write = adlib_write, }, - PORTIO_END_OF_LIST(), -}; - -static void adlib_realizefn (DeviceState *dev, Error **errp) -{ - AdlibState *s = ADLIB(dev); - struct audsettings as; - - if (glob_adlib) { - error_setg (errp, "Cannot create more than 1 adlib device"); - return; - } - glob_adlib = s; - -#ifdef HAS_YMF262 - if (YMF262Init (1, 14318180, s->freq)) { - error_setg (errp, "YMF262Init %d failed", s->freq); - return; - } - else { - YMF262SetTimerHandler (0, timer_handler, 0); - s->enabled = 1; - } -#else - s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq); - if (!s->opl) { - error_setg (errp, "OPLCreate %d failed", s->freq); - return; - } - else { - OPLSetTimerHandler (s->opl, timer_handler, 0); - s->enabled = 1; - } -#endif - - as.freq = s->freq; - as.nchannels = SHIFT; - as.fmt = AUD_FMT_S16; - as.endianness = AUDIO_HOST_ENDIANNESS; - - AUD_register_card ("adlib", &s->card); - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "adlib", - s, - adlib_callback, - &as - ); - if (!s->voice) { - Adlib_fini (s); - error_setg (errp, "Initializing audio voice failed"); - return; - } - - s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT; - s->mixbuf = g_malloc0 (s->samples << SHIFT); - - adlib_portio_list[0].offset = s->port; - adlib_portio_list[1].offset = s->port + 8; - portio_list_init (&s->port_list, OBJECT(s), adlib_portio_list, s, "adlib"); - portio_list_add (&s->port_list, isa_address_space_io(&s->parent_obj), 0); -} - -static Property adlib_properties[] = { - DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220), - DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100), - DEFINE_PROP_END_OF_LIST (), -}; - -static void adlib_class_initfn (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - - dc->realize = adlib_realizefn; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = ADLIB_DESC; - dc->props = adlib_properties; -} - -static const TypeInfo adlib_info = { - .name = TYPE_ADLIB, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof (AdlibState), - .class_init = adlib_class_initfn, -}; - -static int Adlib_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_ADLIB); - return 0; -} - -static void adlib_register_types (void) -{ - type_register_static (&adlib_info); - isa_register_soundhw("adlib", ADLIB_DESC, Adlib_init); -} - -type_init (adlib_register_types) diff --git a/qemu/hw/audio/cs4231.c b/qemu/hw/audio/cs4231.c deleted file mode 100644 index caf97c169..000000000 --- a/qemu/hw/audio/cs4231.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * QEMU Crystal CS4231 audio chip emulation - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "trace.h" - -/* - * In addition to Crystal CS4231 there is a DMA controller on Sparc. - */ -#define CS_SIZE 0x40 -#define CS_REGS 16 -#define CS_DREGS 32 -#define CS_MAXDREG (CS_DREGS - 1) - -#define TYPE_CS4231 "SUNW,CS4231" -#define CS4231(obj) \ - OBJECT_CHECK(CSState, (obj), TYPE_CS4231) - -typedef struct CSState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - uint32_t regs[CS_REGS]; - uint8_t dregs[CS_DREGS]; -} CSState; - -#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG) -#define CS_VER 0xa0 -#define CS_CDC_VER 0x8a - -static void cs_reset(DeviceState *d) -{ - CSState *s = CS4231(d); - - memset(s->regs, 0, CS_REGS * 4); - memset(s->dregs, 0, CS_DREGS); - s->dregs[12] = CS_CDC_VER; - s->dregs[25] = CS_VER; -} - -static uint64_t cs_mem_read(void *opaque, hwaddr addr, - unsigned size) -{ - CSState *s = opaque; - uint32_t saddr, ret; - - saddr = addr >> 2; - switch (saddr) { - case 1: - switch (CS_RAP(s)) { - case 3: // Write only - ret = 0; - break; - default: - ret = s->dregs[CS_RAP(s)]; - break; - } - trace_cs4231_mem_readl_dreg(CS_RAP(s), ret); - break; - default: - ret = s->regs[saddr]; - trace_cs4231_mem_readl_reg(saddr, ret); - break; - } - return ret; -} - -static void cs_mem_write(void *opaque, hwaddr addr, - uint64_t val, unsigned size) -{ - CSState *s = opaque; - uint32_t saddr; - - saddr = addr >> 2; - trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val); - switch (saddr) { - case 1: - trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val); - switch(CS_RAP(s)) { - case 11: - case 25: // Read only - break; - case 12: - val &= 0x40; - val |= CS_CDC_VER; // Codec version - s->dregs[CS_RAP(s)] = val; - break; - default: - s->dregs[CS_RAP(s)] = val; - break; - } - break; - case 2: // Read only - break; - case 4: - if (val & 1) { - cs_reset(DEVICE(s)); - } - val &= 0x7f; - s->regs[saddr] = val; - break; - default: - s->regs[saddr] = val; - break; - } -} - -static const MemoryRegionOps cs_mem_ops = { - .read = cs_mem_read, - .write = cs_mem_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static const VMStateDescription vmstate_cs4231 = { - .name ="cs4231", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS), - VMSTATE_UINT8_ARRAY(dregs, CSState, CS_DREGS), - VMSTATE_END_OF_LIST() - } -}; - -static int cs4231_init1(SysBusDevice *dev) -{ - CSState *s = CS4231(dev); - - memory_region_init_io(&s->iomem, OBJECT(s), &cs_mem_ops, s, "cs4321", - CS_SIZE); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - - return 0; -} - -static Property cs4231_properties[] = { - {.name = NULL}, -}; - -static void cs4231_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = cs4231_init1; - dc->reset = cs_reset; - dc->vmsd = &vmstate_cs4231; - dc->props = cs4231_properties; -} - -static const TypeInfo cs4231_info = { - .name = TYPE_CS4231, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(CSState), - .class_init = cs4231_class_init, -}; - -static void cs4231_register_types(void) -{ - type_register_static(&cs4231_info); -} - -type_init(cs4231_register_types) diff --git a/qemu/hw/audio/cs4231a.c b/qemu/hw/audio/cs4231a.c deleted file mode 100644 index 3ecd0582b..000000000 --- a/qemu/hw/audio/cs4231a.c +++ /dev/null @@ -1,715 +0,0 @@ -/* - * QEMU Crystal CS4231 audio chip emulation - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "hw/isa/isa.h" -#include "hw/qdev.h" -#include "qemu/timer.h" - -/* - Missing features: - ADC - Loopback - Timer - ADPCM - More... -*/ - -/* #define DEBUG */ -/* #define DEBUG_XLAW */ - -static struct { - int aci_counter; -} conf = {1}; - -#ifdef DEBUG -#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__) -#else -#define dolog(...) -#endif - -#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__) -#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__) - -#define CS_REGS 16 -#define CS_DREGS 32 - -#define TYPE_CS4231A "cs4231a" -#define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A) - -typedef struct CSState { - ISADevice dev; - QEMUSoundCard card; - MemoryRegion ioports; - qemu_irq pic; - uint32_t regs[CS_REGS]; - uint8_t dregs[CS_DREGS]; - uint32_t irq; - uint32_t dma; - uint32_t port; - IsaDma *isa_dma; - int shift; - int dma_running; - int audio_free; - int transferred; - int aci_counter; - SWVoiceOut *voice; - int16_t *tab; -} CSState; - -#define MODE2 (1 << 6) -#define MCE (1 << 6) -#define PMCE (1 << 4) -#define CMCE (1 << 5) -#define TE (1 << 6) -#define PEN (1 << 0) -#define INT (1 << 0) -#define IEN (1 << 1) -#define PPIO (1 << 6) -#define PI (1 << 4) -#define CI (1 << 5) -#define TI (1 << 6) - -enum { - Index_Address, - Index_Data, - Status, - PIO_Data -}; - -enum { - Left_ADC_Input_Control, - Right_ADC_Input_Control, - Left_AUX1_Input_Control, - Right_AUX1_Input_Control, - Left_AUX2_Input_Control, - Right_AUX2_Input_Control, - Left_DAC_Output_Control, - Right_DAC_Output_Control, - FS_And_Playback_Data_Format, - Interface_Configuration, - Pin_Control, - Error_Status_And_Initialization, - MODE_And_ID, - Loopback_Control, - Playback_Upper_Base_Count, - Playback_Lower_Base_Count, - Alternate_Feature_Enable_I, - Alternate_Feature_Enable_II, - Left_Line_Input_Control, - Right_Line_Input_Control, - Timer_Low_Base, - Timer_High_Base, - RESERVED, - Alternate_Feature_Enable_III, - Alternate_Feature_Status, - Version_Chip_ID, - Mono_Input_And_Output_Control, - RESERVED_2, - Capture_Data_Format, - RESERVED_3, - Capture_Upper_Base_Count, - Capture_Lower_Base_Count -}; - -static int freqs[2][8] = { - { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 }, - { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 } -}; - -/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */ -static int16_t MuLawDecompressTable[256] = -{ - -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, - -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, - -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, - -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, - -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, - -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, - -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, - -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, - -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, - -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, - -876, -844, -812, -780, -748, -716, -684, -652, - -620, -588, -556, -524, -492, -460, -428, -396, - -372, -356, -340, -324, -308, -292, -276, -260, - -244, -228, -212, -196, -180, -164, -148, -132, - -120, -112, -104, -96, -88, -80, -72, -64, - -56, -48, -40, -32, -24, -16, -8, 0, - 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, - 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, - 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, - 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, - 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, - 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, - 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, - 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, - 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, - 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, - 876, 844, 812, 780, 748, 716, 684, 652, - 620, 588, 556, 524, 492, 460, 428, 396, - 372, 356, 340, 324, 308, 292, 276, 260, - 244, 228, 212, 196, 180, 164, 148, 132, - 120, 112, 104, 96, 88, 80, 72, 64, - 56, 48, 40, 32, 24, 16, 8, 0 -}; - -static int16_t ALawDecompressTable[256] = -{ - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, - -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, - -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, - -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, - -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, - -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, - -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472, - -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, - -344, -328, -376, -360, -280, -264, -312, -296, - -472, -456, -504, -488, -408, -392, -440, -424, - -88, -72, -120, -104, -24, -8, -56, -40, - -216, -200, -248, -232, -152, -136, -184, -168, - -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, - -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, - -688, -656, -752, -720, -560, -528, -624, -592, - -944, -912, -1008, -976, -816, -784, -880, -848, - 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, - 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, - 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, - 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, - 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, - 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, - 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, - 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, - 344, 328, 376, 360, 280, 264, 312, 296, - 472, 456, 504, 488, 408, 392, 440, 424, - 88, 72, 120, 104, 24, 8, 56, 40, - 216, 200, 248, 232, 152, 136, 184, 168, - 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, - 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, - 688, 656, 752, 720, 560, 528, 624, 592, - 944, 912, 1008, 976, 816, 784, 880, 848 -}; - -static void cs4231a_reset (DeviceState *dev) -{ - CSState *s = CS4231A (dev); - - s->regs[Index_Address] = 0x40; - s->regs[Index_Data] = 0x00; - s->regs[Status] = 0x00; - s->regs[PIO_Data] = 0x00; - - s->dregs[Left_ADC_Input_Control] = 0x00; - s->dregs[Right_ADC_Input_Control] = 0x00; - s->dregs[Left_AUX1_Input_Control] = 0x88; - s->dregs[Right_AUX1_Input_Control] = 0x88; - s->dregs[Left_AUX2_Input_Control] = 0x88; - s->dregs[Right_AUX2_Input_Control] = 0x88; - s->dregs[Left_DAC_Output_Control] = 0x80; - s->dregs[Right_DAC_Output_Control] = 0x80; - s->dregs[FS_And_Playback_Data_Format] = 0x00; - s->dregs[Interface_Configuration] = 0x08; - s->dregs[Pin_Control] = 0x00; - s->dregs[Error_Status_And_Initialization] = 0x00; - s->dregs[MODE_And_ID] = 0x8a; - s->dregs[Loopback_Control] = 0x00; - s->dregs[Playback_Upper_Base_Count] = 0x00; - s->dregs[Playback_Lower_Base_Count] = 0x00; - s->dregs[Alternate_Feature_Enable_I] = 0x00; - s->dregs[Alternate_Feature_Enable_II] = 0x00; - s->dregs[Left_Line_Input_Control] = 0x88; - s->dregs[Right_Line_Input_Control] = 0x88; - s->dregs[Timer_Low_Base] = 0x00; - s->dregs[Timer_High_Base] = 0x00; - s->dregs[RESERVED] = 0x00; - s->dregs[Alternate_Feature_Enable_III] = 0x00; - s->dregs[Alternate_Feature_Status] = 0x00; - s->dregs[Version_Chip_ID] = 0xa0; - s->dregs[Mono_Input_And_Output_Control] = 0xa0; - s->dregs[RESERVED_2] = 0x00; - s->dregs[Capture_Data_Format] = 0x00; - s->dregs[RESERVED_3] = 0x00; - s->dregs[Capture_Upper_Base_Count] = 0x00; - s->dregs[Capture_Lower_Base_Count] = 0x00; -} - -static void cs_audio_callback (void *opaque, int free) -{ - CSState *s = opaque; - s->audio_free = free; -} - -static void cs_reset_voices (CSState *s, uint32_t val) -{ - int xtal; - struct audsettings as; - IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); - -#ifdef DEBUG_XLAW - if (val == 0 || val == 32) - val = (1 << 4) | (1 << 5); -#endif - - xtal = val & 1; - as.freq = freqs[xtal][(val >> 1) & 7]; - - if (as.freq == -1) { - lerr ("unsupported frequency (val=%#x)\n", val); - goto error; - } - - as.nchannels = (val & (1 << 4)) ? 2 : 1; - as.endianness = 0; - s->tab = NULL; - - switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) { - case 0: - as.fmt = AUD_FMT_U8; - s->shift = as.nchannels == 2; - break; - - case 1: - s->tab = MuLawDecompressTable; - goto x_law; - case 3: - s->tab = ALawDecompressTable; - x_law: - as.fmt = AUD_FMT_S16; - as.endianness = AUDIO_HOST_ENDIANNESS; - s->shift = as.nchannels == 2; - break; - - case 6: - as.endianness = 1; - case 2: - as.fmt = AUD_FMT_S16; - s->shift = as.nchannels; - break; - - case 7: - case 4: - lerr ("attempt to use reserved format value (%#x)\n", val); - goto error; - - case 5: - lerr ("ADPCM 4 bit IMA compatible format is not supported\n"); - goto error; - } - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "cs4231a", - s, - cs_audio_callback, - &as - ); - - if (s->dregs[Interface_Configuration] & PEN) { - if (!s->dma_running) { - k->hold_DREQ(s->isa_dma, s->dma); - AUD_set_active_out (s->voice, 1); - s->transferred = 0; - } - s->dma_running = 1; - } - else { - if (s->dma_running) { - k->release_DREQ(s->isa_dma, s->dma); - AUD_set_active_out (s->voice, 0); - } - s->dma_running = 0; - } - return; - - error: - if (s->dma_running) { - k->release_DREQ(s->isa_dma, s->dma); - AUD_set_active_out (s->voice, 0); - } -} - -static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size) -{ - CSState *s = opaque; - uint32_t saddr, iaddr, ret; - - saddr = addr; - iaddr = ~0U; - - switch (saddr) { - case Index_Address: - ret = s->regs[saddr] & ~0x80; - break; - - case Index_Data: - if (!(s->dregs[MODE_And_ID] & MODE2)) - iaddr = s->regs[Index_Address] & 0x0f; - else - iaddr = s->regs[Index_Address] & 0x1f; - - ret = s->dregs[iaddr]; - if (iaddr == Error_Status_And_Initialization) { - /* keep SEAL happy */ - if (s->aci_counter) { - ret |= 1 << 5; - s->aci_counter -= 1; - } - } - break; - - default: - ret = s->regs[saddr]; - break; - } - dolog ("read %d:%d -> %d\n", saddr, iaddr, ret); - return ret; -} - -static void cs_write (void *opaque, hwaddr addr, - uint64_t val64, unsigned size) -{ - CSState *s = opaque; - uint32_t saddr, iaddr, val; - - saddr = addr; - val = val64; - - switch (saddr) { - case Index_Address: - if (!(s->regs[Index_Address] & MCE) && (val & MCE) - && (s->dregs[Interface_Configuration] & (3 << 3))) - s->aci_counter = conf.aci_counter; - - s->regs[Index_Address] = val & ~(1 << 7); - break; - - case Index_Data: - if (!(s->dregs[MODE_And_ID] & MODE2)) - iaddr = s->regs[Index_Address] & 0x0f; - else - iaddr = s->regs[Index_Address] & 0x1f; - - switch (iaddr) { - case RESERVED: - case RESERVED_2: - case RESERVED_3: - lwarn ("attempt to write %#x to reserved indirect register %d\n", - val, iaddr); - break; - - case FS_And_Playback_Data_Format: - if (s->regs[Index_Address] & MCE) { - cs_reset_voices (s, val); - } - else { - if (s->dregs[Alternate_Feature_Status] & PMCE) { - val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f); - cs_reset_voices (s, val); - } - else { - lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n", - s->regs[Index_Address], - s->dregs[Alternate_Feature_Status], - val); - break; - } - } - s->dregs[iaddr] = val; - break; - - case Interface_Configuration: - val &= ~(1 << 5); /* D5 is reserved */ - s->dregs[iaddr] = val; - if (val & PPIO) { - lwarn ("PIO is not supported (%#x)\n", val); - break; - } - if (val & PEN) { - if (!s->dma_running) { - cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); - } - } - else { - if (s->dma_running) { - IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); - k->release_DREQ(s->isa_dma, s->dma); - AUD_set_active_out (s->voice, 0); - s->dma_running = 0; - } - } - break; - - case Error_Status_And_Initialization: - lwarn ("attempt to write to read only register %d\n", iaddr); - break; - - case MODE_And_ID: - dolog ("val=%#x\n", val); - if (val & MODE2) - s->dregs[iaddr] |= MODE2; - else - s->dregs[iaddr] &= ~MODE2; - break; - - case Alternate_Feature_Enable_I: - if (val & TE) - lerr ("timer is not yet supported\n"); - s->dregs[iaddr] = val; - break; - - case Alternate_Feature_Status: - if ((s->dregs[iaddr] & PI) && !(val & PI)) { - /* XXX: TI CI */ - qemu_irq_lower (s->pic); - s->regs[Status] &= ~INT; - } - s->dregs[iaddr] = val; - break; - - case Version_Chip_ID: - lwarn ("write to Version_Chip_ID register %#x\n", val); - s->dregs[iaddr] = val; - break; - - default: - s->dregs[iaddr] = val; - break; - } - dolog ("written value %#x to indirect register %d\n", val, iaddr); - break; - - case Status: - if (s->regs[Status] & INT) { - qemu_irq_lower (s->pic); - } - s->regs[Status] &= ~INT; - s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI); - break; - - case PIO_Data: - lwarn ("attempt to write value %#x to PIO register\n", val); - break; - } -} - -static int cs_write_audio (CSState *s, int nchan, int dma_pos, - int dma_len, int len) -{ - int temp, net; - uint8_t tmpbuf[4096]; - IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); - - temp = len; - net = 0; - - while (temp) { - int left = dma_len - dma_pos; - int copied; - size_t to_copy; - - to_copy = audio_MIN (temp, left); - if (to_copy > sizeof (tmpbuf)) { - to_copy = sizeof (tmpbuf); - } - - copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy); - if (s->tab) { - int i; - int16_t linbuf[4096]; - - for (i = 0; i < copied; ++i) - linbuf[i] = s->tab[tmpbuf[i]]; - copied = AUD_write (s->voice, linbuf, copied << 1); - copied >>= 1; - } - else { - copied = AUD_write (s->voice, tmpbuf, copied); - } - - temp -= copied; - dma_pos = (dma_pos + copied) % dma_len; - net += copied; - - if (!copied) { - break; - } - } - - return net; -} - -static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len) -{ - CSState *s = opaque; - int copy, written; - int till = -1; - - copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len; - - if (s->dregs[Pin_Control] & IEN) { - till = (s->dregs[Playback_Lower_Base_Count] - | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift; - till -= s->transferred; - copy = audio_MIN (till, copy); - } - - if ((copy <= 0) || (dma_len <= 0)) { - return dma_pos; - } - - written = cs_write_audio (s, nchan, dma_pos, dma_len, copy); - - dma_pos = (dma_pos + written) % dma_len; - s->audio_free -= (written << (s->tab != NULL)); - - if (written == till) { - s->regs[Status] |= INT; - s->dregs[Alternate_Feature_Status] |= PI; - s->transferred = 0; - qemu_irq_raise (s->pic); - } - else { - s->transferred += written; - } - - return dma_pos; -} - -static int cs4231a_pre_load (void *opaque) -{ - CSState *s = opaque; - - if (s->dma_running) { - IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); - k->release_DREQ(s->isa_dma, s->dma); - AUD_set_active_out (s->voice, 0); - } - s->dma_running = 0; - return 0; -} - -static int cs4231a_post_load (void *opaque, int version_id) -{ - CSState *s = opaque; - - if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) { - s->dma_running = 0; - cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); - } - return 0; -} - -static const VMStateDescription vmstate_cs4231a = { - .name = "cs4231a", - .version_id = 1, - .minimum_version_id = 1, - .pre_load = cs4231a_pre_load, - .post_load = cs4231a_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS), - VMSTATE_BUFFER (dregs, CSState), - VMSTATE_INT32 (dma_running, CSState), - VMSTATE_INT32 (audio_free, CSState), - VMSTATE_INT32 (transferred, CSState), - VMSTATE_INT32 (aci_counter, CSState), - VMSTATE_END_OF_LIST () - } -}; - -static const MemoryRegionOps cs_ioport_ops = { - .read = cs_read, - .write = cs_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - } -}; - -static void cs4231a_initfn (Object *obj) -{ - CSState *s = CS4231A (obj); - - memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s, - "cs4231a", 4); -} - -static void cs4231a_realizefn (DeviceState *dev, Error **errp) -{ - ISADevice *d = ISA_DEVICE (dev); - CSState *s = CS4231A (dev); - IsaDmaClass *k; - - isa_init_irq (d, &s->pic, s->irq); - s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->dma); - k = ISADMA_GET_CLASS(s->isa_dma); - k->register_channel(s->isa_dma, s->dma, cs_dma_read, s); - - isa_register_ioport (d, &s->ioports, s->port); - - AUD_register_card ("cs4231a", &s->card); -} - -static int cs4231a_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_CS4231A); - return 0; -} - -static Property cs4231a_properties[] = { - DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534), - DEFINE_PROP_UINT32 ("irq", CSState, irq, 9), - DEFINE_PROP_UINT32 ("dma", CSState, dma, 3), - DEFINE_PROP_END_OF_LIST (), -}; - -static void cs4231a_class_initfn (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - - dc->realize = cs4231a_realizefn; - dc->reset = cs4231a_reset; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "Crystal Semiconductor CS4231A"; - dc->vmsd = &vmstate_cs4231a; - dc->props = cs4231a_properties; -} - -static const TypeInfo cs4231a_info = { - .name = TYPE_CS4231A, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof (CSState), - .instance_init = cs4231a_initfn, - .class_init = cs4231a_class_initfn, -}; - -static void cs4231a_register_types (void) -{ - type_register_static (&cs4231a_info); - isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init); -} - -type_init (cs4231a_register_types) diff --git a/qemu/hw/audio/es1370.c b/qemu/hw/audio/es1370.c deleted file mode 100644 index 8449b5f43..000000000 --- a/qemu/hw/audio/es1370.c +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * QEMU ES1370 emulation - * - * Copyright (c) 2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* #define DEBUG_ES1370 */ -/* #define VERBOSE_ES1370 */ -#define SILENT_ES1370 - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "hw/pci/pci.h" -#include "sysemu/dma.h" - -/* Missing stuff: - SCTRL_P[12](END|ST)INC - SCTRL_P1SCTRLD - SCTRL_P2DACSEN - CTRL_DAC_SYNC - MIDI - non looped mode - surely more -*/ - -/* - Following macros and samplerate array were copied verbatim from - Linux kernel 2.4.30: drivers/sound/es1370.c - - Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) -*/ - -/* Start blatant GPL violation */ - -#define ES1370_REG_CONTROL 0x00 -#define ES1370_REG_STATUS 0x04 -#define ES1370_REG_UART_DATA 0x08 -#define ES1370_REG_UART_STATUS 0x09 -#define ES1370_REG_UART_CONTROL 0x09 -#define ES1370_REG_UART_TEST 0x0a -#define ES1370_REG_MEMPAGE 0x0c -#define ES1370_REG_CODEC 0x10 -#define ES1370_REG_SERIAL_CONTROL 0x20 -#define ES1370_REG_DAC1_SCOUNT 0x24 -#define ES1370_REG_DAC2_SCOUNT 0x28 -#define ES1370_REG_ADC_SCOUNT 0x2c - -#define ES1370_REG_DAC1_FRAMEADR 0xc30 -#define ES1370_REG_DAC1_FRAMECNT 0xc34 -#define ES1370_REG_DAC2_FRAMEADR 0xc38 -#define ES1370_REG_DAC2_FRAMECNT 0xc3c -#define ES1370_REG_ADC_FRAMEADR 0xd30 -#define ES1370_REG_ADC_FRAMECNT 0xd34 -#define ES1370_REG_PHANTOM_FRAMEADR 0xd38 -#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c - -static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 }; - -#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2) -#define DAC2_DIVTOSR(x) (1411200/((x)+2)) - -#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */ -#define CTRL_XCTL1 0x40000000 /* electret mic bias */ -#define CTRL_OPEN 0x20000000 /* no function, can be read and written */ -#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */ -#define CTRL_SH_PCLKDIV 16 -#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */ -#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */ -#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */ -#define CTRL_SH_WTSRSEL 12 -#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */ -#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ -#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */ -#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */ -#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ -#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ -#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ -#define CTRL_ADC_EN 0x00000010 /* enable ADC */ -#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ -#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */ -#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */ -#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */ - -#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ -#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */ -#define STAT_CBUSY 0x00000200 /* 1 = codec busy */ -#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */ -#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */ -#define STAT_SH_VC 5 -#define STAT_MCCB 0x00000010 /* CCB int pending */ -#define STAT_UART 0x00000008 /* UART int pending */ -#define STAT_DAC1 0x00000004 /* DAC1 int pending */ -#define STAT_DAC2 0x00000002 /* DAC2 int pending */ -#define STAT_ADC 0x00000001 /* ADC int pending */ - -#define USTAT_RXINT 0x80 /* UART rx int pending */ -#define USTAT_TXINT 0x04 /* UART tx int pending */ -#define USTAT_TXRDY 0x02 /* UART tx ready */ -#define USTAT_RXRDY 0x01 /* UART rx ready */ - -#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */ -#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */ -#define UCTRL_ENA_TXINT 0x20 /* enable TX int */ -#define UCTRL_CNTRL 0x03 /* control field */ -#define UCTRL_CNTRL_SWR 0x03 /* software reset command */ - -#define SCTRL_P2ENDINC 0x00380000 /* */ -#define SCTRL_SH_P2ENDINC 19 -#define SCTRL_P2STINC 0x00070000 /* */ -#define SCTRL_SH_P2STINC 16 -#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ -#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ -#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ -#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ -#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ -#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ -#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ -#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ -#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */ -#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */ -#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ -#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ -#define SCTRL_R1FMT 0x00000030 /* format mask */ -#define SCTRL_SH_R1FMT 4 -#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ -#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ -#define SCTRL_P2FMT 0x0000000c /* format mask */ -#define SCTRL_SH_P2FMT 2 -#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ -#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ -#define SCTRL_P1FMT 0x00000003 /* format mask */ -#define SCTRL_SH_P1FMT 0 - -/* End blatant GPL violation */ - -#define NB_CHANNELS 3 -#define DAC1_CHANNEL 0 -#define DAC2_CHANNEL 1 -#define ADC_CHANNEL 2 - -static void es1370_dac1_callback (void *opaque, int free); -static void es1370_dac2_callback (void *opaque, int free); -static void es1370_adc_callback (void *opaque, int avail); - -#ifdef DEBUG_ES1370 - -#define ldebug(...) AUD_log ("es1370", __VA_ARGS__) - -static void print_ctl (uint32_t val) -{ - char buf[1024]; - - buf[0] = '\0'; -#define a(n) if (val & CTRL_##n) strcat (buf, " "#n) - a (ADC_STOP); - a (XCTL1); - a (OPEN); - a (MSFMTSEL); - a (M_SBB); - a (DAC_SYNC); - a (CCB_INTRM); - a (M_CB); - a (XCTL0); - a (BREQ); - a (DAC1_EN); - a (DAC2_EN); - a (ADC_EN); - a (UART_EN); - a (JYSTK_EN); - a (CDC_EN); - a (SERR_DIS); -#undef a - AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n", - (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV, - DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), - dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], - buf); -} - -static void print_sctl (uint32_t val) -{ - static const char *fmt_names[] = {"8M", "8S", "16M", "16S"}; - char buf[1024]; - - buf[0] = '\0'; - -#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n) -#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n) - b (R1LOOPSEL); - b (P2LOOPSEL); - b (P1LOOPSEL); - a (P2PAUSE); - a (P1PAUSE); - a (R1INTEN); - a (P2INTEN); - a (P1INTEN); - a (P1SCTRLD); - a (P2DACSEN); - if (buf[0]) { - strcat (buf, "\n "); - } - else { - buf[0] = ' '; - buf[1] = '\0'; - } -#undef b -#undef a - AUD_log ("es1370", - "%s" - "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n", - buf, - (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC, - (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC, - fmt_names [(val >> SCTRL_SH_R1FMT) & 3], - fmt_names [(val >> SCTRL_SH_P2FMT) & 3], - fmt_names [(val >> SCTRL_SH_P1FMT) & 3] - ); -} -#else -#define ldebug(...) -#define print_ctl(...) -#define print_sctl(...) -#endif - -#ifdef VERBOSE_ES1370 -#define dolog(...) AUD_log ("es1370", __VA_ARGS__) -#else -#define dolog(...) -#endif - -#ifndef SILENT_ES1370 -#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__) -#else -#define lwarn(...) -#endif - -struct chan { - uint32_t shift; - uint32_t leftover; - uint32_t scount; - uint32_t frame_addr; - uint32_t frame_cnt; -}; - -typedef struct ES1370State { - PCIDevice dev; - QEMUSoundCard card; - MemoryRegion io; - struct chan chan[NB_CHANNELS]; - SWVoiceOut *dac_voice[2]; - SWVoiceIn *adc_voice; - - uint32_t ctl; - uint32_t status; - uint32_t mempage; - uint32_t codec; - uint32_t sctl; -} ES1370State; - -struct chan_bits { - uint32_t ctl_en; - uint32_t stat_int; - uint32_t sctl_pause; - uint32_t sctl_inten; - uint32_t sctl_fmt; - uint32_t sctl_sh_fmt; - uint32_t sctl_loopsel; - void (*calc_freq) (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, uint32_t *new_freq); -}; - -#define TYPE_ES1370 "ES1370" -#define ES1370(obj) \ - OBJECT_CHECK(ES1370State, (obj), TYPE_ES1370) - -static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, uint32_t *new_freq); -static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, - uint32_t *new_freq); - -static const struct chan_bits es1370_chan_bits[] = { - {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN, - SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL, - es1370_dac1_calc_freq}, - - {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN, - SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL, - es1370_dac2_and_adc_calc_freq}, - - {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN, - SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL, - es1370_dac2_and_adc_calc_freq} -}; - -static void es1370_update_status (ES1370State *s, uint32_t new_status) -{ - uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC); - - if (level) { - s->status = new_status | STAT_INTR; - } - else { - s->status = new_status & ~STAT_INTR; - } - pci_set_irq(&s->dev, !!level); -} - -static void es1370_reset (ES1370State *s) -{ - size_t i; - - s->ctl = 1; - s->status = 0x60; - s->mempage = 0; - s->codec = 0; - s->sctl = 0; - - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - d->scount = 0; - d->leftover = 0; - if (i == ADC_CHANNEL) { - AUD_close_in (&s->card, s->adc_voice); - s->adc_voice = NULL; - } - else { - AUD_close_out (&s->card, s->dac_voice[i]); - s->dac_voice[i] = NULL; - } - } - pci_irq_deassert(&s->dev); -} - -static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl) -{ - uint32_t new_status = s->status; - - if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) { - new_status &= ~STAT_DAC1; - } - - if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) { - new_status &= ~STAT_DAC2; - } - - if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) { - new_status &= ~STAT_ADC; - } - - if (new_status != s->status) { - es1370_update_status (s, new_status); - } -} - -static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, uint32_t *new_freq) - -{ - *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; - *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; -} - -static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, - uint32_t *new_freq) - -{ - uint32_t old_pclkdiv, new_pclkdiv; - - new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV; - old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV; - *new_freq = DAC2_DIVTOSR (new_pclkdiv); - *old_freq = DAC2_DIVTOSR (old_pclkdiv); -} - -static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) -{ - size_t i; - uint32_t old_freq, new_freq, old_fmt, new_fmt; - - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - const struct chan_bits *b = &es1370_chan_bits[i]; - - new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt; - old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt; - - b->calc_freq (s, ctl, &old_freq, &new_freq); - - if ((old_fmt != new_fmt) || (old_freq != new_freq)) { - d->shift = (new_fmt & 1) + (new_fmt >> 1); - ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n", - i, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8, - d->shift); - if (new_freq) { - struct audsettings as; - - as.freq = new_freq; - as.nchannels = 1 << (new_fmt & 1); - as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; - as.endianness = 0; - - if (i == ADC_CHANNEL) { - s->adc_voice = - AUD_open_in ( - &s->card, - s->adc_voice, - "es1370.adc", - s, - es1370_adc_callback, - &as - ); - } - else { - s->dac_voice[i] = - AUD_open_out ( - &s->card, - s->dac_voice[i], - i ? "es1370.dac2" : "es1370.dac1", - s, - i ? es1370_dac2_callback : es1370_dac1_callback, - &as - ); - } - } - } - - if (((ctl ^ s->ctl) & b->ctl_en) - || ((sctl ^ s->sctl) & b->sctl_pause)) { - int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause); - - if (i == ADC_CHANNEL) { - AUD_set_active_in (s->adc_voice, on); - } - else { - AUD_set_active_out (s->dac_voice[i], on); - } - } - } - - s->ctl = ctl; - s->sctl = sctl; -} - -static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) -{ - addr &= 0xff; - if (addr >= 0x30 && addr <= 0x3f) - addr |= s->mempage << 8; - return addr; -} - -static void es1370_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - ES1370State *s = opaque; - uint32_t shift, mask; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_CONTROL: - case ES1370_REG_CONTROL + 1: - case ES1370_REG_CONTROL + 2: - case ES1370_REG_CONTROL + 3: - shift = (addr - ES1370_REG_CONTROL) << 3; - mask = 0xff << shift; - val = (s->ctl & ~mask) | ((val & 0xff) << shift); - es1370_update_voices (s, val, s->sctl); - print_ctl (val); - break; - case ES1370_REG_MEMPAGE: - s->mempage = val; - break; - case ES1370_REG_SERIAL_CONTROL: - case ES1370_REG_SERIAL_CONTROL + 1: - case ES1370_REG_SERIAL_CONTROL + 2: - case ES1370_REG_SERIAL_CONTROL + 3: - shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3; - mask = 0xff << shift; - val = (s->sctl & ~mask) | ((val & 0xff) << shift); - es1370_maybe_lower_irq (s, val); - es1370_update_voices (s, s->ctl, val); - print_sctl (val); - break; - default: - lwarn ("writeb %#x <- %#x\n", addr, val); - break; - } -} - -static void es1370_writew(void *opaque, uint32_t addr, uint32_t val) -{ - ES1370State *s = opaque; - addr = es1370_fixup (s, addr); - uint32_t shift, mask; - struct chan *d = &s->chan[0]; - - switch (addr) { - case ES1370_REG_CODEC: - dolog ("ignored codec write address %#x, data %#x\n", - (val >> 8) & 0xff, val & 0xff); - s->codec = val; - break; - - case ES1370_REG_CONTROL: - case ES1370_REG_CONTROL + 2: - shift = (addr != ES1370_REG_CONTROL) << 4; - mask = 0xffff << shift; - val = (s->ctl & ~mask) | ((val & 0xffff) << shift); - es1370_update_voices (s, val, s->sctl); - print_ctl (val); - break; - - case ES1370_REG_ADC_SCOUNT: - d++; - case ES1370_REG_DAC2_SCOUNT: - d++; - case ES1370_REG_DAC1_SCOUNT: - d->scount = (d->scount & ~0xffff) | (val & 0xffff); - break; - - default: - lwarn ("writew %#x <- %#x\n", addr, val); - break; - } -} - -static void es1370_writel(void *opaque, uint32_t addr, uint32_t val) -{ - ES1370State *s = opaque; - struct chan *d = &s->chan[0]; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_CONTROL: - es1370_update_voices (s, val, s->sctl); - print_ctl (val); - break; - - case ES1370_REG_MEMPAGE: - s->mempage = val & 0xf; - break; - - case ES1370_REG_SERIAL_CONTROL: - es1370_maybe_lower_irq (s, val); - es1370_update_voices (s, s->ctl, val); - print_sctl (val); - break; - - case ES1370_REG_ADC_SCOUNT: - d++; - case ES1370_REG_DAC2_SCOUNT: - d++; - case ES1370_REG_DAC1_SCOUNT: - d->scount = (val & 0xffff) | (d->scount & ~0xffff); - ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n", - d - &s->chan[0], val >> 16, (val & 0xffff)); - break; - - case ES1370_REG_ADC_FRAMEADR: - d++; - case ES1370_REG_DAC2_FRAMEADR: - d++; - case ES1370_REG_DAC1_FRAMEADR: - d->frame_addr = val; - ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val); - break; - - case ES1370_REG_PHANTOM_FRAMECNT: - lwarn ("writing to phantom frame count %#x\n", val); - break; - case ES1370_REG_PHANTOM_FRAMEADR: - lwarn ("writing to phantom frame address %#x\n", val); - break; - - case ES1370_REG_ADC_FRAMECNT: - d++; - case ES1370_REG_DAC2_FRAMECNT: - d++; - case ES1370_REG_DAC1_FRAMECNT: - d->frame_cnt = val; - d->leftover = 0; - ldebug ("chan %td frame count %d, buffer size %d\n", - d - &s->chan[0], val >> 16, val & 0xffff); - break; - - default: - lwarn ("writel %#x <- %#x\n", addr, val); - break; - } -} - -static uint32_t es1370_readb(void *opaque, uint32_t addr) -{ - ES1370State *s = opaque; - uint32_t val; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case 0x1b: /* Legacy */ - lwarn ("Attempt to read from legacy register\n"); - val = 5; - break; - case ES1370_REG_MEMPAGE: - val = s->mempage; - break; - case ES1370_REG_CONTROL + 0: - case ES1370_REG_CONTROL + 1: - case ES1370_REG_CONTROL + 2: - case ES1370_REG_CONTROL + 3: - val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3); - break; - case ES1370_REG_STATUS + 0: - case ES1370_REG_STATUS + 1: - case ES1370_REG_STATUS + 2: - case ES1370_REG_STATUS + 3: - val = s->status >> ((addr - ES1370_REG_STATUS) << 3); - break; - default: - val = ~0; - lwarn ("readb %#x -> %#x\n", addr, val); - break; - } - return val; -} - -static uint32_t es1370_readw(void *opaque, uint32_t addr) -{ - ES1370State *s = opaque; - struct chan *d = &s->chan[0]; - uint32_t val; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_ADC_SCOUNT + 2: - d++; - case ES1370_REG_DAC2_SCOUNT + 2: - d++; - case ES1370_REG_DAC1_SCOUNT + 2: - val = d->scount >> 16; - break; - - case ES1370_REG_ADC_FRAMECNT: - d++; - case ES1370_REG_DAC2_FRAMECNT: - d++; - case ES1370_REG_DAC1_FRAMECNT: - val = d->frame_cnt & 0xffff; - break; - - case ES1370_REG_ADC_FRAMECNT + 2: - d++; - case ES1370_REG_DAC2_FRAMECNT + 2: - d++; - case ES1370_REG_DAC1_FRAMECNT + 2: - val = d->frame_cnt >> 16; - break; - - default: - val = ~0; - lwarn ("readw %#x -> %#x\n", addr, val); - break; - } - - return val; -} - -static uint32_t es1370_readl(void *opaque, uint32_t addr) -{ - ES1370State *s = opaque; - uint32_t val; - struct chan *d = &s->chan[0]; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_CONTROL: - val = s->ctl; - break; - case ES1370_REG_STATUS: - val = s->status; - break; - case ES1370_REG_MEMPAGE: - val = s->mempage; - break; - case ES1370_REG_CODEC: - val = s->codec; - break; - case ES1370_REG_SERIAL_CONTROL: - val = s->sctl; - break; - - case ES1370_REG_ADC_SCOUNT: - d++; - case ES1370_REG_DAC2_SCOUNT: - d++; - case ES1370_REG_DAC1_SCOUNT: - val = d->scount; -#ifdef DEBUG_ES1370 - { - uint32_t curr_count = d->scount >> 16; - uint32_t count = d->scount & 0xffff; - - curr_count <<= d->shift; - count <<= d->shift; - dolog ("read scount curr %d, total %d\n", curr_count, count); - } -#endif - break; - - case ES1370_REG_ADC_FRAMECNT: - d++; - case ES1370_REG_DAC2_FRAMECNT: - d++; - case ES1370_REG_DAC1_FRAMECNT: - val = d->frame_cnt; -#ifdef DEBUG_ES1370 - { - uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2; - uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2; - if (curr > size) { - dolog ("read framecnt curr %d, size %d %d\n", curr, size, - curr > size); - } - } -#endif - break; - - case ES1370_REG_ADC_FRAMEADR: - d++; - case ES1370_REG_DAC2_FRAMEADR: - d++; - case ES1370_REG_DAC1_FRAMEADR: - val = d->frame_addr; - break; - - case ES1370_REG_PHANTOM_FRAMECNT: - val = ~0U; - lwarn ("reading from phantom frame count\n"); - break; - case ES1370_REG_PHANTOM_FRAMEADR: - val = ~0U; - lwarn ("reading from phantom frame address\n"); - break; - - default: - val = ~0U; - lwarn ("readl %#x -> %#x\n", addr, val); - break; - } - return val; -} - -static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, - int max, int *irq) -{ - uint8_t tmpbuf[4096]; - uint32_t addr = d->frame_addr; - int sc = d->scount & 0xffff; - int csc = d->scount >> 16; - int csc_bytes = (csc + 1) << d->shift; - int cnt = d->frame_cnt >> 16; - int size = d->frame_cnt & 0xffff; - int left = ((size - cnt + 1) << 2) + d->leftover; - int transferred = 0; - int temp = audio_MIN (max, audio_MIN (left, csc_bytes)); - int index = d - &s->chan[0]; - - addr += (cnt << 2) + d->leftover; - - if (index == ADC_CHANNEL) { - while (temp) { - int acquired, to_copy; - - to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); - acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); - if (!acquired) - break; - - pci_dma_write (&s->dev, addr, tmpbuf, acquired); - - temp -= acquired; - addr += acquired; - transferred += acquired; - } - } - else { - SWVoiceOut *voice = s->dac_voice[index]; - - while (temp) { - int copied, to_copy; - - to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); - pci_dma_read (&s->dev, addr, tmpbuf, to_copy); - copied = AUD_write (voice, tmpbuf, to_copy); - if (!copied) - break; - temp -= copied; - addr += copied; - transferred += copied; - } - } - - if (csc_bytes == transferred) { - *irq = 1; - d->scount = sc | (sc << 16); - ldebug ("sc = %d, rate = %f\n", - (sc + 1) << d->shift, - (sc + 1) / (double) 44100); - } - else { - *irq = 0; - d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16); - } - - cnt += (transferred + d->leftover) >> 2; - - if (s->sctl & loop_sel) { - /* Bah, how stupid is that having a 0 represent true value? - i just spent few hours on this shit */ - AUD_log ("es1370: warning", "non looping mode\n"); - } - else { - d->frame_cnt = size; - - if ((uint32_t) cnt <= d->frame_cnt) - d->frame_cnt |= cnt << 16; - } - - d->leftover = (transferred + d->leftover) & 3; -} - -static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail) -{ - uint32_t new_status = s->status; - int max_bytes, irq; - struct chan *d = &s->chan[chan]; - const struct chan_bits *b = &es1370_chan_bits[chan]; - - if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) { - return; - } - - max_bytes = free_or_avail; - max_bytes &= ~((1 << d->shift) - 1); - if (!max_bytes) { - return; - } - - es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq); - - if (irq) { - if (s->sctl & b->sctl_inten) { - new_status |= b->stat_int; - } - } - - if (new_status != s->status) { - es1370_update_status (s, new_status); - } -} - -static void es1370_dac1_callback (void *opaque, int free) -{ - ES1370State *s = opaque; - - es1370_run_channel (s, DAC1_CHANNEL, free); -} - -static void es1370_dac2_callback (void *opaque, int free) -{ - ES1370State *s = opaque; - - es1370_run_channel (s, DAC2_CHANNEL, free); -} - -static void es1370_adc_callback (void *opaque, int avail) -{ - ES1370State *s = opaque; - - es1370_run_channel (s, ADC_CHANNEL, avail); -} - -static uint64_t es1370_read(void *opaque, hwaddr addr, - unsigned size) -{ - switch (size) { - case 1: - return es1370_readb(opaque, addr); - case 2: - return es1370_readw(opaque, addr); - case 4: - return es1370_readl(opaque, addr); - default: - return -1; - } -} - -static void es1370_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - switch (size) { - case 1: - es1370_writeb(opaque, addr, val); - break; - case 2: - es1370_writew(opaque, addr, val); - break; - case 4: - es1370_writel(opaque, addr, val); - break; - } -} - -static const MemoryRegionOps es1370_io_ops = { - .read = es1370_read, - .write = es1370_write, - .impl = { - .min_access_size = 1, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static const VMStateDescription vmstate_es1370_channel = { - .name = "es1370_channel", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_UINT32 (shift, struct chan), - VMSTATE_UINT32 (leftover, struct chan), - VMSTATE_UINT32 (scount, struct chan), - VMSTATE_UINT32 (frame_addr, struct chan), - VMSTATE_UINT32 (frame_cnt, struct chan), - VMSTATE_END_OF_LIST () - } -}; - -static int es1370_post_load (void *opaque, int version_id) -{ - uint32_t ctl, sctl; - ES1370State *s = opaque; - size_t i; - - for (i = 0; i < NB_CHANNELS; ++i) { - if (i == ADC_CHANNEL) { - if (s->adc_voice) { - AUD_close_in (&s->card, s->adc_voice); - s->adc_voice = NULL; - } - } - else { - if (s->dac_voice[i]) { - AUD_close_out (&s->card, s->dac_voice[i]); - s->dac_voice[i] = NULL; - } - } - } - - ctl = s->ctl; - sctl = s->sctl; - s->ctl = 0; - s->sctl = 0; - es1370_update_voices (s, ctl, sctl); - return 0; -} - -static const VMStateDescription vmstate_es1370 = { - .name = "es1370", - .version_id = 2, - .minimum_version_id = 2, - .post_load = es1370_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE (dev, ES1370State), - VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2, - vmstate_es1370_channel, struct chan), - VMSTATE_UINT32 (ctl, ES1370State), - VMSTATE_UINT32 (status, ES1370State), - VMSTATE_UINT32 (mempage, ES1370State), - VMSTATE_UINT32 (codec, ES1370State), - VMSTATE_UINT32 (sctl, ES1370State), - VMSTATE_END_OF_LIST () - } -}; - -static void es1370_on_reset (void *opaque) -{ - ES1370State *s = opaque; - es1370_reset (s); -} - -static void es1370_realize(PCIDevice *dev, Error **errp) -{ - ES1370State *s = ES1370(dev); - uint8_t *c = s->dev.config; - - c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8; - -#if 0 - c[PCI_CAPABILITY_LIST] = 0xdc; - c[PCI_INTERRUPT_LINE] = 10; - c[0xdc] = 0x00; -#endif - - c[PCI_INTERRUPT_PIN] = 1; - c[PCI_MIN_GNT] = 0x0c; - c[PCI_MAX_LAT] = 0x80; - - memory_region_init_io (&s->io, OBJECT(s), &es1370_io_ops, s, "es1370", 256); - pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); - qemu_register_reset (es1370_on_reset, s); - - AUD_register_card ("es1370", &s->card); - es1370_reset (s); -} - -static int es1370_init (PCIBus *bus) -{ - pci_create_simple (bus, -1, TYPE_ES1370); - return 0; -} - -static void es1370_class_init (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); - - k->realize = es1370_realize; - k->vendor_id = PCI_VENDOR_ID_ENSONIQ; - k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370; - k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; - k->subsystem_vendor_id = 0x4942; - k->subsystem_id = 0x4c4c; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "ENSONIQ AudioPCI ES1370"; - dc->vmsd = &vmstate_es1370; -} - -static const TypeInfo es1370_info = { - .name = TYPE_ES1370, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof (ES1370State), - .class_init = es1370_class_init, -}; - -static void es1370_register_types (void) -{ - type_register_static (&es1370_info); - pci_register_soundhw("es1370", "ENSONIQ AudioPCI ES1370", es1370_init); -} - -type_init (es1370_register_types) - diff --git a/qemu/hw/audio/fmopl.c b/qemu/hw/audio/fmopl.c deleted file mode 100644 index 731110fe8..000000000 --- a/qemu/hw/audio/fmopl.c +++ /dev/null @@ -1,1391 +0,0 @@ -/* -** -** File: fmopl.c -- software implementation of FM sound generator -** -** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development -** -** Version 0.37a -** -*/ - -/* - preliminary : - Problem : - note: -*/ - -/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#define HAS_YM3812 1 - -#include "qemu/osdep.h" -#include -//#include "driver.h" /* use M.A.M.E. */ -#include "fmopl.h" - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -/* -------------------- for debug --------------------- */ -/* #define OPL_OUTPUT_LOG */ -#ifdef OPL_OUTPUT_LOG -static FILE *opl_dbg_fp = NULL; -static FM_OPL *opl_dbg_opl[16]; -static int opl_dbg_maxchip,opl_dbg_chip; -#endif - -/* -------------------- preliminary define section --------------------- */ -/* attack/decay rate time rate */ -#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */ -#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */ - -#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */ - -#define FREQ_BITS 24 /* frequency turn */ - -/* counter bits = 20 , octerve 7 */ -#define FREQ_RATE (1<<(FREQ_BITS-20)) -#define TL_BITS (FREQ_BITS+2) - -/* final output shift , limit minimum and maximum */ -#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */ -#define OPL_MAXOUT (0x7fff<=LOG_LEVEL ) logerror x -#define LOG(n,x) - -/* --------------------- subroutines --------------------- */ - -static inline int Limit( int val, int max, int min ) { - if ( val > max ) - val = max; - else if ( val < min ) - val = min; - - return val; -} - -/* status set and IRQ handling */ -static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag) -{ - /* set status flag */ - OPL->status |= flag; - if(!(OPL->status & 0x80)) - { - if(OPL->status & OPL->statusmask) - { /* IRQ on */ - OPL->status |= 0x80; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); - } - } -} - -/* status reset and IRQ handling */ -static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag) -{ - /* reset status flag */ - OPL->status &=~flag; - if((OPL->status & 0x80)) - { - if (!(OPL->status & OPL->statusmask) ) - { - OPL->status &= 0x7f; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); - } - } -} - -/* IRQ mask set */ -static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) -{ - OPL->statusmask = flag; - /* IRQ handling check */ - OPL_STATUS_SET(OPL,0); - OPL_STATUS_RESET(OPL,0); -} - -/* ----- key on ----- */ -static inline void OPL_KEYON(OPL_SLOT *SLOT) -{ - /* sin wave restart */ - SLOT->Cnt = 0; - /* set attack */ - SLOT->evm = ENV_MOD_AR; - SLOT->evs = SLOT->evsa; - SLOT->evc = EG_AST; - SLOT->eve = EG_AED; -} -/* ----- key off ----- */ -static inline void OPL_KEYOFF(OPL_SLOT *SLOT) -{ - if( SLOT->evm > ENV_MOD_RR) - { - /* set envelope counter from envleope output */ - SLOT->evm = ENV_MOD_RR; - if( !(SLOT->evc&EG_DST) ) - //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<evc = EG_DST; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsr; - } -} - -/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ -/* return : envelope output */ -static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) -{ - /* calcrate envelope generator */ - if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) - { - switch( SLOT->evm ){ - case ENV_MOD_AR: /* ATTACK -> DECAY1 */ - /* next DR */ - SLOT->evm = ENV_MOD_DR; - SLOT->evc = EG_DST; - SLOT->eve = SLOT->SL; - SLOT->evs = SLOT->evsd; - break; - case ENV_MOD_DR: /* DECAY -> SL or RR */ - SLOT->evc = SLOT->SL; - SLOT->eve = EG_DED; - if(SLOT->eg_typ) - { - SLOT->evs = 0; - } - else - { - SLOT->evm = ENV_MOD_RR; - SLOT->evs = SLOT->evsr; - } - break; - case ENV_MOD_RR: /* RR -> OFF */ - SLOT->evc = EG_OFF; - SLOT->eve = EG_OFF+1; - SLOT->evs = 0; - break; - } - } - /* calcrate envelope */ - return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0); -} - -/* set algorithm connection */ -static void set_algorithm( OPL_CH *CH) -{ - INT32 *carrier = &outd[0]; - CH->connect1 = CH->CON ? carrier : &feedback2; - CH->connect2 = carrier; -} - -/* ---------- frequency counter for operater update ---------- */ -static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) -{ - int ksr; - - /* frequency step counter */ - SLOT->Incr = CH->fc * SLOT->mul; - ksr = CH->kcode >> SLOT->KSR; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - /* attack , decay rate recalcration */ - SLOT->evsa = SLOT->AR[ksr]; - SLOT->evsd = SLOT->DR[ksr]; - SLOT->evsr = SLOT->RR[ksr]; - } - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); -} - -/* set multi,am,vib,EG-TYP,KSR,mul */ -static inline void set_mul(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->mul = MUL_TABLE[v&0x0f]; - SLOT->KSR = (v&0x10) ? 0 : 2; - SLOT->eg_typ = (v&0x20)>>5; - SLOT->vib = (v&0x40); - SLOT->ams = (v&0x80); - CALC_FCSLOT(CH,SLOT); -} - -/* set ksl & tl */ -static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */ - - SLOT->ksl = ksl ? 3-ksl : 31; - SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */ - - if( !(OPL->mode&0x80) ) - { /* not CSM latch total level */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - } -} - -/* set attack rate & decay rate */ -static inline void set_ar_dr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int ar = v>>4; - int dr = v&0x0f; - - SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0; - SLOT->evsa = SLOT->AR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa; - - SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0; - SLOT->evsd = SLOT->DR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd; -} - -/* set sustain level & release rate */ -static inline void set_sl_rr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int sl = v>>4; - int rr = v & 0x0f; - - SLOT->SL = SL_TABLE[sl]; - if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL; - SLOT->RR = &OPL->DR_TABLE[rr<<2]; - SLOT->evsr = SLOT->RR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr; -} - -/* operator output calcrator */ -#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] -/* ---------- calcrate one of channel ---------- */ -static inline void OPL_CALC_CH( OPL_CH *CH ) -{ - UINT32 env_out; - OPL_SLOT *SLOT; - - feedback2 = 0; - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - if(CH->FB) - { - int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; - CH->op1_out[1] = CH->op1_out[0]; - *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1); - } - else - { - *CH->connect1 += OP_OUT(SLOT,env_out,0); - } - }else - { - CH->op1_out[1] = CH->op1_out[0]; - CH->op1_out[0] = 0; - } - /* SLOT 2 */ - SLOT = &CH->SLOT[SLOT2]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - outd[0] += OP_OUT(SLOT,env_out, feedback2); - } -} - -/* ---------- calcrate rhythm block ---------- */ -#define WHITE_NOISE_db 6.0 -static inline void OPL_CALC_RH( OPL_CH *CH ) -{ - UINT32 env_tam,env_sd,env_top,env_hh; - int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); - INT32 tone8; - - OPL_SLOT *SLOT; - int env_out; - - /* BD : same as FM serial mode and output level is large */ - feedback2 = 0; - /* SLOT 1 */ - SLOT = &CH[6].SLOT[SLOT1]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - if(CH[6].FB) - { - int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; - CH[6].op1_out[1] = CH[6].op1_out[0]; - feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); - } - else - { - feedback2 = OP_OUT(SLOT,env_out,0); - } - }else - { - feedback2 = 0; - CH[6].op1_out[1] = CH[6].op1_out[0]; - CH[6].op1_out[0] = 0; - } - /* SLOT 2 */ - SLOT = &CH[6].SLOT[SLOT2]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; - } - - // SD (17) = mul14[fnum7] + white noise - // TAM (15) = mul15[fnum8] - // TOP (18) = fnum6(mul18[fnum8]+whitenoise) - // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise - env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; - env_tam=OPL_CALC_SLOT(SLOT8_1); - env_top=OPL_CALC_SLOT(SLOT8_2); - env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; - - /* PG */ - if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); - else SLOT7_1->Cnt += 2*SLOT7_1->Incr; - if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); - else SLOT7_2->Cnt += (CH[7].fc*8); - if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE); - else SLOT8_1->Cnt += SLOT8_1->Incr; - if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); - else SLOT8_2->Cnt += (CH[8].fc*48); - - tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); - - /* SD */ - if( env_sd < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; - /* TAM */ - if( env_tam < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; - /* TOP-CY */ - if( env_top < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; - /* HH */ - if( env_hh < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2; -} - -/* ----------- initialize time tabls ----------- */ -static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) -{ - int i; - double rate; - - /* make attack rate & decay rate tables */ - for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; - for (i = 4;i <= 60;i++){ - rate = OPL->freqbase; /* frequency rate */ - if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ - rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ - rate *= (double)(EG_ENT<AR_TABLE[i] = rate / ARRATE; - OPL->DR_TABLE[i] = rate / DRRATE; - } - for (i = 60; i < ARRAY_SIZE(OPL->AR_TABLE); i++) - { - OPL->AR_TABLE[i] = EG_AED-1; - OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; - } -#if 0 - for (i = 0;i < 64 ;i++){ /* make for overflow area */ - LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i, - ((double)(EG_ENT<AR_TABLE[i]) * (1000.0 / OPL->rate), - ((double)(EG_ENT<DR_TABLE[i]) * (1000.0 / OPL->rate) )); - } -#endif -} - -/* ---------- generic table initialize ---------- */ -static int OPLOpenTable( void ) -{ - int s,t; - double rate; - int i,j; - double pom; - - /* allocate dynamic tables */ - if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) - return 0; - if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) - { - free(TL_TABLE); - return 0; - } - if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) - { - free(TL_TABLE); - free(SIN_TABLE); - return 0; - } - if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) - { - free(TL_TABLE); - free(SIN_TABLE); - free(AMS_TABLE); - return 0; - } - /* make total level table */ - for (t = 0;t < EG_ENT-1 ;t++){ - rate = ((1< voltage */ - TL_TABLE[ t] = (int)rate; - TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; -/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/ - } - /* fill volume off area */ - for ( t = EG_ENT-1; t < TL_MAX ;t++){ - TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0; - } - - /* make sinwave table (total level offet) */ - /* degree 0 = degree 180 = off */ - SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; - for (s = 1;s <= SIN_ENT/4;s++){ - pom = sin(2*PI*s/SIN_ENT); /* sin */ - pom = 20*log10(1/pom); /* decibel */ - j = pom / EG_STEP; /* TL_TABLE steps */ - - /* degree 0 - 90 , degree 180 - 90 : plus section */ - SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; - /* degree 180 - 270 , degree 360 - 270 : minus section */ - SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; -/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/ - } - for (s = 0;s < SIN_ENT;s++) - { - SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; - SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; - SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; - } - - /* envelope counter -> envelope output table */ - for (i=0; i= EG_ENT ) pom = EG_ENT-1; */ - ENV_CURVE[i] = (int)pom; - /* DECAY ,RELEASE curve */ - ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; - } - /* off */ - ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; - /* make LFO ams table */ - for (i=0; iSLOT[SLOT1]; - OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; - /* all key off */ - OPL_KEYOFF(slot1); - OPL_KEYOFF(slot2); - /* total level latch */ - slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); - slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); - /* key on */ - CH->op1_out[0] = CH->op1_out[1] = 0; - OPL_KEYON(slot1); - OPL_KEYON(slot2); -} - -/* ---------- opl initialize ---------- */ -static void OPL_initialize(FM_OPL *OPL) -{ - int fn; - - /* frequency base */ - OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; - /* Timer base time */ - OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); - /* make time tables */ - init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); - /* make fnumber -> increment counter table */ - for( fn=0 ; fn < 1024 ; fn++ ) - { - OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; - } - /* LFO freq.table */ - OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<rate * 3.7 * ((double)OPL->clock/3600000) : 0; - OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<rate * 6.4 * ((double)OPL->clock/3600000) : 0; -} - -/* ---------- write a OPL registers ---------- */ -static void OPLWriteReg(FM_OPL *OPL, int r, int v) -{ - OPL_CH *CH; - int slot; - int block_fnum; - - switch(r&0xe0) - { - case 0x00: /* 00-1f:control */ - switch(r&0x1f) - { - case 0x01: - /* wave selector enable */ - if(OPL->type&OPL_TYPE_WAVESEL) - { - OPL->wavesel = v&0x20; - if(!OPL->wavesel) - { - /* preset compatible mode */ - int c; - for(c=0;cmax_ch;c++) - { - OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; - OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; - } - } - } - return; - case 0x02: /* Timer 1 */ - OPL->T[0] = (256-v)*4; - break; - case 0x03: /* Timer 2 */ - OPL->T[1] = (256-v)*16; - return; - case 0x04: /* IRQ clear / mask and Timer enable */ - if(v&0x80) - { /* IRQ flag clear */ - OPL_STATUS_RESET(OPL,0x7f); - } - else - { /* set IRQ mask ,timer enable*/ - UINT8 st1 = v&1; - UINT8 st2 = (v>>1)&1; - /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ - OPL_STATUS_RESET(OPL,v&0x78); - OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); - /* timer 2 */ - if(OPL->st[1] != st2) - { - double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; - OPL->st[1] = st2; - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); - } - /* timer 1 */ - if(OPL->st[0] != st1) - { - double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; - OPL->st[0] = st1; - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); - } - } - return; -#if BUILD_Y8950 - case 0x06: /* Key Board OUT */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_w) - OPL->keyboardhandler_w(OPL->keyboard_param,v); - else - LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); - } - return; - case 0x07: /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - return; - case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ - OPL->mode = v; - v&=0x1f; /* for DELTA-T unit */ - case 0x09: /* START ADD */ - case 0x0a: - case 0x0b: /* STOP ADD */ - case 0x0c: - case 0x0d: /* PRESCALE */ - case 0x0e: - case 0x0f: /* ADPCM data */ - case 0x10: /* DELTA-N */ - case 0x11: /* DELTA-N */ - case 0x12: /* EG-CTRL */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - return; -#if 0 - case 0x15: /* DAC data */ - case 0x16: - case 0x17: /* SHIFT */ - return; - case 0x18: /* I/O CTRL (Direction) */ - if(OPL->type&OPL_TYPE_IO) - OPL->portDirection = v&0x0f; - return; - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - OPL->portLatch = v; - if(OPL->porthandler_w) - OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); - } - return; - case 0x1a: /* PCM data */ - return; -#endif -#endif - } - break; - case 0x20: /* am,vib,ksr,eg type,mul */ - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_mul(OPL,slot,v); - return; - case 0x40: - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_ksl_tl(OPL,slot,v); - return; - case 0x60: - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_ar_dr(OPL,slot,v); - return; - case 0x80: - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_sl_rr(OPL,slot,v); - return; - case 0xa0: - switch(r) - { - case 0xbd: - /* amsep,vibdep,r,bd,sd,tom,tc,hh */ - { - UINT8 rkey = OPL->rhythm^v; - OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; - OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; - OPL->rhythm = v&0x3f; - if(OPL->rhythm&0x20) - { -#if 0 - usrintf_showmessage("OPL Rhythm mode select"); -#endif - /* BD key on/off */ - if(rkey&0x10) - { - if(v&0x10) - { - OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; - OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); - OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); - } - else - { - OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); - OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); - } - } - /* SD key on/off */ - if(rkey&0x08) - { - if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); - else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); - }/* TAM key on/off */ - if(rkey&0x04) - { - if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); - else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); - } - /* TOP-CY key on/off */ - if(rkey&0x02) - { - if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); - else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); - } - /* HH key on/off */ - if(rkey&0x01) - { - if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); - else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); - } - } - } - return; - } - /* keyon,block,fnum */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - if(!(r&0x10)) - { /* a0-a8 */ - block_fnum = (CH->block_fnum&0x1f00) | v; - } - else - { /* b0-b8 */ - int keyon = (v>>5)&1; - block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); - if(CH->keyon != keyon) - { - if( (CH->keyon=keyon) ) - { - CH->op1_out[0] = CH->op1_out[1] = 0; - OPL_KEYON(&CH->SLOT[SLOT1]); - OPL_KEYON(&CH->SLOT[SLOT2]); - } - else - { - OPL_KEYOFF(&CH->SLOT[SLOT1]); - OPL_KEYOFF(&CH->SLOT[SLOT2]); - } - } - } - /* update */ - if(CH->block_fnum != block_fnum) - { - int blockRv = 7-(block_fnum>>10); - int fnum = block_fnum&0x3ff; - CH->block_fnum = block_fnum; - - CH->ksl_base = KSL_TABLE[block_fnum>>6]; - CH->fc = OPL->FN_TABLE[fnum]>>blockRv; - CH->kcode = CH->block_fnum>>9; - if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; - CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); - CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); - } - return; - case 0xc0: - /* FB,C */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - { - int feedback = (v>>1)&7; - CH->FB = feedback ? (8+1) - feedback : 0; - CH->CON = v&1; - set_algorithm(CH); - } - return; - case 0xe0: /* wave type */ - slot = slot_array[r&0x1f]; - if(slot == -1) return; - CH = &OPL->P_CH[slot/2]; - if(OPL->wavesel) - { - /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */ - CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; - } - return; - } -} - -/* lock/unlock for common table */ -static int OPL_LockTable(void) -{ - num_lock++; - if(num_lock>1) return 0; - /* first time */ - cur_chip = NULL; - /* allocate total level table (128kb space) */ - if( !OPLOpenTable() ) - { - num_lock--; - return -1; - } - return 0; -} - -static void OPL_UnLockTable(void) -{ - if(num_lock) num_lock--; - if(num_lock) return; - /* last time */ - cur_chip = NULL; - OPLCloseTable(); -} - -#if (BUILD_YM3812 || BUILD_YM3526) -/*******************************************************************************/ -/* YM3812 local section */ -/*******************************************************************************/ - -/* ---------- update one of chip ----------- */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) -{ - int i; - int data; - OPLSAMPLE *buf = buffer; - UINT32 amsCnt = OPL->amsCnt; - UINT32 vibCnt = OPL->vibCnt; - UINT8 rhythm = OPL->rhythm&0x20; - OPL_CH *CH,*R_CH; - - if( (void *)OPL != cur_chip ){ - cur_chip = (void *)OPL; - /* channel pointers */ - S_CH = OPL->P_CH; - E_CH = &S_CH[9]; - /* rhythm slot */ - SLOT7_1 = &S_CH[7].SLOT[SLOT1]; - SLOT7_2 = &S_CH[7].SLOT[SLOT2]; - SLOT8_1 = &S_CH[8].SLOT[SLOT1]; - SLOT8_2 = &S_CH[8].SLOT[SLOT2]; - /* LFO state */ - amsIncr = OPL->amsIncr; - vibIncr = OPL->vibIncr; - ams_table = OPL->ams_table; - vib_table = OPL->vib_table; - } - R_CH = rhythm ? &S_CH[6] : E_CH; - for( i=0; i < length ; i++ ) - { - /* channel A channel B channel C */ - /* LFO */ - ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; - vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; - outd[0] = 0; - /* FM part */ - for(CH=S_CH ; CH < R_CH ; CH++) - OPL_CALC_CH(CH); - /* Rythn part */ - if(rhythm) - OPL_CALC_RH(S_CH); - /* limit check */ - data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); - /* store to sound buffer */ - buf[i] = data >> OPL_OUTSB; - } - - OPL->amsCnt = amsCnt; - OPL->vibCnt = vibCnt; -#ifdef OPL_OUTPUT_LOG - if(opl_dbg_fp) - { - for(opl_dbg_chip=0;opl_dbg_chipamsCnt; - UINT32 vibCnt = OPL->vibCnt; - UINT8 rhythm = OPL->rhythm&0x20; - OPL_CH *CH,*R_CH; - YM_DELTAT *DELTAT = OPL->deltat; - - /* setup DELTA-T unit */ - YM_DELTAT_DECODE_PRESET(DELTAT); - - if( (void *)OPL != cur_chip ){ - cur_chip = (void *)OPL; - /* channel pointers */ - S_CH = OPL->P_CH; - E_CH = &S_CH[9]; - /* rhythm slot */ - SLOT7_1 = &S_CH[7].SLOT[SLOT1]; - SLOT7_2 = &S_CH[7].SLOT[SLOT2]; - SLOT8_1 = &S_CH[8].SLOT[SLOT1]; - SLOT8_2 = &S_CH[8].SLOT[SLOT2]; - /* LFO state */ - amsIncr = OPL->amsIncr; - vibIncr = OPL->vibIncr; - ams_table = OPL->ams_table; - vib_table = OPL->vib_table; - } - R_CH = rhythm ? &S_CH[6] : E_CH; - for( i=0; i < length ; i++ ) - { - /* channel A channel B channel C */ - /* LFO */ - ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; - vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; - outd[0] = 0; - /* deltaT ADPCM */ - if( DELTAT->portstate ) - YM_DELTAT_ADPCM_CALC(DELTAT); - /* FM part */ - for(CH=S_CH ; CH < R_CH ; CH++) - OPL_CALC_CH(CH); - /* Rythn part */ - if(rhythm) - OPL_CALC_RH(S_CH); - /* limit check */ - data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); - /* store to sound buffer */ - buf[i] = data >> OPL_OUTSB; - } - OPL->amsCnt = amsCnt; - OPL->vibCnt = vibCnt; - /* deltaT START flag */ - if( !DELTAT->portstate ) - OPL->status &= 0xfe; -} -#endif - -/* ---------- reset one of chip ---------- */ -void OPLResetChip(FM_OPL *OPL) -{ - int c,s; - int i; - - /* reset chip */ - OPL->mode = 0; /* normal mode */ - OPL_STATUS_RESET(OPL,0x7f); - /* reset with register write */ - OPLWriteReg(OPL,0x01,0); /* wabesel disable */ - OPLWriteReg(OPL,0x02,0); /* Timer1 */ - OPLWriteReg(OPL,0x03,0); /* Timer2 */ - OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ - for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); - /* reset operator parameter */ - for( c = 0 ; c < OPL->max_ch ; c++ ) - { - OPL_CH *CH = &OPL->P_CH[c]; - /* OPL->P_CH[c].PAN = OPN_CENTER; */ - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = &SIN_TABLE[0]; - /* CH->SLOT[s].evm = ENV_MOD_RR; */ - CH->SLOT[s].evc = EG_OFF; - CH->SLOT[s].eve = EG_OFF+1; - CH->SLOT[s].evs = 0; - } - } -#if BUILD_Y8950 - if(OPL->type&OPL_TYPE_ADPCM) - { - YM_DELTAT *DELTAT = OPL->deltat; - - DELTAT->freqbase = OPL->freqbase; - DELTAT->output_pointer = outd; - DELTAT->portshift = 5; - DELTAT->output_range = DELTAT_MIXING_LEVEL<P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch; -#if BUILD_Y8950 - if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); -#endif - /* set channel state pointer */ - OPL->type = type; - OPL->clock = clock; - OPL->rate = rate; - OPL->max_ch = max_ch; - /* init grobal tables */ - OPL_initialize(OPL); - /* reset chip */ - OPLResetChip(OPL); -#ifdef OPL_OUTPUT_LOG - if(!opl_dbg_fp) - { - opl_dbg_fp = fopen("opllog.opl","wb"); - opl_dbg_maxchip = 0; - } - if(opl_dbg_fp) - { - opl_dbg_opl[opl_dbg_maxchip] = OPL; - fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, - type, - clock&0xff, - (clock/0x100)&0xff, - (clock/0x10000)&0xff, - (clock/0x1000000)&0xff); - opl_dbg_maxchip++; - } -#endif - return OPL; -} - -/* ---------- Destroy one of vietual YM3812 ---------- */ -void OPLDestroy(FM_OPL *OPL) -{ -#ifdef OPL_OUTPUT_LOG - if(opl_dbg_fp) - { - fclose(opl_dbg_fp); - opl_dbg_fp = NULL; - } -#endif - OPL_UnLockTable(); - free(OPL); -} - -/* ---------- Option handlers ---------- */ - -void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) -{ - OPL->TimerHandler = TimerHandler; - OPL->TimerParam = channelOffset; -} -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = param; -} -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = param; -} -#if BUILD_Y8950 -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) -{ - OPL->porthandler_w = PortHandler_w; - OPL->porthandler_r = PortHandler_r; - OPL->port_param = param; -} - -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) -{ - OPL->keyboardhandler_w = KeyboardHandler_w; - OPL->keyboardhandler_r = KeyboardHandler_r; - OPL->keyboard_param = param; -} -#endif -/* ---------- YM3812 I/O interface ---------- */ -int OPLWrite(FM_OPL *OPL,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - OPL->address = v & 0xff; - } - else - { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); -#ifdef OPL_OUTPUT_LOG - if(opl_dbg_fp) - { - for(opl_dbg_chip=0;opl_dbg_chipaddress,v); - } -#endif - OPLWriteReg(OPL,OPL->address,v); - } - return OPL->status>>7; -} - -unsigned char OPLRead(FM_OPL *OPL,int a) -{ - if( !(a&1) ) - { /* status port */ - return OPL->status & (OPL->statusmask|0x80); - } - /* data port */ - switch(OPL->address) - { - case 0x05: /* KeyBoard IN */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_r) - return OPL->keyboardhandler_r(OPL->keyboard_param); - else { - LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); - } - } - return 0; -#if 0 - case 0x0f: /* ADPCM-DATA */ - return 0; -#endif - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - if(OPL->porthandler_r) - return OPL->porthandler_r(OPL->port_param); - else { - LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); - } - } - return 0; - case 0x1a: /* PCM-DATA */ - return 0; - } - return 0; -} - -int OPLTimerOver(FM_OPL *OPL,int c) -{ - if( c ) - { /* Timer B */ - OPL_STATUS_SET(OPL,0x20); - } - else - { /* Timer A */ - OPL_STATUS_SET(OPL,0x40); - /* CSM mode key,TL control */ - if( OPL->mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - for(ch=0;ch<9;ch++) - CSMKeyControll( &OPL->P_CH[ch] ); - } - } - /* reload timer */ - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); - return OPL->status>>7; -} diff --git a/qemu/hw/audio/fmopl.h b/qemu/hw/audio/fmopl.h deleted file mode 100644 index 24ba5f480..000000000 --- a/qemu/hw/audio/fmopl.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef __FMOPL_H_ -#define __FMOPL_H_ - -/* --- select emulation chips --- */ -#define BUILD_YM3812 (HAS_YM3812) -//#define BUILD_YM3526 (HAS_YM3526) -//#define BUILD_Y8950 (HAS_Y8950) - -/* --- system optimize --- */ -/* select bit size of output : 8 or 16 */ -#define OPL_OUTPUT_BIT 16 - -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -#endif - -#if (OPL_OUTPUT_BIT==16) -typedef INT16 OPLSAMPLE; -#endif -#if (OPL_OUTPUT_BIT==8) -typedef unsigned char OPLSAMPLE; -#endif - - -#if BUILD_Y8950 -#include "ymdeltat.h" -#endif - -typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); -typedef void (*OPL_IRQHANDLER)(int param,int irq); -typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); -typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); -typedef unsigned char (*OPL_PORTHANDLER_R)(int param); - -/* !!!!! here is private section , do not access there member direct !!!!! */ - -#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ -#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ -#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ -#define OPL_TYPE_IO 0x08 /* I/O port */ - -/* Saving is necessary for member of the 'R' mark for suspend/resume */ -/* ---------- OPL one of slot ---------- */ -typedef struct fm_opl_slot { - INT32 TL; /* total level :TL << 8 */ - INT32 TLL; /* adjusted now TL */ - UINT8 KSR; /* key scale rate :(shift down bit) */ - INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ - INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ - INT32 SL; /* sustin level :SL_TALBE[SL] */ - INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ - UINT8 ksl; /* keyscale level :(shift down bits) */ - UINT8 ksr; /* key scale rate :kcode>>KSR */ - UINT32 mul; /* multiple :ML_TABLE[ML] */ - UINT32 Cnt; /* frequency count : */ - UINT32 Incr; /* frequency step : */ - /* envelope generator state */ - UINT8 eg_typ; /* envelope type flag */ - UINT8 evm; /* envelope phase */ - INT32 evc; /* envelope counter */ - INT32 eve; /* envelope counter end point */ - INT32 evs; /* envelope counter step */ - INT32 evsa; /* envelope step for AR :AR[ksr] */ - INT32 evsd; /* envelope step for DR :DR[ksr] */ - INT32 evsr; /* envelope step for RR :RR[ksr] */ - /* LFO */ - UINT8 ams; /* ams flag */ - UINT8 vib; /* vibrate flag */ - /* wave selector */ - INT32 **wavetable; -}OPL_SLOT; - -/* ---------- OPL one of channel ---------- */ -typedef struct fm_opl_channel { - OPL_SLOT SLOT[2]; - UINT8 CON; /* connection type */ - UINT8 FB; /* feed back :(shift down bit) */ - INT32 *connect1; /* slot1 output pointer */ - INT32 *connect2; /* slot2 output pointer */ - INT32 op1_out[2]; /* slot1 output for selfeedback */ - /* phase generator state */ - UINT32 block_fnum; /* block+fnum : */ - UINT8 kcode; /* key code : KeyScaleCode */ - UINT32 fc; /* Freq. Increment base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 keyon; /* key on/off flag */ -} OPL_CH; - -/* OPL state */ -typedef struct fm_opl_f { - UINT8 type; /* chip type */ - int clock; /* master clock (Hz) */ - int rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - double TimerBase; /* Timer base time (==sampling time) */ - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT8 statusmask; /* status mask */ - UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ - /* Timer */ - int T[2]; /* timer counter */ - UINT8 st[2]; /* timer enable */ - /* FM channel slots */ - OPL_CH *P_CH; /* pointer of CH */ - int max_ch; /* maximum channel */ - /* Rhythm sention */ - UINT8 rhythm; /* Rhythm mode , key flag */ -#if BUILD_Y8950 - /* Delta-T ADPCM unit (Y8950) */ - YM_DELTAT *deltat; /* DELTA-T ADPCM */ -#endif - /* Keyboard / I/O interface unit (Y8950) */ - UINT8 portDirection; - UINT8 portLatch; - OPL_PORTHANDLER_R porthandler_r; - OPL_PORTHANDLER_W porthandler_w; - int port_param; - OPL_PORTHANDLER_R keyboardhandler_r; - OPL_PORTHANDLER_W keyboardhandler_w; - int keyboard_param; - /* time tables */ - INT32 AR_TABLE[75]; /* atttack rate tables */ - INT32 DR_TABLE[75]; /* decay rate tables */ - UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ - /* LFO */ - INT32 *ams_table; - INT32 *vib_table; - INT32 amsCnt; - INT32 amsIncr; - INT32 vibCnt; - INT32 vibIncr; - /* wave selector enable flag */ - UINT8 wavesel; - /* external event callback handler */ - OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ - int TimerParam; /* TIMER parameter */ - OPL_IRQHANDLER IRQHandler; /* IRQ handler */ - int IRQParam; /* IRQ parameter */ - OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ - int UpdateParam; /* stream update parameter */ -} FM_OPL; - -/* ---------- Generic interface section ---------- */ -#define OPL_TYPE_YM3526 (0) -#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) -#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) - -FM_OPL *OPLCreate(int type, int clock, int rate); -void OPLDestroy(FM_OPL *OPL); -void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); -/* Y8950 port handlers */ -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); - -void OPLResetChip(FM_OPL *OPL); -int OPLWrite(FM_OPL *OPL,int a,int v); -unsigned char OPLRead(FM_OPL *OPL,int a); -int OPLTimerOver(FM_OPL *OPL,int c); - -/* YM3626/YM3812 local section */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - -#endif diff --git a/qemu/hw/audio/gus.c b/qemu/hw/audio/gus.c deleted file mode 100644 index 9dd6947be..000000000 --- a/qemu/hw/audio/gus.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz - * - * Copyright (c) 2002-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "hw/isa/isa.h" -#include "gusemu.h" -#include "gustate.h" - -#define dolog(...) AUD_log ("audio", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif - -#ifdef HOST_WORDS_BIGENDIAN -#define GUS_ENDIANNESS 1 -#else -#define GUS_ENDIANNESS 0 -#endif - -#define TYPE_GUS "gus" -#define GUS(obj) OBJECT_CHECK (GUSState, (obj), TYPE_GUS) - -typedef struct GUSState { - ISADevice dev; - GUSEmuState emu; - QEMUSoundCard card; - uint32_t freq; - uint32_t port; - int pos, left, shift, irqs; - GUSsample *mixbuf; - uint8_t himem[1024 * 1024 + 32 + 4096]; - int samples; - SWVoiceOut *voice; - int64_t last_ticks; - qemu_irq pic; - IsaDma *isa_dma; -} GUSState; - -static uint32_t gus_readb(void *opaque, uint32_t nport) -{ - GUSState *s = opaque; - - return gus_read (&s->emu, nport, 1); -} - -static void gus_writeb(void *opaque, uint32_t nport, uint32_t val) -{ - GUSState *s = opaque; - - gus_write (&s->emu, nport, 1, val); -} - -static int write_audio (GUSState *s, int samples) -{ - int net = 0; - int pos = s->pos; - - while (samples) { - int nbytes, wbytes, wsampl; - - nbytes = samples << s->shift; - wbytes = AUD_write ( - s->voice, - s->mixbuf + (pos << (s->shift - 1)), - nbytes - ); - - if (wbytes) { - wsampl = wbytes >> s->shift; - - samples -= wsampl; - pos = (pos + wsampl) % s->samples; - - net += wsampl; - } - else { - break; - } - } - - return net; -} - -static void GUS_callback (void *opaque, int free) -{ - int samples, to_play, net = 0; - GUSState *s = opaque; - - samples = free >> s->shift; - to_play = audio_MIN (samples, s->left); - - while (to_play) { - int written = write_audio (s, to_play); - - if (!written) { - goto reset; - } - - s->left -= written; - to_play -= written; - samples -= written; - net += written; - } - - samples = audio_MIN (samples, s->samples); - if (samples) { - gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf); - - while (samples) { - int written = write_audio (s, samples); - if (!written) { - break; - } - samples -= written; - net += written; - } - } - s->left = samples; - - reset: - gus_irqgen (&s->emu, muldiv64 (net, 1000000, s->freq)); -} - -int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n) -{ - GUSState *s = emu->opaque; - /* qemu_irq_lower (s->pic); */ - qemu_irq_raise (s->pic); - s->irqs += n; - ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs); - return n; -} - -void GUS_irqclear (GUSEmuState *emu, int hwirq) -{ - GUSState *s = emu->opaque; - ldebug ("irqclear %d %d\n", hwirq, s->irqs); - qemu_irq_lower (s->pic); - s->irqs -= 1; -#ifdef IRQ_STORM - if (s->irqs > 0) { - qemu_irq_raise (s->pic[hwirq]); - } -#endif -} - -void GUS_dmarequest (GUSEmuState *emu) -{ - GUSState *s = emu->opaque; - IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); - ldebug ("dma request %d\n", der->gusdma); - k->hold_DREQ(s->isa_dma, s->emu.gusdma); -} - -static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) -{ - GUSState *s = opaque; - IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma); - char tmpbuf[4096]; - int pos = dma_pos, mode, left = dma_len - dma_pos; - - ldebug ("read DMA %#x %d\n", dma_pos, dma_len); - mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma); - while (left) { - int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf)); - int copied; - - ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos); - copied = k->read_memory(s->isa_dma, nchan, tmpbuf, pos, to_copy); - gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied); - left -= copied; - pos += copied; - } - - if (((mode >> 4) & 1) == 0) { - k->release_DREQ(s->isa_dma, s->emu.gusdma); - } - return dma_len; -} - -static const VMStateDescription vmstate_gus = { - .name = "gus", - .version_id = 2, - .minimum_version_id = 2, - .fields = (VMStateField[]) { - VMSTATE_INT32 (pos, GUSState), - VMSTATE_INT32 (left, GUSState), - VMSTATE_INT32 (shift, GUSState), - VMSTATE_INT32 (irqs, GUSState), - VMSTATE_INT32 (samples, GUSState), - VMSTATE_INT64 (last_ticks, GUSState), - VMSTATE_BUFFER (himem, GUSState), - VMSTATE_END_OF_LIST () - } -}; - -static const MemoryRegionPortio gus_portio_list1[] = { - {0x000, 1, 1, .write = gus_writeb }, - {0x006, 10, 1, .read = gus_readb, .write = gus_writeb }, - {0x100, 8, 1, .read = gus_readb, .write = gus_writeb }, - PORTIO_END_OF_LIST (), -}; - -static const MemoryRegionPortio gus_portio_list2[] = { - {0, 2, 1, .read = gus_readb }, - PORTIO_END_OF_LIST (), -}; - -static void gus_realizefn (DeviceState *dev, Error **errp) -{ - ISADevice *d = ISA_DEVICE(dev); - GUSState *s = GUS (dev); - IsaDmaClass *k; - struct audsettings as; - - AUD_register_card ("gus", &s->card); - - as.freq = s->freq; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = GUS_ENDIANNESS; - - s->voice = AUD_open_out ( - &s->card, - NULL, - "gus", - s, - GUS_callback, - &as - ); - - if (!s->voice) { - AUD_remove_card (&s->card); - error_setg(errp, "No voice"); - return; - } - - s->shift = 2; - s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift; - s->mixbuf = g_malloc0 (s->samples << s->shift); - - isa_register_portio_list (d, s->port, gus_portio_list1, s, "gus"); - isa_register_portio_list (d, (s->port + 0x100) & 0xf00, - gus_portio_list2, s, "gus"); - - s->isa_dma = isa_get_dma(isa_bus_from_device(d), s->emu.gusdma); - k = ISADMA_GET_CLASS(s->isa_dma); - k->register_channel(s->isa_dma, s->emu.gusdma, GUS_read_DMA, s); - s->emu.himemaddr = s->himem; - s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32; - s->emu.opaque = s; - isa_init_irq (d, &s->pic, s->emu.gusirq); - - AUD_set_active_out (s->voice, 1); -} - -static int GUS_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_GUS); - return 0; -} - -static Property gus_properties[] = { - DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100), - DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240), - DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7), - DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3), - DEFINE_PROP_END_OF_LIST (), -}; - -static void gus_class_initfn (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - - dc->realize = gus_realizefn; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "Gravis Ultrasound GF1"; - dc->vmsd = &vmstate_gus; - dc->props = gus_properties; -} - -static const TypeInfo gus_info = { - .name = TYPE_GUS, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof (GUSState), - .class_init = gus_class_initfn, -}; - -static void gus_register_types (void) -{ - type_register_static (&gus_info); - isa_register_soundhw("gus", "Gravis Ultrasound GF1", GUS_init); -} - -type_init (gus_register_types) diff --git a/qemu/hw/audio/gusemu.h b/qemu/hw/audio/gusemu.h deleted file mode 100644 index b7f075126..000000000 --- a/qemu/hw/audio/gusemu.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * GUSEMU32 - API - * - * Copyright (C) 2000-2007 Tibor "TS" Schütz - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef GUSEMU_H -#define GUSEMU_H - -/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */ - -#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */ - typedef unsigned char GUSbyte; - typedef unsigned short GUSword; - typedef unsigned int GUSdword; - typedef signed char GUSchar; - typedef signed short GUSsample; -#else - typedef int8_t GUSchar; - typedef uint8_t GUSbyte; - typedef uint16_t GUSword; - typedef uint32_t GUSdword; - typedef int16_t GUSsample; -#endif - -typedef struct _GUSEmuState -{ - GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */ - GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */ - uint32_t gusirq; - uint32_t gusdma; - unsigned int timer1fraction; - unsigned int timer2fraction; - void *opaque; -} GUSEmuState; - -/* ** Callback functions needed: */ -/* NMI is defined as hwirq=-1 (not supported (yet?)) */ -/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */ -/* Level triggered IRQ simulations normally return 1 */ -/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */ -int GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */ -void GUS_irqclear( GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */ -void GUS_dmarequest(GUSEmuState *state); /* used by gus_write() only - can be left empty for mixer functions */ - -/* ** ISA bus interface functions: */ - -/* Port I/O handlers */ -/* support the following ports: */ -/* 2x0,2x6,2x8...2xF,3x0...3x7; */ -/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */ -/* data is passed in host byte order */ -unsigned int gus_read( GUSEmuState *state, int port, int size); -void gus_write(GUSEmuState *state, int port, int size, unsigned int data); -/* size is given in bytes (1 for byte, 2 for word) */ - -/* DMA data transfer function */ -/* data pointed to is passed in native x86 order */ -void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC); -/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */ -/* (might be immediately if the DMA controller was programmed first) */ -/* dma_addr is an already translated address directly pointing to the beginning of the memory block */ -/* do not forget to update DMA states after the call, including the DREQ and TC flags */ -/* it is possible to break down a single transfer into multiple ones, but take care that: */ -/* -dma_count is actually count-1 */ -/* -before and during a transfer, DREQ is set and TC cleared */ -/* -when calling gus_dma_transferdata(), TC is only set true for call transferring the last byte */ -/* -after the last transfer, DREQ is cleared and TC is set */ - -/* ** GF1 mixer emulation functions: */ -/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */ -/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */ -/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */ -/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */ -/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */ - -void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos); -/* recommended range: 10 < numsamples < 100 */ -/* lower values may result in increased rounding error, higher values often cause audible timing delays */ - -void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time); -/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */ -/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */ -/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */ - -#endif /* gusemu.h */ diff --git a/qemu/hw/audio/gusemu_hal.c b/qemu/hw/audio/gusemu_hal.c deleted file mode 100644 index 973d6b9f4..000000000 --- a/qemu/hw/audio/gusemu_hal.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * GUSEMU32 - bus interface part - * - * Copyright (C) 2000-2007 Tibor "TS" Schütz - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)? - */ - -#include "qemu/osdep.h" -#include "gustate.h" -#include "gusemu.h" - -#define GUSregb(position) (* (gusptr+(position))) -#define GUSregw(position) (*(GUSword *) (gusptr+(position))) -#define GUSregd(position) (*(GUSdword *)(gusptr+(position))) - -/* size given in bytes */ -unsigned int gus_read(GUSEmuState * state, int port, int size) -{ - int value_read = 0; - - GUSbyte *gusptr; - gusptr = state->gusdatapos; - GUSregd(portaccesses)++; - - switch (port & 0xff0f) - { - /* MixerCtrlReg (read not supported on GUS classic) */ - /* case 0x200: return GUSregb(MixerCtrlReg2x0); */ - case 0x206: /* IRQstatReg / SB2x6IRQ */ - /* adlib/sb bits set in port handlers */ - /* timer/voice bits set in gus_irqgen() */ - /* dma bit set in gus_dma_transferdata */ - /* midi not implemented yet */ - return GUSregb(IRQStatReg2x6); - /* case 0x308: */ /* AdLib388 */ - case 0x208: - if (GUSregb(GUS45TimerCtrl) & 1) - return GUSregb(TimerStatus2x8); - return GUSregb(AdLibStatus2x8); /* AdLibStatus */ - case 0x309: /* AdLib389 */ - case 0x209: - return GUSregb(AdLibData2x9); /* AdLibData */ - case 0x20A: - return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */ - -#if 0 - case 0x20B: /* GUS hidden registers (read not supported on GUS classic) */ - switch (GUSregb(RegCtrl_2xF) & 0x07) - { - case 0: /* IRQ/DMA select */ - if (GUSregb(MixerCtrlReg2x0) & 0x40) - return GUSregb(IRQ_2xB); /* control register select bit */ - else - return GUSregb(DMA_2xB); - /* case 1-5: */ /* general purpose emulation regs */ - /* return ... */ /* + status reset reg (write only) */ - case 6: - return GUSregb(Jumper_2xB); /* Joystick/MIDI enable (JumperReg) */ - default:; - } - break; -#endif - - case 0x20C: /* SB2xCd */ - value_read = GUSregb(SB2xCd); - if (GUSregb(StatRead_2xF) & 0x20) - GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */ - return value_read; - /* case 0x20D: */ /* SB2xD is write only -> 2xE writes to it*/ - case 0x20E: - if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */ - { - GUSregb(StatRead_2xF) |= 0x80; - GUS_irqrequest(state, state->gusirq, 1); - } - return GUSregb(SB2xE); /* SB2xE */ - case 0x20F: /* StatRead_2xF */ - /*set/clear fixed bits */ - /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/ - value_read = (GUSregb(StatRead_2xF) & 0xf9); - if (GUSregb(MixerCtrlReg2x0) & 0x08) - value_read |= 2; /* DMA/IRQ enabled flag */ - return value_read; - /* case 0x300: */ /* MIDI (not implemented) */ - /* case 0x301: */ /* MIDI (not implemented) */ - case 0x302: - return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */ - case 0x303: - return GUSregb(FunkSelReg3x3); /* FunkSelReg */ - case 0x304: /* DataRegLoByte3x4 + DataRegWord3x4 */ - case 0x305: /* DataRegHiByte3x5 */ - switch (GUSregb(FunkSelReg3x3)) - { - /* common functions */ - case 0x41: /* DramDMAContrReg */ - value_read = GUSregb(GUS41DMACtrl); /* &0xfb */ - GUSregb(GUS41DMACtrl) &= 0xbb; - if (state->gusdma >= 4) - value_read |= 0x04; - if (GUSregb(IRQStatReg2x6) & 0x80) - { - value_read |= 0x40; - GUSregb(IRQStatReg2x6) &= 0x7f; - if (!GUSregb(IRQStatReg2x6)) - GUS_irqclear(state, state->gusirq); - } - return (GUSbyte) value_read; - /* DramDMAmemPosReg */ - /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/ - /* 43h+44h write only */ - case 0x45: - return GUSregb(GUS45TimerCtrl); /* TimerCtrlReg */ - /* 46h+47h write only */ - /* 48h: samp freq - write only */ - case 0x49: - return GUSregb(GUS49SampCtrl) & 0xbf; /* SampCtrlReg */ - /* case 4bh: */ /* joystick trim not supported */ - /* case 0x4c: return GUSregb(GUS4cReset); */ /* GUSreset: write only*/ - /* voice specific functions */ - case 0x80: - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x85: - case 0x86: - case 0x87: - case 0x88: - case 0x89: - case 0x8a: - case 0x8b: - case 0x8c: - case 0x8d: - { - int offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); - offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ - value_read = GUSregw(offset); - } - break; - /* voice unspecific functions */ - case 0x8e: /* NumVoice */ - return GUSregb(NumVoices); - case 0x8f: /* irqstatreg */ - /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */ - return GUSregb(SynVoiceIRQ8f); - default: - return 0xffff; - } - if (size == 1) - { - if ((port & 0xff0f) == 0x305) - value_read = value_read >> 8; - value_read &= 0xff; - } - return (GUSword) value_read; - /* case 0x306: */ /* Mixer/Version info */ - /* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */ - case 0x307: /* DRAMaccess */ - { - GUSbyte *adr; - adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff); - return *adr; - } - default:; - } - return 0xffff; -} - -void gus_write(GUSEmuState * state, int port, int size, unsigned int data) -{ - GUSbyte *gusptr; - gusptr = state->gusdatapos; - GUSregd(portaccesses)++; - - switch (port & 0xff0f) - { - case 0x200: /* MixerCtrlReg */ - GUSregb(MixerCtrlReg2x0) = (GUSbyte) data; - break; - case 0x206: /* IRQstatReg / SB2x6IRQ */ - if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */ - { - GUSregb(TimerStatus2x8) |= 0x08; - GUSregb(IRQStatReg2x6) = 0x10; - GUS_irqrequest(state, state->gusirq, 1); - } - break; - case 0x308: /* AdLib 388h */ - case 0x208: /* AdLibCommandReg */ - GUSregb(AdLibCommand2xA) = (GUSbyte) data; - break; - case 0x309: /* AdLib 389h */ - case 0x209: /* AdLibDataReg */ - if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */ - { - if (data & 0x80) - GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */ - else - GUSregb(TimerDataReg2x9) = (GUSbyte) data; - } - else - { - GUSregb(AdLibData2x9) = (GUSbyte) data; - if (GUSregb(GUS45TimerCtrl) & 0x02) - { - GUSregb(TimerStatus2x8) |= 0x01; - GUSregb(IRQStatReg2x6) = 0x10; - GUS_irqrequest(state, state->gusirq, 1); - } - } - break; - case 0x20A: - GUSregb(AdLibStatus2x8) = (GUSbyte) data; - break; /* AdLibStatus2x8 */ - case 0x20B: /* GUS hidden registers */ - switch (GUSregb(RegCtrl_2xF) & 0x7) - { - case 0: - if (GUSregb(MixerCtrlReg2x0) & 0x40) - GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */ - else - GUSregb(DMA_2xB) = (GUSbyte) data; - break; - /* case 1-4: general purpose emulation regs */ - case 5: /* clear stat reg 2xF */ - GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */ - if (!GUSregb(IRQStatReg2x6)) - GUS_irqclear(state, state->gusirq); - break; - case 6: /* Jumper reg (Joystick/MIDI enable) */ - GUSregb(Jumper_2xB) = (GUSbyte) data; - break; - default:; - } - break; - case 0x20C: /* SB2xCd */ - if (GUSregb(GUS45TimerCtrl) & 0x20) - { - GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */ - GUSregb(IRQStatReg2x6) = 0x10; - GUS_irqrequest(state, state->gusirq, 1); - } - case 0x20D: /* SB2xCd no IRQ */ - GUSregb(SB2xCd) = (GUSbyte) data; - break; - case 0x20E: /* SB2xE */ - GUSregb(SB2xE) = (GUSbyte) data; - break; - case 0x20F: - GUSregb(RegCtrl_2xF) = (GUSbyte) data; - break; /* CtrlReg2xF */ - case 0x302: /* VoiceSelReg */ - GUSregb(VoiceSelReg3x2) = (GUSbyte) data; - break; - case 0x303: /* FunkSelReg */ - GUSregb(FunkSelReg3x3) = (GUSbyte) data; - if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */ - { - int voice; - if (GUSregd(voicewavetableirq)) /* WavetableIRQ */ - { - for (voice = 0; voice < 31; voice++) - { - if (GUSregd(voicewavetableirq) & (1 << voice)) - { - GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */ - GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */ - if (!GUSregd(voicewavetableirq)) - GUSregb(IRQStatReg2x6) &= 0xdf; - if (!GUSregb(IRQStatReg2x6)) - GUS_irqclear(state, state->gusirq); - GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */ - return; - } - } - } - else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */ - { - for (voice = 0; voice < 31; voice++) - { - if (GUSregd(voicevolrampirq) & (1 << voice)) - { - GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */ - GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */ - if (!GUSregd(voicevolrampirq)) - GUSregb(IRQStatReg2x6) &= 0xbf; - if (!GUSregb(IRQStatReg2x6)) - GUS_irqclear(state, state->gusirq); - GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */ - return; - } - } - } - GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */ - } - break; - case 0x304: - case 0x305: - { - GUSword writedata = (GUSword) data; - GUSword readmask = 0x0000; - if (size == 1) - { - readmask = 0xff00; - writedata &= 0xff; - if ((port & 0xff0f) == 0x305) - { - writedata = (GUSword) (writedata << 8); - readmask = 0x00ff; - } - } - switch (GUSregb(FunkSelReg3x3)) - { - /* voice specific functions */ - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x0c: - case 0x0d: - { - int offset; - if (!(GUSregb(GUS4cReset) & 0x01)) - break; /* reset flag active? */ - offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f); - offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */ - GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata); - } - break; - /* voice unspecific functions */ - case 0x0e: /* NumVoices */ - GUSregb(NumVoices) = (GUSbyte) data; - break; - /* case 0x0f: */ /* read only */ - /* common functions */ - case 0x41: /* DramDMAContrReg */ - GUSregb(GUS41DMACtrl) = (GUSbyte) data; - if (data & 0x01) - GUS_dmarequest(state); - break; - case 0x42: /* DramDMAmemPosReg */ - GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata; - GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */ - break; - case 0x43: /* DRAMaddrLo */ - GUSregd(GUSDRAMPOS24bit) = - (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata; - break; - case 0x44: /* DRAMaddrHi */ - GUSregd(GUSDRAMPOS24bit) = - (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16); - break; - case 0x45: /* TCtrlReg */ - GUSregb(GUS45TimerCtrl) = (GUSbyte) data; - if (!(data & 0x20)) - GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */ - if (!(data & 0x02)) - GUSregb(TimerStatus2x8) &= 0xfe; /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */ - if (!(GUSregb(TimerStatus2x8) & 0x19)) - GUSregb(IRQStatReg2x6) &= 0xef; /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */ - /* catch up delayed timer IRQs: */ - if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3)) - { - if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ - { - if (!(GUSregb(TimerDataReg2x9) & 0x40)) - GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */ - if (data & 4) /* timer1 irq enable */ - { - GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */ - GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */ - } - } - if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */ - { - if (!(GUSregb(TimerDataReg2x9) & 0x20)) - GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */ - if (data & 8) /* timer2 irq enable */ - { - GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */ - GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */ - } - } - GUSregw(TimerIRQs)--; - if (GUSregw(BusyTimerIRQs) > 1) - GUSregw(BusyTimerIRQs)--; - else - GUSregw(BusyTimerIRQs) = - GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs)); - } - else - GUSregw(TimerIRQs) = 0; - - if (!(data & 0x04)) - { - GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */ - GUSregb(IRQStatReg2x6) &= 0xfb; - } - if (!(data & 0x08)) - { - GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */ - GUSregb(IRQStatReg2x6) &= 0xf7; - } - if (!GUSregb(IRQStatReg2x6)) - GUS_irqclear(state, state->gusirq); - break; - case 0x46: /* Counter1 */ - GUSregb(GUS46Counter1) = (GUSbyte) data; - break; - case 0x47: /* Counter2 */ - GUSregb(GUS47Counter2) = (GUSbyte) data; - break; - /* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */ - case 0x49: /* SampCtrlReg */ - GUSregb(GUS49SampCtrl) = (GUSbyte) data; - break; - /* case 0x4b: */ /* joystick trim not emulated */ - case 0x4c: /* GUSreset */ - GUSregb(GUS4cReset) = (GUSbyte) data; - if (!(GUSregb(GUS4cReset) & 1)) /* reset... */ - { - GUSregd(voicewavetableirq) = 0; - GUSregd(voicevolrampirq) = 0; - GUSregw(TimerIRQs) = 0; - GUSregw(BusyTimerIRQs) = 0; - GUSregb(NumVoices) = 0xcd; - GUSregb(IRQStatReg2x6) = 0; - GUSregb(TimerStatus2x8) = 0; - GUSregb(AdLibData2x9) = 0; - GUSregb(TimerDataReg2x9) = 0; - GUSregb(GUS41DMACtrl) = 0; - GUSregb(GUS45TimerCtrl) = 0; - GUSregb(GUS49SampCtrl) = 0; - GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */ - GUS_irqclear(state, state->gusirq); - } - /* IRQ enable bit checked elsewhere */ - /* EnableDAC bit may be used by external callers */ - break; - } - } - break; - case 0x307: /* DRAMaccess */ - { - GUSbyte *adr; - adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff); - *adr = (GUSbyte) data; - } - break; - } -} - -/* Attention when breaking up a single DMA transfer to multiple ones: - * it may lead to multiple terminal count interrupts and broken transfers: - * - * 1. Whenever you transfer a piece of data, the gusemu callback is invoked - * 2. The callback may generate a TC irq (if the register was set up to do so) - * 3. The irq may result in the program using the GUS to reprogram the GUS - * - * Some programs also decide to upload by just checking if TC occurs - * (via interrupt or a cleared GUS dma flag) - * and then start the next transfer, without checking DMA state - * - * Thus: Always make sure to set the TC flag correctly! - * - * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA - * while later cards had atomic granularity provided by an additional GUS50DMAHigh register - * GUSemu also uses this register to support byte-granular transfers for better compatibility - * with emulators other than GUSemu32 - */ - -void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC) -{ - /* this function gets called by the callback function as soon as a DMA transfer is about to start - * dma_addr is a translated address within accessible memory, not the physical one, - * count is (real dma count register)+1 - * note that the amount of bytes transferred is fully determined by values in the DMA registers - * do not forget to update DMA states after transferring the entire block: - * DREQ cleared & TC asserted after the _whole_ transfer */ - - char *srcaddr; - char *destaddr; - char msbmask = 0; - GUSbyte *gusptr; - gusptr = state->gusdatapos; - - srcaddr = dma_addr; /* system memory address */ - { - int offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf); - if (state->gusdma >= 4) - offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */ - destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */ - } - - GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */ - GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */ - - if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */ - { - char *tmpaddr = destaddr; - destaddr = srcaddr; - srcaddr = tmpaddr; - } - - if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02))) - msbmask = (const char) 0x80; /* invert MSB */ - for (; count > 0; count--) - { - if (GUSregb(GUS41DMACtrl) & 0x40) - *(destaddr++) = *(srcaddr++); /* 16 bit lobyte */ - else - *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */ - if (state->gusdma >= 4) - *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */ - } - - if (TC) - { - (GUSregb(GUS41DMACtrl)) &= 0xfe; /* clear DMA request bit */ - if (GUSregb(GUS41DMACtrl) & 0x20) /* DMA terminal count IRQ */ - { - GUSregb(IRQStatReg2x6) |= 0x80; - GUS_irqrequest(state, state->gusirq, 1); - } - } -} diff --git a/qemu/hw/audio/gusemu_mixer.c b/qemu/hw/audio/gusemu_mixer.c deleted file mode 100644 index 701e8fb0e..000000000 --- a/qemu/hw/audio/gusemu_mixer.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility) - * - * Copyright (C) 2000-2007 Tibor "TS" Schütz - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "gusemu.h" -#include "gustate.h" - -#define GUSregb(position) (* (gusptr+(position))) -#define GUSregw(position) (*(GUSword *) (gusptr+(position))) -#define GUSregd(position) (*(GUSdword *)(gusptr+(position))) - -#define GUSvoice(position) (*(GUSword *)(voiceptr+(position))) - -/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */ -void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples, - GUSsample *bufferpos) -{ - /* note that byte registers are stored in the upper half of each voice register! */ - GUSbyte *gusptr; - int Voice; - GUSword *voiceptr; - - unsigned int count; - for (count = 0; count < numsamples * 2; count++) - *(bufferpos + count) = 0; /* clear */ - - gusptr = state->gusdatapos; - voiceptr = (GUSword *) gusptr; - if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */ - return; - - for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++) - { - if (GUSvoice(wVSRControl) & 0x200) - GUSvoice(wVSRControl) |= 0x100; /* voice stop request */ - if (GUSvoice(wVSRVolRampControl) & 0x200) - GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */ - if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */ - { - unsigned int sample; - - unsigned int LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */ - unsigned int LoopEnd = (GUSvoice(wVSRLoopEndHi) << 16) | GUSvoice(wVSRLoopEndLo); /* 23.9 format */ - unsigned int CurrPos = (GUSvoice(wVSRCurrPosHi) << 16) | GUSvoice(wVSRCurrPosLo); /* 23.9 format */ - int VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) / - ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */ - - int PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf; - - unsigned int Volume32 = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */ - unsigned int StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32; - unsigned int EndVol32 = (GUSvoice(wVSRVolRampEndVol) & 0xff00) * 32; - int VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */ - VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */ - - if (GUSvoice(wVSRControl) & 0x4000) - VoiceIncrement = -VoiceIncrement; /* reverse playback */ - if (GUSvoice(wVSRVolRampControl) & 0x4000) - VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */ - - for (sample = 0; sample < numsamples; sample++) - { - int sample1, sample2, Volume; - if (GUSvoice(wVSRControl) & 0x400) /* 16bit */ - { - int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1); - GUSchar *adr; - adr = (GUSchar *) state->himemaddr + offset; - sample1 = (*adr & 0xff) + (*(adr + 1) * 256); - sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256); - } - else /* 8bit */ - { - int offset = (CurrPos >> 9) & 0xfffff; - GUSchar *adr; - adr = (GUSchar *) state->himemaddr + offset; - sample1 = (*adr) * 256; - sample2 = (*(adr + 1)) * 256; - } - - Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */ - sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512; - sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512; - sample1 += sample2; - - if (!(GUSvoice(wVSRVolRampControl) & 0x100)) - { - Volume32 += VolumeIncrement32; - if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */ - { - if (GUSvoice(wVSRVolRampControl) & 0x2000) - GUSvoice(wVSRVolRampControl) |= 0x8000; /* volramp IRQ enabled? -> IRQ wait flag */ - if (GUSvoice(wVSRVolRampControl) & 0x800) /* loop enabled */ - { - if (GUSvoice(wVSRVolRampControl) & 0x1000) /* bidir. loop */ - { - GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */ - VolumeIncrement32 = -VolumeIncrement32; - } - else - Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */ - } - else - { - GUSvoice(wVSRVolRampControl) |= 0x100; - Volume32 = - (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32; - } - } - } - if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000) /* volramp IRQ set and enabled? */ - { - GUSregd(voicevolrampirq) |= 1 << Voice; /* set irq slot */ - } - else - { - GUSregd(voicevolrampirq) &= (~(1 << Voice)); /* clear irq slot */ - GUSvoice(wVSRVolRampControl) &= 0x7f00; - } - - if (!(GUSvoice(wVSRControl) & 0x100)) - { - CurrPos += VoiceIncrement; - if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */ - { - if (GUSvoice(wVSRControl) & 0x2000) - GUSvoice(wVSRControl) |= 0x8000; /* voice IRQ enabled -> IRQ wait flag */ - if (GUSvoice(wVSRControl) & 0x800) /* loop enabled */ - { - if (GUSvoice(wVSRControl) & 0x1000) /* pingpong loop */ - { - GUSvoice(wVSRControl) ^= 0x4000; /* toggle dir */ - VoiceIncrement = -VoiceIncrement; - } - else - CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */ - } - else if (!(GUSvoice(wVSRVolRampControl) & 0x400)) - GUSvoice(wVSRControl) |= 0x100; /* loop disabled, rollover check */ - } - } - if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000) /* wavetable IRQ set and enabled? */ - { - GUSregd(voicewavetableirq) |= 1 << Voice; /* set irq slot */ - } - else - { - GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */ - GUSvoice(wVSRControl) &= 0x7f00; - } - - /* mix samples into buffer */ - *(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */ - *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */ - } - /* write back voice and volume */ - GUSvoice(wVSRCurrVol) = Volume32 / 32; - GUSvoice(wVSRCurrPosHi) = CurrPos >> 16; - GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff; - } - voiceptr += 16; /* next voice */ - } -} - -void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time) -/* time given in microseconds */ -{ - int requestedIRQs = 0; - GUSbyte *gusptr; - gusptr = state->gusdatapos; - if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */ - { - unsigned int timer1fraction = state->timer1fraction; - int newtimerirqs; - newtimerirqs = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1))); - state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1))); - if (newtimerirqs) - { - if (!(GUSregb(TimerDataReg2x9) & 0x40)) - GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */ - if (GUSregb(GUS45TimerCtrl) & 4) /* timer1 irq enable */ - { - GUSregb(TimerStatus2x8) |= 4; /* nonmaskable bit */ - GUSregb(IRQStatReg2x6) |= 4; /* timer 1 irq pending */ - GUSregw(TimerIRQs) += newtimerirqs; - requestedIRQs += newtimerirqs; - } - } - } - if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */ - { - unsigned int timer2fraction = state->timer2fraction; - int newtimerirqs; - newtimerirqs = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2))); - state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2))); - if (newtimerirqs) - { - if (!(GUSregb(TimerDataReg2x9) & 0x20)) - GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */ - if (GUSregb(GUS45TimerCtrl) & 8) /* timer2 irq enable */ - { - GUSregb(TimerStatus2x8) |= 2; /* nonmaskable bit */ - GUSregb(IRQStatReg2x6) |= 8; /* timer 2 irq pending */ - GUSregw(TimerIRQs) += newtimerirqs; - requestedIRQs += newtimerirqs; - } - } - } - if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */ - { - if (GUSregd(voicewavetableirq)) - GUSregb(IRQStatReg2x6) |= 0x20; - if (GUSregd(voicevolrampirq)) - GUSregb(IRQStatReg2x6) |= 0x40; - } - if ((!requestedIRQs) && GUSregb(IRQStatReg2x6)) - requestedIRQs++; - if (GUSregb(IRQStatReg2x6)) - GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs); -} diff --git a/qemu/hw/audio/gustate.h b/qemu/hw/audio/gustate.h deleted file mode 100644 index ece903abb..000000000 --- a/qemu/hw/audio/gustate.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * GUSEMU32 - persistent GUS register state - * - * Copyright (C) 2000-2007 Tibor "TS" Schütz - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef GUSTATE_H -#define GUSTATE_H - -/*state block offset*/ -#define gusdata (0) - -/* data stored using this structure is in host byte order! */ - -/*access type*/ -#define PortRead (0) -#define PortWrite (1) - -#define Port8Bitacc (0) -#define Port16Bitacc (1) - -/*voice register offsets (in bytes)*/ -#define VSRegs (0) -#define VSRControl (0) -#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2)) -#define VSRFreq (2) -#define VSRLoopStartHi (4) -#define VSRLoopStartLo (6) -#define VSRLoopEndHi (8) -#define VSRLoopEndLo (10) -#define VSRVolRampRate (12) -#define VSRVolRampStartVol (14) -#define VSRVolRampEndVol (16) -#define VSRCurrVol (18) -#define VSRCurrPosHi (20) -#define VSRCurrPosLo (22) -#define VSRPanning (24) -#define VSRVolRampControl (26) - -/*voice register offsets (in words)*/ -#define wVSRegs (0) -#define wVSRControl (0) -#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16)) -#define wVSRFreq (1) -#define wVSRLoopStartHi (2) -#define wVSRLoopStartLo (3) -#define wVSRLoopEndHi (4) -#define wVSRLoopEndLo (5) -#define wVSRVolRampRate (6) -#define wVSRVolRampStartVol (7) -#define wVSRVolRampEndVol (8) -#define wVSRCurrVol (9) -#define wVSRCurrPosHi (10) -#define wVSRCurrPosLo (11) -#define wVSRPanning (12) -#define wVSRVolRampControl (13) - -/*GUS register state block: 32 voices, padding filled with remaining registers*/ -#define DataRegLoByte3x4 (VSRVolRampControl+2) -#define DataRegWord3x4 (DataRegLoByte3x4) -#define DataRegHiByte3x5 (VSRVolRampControl+2 +1) -#define DMA_2xB (VSRVolRampControl+2+2) -#define IRQ_2xB (VSRVolRampControl+2+3) - -#define RegCtrl_2xF (VSRVolRampControl+2+(16*2)) -#define Jumper_2xB (VSRVolRampControl+2+(16*2)+1) -#define GUS42DMAStart (VSRVolRampControl+2+(16*2)+2) - -#define GUS43DRAMIOlo (VSRVolRampControl+2+(16*2)*2) -#define GUSDRAMPOS24bit (GUS43DRAMIOlo) -#define GUS44DRAMIOhi (VSRVolRampControl+2+(16*2)*2+2) - -#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */ - -#define voicevolrampirq (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */ - -#define startvoices (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */ - -#define IRQStatReg2x6 (VSRVolRampControl+2+(16*2)*6) -#define TimerStatus2x8 (VSRVolRampControl+2+(16*2)*6+1) -#define TimerDataReg2x9 (VSRVolRampControl+2+(16*2)*6+2) -#define MixerCtrlReg2x0 (VSRVolRampControl+2+(16*2)*6+3) - -#define VoiceSelReg3x2 (VSRVolRampControl+2+(16*2)*7) -#define FunkSelReg3x3 (VSRVolRampControl+2+(16*2)*7+1) -#define AdLibStatus2x8 (VSRVolRampControl+2+(16*2)*7+2) -#define StatRead_2xF (VSRVolRampControl+2+(16*2)*7+3) - -#define GUS48SampSpeed (VSRVolRampControl+2+(16*2)*8) -#define GUS41DMACtrl (VSRVolRampControl+2+(16*2)*8+1) -#define GUS45TimerCtrl (VSRVolRampControl+2+(16*2)*8+2) -#define GUS46Counter1 (VSRVolRampControl+2+(16*2)*8+3) - -#define GUS47Counter2 (VSRVolRampControl+2+(16*2)*9) -#define GUS49SampCtrl (VSRVolRampControl+2+(16*2)*9+1) -#define GUS4cReset (VSRVolRampControl+2+(16*2)*9+2) -#define NumVoices (VSRVolRampControl+2+(16*2)*9+3) - -#define TimerIRQs (VSRVolRampControl+2+(16*2)*10) /* delayed IRQ, statistics */ -#define BusyTimerIRQs (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */ - -#define AdLibCommand2xA (VSRVolRampControl+2+(16*2)*11) -#define AdLibData2x9 (VSRVolRampControl+2+(16*2)*11+1) -#define SB2xCd (VSRVolRampControl+2+(16*2)*11+2) -#define SB2xE (VSRVolRampControl+2+(16*2)*11+3) - -#define SynVoiceIRQ8f (VSRVolRampControl+2+(16*2)*12) -#define GUS50DMAHigh (VSRVolRampControl+2+(16*2)*12+1) - -#define portaccesses (VSRegsEnd) /* statistics / suspend mode */ - -#define gusdataend (VSRegsEnd+4) - -#endif /* gustate.h */ diff --git a/qemu/hw/audio/hda-codec-common.h b/qemu/hw/audio/hda-codec-common.h deleted file mode 100644 index b4fdb51e8..000000000 --- a/qemu/hw/audio/hda-codec-common.h +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Common code to disable/enable mixer emulation at run time - * - * Copyright (C) 2013 Red Hat, Inc. - * - * Written by Bandan Das - * with important bits picked up from hda-codec.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -/* - * HDA codec descriptions - */ - -#ifdef HDA_MIXER -#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12) -#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22) -#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32) -#define QEMU_HDA_AMP_CAPS \ - (AC_AMPCAP_MUTE | \ - (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \ - (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \ - (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) -#else -#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11) -#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21) -#define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31) -#define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE -#endif - - -/* common: audio output widget */ -static const desc_param glue(common_params_audio_dac_, PARAM)[] = { - { - .id = AC_PAR_AUDIO_WIDGET_CAP, - .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) | - AC_WCAP_FORMAT_OVRD | - AC_WCAP_AMP_OVRD | - AC_WCAP_OUT_AMP | - AC_WCAP_STEREO), - },{ - .id = AC_PAR_PCM, - .val = QEMU_HDA_PCM_FORMATS, - },{ - .id = AC_PAR_STREAM, - .val = AC_SUPFMT_PCM, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_CAPS, - }, -}; - -/* common: audio input widget */ -static const desc_param glue(common_params_audio_adc_, PARAM)[] = { - { - .id = AC_PAR_AUDIO_WIDGET_CAP, - .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) | - AC_WCAP_CONN_LIST | - AC_WCAP_FORMAT_OVRD | - AC_WCAP_AMP_OVRD | - AC_WCAP_IN_AMP | - AC_WCAP_STEREO), - },{ - .id = AC_PAR_CONNLIST_LEN, - .val = 1, - },{ - .id = AC_PAR_PCM, - .val = QEMU_HDA_PCM_FORMATS, - },{ - .id = AC_PAR_STREAM, - .val = AC_SUPFMT_PCM, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_CAPS, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_NONE, - }, -}; - -/* common: pin widget (line-out) */ -static const desc_param glue(common_params_audio_lineout_, PARAM)[] = { - { - .id = AC_PAR_AUDIO_WIDGET_CAP, - .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | - AC_WCAP_CONN_LIST | - AC_WCAP_STEREO), - },{ - .id = AC_PAR_PIN_CAP, - .val = AC_PINCAP_OUT, - },{ - .id = AC_PAR_CONNLIST_LEN, - .val = 1, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_NONE, - }, -}; - -/* common: pin widget (line-in) */ -static const desc_param glue(common_params_audio_linein_, PARAM)[] = { - { - .id = AC_PAR_AUDIO_WIDGET_CAP, - .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) | - AC_WCAP_STEREO), - },{ - .id = AC_PAR_PIN_CAP, - .val = AC_PINCAP_IN, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_NONE, - }, -}; - -/* output: root node */ -static const desc_param glue(output_params_root_, PARAM)[] = { - { - .id = AC_PAR_VENDOR_ID, - .val = QEMU_HDA_ID_OUTPUT, - },{ - .id = AC_PAR_SUBSYSTEM_ID, - .val = QEMU_HDA_ID_OUTPUT, - },{ - .id = AC_PAR_REV_ID, - .val = 0x00100101, - },{ - .id = AC_PAR_NODE_COUNT, - .val = 0x00010001, - }, -}; - -/* output: audio function */ -static const desc_param glue(output_params_audio_func_, PARAM)[] = { - { - .id = AC_PAR_FUNCTION_TYPE, - .val = AC_GRP_AUDIO_FUNCTION, - },{ - .id = AC_PAR_SUBSYSTEM_ID, - .val = QEMU_HDA_ID_OUTPUT, - },{ - .id = AC_PAR_NODE_COUNT, - .val = 0x00020002, - },{ - .id = AC_PAR_PCM, - .val = QEMU_HDA_PCM_FORMATS, - },{ - .id = AC_PAR_STREAM, - .val = AC_SUPFMT_PCM, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_GPIO_CAP, - .val = 0, - },{ - .id = AC_PAR_AUDIO_FG_CAP, - .val = 0x00000808, - },{ - .id = AC_PAR_POWER_STATE, - .val = 0, - }, -}; - -/* output: nodes */ -static const desc_node glue(output_nodes_, PARAM)[] = { - { - .nid = AC_NODE_ROOT, - .name = "root", - .params = glue(output_params_root_, PARAM), - .nparams = ARRAY_SIZE(glue(output_params_root_, PARAM)), - },{ - .nid = 1, - .name = "func", - .params = glue(output_params_audio_func_, PARAM), - .nparams = ARRAY_SIZE(glue(output_params_audio_func_, PARAM)), - },{ - .nid = 2, - .name = "dac", - .params = glue(common_params_audio_dac_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), - .stindex = 0, - },{ - .nid = 3, - .name = "out", - .params = glue(common_params_audio_lineout_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), - .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | - (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | - (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | - (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | - 0x10), - .pinctl = AC_PINCTL_OUT_EN, - .conn = (uint32_t[]) { 2 }, - } -}; - -/* output: codec */ -static const desc_codec glue(output_, PARAM) = { - .name = "output", - .iid = QEMU_HDA_ID_OUTPUT, - .nodes = glue(output_nodes_, PARAM), - .nnodes = ARRAY_SIZE(glue(output_nodes_, PARAM)), -}; - -/* duplex: root node */ -static const desc_param glue(duplex_params_root_, PARAM)[] = { - { - .id = AC_PAR_VENDOR_ID, - .val = QEMU_HDA_ID_DUPLEX, - },{ - .id = AC_PAR_SUBSYSTEM_ID, - .val = QEMU_HDA_ID_DUPLEX, - },{ - .id = AC_PAR_REV_ID, - .val = 0x00100101, - },{ - .id = AC_PAR_NODE_COUNT, - .val = 0x00010001, - }, -}; - -/* duplex: audio function */ -static const desc_param glue(duplex_params_audio_func_, PARAM)[] = { - { - .id = AC_PAR_FUNCTION_TYPE, - .val = AC_GRP_AUDIO_FUNCTION, - },{ - .id = AC_PAR_SUBSYSTEM_ID, - .val = QEMU_HDA_ID_DUPLEX, - },{ - .id = AC_PAR_NODE_COUNT, - .val = 0x00020004, - },{ - .id = AC_PAR_PCM, - .val = QEMU_HDA_PCM_FORMATS, - },{ - .id = AC_PAR_STREAM, - .val = AC_SUPFMT_PCM, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_GPIO_CAP, - .val = 0, - },{ - .id = AC_PAR_AUDIO_FG_CAP, - .val = 0x00000808, - },{ - .id = AC_PAR_POWER_STATE, - .val = 0, - }, -}; - -/* duplex: nodes */ -static const desc_node glue(duplex_nodes_, PARAM)[] = { - { - .nid = AC_NODE_ROOT, - .name = "root", - .params = glue(duplex_params_root_, PARAM), - .nparams = ARRAY_SIZE(glue(duplex_params_root_, PARAM)), - },{ - .nid = 1, - .name = "func", - .params = glue(duplex_params_audio_func_, PARAM), - .nparams = ARRAY_SIZE(glue(duplex_params_audio_func_, PARAM)), - },{ - .nid = 2, - .name = "dac", - .params = glue(common_params_audio_dac_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), - .stindex = 0, - },{ - .nid = 3, - .name = "out", - .params = glue(common_params_audio_lineout_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), - .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | - (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) | - (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | - (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | - 0x10), - .pinctl = AC_PINCTL_OUT_EN, - .conn = (uint32_t[]) { 2 }, - },{ - .nid = 4, - .name = "adc", - .params = glue(common_params_audio_adc_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)), - .stindex = 1, - .conn = (uint32_t[]) { 5 }, - },{ - .nid = 5, - .name = "in", - .params = glue(common_params_audio_linein_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)), - .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | - (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) | - (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | - (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | - 0x20), - .pinctl = AC_PINCTL_IN_EN, - } -}; - -/* duplex: codec */ -static const desc_codec glue(duplex_, PARAM) = { - .name = "duplex", - .iid = QEMU_HDA_ID_DUPLEX, - .nodes = glue(duplex_nodes_, PARAM), - .nnodes = ARRAY_SIZE(glue(duplex_nodes_, PARAM)), -}; - -/* micro: root node */ -static const desc_param glue(micro_params_root_, PARAM)[] = { - { - .id = AC_PAR_VENDOR_ID, - .val = QEMU_HDA_ID_MICRO, - },{ - .id = AC_PAR_SUBSYSTEM_ID, - .val = QEMU_HDA_ID_MICRO, - },{ - .id = AC_PAR_REV_ID, - .val = 0x00100101, - },{ - .id = AC_PAR_NODE_COUNT, - .val = 0x00010001, - }, -}; - -/* micro: audio function */ -static const desc_param glue(micro_params_audio_func_, PARAM)[] = { - { - .id = AC_PAR_FUNCTION_TYPE, - .val = AC_GRP_AUDIO_FUNCTION, - },{ - .id = AC_PAR_SUBSYSTEM_ID, - .val = QEMU_HDA_ID_MICRO, - },{ - .id = AC_PAR_NODE_COUNT, - .val = 0x00020004, - },{ - .id = AC_PAR_PCM, - .val = QEMU_HDA_PCM_FORMATS, - },{ - .id = AC_PAR_STREAM, - .val = AC_SUPFMT_PCM, - },{ - .id = AC_PAR_AMP_IN_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_AMP_OUT_CAP, - .val = QEMU_HDA_AMP_NONE, - },{ - .id = AC_PAR_GPIO_CAP, - .val = 0, - },{ - .id = AC_PAR_AUDIO_FG_CAP, - .val = 0x00000808, - },{ - .id = AC_PAR_POWER_STATE, - .val = 0, - }, -}; - -/* micro: nodes */ -static const desc_node glue(micro_nodes_, PARAM)[] = { - { - .nid = AC_NODE_ROOT, - .name = "root", - .params = glue(micro_params_root_, PARAM), - .nparams = ARRAY_SIZE(glue(micro_params_root_, PARAM)), - },{ - .nid = 1, - .name = "func", - .params = glue(micro_params_audio_func_, PARAM), - .nparams = ARRAY_SIZE(glue(micro_params_audio_func_, PARAM)), - },{ - .nid = 2, - .name = "dac", - .params = glue(common_params_audio_dac_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_dac_, PARAM)), - .stindex = 0, - },{ - .nid = 3, - .name = "out", - .params = glue(common_params_audio_lineout_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_lineout_, PARAM)), - .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | - (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) | - (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | - (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) | - 0x10), - .pinctl = AC_PINCTL_OUT_EN, - .conn = (uint32_t[]) { 2 }, - },{ - .nid = 4, - .name = "adc", - .params = glue(common_params_audio_adc_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_adc_, PARAM)), - .stindex = 1, - .conn = (uint32_t[]) { 5 }, - },{ - .nid = 5, - .name = "in", - .params = glue(common_params_audio_linein_, PARAM), - .nparams = ARRAY_SIZE(glue(common_params_audio_linein_, PARAM)), - .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) | - (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) | - (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) | - (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) | - 0x20), - .pinctl = AC_PINCTL_IN_EN, - } -}; - -/* micro: codec */ -static const desc_codec glue(micro_, PARAM) = { - .name = "micro", - .iid = QEMU_HDA_ID_MICRO, - .nodes = glue(micro_nodes_, PARAM), - .nnodes = ARRAY_SIZE(glue(micro_nodes_, PARAM)), -}; - -#undef PARAM -#undef HDA_MIXER -#undef QEMU_HDA_ID_OUTPUT -#undef QEMU_HDA_ID_DUPLEX -#undef QEMU_HDA_ID_MICRO -#undef QEMU_HDA_AMP_CAPS diff --git a/qemu/hw/audio/hda-codec.c b/qemu/hw/audio/hda-codec.c deleted file mode 100644 index 52d4640e6..000000000 --- a/qemu/hw/audio/hda-codec.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * written by Gerd Hoffmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "intel-hda.h" -#include "intel-hda-defs.h" -#include "audio/audio.h" - -/* -------------------------------------------------------------------------- */ - -typedef struct desc_param { - uint32_t id; - uint32_t val; -} desc_param; - -typedef struct desc_node { - uint32_t nid; - const char *name; - const desc_param *params; - uint32_t nparams; - uint32_t config; - uint32_t pinctl; - uint32_t *conn; - uint32_t stindex; -} desc_node; - -typedef struct desc_codec { - const char *name; - uint32_t iid; - const desc_node *nodes; - uint32_t nnodes; -} desc_codec; - -static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id) -{ - int i; - - for (i = 0; i < node->nparams; i++) { - if (node->params[i].id == id) { - return &node->params[i]; - } - } - return NULL; -} - -static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid) -{ - int i; - - for (i = 0; i < codec->nnodes; i++) { - if (codec->nodes[i].nid == nid) { - return &codec->nodes[i]; - } - } - return NULL; -} - -static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) -{ - if (format & AC_FMT_TYPE_NON_PCM) { - return; - } - - as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000; - - switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) { - case 1: as->freq *= 2; break; - case 2: as->freq *= 3; break; - case 3: as->freq *= 4; break; - } - - switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) { - case 1: as->freq /= 2; break; - case 2: as->freq /= 3; break; - case 3: as->freq /= 4; break; - case 4: as->freq /= 5; break; - case 5: as->freq /= 6; break; - case 6: as->freq /= 7; break; - case 7: as->freq /= 8; break; - } - - switch (format & AC_FMT_BITS_MASK) { - case AC_FMT_BITS_8: as->fmt = AUD_FMT_S8; break; - case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break; - case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break; - } - - as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1; -} - -/* -------------------------------------------------------------------------- */ -/* - * HDA codec descriptions - */ - -/* some defines */ - -#define QEMU_HDA_ID_VENDOR 0x1af4 -#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \ - 0x1fc /* 16 -> 96 kHz */) -#define QEMU_HDA_AMP_NONE (0) -#define QEMU_HDA_AMP_STEPS 0x4a - -#define PARAM mixemu -#define HDA_MIXER -#include "hda-codec-common.h" - -#define PARAM nomixemu -#include "hda-codec-common.h" - -/* -------------------------------------------------------------------------- */ - -static const char *fmt2name[] = { - [ AUD_FMT_U8 ] = "PCM-U8", - [ AUD_FMT_S8 ] = "PCM-S8", - [ AUD_FMT_U16 ] = "PCM-U16", - [ AUD_FMT_S16 ] = "PCM-S16", - [ AUD_FMT_U32 ] = "PCM-U32", - [ AUD_FMT_S32 ] = "PCM-S32", -}; - -typedef struct HDAAudioState HDAAudioState; -typedef struct HDAAudioStream HDAAudioStream; - -struct HDAAudioStream { - HDAAudioState *state; - const desc_node *node; - bool output, running; - uint32_t stream; - uint32_t channel; - uint32_t format; - uint32_t gain_left, gain_right; - bool mute_left, mute_right; - struct audsettings as; - union { - SWVoiceIn *in; - SWVoiceOut *out; - } voice; - uint8_t buf[HDA_BUFFER_SIZE]; - uint32_t bpos; -}; - -#define TYPE_HDA_AUDIO "hda-audio" -#define HDA_AUDIO(obj) OBJECT_CHECK(HDAAudioState, (obj), TYPE_HDA_AUDIO) - -struct HDAAudioState { - HDACodecDevice hda; - const char *name; - - QEMUSoundCard card; - const desc_codec *desc; - HDAAudioStream st[4]; - bool running_compat[16]; - bool running_real[2 * 16]; - - /* properties */ - uint32_t debug; - bool mixer; -}; - -static void hda_audio_input_cb(void *opaque, int avail) -{ - HDAAudioStream *st = opaque; - int recv = 0; - int len; - bool rc; - - while (avail - recv >= sizeof(st->buf)) { - if (st->bpos != sizeof(st->buf)) { - len = AUD_read(st->voice.in, st->buf + st->bpos, - sizeof(st->buf) - st->bpos); - st->bpos += len; - recv += len; - if (st->bpos != sizeof(st->buf)) { - break; - } - } - rc = hda_codec_xfer(&st->state->hda, st->stream, false, - st->buf, sizeof(st->buf)); - if (!rc) { - break; - } - st->bpos = 0; - } -} - -static void hda_audio_output_cb(void *opaque, int avail) -{ - HDAAudioStream *st = opaque; - int sent = 0; - int len; - bool rc; - - while (avail - sent >= sizeof(st->buf)) { - if (st->bpos == sizeof(st->buf)) { - rc = hda_codec_xfer(&st->state->hda, st->stream, true, - st->buf, sizeof(st->buf)); - if (!rc) { - break; - } - st->bpos = 0; - } - len = AUD_write(st->voice.out, st->buf + st->bpos, - sizeof(st->buf) - st->bpos); - st->bpos += len; - sent += len; - if (st->bpos != sizeof(st->buf)) { - break; - } - } -} - -static void hda_audio_set_running(HDAAudioStream *st, bool running) -{ - if (st->node == NULL) { - return; - } - if (st->running == running) { - return; - } - st->running = running; - dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, - st->running ? "on" : "off", st->stream); - if (st->output) { - AUD_set_active_out(st->voice.out, st->running); - } else { - AUD_set_active_in(st->voice.in, st->running); - } -} - -static void hda_audio_set_amp(HDAAudioStream *st) -{ - bool muted; - uint32_t left, right; - - if (st->node == NULL) { - return; - } - - muted = st->mute_left && st->mute_right; - left = st->mute_left ? 0 : st->gain_left; - right = st->mute_right ? 0 : st->gain_right; - - left = left * 255 / QEMU_HDA_AMP_STEPS; - right = right * 255 / QEMU_HDA_AMP_STEPS; - - if (!st->state->mixer) { - return; - } - if (st->output) { - AUD_set_volume_out(st->voice.out, muted, left, right); - } else { - AUD_set_volume_in(st->voice.in, muted, left, right); - } -} - -static void hda_audio_setup(HDAAudioStream *st) -{ - if (st->node == NULL) { - return; - } - - dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n", - st->node->name, st->as.nchannels, - fmt2name[st->as.fmt], st->as.freq); - - if (st->output) { - st->voice.out = AUD_open_out(&st->state->card, st->voice.out, - st->node->name, st, - hda_audio_output_cb, &st->as); - } else { - st->voice.in = AUD_open_in(&st->state->card, st->voice.in, - st->node->name, st, - hda_audio_input_cb, &st->as); - } -} - -static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data) -{ - HDAAudioState *a = HDA_AUDIO(hda); - HDAAudioStream *st; - const desc_node *node = NULL; - const desc_param *param; - uint32_t verb, payload, response, count, shift; - - if ((data & 0x70000) == 0x70000) { - /* 12/8 id/payload */ - verb = (data >> 8) & 0xfff; - payload = data & 0x00ff; - } else { - /* 4/16 id/payload */ - verb = (data >> 8) & 0xf00; - payload = data & 0xffff; - } - - node = hda_codec_find_node(a->desc, nid); - if (node == NULL) { - goto fail; - } - dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n", - __FUNCTION__, nid, node->name, verb, payload); - - switch (verb) { - /* all nodes */ - case AC_VERB_PARAMETERS: - param = hda_codec_find_param(node, payload); - if (param == NULL) { - goto fail; - } - hda_codec_response(hda, true, param->val); - break; - case AC_VERB_GET_SUBSYSTEM_ID: - hda_codec_response(hda, true, a->desc->iid); - break; - - /* all functions */ - case AC_VERB_GET_CONNECT_LIST: - param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN); - count = param ? param->val : 0; - response = 0; - shift = 0; - while (payload < count && shift < 32) { - response |= node->conn[payload] << shift; - payload++; - shift += 8; - } - hda_codec_response(hda, true, response); - break; - - /* pin widget */ - case AC_VERB_GET_CONFIG_DEFAULT: - hda_codec_response(hda, true, node->config); - break; - case AC_VERB_GET_PIN_WIDGET_CONTROL: - hda_codec_response(hda, true, node->pinctl); - break; - case AC_VERB_SET_PIN_WIDGET_CONTROL: - if (node->pinctl != payload) { - dprint(a, 1, "unhandled pin control bit\n"); - } - hda_codec_response(hda, true, 0); - break; - - /* audio in/out widget */ - case AC_VERB_SET_CHANNEL_STREAMID: - st = a->st + node->stindex; - if (st->node == NULL) { - goto fail; - } - hda_audio_set_running(st, false); - st->stream = (payload >> 4) & 0x0f; - st->channel = payload & 0x0f; - dprint(a, 2, "%s: stream %d, channel %d\n", - st->node->name, st->stream, st->channel); - hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]); - hda_codec_response(hda, true, 0); - break; - case AC_VERB_GET_CONV: - st = a->st + node->stindex; - if (st->node == NULL) { - goto fail; - } - response = st->stream << 4 | st->channel; - hda_codec_response(hda, true, response); - break; - case AC_VERB_SET_STREAM_FORMAT: - st = a->st + node->stindex; - if (st->node == NULL) { - goto fail; - } - st->format = payload; - hda_codec_parse_fmt(st->format, &st->as); - hda_audio_setup(st); - hda_codec_response(hda, true, 0); - break; - case AC_VERB_GET_STREAM_FORMAT: - st = a->st + node->stindex; - if (st->node == NULL) { - goto fail; - } - hda_codec_response(hda, true, st->format); - break; - case AC_VERB_GET_AMP_GAIN_MUTE: - st = a->st + node->stindex; - if (st->node == NULL) { - goto fail; - } - if (payload & AC_AMP_GET_LEFT) { - response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0); - } else { - response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0); - } - hda_codec_response(hda, true, response); - break; - case AC_VERB_SET_AMP_GAIN_MUTE: - st = a->st + node->stindex; - if (st->node == NULL) { - goto fail; - } - dprint(a, 1, "amp (%s): %s%s%s%s index %d gain %3d %s\n", - st->node->name, - (payload & AC_AMP_SET_OUTPUT) ? "o" : "-", - (payload & AC_AMP_SET_INPUT) ? "i" : "-", - (payload & AC_AMP_SET_LEFT) ? "l" : "-", - (payload & AC_AMP_SET_RIGHT) ? "r" : "-", - (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT, - (payload & AC_AMP_GAIN), - (payload & AC_AMP_MUTE) ? "muted" : ""); - if (payload & AC_AMP_SET_LEFT) { - st->gain_left = payload & AC_AMP_GAIN; - st->mute_left = payload & AC_AMP_MUTE; - } - if (payload & AC_AMP_SET_RIGHT) { - st->gain_right = payload & AC_AMP_GAIN; - st->mute_right = payload & AC_AMP_MUTE; - } - hda_audio_set_amp(st); - hda_codec_response(hda, true, 0); - break; - - /* not supported */ - case AC_VERB_SET_POWER_STATE: - case AC_VERB_GET_POWER_STATE: - case AC_VERB_GET_SDI_SELECT: - hda_codec_response(hda, true, 0); - break; - default: - goto fail; - } - return; - -fail: - dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n", - __FUNCTION__, nid, node ? node->name : "?", verb, payload); - hda_codec_response(hda, true, 0); -} - -static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output) -{ - HDAAudioState *a = HDA_AUDIO(hda); - int s; - - a->running_compat[stnr] = running; - a->running_real[output * 16 + stnr] = running; - for (s = 0; s < ARRAY_SIZE(a->st); s++) { - if (a->st[s].node == NULL) { - continue; - } - if (a->st[s].output != output) { - continue; - } - if (a->st[s].stream != stnr) { - continue; - } - hda_audio_set_running(&a->st[s], running); - } -} - -static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) -{ - HDAAudioState *a = HDA_AUDIO(hda); - HDAAudioStream *st; - const desc_node *node; - const desc_param *param; - uint32_t i, type; - - a->desc = desc; - a->name = object_get_typename(OBJECT(a)); - dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad); - - AUD_register_card("hda", &a->card); - for (i = 0; i < a->desc->nnodes; i++) { - node = a->desc->nodes + i; - param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP); - if (param == NULL) { - continue; - } - type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - switch (type) { - case AC_WID_AUD_OUT: - case AC_WID_AUD_IN: - assert(node->stindex < ARRAY_SIZE(a->st)); - st = a->st + node->stindex; - st->state = a; - st->node = node; - if (type == AC_WID_AUD_OUT) { - /* unmute output by default */ - st->gain_left = QEMU_HDA_AMP_STEPS; - st->gain_right = QEMU_HDA_AMP_STEPS; - st->bpos = sizeof(st->buf); - st->output = true; - } else { - st->output = false; - } - st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 | - (1 << AC_FMT_CHAN_SHIFT); - hda_codec_parse_fmt(st->format, &st->as); - hda_audio_setup(st); - break; - } - } - return 0; -} - -static int hda_audio_exit(HDACodecDevice *hda) -{ - HDAAudioState *a = HDA_AUDIO(hda); - HDAAudioStream *st; - int i; - - dprint(a, 1, "%s\n", __FUNCTION__); - for (i = 0; i < ARRAY_SIZE(a->st); i++) { - st = a->st + i; - if (st->node == NULL) { - continue; - } - if (st->output) { - AUD_close_out(&a->card, st->voice.out); - } else { - AUD_close_in(&a->card, st->voice.in); - } - } - AUD_remove_card(&a->card); - return 0; -} - -static int hda_audio_post_load(void *opaque, int version) -{ - HDAAudioState *a = opaque; - HDAAudioStream *st; - int i; - - dprint(a, 1, "%s\n", __FUNCTION__); - if (version == 1) { - /* assume running_compat[] is for output streams */ - for (i = 0; i < ARRAY_SIZE(a->running_compat); i++) - a->running_real[16 + i] = a->running_compat[i]; - } - - for (i = 0; i < ARRAY_SIZE(a->st); i++) { - st = a->st + i; - if (st->node == NULL) - continue; - hda_codec_parse_fmt(st->format, &st->as); - hda_audio_setup(st); - hda_audio_set_amp(st); - hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]); - } - return 0; -} - -static void hda_audio_reset(DeviceState *dev) -{ - HDAAudioState *a = HDA_AUDIO(dev); - HDAAudioStream *st; - int i; - - dprint(a, 1, "%s\n", __func__); - for (i = 0; i < ARRAY_SIZE(a->st); i++) { - st = a->st + i; - if (st->node != NULL) { - hda_audio_set_running(st, false); - } - } -} - -static const VMStateDescription vmstate_hda_audio_stream = { - .name = "hda-audio-stream", - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(stream, HDAAudioStream), - VMSTATE_UINT32(channel, HDAAudioStream), - VMSTATE_UINT32(format, HDAAudioStream), - VMSTATE_UINT32(gain_left, HDAAudioStream), - VMSTATE_UINT32(gain_right, HDAAudioStream), - VMSTATE_BOOL(mute_left, HDAAudioStream), - VMSTATE_BOOL(mute_right, HDAAudioStream), - VMSTATE_UINT32(bpos, HDAAudioStream), - VMSTATE_BUFFER(buf, HDAAudioStream), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_hda_audio = { - .name = "hda-audio", - .version_id = 2, - .post_load = hda_audio_post_load, - .fields = (VMStateField[]) { - VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0, - vmstate_hda_audio_stream, - HDAAudioStream), - VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16), - VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2), - VMSTATE_END_OF_LIST() - } -}; - -static Property hda_audio_properties[] = { - DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0), - DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true), - DEFINE_PROP_END_OF_LIST(), -}; - -static int hda_audio_init_output(HDACodecDevice *hda) -{ - HDAAudioState *a = HDA_AUDIO(hda); - - if (!a->mixer) { - return hda_audio_init(hda, &output_nomixemu); - } else { - return hda_audio_init(hda, &output_mixemu); - } -} - -static int hda_audio_init_duplex(HDACodecDevice *hda) -{ - HDAAudioState *a = HDA_AUDIO(hda); - - if (!a->mixer) { - return hda_audio_init(hda, &duplex_nomixemu); - } else { - return hda_audio_init(hda, &duplex_mixemu); - } -} - -static int hda_audio_init_micro(HDACodecDevice *hda) -{ - HDAAudioState *a = HDA_AUDIO(hda); - - if (!a->mixer) { - return hda_audio_init(hda, µ_nomixemu); - } else { - return hda_audio_init(hda, µ_mixemu); - } -} - -static void hda_audio_base_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); - - k->exit = hda_audio_exit; - k->command = hda_audio_command; - k->stream = hda_audio_stream; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->reset = hda_audio_reset; - dc->vmsd = &vmstate_hda_audio; - dc->props = hda_audio_properties; -} - -static const TypeInfo hda_audio_info = { - .name = TYPE_HDA_AUDIO, - .parent = TYPE_HDA_CODEC_DEVICE, - .class_init = hda_audio_base_class_init, - .abstract = true, -}; - -static void hda_audio_output_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); - - k->init = hda_audio_init_output; - dc->desc = "HDA Audio Codec, output-only (line-out)"; -} - -static const TypeInfo hda_audio_output_info = { - .name = "hda-output", - .parent = TYPE_HDA_AUDIO, - .instance_size = sizeof(HDAAudioState), - .class_init = hda_audio_output_class_init, -}; - -static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); - - k->init = hda_audio_init_duplex; - dc->desc = "HDA Audio Codec, duplex (line-out, line-in)"; -} - -static const TypeInfo hda_audio_duplex_info = { - .name = "hda-duplex", - .parent = TYPE_HDA_AUDIO, - .instance_size = sizeof(HDAAudioState), - .class_init = hda_audio_duplex_class_init, -}; - -static void hda_audio_micro_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); - - k->init = hda_audio_init_micro; - dc->desc = "HDA Audio Codec, duplex (speaker, microphone)"; -} - -static const TypeInfo hda_audio_micro_info = { - .name = "hda-micro", - .parent = TYPE_HDA_AUDIO, - .instance_size = sizeof(HDAAudioState), - .class_init = hda_audio_micro_class_init, -}; - -static void hda_audio_register_types(void) -{ - type_register_static(&hda_audio_info); - type_register_static(&hda_audio_output_info); - type_register_static(&hda_audio_duplex_info); - type_register_static(&hda_audio_micro_info); -} - -type_init(hda_audio_register_types) diff --git a/qemu/hw/audio/intel-hda-defs.h b/qemu/hw/audio/intel-hda-defs.h deleted file mode 100644 index 2e37e5b87..000000000 --- a/qemu/hw/audio/intel-hda-defs.h +++ /dev/null @@ -1,717 +0,0 @@ -#ifndef HW_INTEL_HDA_DEFS_H -#define HW_INTEL_HDA_DEFS_H - -/* qemu */ -#define HDA_BUFFER_SIZE 256 - -/* --------------------------------------------------------------------- */ -/* from linux/sound/pci/hda/hda_intel.c */ - -/* - * registers - */ -#define ICH6_REG_GCAP 0x00 -#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ -#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ -#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ -#define ICH6_REG_VMIN 0x02 -#define ICH6_REG_VMAJ 0x03 -#define ICH6_REG_OUTPAY 0x04 -#define ICH6_REG_INPAY 0x06 -#define ICH6_REG_GCTL 0x08 -#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ -#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ -#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define ICH6_REG_WAKEEN 0x0c -#define ICH6_REG_STATESTS 0x0e -#define ICH6_REG_GSTS 0x10 -#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ -#define ICH6_REG_INTCTL 0x20 -#define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_SYNC 0x34 -#define ICH6_REG_CORBLBASE 0x40 -#define ICH6_REG_CORBUBASE 0x44 -#define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4a -#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ -#define ICH6_REG_CORBCTL 0x4c -#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define ICH6_REG_CORBSTS 0x4d -#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define ICH6_REG_CORBSIZE 0x4e - -#define ICH6_REG_RIRBLBASE 0x50 -#define ICH6_REG_RIRBUBASE 0x54 -#define ICH6_REG_RIRBWP 0x58 -#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define ICH6_REG_RINTCNT 0x5a -#define ICH6_REG_RIRBCTL 0x5c -#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define ICH6_REG_RIRBSTS 0x5d -#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ -#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define ICH6_REG_RIRBSIZE 0x5e - -#define ICH6_REG_IC 0x60 -#define ICH6_REG_IR 0x64 -#define ICH6_REG_IRS 0x68 -#define ICH6_IRS_VALID (1<<1) -#define ICH6_IRS_BUSY (1<<0) - -#define ICH6_REG_DPLBASE 0x70 -#define ICH6_REG_DPUBASE 0x74 -#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ - -/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ -enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; - -/* stream register offsets from stream base */ -#define ICH6_REG_SD_CTL 0x00 -#define ICH6_REG_SD_STS 0x03 -#define ICH6_REG_SD_LPIB 0x04 -#define ICH6_REG_SD_CBL 0x08 -#define ICH6_REG_SD_LVI 0x0c -#define ICH6_REG_SD_FIFOW 0x0e -#define ICH6_REG_SD_FIFOSIZE 0x10 -#define ICH6_REG_SD_FORMAT 0x12 -#define ICH6_REG_SD_BDLPL 0x18 -#define ICH6_REG_SD_BDLPU 0x1c - -/* PCI space */ -#define ICH6_PCIREG_TCSEL 0x44 - -/* - * other constants - */ - -/* max number of SDs */ -/* ICH, ATI and VIA have 4 playback and 4 capture */ -#define ICH6_NUM_CAPTURE 4 -#define ICH6_NUM_PLAYBACK 4 - -/* ULI has 6 playback and 5 capture */ -#define ULI_NUM_CAPTURE 5 -#define ULI_NUM_PLAYBACK 6 - -/* ATI HDMI has 1 playback and 0 capture */ -#define ATIHDMI_NUM_CAPTURE 0 -#define ATIHDMI_NUM_PLAYBACK 1 - -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - -/* this number is statically defined for simplicity */ -#define MAX_AZX_DEV 16 - -/* max number of fragments - we may use more if allocating more pages for BDL */ -#define BDL_SIZE 4096 -#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) -#define AZX_MAX_FRAG 32 -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) - -/* RIRB int mask: overrun[2], response[0] */ -#define RIRB_INT_RESPONSE 0x01 -#define RIRB_INT_OVERRUN 0x04 -#define RIRB_INT_MASK 0x05 - -/* STATESTS int mask: S3,SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 8 -#define AZX_DEFAULT_CODECS 4 -#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) - -/* SD_CTL bits */ -#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ -#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ -#define SD_CTL_STRIPE (3 << 16) /* stripe control */ -#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ -#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ -#define SD_CTL_STREAM_TAG_MASK (0xf << 20) -#define SD_CTL_STREAM_TAG_SHIFT 20 - -/* SD_CTL and SD_STS */ -#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ -#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ - SD_INT_COMPLETE) - -/* SD_STS */ -#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ - -/* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ - -/* below are so far hardcoded - should read registers in future */ -#define ICH6_MAX_CORB_ENTRIES 256 -#define ICH6_MAX_RIRB_ENTRIES 256 - -/* position fix mode */ -enum { - POS_FIX_AUTO, - POS_FIX_LPIB, - POS_FIX_POSBUF, -}; - -/* Defines for ATI HD Audio support in SB450 south bridge */ -#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 -#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 - -/* Defines for Nvidia HDA support */ -#define NVIDIA_HDA_TRANSREG_ADDR 0x4e -#define NVIDIA_HDA_ENABLE_COHBITS 0x0f -#define NVIDIA_HDA_ISTRM_COH 0x4d -#define NVIDIA_HDA_OSTRM_COH 0x4c -#define NVIDIA_HDA_ENABLE_COHBIT 0x01 - -/* Defines for Intel SCH HDA snoop control */ -#define INTEL_SCH_HDA_DEVC 0x78 -#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) - -/* Define IN stream 0 FIFO size offset in VIA controller */ -#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 -/* Define VIA HD Audio Device ID*/ -#define VIA_HDAC_DEVICE_ID 0x3288 - -/* HD Audio class code */ -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 - -/* --------------------------------------------------------------------- */ -/* from linux/sound/pci/hda/hda_codec.h */ - -/* - * nodes - */ -#define AC_NODE_ROOT 0x00 - -/* - * function group types - */ -enum { - AC_GRP_AUDIO_FUNCTION = 0x01, - AC_GRP_MODEM_FUNCTION = 0x02, -}; - -/* - * widget types - */ -enum { - AC_WID_AUD_OUT, /* Audio Out */ - AC_WID_AUD_IN, /* Audio In */ - AC_WID_AUD_MIX, /* Audio Mixer */ - AC_WID_AUD_SEL, /* Audio Selector */ - AC_WID_PIN, /* Pin Complex */ - AC_WID_POWER, /* Power */ - AC_WID_VOL_KNB, /* Volume Knob */ - AC_WID_BEEP, /* Beep Generator */ - AC_WID_VENDOR = 0x0f /* Vendor specific */ -}; - -/* - * GET verbs - */ -#define AC_VERB_GET_STREAM_FORMAT 0x0a00 -#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 -#define AC_VERB_GET_PROC_COEF 0x0c00 -#define AC_VERB_GET_COEF_INDEX 0x0d00 -#define AC_VERB_PARAMETERS 0x0f00 -#define AC_VERB_GET_CONNECT_SEL 0x0f01 -#define AC_VERB_GET_CONNECT_LIST 0x0f02 -#define AC_VERB_GET_PROC_STATE 0x0f03 -#define AC_VERB_GET_SDI_SELECT 0x0f04 -#define AC_VERB_GET_POWER_STATE 0x0f05 -#define AC_VERB_GET_CONV 0x0f06 -#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 -#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 -#define AC_VERB_GET_PIN_SENSE 0x0f09 -#define AC_VERB_GET_BEEP_CONTROL 0x0f0a -#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c -#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d -#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ -#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f -/* f10-f1a: GPIO */ -#define AC_VERB_GET_GPIO_DATA 0x0f15 -#define AC_VERB_GET_GPIO_MASK 0x0f16 -#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 -#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 -#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 -#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a -#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c -/* f20: AFG/MFG */ -#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 -#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d -#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e -#define AC_VERB_GET_HDMI_ELDD 0x0f2f -#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 -#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 -#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 -#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 -#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 - -/* - * SET verbs - */ -#define AC_VERB_SET_STREAM_FORMAT 0x200 -#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 -#define AC_VERB_SET_PROC_COEF 0x400 -#define AC_VERB_SET_COEF_INDEX 0x500 -#define AC_VERB_SET_CONNECT_SEL 0x701 -#define AC_VERB_SET_PROC_STATE 0x703 -#define AC_VERB_SET_SDI_SELECT 0x704 -#define AC_VERB_SET_POWER_STATE 0x705 -#define AC_VERB_SET_CHANNEL_STREAMID 0x706 -#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 -#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 -#define AC_VERB_SET_PIN_SENSE 0x709 -#define AC_VERB_SET_BEEP_CONTROL 0x70a -#define AC_VERB_SET_EAPD_BTLENABLE 0x70c -#define AC_VERB_SET_DIGI_CONVERT_1 0x70d -#define AC_VERB_SET_DIGI_CONVERT_2 0x70e -#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f -#define AC_VERB_SET_GPIO_DATA 0x715 -#define AC_VERB_SET_GPIO_MASK 0x716 -#define AC_VERB_SET_GPIO_DIRECTION 0x717 -#define AC_VERB_SET_GPIO_WAKE_MASK 0x718 -#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 -#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f -#define AC_VERB_SET_EAPD 0x788 -#define AC_VERB_SET_CODEC_RESET 0x7ff -#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d -#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 -#define AC_VERB_SET_HDMI_DIP_DATA 0x731 -#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 -#define AC_VERB_SET_HDMI_CP_CTRL 0x733 -#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 - -/* - * Parameter IDs - */ -#define AC_PAR_VENDOR_ID 0x00 -#define AC_PAR_SUBSYSTEM_ID 0x01 -#define AC_PAR_REV_ID 0x02 -#define AC_PAR_NODE_COUNT 0x04 -#define AC_PAR_FUNCTION_TYPE 0x05 -#define AC_PAR_AUDIO_FG_CAP 0x08 -#define AC_PAR_AUDIO_WIDGET_CAP 0x09 -#define AC_PAR_PCM 0x0a -#define AC_PAR_STREAM 0x0b -#define AC_PAR_PIN_CAP 0x0c -#define AC_PAR_AMP_IN_CAP 0x0d -#define AC_PAR_CONNLIST_LEN 0x0e -#define AC_PAR_POWER_STATE 0x0f -#define AC_PAR_PROC_CAP 0x10 -#define AC_PAR_GPIO_CAP 0x11 -#define AC_PAR_AMP_OUT_CAP 0x12 -#define AC_PAR_VOL_KNB_CAP 0x13 -#define AC_PAR_HDMI_LPCM_CAP 0x20 - -/* - * AC_VERB_PARAMETERS results (32bit) - */ - -/* Function Group Type */ -#define AC_FGT_TYPE (0xff<<0) -#define AC_FGT_TYPE_SHIFT 0 -#define AC_FGT_UNSOL_CAP (1<<8) - -/* Audio Function Group Capabilities */ -#define AC_AFG_OUT_DELAY (0xf<<0) -#define AC_AFG_IN_DELAY (0xf<<8) -#define AC_AFG_BEEP_GEN (1<<16) - -/* Audio Widget Capabilities */ -#define AC_WCAP_STEREO (1<<0) /* stereo I/O */ -#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ -#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ -#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ -#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ -#define AC_WCAP_STRIPE (1<<5) /* stripe */ -#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ -#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ -#define AC_WCAP_CONN_LIST (1<<8) /* connection list */ -#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ -#define AC_WCAP_POWER (1<<10) /* power control */ -#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ -#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ -#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ -#define AC_WCAP_DELAY (0xf<<16) -#define AC_WCAP_DELAY_SHIFT 16 -#define AC_WCAP_TYPE (0xf<<20) -#define AC_WCAP_TYPE_SHIFT 20 - -/* supported PCM rates and bits */ -#define AC_SUPPCM_RATES (0xfff << 0) -#define AC_SUPPCM_BITS_8 (1<<16) -#define AC_SUPPCM_BITS_16 (1<<17) -#define AC_SUPPCM_BITS_20 (1<<18) -#define AC_SUPPCM_BITS_24 (1<<19) -#define AC_SUPPCM_BITS_32 (1<<20) - -/* supported PCM stream format */ -#define AC_SUPFMT_PCM (1<<0) -#define AC_SUPFMT_FLOAT32 (1<<1) -#define AC_SUPFMT_AC3 (1<<2) - -/* GP I/O count */ -#define AC_GPIO_IO_COUNT (0xff<<0) -#define AC_GPIO_O_COUNT (0xff<<8) -#define AC_GPIO_O_COUNT_SHIFT 8 -#define AC_GPIO_I_COUNT (0xff<<16) -#define AC_GPIO_I_COUNT_SHIFT 16 -#define AC_GPIO_UNSOLICITED (1<<30) -#define AC_GPIO_WAKE (1<<31) - -/* Converter stream, channel */ -#define AC_CONV_CHANNEL (0xf<<0) -#define AC_CONV_STREAM (0xf<<4) -#define AC_CONV_STREAM_SHIFT 4 - -/* Input converter SDI select */ -#define AC_SDI_SELECT (0xf<<0) - -/* stream format id */ -#define AC_FMT_CHAN_SHIFT 0 -#define AC_FMT_CHAN_MASK (0x0f << 0) -#define AC_FMT_BITS_SHIFT 4 -#define AC_FMT_BITS_MASK (7 << 4) -#define AC_FMT_BITS_8 (0 << 4) -#define AC_FMT_BITS_16 (1 << 4) -#define AC_FMT_BITS_20 (2 << 4) -#define AC_FMT_BITS_24 (3 << 4) -#define AC_FMT_BITS_32 (4 << 4) -#define AC_FMT_DIV_SHIFT 8 -#define AC_FMT_DIV_MASK (7 << 8) -#define AC_FMT_MULT_SHIFT 11 -#define AC_FMT_MULT_MASK (7 << 11) -#define AC_FMT_BASE_SHIFT 14 -#define AC_FMT_BASE_48K (0 << 14) -#define AC_FMT_BASE_44K (1 << 14) -#define AC_FMT_TYPE_SHIFT 15 -#define AC_FMT_TYPE_PCM (0 << 15) -#define AC_FMT_TYPE_NON_PCM (1 << 15) - -/* Unsolicited response control */ -#define AC_UNSOL_TAG (0x3f<<0) -#define AC_UNSOL_ENABLED (1<<7) -#define AC_USRSP_EN AC_UNSOL_ENABLED - -/* Unsolicited responses */ -#define AC_UNSOL_RES_TAG (0x3f<<26) -#define AC_UNSOL_RES_TAG_SHIFT 26 -#define AC_UNSOL_RES_SUBTAG (0x1f<<21) -#define AC_UNSOL_RES_SUBTAG_SHIFT 21 -#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ -#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ -#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ -#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ - -/* Pin widget capabilies */ -#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ -#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ -#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ -#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ -#define AC_PINCAP_OUT (1<<4) /* output capable */ -#define AC_PINCAP_IN (1<<5) /* input capable */ -#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ -/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, - * but is marked reserved in the Intel HDA specification. - */ -#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ -/* Note: The same bit as LR_SWAP is newly defined as HDMI capability - * in HD-audio specification - */ -#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ -#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can - * coexist with AC_PINCAP_HDMI - */ -#define AC_PINCAP_VREF (0x37<<8) -#define AC_PINCAP_VREF_SHIFT 8 -#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ -#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */ -/* Vref status (used in pin cap) */ -#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ -#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ -#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ -#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ -#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ - -/* Amplifier capabilities */ -#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ -#define AC_AMPCAP_OFFSET_SHIFT 0 -#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ -#define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB - * in 0.25dB - */ -#define AC_AMPCAP_STEP_SIZE_SHIFT 16 -#define AC_AMPCAP_MUTE (1<<31) /* mute capable */ -#define AC_AMPCAP_MUTE_SHIFT 31 - -/* Connection list */ -#define AC_CLIST_LENGTH (0x7f<<0) -#define AC_CLIST_LONG (1<<7) - -/* Supported power status */ -#define AC_PWRST_D0SUP (1<<0) -#define AC_PWRST_D1SUP (1<<1) -#define AC_PWRST_D2SUP (1<<2) -#define AC_PWRST_D3SUP (1<<3) -#define AC_PWRST_D3COLDSUP (1<<4) -#define AC_PWRST_S3D3COLDSUP (1<<29) -#define AC_PWRST_CLKSTOP (1<<30) -#define AC_PWRST_EPSS (1U<<31) - -/* Power state values */ -#define AC_PWRST_SETTING (0xf<<0) -#define AC_PWRST_ACTUAL (0xf<<4) -#define AC_PWRST_ACTUAL_SHIFT 4 -#define AC_PWRST_D0 0x00 -#define AC_PWRST_D1 0x01 -#define AC_PWRST_D2 0x02 -#define AC_PWRST_D3 0x03 - -/* Processing capabilies */ -#define AC_PCAP_BENIGN (1<<0) -#define AC_PCAP_NUM_COEF (0xff<<8) -#define AC_PCAP_NUM_COEF_SHIFT 8 - -/* Volume knobs capabilities */ -#define AC_KNBCAP_NUM_STEPS (0x7f<<0) -#define AC_KNBCAP_DELTA (1<<7) - -/* HDMI LPCM capabilities */ -#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ -#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ -#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ -#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ -#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ -#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ -#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ -#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ -#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ -#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ -#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ -#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ -#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ -#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ - -/* - * Control Parameters - */ - -/* Amp gain/mute */ -#define AC_AMP_MUTE (1<<7) -#define AC_AMP_GAIN (0x7f) -#define AC_AMP_GET_INDEX (0xf<<0) - -#define AC_AMP_GET_LEFT (1<<13) -#define AC_AMP_GET_RIGHT (0<<13) -#define AC_AMP_GET_OUTPUT (1<<15) -#define AC_AMP_GET_INPUT (0<<15) - -#define AC_AMP_SET_INDEX (0xf<<8) -#define AC_AMP_SET_INDEX_SHIFT 8 -#define AC_AMP_SET_RIGHT (1<<12) -#define AC_AMP_SET_LEFT (1<<13) -#define AC_AMP_SET_INPUT (1<<14) -#define AC_AMP_SET_OUTPUT (1<<15) - -/* DIGITAL1 bits */ -#define AC_DIG1_ENABLE (1<<0) -#define AC_DIG1_V (1<<1) -#define AC_DIG1_VCFG (1<<2) -#define AC_DIG1_EMPHASIS (1<<3) -#define AC_DIG1_COPYRIGHT (1<<4) -#define AC_DIG1_NONAUDIO (1<<5) -#define AC_DIG1_PROFESSIONAL (1<<6) -#define AC_DIG1_LEVEL (1<<7) - -/* DIGITAL2 bits */ -#define AC_DIG2_CC (0x7f<<0) - -/* Pin widget control - 8bit */ -#define AC_PINCTL_EPT (0x3<<0) -#define AC_PINCTL_EPT_NATIVE 0 -#define AC_PINCTL_EPT_HBR 3 -#define AC_PINCTL_VREFEN (0x7<<0) -#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ -#define AC_PINCTL_VREF_50 1 /* 50% */ -#define AC_PINCTL_VREF_GRD 2 /* ground */ -#define AC_PINCTL_VREF_80 4 /* 80% */ -#define AC_PINCTL_VREF_100 5 /* 100% */ -#define AC_PINCTL_IN_EN (1<<5) -#define AC_PINCTL_OUT_EN (1<<6) -#define AC_PINCTL_HP_EN (1<<7) - -/* Pin sense - 32bit */ -#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) -#define AC_PINSENSE_PRESENCE (1<<31) -#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ - -/* EAPD/BTL enable - 32bit */ -#define AC_EAPDBTL_BALANCED (1<<0) -#define AC_EAPDBTL_EAPD (1<<1) -#define AC_EAPDBTL_LR_SWAP (1<<2) - -/* HDMI ELD data */ -#define AC_ELDD_ELD_VALID (1<<31) -#define AC_ELDD_ELD_DATA 0xff - -/* HDMI DIP size */ -#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ -#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ - -/* HDMI DIP index */ -#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ -#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ - -/* HDMI DIP xmit (transmit) control */ -#define AC_DIPXMIT_MASK (0x3<<6) -#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ -#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ -#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ - -/* HDMI content protection (CP) control */ -#define AC_CPCTRL_CES (1<<9) /* current encryption state */ -#define AC_CPCTRL_READY (1<<8) /* ready bit */ -#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ -#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ - -/* Converter channel <-> HDMI slot mapping */ -#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ -#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ - -/* configuration default - 32bit */ -#define AC_DEFCFG_SEQUENCE (0xf<<0) -#define AC_DEFCFG_DEF_ASSOC (0xf<<4) -#define AC_DEFCFG_ASSOC_SHIFT 4 -#define AC_DEFCFG_MISC (0xf<<8) -#define AC_DEFCFG_MISC_SHIFT 8 -#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) -#define AC_DEFCFG_COLOR (0xf<<12) -#define AC_DEFCFG_COLOR_SHIFT 12 -#define AC_DEFCFG_CONN_TYPE (0xf<<16) -#define AC_DEFCFG_CONN_TYPE_SHIFT 16 -#define AC_DEFCFG_DEVICE (0xf<<20) -#define AC_DEFCFG_DEVICE_SHIFT 20 -#define AC_DEFCFG_LOCATION (0x3f<<24) -#define AC_DEFCFG_LOCATION_SHIFT 24 -#define AC_DEFCFG_PORT_CONN (0x3<<30) -#define AC_DEFCFG_PORT_CONN_SHIFT 30 - -/* device device types (0x0-0xf) */ -enum { - AC_JACK_LINE_OUT, - AC_JACK_SPEAKER, - AC_JACK_HP_OUT, - AC_JACK_CD, - AC_JACK_SPDIF_OUT, - AC_JACK_DIG_OTHER_OUT, - AC_JACK_MODEM_LINE_SIDE, - AC_JACK_MODEM_HAND_SIDE, - AC_JACK_LINE_IN, - AC_JACK_AUX, - AC_JACK_MIC_IN, - AC_JACK_TELEPHONY, - AC_JACK_SPDIF_IN, - AC_JACK_DIG_OTHER_IN, - AC_JACK_OTHER = 0xf, -}; - -/* jack connection types (0x0-0xf) */ -enum { - AC_JACK_CONN_UNKNOWN, - AC_JACK_CONN_1_8, - AC_JACK_CONN_1_4, - AC_JACK_CONN_ATAPI, - AC_JACK_CONN_RCA, - AC_JACK_CONN_OPTICAL, - AC_JACK_CONN_OTHER_DIGITAL, - AC_JACK_CONN_OTHER_ANALOG, - AC_JACK_CONN_DIN, - AC_JACK_CONN_XLR, - AC_JACK_CONN_RJ11, - AC_JACK_CONN_COMB, - AC_JACK_CONN_OTHER = 0xf, -}; - -/* jack colors (0x0-0xf) */ -enum { - AC_JACK_COLOR_UNKNOWN, - AC_JACK_COLOR_BLACK, - AC_JACK_COLOR_GREY, - AC_JACK_COLOR_BLUE, - AC_JACK_COLOR_GREEN, - AC_JACK_COLOR_RED, - AC_JACK_COLOR_ORANGE, - AC_JACK_COLOR_YELLOW, - AC_JACK_COLOR_PURPLE, - AC_JACK_COLOR_PINK, - AC_JACK_COLOR_WHITE = 0xe, - AC_JACK_COLOR_OTHER, -}; - -/* Jack location (0x0-0x3f) */ -/* common case */ -enum { - AC_JACK_LOC_NONE, - AC_JACK_LOC_REAR, - AC_JACK_LOC_FRONT, - AC_JACK_LOC_LEFT, - AC_JACK_LOC_RIGHT, - AC_JACK_LOC_TOP, - AC_JACK_LOC_BOTTOM, -}; -/* bits 4-5 */ -enum { - AC_JACK_LOC_EXTERNAL = 0x00, - AC_JACK_LOC_INTERNAL = 0x10, - AC_JACK_LOC_SEPARATE = 0x20, - AC_JACK_LOC_OTHER = 0x30, -}; -enum { - /* external on primary chasis */ - AC_JACK_LOC_REAR_PANEL = 0x07, - AC_JACK_LOC_DRIVE_BAY, - /* internal */ - AC_JACK_LOC_RISER = 0x17, - AC_JACK_LOC_HDMI, - AC_JACK_LOC_ATAPI, - /* others */ - AC_JACK_LOC_MOBILE_IN = 0x37, - AC_JACK_LOC_MOBILE_OUT, -}; - -/* Port connectivity (0-3) */ -enum { - AC_JACK_PORT_COMPLEX, - AC_JACK_PORT_NONE, - AC_JACK_PORT_FIXED, - AC_JACK_PORT_BOTH, -}; - -/* max. connections to a widget */ -#define HDA_MAX_CONNECTIONS 32 - -/* max. codec address */ -#define HDA_MAX_CODEC_ADDRESS 0x0f - -/* max number of PCM devics per card */ -#define HDA_MAX_PCMS 10 - -/* --------------------------------------------------------------------- */ - -#endif diff --git a/qemu/hw/audio/intel-hda.c b/qemu/hw/audio/intel-hda.c deleted file mode 100644 index d372d4ab9..000000000 --- a/qemu/hw/audio/intel-hda.c +++ /dev/null @@ -1,1344 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * written by Gerd Hoffmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/pci/pci.h" -#include "hw/pci/msi.h" -#include "qemu/timer.h" -#include "hw/audio/audio.h" -#include "intel-hda.h" -#include "intel-hda-defs.h" -#include "sysemu/dma.h" - -/* --------------------------------------------------------------------- */ -/* hda bus */ - -static Property hda_props[] = { - DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1), - DEFINE_PROP_END_OF_LIST() -}; - -static const TypeInfo hda_codec_bus_info = { - .name = TYPE_HDA_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(HDACodecBus), -}; - -void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size, - hda_codec_response_func response, - hda_codec_xfer_func xfer) -{ - qbus_create_inplace(bus, bus_size, TYPE_HDA_BUS, dev, NULL); - bus->response = response; - bus->xfer = xfer; -} - -static int hda_codec_dev_init(DeviceState *qdev) -{ - HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus); - HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); - HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); - - if (dev->cad == -1) { - dev->cad = bus->next_cad; - } - if (dev->cad >= 15) { - return -1; - } - bus->next_cad = dev->cad + 1; - return cdc->init(dev); -} - -static int hda_codec_dev_exit(DeviceState *qdev) -{ - HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev); - HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev); - - if (cdc->exit) { - cdc->exit(dev); - } - return 0; -} - -HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad) -{ - BusChild *kid; - HDACodecDevice *cdev; - - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { - DeviceState *qdev = kid->child; - cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); - if (cdev->cad == cad) { - return cdev; - } - } - return NULL; -} - -void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response) -{ - HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); - bus->response(dev, solicited, response); -} - -bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, - uint8_t *buf, uint32_t len) -{ - HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); - return bus->xfer(dev, stnr, output, buf, len); -} - -/* --------------------------------------------------------------------- */ -/* intel hda emulation */ - -typedef struct IntelHDAStream IntelHDAStream; -typedef struct IntelHDAState IntelHDAState; -typedef struct IntelHDAReg IntelHDAReg; - -typedef struct bpl { - uint64_t addr; - uint32_t len; - uint32_t flags; -} bpl; - -struct IntelHDAStream { - /* registers */ - uint32_t ctl; - uint32_t lpib; - uint32_t cbl; - uint32_t lvi; - uint32_t fmt; - uint32_t bdlp_lbase; - uint32_t bdlp_ubase; - - /* state */ - bpl *bpl; - uint32_t bentries; - uint32_t bsize, be, bp; -}; - -struct IntelHDAState { - PCIDevice pci; - const char *name; - HDACodecBus codecs; - - /* registers */ - uint32_t g_ctl; - uint32_t wake_en; - uint32_t state_sts; - uint32_t int_ctl; - uint32_t int_sts; - uint32_t wall_clk; - - uint32_t corb_lbase; - uint32_t corb_ubase; - uint32_t corb_rp; - uint32_t corb_wp; - uint32_t corb_ctl; - uint32_t corb_sts; - uint32_t corb_size; - - uint32_t rirb_lbase; - uint32_t rirb_ubase; - uint32_t rirb_wp; - uint32_t rirb_cnt; - uint32_t rirb_ctl; - uint32_t rirb_sts; - uint32_t rirb_size; - - uint32_t dp_lbase; - uint32_t dp_ubase; - - uint32_t icw; - uint32_t irr; - uint32_t ics; - - /* streams */ - IntelHDAStream st[8]; - - /* state */ - MemoryRegion mmio; - uint32_t rirb_count; - int64_t wall_base_ns; - - /* debug logging */ - const IntelHDAReg *last_reg; - uint32_t last_val; - uint32_t last_write; - uint32_t last_sec; - uint32_t repeat_count; - - /* properties */ - uint32_t debug; - uint32_t msi; - bool old_msi_addr; -}; - -#define TYPE_INTEL_HDA_GENERIC "intel-hda-generic" - -#define INTEL_HDA(obj) \ - OBJECT_CHECK(IntelHDAState, (obj), TYPE_INTEL_HDA_GENERIC) - -struct IntelHDAReg { - const char *name; /* register name */ - uint32_t size; /* size in bytes */ - uint32_t reset; /* reset value */ - uint32_t wmask; /* write mask */ - uint32_t wclear; /* write 1 to clear bits */ - uint32_t offset; /* location in IntelHDAState */ - uint32_t shift; /* byte access entries for dwords */ - uint32_t stream; - void (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old); - void (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg); -}; - -static void intel_hda_reset(DeviceState *dev); - -/* --------------------------------------------------------------------- */ - -static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase) -{ - hwaddr addr; - - addr = ((uint64_t)ubase << 32) | lbase; - return addr; -} - -static void intel_hda_update_int_sts(IntelHDAState *d) -{ - uint32_t sts = 0; - uint32_t i; - - /* update controller status */ - if (d->rirb_sts & ICH6_RBSTS_IRQ) { - sts |= (1 << 30); - } - if (d->rirb_sts & ICH6_RBSTS_OVERRUN) { - sts |= (1 << 30); - } - if (d->state_sts & d->wake_en) { - sts |= (1 << 30); - } - - /* update stream status */ - for (i = 0; i < 8; i++) { - /* buffer completion interrupt */ - if (d->st[i].ctl & (1 << 26)) { - sts |= (1 << i); - } - } - - /* update global status */ - if (sts & d->int_ctl) { - sts |= (1U << 31); - } - - d->int_sts = sts; -} - -static void intel_hda_update_irq(IntelHDAState *d) -{ - int msi = d->msi && msi_enabled(&d->pci); - int level; - - intel_hda_update_int_sts(d); - if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) { - level = 1; - } else { - level = 0; - } - dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__, - level, msi ? "msi" : "intx"); - if (msi) { - if (level) { - msi_notify(&d->pci, 0); - } - } else { - pci_set_irq(&d->pci, level); - } -} - -static int intel_hda_send_command(IntelHDAState *d, uint32_t verb) -{ - uint32_t cad, nid, data; - HDACodecDevice *codec; - HDACodecDeviceClass *cdc; - - cad = (verb >> 28) & 0x0f; - if (verb & (1 << 27)) { - /* indirect node addressing, not specified in HDA 1.0 */ - dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__); - return -1; - } - nid = (verb >> 20) & 0x7f; - data = verb & 0xfffff; - - codec = hda_codec_find(&d->codecs, cad); - if (codec == NULL) { - dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__); - return -1; - } - cdc = HDA_CODEC_DEVICE_GET_CLASS(codec); - cdc->command(codec, nid, data); - return 0; -} - -static void intel_hda_corb_run(IntelHDAState *d) -{ - hwaddr addr; - uint32_t rp, verb; - - if (d->ics & ICH6_IRS_BUSY) { - dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw); - intel_hda_send_command(d, d->icw); - return; - } - - for (;;) { - if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) { - dprint(d, 2, "%s: !run\n", __FUNCTION__); - return; - } - if ((d->corb_rp & 0xff) == d->corb_wp) { - dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__); - return; - } - if (d->rirb_count == d->rirb_cnt) { - dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__); - return; - } - - rp = (d->corb_rp + 1) & 0xff; - addr = intel_hda_addr(d->corb_lbase, d->corb_ubase); - verb = ldl_le_pci_dma(&d->pci, addr + 4*rp); - d->corb_rp = rp; - - dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb); - intel_hda_send_command(d, verb); - } -} - -static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response) -{ - HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); - IntelHDAState *d = container_of(bus, IntelHDAState, codecs); - hwaddr addr; - uint32_t wp, ex; - - if (d->ics & ICH6_IRS_BUSY) { - dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n", - __FUNCTION__, response, dev->cad); - d->irr = response; - d->ics &= ~(ICH6_IRS_BUSY | 0xf0); - d->ics |= (ICH6_IRS_VALID | (dev->cad << 4)); - return; - } - - if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) { - dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__); - return; - } - - ex = (solicited ? 0 : (1 << 4)) | dev->cad; - wp = (d->rirb_wp + 1) & 0xff; - addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase); - stl_le_pci_dma(&d->pci, addr + 8*wp, response); - stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex); - d->rirb_wp = wp; - - dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n", - __FUNCTION__, wp, response, ex); - - d->rirb_count++; - if (d->rirb_count == d->rirb_cnt) { - dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count); - if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) { - d->rirb_sts |= ICH6_RBSTS_IRQ; - intel_hda_update_irq(d); - } - } else if ((d->corb_rp & 0xff) == d->corb_wp) { - dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__, - d->rirb_count, d->rirb_cnt); - if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) { - d->rirb_sts |= ICH6_RBSTS_IRQ; - intel_hda_update_irq(d); - } - } -} - -static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, - uint8_t *buf, uint32_t len) -{ - HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus); - IntelHDAState *d = container_of(bus, IntelHDAState, codecs); - hwaddr addr; - uint32_t s, copy, left; - IntelHDAStream *st; - bool irq = false; - - st = output ? d->st + 4 : d->st; - for (s = 0; s < 4; s++) { - if (stnr == ((st[s].ctl >> 20) & 0x0f)) { - st = st + s; - break; - } - } - if (s == 4) { - return false; - } - if (st->bpl == NULL) { - return false; - } - if (st->ctl & (1 << 26)) { - /* - * Wait with the next DMA xfer until the guest - * has acked the buffer completion interrupt - */ - return false; - } - - left = len; - while (left > 0) { - copy = left; - if (copy > st->bsize - st->lpib) - copy = st->bsize - st->lpib; - if (copy > st->bpl[st->be].len - st->bp) - copy = st->bpl[st->be].len - st->bp; - - dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n", - st->be, st->bp, st->bpl[st->be].len, copy); - - pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output); - st->lpib += copy; - st->bp += copy; - buf += copy; - left -= copy; - - if (st->bpl[st->be].len == st->bp) { - /* bpl entry filled */ - if (st->bpl[st->be].flags & 0x01) { - irq = true; - } - st->bp = 0; - st->be++; - if (st->be == st->bentries) { - /* bpl wrap around */ - st->be = 0; - st->lpib = 0; - } - } - } - if (d->dp_lbase & 0x01) { - s = st - d->st; - addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase); - stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib); - } - dprint(d, 3, "dma: --\n"); - - if (irq) { - st->ctl |= (1 << 26); /* buffer completion interrupt */ - intel_hda_update_irq(d); - } - return true; -} - -static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st) -{ - hwaddr addr; - uint8_t buf[16]; - uint32_t i; - - addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase); - st->bentries = st->lvi +1; - g_free(st->bpl); - st->bpl = g_malloc(sizeof(bpl) * st->bentries); - for (i = 0; i < st->bentries; i++, addr += 16) { - pci_dma_read(&d->pci, addr, buf, 16); - st->bpl[i].addr = le64_to_cpu(*(uint64_t *)buf); - st->bpl[i].len = le32_to_cpu(*(uint32_t *)(buf + 8)); - st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12)); - dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n", - i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags); - } - - st->bsize = st->cbl; - st->lpib = 0; - st->be = 0; - st->bp = 0; -} - -static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output) -{ - BusChild *kid; - HDACodecDevice *cdev; - - QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { - DeviceState *qdev = kid->child; - HDACodecDeviceClass *cdc; - - cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); - cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev); - if (cdc->stream) { - cdc->stream(cdev, stream, running, output); - } - } -} - -/* --------------------------------------------------------------------- */ - -static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - if ((d->g_ctl & ICH6_GCTL_RESET) == 0) { - intel_hda_reset(DEVICE(d)); - } -} - -static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - intel_hda_update_irq(d); -} - -static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - intel_hda_update_irq(d); -} - -static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - intel_hda_update_irq(d); -} - -static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg) -{ - int64_t ns; - - ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - d->wall_base_ns; - d->wall_clk = (uint32_t)(ns * 24 / 1000); /* 24 MHz */ -} - -static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - intel_hda_corb_run(d); -} - -static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - intel_hda_corb_run(d); -} - -static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - if (d->rirb_wp & ICH6_RIRBWP_RST) { - d->rirb_wp = 0; - } -} - -static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - intel_hda_update_irq(d); - - if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) { - /* cleared ICH6_RBSTS_IRQ */ - d->rirb_count = 0; - intel_hda_corb_run(d); - } -} - -static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - if (d->ics & ICH6_IRS_BUSY) { - intel_hda_corb_run(d); - } -} - -static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old) -{ - bool output = reg->stream >= 4; - IntelHDAStream *st = d->st + reg->stream; - - if (st->ctl & 0x01) { - /* reset */ - dprint(d, 1, "st #%d: reset\n", reg->stream); - st->ctl = SD_STS_FIFO_READY << 24; - } - if ((st->ctl & 0x02) != (old & 0x02)) { - uint32_t stnr = (st->ctl >> 20) & 0x0f; - /* run bit flipped */ - if (st->ctl & 0x02) { - /* start */ - dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n", - reg->stream, stnr, st->cbl); - intel_hda_parse_bdl(d, st); - intel_hda_notify_codecs(d, stnr, true, output); - } else { - /* stop */ - dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr); - intel_hda_notify_codecs(d, stnr, false, output); - } - } - intel_hda_update_irq(d); -} - -/* --------------------------------------------------------------------- */ - -#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o)) - -static const struct IntelHDAReg regtab[] = { - /* global */ - [ ICH6_REG_GCAP ] = { - .name = "GCAP", - .size = 2, - .reset = 0x4401, - }, - [ ICH6_REG_VMIN ] = { - .name = "VMIN", - .size = 1, - }, - [ ICH6_REG_VMAJ ] = { - .name = "VMAJ", - .size = 1, - .reset = 1, - }, - [ ICH6_REG_OUTPAY ] = { - .name = "OUTPAY", - .size = 2, - .reset = 0x3c, - }, - [ ICH6_REG_INPAY ] = { - .name = "INPAY", - .size = 2, - .reset = 0x1d, - }, - [ ICH6_REG_GCTL ] = { - .name = "GCTL", - .size = 4, - .wmask = 0x0103, - .offset = offsetof(IntelHDAState, g_ctl), - .whandler = intel_hda_set_g_ctl, - }, - [ ICH6_REG_WAKEEN ] = { - .name = "WAKEEN", - .size = 2, - .wmask = 0x7fff, - .offset = offsetof(IntelHDAState, wake_en), - .whandler = intel_hda_set_wake_en, - }, - [ ICH6_REG_STATESTS ] = { - .name = "STATESTS", - .size = 2, - .wmask = 0x7fff, - .wclear = 0x7fff, - .offset = offsetof(IntelHDAState, state_sts), - .whandler = intel_hda_set_state_sts, - }, - - /* interrupts */ - [ ICH6_REG_INTCTL ] = { - .name = "INTCTL", - .size = 4, - .wmask = 0xc00000ff, - .offset = offsetof(IntelHDAState, int_ctl), - .whandler = intel_hda_set_int_ctl, - }, - [ ICH6_REG_INTSTS ] = { - .name = "INTSTS", - .size = 4, - .wmask = 0xc00000ff, - .wclear = 0xc00000ff, - .offset = offsetof(IntelHDAState, int_sts), - }, - - /* misc */ - [ ICH6_REG_WALLCLK ] = { - .name = "WALLCLK", - .size = 4, - .offset = offsetof(IntelHDAState, wall_clk), - .rhandler = intel_hda_get_wall_clk, - }, - [ ICH6_REG_WALLCLK + 0x2000 ] = { - .name = "WALLCLK(alias)", - .size = 4, - .offset = offsetof(IntelHDAState, wall_clk), - .rhandler = intel_hda_get_wall_clk, - }, - - /* dma engine */ - [ ICH6_REG_CORBLBASE ] = { - .name = "CORBLBASE", - .size = 4, - .wmask = 0xffffff80, - .offset = offsetof(IntelHDAState, corb_lbase), - }, - [ ICH6_REG_CORBUBASE ] = { - .name = "CORBUBASE", - .size = 4, - .wmask = 0xffffffff, - .offset = offsetof(IntelHDAState, corb_ubase), - }, - [ ICH6_REG_CORBWP ] = { - .name = "CORBWP", - .size = 2, - .wmask = 0xff, - .offset = offsetof(IntelHDAState, corb_wp), - .whandler = intel_hda_set_corb_wp, - }, - [ ICH6_REG_CORBRP ] = { - .name = "CORBRP", - .size = 2, - .wmask = 0x80ff, - .offset = offsetof(IntelHDAState, corb_rp), - }, - [ ICH6_REG_CORBCTL ] = { - .name = "CORBCTL", - .size = 1, - .wmask = 0x03, - .offset = offsetof(IntelHDAState, corb_ctl), - .whandler = intel_hda_set_corb_ctl, - }, - [ ICH6_REG_CORBSTS ] = { - .name = "CORBSTS", - .size = 1, - .wmask = 0x01, - .wclear = 0x01, - .offset = offsetof(IntelHDAState, corb_sts), - }, - [ ICH6_REG_CORBSIZE ] = { - .name = "CORBSIZE", - .size = 1, - .reset = 0x42, - .offset = offsetof(IntelHDAState, corb_size), - }, - [ ICH6_REG_RIRBLBASE ] = { - .name = "RIRBLBASE", - .size = 4, - .wmask = 0xffffff80, - .offset = offsetof(IntelHDAState, rirb_lbase), - }, - [ ICH6_REG_RIRBUBASE ] = { - .name = "RIRBUBASE", - .size = 4, - .wmask = 0xffffffff, - .offset = offsetof(IntelHDAState, rirb_ubase), - }, - [ ICH6_REG_RIRBWP ] = { - .name = "RIRBWP", - .size = 2, - .wmask = 0x8000, - .offset = offsetof(IntelHDAState, rirb_wp), - .whandler = intel_hda_set_rirb_wp, - }, - [ ICH6_REG_RINTCNT ] = { - .name = "RINTCNT", - .size = 2, - .wmask = 0xff, - .offset = offsetof(IntelHDAState, rirb_cnt), - }, - [ ICH6_REG_RIRBCTL ] = { - .name = "RIRBCTL", - .size = 1, - .wmask = 0x07, - .offset = offsetof(IntelHDAState, rirb_ctl), - }, - [ ICH6_REG_RIRBSTS ] = { - .name = "RIRBSTS", - .size = 1, - .wmask = 0x05, - .wclear = 0x05, - .offset = offsetof(IntelHDAState, rirb_sts), - .whandler = intel_hda_set_rirb_sts, - }, - [ ICH6_REG_RIRBSIZE ] = { - .name = "RIRBSIZE", - .size = 1, - .reset = 0x42, - .offset = offsetof(IntelHDAState, rirb_size), - }, - - [ ICH6_REG_DPLBASE ] = { - .name = "DPLBASE", - .size = 4, - .wmask = 0xffffff81, - .offset = offsetof(IntelHDAState, dp_lbase), - }, - [ ICH6_REG_DPUBASE ] = { - .name = "DPUBASE", - .size = 4, - .wmask = 0xffffffff, - .offset = offsetof(IntelHDAState, dp_ubase), - }, - - [ ICH6_REG_IC ] = { - .name = "ICW", - .size = 4, - .wmask = 0xffffffff, - .offset = offsetof(IntelHDAState, icw), - }, - [ ICH6_REG_IR ] = { - .name = "IRR", - .size = 4, - .offset = offsetof(IntelHDAState, irr), - }, - [ ICH6_REG_IRS ] = { - .name = "ICS", - .size = 2, - .wmask = 0x0003, - .wclear = 0x0002, - .offset = offsetof(IntelHDAState, ics), - .whandler = intel_hda_set_ics, - }, - -#define HDA_STREAM(_t, _i) \ - [ ST_REG(_i, ICH6_REG_SD_CTL) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " CTL", \ - .size = 4, \ - .wmask = 0x1cff001f, \ - .offset = offsetof(IntelHDAState, st[_i].ctl), \ - .whandler = intel_hda_set_st_ctl, \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = { \ - .stream = _i, \ - .name = _t stringify(_i) " CTL(stnr)", \ - .size = 1, \ - .shift = 16, \ - .wmask = 0x00ff0000, \ - .offset = offsetof(IntelHDAState, st[_i].ctl), \ - .whandler = intel_hda_set_st_ctl, \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_STS)] = { \ - .stream = _i, \ - .name = _t stringify(_i) " CTL(sts)", \ - .size = 1, \ - .shift = 24, \ - .wmask = 0x1c000000, \ - .wclear = 0x1c000000, \ - .offset = offsetof(IntelHDAState, st[_i].ctl), \ - .whandler = intel_hda_set_st_ctl, \ - .reset = SD_STS_FIFO_READY << 24 \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " LPIB", \ - .size = 4, \ - .offset = offsetof(IntelHDAState, st[_i].lpib), \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " LPIB(alias)", \ - .size = 4, \ - .offset = offsetof(IntelHDAState, st[_i].lpib), \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_CBL) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " CBL", \ - .size = 4, \ - .wmask = 0xffffffff, \ - .offset = offsetof(IntelHDAState, st[_i].cbl), \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_LVI) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " LVI", \ - .size = 2, \ - .wmask = 0x00ff, \ - .offset = offsetof(IntelHDAState, st[_i].lvi), \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " FIFOS", \ - .size = 2, \ - .reset = HDA_BUFFER_SIZE, \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " FMT", \ - .size = 2, \ - .wmask = 0x7f7f, \ - .offset = offsetof(IntelHDAState, st[_i].fmt), \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " BDLPL", \ - .size = 4, \ - .wmask = 0xffffff80, \ - .offset = offsetof(IntelHDAState, st[_i].bdlp_lbase), \ - }, \ - [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = { \ - .stream = _i, \ - .name = _t stringify(_i) " BDLPU", \ - .size = 4, \ - .wmask = 0xffffffff, \ - .offset = offsetof(IntelHDAState, st[_i].bdlp_ubase), \ - }, \ - - HDA_STREAM("IN", 0) - HDA_STREAM("IN", 1) - HDA_STREAM("IN", 2) - HDA_STREAM("IN", 3) - - HDA_STREAM("OUT", 4) - HDA_STREAM("OUT", 5) - HDA_STREAM("OUT", 6) - HDA_STREAM("OUT", 7) - -}; - -static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr) -{ - const IntelHDAReg *reg; - - if (addr >= ARRAY_SIZE(regtab)) { - goto noreg; - } - reg = regtab+addr; - if (reg->name == NULL) { - goto noreg; - } - return reg; - -noreg: - dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr); - return NULL; -} - -static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg) -{ - uint8_t *addr = (void*)d; - - addr += reg->offset; - return (uint32_t*)addr; -} - -static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val, - uint32_t wmask) -{ - uint32_t *addr; - uint32_t old; - - if (!reg) { - return; - } - - if (d->debug) { - time_t now = time(NULL); - if (d->last_write && d->last_reg == reg && d->last_val == val) { - d->repeat_count++; - if (d->last_sec != now) { - dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); - d->last_sec = now; - d->repeat_count = 0; - } - } else { - if (d->repeat_count) { - dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); - } - dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask); - d->last_write = 1; - d->last_reg = reg; - d->last_val = val; - d->last_sec = now; - d->repeat_count = 0; - } - } - assert(reg->offset != 0); - - addr = intel_hda_reg_addr(d, reg); - old = *addr; - - if (reg->shift) { - val <<= reg->shift; - wmask <<= reg->shift; - } - wmask &= reg->wmask; - *addr &= ~wmask; - *addr |= wmask & val; - *addr &= ~(val & reg->wclear); - - if (reg->whandler) { - reg->whandler(d, reg, old); - } -} - -static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg, - uint32_t rmask) -{ - uint32_t *addr, ret; - - if (!reg) { - return 0; - } - - if (reg->rhandler) { - reg->rhandler(d, reg); - } - - if (reg->offset == 0) { - /* constant read-only register */ - ret = reg->reset; - } else { - addr = intel_hda_reg_addr(d, reg); - ret = *addr; - if (reg->shift) { - ret >>= reg->shift; - } - ret &= rmask; - } - if (d->debug) { - time_t now = time(NULL); - if (!d->last_write && d->last_reg == reg && d->last_val == ret) { - d->repeat_count++; - if (d->last_sec != now) { - dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); - d->last_sec = now; - d->repeat_count = 0; - } - } else { - if (d->repeat_count) { - dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count); - } - dprint(d, 2, "read %-16s: 0x%x (%x)\n", reg->name, ret, rmask); - d->last_write = 0; - d->last_reg = reg; - d->last_val = ret; - d->last_sec = now; - d->repeat_count = 0; - } - } - return ret; -} - -static void intel_hda_regs_reset(IntelHDAState *d) -{ - uint32_t *addr; - int i; - - for (i = 0; i < ARRAY_SIZE(regtab); i++) { - if (regtab[i].name == NULL) { - continue; - } - if (regtab[i].offset == 0) { - continue; - } - addr = intel_hda_reg_addr(d, regtab + i); - *addr = regtab[i].reset; - } -} - -/* --------------------------------------------------------------------- */ - -static void intel_hda_mmio_writeb(void *opaque, hwaddr addr, uint32_t val) -{ - IntelHDAState *d = opaque; - const IntelHDAReg *reg = intel_hda_reg_find(d, addr); - - intel_hda_reg_write(d, reg, val, 0xff); -} - -static void intel_hda_mmio_writew(void *opaque, hwaddr addr, uint32_t val) -{ - IntelHDAState *d = opaque; - const IntelHDAReg *reg = intel_hda_reg_find(d, addr); - - intel_hda_reg_write(d, reg, val, 0xffff); -} - -static void intel_hda_mmio_writel(void *opaque, hwaddr addr, uint32_t val) -{ - IntelHDAState *d = opaque; - const IntelHDAReg *reg = intel_hda_reg_find(d, addr); - - intel_hda_reg_write(d, reg, val, 0xffffffff); -} - -static uint32_t intel_hda_mmio_readb(void *opaque, hwaddr addr) -{ - IntelHDAState *d = opaque; - const IntelHDAReg *reg = intel_hda_reg_find(d, addr); - - return intel_hda_reg_read(d, reg, 0xff); -} - -static uint32_t intel_hda_mmio_readw(void *opaque, hwaddr addr) -{ - IntelHDAState *d = opaque; - const IntelHDAReg *reg = intel_hda_reg_find(d, addr); - - return intel_hda_reg_read(d, reg, 0xffff); -} - -static uint32_t intel_hda_mmio_readl(void *opaque, hwaddr addr) -{ - IntelHDAState *d = opaque; - const IntelHDAReg *reg = intel_hda_reg_find(d, addr); - - return intel_hda_reg_read(d, reg, 0xffffffff); -} - -static const MemoryRegionOps intel_hda_mmio_ops = { - .old_mmio = { - .read = { - intel_hda_mmio_readb, - intel_hda_mmio_readw, - intel_hda_mmio_readl, - }, - .write = { - intel_hda_mmio_writeb, - intel_hda_mmio_writew, - intel_hda_mmio_writel, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -/* --------------------------------------------------------------------- */ - -static void intel_hda_reset(DeviceState *dev) -{ - BusChild *kid; - IntelHDAState *d = INTEL_HDA(dev); - HDACodecDevice *cdev; - - intel_hda_regs_reset(d); - d->wall_base_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - - /* reset codecs */ - QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) { - DeviceState *qdev = kid->child; - cdev = DO_UPCAST(HDACodecDevice, qdev, qdev); - device_reset(DEVICE(cdev)); - d->state_sts |= (1 << cdev->cad); - } - intel_hda_update_irq(d); -} - -static void intel_hda_realize(PCIDevice *pci, Error **errp) -{ - IntelHDAState *d = INTEL_HDA(pci); - uint8_t *conf = d->pci.config; - - d->name = object_get_typename(OBJECT(d)); - - pci_config_set_interrupt_pin(conf, 1); - - /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */ - conf[0x40] = 0x01; - - memory_region_init_io(&d->mmio, OBJECT(d), &intel_hda_mmio_ops, d, - "intel-hda", 0x4000); - pci_register_bar(&d->pci, 0, 0, &d->mmio); - if (d->msi) { - msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false); - } - - hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs), - intel_hda_response, intel_hda_xfer); -} - -static void intel_hda_exit(PCIDevice *pci) -{ - IntelHDAState *d = INTEL_HDA(pci); - - msi_uninit(&d->pci); -} - -static int intel_hda_post_load(void *opaque, int version) -{ - IntelHDAState* d = opaque; - int i; - - dprint(d, 1, "%s\n", __FUNCTION__); - for (i = 0; i < ARRAY_SIZE(d->st); i++) { - if (d->st[i].ctl & 0x02) { - intel_hda_parse_bdl(d, &d->st[i]); - } - } - intel_hda_update_irq(d); - return 0; -} - -static const VMStateDescription vmstate_intel_hda_stream = { - .name = "intel-hda-stream", - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(ctl, IntelHDAStream), - VMSTATE_UINT32(lpib, IntelHDAStream), - VMSTATE_UINT32(cbl, IntelHDAStream), - VMSTATE_UINT32(lvi, IntelHDAStream), - VMSTATE_UINT32(fmt, IntelHDAStream), - VMSTATE_UINT32(bdlp_lbase, IntelHDAStream), - VMSTATE_UINT32(bdlp_ubase, IntelHDAStream), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_intel_hda = { - .name = "intel-hda", - .version_id = 1, - .post_load = intel_hda_post_load, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(pci, IntelHDAState), - - /* registers */ - VMSTATE_UINT32(g_ctl, IntelHDAState), - VMSTATE_UINT32(wake_en, IntelHDAState), - VMSTATE_UINT32(state_sts, IntelHDAState), - VMSTATE_UINT32(int_ctl, IntelHDAState), - VMSTATE_UINT32(int_sts, IntelHDAState), - VMSTATE_UINT32(wall_clk, IntelHDAState), - VMSTATE_UINT32(corb_lbase, IntelHDAState), - VMSTATE_UINT32(corb_ubase, IntelHDAState), - VMSTATE_UINT32(corb_rp, IntelHDAState), - VMSTATE_UINT32(corb_wp, IntelHDAState), - VMSTATE_UINT32(corb_ctl, IntelHDAState), - VMSTATE_UINT32(corb_sts, IntelHDAState), - VMSTATE_UINT32(corb_size, IntelHDAState), - VMSTATE_UINT32(rirb_lbase, IntelHDAState), - VMSTATE_UINT32(rirb_ubase, IntelHDAState), - VMSTATE_UINT32(rirb_wp, IntelHDAState), - VMSTATE_UINT32(rirb_cnt, IntelHDAState), - VMSTATE_UINT32(rirb_ctl, IntelHDAState), - VMSTATE_UINT32(rirb_sts, IntelHDAState), - VMSTATE_UINT32(rirb_size, IntelHDAState), - VMSTATE_UINT32(dp_lbase, IntelHDAState), - VMSTATE_UINT32(dp_ubase, IntelHDAState), - VMSTATE_UINT32(icw, IntelHDAState), - VMSTATE_UINT32(irr, IntelHDAState), - VMSTATE_UINT32(ics, IntelHDAState), - VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0, - vmstate_intel_hda_stream, - IntelHDAStream), - - /* additional state info */ - VMSTATE_UINT32(rirb_count, IntelHDAState), - VMSTATE_INT64(wall_base_ns, IntelHDAState), - - VMSTATE_END_OF_LIST() - } -}; - -static Property intel_hda_properties[] = { - DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0), - DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1), - DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false), - DEFINE_PROP_END_OF_LIST(), -}; - -static void intel_hda_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->realize = intel_hda_realize; - k->exit = intel_hda_exit; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO; - dc->reset = intel_hda_reset; - dc->vmsd = &vmstate_intel_hda; - dc->props = intel_hda_properties; -} - -static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->device_id = 0x2668; - k->revision = 1; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "Intel HD Audio Controller (ich6)"; -} - -static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->device_id = 0x293e; - k->revision = 3; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "Intel HD Audio Controller (ich9)"; -} - -static const TypeInfo intel_hda_info = { - .name = TYPE_INTEL_HDA_GENERIC, - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(IntelHDAState), - .class_init = intel_hda_class_init, - .abstract = true, -}; - -static const TypeInfo intel_hda_info_ich6 = { - .name = "intel-hda", - .parent = TYPE_INTEL_HDA_GENERIC, - .class_init = intel_hda_class_init_ich6, -}; - -static const TypeInfo intel_hda_info_ich9 = { - .name = "ich9-intel-hda", - .parent = TYPE_INTEL_HDA_GENERIC, - .class_init = intel_hda_class_init_ich9, -}; - -static void hda_codec_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *k = DEVICE_CLASS(klass); - k->init = hda_codec_dev_init; - k->exit = hda_codec_dev_exit; - set_bit(DEVICE_CATEGORY_SOUND, k->categories); - k->bus_type = TYPE_HDA_BUS; - k->props = hda_props; -} - -static const TypeInfo hda_codec_device_type_info = { - .name = TYPE_HDA_CODEC_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(HDACodecDevice), - .abstract = true, - .class_size = sizeof(HDACodecDeviceClass), - .class_init = hda_codec_device_class_init, -}; - -/* - * create intel hda controller with codec attached to it, - * so '-soundhw hda' works. - */ -static int intel_hda_and_codec_init(PCIBus *bus) -{ - DeviceState *controller; - BusState *hdabus; - DeviceState *codec; - - controller = DEVICE(pci_create_simple(bus, -1, "intel-hda")); - hdabus = QLIST_FIRST(&controller->child_bus); - codec = qdev_create(hdabus, "hda-duplex"); - qdev_init_nofail(codec); - return 0; -} - -static void intel_hda_register_types(void) -{ - type_register_static(&hda_codec_bus_info); - type_register_static(&intel_hda_info); - type_register_static(&intel_hda_info_ich6); - type_register_static(&intel_hda_info_ich9); - type_register_static(&hda_codec_device_type_info); - pci_register_soundhw("hda", "Intel HD Audio", intel_hda_and_codec_init); -} - -type_init(intel_hda_register_types) diff --git a/qemu/hw/audio/intel-hda.h b/qemu/hw/audio/intel-hda.h deleted file mode 100644 index d784bcf5f..000000000 --- a/qemu/hw/audio/intel-hda.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef HW_INTEL_HDA_H -#define HW_INTEL_HDA_H - -#include "hw/qdev.h" - -/* --------------------------------------------------------------------- */ -/* hda bus */ - -#define TYPE_HDA_CODEC_DEVICE "hda-codec" -#define HDA_CODEC_DEVICE(obj) \ - OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE) -#define HDA_CODEC_DEVICE_CLASS(klass) \ - OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE) -#define HDA_CODEC_DEVICE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE) - -#define TYPE_HDA_BUS "HDA" -#define HDA_BUS(obj) OBJECT_CHECK(HDACodecBus, (obj), TYPE_HDA_BUS) - -typedef struct HDACodecBus HDACodecBus; -typedef struct HDACodecDevice HDACodecDevice; - -typedef void (*hda_codec_response_func)(HDACodecDevice *dev, - bool solicited, uint32_t response); -typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev, - uint32_t stnr, bool output, - uint8_t *buf, uint32_t len); - -struct HDACodecBus { - BusState qbus; - uint32_t next_cad; - hda_codec_response_func response; - hda_codec_xfer_func xfer; -}; - -typedef struct HDACodecDeviceClass -{ - DeviceClass parent_class; - - int (*init)(HDACodecDevice *dev); - int (*exit)(HDACodecDevice *dev); - void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data); - void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output); -} HDACodecDeviceClass; - -struct HDACodecDevice { - DeviceState qdev; - uint32_t cad; /* codec address */ -}; - -void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus, size_t bus_size, - hda_codec_response_func response, - hda_codec_xfer_func xfer); -HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad); - -void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response); -bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, - uint8_t *buf, uint32_t len); - -/* --------------------------------------------------------------------- */ - -#define dprint(_dev, _level, _fmt, ...) \ - do { \ - if (_dev->debug >= _level) { \ - fprintf(stderr, "%s: ", _dev->name); \ - fprintf(stderr, _fmt, ## __VA_ARGS__); \ - } \ - } while (0) - -/* --------------------------------------------------------------------- */ - -#endif diff --git a/qemu/hw/audio/lm4549.c b/qemu/hw/audio/lm4549.c deleted file mode 100644 index a46f2301a..000000000 --- a/qemu/hw/audio/lm4549.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * LM4549 Audio Codec Interface - * - * Copyright (c) 2011 - * Written by Mathieu Sonet - www.elasticsheep.com - * - * This code is licensed under the GPL. - * - * ***************************************************************** - * - * This driver emulates the LM4549 codec. - * - * It supports only one playback voice and no record voice. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "audio/audio.h" -#include "lm4549.h" - -#if 0 -#define LM4549_DEBUG 1 -#endif - -#if 0 -#define LM4549_DUMP_DAC_INPUT 1 -#endif - -#ifdef LM4549_DEBUG -#define DPRINTF(fmt, ...) \ -do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) do {} while (0) -#endif - -#if defined(LM4549_DUMP_DAC_INPUT) -static FILE *fp_dac_input; -#endif - -/* LM4549 register list */ -enum { - LM4549_Reset = 0x00, - LM4549_Master_Volume = 0x02, - LM4549_Line_Out_Volume = 0x04, - LM4549_Master_Volume_Mono = 0x06, - LM4549_PC_Beep_Volume = 0x0A, - LM4549_Phone_Volume = 0x0C, - LM4549_Mic_Volume = 0x0E, - LM4549_Line_In_Volume = 0x10, - LM4549_CD_Volume = 0x12, - LM4549_Video_Volume = 0x14, - LM4549_Aux_Volume = 0x16, - LM4549_PCM_Out_Volume = 0x18, - LM4549_Record_Select = 0x1A, - LM4549_Record_Gain = 0x1C, - LM4549_General_Purpose = 0x20, - LM4549_3D_Control = 0x22, - LM4549_Powerdown_Ctrl_Stat = 0x26, - LM4549_Ext_Audio_ID = 0x28, - LM4549_Ext_Audio_Stat_Ctrl = 0x2A, - LM4549_PCM_Front_DAC_Rate = 0x2C, - LM4549_PCM_ADC_Rate = 0x32, - LM4549_Vendor_ID1 = 0x7C, - LM4549_Vendor_ID2 = 0x7E -}; - -static void lm4549_reset(lm4549_state *s) -{ - uint16_t *regfile = s->regfile; - - regfile[LM4549_Reset] = 0x0d50; - regfile[LM4549_Master_Volume] = 0x8008; - regfile[LM4549_Line_Out_Volume] = 0x8000; - regfile[LM4549_Master_Volume_Mono] = 0x8000; - regfile[LM4549_PC_Beep_Volume] = 0x0000; - regfile[LM4549_Phone_Volume] = 0x8008; - regfile[LM4549_Mic_Volume] = 0x8008; - regfile[LM4549_Line_In_Volume] = 0x8808; - regfile[LM4549_CD_Volume] = 0x8808; - regfile[LM4549_Video_Volume] = 0x8808; - regfile[LM4549_Aux_Volume] = 0x8808; - regfile[LM4549_PCM_Out_Volume] = 0x8808; - regfile[LM4549_Record_Select] = 0x0000; - regfile[LM4549_Record_Gain] = 0x8000; - regfile[LM4549_General_Purpose] = 0x0000; - regfile[LM4549_3D_Control] = 0x0101; - regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f; - regfile[LM4549_Ext_Audio_ID] = 0x0001; - regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000; - regfile[LM4549_PCM_Front_DAC_Rate] = 0xbb80; - regfile[LM4549_PCM_ADC_Rate] = 0xbb80; - regfile[LM4549_Vendor_ID1] = 0x4e53; - regfile[LM4549_Vendor_ID2] = 0x4331; -} - -static void lm4549_audio_transfer(lm4549_state *s) -{ - uint32_t written_bytes, written_samples; - uint32_t i; - - /* Activate the voice */ - AUD_set_active_out(s->voice, 1); - s->voice_is_active = 1; - - /* Try to write the buffer content */ - written_bytes = AUD_write(s->voice, s->buffer, - s->buffer_level * sizeof(uint16_t)); - written_samples = written_bytes >> 1; - -#if defined(LM4549_DUMP_DAC_INPUT) - fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input); -#endif - - s->buffer_level -= written_samples; - - if (s->buffer_level > 0) { - /* Move the data back to the start of the buffer */ - for (i = 0; i < s->buffer_level; i++) { - s->buffer[i] = s->buffer[i + written_samples]; - } - } -} - -static void lm4549_audio_out_callback(void *opaque, int free) -{ - lm4549_state *s = (lm4549_state *)opaque; - static uint32_t prev_buffer_level; - -#ifdef LM4549_DEBUG - int size = AUD_get_buffer_size_out(s->voice); - DPRINTF("audio_out_callback size = %i free = %i\n", size, free); -#endif - - /* Detect that no data are consumed - => disable the voice */ - if (s->buffer_level == prev_buffer_level) { - AUD_set_active_out(s->voice, 0); - s->voice_is_active = 0; - } - prev_buffer_level = s->buffer_level; - - /* Check if a buffer transfer is pending */ - if (s->buffer_level == LM4549_BUFFER_SIZE) { - lm4549_audio_transfer(s); - - /* Request more data */ - if (s->data_req_cb != NULL) { - (s->data_req_cb)(s->opaque); - } - } -} - -uint32_t lm4549_read(lm4549_state *s, hwaddr offset) -{ - uint16_t *regfile = s->regfile; - uint32_t value = 0; - - /* Read the stored value */ - assert(offset < 128); - value = regfile[offset]; - - DPRINTF("read [0x%02x] = 0x%04x\n", offset, value); - - return value; -} - -void lm4549_write(lm4549_state *s, - hwaddr offset, uint32_t value) -{ - uint16_t *regfile = s->regfile; - - assert(offset < 128); - DPRINTF("write [0x%02x] = 0x%04x\n", offset, value); - - switch (offset) { - case LM4549_Reset: - lm4549_reset(s); - break; - - case LM4549_PCM_Front_DAC_Rate: - regfile[LM4549_PCM_Front_DAC_Rate] = value; - DPRINTF("DAC rate change = %i\n", value); - - /* Re-open a voice with the new sample rate */ - struct audsettings as; - as.freq = value; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 0; - - s->voice = AUD_open_out( - &s->card, - s->voice, - "lm4549.out", - s, - lm4549_audio_out_callback, - &as - ); - break; - - case LM4549_Powerdown_Ctrl_Stat: - value &= ~0xf; - value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf; - regfile[LM4549_Powerdown_Ctrl_Stat] = value; - break; - - case LM4549_Ext_Audio_ID: - case LM4549_Vendor_ID1: - case LM4549_Vendor_ID2: - DPRINTF("Write to read-only register 0x%x\n", (int)offset); - break; - - default: - /* Store the new value */ - regfile[offset] = value; - break; - } -} - -uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right) -{ - /* The left and right samples are in 20-bit resolution. - The LM4549 has 18-bit resolution and only uses the bits [19:2]. - This model supports 16-bit playback. - */ - - if (s->buffer_level > LM4549_BUFFER_SIZE - 2) { - DPRINTF("write_sample Buffer full\n"); - return 0; - } - - /* Store 16-bit samples in the buffer */ - s->buffer[s->buffer_level++] = (left >> 4); - s->buffer[s->buffer_level++] = (right >> 4); - - if (s->buffer_level == LM4549_BUFFER_SIZE) { - /* Trigger the transfer of the buffer to the audio host */ - lm4549_audio_transfer(s); - } - - return 1; -} - -static int lm4549_post_load(void *opaque, int version_id) -{ - lm4549_state *s = (lm4549_state *)opaque; - uint16_t *regfile = s->regfile; - - /* Re-open a voice with the current sample rate */ - uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate]; - - DPRINTF("post_load freq = %i\n", freq); - DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active); - - struct audsettings as; - as.freq = freq; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 0; - - s->voice = AUD_open_out( - &s->card, - s->voice, - "lm4549.out", - s, - lm4549_audio_out_callback, - &as - ); - - /* Request data */ - if (s->voice_is_active == 1) { - lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice)); - } - - return 0; -} - -void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque) -{ - struct audsettings as; - - /* Store the callback and opaque pointer */ - s->data_req_cb = data_req_cb; - s->opaque = opaque; - - /* Init the registers */ - lm4549_reset(s); - - /* Register an audio card */ - AUD_register_card("lm4549", &s->card); - - /* Open a default voice */ - as.freq = 48000; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 0; - - s->voice = AUD_open_out( - &s->card, - s->voice, - "lm4549.out", - s, - lm4549_audio_out_callback, - &as - ); - - AUD_set_volume_out(s->voice, 0, 255, 255); - - s->voice_is_active = 0; - - /* Reset the input buffer */ - memset(s->buffer, 0x00, sizeof(s->buffer)); - s->buffer_level = 0; - -#if defined(LM4549_DUMP_DAC_INPUT) - fp_dac_input = fopen("lm4549_dac_input.pcm", "wb"); - if (!fp_dac_input) { - hw_error("Unable to open lm4549_dac_input.pcm for writing\n"); - } -#endif -} - -const VMStateDescription vmstate_lm4549_state = { - .name = "lm4549_state", - .version_id = 1, - .minimum_version_id = 1, - .post_load = lm4549_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32(voice_is_active, lm4549_state), - VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128), - VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE), - VMSTATE_UINT32(buffer_level, lm4549_state), - VMSTATE_END_OF_LIST() - } -}; diff --git a/qemu/hw/audio/lm4549.h b/qemu/hw/audio/lm4549.h deleted file mode 100644 index 812a7a444..000000000 --- a/qemu/hw/audio/lm4549.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * LM4549 Audio Codec Interface - * - * Copyright (c) 2011 - * Written by Mathieu Sonet - www.elasticsheep.com - * - * This code is licensed under the GPL. - * - * ***************************************************************** - */ - -#ifndef HW_LM4549_H -#define HW_LM4549_H - -#include "audio/audio.h" - -typedef void (*lm4549_callback)(void *opaque); - -#define LM4549_BUFFER_SIZE (512 * 2) /* 512 16-bit stereo samples */ - - -typedef struct { - QEMUSoundCard card; - SWVoiceOut *voice; - uint32_t voice_is_active; - - uint16_t regfile[128]; - lm4549_callback data_req_cb; - void *opaque; - - uint16_t buffer[LM4549_BUFFER_SIZE]; - uint32_t buffer_level; -} lm4549_state; - -extern const VMStateDescription vmstate_lm4549_state; - - -void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque); -uint32_t lm4549_read(lm4549_state *s, hwaddr offset); -void lm4549_write(lm4549_state *s, hwaddr offset, uint32_t value); -uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right); - -#endif /* #ifndef HW_LM4549_H */ diff --git a/qemu/hw/audio/marvell_88w8618.c b/qemu/hw/audio/marvell_88w8618.c deleted file mode 100644 index a6ca1806b..000000000 --- a/qemu/hw/audio/marvell_88w8618.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Marvell 88w8618 audio emulation extracted from - * Marvell MV88w8618 / Freecom MusicPal emulation. - * - * Copyright (c) 2008 Jan Kiszka - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "audio/audio.h" - -#define MP_AUDIO_SIZE 0x00001000 - -/* Audio register offsets */ -#define MP_AUDIO_PLAYBACK_MODE 0x00 -#define MP_AUDIO_CLOCK_DIV 0x18 -#define MP_AUDIO_IRQ_STATUS 0x20 -#define MP_AUDIO_IRQ_ENABLE 0x24 -#define MP_AUDIO_TX_START_LO 0x28 -#define MP_AUDIO_TX_THRESHOLD 0x2C -#define MP_AUDIO_TX_STATUS 0x38 -#define MP_AUDIO_TX_START_HI 0x40 - -/* Status register and IRQ enable bits */ -#define MP_AUDIO_TX_HALF (1 << 6) -#define MP_AUDIO_TX_FULL (1 << 7) - -/* Playback mode bits */ -#define MP_AUDIO_16BIT_SAMPLE (1 << 0) -#define MP_AUDIO_PLAYBACK_EN (1 << 7) -#define MP_AUDIO_CLOCK_24MHZ (1 << 9) -#define MP_AUDIO_MONO (1 << 14) - -#define TYPE_MV88W8618_AUDIO "mv88w8618_audio" -#define MV88W8618_AUDIO(obj) \ - OBJECT_CHECK(mv88w8618_audio_state, (obj), TYPE_MV88W8618_AUDIO) - -typedef struct mv88w8618_audio_state { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - uint32_t playback_mode; - uint32_t status; - uint32_t irq_enable; - uint32_t phys_buf; - uint32_t target_buffer; - uint32_t threshold; - uint32_t play_pos; - uint32_t last_free; - uint32_t clock_div; - void *wm; -} mv88w8618_audio_state; - -static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in) -{ - mv88w8618_audio_state *s = opaque; - int16_t *codec_buffer; - int8_t buf[4096]; - int8_t *mem_buffer; - int pos, block_size; - - if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) { - return; - } - if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) { - free_out <<= 1; - } - if (!(s->playback_mode & MP_AUDIO_MONO)) { - free_out <<= 1; - } - block_size = s->threshold / 2; - if (free_out - s->last_free < block_size) { - return; - } - if (block_size > 4096) { - return; - } - cpu_physical_memory_read(s->target_buffer + s->play_pos, buf, block_size); - mem_buffer = buf; - if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) { - if (s->playback_mode & MP_AUDIO_MONO) { - codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); - for (pos = 0; pos < block_size; pos += 2) { - *codec_buffer++ = *(int16_t *)mem_buffer; - *codec_buffer++ = *(int16_t *)mem_buffer; - mem_buffer += 2; - } - } else { - memcpy(wm8750_dac_buffer(s->wm, block_size >> 2), - (uint32_t *)mem_buffer, block_size); - } - } else { - if (s->playback_mode & MP_AUDIO_MONO) { - codec_buffer = wm8750_dac_buffer(s->wm, block_size); - for (pos = 0; pos < block_size; pos++) { - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer); - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); - } - } else { - codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); - for (pos = 0; pos < block_size; pos += 2) { - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); - *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++); - } - } - } - wm8750_dac_commit(s->wm); - - s->last_free = free_out - block_size; - - if (s->play_pos == 0) { - s->status |= MP_AUDIO_TX_HALF; - s->play_pos = block_size; - } else { - s->status |= MP_AUDIO_TX_FULL; - s->play_pos = 0; - } - - if (s->status & s->irq_enable) { - qemu_irq_raise(s->irq); - } -} - -static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s) -{ - int rate; - - if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) { - rate = 24576000 / 64; /* 24.576MHz */ - } else { - rate = 11289600 / 64; /* 11.2896MHz */ - } - rate /= ((s->clock_div >> 8) & 0xff) + 1; - - wm8750_set_bclk_in(s->wm, rate); -} - -static uint64_t mv88w8618_audio_read(void *opaque, hwaddr offset, - unsigned size) -{ - mv88w8618_audio_state *s = opaque; - - switch (offset) { - case MP_AUDIO_PLAYBACK_MODE: - return s->playback_mode; - - case MP_AUDIO_CLOCK_DIV: - return s->clock_div; - - case MP_AUDIO_IRQ_STATUS: - return s->status; - - case MP_AUDIO_IRQ_ENABLE: - return s->irq_enable; - - case MP_AUDIO_TX_STATUS: - return s->play_pos >> 2; - - default: - return 0; - } -} - -static void mv88w8618_audio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - mv88w8618_audio_state *s = opaque; - - switch (offset) { - case MP_AUDIO_PLAYBACK_MODE: - if (value & MP_AUDIO_PLAYBACK_EN && - !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) { - s->status = 0; - s->last_free = 0; - s->play_pos = 0; - } - s->playback_mode = value; - mv88w8618_audio_clock_update(s); - break; - - case MP_AUDIO_CLOCK_DIV: - s->clock_div = value; - s->last_free = 0; - s->play_pos = 0; - mv88w8618_audio_clock_update(s); - break; - - case MP_AUDIO_IRQ_STATUS: - s->status &= ~value; - break; - - case MP_AUDIO_IRQ_ENABLE: - s->irq_enable = value; - if (s->status & s->irq_enable) { - qemu_irq_raise(s->irq); - } - break; - - case MP_AUDIO_TX_START_LO: - s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF); - s->target_buffer = s->phys_buf; - s->play_pos = 0; - s->last_free = 0; - break; - - case MP_AUDIO_TX_THRESHOLD: - s->threshold = (value + 1) * 4; - break; - - case MP_AUDIO_TX_START_HI: - s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16); - s->target_buffer = s->phys_buf; - s->play_pos = 0; - s->last_free = 0; - break; - } -} - -static void mv88w8618_audio_reset(DeviceState *d) -{ - mv88w8618_audio_state *s = MV88W8618_AUDIO(d); - - s->playback_mode = 0; - s->status = 0; - s->irq_enable = 0; - s->clock_div = 0; - s->threshold = 0; - s->phys_buf = 0; -} - -static const MemoryRegionOps mv88w8618_audio_ops = { - .read = mv88w8618_audio_read, - .write = mv88w8618_audio_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int mv88w8618_audio_init(SysBusDevice *dev) -{ - mv88w8618_audio_state *s = MV88W8618_AUDIO(dev); - - sysbus_init_irq(dev, &s->irq); - - wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s); - - memory_region_init_io(&s->iomem, OBJECT(s), &mv88w8618_audio_ops, s, - "audio", MP_AUDIO_SIZE); - sysbus_init_mmio(dev, &s->iomem); - - return 0; -} - -static const VMStateDescription mv88w8618_audio_vmsd = { - .name = "mv88w8618_audio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(playback_mode, mv88w8618_audio_state), - VMSTATE_UINT32(status, mv88w8618_audio_state), - VMSTATE_UINT32(irq_enable, mv88w8618_audio_state), - VMSTATE_UINT32(phys_buf, mv88w8618_audio_state), - VMSTATE_UINT32(target_buffer, mv88w8618_audio_state), - VMSTATE_UINT32(threshold, mv88w8618_audio_state), - VMSTATE_UINT32(play_pos, mv88w8618_audio_state), - VMSTATE_UINT32(last_free, mv88w8618_audio_state), - VMSTATE_UINT32(clock_div, mv88w8618_audio_state), - VMSTATE_END_OF_LIST() - } -}; - -static Property mv88w8618_audio_properties[] = { - DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm), - {/* end of list */}, -}; - -static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = mv88w8618_audio_init; - dc->reset = mv88w8618_audio_reset; - dc->vmsd = &mv88w8618_audio_vmsd; - dc->props = mv88w8618_audio_properties; - /* Reason: pointer property "wm8750" */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo mv88w8618_audio_info = { - .name = TYPE_MV88W8618_AUDIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(mv88w8618_audio_state), - .class_init = mv88w8618_audio_class_init, -}; - -static void mv88w8618_register_types(void) -{ - type_register_static(&mv88w8618_audio_info); -} - -type_init(mv88w8618_register_types) diff --git a/qemu/hw/audio/milkymist-ac97.c b/qemu/hw/audio/milkymist-ac97.c deleted file mode 100644 index 6a3b53674..000000000 --- a/qemu/hw/audio/milkymist-ac97.c +++ /dev/null @@ -1,349 +0,0 @@ -/* - * QEMU model of the Milkymist System Controller. - * - * Copyright (c) 2010 Michael Walle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - * - * Specification available at: - * http://www.milkymist.org/socdoc/ac97.pdf - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/sysbus.h" -#include "trace.h" -#include "audio/audio.h" -#include "qemu/error-report.h" - -enum { - R_AC97_CTRL = 0, - R_AC97_ADDR, - R_AC97_DATAOUT, - R_AC97_DATAIN, - R_D_CTRL, - R_D_ADDR, - R_D_REMAINING, - R_RESERVED, - R_U_CTRL, - R_U_ADDR, - R_U_REMAINING, - R_MAX -}; - -enum { - AC97_CTRL_RQEN = (1<<0), - AC97_CTRL_WRITE = (1<<1), -}; - -enum { - CTRL_EN = (1<<0), -}; - -#define TYPE_MILKYMIST_AC97 "milkymist-ac97" -#define MILKYMIST_AC97(obj) \ - OBJECT_CHECK(MilkymistAC97State, (obj), TYPE_MILKYMIST_AC97) - -struct MilkymistAC97State { - SysBusDevice parent_obj; - - MemoryRegion regs_region; - - QEMUSoundCard card; - SWVoiceIn *voice_in; - SWVoiceOut *voice_out; - - uint32_t regs[R_MAX]; - - qemu_irq crrequest_irq; - qemu_irq crreply_irq; - qemu_irq dmar_irq; - qemu_irq dmaw_irq; -}; -typedef struct MilkymistAC97State MilkymistAC97State; - -static void update_voices(MilkymistAC97State *s) -{ - if (s->regs[R_D_CTRL] & CTRL_EN) { - AUD_set_active_out(s->voice_out, 1); - } else { - AUD_set_active_out(s->voice_out, 0); - } - - if (s->regs[R_U_CTRL] & CTRL_EN) { - AUD_set_active_in(s->voice_in, 1); - } else { - AUD_set_active_in(s->voice_in, 0); - } -} - -static uint64_t ac97_read(void *opaque, hwaddr addr, - unsigned size) -{ - MilkymistAC97State *s = opaque; - uint32_t r = 0; - - addr >>= 2; - switch (addr) { - case R_AC97_CTRL: - case R_AC97_ADDR: - case R_AC97_DATAOUT: - case R_AC97_DATAIN: - case R_D_CTRL: - case R_D_ADDR: - case R_D_REMAINING: - case R_U_CTRL: - case R_U_ADDR: - case R_U_REMAINING: - r = s->regs[addr]; - break; - - default: - error_report("milkymist_ac97: read access to unknown register 0x" - TARGET_FMT_plx, addr << 2); - break; - } - - trace_milkymist_ac97_memory_read(addr << 2, r); - - return r; -} - -static void ac97_write(void *opaque, hwaddr addr, uint64_t value, - unsigned size) -{ - MilkymistAC97State *s = opaque; - - trace_milkymist_ac97_memory_write(addr, value); - - addr >>= 2; - switch (addr) { - case R_AC97_CTRL: - /* always raise an IRQ according to the direction */ - if (value & AC97_CTRL_RQEN) { - if (value & AC97_CTRL_WRITE) { - trace_milkymist_ac97_pulse_irq_crrequest(); - qemu_irq_pulse(s->crrequest_irq); - } else { - trace_milkymist_ac97_pulse_irq_crreply(); - qemu_irq_pulse(s->crreply_irq); - } - } - - /* RQEN is self clearing */ - s->regs[addr] = value & ~AC97_CTRL_RQEN; - break; - case R_D_CTRL: - case R_U_CTRL: - s->regs[addr] = value; - update_voices(s); - break; - case R_AC97_ADDR: - case R_AC97_DATAOUT: - case R_AC97_DATAIN: - case R_D_ADDR: - case R_D_REMAINING: - case R_U_ADDR: - case R_U_REMAINING: - s->regs[addr] = value; - break; - - default: - error_report("milkymist_ac97: write access to unknown register 0x" - TARGET_FMT_plx, addr); - break; - } - -} - -static const MemoryRegionOps ac97_mmio_ops = { - .read = ac97_read, - .write = ac97_write, - .valid = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ac97_in_cb(void *opaque, int avail_b) -{ - MilkymistAC97State *s = opaque; - uint8_t buf[4096]; - uint32_t remaining = s->regs[R_U_REMAINING]; - int temp = audio_MIN(remaining, avail_b); - uint32_t addr = s->regs[R_U_ADDR]; - int transferred = 0; - - trace_milkymist_ac97_in_cb(avail_b, remaining); - - /* prevent from raising an IRQ */ - if (temp == 0) { - return; - } - - while (temp) { - int acquired, to_copy; - - to_copy = audio_MIN(temp, sizeof(buf)); - acquired = AUD_read(s->voice_in, buf, to_copy); - if (!acquired) { - break; - } - - cpu_physical_memory_write(addr, buf, acquired); - - temp -= acquired; - addr += acquired; - transferred += acquired; - } - - trace_milkymist_ac97_in_cb_transferred(transferred); - - s->regs[R_U_ADDR] = addr; - s->regs[R_U_REMAINING] -= transferred; - - if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) { - trace_milkymist_ac97_pulse_irq_dmaw(); - qemu_irq_pulse(s->dmaw_irq); - } -} - -static void ac97_out_cb(void *opaque, int free_b) -{ - MilkymistAC97State *s = opaque; - uint8_t buf[4096]; - uint32_t remaining = s->regs[R_D_REMAINING]; - int temp = audio_MIN(remaining, free_b); - uint32_t addr = s->regs[R_D_ADDR]; - int transferred = 0; - - trace_milkymist_ac97_out_cb(free_b, remaining); - - /* prevent from raising an IRQ */ - if (temp == 0) { - return; - } - - while (temp) { - int copied, to_copy; - - to_copy = audio_MIN(temp, sizeof(buf)); - cpu_physical_memory_read(addr, buf, to_copy); - copied = AUD_write(s->voice_out, buf, to_copy); - if (!copied) { - break; - } - temp -= copied; - addr += copied; - transferred += copied; - } - - trace_milkymist_ac97_out_cb_transferred(transferred); - - s->regs[R_D_ADDR] = addr; - s->regs[R_D_REMAINING] -= transferred; - - if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) { - trace_milkymist_ac97_pulse_irq_dmar(); - qemu_irq_pulse(s->dmar_irq); - } -} - -static void milkymist_ac97_reset(DeviceState *d) -{ - MilkymistAC97State *s = MILKYMIST_AC97(d); - int i; - - for (i = 0; i < R_MAX; i++) { - s->regs[i] = 0; - } - - AUD_set_active_in(s->voice_in, 0); - AUD_set_active_out(s->voice_out, 0); -} - -static int ac97_post_load(void *opaque, int version_id) -{ - MilkymistAC97State *s = opaque; - - update_voices(s); - - return 0; -} - -static int milkymist_ac97_init(SysBusDevice *dev) -{ - MilkymistAC97State *s = MILKYMIST_AC97(dev); - - struct audsettings as; - sysbus_init_irq(dev, &s->crrequest_irq); - sysbus_init_irq(dev, &s->crreply_irq); - sysbus_init_irq(dev, &s->dmar_irq); - sysbus_init_irq(dev, &s->dmaw_irq); - - AUD_register_card("Milkymist AC'97", &s->card); - - as.freq = 48000; - as.nchannels = 2; - as.fmt = AUD_FMT_S16; - as.endianness = 1; - - s->voice_in = AUD_open_in(&s->card, s->voice_in, - "mm_ac97.in", s, ac97_in_cb, &as); - s->voice_out = AUD_open_out(&s->card, s->voice_out, - "mm_ac97.out", s, ac97_out_cb, &as); - - memory_region_init_io(&s->regs_region, OBJECT(s), &ac97_mmio_ops, s, - "milkymist-ac97", R_MAX * 4); - sysbus_init_mmio(dev, &s->regs_region); - - return 0; -} - -static const VMStateDescription vmstate_milkymist_ac97 = { - .name = "milkymist-ac97", - .version_id = 1, - .minimum_version_id = 1, - .post_load = ac97_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX), - VMSTATE_END_OF_LIST() - } -}; - -static void milkymist_ac97_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = milkymist_ac97_init; - dc->reset = milkymist_ac97_reset; - dc->vmsd = &vmstate_milkymist_ac97; -} - -static const TypeInfo milkymist_ac97_info = { - .name = TYPE_MILKYMIST_AC97, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(MilkymistAC97State), - .class_init = milkymist_ac97_class_init, -}; - -static void milkymist_ac97_register_types(void) -{ - type_register_static(&milkymist_ac97_info); -} - -type_init(milkymist_ac97_register_types) diff --git a/qemu/hw/audio/pcspk.c b/qemu/hw/audio/pcspk.c deleted file mode 100644 index f9afc8eda..000000000 --- a/qemu/hw/audio/pcspk.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * QEMU PC speaker emulation - * - * Copyright (c) 2006 Joachim Henke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i386/pc.h" -#include "hw/isa/isa.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "qemu/timer.h" -#include "hw/timer/i8254.h" -#include "hw/audio/pcspk.h" - -#define PCSPK_BUF_LEN 1792 -#define PCSPK_SAMPLE_RATE 32000 -#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1) -#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ) - -#define PC_SPEAKER(obj) OBJECT_CHECK(PCSpkState, (obj), TYPE_PC_SPEAKER) - -typedef struct { - ISADevice parent_obj; - - MemoryRegion ioport; - uint32_t iobase; - uint8_t sample_buf[PCSPK_BUF_LEN]; - QEMUSoundCard card; - SWVoiceOut *voice; - void *pit; - unsigned int pit_count; - unsigned int samples; - unsigned int play_pos; - int data_on; - int dummy_refresh_clock; -} PCSpkState; - -static const char *s_spk = "pcspk"; -static PCSpkState *pcspk_state; - -static inline void generate_samples(PCSpkState *s) -{ - unsigned int i; - - if (s->pit_count) { - const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count; - const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m; - - /* multiple of wavelength for gapless looping */ - s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1; - for (i = 0; i < s->samples; ++i) - s->sample_buf[i] = (64 & (n * i >> 25)) - 32; - } else { - s->samples = PCSPK_BUF_LEN; - for (i = 0; i < PCSPK_BUF_LEN; ++i) - s->sample_buf[i] = 128; /* silence */ - } -} - -static void pcspk_callback(void *opaque, int free) -{ - PCSpkState *s = opaque; - PITChannelInfo ch; - unsigned int n; - - pit_get_channel_info(s->pit, 2, &ch); - - if (ch.mode != 3) { - return; - } - - n = ch.initial_count; - /* avoid frequencies that are not reproducible with sample rate */ - if (n < PCSPK_MIN_COUNT) - n = 0; - - if (s->pit_count != n) { - s->pit_count = n; - s->play_pos = 0; - generate_samples(s); - } - - while (free > 0) { - n = audio_MIN(s->samples - s->play_pos, (unsigned int)free); - n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n); - if (!n) - break; - s->play_pos = (s->play_pos + n) % s->samples; - free -= n; - } -} - -static int pcspk_audio_init(ISABus *bus) -{ - PCSpkState *s = pcspk_state; - struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; - - AUD_register_card(s_spk, &s->card); - - s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as); - if (!s->voice) { - AUD_log(s_spk, "Could not open voice\n"); - return -1; - } - - return 0; -} - -static uint64_t pcspk_io_read(void *opaque, hwaddr addr, - unsigned size) -{ - PCSpkState *s = opaque; - PITChannelInfo ch; - - pit_get_channel_info(s->pit, 2, &ch); - - s->dummy_refresh_clock ^= (1 << 4); - - return ch.gate | (s->data_on << 1) | s->dummy_refresh_clock | - (ch.out << 5); -} - -static void pcspk_io_write(void *opaque, hwaddr addr, uint64_t val, - unsigned size) -{ - PCSpkState *s = opaque; - const int gate = val & 1; - - s->data_on = (val >> 1) & 1; - pit_set_gate(s->pit, 2, gate); - if (s->voice) { - if (gate) /* restart */ - s->play_pos = 0; - AUD_set_active_out(s->voice, gate & s->data_on); - } -} - -static const MemoryRegionOps pcspk_io_ops = { - .read = pcspk_io_read, - .write = pcspk_io_write, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, -}; - -static void pcspk_initfn(Object *obj) -{ - PCSpkState *s = PC_SPEAKER(obj); - - memory_region_init_io(&s->ioport, OBJECT(s), &pcspk_io_ops, s, "pcspk", 1); -} - -static void pcspk_realizefn(DeviceState *dev, Error **errp) -{ - ISADevice *isadev = ISA_DEVICE(dev); - PCSpkState *s = PC_SPEAKER(dev); - - isa_register_ioport(isadev, &s->ioport, s->iobase); - - pcspk_state = s; -} - -static Property pcspk_properties[] = { - DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1), - DEFINE_PROP_PTR("pit", PCSpkState, pit), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pcspk_class_initfn(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = pcspk_realizefn; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->props = pcspk_properties; - /* Reason: pointer property "pit", realize sets global pcspk_state */ - dc->cannot_instantiate_with_device_add_yet = true; -} - -static const TypeInfo pcspk_info = { - .name = TYPE_PC_SPEAKER, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof(PCSpkState), - .instance_init = pcspk_initfn, - .class_init = pcspk_class_initfn, -}; - -static void pcspk_register(void) -{ - type_register_static(&pcspk_info); - isa_register_soundhw("pcspk", "PC speaker", pcspk_audio_init); -} -type_init(pcspk_register) diff --git a/qemu/hw/audio/pl041.c b/qemu/hw/audio/pl041.c deleted file mode 100644 index 4717bc9b9..000000000 --- a/qemu/hw/audio/pl041.c +++ /dev/null @@ -1,650 +0,0 @@ -/* - * Arm PrimeCell PL041 Advanced Audio Codec Interface - * - * Copyright (c) 2011 - * Written by Mathieu Sonet - www.elasticsheep.com - * - * This code is licensed under the GPL. - * - * ***************************************************************** - * - * This driver emulates the ARM AACI interface - * connected to a LM4549 codec. - * - * Limitations: - * - Supports only a playback on one channel (Versatile/Vexpress) - * - Supports only one TX FIFO in compact-mode or non-compact mode. - * - Supports playback of 12, 16, 18 and 20 bits samples. - * - Record is not supported. - * - The PL041 is hardwired to a LM4549 codec. - * - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" - -#include "pl041.h" -#include "lm4549.h" - -#if 0 -#define PL041_DEBUG_LEVEL 1 -#endif - -#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1) -#define DBG_L1(fmt, ...) \ -do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DBG_L1(fmt, ...) \ -do { } while (0) -#endif - -#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2) -#define DBG_L2(fmt, ...) \ -do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0) -#else -#define DBG_L2(fmt, ...) \ -do { } while (0) -#endif - - -#define MAX_FIFO_DEPTH (1024) -#define DEFAULT_FIFO_DEPTH (8) - -#define SLOT1_RW (1 << 19) - -/* This FIFO only stores 20-bit samples on 32-bit words. - So its level is independent of the selected mode */ -typedef struct { - uint32_t level; - uint32_t data[MAX_FIFO_DEPTH]; -} pl041_fifo; - -typedef struct { - pl041_fifo tx_fifo; - uint8_t tx_enabled; - uint8_t tx_compact_mode; - uint8_t tx_sample_size; - - pl041_fifo rx_fifo; - uint8_t rx_enabled; - uint8_t rx_compact_mode; - uint8_t rx_sample_size; -} pl041_channel; - -#define TYPE_PL041 "pl041" -#define PL041(obj) OBJECT_CHECK(PL041State, (obj), TYPE_PL041) - -typedef struct PL041State { - SysBusDevice parent_obj; - - MemoryRegion iomem; - qemu_irq irq; - - uint32_t fifo_depth; /* FIFO depth in non-compact mode */ - - pl041_regfile regs; - pl041_channel fifo1; - lm4549_state codec; -} PL041State; - - -static const unsigned char pl041_default_id[8] = { - 0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 -}; - -#if defined(PL041_DEBUG_LEVEL) -#define REGISTER(name, offset) #name, -static const char *pl041_regs_name[] = { - #include "pl041.hx" -}; -#undef REGISTER -#endif - - -#if defined(PL041_DEBUG_LEVEL) -static const char *get_reg_name(hwaddr offset) -{ - if (offset <= PL041_dr1_7) { - return pl041_regs_name[offset >> 2]; - } - - return "unknown"; -} -#endif - -static uint8_t pl041_compute_periphid3(PL041State *s) -{ - uint8_t id3 = 1; /* One channel */ - - /* Add the fifo depth information */ - switch (s->fifo_depth) { - case 8: - id3 |= 0 << 3; - break; - case 32: - id3 |= 1 << 3; - break; - case 64: - id3 |= 2 << 3; - break; - case 128: - id3 |= 3 << 3; - break; - case 256: - id3 |= 4 << 3; - break; - case 512: - id3 |= 5 << 3; - break; - case 1024: - id3 |= 6 << 3; - break; - case 2048: - id3 |= 7 << 3; - break; - } - - return id3; -} - -static void pl041_reset(PL041State *s) -{ - DBG_L1("pl041_reset\n"); - - memset(&s->regs, 0x00, sizeof(pl041_regfile)); - - s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY; - s->regs.sr1 = TXFE | RXFE | TXHE; - s->regs.isr1 = 0; - - memset(&s->fifo1, 0x00, sizeof(s->fifo1)); -} - - -static void pl041_fifo1_write(PL041State *s, uint32_t value) -{ - pl041_channel *channel = &s->fifo1; - pl041_fifo *fifo = &s->fifo1.tx_fifo; - - /* Push the value in the FIFO */ - if (channel->tx_compact_mode == 0) { - /* Non-compact mode */ - - if (fifo->level < s->fifo_depth) { - /* Pad the value with 0 to obtain a 20-bit sample */ - switch (channel->tx_sample_size) { - case 12: - value = (value << 8) & 0xFFFFF; - break; - case 16: - value = (value << 4) & 0xFFFFF; - break; - case 18: - value = (value << 2) & 0xFFFFF; - break; - case 20: - default: - break; - } - - /* Store the sample in the FIFO */ - fifo->data[fifo->level++] = value; - } -#if defined(PL041_DEBUG_LEVEL) - else { - DBG_L1("fifo1 write: overrun\n"); - } -#endif - } else { - /* Compact mode */ - - if ((fifo->level + 2) < s->fifo_depth) { - uint32_t i = 0; - uint32_t sample = 0; - - for (i = 0; i < 2; i++) { - sample = value & 0xFFFF; - value = value >> 16; - - /* Pad each sample with 0 to obtain a 20-bit sample */ - switch (channel->tx_sample_size) { - case 12: - sample = sample << 8; - break; - case 16: - default: - sample = sample << 4; - break; - } - - /* Store the sample in the FIFO */ - fifo->data[fifo->level++] = sample; - } - } -#if defined(PL041_DEBUG_LEVEL) - else { - DBG_L1("fifo1 write: overrun\n"); - } -#endif - } - - /* Update the status register */ - if (fifo->level > 0) { - s->regs.sr1 &= ~(TXUNDERRUN | TXFE); - } - - if (fifo->level >= (s->fifo_depth / 2)) { - s->regs.sr1 &= ~TXHE; - } - - if (fifo->level >= s->fifo_depth) { - s->regs.sr1 |= TXFF; - } - - DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1); -} - -static void pl041_fifo1_transmit(PL041State *s) -{ - pl041_channel *channel = &s->fifo1; - pl041_fifo *fifo = &s->fifo1.tx_fifo; - uint32_t slots = s->regs.txcr1 & TXSLOT_MASK; - uint32_t written_samples; - - /* Check if FIFO1 transmit is enabled */ - if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) { - if (fifo->level >= (s->fifo_depth / 2)) { - int i; - - DBG_L1("Transfer FIFO level = %i\n", fifo->level); - - /* Try to transfer the whole FIFO */ - for (i = 0; i < (fifo->level / 2); i++) { - uint32_t left = fifo->data[i * 2]; - uint32_t right = fifo->data[i * 2 + 1]; - - /* Transmit two 20-bit samples to the codec */ - if (lm4549_write_samples(&s->codec, left, right) == 0) { - DBG_L1("Codec buffer full\n"); - break; - } - } - - written_samples = i * 2; - if (written_samples > 0) { - /* Update the FIFO level */ - fifo->level -= written_samples; - - /* Move back the pending samples to the start of the FIFO */ - for (i = 0; i < fifo->level; i++) { - fifo->data[i] = fifo->data[written_samples + i]; - } - - /* Update the status register */ - s->regs.sr1 &= ~TXFF; - - if (fifo->level <= (s->fifo_depth / 2)) { - s->regs.sr1 |= TXHE; - } - - if (fifo->level == 0) { - s->regs.sr1 |= TXFE | TXUNDERRUN; - DBG_L1("Empty FIFO\n"); - } - } - } - } -} - -static void pl041_isr1_update(PL041State *s) -{ - /* Update ISR1 */ - if (s->regs.sr1 & TXUNDERRUN) { - s->regs.isr1 |= URINTR; - } else { - s->regs.isr1 &= ~URINTR; - } - - if (s->regs.sr1 & TXHE) { - s->regs.isr1 |= TXINTR; - } else { - s->regs.isr1 &= ~TXINTR; - } - - if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) { - s->regs.isr1 |= TXCINTR; - } else { - s->regs.isr1 &= ~TXCINTR; - } - - /* Update the irq state */ - qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0); - DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n", - s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1); -} - -static void pl041_request_data(void *opaque) -{ - PL041State *s = (PL041State *)opaque; - - /* Trigger pending transfers */ - pl041_fifo1_transmit(s); - pl041_isr1_update(s); -} - -static uint64_t pl041_read(void *opaque, hwaddr offset, - unsigned size) -{ - PL041State *s = (PL041State *)opaque; - int value; - - if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) { - if (offset == PL041_periphid3) { - value = pl041_compute_periphid3(s); - } else { - value = pl041_default_id[(offset - PL041_periphid0) >> 2]; - } - - DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value); - return value; - } else if (offset <= PL041_dr4_7) { - value = *((uint32_t *)&s->regs + (offset >> 2)); - } else { - DBG_L1("pl041_read: Reserved offset %x\n", (int)offset); - return 0; - } - - switch (offset) { - case PL041_allints: - value = s->regs.isr1 & 0x7F; - break; - } - - DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset, - get_reg_name(offset), value); - - return value; -} - -static void pl041_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) -{ - PL041State *s = (PL041State *)opaque; - uint16_t control, data; - uint32_t result; - - DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset, - get_reg_name(offset), (unsigned int)value); - - /* Write the register */ - if (offset <= PL041_dr4_7) { - *((uint32_t *)&s->regs + (offset >> 2)) = value; - } else { - DBG_L1("pl041_write: Reserved offset %x\n", (int)offset); - return; - } - - /* Execute the actions */ - switch (offset) { - case PL041_txcr1: - { - pl041_channel *channel = &s->fifo1; - - uint32_t txen = s->regs.txcr1 & TXEN; - uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT; - uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0; -#if defined(PL041_DEBUG_LEVEL) - uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT; - uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0; -#endif - - DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i " - "txfen = %i\n", txen, slots, tsize, compact_mode, txfen); - - channel->tx_enabled = txen; - channel->tx_compact_mode = compact_mode; - - switch (tsize) { - case 0: - channel->tx_sample_size = 16; - break; - case 1: - channel->tx_sample_size = 18; - break; - case 2: - channel->tx_sample_size = 20; - break; - case 3: - channel->tx_sample_size = 12; - break; - } - - DBG_L1("TX enabled = %i\n", channel->tx_enabled); - DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode); - DBG_L1("TX sample width = %i\n", channel->tx_sample_size); - - /* Check if compact mode is allowed with selected tsize */ - if (channel->tx_compact_mode == 1) { - if ((channel->tx_sample_size == 18) || - (channel->tx_sample_size == 20)) { - channel->tx_compact_mode = 0; - DBG_L1("Compact mode not allowed with 18/20-bit sample size\n"); - } - } - - break; - } - case PL041_sl1tx: - s->regs.slfr &= ~SL1TXEMPTY; - - control = (s->regs.sl1tx >> 12) & 0x7F; - data = (s->regs.sl2tx >> 4) & 0xFFFF; - - if ((s->regs.sl1tx & SLOT1_RW) == 0) { - /* Write operation */ - lm4549_write(&s->codec, control, data); - } else { - /* Read operation */ - result = lm4549_read(&s->codec, control); - - /* Store the returned value */ - s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW; - s->regs.sl2rx = result << 4; - - s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY); - s->regs.slfr |= SL1RXVALID | SL2RXVALID; - } - break; - - case PL041_sl2tx: - s->regs.sl2tx = value; - s->regs.slfr &= ~SL2TXEMPTY; - break; - - case PL041_intclr: - DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n", - s->regs.intclr, s->regs.isr1); - - if (s->regs.intclr & TXUEC1) { - s->regs.sr1 &= ~TXUNDERRUN; - } - break; - - case PL041_maincr: - { -#if defined(PL041_DEBUG_LEVEL) - char debug[] = " AACIFE SL1RXEN SL1TXEN"; - if (!(value & AACIFE)) { - debug[0] = '!'; - } - if (!(value & SL1RXEN)) { - debug[8] = '!'; - } - if (!(value & SL1TXEN)) { - debug[17] = '!'; - } - DBG_L1("%s\n", debug); -#endif - - if ((s->regs.maincr & AACIFE) == 0) { - pl041_reset(s); - } - break; - } - - case PL041_dr1_0: - case PL041_dr1_1: - case PL041_dr1_2: - case PL041_dr1_3: - pl041_fifo1_write(s, value); - break; - } - - /* Transmit the FIFO content */ - pl041_fifo1_transmit(s); - - /* Update the ISR1 register */ - pl041_isr1_update(s); -} - -static void pl041_device_reset(DeviceState *d) -{ - PL041State *s = PL041(d); - - pl041_reset(s); -} - -static const MemoryRegionOps pl041_ops = { - .read = pl041_read, - .write = pl041_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static int pl041_init(SysBusDevice *dev) -{ - PL041State *s = PL041(dev); - - DBG_L1("pl041_init 0x%08x\n", (uint32_t)s); - - /* Check the device properties */ - switch (s->fifo_depth) { - case 8: - case 32: - case 64: - case 128: - case 256: - case 512: - case 1024: - case 2048: - break; - case 16: - default: - /* NC FIFO depth of 16 is not allowed because its id bits in - AACIPERIPHID3 overlap with the id for the default NC FIFO depth */ - qemu_log_mask(LOG_UNIMP, - "pl041: unsupported non-compact fifo depth [%i]\n", - s->fifo_depth); - return -1; - } - - /* Connect the device to the sysbus */ - memory_region_init_io(&s->iomem, OBJECT(s), &pl041_ops, s, "pl041", 0x1000); - sysbus_init_mmio(dev, &s->iomem); - sysbus_init_irq(dev, &s->irq); - - /* Init the codec */ - lm4549_init(&s->codec, &pl041_request_data, (void *)s); - - return 0; -} - -static const VMStateDescription vmstate_pl041_regfile = { - .name = "pl041_regfile", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { -#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile), - #include "pl041.hx" -#undef REGISTER - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pl041_fifo = { - .name = "pl041_fifo", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(level, pl041_fifo), - VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pl041_channel = { - .name = "pl041_channel", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_STRUCT(tx_fifo, pl041_channel, 0, - vmstate_pl041_fifo, pl041_fifo), - VMSTATE_UINT8(tx_enabled, pl041_channel), - VMSTATE_UINT8(tx_compact_mode, pl041_channel), - VMSTATE_UINT8(tx_sample_size, pl041_channel), - VMSTATE_STRUCT(rx_fifo, pl041_channel, 0, - vmstate_pl041_fifo, pl041_fifo), - VMSTATE_UINT8(rx_enabled, pl041_channel), - VMSTATE_UINT8(rx_compact_mode, pl041_channel), - VMSTATE_UINT8(rx_sample_size, pl041_channel), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_pl041 = { - .name = "pl041", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(fifo_depth, PL041State), - VMSTATE_STRUCT(regs, PL041State, 0, - vmstate_pl041_regfile, pl041_regfile), - VMSTATE_STRUCT(fifo1, PL041State, 0, - vmstate_pl041_channel, pl041_channel), - VMSTATE_STRUCT(codec, PL041State, 0, - vmstate_lm4549_state, lm4549_state), - VMSTATE_END_OF_LIST() - } -}; - -static Property pl041_device_properties[] = { - /* Non-compact FIFO depth property */ - DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth, - DEFAULT_FIFO_DEPTH), - DEFINE_PROP_END_OF_LIST(), -}; - -static void pl041_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = pl041_init; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->reset = pl041_device_reset; - dc->vmsd = &vmstate_pl041; - dc->props = pl041_device_properties; -} - -static const TypeInfo pl041_device_info = { - .name = TYPE_PL041, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(PL041State), - .class_init = pl041_device_class_init, -}; - -static void pl041_register_types(void) -{ - type_register_static(&pl041_device_info); -} - -type_init(pl041_register_types) diff --git a/qemu/hw/audio/pl041.h b/qemu/hw/audio/pl041.h deleted file mode 100644 index 427ab6d6f..000000000 --- a/qemu/hw/audio/pl041.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Arm PrimeCell PL041 Advanced Audio Codec Interface - * - * Copyright (c) 2011 - * Written by Mathieu Sonet - www.elasticsheep.com - * - * This code is licensed under the GPL. - * - * ***************************************************************** - */ - -#ifndef HW_PL041_H -#define HW_PL041_H - -/* Register file */ -#define REGISTER(name, offset) uint32_t name; -typedef struct { - #include "pl041.hx" -} pl041_regfile; -#undef REGISTER - -/* Register addresses */ -#define REGISTER(name, offset) PL041_##name = offset, -enum { - #include "pl041.hx" - - PL041_periphid0 = 0xFE0, - PL041_periphid1 = 0xFE4, - PL041_periphid2 = 0xFE8, - PL041_periphid3 = 0xFEC, - PL041_pcellid0 = 0xFF0, - PL041_pcellid1 = 0xFF4, - PL041_pcellid2 = 0xFF8, - PL041_pcellid3 = 0xFFC, -}; -#undef REGISTER - -/* Register bits */ - -/* IEx */ -#define TXCIE (1 << 0) -#define RXTIE (1 << 1) -#define TXIE (1 << 2) -#define RXIE (1 << 3) -#define RXOIE (1 << 4) -#define TXUIE (1 << 5) -#define RXTOIE (1 << 6) - -/* TXCRx */ -#define TXEN (1 << 0) -#define TXSLOT1 (1 << 1) -#define TXSLOT2 (1 << 2) -#define TXSLOT3 (1 << 3) -#define TXSLOT4 (1 << 4) -#define TXCOMPACT (1 << 15) -#define TXFEN (1 << 16) - -#define TXSLOT_MASK_BIT (1) -#define TXSLOT_MASK (0xFFF << TXSLOT_MASK_BIT) - -#define TSIZE_MASK_BIT (13) -#define TSIZE_MASK (0x3 << TSIZE_MASK_BIT) - -#define TSIZE_16BITS (0x0 << TSIZE_MASK_BIT) -#define TSIZE_18BITS (0x1 << TSIZE_MASK_BIT) -#define TSIZE_20BITS (0x2 << TSIZE_MASK_BIT) -#define TSIZE_12BITS (0x3 << TSIZE_MASK_BIT) - -/* SRx */ -#define RXFE (1 << 0) -#define TXFE (1 << 1) -#define RXHF (1 << 2) -#define TXHE (1 << 3) -#define RXFF (1 << 4) -#define TXFF (1 << 5) -#define RXBUSY (1 << 6) -#define TXBUSY (1 << 7) -#define RXOVERRUN (1 << 8) -#define TXUNDERRUN (1 << 9) -#define RXTIMEOUT (1 << 10) -#define RXTOFE (1 << 11) - -/* ISRx */ -#define TXCINTR (1 << 0) -#define RXTOINTR (1 << 1) -#define TXINTR (1 << 2) -#define RXINTR (1 << 3) -#define ORINTR (1 << 4) -#define URINTR (1 << 5) -#define RXTOFEINTR (1 << 6) - -/* SLFR */ -#define SL1RXBUSY (1 << 0) -#define SL1TXBUSY (1 << 1) -#define SL2RXBUSY (1 << 2) -#define SL2TXBUSY (1 << 3) -#define SL12RXBUSY (1 << 4) -#define SL12TXBUSY (1 << 5) -#define SL1RXVALID (1 << 6) -#define SL1TXEMPTY (1 << 7) -#define SL2RXVALID (1 << 8) -#define SL2TXEMPTY (1 << 9) -#define SL12RXVALID (1 << 10) -#define SL12TXEMPTY (1 << 11) -#define RAWGPIOINT (1 << 12) -#define RWIS (1 << 13) - -/* MAINCR */ -#define AACIFE (1 << 0) -#define LOOPBACK (1 << 1) -#define LOWPOWER (1 << 2) -#define SL1RXEN (1 << 3) -#define SL1TXEN (1 << 4) -#define SL2RXEN (1 << 5) -#define SL2TXEN (1 << 6) -#define SL12RXEN (1 << 7) -#define SL12TXEN (1 << 8) -#define DMAENABLE (1 << 9) - -/* INTCLR */ -#define WISC (1 << 0) -#define RXOEC1 (1 << 1) -#define RXOEC2 (1 << 2) -#define RXOEC3 (1 << 3) -#define RXOEC4 (1 << 4) -#define TXUEC1 (1 << 5) -#define TXUEC2 (1 << 6) -#define TXUEC3 (1 << 7) -#define TXUEC4 (1 << 8) -#define RXTOFEC1 (1 << 9) -#define RXTOFEC2 (1 << 10) -#define RXTOFEC3 (1 << 11) -#define RXTOFEC4 (1 << 12) - -#endif /* #ifndef HW_PL041_H */ diff --git a/qemu/hw/audio/pl041.hx b/qemu/hw/audio/pl041.hx deleted file mode 100644 index dd7188cbc..000000000 --- a/qemu/hw/audio/pl041.hx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Arm PrimeCell PL041 Advanced Audio Codec Interface - * - * Copyright (c) 2011 - * Written by Mathieu Sonet - www.elasticsheep.com - * - * This code is licensed under the GPL. - * - * ***************************************************************** - */ - -/* PL041 register file description */ - -REGISTER( rxcr1, 0x00 ) -REGISTER( txcr1, 0x04 ) -REGISTER( sr1, 0x08 ) -REGISTER( isr1, 0x0C ) -REGISTER( ie1, 0x10 ) -REGISTER( rxcr2, 0x14 ) -REGISTER( txcr2, 0x18 ) -REGISTER( sr2, 0x1C ) -REGISTER( isr2, 0x20 ) -REGISTER( ie2, 0x24 ) -REGISTER( rxcr3, 0x28 ) -REGISTER( txcr3, 0x2C ) -REGISTER( sr3, 0x30 ) -REGISTER( isr3, 0x34 ) -REGISTER( ie3, 0x38 ) -REGISTER( rxcr4, 0x3C ) -REGISTER( txcr4, 0x40 ) -REGISTER( sr4, 0x44 ) -REGISTER( isr4, 0x48 ) -REGISTER( ie4, 0x4C ) -REGISTER( sl1rx, 0x50 ) -REGISTER( sl1tx, 0x54 ) -REGISTER( sl2rx, 0x58 ) -REGISTER( sl2tx, 0x5C ) -REGISTER( sl12rx, 0x60 ) -REGISTER( sl12tx, 0x64 ) -REGISTER( slfr, 0x68 ) -REGISTER( slistat, 0x6C ) -REGISTER( slien, 0x70 ) -REGISTER( intclr, 0x74 ) -REGISTER( maincr, 0x78 ) -REGISTER( reset, 0x7C ) -REGISTER( sync, 0x80 ) -REGISTER( allints, 0x84 ) -REGISTER( mainfr, 0x88 ) -REGISTER( unused, 0x8C ) -REGISTER( dr1_0, 0x90 ) -REGISTER( dr1_1, 0x94 ) -REGISTER( dr1_2, 0x98 ) -REGISTER( dr1_3, 0x9C ) -REGISTER( dr1_4, 0xA0 ) -REGISTER( dr1_5, 0xA4 ) -REGISTER( dr1_6, 0xA8 ) -REGISTER( dr1_7, 0xAC ) -REGISTER( dr2_0, 0xB0 ) -REGISTER( dr2_1, 0xB4 ) -REGISTER( dr2_2, 0xB8 ) -REGISTER( dr2_3, 0xBC ) -REGISTER( dr2_4, 0xC0 ) -REGISTER( dr2_5, 0xC4 ) -REGISTER( dr2_6, 0xC8 ) -REGISTER( dr2_7, 0xCC ) -REGISTER( dr3_0, 0xD0 ) -REGISTER( dr3_1, 0xD4 ) -REGISTER( dr3_2, 0xD8 ) -REGISTER( dr3_3, 0xDC ) -REGISTER( dr3_4, 0xE0 ) -REGISTER( dr3_5, 0xE4 ) -REGISTER( dr3_6, 0xE8 ) -REGISTER( dr3_7, 0xEC ) -REGISTER( dr4_0, 0xF0 ) -REGISTER( dr4_1, 0xF4 ) -REGISTER( dr4_2, 0xF8 ) -REGISTER( dr4_3, 0xFC ) -REGISTER( dr4_4, 0x100 ) -REGISTER( dr4_5, 0x104 ) -REGISTER( dr4_6, 0x108 ) -REGISTER( dr4_7, 0x10C ) diff --git a/qemu/hw/audio/sb16.c b/qemu/hw/audio/sb16.c deleted file mode 100644 index 3a4a57ac3..000000000 --- a/qemu/hw/audio/sb16.c +++ /dev/null @@ -1,1436 +0,0 @@ -/* - * QEMU Soundblaster 16 emulation - * - * Copyright (c) 2003-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/audio/audio.h" -#include "audio/audio.h" -#include "hw/isa/isa.h" -#include "hw/qdev.h" -#include "qemu/timer.h" -#include "qemu/host-utils.h" - -#define dolog(...) AUD_log ("sb16", __VA_ARGS__) - -/* #define DEBUG */ -/* #define DEBUG_SB16_MOST */ - -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif - -static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; - -#define TYPE_SB16 "sb16" -#define SB16(obj) OBJECT_CHECK (SB16State, (obj), TYPE_SB16) - -typedef struct SB16State { - ISADevice parent_obj; - - QEMUSoundCard card; - qemu_irq pic; - uint32_t irq; - uint32_t dma; - uint32_t hdma; - uint32_t port; - uint32_t ver; - IsaDma *isa_dma; - IsaDma *isa_hdma; - - int in_index; - int out_data_len; - int fmt_stereo; - int fmt_signed; - int fmt_bits; - audfmt_e fmt; - int dma_auto; - int block_size; - int fifo; - int freq; - int time_const; - int speaker; - int needed_bytes; - int cmd; - int use_hdma; - int highspeed; - int can_write; - - int v2x6; - - uint8_t csp_param; - uint8_t csp_value; - uint8_t csp_mode; - uint8_t csp_regs[256]; - uint8_t csp_index; - uint8_t csp_reg83[4]; - int csp_reg83r; - int csp_reg83w; - - uint8_t in2_data[10]; - uint8_t out_data[50]; - uint8_t test_reg; - uint8_t last_read_byte; - int nzero; - - int left_till_irq; - - int dma_running; - int bytes_per_second; - int align; - int audio_free; - SWVoiceOut *voice; - - QEMUTimer *aux_ts; - /* mixer state */ - int mixer_nreg; - uint8_t mixer_regs[256]; -} SB16State; - -static void SB_audio_callback (void *opaque, int free); - -static int magic_of_irq (int irq) -{ - switch (irq) { - case 5: - return 2; - case 7: - return 4; - case 9: - return 1; - case 10: - return 8; - default: - dolog ("bad irq %d\n", irq); - return 2; - } -} - -static int irq_of_magic (int magic) -{ - switch (magic) { - case 1: - return 9; - case 2: - return 5; - case 4: - return 7; - case 8: - return 10; - default: - dolog ("bad irq magic %d\n", magic); - return -1; - } -} - -#if 0 -static void log_dsp (SB16State *dsp) -{ - ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n", - dsp->fmt_stereo ? "Stereo" : "Mono", - dsp->fmt_signed ? "Signed" : "Unsigned", - dsp->fmt_bits, - dsp->dma_auto ? "Auto" : "Single", - dsp->block_size, - dsp->freq, - dsp->time_const, - dsp->speaker); -} -#endif - -static void speaker (SB16State *s, int on) -{ - s->speaker = on; - /* AUD_enable (s->voice, on); */ -} - -static void control (SB16State *s, int hold) -{ - int dma = s->use_hdma ? s->hdma : s->dma; - IsaDma *isa_dma = s->use_hdma ? s->isa_hdma : s->isa_dma; - IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma); - s->dma_running = hold; - - ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma); - - if (hold) { - k->hold_DREQ(isa_dma, dma); - AUD_set_active_out (s->voice, 1); - } - else { - k->release_DREQ(isa_dma, dma); - AUD_set_active_out (s->voice, 0); - } -} - -static void aux_timer (void *opaque) -{ - SB16State *s = opaque; - s->can_write = 1; - qemu_irq_raise (s->pic); -} - -#define DMA8_AUTO 1 -#define DMA8_HIGH 2 - -static void continue_dma8 (SB16State *s) -{ - if (s->freq > 0) { - struct audsettings as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - } - - control (s, 1); -} - -static void dma_cmd8 (SB16State *s, int mask, int dma_len) -{ - s->fmt = AUD_FMT_U8; - s->use_hdma = 0; - s->fmt_bits = 8; - s->fmt_signed = 0; - s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; - if (-1 == s->time_const) { - if (s->freq <= 0) - s->freq = 11025; - } - else { - int tmp = (256 - s->time_const); - s->freq = (1000000 + (tmp / 2)) / tmp; - } - - if (dma_len != -1) { - s->block_size = dma_len << s->fmt_stereo; - } - else { - /* This is apparently the only way to make both Act1/PL - and SecondReality/FC work - - Act1 sets block size via command 0x48 and it's an odd number - SR does the same with even number - Both use stereo, and Creatives own documentation states that - 0x48 sets block size in bytes less one.. go figure */ - s->block_size &= ~s->fmt_stereo; - } - - s->freq >>= s->fmt_stereo; - s->left_till_irq = s->block_size; - s->bytes_per_second = (s->freq << s->fmt_stereo); - /* s->highspeed = (mask & DMA8_HIGH) != 0; */ - s->dma_auto = (mask & DMA8_AUTO) != 0; - s->align = (1 << s->fmt_stereo) - 1; - - if (s->block_size & s->align) { - dolog ("warning: misaligned block size %d, alignment %d\n", - s->block_size, s->align + 1); - } - - ldebug ("freq %d, stereo %d, sign %d, bits %d, " - "dma %d, auto %d, fifo %d, high %d\n", - s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, - s->block_size, s->dma_auto, s->fifo, s->highspeed); - - continue_dma8 (s); - speaker (s, 1); -} - -static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) -{ - s->use_hdma = cmd < 0xc0; - s->fifo = (cmd >> 1) & 1; - s->dma_auto = (cmd >> 2) & 1; - s->fmt_signed = (d0 >> 4) & 1; - s->fmt_stereo = (d0 >> 5) & 1; - - switch (cmd >> 4) { - case 11: - s->fmt_bits = 16; - break; - - case 12: - s->fmt_bits = 8; - break; - } - - if (-1 != s->time_const) { -#if 1 - int tmp = 256 - s->time_const; - s->freq = (1000000 + (tmp / 2)) / tmp; -#else - /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */ - s->freq = 1000000 / ((255 - s->time_const)); -#endif - s->time_const = -1; - } - - s->block_size = dma_len + 1; - s->block_size <<= (s->fmt_bits == 16); - if (!s->dma_auto) { - /* It is clear that for DOOM and auto-init this value - shouldn't take stereo into account, while Miles Sound Systems - setsound.exe with single transfer mode wouldn't work without it - wonders of SB16 yet again */ - s->block_size <<= s->fmt_stereo; - } - - ldebug ("freq %d, stereo %d, sign %d, bits %d, " - "dma %d, auto %d, fifo %d, high %d\n", - s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, - s->block_size, s->dma_auto, s->fifo, s->highspeed); - - if (16 == s->fmt_bits) { - if (s->fmt_signed) { - s->fmt = AUD_FMT_S16; - } - else { - s->fmt = AUD_FMT_U16; - } - } - else { - if (s->fmt_signed) { - s->fmt = AUD_FMT_S8; - } - else { - s->fmt = AUD_FMT_U8; - } - } - - s->left_till_irq = s->block_size; - - s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); - s->highspeed = 0; - s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; - if (s->block_size & s->align) { - dolog ("warning: misaligned block size %d, alignment %d\n", - s->block_size, s->align + 1); - } - - if (s->freq) { - struct audsettings as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - } - - control (s, 1); - speaker (s, 1); -} - -static inline void dsp_out_data (SB16State *s, uint8_t val) -{ - ldebug ("outdata %#x\n", val); - if ((size_t) s->out_data_len < sizeof (s->out_data)) { - s->out_data[s->out_data_len++] = val; - } -} - -static inline uint8_t dsp_get_data (SB16State *s) -{ - if (s->in_index) { - return s->in2_data[--s->in_index]; - } - else { - dolog ("buffer underflow\n"); - return 0; - } -} - -static void command (SB16State *s, uint8_t cmd) -{ - ldebug ("command %#x\n", cmd); - - if (cmd > 0xaf && cmd < 0xd0) { - if (cmd & 8) { - dolog ("ADC not yet supported (command %#x)\n", cmd); - } - - switch (cmd >> 4) { - case 11: - case 12: - break; - default: - dolog ("%#x wrong bits\n", cmd); - } - s->needed_bytes = 3; - } - else { - s->needed_bytes = 0; - - switch (cmd) { - case 0x03: - dsp_out_data (s, 0x10); /* s->csp_param); */ - goto warn; - - case 0x04: - s->needed_bytes = 1; - goto warn; - - case 0x05: - s->needed_bytes = 2; - goto warn; - - case 0x08: - /* __asm__ ("int3"); */ - goto warn; - - case 0x0e: - s->needed_bytes = 2; - goto warn; - - case 0x09: - dsp_out_data (s, 0xf8); - goto warn; - - case 0x0f: - s->needed_bytes = 1; - goto warn; - - case 0x10: - s->needed_bytes = 1; - goto warn; - - case 0x14: - s->needed_bytes = 2; - s->block_size = 0; - break; - - case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ - dma_cmd8 (s, DMA8_AUTO, -1); - break; - - case 0x20: /* Direct ADC, Juice/PL */ - dsp_out_data (s, 0xff); - goto warn; - - case 0x35: - dolog ("0x35 - MIDI command not implemented\n"); - break; - - case 0x40: - s->freq = -1; - s->time_const = -1; - s->needed_bytes = 1; - break; - - case 0x41: - s->freq = -1; - s->time_const = -1; - s->needed_bytes = 2; - break; - - case 0x42: - s->freq = -1; - s->time_const = -1; - s->needed_bytes = 2; - goto warn; - - case 0x45: - dsp_out_data (s, 0xaa); - goto warn; - - case 0x47: /* Continue Auto-Initialize DMA 16bit */ - break; - - case 0x48: - s->needed_bytes = 2; - break; - - case 0x74: - s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */ - dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"); - break; - - case 0x75: /* DMA DAC, 4-bit ADPCM Reference */ - s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"); - break; - - case 0x76: /* DMA DAC, 2.6-bit ADPCM */ - s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"); - break; - - case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */ - s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"); - break; - - case 0x7d: - dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"); - dolog ("not implemented\n"); - break; - - case 0x7f: - dolog ( - "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n" - ); - dolog ("not implemented\n"); - break; - - case 0x80: - s->needed_bytes = 2; - break; - - case 0x90: - case 0x91: - dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1); - break; - - case 0xd0: /* halt DMA operation. 8bit */ - control (s, 0); - break; - - case 0xd1: /* speaker on */ - speaker (s, 1); - break; - - case 0xd3: /* speaker off */ - speaker (s, 0); - break; - - case 0xd4: /* continue DMA operation. 8bit */ - /* KQ6 (or maybe Sierras audblst.drv in general) resets - the frequency between halt/continue */ - continue_dma8 (s); - break; - - case 0xd5: /* halt DMA operation. 16bit */ - control (s, 0); - break; - - case 0xd6: /* continue DMA operation. 16bit */ - control (s, 1); - break; - - case 0xd9: /* exit auto-init DMA after this block. 16bit */ - s->dma_auto = 0; - break; - - case 0xda: /* exit auto-init DMA after this block. 8bit */ - s->dma_auto = 0; - break; - - case 0xe0: /* DSP identification */ - s->needed_bytes = 1; - break; - - case 0xe1: - dsp_out_data (s, s->ver & 0xff); - dsp_out_data (s, s->ver >> 8); - break; - - case 0xe2: - s->needed_bytes = 1; - goto warn; - - case 0xe3: - { - int i; - for (i = sizeof (e3) - 1; i >= 0; --i) - dsp_out_data (s, e3[i]); - } - break; - - case 0xe4: /* write test reg */ - s->needed_bytes = 1; - break; - - case 0xe7: - dolog ("Attempt to probe for ESS (0xe7)?\n"); - break; - - case 0xe8: /* read test reg */ - dsp_out_data (s, s->test_reg); - break; - - case 0xf2: - case 0xf3: - dsp_out_data (s, 0xaa); - s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2; - qemu_irq_raise (s->pic); - break; - - case 0xf9: - s->needed_bytes = 1; - goto warn; - - case 0xfa: - dsp_out_data (s, 0); - goto warn; - - case 0xfc: /* FIXME */ - dsp_out_data (s, 0); - goto warn; - - default: - dolog ("Unrecognized command %#x\n", cmd); - break; - } - } - - if (!s->needed_bytes) { - ldebug ("\n"); - } - - exit: - if (!s->needed_bytes) { - s->cmd = -1; - } - else { - s->cmd = cmd; - } - return; - - warn: - dolog ("warning: command %#x,%d is not truly understood yet\n", - cmd, s->needed_bytes); - goto exit; - -} - -static uint16_t dsp_get_lohi (SB16State *s) -{ - uint8_t hi = dsp_get_data (s); - uint8_t lo = dsp_get_data (s); - return (hi << 8) | lo; -} - -static uint16_t dsp_get_hilo (SB16State *s) -{ - uint8_t lo = dsp_get_data (s); - uint8_t hi = dsp_get_data (s); - return (hi << 8) | lo; -} - -static void complete (SB16State *s) -{ - int d0, d1, d2; - ldebug ("complete command %#x, in_index %d, needed_bytes %d\n", - s->cmd, s->in_index, s->needed_bytes); - - if (s->cmd > 0xaf && s->cmd < 0xd0) { - d2 = dsp_get_data (s); - d1 = dsp_get_data (s); - d0 = dsp_get_data (s); - - if (s->cmd & 8) { - dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", - s->cmd, d0, d1, d2); - } - else { - ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", - s->cmd, d0, d1, d2); - dma_cmd (s, s->cmd, d0, d1 + (d2 << 8)); - } - } - else { - switch (s->cmd) { - case 0x04: - s->csp_mode = dsp_get_data (s); - s->csp_reg83r = 0; - s->csp_reg83w = 0; - ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode); - break; - - case 0x05: - s->csp_param = dsp_get_data (s); - s->csp_value = dsp_get_data (s); - ldebug ("CSP command 0x05: param=%#x value=%#x\n", - s->csp_param, - s->csp_value); - break; - - case 0x0e: - d0 = dsp_get_data (s); - d1 = dsp_get_data (s); - ldebug ("write CSP register %d <- %#x\n", d1, d0); - if (d1 == 0x83) { - ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0); - s->csp_reg83[s->csp_reg83r % 4] = d0; - s->csp_reg83r += 1; - } - else { - s->csp_regs[d1] = d0; - } - break; - - case 0x0f: - d0 = dsp_get_data (s); - ldebug ("read CSP register %#x -> %#x, mode=%#x\n", - d0, s->csp_regs[d0], s->csp_mode); - if (d0 == 0x83) { - ldebug ("0x83[%d] -> %#x\n", - s->csp_reg83w, - s->csp_reg83[s->csp_reg83w % 4]); - dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]); - s->csp_reg83w += 1; - } - else { - dsp_out_data (s, s->csp_regs[d0]); - } - break; - - case 0x10: - d0 = dsp_get_data (s); - dolog ("cmd 0x10 d0=%#x\n", d0); - break; - - case 0x14: - dma_cmd8 (s, 0, dsp_get_lohi (s) + 1); - break; - - case 0x40: - s->time_const = dsp_get_data (s); - ldebug ("set time const %d\n", s->time_const); - break; - - case 0x42: /* FT2 sets output freq with this, go figure */ -#if 0 - dolog ("cmd 0x42 might not do what it think it should\n"); -#endif - case 0x41: - s->freq = dsp_get_hilo (s); - ldebug ("set freq %d\n", s->freq); - break; - - case 0x48: - s->block_size = dsp_get_lohi (s) + 1; - ldebug ("set dma block len %d\n", s->block_size); - break; - - case 0x74: - case 0x75: - case 0x76: - case 0x77: - /* ADPCM stuff, ignore */ - break; - - case 0x80: - { - int freq, samples, bytes; - int64_t ticks; - - freq = s->freq > 0 ? s->freq : 11025; - samples = dsp_get_lohi (s) + 1; - bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); - ticks = muldiv64(bytes, NANOSECONDS_PER_SECOND, freq); - if (ticks < NANOSECONDS_PER_SECOND / 1024) { - qemu_irq_raise (s->pic); - } - else { - if (s->aux_ts) { - timer_mod ( - s->aux_ts, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ticks - ); - } - } - ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks); - } - break; - - case 0xe0: - d0 = dsp_get_data (s); - s->out_data_len = 0; - ldebug ("E0 data = %#x\n", d0); - dsp_out_data (s, ~d0); - break; - - case 0xe2: -#ifdef DEBUG - d0 = dsp_get_data (s); - dolog ("E2 = %#x\n", d0); -#endif - break; - - case 0xe4: - s->test_reg = dsp_get_data (s); - break; - - case 0xf9: - d0 = dsp_get_data (s); - ldebug ("command 0xf9 with %#x\n", d0); - switch (d0) { - case 0x0e: - dsp_out_data (s, 0xff); - break; - - case 0x0f: - dsp_out_data (s, 0x07); - break; - - case 0x37: - dsp_out_data (s, 0x38); - break; - - default: - dsp_out_data (s, 0x00); - break; - } - break; - - default: - dolog ("complete: unrecognized command %#x\n", s->cmd); - return; - } - } - - ldebug ("\n"); - s->cmd = -1; -} - -static void legacy_reset (SB16State *s) -{ - struct audsettings as; - - s->freq = 11025; - s->fmt_signed = 0; - s->fmt_bits = 8; - s->fmt_stereo = 0; - - as.freq = s->freq; - as.nchannels = 1; - as.fmt = AUD_FMT_U8; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - - /* Not sure about that... */ - /* AUD_set_active_out (s->voice, 1); */ -} - -static void reset (SB16State *s) -{ - qemu_irq_lower (s->pic); - if (s->dma_auto) { - qemu_irq_raise (s->pic); - qemu_irq_lower (s->pic); - } - - s->mixer_regs[0x82] = 0; - s->dma_auto = 0; - s->in_index = 0; - s->out_data_len = 0; - s->left_till_irq = 0; - s->needed_bytes = 0; - s->block_size = -1; - s->nzero = 0; - s->highspeed = 0; - s->v2x6 = 0; - s->cmd = -1; - - dsp_out_data (s, 0xaa); - speaker (s, 0); - control (s, 0); - legacy_reset (s); -} - -static void dsp_write(void *opaque, uint32_t nport, uint32_t val) -{ - SB16State *s = opaque; - int iport; - - iport = nport - s->port; - - ldebug ("write %#x <- %#x\n", nport, val); - switch (iport) { - case 0x06: - switch (val) { - case 0x00: - if (s->v2x6 == 1) { - reset (s); - } - s->v2x6 = 0; - break; - - case 0x01: - case 0x03: /* FreeBSD kludge */ - s->v2x6 = 1; - break; - - case 0xc6: - s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */ - break; - - case 0xb8: /* Panic */ - reset (s); - break; - - case 0x39: - dsp_out_data (s, 0x38); - reset (s); - s->v2x6 = 0x39; - break; - - default: - s->v2x6 = val; - break; - } - break; - - case 0x0c: /* write data or command | write status */ -/* if (s->highspeed) */ -/* break; */ - - if (s->needed_bytes == 0) { - command (s, val); -#if 0 - if (0 == s->needed_bytes) { - log_dsp (s); - } -#endif - } - else { - if (s->in_index == sizeof (s->in2_data)) { - dolog ("in data overrun\n"); - } - else { - s->in2_data[s->in_index++] = val; - if (s->in_index == s->needed_bytes) { - s->needed_bytes = 0; - complete (s); -#if 0 - log_dsp (s); -#endif - } - } - } - break; - - default: - ldebug ("(nport=%#x, val=%#x)\n", nport, val); - break; - } -} - -static uint32_t dsp_read(void *opaque, uint32_t nport) -{ - SB16State *s = opaque; - int iport, retval, ack = 0; - - iport = nport - s->port; - - switch (iport) { - case 0x06: /* reset */ - retval = 0xff; - break; - - case 0x0a: /* read data */ - if (s->out_data_len) { - retval = s->out_data[--s->out_data_len]; - s->last_read_byte = retval; - } - else { - if (s->cmd != -1) { - dolog ("empty output buffer for command %#x\n", - s->cmd); - } - retval = s->last_read_byte; - /* goto error; */ - } - break; - - case 0x0c: /* 0 can write */ - retval = s->can_write ? 0 : 0x80; - break; - - case 0x0d: /* timer interrupt clear */ - /* dolog ("timer interrupt clear\n"); */ - retval = 0; - break; - - case 0x0e: /* data available status | irq 8 ack */ - retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80; - if (s->mixer_regs[0x82] & 1) { - ack = 1; - s->mixer_regs[0x82] &= ~1; - qemu_irq_lower (s->pic); - } - break; - - case 0x0f: /* irq 16 ack */ - retval = 0xff; - if (s->mixer_regs[0x82] & 2) { - ack = 1; - s->mixer_regs[0x82] &= ~2; - qemu_irq_lower (s->pic); - } - break; - - default: - goto error; - } - - if (!ack) { - ldebug ("read %#x -> %#x\n", nport, retval); - } - - return retval; - - error: - dolog ("warning: dsp_read %#x error\n", nport); - return 0xff; -} - -static void reset_mixer (SB16State *s) -{ - int i; - - memset (s->mixer_regs, 0xff, 0x7f); - memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83); - - s->mixer_regs[0x02] = 4; /* master volume 3bits */ - s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */ - s->mixer_regs[0x08] = 0; /* CD volume 3bits */ - s->mixer_regs[0x0a] = 0; /* voice volume 2bits */ - - /* d5=input filt, d3=lowpass filt, d1,d2=input source */ - s->mixer_regs[0x0c] = 0; - - /* d5=output filt, d1=stereo switch */ - s->mixer_regs[0x0e] = 0; - - /* voice volume L d5,d7, R d1,d3 */ - s->mixer_regs[0x04] = (4 << 5) | (4 << 1); - /* master ... */ - s->mixer_regs[0x22] = (4 << 5) | (4 << 1); - /* MIDI ... */ - s->mixer_regs[0x26] = (4 << 5) | (4 << 1); - - for (i = 0x30; i < 0x48; i++) { - s->mixer_regs[i] = 0x20; - } -} - -static void mixer_write_indexb(void *opaque, uint32_t nport, uint32_t val) -{ - SB16State *s = opaque; - (void) nport; - s->mixer_nreg = val; -} - -static void mixer_write_datab(void *opaque, uint32_t nport, uint32_t val) -{ - SB16State *s = opaque; - - (void) nport; - ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); - - switch (s->mixer_nreg) { - case 0x00: - reset_mixer (s); - break; - - case 0x80: - { - int irq = irq_of_magic (val); - ldebug ("setting irq to %d (val=%#x)\n", irq, val); - if (irq > 0) { - s->irq = irq; - } - } - break; - - case 0x81: - { - int dma, hdma; - - dma = ctz32 (val & 0xf); - hdma = ctz32 (val & 0xf0); - if (dma != s->dma || hdma != s->hdma) { - dolog ( - "attempt to change DMA " - "8bit %d(%d), 16bit %d(%d) (val=%#x)\n", - dma, s->dma, hdma, s->hdma, val); - } -#if 0 - s->dma = dma; - s->hdma = hdma; -#endif - } - break; - - case 0x82: - dolog ("attempt to write into IRQ status register (val=%#x)\n", - val); - return; - - default: - if (s->mixer_nreg >= 0x80) { - ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); - } - break; - } - - s->mixer_regs[s->mixer_nreg] = val; -} - -static uint32_t mixer_read(void *opaque, uint32_t nport) -{ - SB16State *s = opaque; - - (void) nport; -#ifndef DEBUG_SB16_MOST - if (s->mixer_nreg != 0x82) { - ldebug ("mixer_read[%#x] -> %#x\n", - s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); - } -#else - ldebug ("mixer_read[%#x] -> %#x\n", - s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); -#endif - return s->mixer_regs[s->mixer_nreg]; -} - -static int write_audio (SB16State *s, int nchan, int dma_pos, - int dma_len, int len) -{ - IsaDma *isa_dma = nchan == s->dma ? s->isa_dma : s->isa_hdma; - IsaDmaClass *k = ISADMA_GET_CLASS(isa_dma); - int temp, net; - uint8_t tmpbuf[4096]; - - temp = len; - net = 0; - - while (temp) { - int left = dma_len - dma_pos; - int copied; - size_t to_copy; - - to_copy = audio_MIN (temp, left); - if (to_copy > sizeof (tmpbuf)) { - to_copy = sizeof (tmpbuf); - } - - copied = k->read_memory(isa_dma, nchan, tmpbuf, dma_pos, to_copy); - copied = AUD_write (s->voice, tmpbuf, copied); - - temp -= copied; - dma_pos = (dma_pos + copied) % dma_len; - net += copied; - - if (!copied) { - break; - } - } - - return net; -} - -static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) -{ - SB16State *s = opaque; - int till, copy, written, free; - - if (s->block_size <= 0) { - dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n", - s->block_size, nchan, dma_pos, dma_len); - return dma_pos; - } - - if (s->left_till_irq < 0) { - s->left_till_irq = s->block_size; - } - - if (s->voice) { - free = s->audio_free & ~s->align; - if ((free <= 0) || !dma_len) { - return dma_pos; - } - } - else { - free = dma_len; - } - - copy = free; - till = s->left_till_irq; - -#ifdef DEBUG_SB16_MOST - dolog ("pos:%06d %d till:%d len:%d\n", - dma_pos, free, till, dma_len); -#endif - - if (till <= copy) { - if (s->dma_auto == 0) { - copy = till; - } - } - - written = write_audio (s, nchan, dma_pos, dma_len, copy); - dma_pos = (dma_pos + written) % dma_len; - s->left_till_irq -= written; - - if (s->left_till_irq <= 0) { - s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1; - qemu_irq_raise (s->pic); - if (s->dma_auto == 0) { - control (s, 0); - speaker (s, 0); - } - } - -#ifdef DEBUG_SB16_MOST - ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n", - dma_pos, free, dma_len, s->left_till_irq, copy, written, - s->block_size); -#endif - - while (s->left_till_irq <= 0) { - s->left_till_irq = s->block_size + s->left_till_irq; - } - - return dma_pos; -} - -static void SB_audio_callback (void *opaque, int free) -{ - SB16State *s = opaque; - s->audio_free = free; -} - -static int sb16_post_load (void *opaque, int version_id) -{ - SB16State *s = opaque; - - if (s->voice) { - AUD_close_out (&s->card, s->voice); - s->voice = NULL; - } - - if (s->dma_running) { - if (s->freq) { - struct audsettings as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - } - - control (s, 1); - speaker (s, s->speaker); - } - return 0; -} - -static const VMStateDescription vmstate_sb16 = { - .name = "sb16", - .version_id = 1, - .minimum_version_id = 1, - .post_load = sb16_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT32 (irq, SB16State), - VMSTATE_UINT32 (dma, SB16State), - VMSTATE_UINT32 (hdma, SB16State), - VMSTATE_UINT32 (port, SB16State), - VMSTATE_UINT32 (ver, SB16State), - VMSTATE_INT32 (in_index, SB16State), - VMSTATE_INT32 (out_data_len, SB16State), - VMSTATE_INT32 (fmt_stereo, SB16State), - VMSTATE_INT32 (fmt_signed, SB16State), - VMSTATE_INT32 (fmt_bits, SB16State), - VMSTATE_UINT32 (fmt, SB16State), - VMSTATE_INT32 (dma_auto, SB16State), - VMSTATE_INT32 (block_size, SB16State), - VMSTATE_INT32 (fifo, SB16State), - VMSTATE_INT32 (freq, SB16State), - VMSTATE_INT32 (time_const, SB16State), - VMSTATE_INT32 (speaker, SB16State), - VMSTATE_INT32 (needed_bytes, SB16State), - VMSTATE_INT32 (cmd, SB16State), - VMSTATE_INT32 (use_hdma, SB16State), - VMSTATE_INT32 (highspeed, SB16State), - VMSTATE_INT32 (can_write, SB16State), - VMSTATE_INT32 (v2x6, SB16State), - - VMSTATE_UINT8 (csp_param, SB16State), - VMSTATE_UINT8 (csp_value, SB16State), - VMSTATE_UINT8 (csp_mode, SB16State), - VMSTATE_UINT8 (csp_param, SB16State), - VMSTATE_BUFFER (csp_regs, SB16State), - VMSTATE_UINT8 (csp_index, SB16State), - VMSTATE_BUFFER (csp_reg83, SB16State), - VMSTATE_INT32 (csp_reg83r, SB16State), - VMSTATE_INT32 (csp_reg83w, SB16State), - - VMSTATE_BUFFER (in2_data, SB16State), - VMSTATE_BUFFER (out_data, SB16State), - VMSTATE_UINT8 (test_reg, SB16State), - VMSTATE_UINT8 (last_read_byte, SB16State), - - VMSTATE_INT32 (nzero, SB16State), - VMSTATE_INT32 (left_till_irq, SB16State), - VMSTATE_INT32 (dma_running, SB16State), - VMSTATE_INT32 (bytes_per_second, SB16State), - VMSTATE_INT32 (align, SB16State), - - VMSTATE_INT32 (mixer_nreg, SB16State), - VMSTATE_BUFFER (mixer_regs, SB16State), - - VMSTATE_END_OF_LIST () - } -}; - -static const MemoryRegionPortio sb16_ioport_list[] = { - { 4, 1, 1, .write = mixer_write_indexb }, - { 5, 1, 1, .read = mixer_read, .write = mixer_write_datab }, - { 6, 1, 1, .read = dsp_read, .write = dsp_write }, - { 10, 1, 1, .read = dsp_read }, - { 12, 1, 1, .write = dsp_write }, - { 12, 4, 1, .read = dsp_read }, - PORTIO_END_OF_LIST (), -}; - - -static void sb16_initfn (Object *obj) -{ - SB16State *s = SB16 (obj); - - s->cmd = -1; -} - -static void sb16_realizefn (DeviceState *dev, Error **errp) -{ - ISADevice *isadev = ISA_DEVICE (dev); - SB16State *s = SB16 (dev); - IsaDmaClass *k; - - isa_init_irq (isadev, &s->pic, s->irq); - - s->mixer_regs[0x80] = magic_of_irq (s->irq); - s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma); - s->mixer_regs[0x82] = 2 << 5; - - s->csp_regs[5] = 1; - s->csp_regs[9] = 0xf8; - - reset_mixer (s); - s->aux_ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, aux_timer, s); - if (!s->aux_ts) { - dolog ("warning: Could not create auxiliary timer\n"); - } - - isa_register_portio_list (isadev, s->port, sb16_ioport_list, s, "sb16"); - - s->isa_hdma = isa_get_dma(isa_bus_from_device(isadev), s->hdma); - k = ISADMA_GET_CLASS(s->isa_hdma); - k->register_channel(s->isa_hdma, s->hdma, SB_read_DMA, s); - - s->isa_dma = isa_get_dma(isa_bus_from_device(isadev), s->dma); - k = ISADMA_GET_CLASS(s->isa_dma); - k->register_channel(s->isa_dma, s->dma, SB_read_DMA, s); - - s->can_write = 1; - - AUD_register_card ("sb16", &s->card); -} - -static int SB16_init (ISABus *bus) -{ - isa_create_simple (bus, TYPE_SB16); - return 0; -} - -static Property sb16_properties[] = { - DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */ - DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220), - DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5), - DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1), - DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5), - DEFINE_PROP_END_OF_LIST (), -}; - -static void sb16_class_initfn (ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS (klass); - - dc->realize = sb16_realizefn; - set_bit(DEVICE_CATEGORY_SOUND, dc->categories); - dc->desc = "Creative Sound Blaster 16"; - dc->vmsd = &vmstate_sb16; - dc->props = sb16_properties; -} - -static const TypeInfo sb16_info = { - .name = TYPE_SB16, - .parent = TYPE_ISA_DEVICE, - .instance_size = sizeof (SB16State), - .instance_init = sb16_initfn, - .class_init = sb16_class_initfn, -}; - -static void sb16_register_types (void) -{ - type_register_static (&sb16_info); - isa_register_soundhw("sb16", "Creative Sound Blaster 16", SB16_init); -} - -type_init (sb16_register_types) diff --git a/qemu/hw/audio/wm8750.c b/qemu/hw/audio/wm8750.c deleted file mode 100644 index 0c6500e96..000000000 --- a/qemu/hw/audio/wm8750.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * WM8750 audio CODEC. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * This file is licensed under GNU GPL. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/i2c/i2c.h" -#include "audio/audio.h" - -#define IN_PORT_N 3 -#define OUT_PORT_N 3 - -#define CODEC "wm8750" - -typedef struct { - int adc; - int adc_hz; - int dac; - int dac_hz; -} WMRate; - -#define TYPE_WM8750 "wm8750" -#define WM8750(obj) OBJECT_CHECK(WM8750State, (obj), TYPE_WM8750) - -typedef struct WM8750State { - I2CSlave parent_obj; - - uint8_t i2c_data[2]; - int i2c_len; - QEMUSoundCard card; - SWVoiceIn *adc_voice[IN_PORT_N]; - SWVoiceOut *dac_voice[OUT_PORT_N]; - int enable; - void (*data_req)(void *, int, int); - void *opaque; - uint8_t data_in[4096]; - uint8_t data_out[4096]; - int idx_in, req_in; - int idx_out, req_out; - - SWVoiceOut **out[2]; - uint8_t outvol[7], outmute[2]; - SWVoiceIn **in[2]; - uint8_t invol[4], inmute[2]; - - uint8_t diff[2], pol, ds, monomix[2], alc, mute; - uint8_t path[4], mpath[2], power, format; - const WMRate *rate; - uint8_t rate_vmstate; - int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master; -} WM8750State; - -/* pow(10.0, -i / 20.0) * 255, i = 0..42 */ -static const uint8_t wm8750_vol_db_table[] = { - 255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45, - 40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5, - 4, 4, 3, 3, 3, 2, 2 -}; - -#define WM8750_OUTVOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3] -#define WM8750_INVOL_TRANSFORM(x) (x << 2) - -static inline void wm8750_in_load(WM8750State *s) -{ - if (s->idx_in + s->req_in <= sizeof(s->data_in)) - return; - s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in); - AUD_read(*s->in[0], s->data_in + s->idx_in, - sizeof(s->data_in) - s->idx_in); -} - -static inline void wm8750_out_flush(WM8750State *s) -{ - int sent = 0; - while (sent < s->idx_out) - sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent) - ?: s->idx_out; - s->idx_out = 0; -} - -static void wm8750_audio_in_cb(void *opaque, int avail_b) -{ - WM8750State *s = (WM8750State *) opaque; - s->req_in = avail_b; - s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2); -} - -static void wm8750_audio_out_cb(void *opaque, int free_b) -{ - WM8750State *s = (WM8750State *) opaque; - - if (s->idx_out >= free_b) { - s->idx_out = free_b; - s->req_out = 0; - wm8750_out_flush(s); - } else - s->req_out = free_b - s->idx_out; - - s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2); -} - -static const WMRate wm_rate_table[] = { - { 256, 48000, 256, 48000 }, /* SR: 00000 */ - { 384, 48000, 384, 48000 }, /* SR: 00001 */ - { 256, 48000, 1536, 8000 }, /* SR: 00010 */ - { 384, 48000, 2304, 8000 }, /* SR: 00011 */ - { 1536, 8000, 256, 48000 }, /* SR: 00100 */ - { 2304, 8000, 384, 48000 }, /* SR: 00101 */ - { 1536, 8000, 1536, 8000 }, /* SR: 00110 */ - { 2304, 8000, 2304, 8000 }, /* SR: 00111 */ - { 1024, 12000, 1024, 12000 }, /* SR: 01000 */ - { 1526, 12000, 1536, 12000 }, /* SR: 01001 */ - { 768, 16000, 768, 16000 }, /* SR: 01010 */ - { 1152, 16000, 1152, 16000 }, /* SR: 01011 */ - { 384, 32000, 384, 32000 }, /* SR: 01100 */ - { 576, 32000, 576, 32000 }, /* SR: 01101 */ - { 128, 96000, 128, 96000 }, /* SR: 01110 */ - { 192, 96000, 192, 96000 }, /* SR: 01111 */ - { 256, 44100, 256, 44100 }, /* SR: 10000 */ - { 384, 44100, 384, 44100 }, /* SR: 10001 */ - { 256, 44100, 1408, 8018 }, /* SR: 10010 */ - { 384, 44100, 2112, 8018 }, /* SR: 10011 */ - { 1408, 8018, 256, 44100 }, /* SR: 10100 */ - { 2112, 8018, 384, 44100 }, /* SR: 10101 */ - { 1408, 8018, 1408, 8018 }, /* SR: 10110 */ - { 2112, 8018, 2112, 8018 }, /* SR: 10111 */ - { 1024, 11025, 1024, 11025 }, /* SR: 11000 */ - { 1536, 11025, 1536, 11025 }, /* SR: 11001 */ - { 512, 22050, 512, 22050 }, /* SR: 11010 */ - { 768, 22050, 768, 22050 }, /* SR: 11011 */ - { 512, 24000, 512, 24000 }, /* SR: 11100 */ - { 768, 24000, 768, 24000 }, /* SR: 11101 */ - { 128, 88200, 128, 88200 }, /* SR: 11110 */ - { 192, 88200, 192, 88200 }, /* SR: 11111 */ -}; - -static void wm8750_vol_update(WM8750State *s) -{ - /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */ - - AUD_set_volume_in(s->adc_voice[0], s->mute, - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); - AUD_set_volume_in(s->adc_voice[1], s->mute, - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); - AUD_set_volume_in(s->adc_voice[2], s->mute, - s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]), - s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1])); - - /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */ - - /* Speaker: LOUT2VOL ROUT2VOL */ - AUD_set_volume_out(s->dac_voice[0], s->mute, - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]), - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5])); - - /* Headphone: LOUT1VOL ROUT1VOL */ - AUD_set_volume_out(s->dac_voice[1], s->mute, - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]), - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3])); - - /* MONOOUT: MONOVOL MONOVOL */ - AUD_set_volume_out(s->dac_voice[2], s->mute, - s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]), - s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6])); -} - -static void wm8750_set_format(WM8750State *s) -{ - int i; - struct audsettings in_fmt; - struct audsettings out_fmt; - - wm8750_out_flush(s); - - if (s->in[0] && *s->in[0]) - AUD_set_active_in(*s->in[0], 0); - if (s->out[0] && *s->out[0]) - AUD_set_active_out(*s->out[0], 0); - - for (i = 0; i < IN_PORT_N; i ++) - if (s->adc_voice[i]) { - AUD_close_in(&s->card, s->adc_voice[i]); - s->adc_voice[i] = NULL; - } - for (i = 0; i < OUT_PORT_N; i ++) - if (s->dac_voice[i]) { - AUD_close_out(&s->card, s->dac_voice[i]); - s->dac_voice[i] = NULL; - } - - if (!s->enable) - return; - - /* Setup input */ - in_fmt.endianness = 0; - in_fmt.nchannels = 2; - in_fmt.freq = s->adc_hz; - in_fmt.fmt = AUD_FMT_S16; - - s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0], - CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt); - s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1], - CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt); - s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2], - CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt); - - /* Setup output */ - out_fmt.endianness = 0; - out_fmt.nchannels = 2; - out_fmt.freq = s->dac_hz; - out_fmt.fmt = AUD_FMT_S16; - - s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], - CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt); - s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1], - CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt); - /* MONOMIX is also in stereo for simplicity */ - s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2], - CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt); - /* no sense emulating OUT3 which is a mix of other outputs */ - - wm8750_vol_update(s); - - /* We should connect the left and right channels to their - * respective inputs/outputs but we have completely no need - * for mixing or combining paths to different ports, so we - * connect both channels to where the left channel is routed. */ - if (s->in[0] && *s->in[0]) - AUD_set_active_in(*s->in[0], 1); - if (s->out[0] && *s->out[0]) - AUD_set_active_out(*s->out[0], 1); -} - -static void wm8750_clk_update(WM8750State *s, int ext) -{ - if (s->master || !s->ext_dac_hz) - s->dac_hz = s->rate->dac_hz; - else - s->dac_hz = s->ext_dac_hz; - - if (s->master || !s->ext_adc_hz) - s->adc_hz = s->rate->adc_hz; - else - s->adc_hz = s->ext_adc_hz; - - if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) { - if (!ext) - wm8750_set_format(s); - } else { - if (ext) - wm8750_set_format(s); - } -} - -static void wm8750_reset(I2CSlave *i2c) -{ - WM8750State *s = WM8750(i2c); - - s->rate = &wm_rate_table[0]; - s->enable = 0; - wm8750_clk_update(s, 1); - s->diff[0] = 0; - s->diff[1] = 0; - s->ds = 0; - s->alc = 0; - s->in[0] = &s->adc_voice[0]; - s->invol[0] = 0x17; - s->invol[1] = 0x17; - s->invol[2] = 0xc3; - s->invol[3] = 0xc3; - s->out[0] = &s->dac_voice[0]; - s->outvol[0] = 0xff; - s->outvol[1] = 0xff; - s->outvol[2] = 0x79; - s->outvol[3] = 0x79; - s->outvol[4] = 0x79; - s->outvol[5] = 0x79; - s->outvol[6] = 0x79; - s->inmute[0] = 0; - s->inmute[1] = 0; - s->outmute[0] = 0; - s->outmute[1] = 0; - s->mute = 1; - s->path[0] = 0; - s->path[1] = 0; - s->path[2] = 0; - s->path[3] = 0; - s->mpath[0] = 0; - s->mpath[1] = 0; - s->format = 0x0a; - s->idx_in = sizeof(s->data_in); - s->req_in = 0; - s->idx_out = 0; - s->req_out = 0; - wm8750_vol_update(s); - s->i2c_len = 0; -} - -static void wm8750_event(I2CSlave *i2c, enum i2c_event event) -{ - WM8750State *s = WM8750(i2c); - - switch (event) { - case I2C_START_SEND: - s->i2c_len = 0; - break; - case I2C_FINISH: -#ifdef VERBOSE - if (s->i2c_len < 2) - printf("%s: message too short (%i bytes)\n", - __FUNCTION__, s->i2c_len); -#endif - break; - default: - break; - } -} - -#define WM8750_LINVOL 0x00 -#define WM8750_RINVOL 0x01 -#define WM8750_LOUT1V 0x02 -#define WM8750_ROUT1V 0x03 -#define WM8750_ADCDAC 0x05 -#define WM8750_IFACE 0x07 -#define WM8750_SRATE 0x08 -#define WM8750_LDAC 0x0a -#define WM8750_RDAC 0x0b -#define WM8750_BASS 0x0c -#define WM8750_TREBLE 0x0d -#define WM8750_RESET 0x0f -#define WM8750_3D 0x10 -#define WM8750_ALC1 0x11 -#define WM8750_ALC2 0x12 -#define WM8750_ALC3 0x13 -#define WM8750_NGATE 0x14 -#define WM8750_LADC 0x15 -#define WM8750_RADC 0x16 -#define WM8750_ADCTL1 0x17 -#define WM8750_ADCTL2 0x18 -#define WM8750_PWR1 0x19 -#define WM8750_PWR2 0x1a -#define WM8750_ADCTL3 0x1b -#define WM8750_ADCIN 0x1f -#define WM8750_LADCIN 0x20 -#define WM8750_RADCIN 0x21 -#define WM8750_LOUTM1 0x22 -#define WM8750_LOUTM2 0x23 -#define WM8750_ROUTM1 0x24 -#define WM8750_ROUTM2 0x25 -#define WM8750_MOUTM1 0x26 -#define WM8750_MOUTM2 0x27 -#define WM8750_LOUT2V 0x28 -#define WM8750_ROUT2V 0x29 -#define WM8750_MOUTV 0x2a - -static int wm8750_tx(I2CSlave *i2c, uint8_t data) -{ - WM8750State *s = WM8750(i2c); - uint8_t cmd; - uint16_t value; - - if (s->i2c_len >= 2) { -#ifdef VERBOSE - printf("%s: long message (%i bytes)\n", __func__, s->i2c_len); -#endif - return 1; - } - s->i2c_data[s->i2c_len ++] = data; - if (s->i2c_len != 2) - return 0; - - cmd = s->i2c_data[0] >> 1; - value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff; - - switch (cmd) { - case WM8750_LADCIN: /* ADC Signal Path Control (Left) */ - s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */ - if (s->diff[0]) - s->in[0] = &s->adc_voice[0 + s->ds * 1]; - else - s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0]; - break; - - case WM8750_RADCIN: /* ADC Signal Path Control (Right) */ - s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */ - if (s->diff[1]) - s->in[1] = &s->adc_voice[0 + s->ds * 1]; - else - s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0]; - break; - - case WM8750_ADCIN: /* ADC Input Mode */ - s->ds = (value >> 8) & 1; /* DS */ - if (s->diff[0]) - s->in[0] = &s->adc_voice[0 + s->ds * 1]; - if (s->diff[1]) - s->in[1] = &s->adc_voice[0 + s->ds * 1]; - s->monomix[0] = (value >> 6) & 3; /* MONOMIX */ - break; - - case WM8750_ADCTL1: /* Additional Control (1) */ - s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */ - break; - - case WM8750_PWR1: /* Power Management (1) */ - s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */ - wm8750_set_format(s); - break; - - case WM8750_LINVOL: /* Left Channel PGA */ - s->invol[0] = value & 0x3f; /* LINVOL */ - s->inmute[0] = (value >> 7) & 1; /* LINMUTE */ - wm8750_vol_update(s); - break; - - case WM8750_RINVOL: /* Right Channel PGA */ - s->invol[1] = value & 0x3f; /* RINVOL */ - s->inmute[1] = (value >> 7) & 1; /* RINMUTE */ - wm8750_vol_update(s); - break; - - case WM8750_ADCDAC: /* ADC and DAC Control */ - s->pol = (value >> 5) & 3; /* ADCPOL */ - s->mute = (value >> 3) & 1; /* DACMU */ - wm8750_vol_update(s); - break; - - case WM8750_ADCTL3: /* Additional Control (3) */ - break; - - case WM8750_LADC: /* Left ADC Digital Volume */ - s->invol[2] = value & 0xff; /* LADCVOL */ - wm8750_vol_update(s); - break; - - case WM8750_RADC: /* Right ADC Digital Volume */ - s->invol[3] = value & 0xff; /* RADCVOL */ - wm8750_vol_update(s); - break; - - case WM8750_ALC1: /* ALC Control (1) */ - s->alc = (value >> 7) & 3; /* ALCSEL */ - break; - - case WM8750_NGATE: /* Noise Gate Control */ - case WM8750_3D: /* 3D enhance */ - break; - - case WM8750_LDAC: /* Left Channel Digital Volume */ - s->outvol[0] = value & 0xff; /* LDACVOL */ - wm8750_vol_update(s); - break; - - case WM8750_RDAC: /* Right Channel Digital Volume */ - s->outvol[1] = value & 0xff; /* RDACVOL */ - wm8750_vol_update(s); - break; - - case WM8750_BASS: /* Bass Control */ - break; - - case WM8750_LOUTM1: /* Left Mixer Control (1) */ - s->path[0] = (value >> 8) & 1; /* LD2LO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_LOUTM2: /* Left Mixer Control (2) */ - s->path[1] = (value >> 8) & 1; /* RD2LO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_ROUTM1: /* Right Mixer Control (1) */ - s->path[2] = (value >> 8) & 1; /* LD2RO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_ROUTM2: /* Right Mixer Control (2) */ - s->path[3] = (value >> 8) & 1; /* RD2RO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_MOUTM1: /* Mono Mixer Control (1) */ - s->mpath[0] = (value >> 8) & 1; /* LD2MO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_MOUTM2: /* Mono Mixer Control (2) */ - s->mpath[1] = (value >> 8) & 1; /* RD2MO */ - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_LOUT1V: /* LOUT1 Volume */ - s->outvol[2] = value & 0x7f; /* LOUT1VOL */ - wm8750_vol_update(s); - break; - - case WM8750_LOUT2V: /* LOUT2 Volume */ - s->outvol[4] = value & 0x7f; /* LOUT2VOL */ - wm8750_vol_update(s); - break; - - case WM8750_ROUT1V: /* ROUT1 Volume */ - s->outvol[3] = value & 0x7f; /* ROUT1VOL */ - wm8750_vol_update(s); - break; - - case WM8750_ROUT2V: /* ROUT2 Volume */ - s->outvol[5] = value & 0x7f; /* ROUT2VOL */ - wm8750_vol_update(s); - break; - - case WM8750_MOUTV: /* MONOOUT Volume */ - s->outvol[6] = value & 0x7f; /* MONOOUTVOL */ - wm8750_vol_update(s); - break; - - case WM8750_ADCTL2: /* Additional Control (2) */ - break; - - case WM8750_PWR2: /* Power Management (2) */ - s->power = value & 0x7e; - /* TODO: mute/unmute respective paths */ - wm8750_vol_update(s); - break; - - case WM8750_IFACE: /* Digital Audio Interface Format */ - s->format = value; - s->master = (value >> 6) & 1; /* MS */ - wm8750_clk_update(s, s->master); - break; - - case WM8750_SRATE: /* Clocking and Sample Rate Control */ - s->rate = &wm_rate_table[(value >> 1) & 0x1f]; - wm8750_clk_update(s, 0); - break; - - case WM8750_RESET: /* Reset */ - wm8750_reset(I2C_SLAVE(s)); - break; - -#ifdef VERBOSE - default: - printf("%s: unknown register %02x\n", __FUNCTION__, cmd); -#endif - } - - return 0; -} - -static int wm8750_rx(I2CSlave *i2c) -{ - return 0x00; -} - -static void wm8750_pre_save(void *opaque) -{ - WM8750State *s = opaque; - - s->rate_vmstate = s->rate - wm_rate_table; -} - -static int wm8750_post_load(void *opaque, int version_id) -{ - WM8750State *s = opaque; - - s->rate = &wm_rate_table[s->rate_vmstate & 0x1f]; - return 0; -} - -static const VMStateDescription vmstate_wm8750 = { - .name = CODEC, - .version_id = 0, - .minimum_version_id = 0, - .pre_save = wm8750_pre_save, - .post_load = wm8750_post_load, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2), - VMSTATE_INT32(i2c_len, WM8750State), - VMSTATE_INT32(enable, WM8750State), - VMSTATE_INT32(idx_in, WM8750State), - VMSTATE_INT32(req_in, WM8750State), - VMSTATE_INT32(idx_out, WM8750State), - VMSTATE_INT32(req_out, WM8750State), - VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7), - VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2), - VMSTATE_UINT8_ARRAY(invol, WM8750State, 4), - VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2), - VMSTATE_UINT8_ARRAY(diff, WM8750State, 2), - VMSTATE_UINT8(pol, WM8750State), - VMSTATE_UINT8(ds, WM8750State), - VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2), - VMSTATE_UINT8(alc, WM8750State), - VMSTATE_UINT8(mute, WM8750State), - VMSTATE_UINT8_ARRAY(path, WM8750State, 4), - VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2), - VMSTATE_UINT8(format, WM8750State), - VMSTATE_UINT8(power, WM8750State), - VMSTATE_UINT8(rate_vmstate, WM8750State), - VMSTATE_I2C_SLAVE(parent_obj, WM8750State), - VMSTATE_END_OF_LIST() - } -}; - -static int wm8750_init(I2CSlave *i2c) -{ - WM8750State *s = WM8750(i2c); - - AUD_register_card(CODEC, &s->card); - wm8750_reset(I2C_SLAVE(s)); - - return 0; -} - -#if 0 -static void wm8750_fini(I2CSlave *i2c) -{ - WM8750State *s = WM8750(i2c); - - wm8750_reset(I2C_SLAVE(s)); - AUD_remove_card(&s->card); - g_free(s); -} -#endif - -void wm8750_data_req_set(DeviceState *dev, - void (*data_req)(void *, int, int), void *opaque) -{ - WM8750State *s = WM8750(dev); - - s->data_req = data_req; - s->opaque = opaque; -} - -void wm8750_dac_dat(void *opaque, uint32_t sample) -{ - WM8750State *s = (WM8750State *) opaque; - - *(uint32_t *) &s->data_out[s->idx_out] = sample; - s->req_out -= 4; - s->idx_out += 4; - if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0) - wm8750_out_flush(s); -} - -void *wm8750_dac_buffer(void *opaque, int samples) -{ - WM8750State *s = (WM8750State *) opaque; - /* XXX: Should check if there are samples free samples available */ - void *ret = s->data_out + s->idx_out; - - s->idx_out += samples << 2; - s->req_out -= samples << 2; - return ret; -} - -void wm8750_dac_commit(void *opaque) -{ - WM8750State *s = (WM8750State *) opaque; - - wm8750_out_flush(s); -} - -uint32_t wm8750_adc_dat(void *opaque) -{ - WM8750State *s = (WM8750State *) opaque; - uint32_t *data; - - if (s->idx_in >= sizeof(s->data_in)) - wm8750_in_load(s); - - data = (uint32_t *) &s->data_in[s->idx_in]; - s->req_in -= 4; - s->idx_in += 4; - return *data; -} - -void wm8750_set_bclk_in(void *opaque, int new_hz) -{ - WM8750State *s = (WM8750State *) opaque; - - s->ext_adc_hz = new_hz; - s->ext_dac_hz = new_hz; - wm8750_clk_update(s, 1); -} - -static void wm8750_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); - - sc->init = wm8750_init; - sc->event = wm8750_event; - sc->recv = wm8750_rx; - sc->send = wm8750_tx; - dc->vmsd = &vmstate_wm8750; -} - -static const TypeInfo wm8750_info = { - .name = TYPE_WM8750, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(WM8750State), - .class_init = wm8750_class_init, -}; - -static void wm8750_register_types(void) -{ - type_register_static(&wm8750_info); -} - -type_init(wm8750_register_types) -- cgit 1.2.3-korg