// Copyright 2018 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. use crate::pci::ac97_regs::*; // AC97 Vendor ID const AC97_VENDOR_ID1: u16 = 0x8086; const AC97_VENDOR_ID2: u16 = 0x8086; // Extented Audio ID const AC97_EXTENDED_ID: u16 = MIXER_EI_VRA | MIXER_EI_CDAC | MIXER_EI_SDAC | MIXER_EI_LDAC; // Master volume register is specified in 1.5dB steps. const MASTER_VOLUME_STEP_DB: f64 = 1.5; /// `Ac97Mixer` holds the mixer state for the AC97 bus. /// The mixer is used by calling the `readb`/`readw`/`readl` functions to read register values and /// the `writeb`/`writew`/`writel` functions to set register values. pub struct Ac97Mixer { // Mixer Registers master_volume_l: u8, master_volume_r: u8, master_mute: bool, mic_muted: bool, mic_20db: bool, mic_volume: u8, record_gain_l: u8, record_gain_r: u8, record_gain_mute: bool, pcm_out_vol_l: u16, pcm_out_vol_r: u16, pcm_out_mute: bool, power_down_control: u16, ext_audio_status_ctl: u16, pcm_front_dac_rate: u16, pcm_surr_dac_rate: u16, pcm_lfe_dac_rate: u16, } impl Ac97Mixer { /// Creates an 'Ac97Mixer' with the standard default register values. pub fn new() -> Self { Ac97Mixer { master_volume_l: 0, master_volume_r: 0, master_mute: true, mic_muted: true, mic_20db: false, mic_volume: 0x8, record_gain_l: 0, record_gain_r: 0, record_gain_mute: true, pcm_out_vol_l: 0x8, pcm_out_vol_r: 0x8, pcm_out_mute: true, power_down_control: PD_REG_STATUS_MASK, // Report everything is ready. ext_audio_status_ctl: 0, // Default to 48 kHz. pcm_front_dac_rate: 0xBB80, pcm_surr_dac_rate: 0xBB80, pcm_lfe_dac_rate: 0xBB80, } } pub fn reset(&mut self) { // Upon reset, the audio sample rate registers default to 48 kHz, and VRA=0. self.ext_audio_status_ctl &= !MIXER_EI_VRA; self.pcm_front_dac_rate = 0xBB80; self.pcm_surr_dac_rate = 0xBB80; self.pcm_lfe_dac_rate = 0xBB80; } /// Reads a word from the register at `offset`. pub fn readw(&self, offset: u64) -> u16 { match offset { MIXER_RESET_00 => BC_DEDICATED_MIC, MIXER_MASTER_VOL_MUTE_02 => self.get_master_reg(), MIXER_MIC_VOL_MUTE_0E => self.get_mic_volume(), MIXER_PCM_OUT_VOL_MUTE_18 => self.get_pcm_out_volume(), MIXER_REC_VOL_MUTE_1C => self.get_record_gain_reg(), MIXER_POWER_DOWN_CONTROL_26 => self.power_down_control, MIXER_EXTENDED_AUDIO_ID_28 => AC97_EXTENDED_ID, MIXER_VENDOR_ID1_7C => AC97_VENDOR_ID1, MIXER_VENDOR_ID2_7E => AC97_VENDOR_ID2, MIXER_EXTENDED_AUDIO_STATUS_CONTROL_28 => self.ext_audio_status_ctl, MIXER_PCM_FRONT_DAC_RATE_2C => self.pcm_front_dac_rate, MIXER_PCM_SURR_DAC_RATE_2E => self.pcm_surr_dac_rate, MIXER_PCM_LFE_DAC_RATE_30 => self.pcm_lfe_dac_rate, _ => 0, } } /// Writes a word `val` to the register `offset`. pub fn writew(&mut self, offset: u64, val: u16) { match offset { MIXER_RESET_00 => self.reset(), MIXER_MASTER_VOL_MUTE_02 => self.set_master_reg(val), MIXER_MIC_VOL_MUTE_0E => self.set_mic_volume(val), MIXER_PCM_OUT_VOL_MUTE_18 => self.set_pcm_out_volume(val), MIXER_REC_VOL_MUTE_1C => self.set_record_gain_reg(val), MIXER_POWER_DOWN_CONTROL_26 => self.set_power_down_reg(val), MIXER_EXTENDED_AUDIO_STATUS_CONTROL_28 => self.ext_audio_status_ctl = val, MIXER_PCM_FRONT_DAC_RATE_2C => self.pcm_front_dac_rate = val, MIXER_PCM_SURR_DAC_RATE_2E => self.pcm_surr_dac_rate = val, MIXER_PCM_LFE_DAC_RATE_30 => self.pcm_lfe_dac_rate = val, _ => (), } } /// Returns the mute status and left and right attenuation from the master volume register. pub fn get_master_volume(&self) -> (bool, f64, f64) { ( self.master_mute, f64::from(self.master_volume_l) * MASTER_VOLUME_STEP_DB, f64::from(self.master_volume_r) * MASTER_VOLUME_STEP_DB, ) } /// Returns the front sample rate (reg 0x2c). pub fn get_sample_rate(&self) -> u16 { // MIXER_PCM_FRONT_DAC_RATE_2C, MIXER_PCM_SURR_DAC_RATE_2E, and MIXER_PCM_LFE_DAC_RATE_30 // are updated to the same rate when playback with 2,4 and 6 tubes. self.pcm_front_dac_rate } // Returns the master mute and l/r volumes (reg 0x02). fn get_master_reg(&self) -> u16 { let reg = (u16::from(self.master_volume_l)) << 8 | u16::from(self.master_volume_r); if self.master_mute { reg | MUTE_REG_BIT } else { reg } } // Handles writes to the master register (0x02). fn set_master_reg(&mut self, val: u16) { self.master_mute = val & MUTE_REG_BIT != 0; self.master_volume_r = (val & VOL_REG_MASK) as u8; self.master_volume_l = (val >> 8 & VOL_REG_MASK) as u8; } // Returns the value read in the Mic volume register (0x0e). fn get_mic_volume(&self) -> u16 { let mut reg = u16::from(self.mic_volume); if self.mic_muted { reg |= MUTE_REG_BIT; } if self.mic_20db { reg |= MIXER_MIC_20DB; } reg } // Sets the mic input mute, boost, and volume settings (0x0e). fn set_mic_volume(&mut self, val: u16) { self.mic_volume = (val & MIXER_VOL_MASK) as u8; self.mic_muted = val & MUTE_REG_BIT != 0; self.mic_20db = val & MIXER_MIC_20DB != 0; } // Returns the value read in the Mic volume register (0x18). fn get_pcm_out_volume(&self) -> u16 { let reg = (self.pcm_out_vol_l as u16) << 8 | self.pcm_out_vol_r as u16; if self.pcm_out_mute { reg | MUTE_REG_BIT } else { reg } } // Sets the pcm output mute and volume states (0x18). fn set_pcm_out_volume(&mut self, val: u16) { self.pcm_out_vol_r = val & MIXER_VOL_MASK; self.pcm_out_vol_l = (val >> MIXER_VOL_LEFT_SHIFT) & MIXER_VOL_MASK; self.pcm_out_mute = val & MUTE_REG_BIT != 0; } // Returns the record gain register (0x01c). fn get_record_gain_reg(&self) -> u16 { let reg = u16::from(self.record_gain_l) << 8 | u16::from(self.record_gain_r); if self.record_gain_mute { reg | MUTE_REG_BIT } else { reg } } // Handles writes to the record_gain register (0x1c). fn set_record_gain_reg(&mut self, val: u16) { self.record_gain_mute = val & MUTE_REG_BIT != 0; self.record_gain_r = (val & VOL_REG_MASK) as u8; self.record_gain_l = (val >> 8 & VOL_REG_MASK) as u8; } // Handles writes to the powerdown ctrl/status register (0x26). fn set_power_down_reg(&mut self, val: u16) { self.power_down_control = (val & !PD_REG_STATUS_MASK) | (self.power_down_control & PD_REG_STATUS_MASK); } }