Red Bear OS base baseline from 0.1.0 pre-patched archive
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "ihdad"
|
||||
description = "Intel HD Audio chipset driver"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bitflags.workspace = true
|
||||
libredox.workspace = true
|
||||
log.workspace = true
|
||||
redox_event.workspace = true
|
||||
redox_syscall.workspace = true
|
||||
spin.workspace = true
|
||||
|
||||
common = { path = "../../common" }
|
||||
daemon = { path = "../../../daemon" }
|
||||
pcid = { path = "../../pcid" }
|
||||
redox-scheme.workspace = true
|
||||
scheme-utils = { path = "../../../scheme-utils" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,5 @@
|
||||
[[drivers]]
|
||||
name = "Intel HD Audio"
|
||||
class = 0x04
|
||||
subclass = 0x03
|
||||
command = ["ihdad"]
|
||||
@@ -0,0 +1,501 @@
|
||||
use common::dma::Dma;
|
||||
use common::io::{Io, Mmio};
|
||||
use common::timeout::Timeout;
|
||||
use syscall::error::{Error, Result, EIO};
|
||||
|
||||
use super::common::*;
|
||||
|
||||
// CORBCTL
|
||||
const CMEIE: u8 = 1 << 0; // 1 bit
|
||||
const CORBRUN: u8 = 1 << 1; // 1 bit
|
||||
|
||||
// CORBSIZE
|
||||
const CORBSZCAP: (u8, u8) = (4, 4);
|
||||
const CORBSIZE: (u8, u8) = (0, 2);
|
||||
|
||||
// CORBRP
|
||||
const CORBRPRST: u16 = 1 << 15;
|
||||
|
||||
// RIRBWP
|
||||
const RIRBWPRST: u16 = 1 << 15;
|
||||
|
||||
// RIRBCTL
|
||||
const RINTCTL: u8 = 1 << 0; // 1 bit
|
||||
const RIRBDMAEN: u8 = 1 << 1; // 1 bit
|
||||
|
||||
const CORB_OFFSET: usize = 0x00;
|
||||
const RIRB_OFFSET: usize = 0x10;
|
||||
const ICMD_OFFSET: usize = 0x20;
|
||||
|
||||
// ICS
|
||||
const ICB: u16 = 1 << 0;
|
||||
const IRV: u16 = 1 << 1;
|
||||
|
||||
// CORB and RIRB offset
|
||||
|
||||
const COMMAND_BUFFER_OFFSET: usize = 0x40;
|
||||
const CORB_BUFF_MAX_SIZE: usize = 1024;
|
||||
|
||||
struct CommandBufferRegs {
|
||||
corblbase: Mmio<u32>,
|
||||
corbubase: Mmio<u32>,
|
||||
corbwp: Mmio<u16>,
|
||||
corbrp: Mmio<u16>,
|
||||
corbctl: Mmio<u8>,
|
||||
corbsts: Mmio<u8>,
|
||||
corbsize: Mmio<u8>,
|
||||
rsvd5: Mmio<u8>,
|
||||
|
||||
rirblbase: Mmio<u32>,
|
||||
rirbubase: Mmio<u32>,
|
||||
rirbwp: Mmio<u16>,
|
||||
rintcnt: Mmio<u16>,
|
||||
rirbctl: Mmio<u8>,
|
||||
rirbsts: Mmio<u8>,
|
||||
rirbsize: Mmio<u8>,
|
||||
rsvd6: Mmio<u8>,
|
||||
}
|
||||
|
||||
struct CorbRegs {
|
||||
corblbase: Mmio<u32>,
|
||||
corbubase: Mmio<u32>,
|
||||
corbwp: Mmio<u16>,
|
||||
corbrp: Mmio<u16>,
|
||||
corbctl: Mmio<u8>,
|
||||
corbsts: Mmio<u8>,
|
||||
corbsize: Mmio<u8>,
|
||||
rsvd5: Mmio<u8>,
|
||||
}
|
||||
|
||||
struct Corb {
|
||||
regs: &'static mut CorbRegs,
|
||||
corb_base: *mut u32,
|
||||
corb_base_phys: usize,
|
||||
corb_count: usize,
|
||||
}
|
||||
|
||||
impl Corb {
|
||||
pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: *mut u32) -> Corb {
|
||||
unsafe {
|
||||
Corb {
|
||||
regs: &mut *(regs_addr as *mut CorbRegs),
|
||||
corb_base: corb_buff_virt,
|
||||
corb_base_phys: corb_buff_phys,
|
||||
corb_count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Intel 4.4.1.3
|
||||
pub fn init(&mut self) -> Result<()> {
|
||||
self.stop()?;
|
||||
//Determine CORB and RIRB size and allocate buffer
|
||||
|
||||
//3.3.24
|
||||
let corbsize_reg = self.regs.corbsize.read();
|
||||
let corbszcap = (corbsize_reg >> 4) & 0xF;
|
||||
|
||||
let mut corbsize_bytes: usize = 0;
|
||||
let mut corbsize: u8 = 0;
|
||||
|
||||
if (corbszcap & 4) == 4 {
|
||||
corbsize = 2;
|
||||
corbsize_bytes = 1024;
|
||||
|
||||
self.corb_count = 256;
|
||||
} else if (corbszcap & 2) == 2 {
|
||||
corbsize = 1;
|
||||
corbsize_bytes = 64;
|
||||
|
||||
self.corb_count = 16;
|
||||
} else if (corbszcap & 1) == 1 {
|
||||
corbsize = 0;
|
||||
corbsize_bytes = 8;
|
||||
|
||||
self.corb_count = 2;
|
||||
}
|
||||
|
||||
assert!(self.corb_count != 0);
|
||||
let addr = self.corb_base_phys;
|
||||
self.set_address(addr);
|
||||
self.regs.corbsize.write((corbsize_reg & 0xFC) | corbsize);
|
||||
|
||||
self.reset_read_pointer()?;
|
||||
let old_wp = self.regs.corbwp.read();
|
||||
self.regs.corbwp.write(old_wp & 0xFF00);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.regs.corbctl.writef(CORBRUN, true);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while self.regs.corbctl.readf(CORBRUN) {
|
||||
self.regs.corbctl.writef(CORBRUN, false);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on clearing CORBRUN");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr: usize) {
|
||||
self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32);
|
||||
self.regs.corbubase.write(((addr as u64) >> 32) as u32);
|
||||
}
|
||||
|
||||
pub fn reset_read_pointer(&mut self) -> Result<()> {
|
||||
// 3.3.21
|
||||
|
||||
self.stop()?;
|
||||
|
||||
// Set CORBRPRST to 1
|
||||
log::trace!("CORBRP {:X}", self.regs.corbrp.read());
|
||||
self.regs.corbrp.writef(CORBRPRST, true);
|
||||
log::trace!("CORBRP {:X}", self.regs.corbrp.read());
|
||||
|
||||
{
|
||||
// Wait for it to become 1
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while !self.regs.corbrp.readf(CORBRPRST) {
|
||||
self.regs.corbrp.writef(CORBRPRST, true);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on setting CORBRPRST");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the bit again
|
||||
self.regs.corbrp.writef(CORBRPRST, false);
|
||||
|
||||
{
|
||||
// Read back the bit until zero to verify that it is cleared.
|
||||
let timeout = Timeout::from_secs(1);
|
||||
loop {
|
||||
if !self.regs.corbrp.readf(CORBRPRST) {
|
||||
break;
|
||||
}
|
||||
self.regs.corbrp.writef(CORBRPRST, false);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on clearing CORBRPRST");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_command(&mut self, cmd: u32) -> Result<()> {
|
||||
{
|
||||
// wait for the commands to finish
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on CORB command");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
let write_pos: usize = ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count;
|
||||
unsafe {
|
||||
*self.corb_base.offset(write_pos as isize) = cmd;
|
||||
}
|
||||
|
||||
self.regs.corbwp.write(write_pos as u16);
|
||||
|
||||
log::trace!("Corb: {:08X}", cmd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct RirbRegs {
|
||||
rirblbase: Mmio<u32>,
|
||||
rirbubase: Mmio<u32>,
|
||||
rirbwp: Mmio<u16>,
|
||||
rintcnt: Mmio<u16>,
|
||||
rirbctl: Mmio<u8>,
|
||||
rirbsts: Mmio<u8>,
|
||||
rirbsize: Mmio<u8>,
|
||||
rsvd6: Mmio<u8>,
|
||||
}
|
||||
|
||||
struct Rirb {
|
||||
regs: &'static mut RirbRegs,
|
||||
rirb_base: *mut u64,
|
||||
rirb_base_phys: usize,
|
||||
rirb_rp: u16,
|
||||
rirb_count: usize,
|
||||
}
|
||||
|
||||
impl Rirb {
|
||||
pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: *mut u64) -> Rirb {
|
||||
unsafe {
|
||||
Rirb {
|
||||
regs: &mut *(regs_addr as *mut RirbRegs),
|
||||
rirb_base: rirb_buff_virt,
|
||||
rirb_rp: 0,
|
||||
rirb_base_phys: rirb_buff_phys,
|
||||
rirb_count: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
//Intel 4.4.1.3
|
||||
pub fn init(&mut self) -> Result<()> {
|
||||
self.stop()?;
|
||||
|
||||
let rirbsize_reg = self.regs.rirbsize.read();
|
||||
let rirbszcap = (rirbsize_reg >> 4) & 0xF;
|
||||
|
||||
let mut rirbsize_bytes: usize = 0;
|
||||
let mut rirbsize: u8 = 0;
|
||||
|
||||
if (rirbszcap & 4) == 4 {
|
||||
rirbsize = 2;
|
||||
rirbsize_bytes = 2048;
|
||||
|
||||
self.rirb_count = 256;
|
||||
} else if (rirbszcap & 2) == 2 {
|
||||
rirbsize = 1;
|
||||
rirbsize_bytes = 128;
|
||||
|
||||
self.rirb_count = 8;
|
||||
} else if (rirbszcap & 1) == 1 {
|
||||
rirbsize = 0;
|
||||
rirbsize_bytes = 16;
|
||||
|
||||
self.rirb_count = 2;
|
||||
}
|
||||
|
||||
assert!(self.rirb_count != 0);
|
||||
|
||||
let addr = self.rirb_base_phys;
|
||||
self.set_address(addr);
|
||||
|
||||
self.reset_write_pointer();
|
||||
self.rirb_rp = 0;
|
||||
|
||||
self.regs.rintcnt.write(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL, true);
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while self.regs.rirbctl.readf(RIRBDMAEN) {
|
||||
self.regs.rirbctl.writef(RIRBDMAEN, false);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on clearing RIRBDMAEN");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr: usize) {
|
||||
self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32);
|
||||
self.regs.rirbubase.write(((addr as u64) >> 32) as u32);
|
||||
}
|
||||
|
||||
pub fn reset_write_pointer(&mut self) {
|
||||
self.regs.rirbwp.writef(RIRBWPRST, true);
|
||||
}
|
||||
|
||||
fn read_response(&mut self) -> Result<u64> {
|
||||
{
|
||||
// wait for response
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on RIRB response");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
let read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16;
|
||||
|
||||
let res: u64;
|
||||
unsafe {
|
||||
res = *self.rirb_base.offset(read_pos as isize);
|
||||
}
|
||||
self.rirb_rp = read_pos;
|
||||
log::trace!("Rirb: {:08X}", res);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
struct ImmediateCommandRegs {
|
||||
icoi: Mmio<u32>,
|
||||
irii: Mmio<u32>,
|
||||
ics: Mmio<u16>,
|
||||
rsvd7: [Mmio<u8>; 6],
|
||||
}
|
||||
|
||||
pub struct ImmediateCommand {
|
||||
regs: &'static mut ImmediateCommandRegs,
|
||||
}
|
||||
|
||||
impl ImmediateCommand {
|
||||
pub fn new(regs_addr: usize) -> ImmediateCommand {
|
||||
unsafe {
|
||||
ImmediateCommand {
|
||||
regs: &mut *(regs_addr as *mut ImmediateCommandRegs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd(&mut self, cmd: u32) -> Result<u64> {
|
||||
{
|
||||
// wait for ready
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while self.regs.ics.readf(ICB) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on immediate command");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// write command
|
||||
self.regs.icoi.write(cmd);
|
||||
|
||||
// set ICB bit to send command
|
||||
self.regs.ics.writef(ICB, true);
|
||||
|
||||
{
|
||||
// wait for IRV bit to be set to indicate a response is latched
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while !self.regs.ics.readf(IRV) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on immediate response");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// read the result register twice, total of 8 bytes
|
||||
// highest 4 will most likely be zeros (so I've heard)
|
||||
let mut res: u64 = self.regs.irii.read() as u64;
|
||||
res |= (self.regs.irii.read() as u64) << 32;
|
||||
|
||||
// clear the bit so we know when the next response comes
|
||||
self.regs.ics.writef(IRV, false);
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommandBuffer {
|
||||
// regs: &'static mut CommandBufferRegs,
|
||||
corb: Corb,
|
||||
rirb: Rirb,
|
||||
icmd: ImmediateCommand,
|
||||
|
||||
use_immediate_cmd: bool,
|
||||
mem: Dma<[u8; 0x1000]>,
|
||||
}
|
||||
|
||||
impl CommandBuffer {
|
||||
pub fn new(regs_addr: usize, mut cmd_buff: Dma<[u8; 0x1000]>) -> CommandBuffer {
|
||||
let corb = Corb::new(
|
||||
regs_addr + CORB_OFFSET,
|
||||
cmd_buff.physical(),
|
||||
cmd_buff.as_mut_ptr().cast(),
|
||||
);
|
||||
let rirb = Rirb::new(
|
||||
regs_addr + RIRB_OFFSET,
|
||||
cmd_buff.physical() + CORB_BUFF_MAX_SIZE,
|
||||
cmd_buff
|
||||
.as_mut_ptr()
|
||||
.cast::<u8>()
|
||||
.wrapping_add(CORB_BUFF_MAX_SIZE)
|
||||
.cast(),
|
||||
);
|
||||
|
||||
let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET);
|
||||
|
||||
let cmdbuff = CommandBuffer {
|
||||
corb,
|
||||
rirb,
|
||||
icmd,
|
||||
|
||||
use_immediate_cmd: false,
|
||||
|
||||
mem: cmd_buff,
|
||||
};
|
||||
|
||||
cmdbuff
|
||||
}
|
||||
|
||||
pub fn init(&mut self, use_imm_cmds: bool) -> Result<()> {
|
||||
self.corb.init()?;
|
||||
self.rirb.init()?;
|
||||
self.set_use_imm_cmds(use_imm_cmds)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
self.corb.stop()?;
|
||||
self.rirb.stop()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> Result<u64> {
|
||||
let mut ncmd: u32 = 0;
|
||||
|
||||
ncmd |= (addr.0 as u32 & 0x00F) << 28;
|
||||
ncmd |= (addr.1 as u32 & 0x0FF) << 20;
|
||||
ncmd |= (command & 0xFFF) << 8;
|
||||
ncmd |= (data as u32 & 0x0FF) << 0;
|
||||
self.cmd(ncmd)
|
||||
}
|
||||
pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> Result<u64> {
|
||||
let mut ncmd: u32 = 0;
|
||||
|
||||
ncmd |= (addr.0 as u32 & 0x000F) << 28;
|
||||
ncmd |= (addr.1 as u32 & 0x00FF) << 20;
|
||||
ncmd |= (command & 0x000F) << 16;
|
||||
ncmd |= (data as u32 & 0xFFFF) << 0;
|
||||
self.cmd(ncmd)
|
||||
}
|
||||
|
||||
pub fn cmd(&mut self, cmd: u32) -> Result<u64> {
|
||||
if self.use_immediate_cmd {
|
||||
self.cmd_imm(cmd)
|
||||
} else {
|
||||
self.cmd_buff(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd_imm(&mut self, cmd: u32) -> Result<u64> {
|
||||
self.icmd.cmd(cmd)
|
||||
}
|
||||
|
||||
pub fn cmd_buff(&mut self, cmd: u32) -> Result<u64> {
|
||||
self.corb.send_command(cmd)?;
|
||||
self.rirb.read_response()
|
||||
}
|
||||
|
||||
pub fn set_use_imm_cmds(&mut self, use_imm: bool) -> Result<()> {
|
||||
self.use_immediate_cmd = use_imm;
|
||||
|
||||
if self.use_immediate_cmd {
|
||||
self.corb.stop()?;
|
||||
self.rirb.stop()?;
|
||||
} else {
|
||||
self.corb.start();
|
||||
self.rirb.start();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
use std::fmt;
|
||||
use std::mem::transmute;
|
||||
|
||||
pub type HDANodeAddr = u16;
|
||||
pub type HDACodecAddr = u8;
|
||||
|
||||
pub type NodeAddr = u16;
|
||||
pub type CodecAddr = u8;
|
||||
|
||||
pub type WidgetAddr = (CodecAddr, NodeAddr);
|
||||
/*
|
||||
impl fmt::Display for WidgetAddr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:01X}:{:02X}\n", self.0, self.1)
|
||||
}
|
||||
}*/
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum HDAWidgetType {
|
||||
AudioOutput = 0x0,
|
||||
AudioInput = 0x1,
|
||||
AudioMixer = 0x2,
|
||||
AudioSelector = 0x3,
|
||||
PinComplex = 0x4,
|
||||
Power = 0x5,
|
||||
VolumeKnob = 0x6,
|
||||
BeepGenerator = 0x7,
|
||||
|
||||
VendorDefined = 0xf,
|
||||
}
|
||||
|
||||
impl fmt::Display for HDAWidgetType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum DefaultDevice {
|
||||
LineOut = 0x0,
|
||||
Speaker = 0x1,
|
||||
HPOut = 0x2,
|
||||
CD = 0x3,
|
||||
SPDIF = 0x4,
|
||||
DigitalOtherOut = 0x5,
|
||||
ModemLineSide = 0x6,
|
||||
ModemHandsetSide = 0x7,
|
||||
LineIn = 0x8,
|
||||
AUX = 0x9,
|
||||
MicIn = 0xA,
|
||||
Telephony = 0xB,
|
||||
SPDIFIn = 0xC,
|
||||
DigitalOtherIn = 0xD,
|
||||
Reserved = 0xE,
|
||||
Other = 0xF,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum PortConnectivity {
|
||||
ConnectedToJack = 0x0,
|
||||
NoPhysicalConnection = 0x1,
|
||||
FixedFunction = 0x2,
|
||||
JackAndInternal = 0x3,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum GrossLocation {
|
||||
ExternalOnPrimary = 0x0,
|
||||
Internal = 0x1,
|
||||
SeperateChasis = 0x2,
|
||||
Other = 0x3,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum GeometricLocation {
|
||||
NA = 0x0,
|
||||
Rear = 0x1,
|
||||
Front = 0x2,
|
||||
Left = 0x3,
|
||||
Right = 0x4,
|
||||
Top = 0x5,
|
||||
Bottom = 0x6,
|
||||
Special1 = 0x7,
|
||||
Special2 = 0x8,
|
||||
Special3 = 0x9,
|
||||
Resvd1 = 0xA,
|
||||
Resvd2 = 0xB,
|
||||
Resvd3 = 0xC,
|
||||
Resvd4 = 0xD,
|
||||
Resvd5 = 0xE,
|
||||
Resvd6 = 0xF,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(u8)]
|
||||
pub enum Color {
|
||||
Unknown = 0x0,
|
||||
Black = 0x1,
|
||||
Grey = 0x2,
|
||||
Blue = 0x3,
|
||||
Green = 0x4,
|
||||
Red = 0x5,
|
||||
Orange = 0x6,
|
||||
Yellow = 0x7,
|
||||
Purple = 0x8,
|
||||
Pink = 0x9,
|
||||
Resvd1 = 0xA,
|
||||
Resvd2 = 0xB,
|
||||
Resvd3 = 0xC,
|
||||
Resvd4 = 0xD,
|
||||
White = 0xE,
|
||||
Other = 0xF,
|
||||
}
|
||||
|
||||
pub struct ConfigurationDefault {
|
||||
value: u32,
|
||||
}
|
||||
|
||||
impl ConfigurationDefault {
|
||||
pub fn from_u32(value: u32) -> ConfigurationDefault {
|
||||
ConfigurationDefault { value: value }
|
||||
}
|
||||
|
||||
pub fn color(&self) -> Color {
|
||||
unsafe { transmute(((self.value >> 12) & 0xF) as u8) }
|
||||
}
|
||||
|
||||
pub fn default_device(&self) -> DefaultDevice {
|
||||
unsafe { transmute(((self.value >> 20) & 0xF) as u8) }
|
||||
}
|
||||
|
||||
pub fn port_connectivity(&self) -> PortConnectivity {
|
||||
unsafe { transmute(((self.value >> 30) & 0x3) as u8) }
|
||||
}
|
||||
|
||||
pub fn gross_location(&self) -> GrossLocation {
|
||||
unsafe { transmute(((self.value >> 28) & 0x3) as u8) }
|
||||
}
|
||||
|
||||
pub fn geometric_location(&self) -> GeometricLocation {
|
||||
unsafe { transmute(((self.value >> 24) & 0x7) as u8) }
|
||||
}
|
||||
|
||||
pub fn is_output(&self) -> bool {
|
||||
match self.default_device() {
|
||||
DefaultDevice::LineOut
|
||||
| DefaultDevice::Speaker
|
||||
| DefaultDevice::HPOut
|
||||
| DefaultDevice::CD
|
||||
| DefaultDevice::SPDIF
|
||||
| DefaultDevice::DigitalOtherOut
|
||||
| DefaultDevice::ModemLineSide => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_input(&self) -> bool {
|
||||
match self.default_device() {
|
||||
DefaultDevice::ModemHandsetSide
|
||||
| DefaultDevice::LineIn
|
||||
| DefaultDevice::AUX
|
||||
| DefaultDevice::MicIn
|
||||
| DefaultDevice::Telephony
|
||||
| DefaultDevice::SPDIFIn
|
||||
| DefaultDevice::DigitalOtherIn => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sequence(&self) -> u8 {
|
||||
(self.value & 0xF) as u8
|
||||
}
|
||||
|
||||
pub fn default_association(&self) -> u8 {
|
||||
((self.value >> 4) & 0xF) as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfigurationDefault {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{:?} {:?} {:?} {:?}",
|
||||
self.default_device(),
|
||||
self.color(),
|
||||
self.gross_location(),
|
||||
self.geometric_location()
|
||||
)
|
||||
}
|
||||
}
|
||||
Executable
+1086
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
#![allow(dead_code)]
|
||||
pub mod cmdbuff;
|
||||
pub mod common;
|
||||
pub mod device;
|
||||
pub mod node;
|
||||
pub mod stream;
|
||||
|
||||
pub use self::node::*;
|
||||
pub use self::stream::*;
|
||||
|
||||
pub use self::cmdbuff::*;
|
||||
pub use self::device::IntelHDA;
|
||||
pub use self::stream::BitsPerSample;
|
||||
pub use self::stream::BufferDescriptorListEntry;
|
||||
pub use self::stream::StreamBuffer;
|
||||
pub use self::stream::StreamDescriptorRegs;
|
||||
@@ -0,0 +1,108 @@
|
||||
use super::common::*;
|
||||
use std::{fmt, mem};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HDANode {
|
||||
pub addr: WidgetAddr,
|
||||
|
||||
// 0x4
|
||||
pub subnode_count: u16,
|
||||
pub subnode_start: u16,
|
||||
|
||||
// 0x5
|
||||
pub function_group_type: u8,
|
||||
|
||||
// 0x9
|
||||
pub capabilities: u32,
|
||||
|
||||
// 0xE
|
||||
pub conn_list_len: u8,
|
||||
|
||||
pub connections: Vec<WidgetAddr>,
|
||||
|
||||
pub connection_default: u8,
|
||||
|
||||
pub is_widget: bool,
|
||||
|
||||
pub config_default: u32,
|
||||
}
|
||||
|
||||
impl HDANode {
|
||||
pub fn new() -> HDANode {
|
||||
HDANode {
|
||||
addr: (0, 0),
|
||||
subnode_count: 0,
|
||||
subnode_start: 0,
|
||||
function_group_type: 0,
|
||||
capabilities: 0,
|
||||
conn_list_len: 0,
|
||||
|
||||
config_default: 0,
|
||||
is_widget: false,
|
||||
connections: Vec::<WidgetAddr>::new(),
|
||||
connection_default: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn widget_type(&self) -> HDAWidgetType {
|
||||
unsafe { mem::transmute(((self.capabilities >> 20) & 0xF) as u8) }
|
||||
}
|
||||
|
||||
pub fn device_default(&self) -> Option<DefaultDevice> {
|
||||
if self.widget_type() != HDAWidgetType::PinComplex {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { mem::transmute(((self.config_default >> 20) & 0xF) as u8) })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configuration_default(&self) -> ConfigurationDefault {
|
||||
ConfigurationDefault::from_u32(self.config_default)
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> WidgetAddr {
|
||||
self.addr
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HDANode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.addr == (0, 0) {
|
||||
write!(
|
||||
f,
|
||||
"Addr: {:02X}:{:02X}, Root Node.",
|
||||
self.addr.0, self.addr.1
|
||||
)
|
||||
} else if self.is_widget {
|
||||
match self.widget_type() {
|
||||
HDAWidgetType::PinComplex => write!(
|
||||
f,
|
||||
"Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.",
|
||||
self.addr.0,
|
||||
self.addr.1,
|
||||
self.widget_type(),
|
||||
self.device_default().unwrap(),
|
||||
self.connection_default,
|
||||
self.conn_list_len,
|
||||
self.connections
|
||||
),
|
||||
_ => write!(
|
||||
f,
|
||||
"Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.",
|
||||
self.addr.0,
|
||||
self.addr.1,
|
||||
self.widget_type(),
|
||||
self.connection_default,
|
||||
self.conn_list_len,
|
||||
self.connections
|
||||
),
|
||||
}
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.",
|
||||
self.addr.0, self.addr.1, self.function_group_type, self.subnode_count
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
use common::dma::Dma;
|
||||
use common::io::{Io, Mmio};
|
||||
use std::cmp::min;
|
||||
use std::ptr::copy_nonoverlapping;
|
||||
use std::result;
|
||||
use syscall::error::{Error, Result, EIO};
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
extern crate syscall;
|
||||
|
||||
pub enum BaseRate {
|
||||
BR44_1,
|
||||
BR48,
|
||||
}
|
||||
|
||||
pub struct SampleRate {
|
||||
base: BaseRate,
|
||||
mult: u16,
|
||||
div: u16,
|
||||
}
|
||||
|
||||
use self::BaseRate::{BR44_1, BR48};
|
||||
|
||||
pub const SR_8: SampleRate = SampleRate {
|
||||
base: BR48,
|
||||
mult: 1,
|
||||
div: 6,
|
||||
};
|
||||
pub const SR_11_025: SampleRate = SampleRate {
|
||||
base: BR44_1,
|
||||
mult: 1,
|
||||
div: 4,
|
||||
};
|
||||
pub const SR_16: SampleRate = SampleRate {
|
||||
base: BR48,
|
||||
mult: 1,
|
||||
div: 3,
|
||||
};
|
||||
pub const SR_22_05: SampleRate = SampleRate {
|
||||
base: BR44_1,
|
||||
mult: 1,
|
||||
div: 2,
|
||||
};
|
||||
pub const SR_32: SampleRate = SampleRate {
|
||||
base: BR48,
|
||||
mult: 2,
|
||||
div: 3,
|
||||
};
|
||||
|
||||
pub const SR_44_1: SampleRate = SampleRate {
|
||||
base: BR44_1,
|
||||
mult: 1,
|
||||
div: 1,
|
||||
};
|
||||
pub const SR_48: SampleRate = SampleRate {
|
||||
base: BR48,
|
||||
mult: 1,
|
||||
div: 1,
|
||||
};
|
||||
pub const SR_88_1: SampleRate = SampleRate {
|
||||
base: BR44_1,
|
||||
mult: 2,
|
||||
div: 1,
|
||||
};
|
||||
pub const SR_96: SampleRate = SampleRate {
|
||||
base: BR48,
|
||||
mult: 2,
|
||||
div: 1,
|
||||
};
|
||||
pub const SR_176_4: SampleRate = SampleRate {
|
||||
base: BR44_1,
|
||||
mult: 4,
|
||||
div: 1,
|
||||
};
|
||||
pub const SR_192: SampleRate = SampleRate {
|
||||
base: BR48,
|
||||
mult: 4,
|
||||
div: 1,
|
||||
};
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum BitsPerSample {
|
||||
Bits8 = 0,
|
||||
Bits16 = 1,
|
||||
Bits20 = 2,
|
||||
Bits24 = 3,
|
||||
Bits32 = 4,
|
||||
}
|
||||
|
||||
pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels: u8) -> u16 {
|
||||
// 3.3.41
|
||||
|
||||
let base: u16 = match sr.base {
|
||||
BaseRate::BR44_1 => 1 << 14,
|
||||
BaseRate::BR48 => 0,
|
||||
};
|
||||
|
||||
let mult = ((sr.mult - 1) & 0x7) << 11;
|
||||
|
||||
let div = ((sr.div - 1) & 0x7) << 8;
|
||||
|
||||
let bits = (bps as u16) << 4;
|
||||
|
||||
let chan = ((channels - 1) & 0xF) as u16;
|
||||
|
||||
let val: u16 = base | mult | div | bits | chan;
|
||||
|
||||
val
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
pub struct StreamDescriptorRegs {
|
||||
ctrl_lo: Mmio<u16>,
|
||||
ctrl_hi: Mmio<u8>,
|
||||
status: Mmio<u8>,
|
||||
link_pos: Mmio<u32>,
|
||||
buff_length: Mmio<u32>,
|
||||
last_valid_index: Mmio<u16>,
|
||||
resv1: Mmio<u16>,
|
||||
fifo_size_: Mmio<u16>,
|
||||
format: Mmio<u16>,
|
||||
resv2: Mmio<u32>,
|
||||
buff_desc_list_lo: Mmio<u32>,
|
||||
buff_desc_list_hi: Mmio<u32>,
|
||||
}
|
||||
|
||||
impl StreamDescriptorRegs {
|
||||
pub fn status(&self) -> u8 {
|
||||
self.status.read()
|
||||
}
|
||||
|
||||
pub fn set_status(&mut self, status: u8) {
|
||||
self.status.write(status);
|
||||
}
|
||||
|
||||
pub fn control(&self) -> u32 {
|
||||
let mut ctrl = self.ctrl_lo.read() as u32;
|
||||
ctrl |= (self.ctrl_hi.read() as u32) << 16;
|
||||
ctrl
|
||||
}
|
||||
|
||||
pub fn set_control(&mut self, control: u32) {
|
||||
self.ctrl_lo.write((control & 0xFFFF) as u16);
|
||||
self.ctrl_hi.write(((control >> 16) & 0xFF) as u8);
|
||||
}
|
||||
|
||||
pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels: u8) {
|
||||
// 3.3.41
|
||||
|
||||
let val = format_to_u16(sr, bps, channels);
|
||||
self.format.write(val);
|
||||
}
|
||||
|
||||
pub fn fifo_size(&self) -> u16 {
|
||||
self.fifo_size_.read()
|
||||
}
|
||||
|
||||
pub fn set_cyclic_buffer_length(&mut self, length: u32) {
|
||||
self.buff_length.write(length);
|
||||
}
|
||||
|
||||
pub fn cyclic_buffer_length(&self) -> u32 {
|
||||
self.buff_length.read()
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
let val = self.control() | (1 << 1);
|
||||
self.set_control(val);
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
let val = self.control() & !(1 << 1);
|
||||
self.set_control(val);
|
||||
}
|
||||
|
||||
pub fn stream_number(&self) -> u8 {
|
||||
((self.control() >> 20) & 0xF) as u8
|
||||
}
|
||||
|
||||
pub fn set_stream_number(&mut self, stream_number: u8) {
|
||||
let val = (self.control() & 0x00FFFF) | (((stream_number & 0xF) as u32) << 20);
|
||||
self.set_control(val);
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr: usize) {
|
||||
self.buff_desc_list_lo.write((addr & 0xFFFFFFFF) as u32);
|
||||
self.buff_desc_list_hi
|
||||
.write((((addr as u64) >> 32) & 0xFFFFFFFF) as u32);
|
||||
}
|
||||
|
||||
pub fn set_last_valid_index(&mut self, index: u16) {
|
||||
self.last_valid_index.write(index);
|
||||
}
|
||||
|
||||
pub fn link_position(&self) -> u32 {
|
||||
self.link_pos.read()
|
||||
}
|
||||
|
||||
pub fn set_interrupt_on_completion(&mut self, enable: bool) {
|
||||
let mut ctrl = self.control();
|
||||
if enable {
|
||||
ctrl |= 1 << 2;
|
||||
} else {
|
||||
ctrl &= !(1 << 2);
|
||||
}
|
||||
self.set_control(ctrl);
|
||||
}
|
||||
|
||||
pub fn buffer_complete(&self) -> bool {
|
||||
self.status.readf(1 << 2)
|
||||
}
|
||||
|
||||
pub fn clear_interrupts(&mut self) {
|
||||
self.status.write(0x7 << 2);
|
||||
}
|
||||
|
||||
// get sample size in bytes
|
||||
pub fn sample_size(&self) -> usize {
|
||||
let format = self.format.read();
|
||||
let chan = (format & 0xF) as usize;
|
||||
let bits = ((format >> 4) & 0xF) as usize;
|
||||
match bits {
|
||||
0 => 1 * (chan + 1),
|
||||
1 => 2 * (chan + 1),
|
||||
_ => 4 * (chan + 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OutputStream {
|
||||
buff: StreamBuffer,
|
||||
|
||||
desc_regs: &'static mut StreamDescriptorRegs,
|
||||
}
|
||||
|
||||
impl OutputStream {
|
||||
pub fn new(
|
||||
block_count: usize,
|
||||
block_length: usize,
|
||||
regs: &'static mut StreamDescriptorRegs,
|
||||
) -> OutputStream {
|
||||
OutputStream {
|
||||
buff: StreamBuffer::new(block_length, block_count).unwrap(),
|
||||
|
||||
desc_regs: regs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_block(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.buff.write_block(buf)
|
||||
}
|
||||
|
||||
pub fn block_size(&self) -> usize {
|
||||
self.buff.block_size()
|
||||
}
|
||||
|
||||
pub fn block_count(&self) -> usize {
|
||||
self.buff.block_count()
|
||||
}
|
||||
|
||||
pub fn current_block(&self) -> usize {
|
||||
self.buff.current_block()
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> usize {
|
||||
self.buff.addr()
|
||||
}
|
||||
|
||||
pub fn phys(&self) -> usize {
|
||||
self.buff.phys()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
pub struct BufferDescriptorListEntry {
|
||||
addr_low: Mmio<u32>,
|
||||
addr_high: Mmio<u32>,
|
||||
len: Mmio<u32>,
|
||||
ioc_resv: Mmio<u32>,
|
||||
}
|
||||
|
||||
impl BufferDescriptorListEntry {
|
||||
pub fn address(&self) -> u64 {
|
||||
(self.addr_low.read() as u64) | ((self.addr_high.read() as u64) << 32)
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr: u64) {
|
||||
self.addr_low.write(addr as u32);
|
||||
self.addr_high.write((addr >> 32) as u32);
|
||||
}
|
||||
|
||||
pub fn length(&self) -> u32 {
|
||||
self.len.read()
|
||||
}
|
||||
|
||||
pub fn set_length(&mut self, length: u32) {
|
||||
self.len.write(length)
|
||||
}
|
||||
|
||||
pub fn interrupt_on_completion(&self) -> bool {
|
||||
(self.ioc_resv.read() & 0x1) == 0x1
|
||||
}
|
||||
|
||||
pub fn set_interrupt_on_complete(&mut self, ioc: bool) {
|
||||
self.ioc_resv.writef(1, ioc);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StreamBuffer {
|
||||
mem: Dma<[u8]>,
|
||||
|
||||
block_cnt: usize,
|
||||
block_len: usize,
|
||||
|
||||
cur_pos: usize,
|
||||
}
|
||||
|
||||
impl StreamBuffer {
|
||||
pub fn new(
|
||||
block_length: usize,
|
||||
block_count: usize,
|
||||
) -> result::Result<StreamBuffer, &'static str> {
|
||||
let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE);
|
||||
let mem = unsafe {
|
||||
Dma::zeroed_slice(page_aligned_size)
|
||||
.map_err(|_| "Could not allocate physical memory for buffer.")?
|
||||
.assume_init()
|
||||
};
|
||||
|
||||
Ok(StreamBuffer {
|
||||
mem,
|
||||
block_len: block_length,
|
||||
block_cnt: block_count,
|
||||
cur_pos: 0,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn length(&self) -> usize {
|
||||
self.block_len * self.block_cnt
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> usize {
|
||||
self.mem.as_ptr() as usize
|
||||
}
|
||||
|
||||
pub fn phys(&self) -> usize {
|
||||
self.mem.physical()
|
||||
}
|
||||
|
||||
pub fn block_size(&self) -> usize {
|
||||
self.block_len
|
||||
}
|
||||
|
||||
pub fn block_count(&self) -> usize {
|
||||
self.block_cnt
|
||||
}
|
||||
|
||||
pub fn current_block(&self) -> usize {
|
||||
self.cur_pos
|
||||
}
|
||||
|
||||
pub fn write_block(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
if buf.len() != self.block_size() {
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
let len = min(self.block_size(), buf.len());
|
||||
|
||||
//log::trace!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len);
|
||||
unsafe {
|
||||
copy_nonoverlapping(
|
||||
buf.as_ptr(),
|
||||
(self.addr() + self.current_block() * self.block_size()) as *mut u8,
|
||||
len,
|
||||
);
|
||||
}
|
||||
|
||||
self.cur_pos += 1;
|
||||
self.cur_pos %= self.block_count();
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
impl Drop for StreamBuffer {
|
||||
fn drop(&mut self) {
|
||||
log::debug!("IHDA: Deallocating buffer.");
|
||||
}
|
||||
}
|
||||
Executable
+135
@@ -0,0 +1,135 @@
|
||||
use redox_scheme::scheme::register_sync_scheme;
|
||||
use redox_scheme::Socket;
|
||||
use scheme_utils::ReadinessBased;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::usize;
|
||||
|
||||
use event::{user_data, EventQueue};
|
||||
use pcid_interface::irq_helpers::pci_allocate_interrupt_vector;
|
||||
use pcid_interface::PciFunctionHandle;
|
||||
|
||||
pub mod hda;
|
||||
|
||||
/*
|
||||
VEND:PROD
|
||||
Virtualbox 8086:2668
|
||||
QEMU ICH9 8086:293E
|
||||
82801H ICH8 8086:284B
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
|
||||
let pci_config = pcid_handle.config();
|
||||
|
||||
let mut name = pci_config.func.name();
|
||||
name.push_str("_ihda");
|
||||
|
||||
common::setup_logging(
|
||||
"audio",
|
||||
"pci",
|
||||
&name,
|
||||
common::output_level(),
|
||||
common::file_level(),
|
||||
);
|
||||
|
||||
log::info!("IHDA {}", pci_config.func.display());
|
||||
|
||||
let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize;
|
||||
|
||||
let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "ihdad");
|
||||
|
||||
{
|
||||
let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16)
|
||||
| (pci_config.func.full_device_id.device_id as u32);
|
||||
|
||||
user_data! {
|
||||
enum Source {
|
||||
Irq,
|
||||
Scheme,
|
||||
}
|
||||
}
|
||||
|
||||
let event_queue =
|
||||
EventQueue::<Source>::new().expect("ihdad: Could not create event queue.");
|
||||
let socket = Socket::nonblock().expect("ihdad: failed to create socket");
|
||||
let mut device = unsafe {
|
||||
hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device")
|
||||
};
|
||||
let mut readiness_based = ReadinessBased::new(&socket, 16);
|
||||
|
||||
register_sync_scheme(&socket, "audiohw", &mut device)
|
||||
.expect("ihdad: failed to register audiohw scheme to namespace");
|
||||
daemon.ready();
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
socket.inner().raw(),
|
||||
Source::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
event_queue
|
||||
.subscribe(
|
||||
irq_file.irq_handle().as_raw_fd() as usize,
|
||||
Source::Irq,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace");
|
||||
|
||||
let all = [Source::Irq, Source::Scheme];
|
||||
|
||||
for event in all
|
||||
.into_iter()
|
||||
.chain(event_queue.map(|e| e.expect("failed to get next event").user_data))
|
||||
{
|
||||
match event {
|
||||
Source::Irq => {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.irq_handle().read(&mut irq).unwrap();
|
||||
|
||||
if !device.irq() {
|
||||
continue;
|
||||
}
|
||||
irq_file.irq_handle().write(&mut irq).unwrap();
|
||||
|
||||
readiness_based
|
||||
.poll_all_requests(&mut device)
|
||||
.expect("ihdad: failed to poll requests");
|
||||
readiness_based
|
||||
.write_responses()
|
||||
.expect("ihdad: failed to write to socket");
|
||||
|
||||
/*
|
||||
let next_read = device_irq.next_read();
|
||||
if next_read > 0 {
|
||||
return Ok(Some(next_read));
|
||||
}
|
||||
*/
|
||||
}
|
||||
Source::Scheme => {
|
||||
readiness_based
|
||||
.read_and_process_requests(&mut device)
|
||||
.expect("ihdad: failed to read from socket");
|
||||
readiness_based
|
||||
.write_responses()
|
||||
.expect("ihdad: failed to write to socket");
|
||||
|
||||
/*
|
||||
let next_read = device.borrow().next_read();
|
||||
if next_read > 0 {
|
||||
return Ok(Some(next_read));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user