• 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 mod sys;
6 
7 use std::sync::atomic::AtomicBool;
8 use std::sync::atomic::Ordering;
9 use std::sync::Arc;
10 use std::thread;
11 use std::time::Instant;
12 
13 use audio_streams::StreamControl;
14 use base::error;
15 use base::warn;
16 use remain::sorted;
17 use sync::Condvar;
18 use sync::Mutex;
19 use thiserror::Error;
20 use vm_memory::GuestAddress;
21 use vm_memory::GuestMemory;
22 
23 use crate::pci::ac97::sys::AudioStreamSource;
24 use crate::pci::ac97_bus_master::sys::Ac97BusMasterSys;
25 pub(crate) use crate::pci::ac97_bus_master::sys::AudioError;
26 use crate::pci::ac97_mixer::Ac97Mixer;
27 use crate::pci::ac97_regs::*;
28 use crate::IrqLevelEvent;
29 
30 const INPUT_SAMPLE_RATE: u32 = 48000;
31 const DEVICE_INPUT_CHANNEL_COUNT: usize = 2;
32 
33 // Bus Master registers. Keeps the state of the bus master register values. Used to share the state
34 // between the main and audio threads.
35 struct Ac97BusMasterRegs {
36     pi_regs: Ac97FunctionRegs,       // Input
37     po_regs: Ac97FunctionRegs,       // Output
38     po_pointer_update_time: Instant, // Time the picb and civ regs were last updated.
39     mc_regs: Ac97FunctionRegs,       // Microphone
40     glob_cnt: u32,
41     glob_sta: u32,
42 
43     // IRQ event - driven by the glob_sta register.
44     irq_evt: Option<IrqLevelEvent>,
45 }
46 
47 impl Ac97BusMasterRegs {
new() -> Ac97BusMasterRegs48     fn new() -> Ac97BusMasterRegs {
49         Ac97BusMasterRegs {
50             pi_regs: Ac97FunctionRegs::new(),
51             po_regs: Ac97FunctionRegs::new(),
52             po_pointer_update_time: Instant::now(),
53             mc_regs: Ac97FunctionRegs::new(),
54             glob_cnt: 0,
55             glob_sta: GLOB_STA_RESET_VAL,
56             irq_evt: None,
57         }
58     }
59 
func_regs(&self, func: Ac97Function) -> &Ac97FunctionRegs60     fn func_regs(&self, func: Ac97Function) -> &Ac97FunctionRegs {
61         match func {
62             Ac97Function::Input => &self.pi_regs,
63             Ac97Function::Output => &self.po_regs,
64             Ac97Function::Microphone => &self.mc_regs,
65         }
66     }
67 
func_regs_mut(&mut self, func: Ac97Function) -> &mut Ac97FunctionRegs68     fn func_regs_mut(&mut self, func: Ac97Function) -> &mut Ac97FunctionRegs {
69         match func {
70             Ac97Function::Input => &mut self.pi_regs,
71             Ac97Function::Output => &mut self.po_regs,
72             Ac97Function::Microphone => &mut self.mc_regs,
73         }
74     }
75 
tube_count(&self, func: Ac97Function) -> usize76     fn tube_count(&self, func: Ac97Function) -> usize {
77         fn output_tube_count(glob_cnt: u32) -> usize {
78             let val = (glob_cnt & GLOB_CNT_PCM_246_MASK) >> 20;
79             match val {
80                 0 => 2,
81                 1 => 4,
82                 2 => 6,
83                 _ => {
84                     warn!("unknown tube_count: 0x{:x}", val);
85                     2
86                 }
87             }
88         }
89 
90         match func {
91             Ac97Function::Output => output_tube_count(self.glob_cnt),
92             _ => DEVICE_INPUT_CHANNEL_COUNT,
93         }
94     }
95 
96     /// Returns whether the irq is set for any one of the bus master function registers.
has_irq(&self) -> bool97     pub fn has_irq(&self) -> bool {
98         self.pi_regs.has_irq() || self.po_regs.has_irq() || self.mc_regs.has_irq()
99     }
100 }
101 
102 // Internal error type used for reporting errors from guest memory reading.
103 #[sorted]
104 #[derive(Error, Debug)]
105 pub(crate) enum GuestMemoryError {
106     // Failure getting the address of the audio buffer.
107     #[error("Failed to get the address of the audio buffer: {0}.")]
108     ReadingGuestBufferAddress(vm_memory::GuestMemoryError),
109 }
110 
111 impl From<GuestMemoryError> for AudioError {
from(err: GuestMemoryError) -> Self112     fn from(err: GuestMemoryError) -> Self {
113         AudioError::ReadingGuestError(err)
114     }
115 }
116 
117 type GuestMemoryResult<T> = std::result::Result<T, GuestMemoryError>;
118 
119 type AudioResult<T> = std::result::Result<T, AudioError>;
120 
121 // Audio thread book-keeping data
122 struct AudioThreadInfo {
123     thread: Option<thread::JoinHandle<()>>,
124     thread_run: Arc<AtomicBool>,
125     thread_semaphore: Arc<Condvar>,
126     stream_control: Option<Box<dyn StreamControl>>,
127 }
128 
129 impl AudioThreadInfo {
new() -> Self130     fn new() -> Self {
131         Self {
132             thread: None,
133             thread_run: Arc::new(AtomicBool::new(false)),
134             thread_semaphore: Arc::new(Condvar::new()),
135             stream_control: None,
136         }
137     }
138 
is_running(&self) -> bool139     fn is_running(&self) -> bool {
140         self.thread_run.load(Ordering::Relaxed)
141     }
142 
stop(&mut self)143     fn stop(&mut self) {
144         self.thread_run.store(false, Ordering::Relaxed);
145         self.thread_semaphore.notify_one();
146         if let Some(thread) = self.thread.take() {
147             if let Err(e) = thread.join() {
148                 error!("Failed to join thread: {:?}.", e);
149             }
150         }
151     }
152 }
153 
154 /// `Ac97BusMaster` emulates the bus master portion of AC97. It exposes a register read/write
155 /// interface compliant with the ICH bus master.
156 pub struct Ac97BusMaster {
157     // Keep guest memory as each function will use it for buffer descriptors.
158     mem: GuestMemory,
159     regs: Arc<Mutex<Ac97BusMasterRegs>>,
160     acc_sema: u8,
161 
162     // Bookkeeping info for playback and capture stream.
163     po_info: AudioThreadInfo,
164     pi_info: AudioThreadInfo,
165     pmic_info: AudioThreadInfo,
166 
167     // Audio server used to create playback or capture streams.
168     audio_server: AudioStreamSource,
169 
170     // Thread for hadlind IRQ resample events from the guest.
171     irq_resample_thread: Option<thread::JoinHandle<()>>,
172     #[cfg_attr(unix, allow(dead_code))]
173     sys: Ac97BusMasterSys,
174 }
175 
176 impl Ac97BusMaster {
177     /// Provides the events needed to raise interrupts in the guest.
set_irq_event(&mut self, irq_evt: IrqLevelEvent)178     pub fn set_irq_event(&mut self, irq_evt: IrqLevelEvent) {
179         let thread_regs = self.regs.clone();
180         self.regs.lock().irq_evt = Some(irq_evt.try_clone().expect("cloning irq_evt failed"));
181         self.irq_resample_thread = Some(thread::spawn(move || {
182             loop {
183                 if let Err(e) = irq_evt.get_resample().wait() {
184                     error!(
185                         "Failed to read the irq event from the resample thread: {}.",
186                         e,
187                     );
188                     break;
189                 }
190                 {
191                     // Scope for the lock on thread_regs.
192                     let regs = thread_regs.lock();
193                     if regs.has_irq() {
194                         if let Err(e) = irq_evt.trigger() {
195                             error!("Failed to set the irq from the resample thread: {}.", e);
196                             break;
197                         }
198                     }
199                 }
200             }
201         }));
202     }
203 
204     /// Called when `mixer` has been changed and the new values should be applied to currently
205     /// active streams.
update_mixer_settings(&mut self, mixer: &Ac97Mixer)206     pub fn update_mixer_settings(&mut self, mixer: &Ac97Mixer) {
207         if let Some(control) = self.po_info.stream_control.as_mut() {
208             // The audio server only supports one volume, not separate left and right.
209             let (muted, left_volume, _right_volume) = mixer.get_master_volume();
210             control.set_volume(left_volume);
211             control.set_mute(muted);
212         }
213     }
214 
215     /// Checks if the bus master is in the cold reset state.
is_cold_reset(&self) -> bool216     pub fn is_cold_reset(&self) -> bool {
217         self.regs.lock().glob_cnt & GLOB_CNT_COLD_RESET == 0
218     }
219 
220     /// Reads a byte from the given `offset`.
readb(&mut self, offset: u64) -> u8221     pub fn readb(&mut self, offset: u64) -> u8 {
222         fn readb_func_regs(func_regs: &Ac97FunctionRegs, offset: u64) -> u8 {
223             match offset {
224                 CIV_OFFSET => func_regs.civ,
225                 LVI_OFFSET => func_regs.lvi,
226                 SR_OFFSET => func_regs.sr as u8,
227                 PIV_OFFSET => func_regs.piv,
228                 CR_OFFSET => func_regs.cr,
229                 _ => 0,
230             }
231         }
232 
233         let regs = self.regs.lock();
234         match offset {
235             PI_BASE_00..=PI_CR_0B => readb_func_regs(&regs.pi_regs, offset - PI_BASE_00),
236             PO_BASE_10..=PO_CR_1B => readb_func_regs(&regs.po_regs, offset - PO_BASE_10),
237             MC_BASE_20..=MC_CR_2B => readb_func_regs(&regs.mc_regs, offset - MC_BASE_20),
238             ACC_SEMA_34 => self.acc_sema,
239             _ => 0,
240         }
241     }
242 
243     /// Reads a word from the given `offset`.
readw(&mut self, offset: u64, mixer: &Ac97Mixer) -> u16244     pub fn readw(&mut self, offset: u64, mixer: &Ac97Mixer) -> u16 {
245         let regs = self.regs.lock();
246         match offset {
247             PI_SR_06 => regs.pi_regs.sr,
248             PI_PICB_08 => regs.pi_regs.picb,
249             PO_SR_16 => regs.po_regs.sr,
250             PO_PICB_18 => {
251                 // PO PICB
252                 if !self.thread_info(Ac97Function::Output).is_running() {
253                     // Not running, no need to estimate what has been consumed.
254                     regs.po_regs.picb
255                 } else {
256                     // Estimate how many samples have been played since the last audio callback.
257                     let num_channels = regs.tube_count(Ac97Function::Output) as u64;
258                     let micros = regs.po_pointer_update_time.elapsed().subsec_micros();
259                     // Round down to the next 10 millisecond boundary. The linux driver often
260                     // assumes that two rapid reads from picb will return the same value.
261                     let millis = micros / 1000 / 10 * 10;
262                     let sample_rate = self.current_sample_rate(Ac97Function::Output, mixer);
263                     let frames_consumed = sample_rate as u64 * u64::from(millis) / 1000;
264 
265                     regs.po_regs
266                         .picb
267                         .saturating_sub((num_channels * frames_consumed) as u16)
268                 }
269             }
270             MC_SR_26 => regs.mc_regs.sr,
271             MC_PICB_28 => regs.mc_regs.picb,
272             _ => 0,
273         }
274     }
275 
276     /// Reads a 32-bit word from the given `offset`.
readl(&mut self, offset: u64) -> u32277     pub fn readl(&mut self, offset: u64) -> u32 {
278         let regs = self.regs.lock();
279         match offset {
280             PI_BDBAR_00 => regs.pi_regs.bdbar,
281             PI_CIV_04 => regs.pi_regs.atomic_status_regs(),
282             PO_BDBAR_10 => regs.po_regs.bdbar,
283             PO_CIV_14 => regs.po_regs.atomic_status_regs(),
284             MC_BDBAR_20 => regs.mc_regs.bdbar,
285             MC_CIV_24 => regs.mc_regs.atomic_status_regs(),
286             GLOB_CNT_2C => regs.glob_cnt,
287             GLOB_STA_30 => regs.glob_sta,
288             _ => 0,
289         }
290     }
291 
292     /// Writes the byte `val` to the register specified by `offset`.
writeb(&mut self, offset: u64, val: u8, mixer: &Ac97Mixer)293     pub fn writeb(&mut self, offset: u64, val: u8, mixer: &Ac97Mixer) {
294         // Only process writes to the control register when cold reset is set.
295         if self.is_cold_reset() {
296             return;
297         }
298 
299         match offset {
300             PI_CIV_04 => (), // RO
301             PI_LVI_05 => self.set_lvi(Ac97Function::Input, val),
302             PI_SR_06 => self.set_sr(Ac97Function::Input, u16::from(val)),
303             PI_PIV_0A => (), // RO
304             PI_CR_0B => self.set_cr(Ac97Function::Input, val, mixer),
305             PO_CIV_14 => (), // RO
306             PO_LVI_15 => self.set_lvi(Ac97Function::Output, val),
307             PO_SR_16 => self.set_sr(Ac97Function::Output, u16::from(val)),
308             PO_PIV_1A => (), // RO
309             PO_CR_1B => self.set_cr(Ac97Function::Output, val, mixer),
310             MC_CIV_24 => (), // RO
311             MC_LVI_25 => self.set_lvi(Ac97Function::Microphone, val),
312             MC_SR_26 => self.set_sr(Ac97Function::Microphone, u16::from(val)),
313             MC_PIV_2A => (), // RO
314             MC_CR_2B => self.set_cr(Ac97Function::Microphone, val, mixer),
315             ACC_SEMA_34 => self.acc_sema = val,
316             o => warn!("write byte to 0x{:x}", o),
317         }
318     }
319 
320     /// Writes the word `val` to the register specified by `offset`.
writew(&mut self, offset: u64, val: u16)321     pub fn writew(&mut self, offset: u64, val: u16) {
322         // Only process writes to the control register when cold reset is set.
323         if self.is_cold_reset() {
324             return;
325         }
326         match offset {
327             PI_SR_06 => self.set_sr(Ac97Function::Input, val),
328             PI_PICB_08 => (), // RO
329             PO_SR_16 => self.set_sr(Ac97Function::Output, val),
330             PO_PICB_18 => (), // RO
331             MC_SR_26 => self.set_sr(Ac97Function::Microphone, val),
332             MC_PICB_28 => (), // RO
333             o => warn!("write word to 0x{:x}", o),
334         }
335     }
336 
337     /// Writes the 32-bit `val` to the register specified by `offset`.
writel(&mut self, offset: u64, val: u32, mixer: &mut Ac97Mixer)338     pub fn writel(&mut self, offset: u64, val: u32, mixer: &mut Ac97Mixer) {
339         // Only process writes to the control register when cold reset is set.
340         if self.is_cold_reset() && offset != 0x2c {
341             return;
342         }
343         match offset {
344             PI_BDBAR_00 => self.set_bdbar(Ac97Function::Input, val),
345             PO_BDBAR_10 => self.set_bdbar(Ac97Function::Output, val),
346             MC_BDBAR_20 => self.set_bdbar(Ac97Function::Microphone, val),
347             GLOB_CNT_2C => self.set_glob_cnt(val, mixer),
348             GLOB_STA_30 => (), // RO
349             o => warn!("write long to 0x{:x}", o),
350         }
351     }
352 
set_bdbar(&mut self, func: Ac97Function, val: u32)353     fn set_bdbar(&mut self, func: Ac97Function, val: u32) {
354         self.regs.lock().func_regs_mut(func).bdbar = val & !0x07;
355     }
356 
set_lvi(&mut self, func: Ac97Function, val: u8)357     fn set_lvi(&mut self, func: Ac97Function, val: u8) {
358         let mut regs = self.regs.lock();
359         let func_regs = regs.func_regs_mut(func);
360         func_regs.lvi = val % 32; // LVI wraps at 32.
361 
362         // If running and stalled waiting for more valid buffers, restart by clearing the "DMA
363         // stopped" bit.
364         if func_regs.cr & CR_RPBM == CR_RPBM
365             && func_regs.sr & SR_DCH == SR_DCH
366             && func_regs.civ != func_regs.lvi
367         {
368             #[cfg(unix)]
369             Ac97BusMaster::check_and_move_to_next_buffer(func_regs);
370 
371             func_regs.sr &= !(SR_DCH | SR_CELV);
372 
373             #[cfg(unix)]
374             self.thread_semaphore_notify(func);
375         }
376     }
377 
set_sr(&mut self, func: Ac97Function, val: u16)378     fn set_sr(&mut self, func: Ac97Function, val: u16) {
379         let mut sr = self.regs.lock().func_regs(func).sr;
380         if val & SR_FIFOE != 0 {
381             sr &= !SR_FIFOE;
382         }
383         if val & SR_LVBCI != 0 {
384             sr &= !SR_LVBCI;
385         }
386         if val & SR_BCIS != 0 {
387             sr &= !SR_BCIS;
388         }
389         update_sr(&mut self.regs.lock(), func, sr);
390     }
391 
set_cr(&mut self, func: Ac97Function, val: u8, mixer: &Ac97Mixer)392     fn set_cr(&mut self, func: Ac97Function, val: u8, mixer: &Ac97Mixer) {
393         if val & CR_RR != 0 {
394             let mut regs = self.regs.lock();
395             Self::reset_func_regs(&mut regs, func);
396         } else {
397             let cr = self.regs.lock().func_regs(func).cr;
398             if val & CR_RPBM == 0 {
399                 // Run/Pause set to pause.
400                 self.thread_info_mut(func).stop();
401                 let mut regs = self.regs.lock();
402                 regs.func_regs_mut(func).sr |= SR_DCH;
403             } else if cr & CR_RPBM == 0 {
404                 // Not already running.
405                 // Run/Pause set to run.
406                 {
407                     let mut regs = self.regs.lock();
408                     let func_regs = regs.func_regs_mut(func);
409                     func_regs.piv = 1;
410                     func_regs.civ = 0;
411                     func_regs.sr &= !SR_DCH;
412                 }
413                 if let Err(e) = self.start_audio(func, mixer) {
414                     warn!("Failed to start audio: {}", e);
415                 }
416             }
417             let mut regs = self.regs.lock();
418             regs.func_regs_mut(func).cr = val & CR_VALID_MASK;
419         }
420     }
421 
set_glob_cnt(&mut self, new_glob_cnt: u32, mixer: &mut Ac97Mixer)422     fn set_glob_cnt(&mut self, new_glob_cnt: u32, mixer: &mut Ac97Mixer) {
423         // Only the reset bits are emulated, the GPI and PCM formatting are not supported.
424         if new_glob_cnt & GLOB_CNT_COLD_RESET == 0 {
425             self.reset_audio_regs();
426             mixer.reset();
427             let mut regs = self.regs.lock();
428             regs.glob_cnt = new_glob_cnt & GLOB_CNT_STABLE_BITS;
429             self.acc_sema = 0;
430             return;
431         }
432         if new_glob_cnt & GLOB_CNT_WARM_RESET != 0 {
433             // Check if running and if so, ignore. Warm reset is specified to no-op when the device
434             // is playing or recording audio.
435             if !self.is_audio_running() {
436                 self.stop_all_audio();
437                 let mut regs = self.regs.lock();
438                 regs.glob_cnt = new_glob_cnt & !GLOB_CNT_WARM_RESET; // Auto-cleared reset bit.
439                 return;
440             }
441         }
442         self.regs.lock().glob_cnt = new_glob_cnt;
443     }
444 
current_sample_rate(&self, func: Ac97Function, mixer: &Ac97Mixer) -> u32445     fn current_sample_rate(&self, func: Ac97Function, mixer: &Ac97Mixer) -> u32 {
446         match func {
447             Ac97Function::Output => mixer.get_sample_rate().into(),
448             _ => INPUT_SAMPLE_RATE,
449         }
450     }
451 
thread_info(&self, func: Ac97Function) -> &AudioThreadInfo452     fn thread_info(&self, func: Ac97Function) -> &AudioThreadInfo {
453         match func {
454             Ac97Function::Microphone => &self.pmic_info,
455             Ac97Function::Input => &self.pi_info,
456             Ac97Function::Output => &self.po_info,
457         }
458     }
459 
thread_info_mut(&mut self, func: Ac97Function) -> &mut AudioThreadInfo460     fn thread_info_mut(&mut self, func: Ac97Function) -> &mut AudioThreadInfo {
461         match func {
462             Ac97Function::Microphone => &mut self.pmic_info,
463             Ac97Function::Input => &mut self.pi_info,
464             Ac97Function::Output => &mut self.po_info,
465         }
466     }
467 
is_audio_running(&self) -> bool468     fn is_audio_running(&self) -> bool {
469         self.thread_info(Ac97Function::Output).is_running()
470             || self.thread_info(Ac97Function::Input).is_running()
471             || self.thread_info(Ac97Function::Microphone).is_running()
472     }
473 
stop_all_audio(&mut self)474     fn stop_all_audio(&mut self) {
475         self.thread_info_mut(Ac97Function::Input).stop();
476         self.thread_info_mut(Ac97Function::Output).stop();
477         self.thread_info_mut(Ac97Function::Microphone).stop();
478     }
479 
480     // Helper function for resetting function registers.
reset_func_regs(regs: &mut Ac97BusMasterRegs, func: Ac97Function)481     fn reset_func_regs(regs: &mut Ac97BusMasterRegs, func: Ac97Function) {
482         regs.func_regs_mut(func).do_reset();
483         update_sr(regs, func, SR_DCH);
484     }
485 
reset_audio_regs(&mut self)486     fn reset_audio_regs(&mut self) {
487         self.stop_all_audio();
488         let mut regs = self.regs.lock();
489         Self::reset_func_regs(&mut regs, Ac97Function::Input);
490         Self::reset_func_regs(&mut regs, Ac97Function::Output);
491         Self::reset_func_regs(&mut regs, Ac97Function::Microphone);
492     }
493 }
494 
get_buffer_samples( func_regs: &Ac97FunctionRegs, mem: &GuestMemory, index: u8, ) -> GuestMemoryResult<usize>495 fn get_buffer_samples(
496     func_regs: &Ac97FunctionRegs,
497     mem: &GuestMemory,
498     index: u8,
499 ) -> GuestMemoryResult<usize> {
500     let descriptor_addr = func_regs.bdbar + u32::from(index) * DESCRIPTOR_LENGTH as u32;
501     let control_reg: u32 = mem
502         .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr) + 4))
503         .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
504     let buffer_samples = control_reg as usize & 0x0000_ffff;
505     Ok(buffer_samples)
506 }
507 
508 // Marks the current buffer completed and moves to the next buffer for the given
509 // function and registers.
buffer_completed( regs: &mut Ac97BusMasterRegs, mem: &GuestMemory, func: Ac97Function, ) -> AudioResult<()>510 fn buffer_completed(
511     regs: &mut Ac97BusMasterRegs,
512     mem: &GuestMemory,
513     func: Ac97Function,
514 ) -> AudioResult<()> {
515     // check if the completed descriptor wanted an interrupt on completion.
516     let civ = regs.func_regs(func).civ;
517     let descriptor_addr = regs.func_regs(func).bdbar + u32::from(civ) * DESCRIPTOR_LENGTH as u32;
518     let control_reg: u32 = mem
519         .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr) + 4))
520         .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
521 
522     let mut new_sr = regs.func_regs(func).sr & !SR_CELV;
523     if control_reg & BD_IOC != 0 {
524         new_sr |= SR_BCIS;
525     }
526 
527     let lvi = regs.func_regs(func).lvi;
528     // if the current buffer was the last valid buffer, then update the status register to
529     // indicate that the end of audio was hit and possibly raise an interrupt.
530     if civ == lvi {
531         new_sr |= SR_DCH | SR_CELV | SR_LVBCI;
532     } else {
533         regs.func_regs_mut(func).move_to_next_buffer();
534     }
535 
536     update_sr(regs, func, new_sr);
537 
538     regs.func_regs_mut(func).picb = current_buffer_size(regs.func_regs(func), mem)? as u16;
539     if func == Ac97Function::Output {
540         regs.po_pointer_update_time = Instant::now();
541     }
542 
543     Ok(())
544 }
545 
546 // Update the status register and if any interrupts need to fire, raise them.
update_sr(regs: &mut Ac97BusMasterRegs, func: Ac97Function, val: u16)547 fn update_sr(regs: &mut Ac97BusMasterRegs, func: Ac97Function, val: u16) {
548     let int_mask = match func {
549         Ac97Function::Input => GS_PIINT,
550         Ac97Function::Output => GS_POINT,
551         Ac97Function::Microphone => GS_MINT,
552     };
553 
554     let mut interrupt_high = false;
555 
556     {
557         let func_regs = regs.func_regs_mut(func);
558         let old_sr = func_regs.sr;
559         func_regs.sr = val;
560         if (old_sr ^ val) & SR_INT_MASK != 0 {
561             if (val & SR_LVBCI) != 0 && (func_regs.cr & CR_LVBIE) != 0 {
562                 interrupt_high = true;
563             }
564             if (val & SR_BCIS) != 0 && (func_regs.cr & CR_IOCE) != 0 {
565                 interrupt_high = true;
566             }
567         } else {
568             return;
569         }
570     }
571 
572     if interrupt_high {
573         regs.glob_sta |= int_mask;
574         if let Some(ref irq_evt) = regs.irq_evt {
575             // Ignore write failure, nothing can be done about it from here.
576             let _ = irq_evt.trigger();
577         }
578     } else {
579         regs.glob_sta &= !int_mask;
580     }
581 }
582 
583 // Returns the size in samples of the buffer pointed to by the CIV register.
current_buffer_size( func_regs: &Ac97FunctionRegs, mem: &GuestMemory, ) -> GuestMemoryResult<usize>584 fn current_buffer_size(
585     func_regs: &Ac97FunctionRegs,
586     mem: &GuestMemory,
587 ) -> GuestMemoryResult<usize> {
588     let civ = func_regs.civ;
589     get_buffer_samples(func_regs, mem, civ)
590 }
591 
592 #[cfg(test)]
593 mod tests {
594 
595     use super::*;
596 
597     #[cfg(unix)]
new_mock_ac97_bus_master() -> Ac97BusMaster598     fn new_mock_ac97_bus_master() -> Ac97BusMaster {
599         Ac97BusMaster::new(
600             GuestMemory::new(&[]).expect("Creating guest memory failed."),
601             Box::new(audio_streams::shm_streams::MockShmStreamSource::new()),
602         )
603     }
604 
605     #[cfg(windows)]
new_mock_ac97_bus_master() -> Ac97BusMaster606     fn new_mock_ac97_bus_master() -> Ac97BusMaster {
607         let memory_start_addr = GuestAddress(0x0);
608         Ac97BusMaster::new(
609             GuestMemory::new(&[(memory_start_addr, 0x1000)])
610                 .expect("Creating guest memory failed."),
611             Arc::new(Mutex::new(audio_streams::NoopStreamSource::new())),
612             None,
613         )
614     }
615 
616     #[test]
bm_bdbar()617     fn bm_bdbar() {
618         let mut bm = new_mock_ac97_bus_master();
619         let mut mixer = Ac97Mixer::new();
620 
621         let bdbars = [0x00u64, 0x10, 0x20];
622 
623         // Make sure writes have no affect during cold reset.
624         bm.writel(0x00, 0x5555_555f, &mut mixer);
625         assert_eq!(bm.readl(0x00), 0x0000_0000);
626 
627         // Relesase cold reset.
628         bm.writel(GLOB_CNT_2C, 0x0000_0002, &mut mixer);
629 
630         // Tests that the base address is writable and that the bottom three bits are read only.
631         for bdbar in &bdbars {
632             assert_eq!(bm.readl(*bdbar), 0x0000_0000);
633             bm.writel(*bdbar, 0x5555_555f, &mut mixer);
634             assert_eq!(bm.readl(*bdbar), 0x5555_5558);
635         }
636     }
637 
638     #[test]
bm_status_reg()639     fn bm_status_reg() {
640         let mut bm = new_mock_ac97_bus_master();
641         let mixer = Ac97Mixer::new();
642 
643         let sr_addrs = [0x06u64, 0x16, 0x26];
644 
645         for sr in &sr_addrs {
646             assert_eq!(bm.readw(*sr, &mixer), 0x0001);
647             bm.writew(*sr, 0xffff);
648             assert_eq!(bm.readw(*sr, &mixer), 0x0001);
649         }
650     }
651 
652     #[test]
bm_global_control()653     fn bm_global_control() {
654         let mut bm = new_mock_ac97_bus_master();
655         let mut mixer = Ac97Mixer::new();
656 
657         assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0000);
658 
659         // Relesase cold reset.
660         bm.writel(GLOB_CNT_2C, 0x0000_0002, &mut mixer);
661 
662         // Check interrupt enable bits are writable.
663         bm.writel(GLOB_CNT_2C, 0x0000_0072, &mut mixer);
664         assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0072);
665 
666         // A Warm reset should doesn't affect register state and is auto cleared.
667         bm.writel(0x00, 0x5555_5558, &mut mixer);
668         bm.writel(GLOB_CNT_2C, 0x0000_0076, &mut mixer);
669         assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0072);
670         assert_eq!(bm.readl(0x00), 0x5555_5558);
671         // Check that a cold reset works, but setting bdbar and checking it is zeroed.
672         bm.writel(0x00, 0x5555_555f, &mut mixer);
673         bm.writel(GLOB_CNT_2C, 0x000_0070, &mut mixer);
674         assert_eq!(bm.readl(GLOB_CNT_2C), 0x0000_0070);
675         assert_eq!(bm.readl(0x00), 0x0000_0000);
676     }
677 
playback_release_cold_reset_and_setup_ping_pong_buffers( bdbar: u64, mixer: &mut Ac97Mixer, bm: &mut Ac97BusMaster, mem: &GuestMemory, num_buffers: usize, guest_addr_base: u32, fragment_size: usize, lvi_mask: u8, ioc_mask: u32, )678     pub(super) fn playback_release_cold_reset_and_setup_ping_pong_buffers(
679         bdbar: u64,
680         mixer: &mut Ac97Mixer,
681         bm: &mut Ac97BusMaster,
682         mem: &GuestMemory,
683         num_buffers: usize,
684         guest_addr_base: u32,
685         fragment_size: usize,
686         lvi_mask: u8,
687         ioc_mask: u32,
688     ) {
689         // Release cold reset.
690         bm.writel(GLOB_CNT_2C, 0x0000_0002, mixer);
691         // Setup ping-pong buffers. A and B repeating for every possible index.
692         bm.writel(bdbar, guest_addr_base, mixer);
693         for i in 0..num_buffers {
694             let pointer_addr = GuestAddress(guest_addr_base as u64 + i as u64 * 8);
695             let control_addr = GuestAddress(guest_addr_base as u64 + i as u64 * 8 + 4);
696             if i % 2 == 0 {
697                 mem.write_obj_at_addr(guest_addr_base, pointer_addr)
698                     .expect("Writing guest memory failed.");
699             } else {
700                 mem.write_obj_at_addr(guest_addr_base + fragment_size as u32, pointer_addr)
701                     .expect("Writing guest memory failed.");
702             };
703             mem.write_obj_at_addr(ioc_mask | ((fragment_size as u32) / 2), control_addr)
704                 .expect("Writing guest memory failed.");
705         }
706         bm.writeb(bdbar + LVI_OFFSET, lvi_mask, mixer);
707     }
708 
capture_release_cold_reset_and_setup_ping_pong_buffers( base: u64, mixer: &mut Ac97Mixer, bm: &mut Ac97BusMaster, mem: &GuestMemory, num_buffers: usize, guest_addr_base: u32, fragment_size: usize, lvi_mask: u8, ioc_mask: u32, )709     pub(super) fn capture_release_cold_reset_and_setup_ping_pong_buffers(
710         base: u64,
711         mixer: &mut Ac97Mixer,
712         bm: &mut Ac97BusMaster,
713         mem: &GuestMemory,
714         num_buffers: usize,
715         guest_addr_base: u32,
716         fragment_size: usize,
717         lvi_mask: u8,
718         ioc_mask: u32,
719     ) {
720         // Release cold reset.
721         bm.writel(GLOB_CNT_2C, 0x0000_0002, mixer);
722 
723         // Setup ping-pong buffers.
724         bm.writel(base, guest_addr_base, mixer);
725         for i in 0..num_buffers {
726             let pointer_addr = GuestAddress(guest_addr_base as u64 + i as u64 * 8);
727             let control_addr = GuestAddress(guest_addr_base as u64 + i as u64 * 8 + 4);
728             mem.write_obj_at_addr(guest_addr_base + fragment_size as u32, pointer_addr)
729                 .expect("Writing guest memory failed.");
730             mem.write_obj_at_addr(ioc_mask | ((fragment_size as u32) / 2), control_addr)
731                 .expect("Writing guest memory failed.");
732         }
733 
734         bm.writeb(base + LVI_OFFSET, lvi_mask, mixer);
735     }
736 
check_buffer_set_and_clear_bcis( base: u64, mixer: &Ac97Mixer, bm: &mut Ac97BusMaster, )737     pub(super) fn check_buffer_set_and_clear_bcis(
738         base: u64,
739         mixer: &Ac97Mixer,
740         bm: &mut Ac97BusMaster,
741     ) {
742         // Buffer complete should be set as the IOC bit was set in the descriptor.
743         assert!(bm.readw(base + SR_OFFSET, mixer) & SR_BCIS != 0);
744         // Clear the BCIS bit
745         bm.writew(base + SR_OFFSET, SR_BCIS);
746         assert!(bm.readw(base + SR_OFFSET, mixer) & SR_BCIS == 0);
747     }
748 
clear_lvb_and_reset_lvi( base: u64, mixer: &Ac97Mixer, bm: &mut Ac97BusMaster, lvi_mask: u8, )749     pub(super) fn clear_lvb_and_reset_lvi(
750         base: u64,
751         mixer: &Ac97Mixer,
752         bm: &mut Ac97BusMaster,
753         lvi_mask: u8,
754     ) {
755         // Clear the LVB bit
756         bm.writeb(base + SR_OFFSET, SR_LVBCI as u8, mixer);
757         assert!(bm.readw(base + SR_OFFSET, mixer) & SR_LVBCI == 0);
758         // Reset the LVI to the last buffer and check that playback resumes
759         bm.writeb(base + LVI_OFFSET, lvi_mask, mixer);
760         assert!(bm.readw(base + SR_OFFSET, mixer) & SR_DCH == 0); // DMA restarts.
761         assert_eq!(bm.readw(base + SR_OFFSET, mixer) & SR_CELV, 0);
762     }
763 
stop(base: u64, int_mask: u32, mixer: &Ac97Mixer, bm: &mut Ac97BusMaster)764     pub(super) fn stop(base: u64, int_mask: u32, mixer: &Ac97Mixer, bm: &mut Ac97BusMaster) {
765         // Stop.
766         bm.writeb(base + CR_OFFSET, 0, mixer);
767         assert!(bm.readw(base + SR_OFFSET, mixer) & 0x01 != 0); // DMA is not running.
768         bm.writeb(base + CR_OFFSET, CR_RR, mixer);
769         assert!(
770             bm.readl(GLOB_STA_30) & int_mask == 0,
771             "POINT bit should be disabled."
772         );
773     }
774 }
775