1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use crate::pci::ac97_regs::*; 6 7 // AC97 Vendor ID 8 const AC97_VENDOR_ID1: u16 = 0x8086; 9 const AC97_VENDOR_ID2: u16 = 0x8086; 10 // Extented Audio ID 11 const AC97_EXTENDED_ID: u16 = MIXER_EI_VRA | MIXER_EI_CDAC | MIXER_EI_SDAC | MIXER_EI_LDAC; 12 13 // Master volume register is specified in 1.5dB steps. 14 const MASTER_VOLUME_STEP_DB: f64 = 1.5; 15 16 /// `Ac97Mixer` holds the mixer state for the AC97 bus. 17 /// The mixer is used by calling the `readb`/`readw`/`readl` functions to read register values and 18 /// the `writeb`/`writew`/`writel` functions to set register values. 19 pub struct Ac97Mixer { 20 // Mixer Registers 21 master_volume_l: u8, 22 master_volume_r: u8, 23 master_mute: bool, 24 mic_muted: bool, 25 mic_20db: bool, 26 mic_volume: u8, 27 record_gain_l: u8, 28 record_gain_r: u8, 29 record_gain_mute: bool, 30 pcm_out_vol_l: u16, 31 pcm_out_vol_r: u16, 32 pcm_out_mute: bool, 33 power_down_control: u16, 34 ext_audio_status_ctl: u16, 35 pcm_front_dac_rate: u16, 36 pcm_surr_dac_rate: u16, 37 pcm_lfe_dac_rate: u16, 38 } 39 40 impl Ac97Mixer { 41 /// Creates an 'Ac97Mixer' with the standard default register values. new() -> Self42 pub fn new() -> Self { 43 Ac97Mixer { 44 master_volume_l: 0, 45 master_volume_r: 0, 46 master_mute: true, 47 mic_muted: true, 48 mic_20db: false, 49 mic_volume: 0x8, 50 record_gain_l: 0, 51 record_gain_r: 0, 52 record_gain_mute: true, 53 pcm_out_vol_l: 0x8, 54 pcm_out_vol_r: 0x8, 55 pcm_out_mute: true, 56 power_down_control: PD_REG_STATUS_MASK, // Report everything is ready. 57 ext_audio_status_ctl: 0, 58 // Default to 48 kHz. 59 pcm_front_dac_rate: 0xBB80, 60 pcm_surr_dac_rate: 0xBB80, 61 pcm_lfe_dac_rate: 0xBB80, 62 } 63 } 64 reset(&mut self)65 pub fn reset(&mut self) { 66 // Upon reset, the audio sample rate registers default to 48 kHz, and VRA=0. 67 self.ext_audio_status_ctl &= !MIXER_EI_VRA; 68 self.pcm_front_dac_rate = 0xBB80; 69 self.pcm_surr_dac_rate = 0xBB80; 70 self.pcm_lfe_dac_rate = 0xBB80; 71 } 72 73 /// Reads a word from the register at `offset`. readw(&self, offset: u64) -> u1674 pub fn readw(&self, offset: u64) -> u16 { 75 match offset { 76 MIXER_RESET_00 => BC_DEDICATED_MIC, 77 MIXER_MASTER_VOL_MUTE_02 => self.get_master_reg(), 78 MIXER_MIC_VOL_MUTE_0E => self.get_mic_volume(), 79 MIXER_PCM_OUT_VOL_MUTE_18 => self.get_pcm_out_volume(), 80 MIXER_REC_VOL_MUTE_1C => self.get_record_gain_reg(), 81 MIXER_POWER_DOWN_CONTROL_26 => self.power_down_control, 82 MIXER_EXTENDED_AUDIO_ID_28 => AC97_EXTENDED_ID, 83 MIXER_VENDOR_ID1_7C => AC97_VENDOR_ID1, 84 MIXER_VENDOR_ID2_7E => AC97_VENDOR_ID2, 85 MIXER_EXTENDED_AUDIO_STATUS_CONTROL_28 => self.ext_audio_status_ctl, 86 MIXER_PCM_FRONT_DAC_RATE_2C => self.pcm_front_dac_rate, 87 MIXER_PCM_SURR_DAC_RATE_2E => self.pcm_surr_dac_rate, 88 MIXER_PCM_LFE_DAC_RATE_30 => self.pcm_lfe_dac_rate, 89 _ => 0, 90 } 91 } 92 93 /// Writes a word `val` to the register `offset`. writew(&mut self, offset: u64, val: u16)94 pub fn writew(&mut self, offset: u64, val: u16) { 95 match offset { 96 MIXER_RESET_00 => self.reset(), 97 MIXER_MASTER_VOL_MUTE_02 => self.set_master_reg(val), 98 MIXER_MIC_VOL_MUTE_0E => self.set_mic_volume(val), 99 MIXER_PCM_OUT_VOL_MUTE_18 => self.set_pcm_out_volume(val), 100 MIXER_REC_VOL_MUTE_1C => self.set_record_gain_reg(val), 101 MIXER_POWER_DOWN_CONTROL_26 => self.set_power_down_reg(val), 102 MIXER_EXTENDED_AUDIO_STATUS_CONTROL_28 => self.ext_audio_status_ctl = val, 103 MIXER_PCM_FRONT_DAC_RATE_2C => self.pcm_front_dac_rate = val, 104 MIXER_PCM_SURR_DAC_RATE_2E => self.pcm_surr_dac_rate = val, 105 MIXER_PCM_LFE_DAC_RATE_30 => self.pcm_lfe_dac_rate = val, 106 _ => (), 107 } 108 } 109 110 /// Returns the mute status and left and right attenuation from the master volume register. get_master_volume(&self) -> (bool, f64, f64)111 pub fn get_master_volume(&self) -> (bool, f64, f64) { 112 ( 113 self.master_mute, 114 f64::from(self.master_volume_l) * MASTER_VOLUME_STEP_DB, 115 f64::from(self.master_volume_r) * MASTER_VOLUME_STEP_DB, 116 ) 117 } 118 119 /// Returns the front sample rate (reg 0x2c). get_sample_rate(&self) -> u16120 pub fn get_sample_rate(&self) -> u16 { 121 // MIXER_PCM_FRONT_DAC_RATE_2C, MIXER_PCM_SURR_DAC_RATE_2E, and MIXER_PCM_LFE_DAC_RATE_30 122 // are updated to the same rate when playback with 2,4 and 6 tubes. 123 self.pcm_front_dac_rate 124 } 125 126 // Returns the master mute and l/r volumes (reg 0x02). get_master_reg(&self) -> u16127 fn get_master_reg(&self) -> u16 { 128 let reg = (u16::from(self.master_volume_l)) << 8 | u16::from(self.master_volume_r); 129 if self.master_mute { 130 reg | MUTE_REG_BIT 131 } else { 132 reg 133 } 134 } 135 136 // Handles writes to the master register (0x02). set_master_reg(&mut self, val: u16)137 fn set_master_reg(&mut self, val: u16) { 138 self.master_mute = val & MUTE_REG_BIT != 0; 139 self.master_volume_r = (val & VOL_REG_MASK) as u8; 140 self.master_volume_l = (val >> 8 & VOL_REG_MASK) as u8; 141 } 142 143 // Returns the value read in the Mic volume register (0x0e). get_mic_volume(&self) -> u16144 fn get_mic_volume(&self) -> u16 { 145 let mut reg = u16::from(self.mic_volume); 146 if self.mic_muted { 147 reg |= MUTE_REG_BIT; 148 } 149 if self.mic_20db { 150 reg |= MIXER_MIC_20DB; 151 } 152 reg 153 } 154 155 // Sets the mic input mute, boost, and volume settings (0x0e). set_mic_volume(&mut self, val: u16)156 fn set_mic_volume(&mut self, val: u16) { 157 self.mic_volume = (val & MIXER_VOL_MASK) as u8; 158 self.mic_muted = val & MUTE_REG_BIT != 0; 159 self.mic_20db = val & MIXER_MIC_20DB != 0; 160 } 161 162 // Returns the value read in the Mic volume register (0x18). get_pcm_out_volume(&self) -> u16163 fn get_pcm_out_volume(&self) -> u16 { 164 let reg = (self.pcm_out_vol_l as u16) << 8 | self.pcm_out_vol_r as u16; 165 if self.pcm_out_mute { 166 reg | MUTE_REG_BIT 167 } else { 168 reg 169 } 170 } 171 172 // Sets the pcm output mute and volume states (0x18). set_pcm_out_volume(&mut self, val: u16)173 fn set_pcm_out_volume(&mut self, val: u16) { 174 self.pcm_out_vol_r = val & MIXER_VOL_MASK; 175 self.pcm_out_vol_l = (val >> MIXER_VOL_LEFT_SHIFT) & MIXER_VOL_MASK; 176 self.pcm_out_mute = val & MUTE_REG_BIT != 0; 177 } 178 179 // Returns the record gain register (0x01c). get_record_gain_reg(&self) -> u16180 fn get_record_gain_reg(&self) -> u16 { 181 let reg = u16::from(self.record_gain_l) << 8 | u16::from(self.record_gain_r); 182 if self.record_gain_mute { 183 reg | MUTE_REG_BIT 184 } else { 185 reg 186 } 187 } 188 189 // Handles writes to the record_gain register (0x1c). set_record_gain_reg(&mut self, val: u16)190 fn set_record_gain_reg(&mut self, val: u16) { 191 self.record_gain_mute = val & MUTE_REG_BIT != 0; 192 self.record_gain_r = (val & VOL_REG_MASK) as u8; 193 self.record_gain_l = (val >> 8 & VOL_REG_MASK) as u8; 194 } 195 196 // Handles writes to the powerdown ctrl/status register (0x26). set_power_down_reg(&mut self, val: u16)197 fn set_power_down_reg(&mut self, val: u16) { 198 self.power_down_control = 199 (val & !PD_REG_STATUS_MASK) | (self.power_down_control & PD_REG_STATUS_MASK); 200 } 201 } 202