Merge pull request #16 from TheSchemm/master

Refactored ihdad and added Qemu support.
This commit is contained in:
Jeremy Soller
2017-06-17 16:51:42 -06:00
committed by GitHub
8 changed files with 1179 additions and 825 deletions
-146
View File
@@ -1,146 +0,0 @@
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,
}
}
}
+469
View File
@@ -0,0 +1,469 @@
use std::{mem, thread, ptr, fmt};
use syscall::io::{Dma, Mmio, Io, ReadOnly};
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:usize) -> Corb {
unsafe {
Corb {
regs: &mut *(regs_addr as *mut CorbRegs),
corb_base: (corb_buff_virt) as *mut u32,
corb_base_phys: corb_buff_phys,
corb_count: 0,
}
}
}
//Intel 4.4.1.3
pub fn init(&mut self) {
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.corbwp.write(0);
self.reset_read_pointer();
}
pub fn start(&mut self) {
self.regs.corbctl.writef(CORBRUN,true);
}
pub fn stop(&mut self) {
while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.write(0); }
}
pub fn set_address(&mut self, addr: usize) {
self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32);
self.regs.corbubase.write((addr >> 32) as u32);
}
pub fn reset_read_pointer(&mut self){
/*
* FIRST ISSUE/PATCH
* This will loop forever in virtualbox
* So maybe just resetting the read pointer
* and leaving for the specific model?
*/
if true {
self.regs.corbrp.writef(CORBRPRST, true);
}
else
{
// 3.3.21
self.stop();
// Set CORBRPRST to 1
print!("CORBRP {:X}\n",self.regs.corbrp.read());
self.regs.corbrp.writef(CORBRPRST, true);
print!("CORBRP {:X}\n",self.regs.corbrp.read());
print!("Here!\n");
// Wait for it to become 1
while ! self.regs.corbrp.readf(CORBRPRST) {
self.regs.corbrp.writef(CORBRPRST, true);
}
print!("Here!!\n");
// Clear the bit again
self.regs.corbrp.write(0);
// Read back the bit until zero to verify that it is cleared.
loop {
if !self.regs.corbrp.readf(CORBRPRST) {
break;
}
self.regs.corbrp.write(0);
}
print!("Here!!!\n");
}
}
fn send_command(&mut self, cmd: u32) {
// wait for the commands to finish
while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {}
let mut 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);
print!("Corb: {:08X}\n", cmd);
}
}
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:usize) -> Rirb {
unsafe {
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,
rirb_count: 0,
}
}
}
//Intel 4.4.1.3
pub fn init(&mut self) {
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);
}
pub fn start(&mut self) {
self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL,true);
}
pub fn stop(&mut self) {
let mut val = self.regs.rirbctl.read();
val &= !(RIRBDMAEN);
self.regs.rirbctl.write(val);
}
pub fn set_address(&mut self, addr: usize) {
self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32);
self.regs.rirbubase.write((addr >> 32) as u32);
}
pub fn reset_write_pointer(&mut self) {
self.regs.rirbwp.writef(RIRBWPRST, true);
}
fn read_response(&mut self) -> u64 {
// wait for response
while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {}
let mut read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16;
let mut res: u64;
unsafe {
res = *self.rirb_base.offset(read_pos as isize);
}
self.rirb_rp = read_pos;
print!("Rirb: {:08X}\n", res);
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) -> u64 {
// wait for ready
while self.regs.ics.readf(ICB) {}
// 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
while !self.regs.ics.readf(IRV) {}
// 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);
res
}
}
pub struct CommandBuffer {
// regs: &'static mut CommandBufferRegs,
corb: Corb,
rirb: Rirb,
icmd: ImmediateCommand,
corb_rirb_base_phys: usize,
use_immediate_cmd: bool,
}
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);
let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET);
let cmdbuff = CommandBuffer {
corb: corb,
rirb: rirb,
icmd: icmd,
corb_rirb_base_phys: cmd_buff_frame_phys,
use_immediate_cmd: false,
};
cmdbuff
}
pub fn init(&mut self, use_imm_cmds: bool) {
self.corb.init();
self.rirb.init();
self.set_use_imm_cmds(use_imm_cmds);
}
pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> 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) -> 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) -> u64 {
if self.use_immediate_cmd {
self.cmd_imm(cmd)
} else {
self.cmd_buff(cmd)
}
}
pub fn cmd_imm(&mut self, cmd:u32) -> u64{
self.icmd.cmd(cmd)
}
pub fn cmd_buff(&mut self, cmd:u32) -> u64{
self.corb.send_command(cmd);
self.rirb.read_response()
}
pub fn set_use_imm_cmds(&mut self, use_imm: bool) {
self.use_immediate_cmd = use_imm;
if self.use_immediate_cmd {
self.corb.stop();
self.rirb.stop();
} else {
self.corb.start();
self.rirb.start();
}
}
}
+146 -4
View File
@@ -1,9 +1,20 @@
use std::{mem, thread, ptr, fmt};
use std::mem::transmute;
pub type HDANodeAddr = u16;
pub type HDACodecAddr = 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)]
@@ -28,9 +39,9 @@ impl fmt::Display for HDAWidgetType {
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
#[repr(u8)]
pub enum HDADefaultDevice {
pub enum DefaultDevice {
LineOut = 0x0,
Speaker = 0x1,
HPOut = 0x2,
@@ -49,3 +60,134 @@ pub enum HDADefaultDevice {
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())
}
}
+418 -634
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -1,14 +1,15 @@
#![allow(dead_code)]
pub mod device;
pub mod stream;
pub mod common;
pub mod node;
pub mod cmdbuff;
pub use self::stream::*;
pub use self::node::*;
pub use self::cmdbuff::*;
pub use self::stream::StreamDescriptorRegs;
pub use self::stream::BufferDescriptorListEntry;
pub use self::stream::BitsPerSample;
+18 -13
View File
@@ -4,7 +4,7 @@ use super::common::*;
#[derive(Clone)]
pub struct HDANode {
pub addr: HDANodeAddr,
pub addr: WidgetAddr,
@@ -35,7 +35,7 @@ pub struct HDANode {
// 0x13
pub vol_knob: u8,
pub connections: Vec<HDANodeAddr>,
pub connections: Vec<WidgetAddr>,
pub is_widget: bool,
@@ -47,7 +47,7 @@ impl HDANode {
pub fn new() -> HDANode {
HDANode {
addr: 0,
addr: (0,0),
subnode_count: 0,
subnode_start: 0,
function_group_type: 0,
@@ -60,7 +60,7 @@ impl HDANode {
config_default: 0,
is_widget: false,
connections: Vec::<HDANodeAddr>::new(),
connections: Vec::<WidgetAddr>::new(),
}
}
@@ -69,7 +69,7 @@ impl HDANode {
}
pub fn getDeviceDefault(&self) -> Option<HDADefaultDevice> {
pub fn device_default(&self) -> Option<DefaultDevice> {
if self.widget_type() != HDAWidgetType::PinComplex {
None
} else {
@@ -77,32 +77,37 @@ impl HDANode {
}
}
pub fn addr(&self) -> HDANodeAddr {
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 {
write!(f, "Addr: {:02X}, Root Node.", self.addr)
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}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.",
self.addr,
write!(f, "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.",
self.addr.0,
self.addr.1,
self.widget_type(),
self.getDeviceDefault().unwrap(),
self.device_default().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) },
_ => { write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr.0, self.addr.1, 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)
write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count)
}
}
}
+95 -22
View File
@@ -1,15 +1,17 @@
use std::{mem, thread, ptr, fmt};
use std::cmp::max;
use syscall::MAP_WRITE;
use syscall::error::{Error, EACCES, EWOULDBLOCK, Result};
use syscall::error::{Error, EACCES, EWOULDBLOCK, EIO, 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;
use std::cmp::{max, min};
use std::ptr::copy_nonoverlapping;
use std::{mem, thread, ptr, fmt};
extern crate syscall;
@@ -201,18 +203,56 @@ impl StreamDescriptorRegs {
_ => 4 * (chan + 1),
}
}
}
pub struct Stream {
buff: usize,
buff_phys: usize,
buff_length: usize,
output_current_block: usize,
block_length: usize,
block_count: usize,
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 {
unsafe {
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(packed)]
pub struct BufferDescriptorListEntry {
addr: Mmio<u64>,
@@ -252,13 +292,16 @@ pub struct StreamBuffer {
phys: usize,
addr: usize,
len: usize,
block_cnt: usize,
block_len: usize,
cur_pos: usize,
}
impl StreamBuffer {
pub fn new(length: usize) -> result::Result<StreamBuffer, &'static str> {
pub fn new(block_length: usize, block_count: usize) -> result::Result<StreamBuffer, &'static str> {
let phys = unsafe {
syscall::physalloc(length)
syscall::physalloc(block_length * block_count)
};
if !phys.is_ok() {
return Err("Could not allocate physical memory for buffer.");
@@ -267,24 +310,25 @@ impl StreamBuffer {
let phys_addr = phys.unwrap();
let addr = unsafe {
syscall::physmap(phys_addr, length, MAP_WRITE)
syscall::physmap(phys_addr, block_length * block_count, MAP_WRITE)
};
if !addr.is_ok() {
unsafe {syscall::physfree(phys_addr, block_length * block_count);}
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,
block_len: block_length,
block_cnt: block_count,
cur_pos: 0,
})
}
pub fn length(&self) -> usize {
self.len
self.block_len * self.block_cnt
}
pub fn addr(&self) -> usize {
@@ -295,14 +339,43 @@ impl StreamBuffer {
self.phys
}
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());
print!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}\n", 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) {
unsafe {
print!("IHDA: Deallocating buffer.\n");
syscall::physunmap(self.addr);
syscall::physfree(self.phys, self.len);
syscall::physfree(self.phys, self.block_len * self.block_cnt);
}
}
}*/
}
+30 -4
View File
@@ -6,7 +6,7 @@ extern crate spin;
extern crate syscall;
extern crate event;
use std::{env, usize, thread};
use std::{env, usize, u16, thread};
use std::fs::File;
use std::io::{Read, Write, Result};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
@@ -14,14 +14,27 @@ 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;
/*
VEND:PROD
Virtualbox 8086:2668
QEMU ICH9 8086:293E
82801H ICH8 8086:284B
*/
fn main() {
let mut args = env::args().skip(1);
@@ -34,8 +47,17 @@ fn main() {
let irq_str = args.next().expect("ihda: no irq provided");
let irq = irq_str.parse::<u8>().expect("ihda: failed to parse irq");
let vend_str = args.next().expect("ihda: no vendor id provided");
let vend = usize::from_str_radix(&vend_str, 16).expect("ihda: failed to parse vendor id");
let prod_str = args.next().expect("ihda: no product id provided");
let prod = usize::from_str_radix(&prod_str, 16).expect("ihda: failed to parse product id");
print!("{}", format!(" + ihda {} on: {:X} IRQ: {}\n", name, bar, irq));
// Daemonize
if unsafe { syscall::clone(0).unwrap() } == 0 {
@@ -45,8 +67,10 @@ fn main() {
let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file");
let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32);
let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address).expect("ihdad: failed to allocate device") }));
let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address, vend_prod).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) }));
@@ -95,7 +119,6 @@ fn main() {
}
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>> {
@@ -114,6 +137,8 @@ fn main() {
socket_packet.borrow_mut().write(&mut packet)?;
}
}
/*
let next_read = device.borrow().next_read();
if next_read > 0 {
@@ -138,6 +163,7 @@ fn main() {
loop {
{
//device_loop.borrow_mut().handle_interrupts();