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