Early Beta of the Intel HD Audio Driver
This commit is contained in:
Executable
+10
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "ihdad"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "0.7"
|
||||
spin = "0.4"
|
||||
redox_event = { git = "https://github.com/redox-os/event.git" }
|
||||
redox_syscall = "0.1"
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
use std::{mem, thread, ptr, fmt};
|
||||
use syscall::io::{Dma, Mmio, Io, ReadOnly};
|
||||
|
||||
|
||||
// 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 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,
|
||||
}
|
||||
|
||||
impl Corb {
|
||||
|
||||
pub fn new(regs_addr:usize, corb_buff_phys:usize, corb_buff_virt:usize) -> Corb {
|
||||
|
||||
|
||||
Corb {
|
||||
regs: &mut *(regs_addr as *mut CorbRegs);
|
||||
corb_base: (corb_buff_virt) as *mut u64,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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: usize,
|
||||
}
|
||||
|
||||
impl Rirb {
|
||||
|
||||
pub fn new(regs_addr:usize, rirb_buff_phys:usize, rirb_buff_virt:usize) -> Rirb {
|
||||
|
||||
|
||||
Rirb {
|
||||
regs: &mut *(regs_addr as *mut RirbRegs);
|
||||
rirb_base: (rirb_buff_virt) as *mut u64,
|
||||
rirb_rp: 0,
|
||||
rirb_base_phys: rirb_buff_phys,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct CommandBuffer {
|
||||
|
||||
// regs: &'static mut CommandBufferRegs,
|
||||
|
||||
corb: Corb,
|
||||
rirb: Rirb,
|
||||
|
||||
|
||||
corb_rirb_base_phys: usize,
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl CommandBuffer {
|
||||
pub fn new(regs_addr:usize, cmd_buff_frame_phys:usize, cmd_buff_frame:usize ) -> CommandBuffer {
|
||||
|
||||
let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame);
|
||||
let rirb = Rirb::new(regs_addr + RIRB_OFFSET,
|
||||
cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE,
|
||||
cmd_buff_frame + CORB_BUFF_MAX_SIZE);
|
||||
|
||||
CommandBuffer {
|
||||
corb: corb,
|
||||
rirb: rirb,
|
||||
corb_rirb_base_phys: cmd_buff_frame_phys,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
|
||||
use std::{mem, thread, ptr, fmt};
|
||||
|
||||
pub type HDANodeAddr = u16;
|
||||
pub type HDACodecAddr = u16;
|
||||
|
||||
#[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)]
|
||||
#[repr(u8)]
|
||||
pub enum HDADefaultDevice {
|
||||
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,
|
||||
}
|
||||
|
||||
Executable
+1248
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
|
||||
pub mod device;
|
||||
pub mod stream;
|
||||
pub mod common;
|
||||
pub mod node;
|
||||
|
||||
|
||||
pub use self::stream::*;
|
||||
pub use self::node::*;
|
||||
|
||||
|
||||
pub use self::stream::StreamDescriptorRegs;
|
||||
pub use self::stream::BufferDescriptorListEntry;
|
||||
pub use self::stream::BitsPerSample;
|
||||
pub use self::stream::StreamBuffer;
|
||||
pub use self::device::IntelHDA;
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
use std::{mem, thread, ptr, fmt};
|
||||
use super::common::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HDANode {
|
||||
pub addr: HDANodeAddr,
|
||||
|
||||
|
||||
|
||||
// 0x4
|
||||
pub subnode_count: u16,
|
||||
pub subnode_start: u16,
|
||||
|
||||
// 0x5
|
||||
pub function_group_type: u8,
|
||||
|
||||
|
||||
// 0x9
|
||||
pub capabilities: u32,
|
||||
|
||||
// 0xC
|
||||
pub pin_caps: u32,
|
||||
|
||||
// 0xD
|
||||
pub in_amp: u32,
|
||||
|
||||
// 0xE
|
||||
pub conn_list_len: u8,
|
||||
|
||||
|
||||
// 0x12
|
||||
pub out_amp: u32,
|
||||
|
||||
// 0x13
|
||||
pub vol_knob: u8,
|
||||
|
||||
pub connections: Vec<HDANodeAddr>,
|
||||
|
||||
pub is_widget: bool,
|
||||
|
||||
pub config_default: u32,
|
||||
}
|
||||
|
||||
|
||||
impl HDANode {
|
||||
|
||||
pub fn new() -> HDANode {
|
||||
HDANode {
|
||||
addr: 0,
|
||||
subnode_count: 0,
|
||||
subnode_start: 0,
|
||||
function_group_type: 0,
|
||||
capabilities: 0,
|
||||
pin_caps: 0,
|
||||
in_amp: 0,
|
||||
out_amp: 0,
|
||||
vol_knob: 0,
|
||||
conn_list_len: 0,
|
||||
|
||||
config_default: 0,
|
||||
is_widget: false,
|
||||
connections: Vec::<HDANodeAddr>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn widget_type(&self) -> HDAWidgetType {
|
||||
unsafe { mem::transmute( ((self.capabilities >> 20) & 0xF) as u8 )}
|
||||
|
||||
}
|
||||
|
||||
pub fn getDeviceDefault(&self) -> Option<HDADefaultDevice> {
|
||||
if self.widget_type() != HDAWidgetType::PinComplex {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { mem::transmute( ((self.config_default >> 20) & 0xF) as u8 )} )
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> HDANodeAddr {
|
||||
self.addr
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HDANode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.addr == 0 {
|
||||
write!(f, "Addr: {:02X}, Root Node.", self.addr)
|
||||
} else if self.is_widget {
|
||||
match self.widget_type() {
|
||||
|
||||
HDAWidgetType::PinComplex => {
|
||||
write!(f, "Addr: {:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.",
|
||||
self.addr,
|
||||
self.widget_type(),
|
||||
self.getDeviceDefault().unwrap(),
|
||||
self.conn_list_len,
|
||||
self.connections)
|
||||
},
|
||||
|
||||
_ => { write!(f, "Addr: {:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr, self.widget_type(), self.conn_list_len, self.connections) },
|
||||
|
||||
}
|
||||
} else {
|
||||
write!(f, "Addr: {:02X}, AFG: {}, Widget count {}.", self.addr, self.function_group_type, self.subnode_count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
use std::{mem, thread, ptr, fmt};
|
||||
use std::cmp::max;
|
||||
|
||||
use syscall::MAP_WRITE;
|
||||
use syscall::error::{Error, EACCES, EWOULDBLOCK, Result};
|
||||
use syscall::flag::O_NONBLOCK;
|
||||
use syscall::io::{Dma, Mmio, Io, ReadOnly};
|
||||
use syscall::scheme::SchemeMut;
|
||||
use std::sync::Arc;
|
||||
use std::cell::RefCell;
|
||||
use std::result;
|
||||
|
||||
|
||||
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(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 >> 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 Stream {
|
||||
buff: usize,
|
||||
buff_phys: usize,
|
||||
buff_length: usize,
|
||||
output_current_block: usize,
|
||||
block_length: usize,
|
||||
block_count: usize,
|
||||
}
|
||||
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct BufferDescriptorListEntry {
|
||||
addr: Mmio<u64>,
|
||||
len: Mmio<u32>,
|
||||
ioc_resv: Mmio<u32>,
|
||||
}
|
||||
|
||||
impl BufferDescriptorListEntry {
|
||||
pub fn address(&self) -> usize {
|
||||
self.addr.read() as usize
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr:usize) {
|
||||
self.addr.write(addr as u64);
|
||||
}
|
||||
|
||||
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 {
|
||||
phys: usize,
|
||||
addr: usize,
|
||||
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl StreamBuffer {
|
||||
pub fn new(length: usize) -> result::Result<StreamBuffer, &'static str> {
|
||||
let phys = unsafe {
|
||||
syscall::physalloc(length)
|
||||
};
|
||||
if !phys.is_ok() {
|
||||
return Err("Could not allocate physical memory for buffer.");
|
||||
}
|
||||
|
||||
let phys_addr = phys.unwrap();
|
||||
|
||||
let addr = unsafe {
|
||||
syscall::physmap(phys_addr, length, MAP_WRITE)
|
||||
};
|
||||
|
||||
if !addr.is_ok() {
|
||||
return Err("Could not map physical memory for buffer.");
|
||||
} else {
|
||||
unsafe {syscall::physfree(phys_addr, length);}
|
||||
}
|
||||
|
||||
Ok(StreamBuffer {
|
||||
phys: phys_addr,
|
||||
addr: addr.unwrap(),
|
||||
len: length,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn length(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
pub fn addr(&self) -> usize {
|
||||
self.addr
|
||||
}
|
||||
|
||||
pub fn phys(&self) -> usize {
|
||||
self.phys
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
impl Drop for StreamBuffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
print!("IHDA: Deallocating buffer.\n");
|
||||
syscall::physunmap(self.addr);
|
||||
syscall::physfree(self.phys, self.len);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
Executable
+164
@@ -0,0 +1,164 @@
|
||||
//#![deny(warnings)]
|
||||
#![feature(asm)]
|
||||
|
||||
extern crate bitflags;
|
||||
extern crate spin;
|
||||
extern crate syscall;
|
||||
extern crate event;
|
||||
|
||||
use std::{env, usize, thread};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write, Result};
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme, SchemeMut};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use event::EventQueue;
|
||||
use syscall::error::EWOULDBLOCK;
|
||||
|
||||
pub mod HDA;
|
||||
|
||||
|
||||
use HDA::IntelHDA;
|
||||
|
||||
fn main() {
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
let mut name = args.next().expect("ihda: no name provided");
|
||||
name.push_str("_ihda");
|
||||
|
||||
let bar_str = args.next().expect("ihda: no address provided");
|
||||
let bar = usize::from_str_radix(&bar_str, 16).expect("ihda: failed to parse address");
|
||||
|
||||
let irq_str = args.next().expect("ihda: no irq provided");
|
||||
let irq = irq_str.parse::<u8>().expect("ihda: failed to parse irq");
|
||||
|
||||
print!("{}", format!(" + ihda {} on: {:X} IRQ: {}\n", name, bar, irq));
|
||||
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(0).unwrap() } == 0 {
|
||||
|
||||
|
||||
let address = unsafe { syscall::physmap(bar, 0x4000, MAP_WRITE).expect("ihdad: failed to map address") };
|
||||
{
|
||||
|
||||
let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file");
|
||||
|
||||
|
||||
let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address).expect("ihdad: failed to allocate device") }));
|
||||
let socket_fd = syscall::open(":audio", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create audio scheme");
|
||||
let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) }));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let mut event_queue = EventQueue::<usize>::new().expect("IHDA: Could not create event queue.");
|
||||
|
||||
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
|
||||
|
||||
|
||||
let todo_irq = todo.clone();
|
||||
let device_irq = device.clone();
|
||||
let socket_irq = socket.clone();
|
||||
let device_loop = device.clone();
|
||||
|
||||
|
||||
event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result<Option<usize>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
|
||||
let _irq = unsafe { device_irq.borrow_mut().irq()};
|
||||
|
||||
if _irq {
|
||||
irq_file.write(&mut irq)?;
|
||||
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
device_irq.borrow_mut().handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
}
|
||||
}
|
||||
/*
|
||||
let next_read = device_irq.next_read();
|
||||
if next_read > 0 {
|
||||
return Ok(Some(next_read));
|
||||
}*/
|
||||
}
|
||||
Ok(Some(0))
|
||||
}).expect("IHDA: failed to catch events on IRQ file");
|
||||
|
||||
let socket_fd = socket.borrow().as_raw_fd();
|
||||
let socket_packet = socket.clone();
|
||||
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<usize>> {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
if socket_packet.borrow_mut().read(&mut packet)? == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let a = packet.a;
|
||||
device.borrow_mut().handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
} else {
|
||||
socket_packet.borrow_mut().write(&mut packet)?;
|
||||
}
|
||||
}
|
||||
/*
|
||||
let next_read = device.borrow().next_read();
|
||||
if next_read > 0 {
|
||||
return Ok(Some(next_read));
|
||||
}*/
|
||||
|
||||
Ok(None)
|
||||
}).expect("IHDA: failed to catch events on IRQ file");
|
||||
|
||||
for event_count in event_queue.trigger_all(0).expect("IHDA: failed to trigger events") {
|
||||
socket.borrow_mut().write(&Packet {
|
||||
id: 0,
|
||||
pid: 0,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
a: syscall::number::SYS_FEVENT,
|
||||
b: 0,
|
||||
c: syscall::flag::EVENT_READ,
|
||||
d: event_count
|
||||
}).expect("IHDA: failed to write event");
|
||||
}
|
||||
|
||||
|
||||
|
||||
loop {
|
||||
{
|
||||
//device_loop.borrow_mut().handle_interrupts();
|
||||
}
|
||||
let event_count = event_queue.run().expect("IHDA: failed to handle events");
|
||||
|
||||
socket.borrow_mut().write(&Packet {
|
||||
id: 0,
|
||||
pid: 0,
|
||||
uid: 0,
|
||||
gid: 0,
|
||||
a: syscall::number::SYS_FEVENT,
|
||||
b: 0,
|
||||
c: syscall::flag::EVENT_READ,
|
||||
d: event_count
|
||||
}).expect("IHDA: failed to write event");
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { let _ = syscall::physunmap(address); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user