X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hw%2Fac97.c;h=0f561fa5c1cadf3cf81f79c3b58eecece78b86b1;hb=07a5298c3067ed63f7d82d8c1a6f479146447289;hp=c0fd0197a028eecbbda04b64e27736f4056ec4e9;hpb=83f7d43a9ef70b1b91e465173e18c845420e931e;p=qemu.git diff --git a/hw/ac97.c b/hw/ac97.c index c0fd0197a..0f561fa5c 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -54,6 +54,8 @@ enum { 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 }; @@ -118,7 +120,6 @@ enum { #define EACS_VRA 1 #define EACS_VRM 8 -#define VOL_MASK 0x1f #define MUTE_SHIFT 15 #define REC_MASK 7 @@ -343,7 +344,7 @@ static uint16_t mixer_load (AC97LinkState *s, uint32_t i) uint16_t val = 0xffff; if (i + 2 > sizeof (s->mixer_data)) { - dolog ("mixer_store: index %d out of bounds %zd\n", + dolog ("mixer_load: index %d out of bounds %zd\n", i, sizeof (s->mixer_data)); } else { @@ -437,83 +438,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } -#ifdef USE_MIXER -static void set_volume (AC97LinkState *s, int index, - audmixerctl_t mt, uint32_t val) +static void get_volume (uint16_t vol, uint16_t mask, int inverse, + int *mute, uint8_t *lvol, uint8_t *rvol) { - int mute = (val >> MUTE_SHIFT) & 1; - uint8_t rvol = VOL_MASK - (val & VOL_MASK); - uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); - rvol = 255 * rvol / VOL_MASK; - lvol = 255 * lvol / VOL_MASK; - -#ifdef SOFT_VOLUME - if (index == AC97_Master_Volume_Mute) { - AUD_set_volume_out (s->voice_po, mute, lvol, rvol); - } - else { - AUD_set_volume (mt, &mute, &lvol, &rvol); - } -#else - AUD_set_volume (mt, &mute, &lvol, &rvol); -#endif + *mute = (vol >> MUTE_SHIFT) & 1; + *rvol = (255 * (vol & mask)) / mask; + *lvol = (255 * ((vol >> 8) & mask)) / mask; - rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); - lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); - mixer_store (s, index, val); + if (inverse) { + *rvol = 255 - *rvol; + *lvol = 255 - *lvol; + } } -static audrecsource_t ac97_to_aud_record_source (uint8_t i) +static void update_combined_volume_out (AC97LinkState *s) { - switch (i) { - case REC_MIC: - return AUD_REC_MIC; - - case REC_CD: - return AUD_REC_CD; - - case REC_VIDEO: - return AUD_REC_VIDEO; + uint8_t lvol, rvol, plvol, prvol; + int mute, pmute; - case REC_AUX: - return AUD_REC_AUX; + 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); - case REC_LINE_IN: - return AUD_REC_LINE_IN; + mute = mute | pmute; + lvol = (lvol * plvol) / 255; + rvol = (rvol * prvol) / 255; - case REC_PHONE: - return AUD_REC_PHONE; - - default: - dolog ("Unknown record source %d, using MIC\n", i); - return AUD_REC_MIC; - } + AUD_set_volume_out (s->voice_po, mute, lvol, rvol); } -static uint8_t aud_to_ac97_record_source (audrecsource_t rs) +static void update_volume_in (AC97LinkState *s) { - switch (rs) { - case AUD_REC_MIC: - return REC_MIC; - - case AUD_REC_CD: - return REC_CD; - - case AUD_REC_VIDEO: - return REC_VIDEO; + uint8_t lvol, rvol; + int mute; - case AUD_REC_AUX: - return REC_AUX; + get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, + &mute, &lvol, &rvol); - case AUD_REC_LINE_IN: - return REC_LINE_IN; - - case AUD_REC_PHONE: - return REC_PHONE; + AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); +} - default: - dolog ("Unknown audio recording source %d using MIC\n", rs); - return REC_MIC; +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; } } @@ -521,14 +504,8 @@ static void record_select (AC97LinkState *s, uint32_t val) { uint8_t rs = val & REC_MASK; uint8_t ls = (val >> 8) & REC_MASK; - audrecsource_t ars = ac97_to_aud_record_source (rs); - audrecsource_t als = ac97_to_aud_record_source (ls); - AUD_set_record_source (&als, &ars); - rs = aud_to_ac97_record_source (ars); - ls = aud_to_ac97_record_source (als); mixer_store (s, AC97_Record_Select, rs | (ls << 8)); } -#endif static void mixer_reset (AC97LinkState *s) { @@ -538,14 +515,17 @@ static void mixer_reset (AC97LinkState *s) memset (s->mixer_data, 0, sizeof (s->mixer_data)); memset (active, 0, sizeof (active)); mixer_store (s, AC97_Reset , 0x0000); /* 6940 */ - mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x8000); + mixer_store (s, AC97_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 , 0x8008); - mixer_store (s, AC97_Mic_Volume_Mute , 0x8008); - mixer_store (s, AC97_CD_Volume_Mute , 0x8808); - mixer_store (s, AC97_Aux_Volume_Mute , 0x8808); - mixer_store (s, AC97_Record_Gain_Mic_Mute , 0x8000); + mixer_store (s, AC97_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); @@ -564,12 +544,11 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); -#ifdef USE_MIXER record_select (s, 0); - set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); - set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM , 0x8808); - set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); -#endif + 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); } @@ -624,24 +603,18 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) mixer_reset (s); break; case AC97_Powerdown_Ctrl_Stat: - val &= ~0xf; + val &= ~0x800f; val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; -#ifdef USE_MIXER - case AC97_Master_Volume_Mute: - set_volume (s, index, AUD_MIXER_VOLUME, val); - break; case AC97_PCM_Out_Volume_Mute: - set_volume (s, index, AUD_MIXER_PCM, val); - break; - case AC97_Line_In_Volume_Mute: - set_volume (s, index, AUD_MIXER_LINE_IN, val); + 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; -#endif case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -698,6 +671,23 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) 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); @@ -1194,14 +1184,14 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; -#ifdef USE_MIXER record_select (s, mixer_load (s, AC97_Record_Select)); -#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) - V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); - V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); - V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); -#undef V_ -#endif + 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); @@ -1329,13 +1319,12 @@ static int ac97_initfn (PCIDevice *dev) return 0; } -static int ac97_exitfn (PCIDevice *dev) +static void ac97_exitfn (PCIDevice *dev) { AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev); memory_region_destroy (&s->io_nam); memory_region_destroy (&s->io_nabm); - return 0; } int ac97_init (PCIBus *bus)