diff options
Diffstat (limited to 'devices/src/pci/ac97.rs')
-rw-r--r-- | devices/src/pci/ac97.rs | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs index 792df24..5f59165 100644 --- a/devices/src/pci/ac97.rs +++ b/devices/src/pci/ac97.rs @@ -2,9 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +use std::default::Default; +use std::error; +use std::fmt::{self, Display}; use std::os::unix::io::RawFd; +use std::str::FromStr; -use audio_streams::shm_streams::ShmStreamSource; +use audio_streams::{ + shm_streams::{NullShmStreamSource, ShmStreamSource}, + StreamEffect, +}; +use libcras::CrasClient; use resources::{Alloc, MmioType, SystemAllocator}; use sys_util::{error, EventFd, GuestMemory}; @@ -25,6 +33,53 @@ const PCI_DEVICE_ID_INTEL_82801AA_5: u16 = 0x2415; /// Internally the `Ac97BusMaster` and `Ac97Mixer` structs are used to emulated the bus master and /// mixer registers respectively. `Ac97BusMaster` handles moving smaples between guest memory and /// the audio backend. +#[derive(Debug, Clone)] +pub enum Ac97Backend { + NULL, + CRAS, +} + +impl Default for Ac97Backend { + fn default() -> Self { + Ac97Backend::NULL + } +} + +/// Errors that are possible from a `Ac97`. +#[derive(Debug)] +pub enum Ac97Error { + InvalidBackend, +} + +impl error::Error for Ac97Error {} + +impl Display for Ac97Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Ac97Error::InvalidBackend => write!(f, "Must be cras or null"), + } + } +} + +impl FromStr for Ac97Backend { + type Err = Ac97Error; + fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { + match s { + "cras" => Ok(Ac97Backend::CRAS), + "null" => Ok(Ac97Backend::NULL), + _ => Err(Ac97Error::InvalidBackend), + } + } +} + +/// Holds the parameters for a AC97 device +#[derive(Default, Debug, Clone)] +pub struct Ac97Parameters { + pub backend: Ac97Backend, + pub capture: bool, + pub capture_effects: Vec<StreamEffect>, +} + pub struct Ac97Dev { config_regs: PciConfiguration, pci_bus_dev: Option<(u8, u8)>, @@ -61,6 +116,37 @@ impl Ac97Dev { } } + fn create_cras_audio_device(params: Ac97Parameters, mem: GuestMemory) -> Result<Ac97Dev> { + let mut server = + Box::new(CrasClient::new().map_err(|e| pci_device::Error::CreateCrasClientFailed(e))?); + if params.capture { + server.enable_cras_capture(); + } + + let mut cras_audio = Ac97Dev::new(mem, server); + cras_audio.set_capture_effects(params.capture_effects); + Ok(cras_audio) + } + + fn create_null_audio_device(mem: GuestMemory) -> Result<Ac97Dev> { + let server = Box::new(NullShmStreamSource::new()); + let null_audio = Ac97Dev::new(mem, server); + Ok(null_audio) + } + + /// Creates an 'Ac97Dev' with suitable audio server inside based on Ac97Parameters + pub fn try_new(mem: GuestMemory, param: Ac97Parameters) -> Result<Ac97Dev> { + match param.backend { + Ac97Backend::CRAS => Ac97Dev::create_cras_audio_device(param, mem), + Ac97Backend::NULL => Ac97Dev::create_null_audio_device(mem), + } + } + + /// Provides the effect needed in capture stream creation + pub fn set_capture_effects(&mut self, effect: Vec<StreamEffect>) { + self.bus_master.set_capture_effects(effect); + } + fn read_mixer(&mut self, offset: u64, data: &mut [u8]) { match data.len() { // The mixer is only accessed with 16-bit words. |