ihdad: cleanup, fix blocking code, decrease buffer size to decrease latency

This commit is contained in:
Jeremy Soller
2018-12-29 12:21:12 -07:00
parent c47c68f44c
commit 939b294eae
9 changed files with 825 additions and 997 deletions
-469
View File
@@ -1,469 +0,0 @@
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();
}
}
}
-193
View File
@@ -1,193 +0,0 @@
use std::{mem, thread, ptr, 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())
}
}
+430
View File
@@ -0,0 +1,430 @@
use syscall::io::{Io, Mmio};
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 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 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;
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();
}
}
}
+195
View File
@@ -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()
)
}
}
@@ -1,24 +1,16 @@
#![allow(dead_code)]
use std::{mem, thread, ptr, fmt};
use std::cmp;
use std::cmp::{max, min};
use std::ptr::copy_nonoverlapping;
use std::sync::Arc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::str;
use std::string::String;
use std::collections::BTreeMap;
use std::sync::atomic::{AtomicUsize, Ordering};
extern crate syscall;
use syscall::PHYSMAP_WRITE;
use syscall::error::{Error, EACCES, EBADF, Result, EINVAL};
use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END};
use syscall::io::{Mmio, Io};
use syscall::scheme::SchemeMut;
use syscall::scheme::SchemeBlockMut;
use spin::Mutex;
@@ -58,24 +50,20 @@ const RIRBDMAEN: u8 = 1 << 1; // 1 bit
const ICB: u16 = 1 << 0;
const IRV: u16 = 1 << 1;
// CORB and RIRB offset
const COMMAND_BUFFER_OFFSET: usize = 0x40;
const NUM_SUB_BUFFS: usize = 2;
const SUB_BUFF_SIZE: usize = 0x4000;
const SUB_BUFF_SIZE: usize = 2048;
enum Handle {
Todo,
Pcmout(usize, usize, usize), // Card, index, block_ptr
Pcmin(usize, usize, usize), // Card, index, block_ptr
StrBuf(Vec<u8>,usize),
}
#[repr(packed)]
#[allow(dead_code)]
struct Regs {
@@ -125,26 +113,20 @@ struct Regs {
dplbase: Mmio<u32>, // 0x70
dpubase: Mmio<u32>, // 0x74
}
pub struct IntelHDA {
vend_prod: u32,
base: usize,
regs: &'static mut Regs,
//corb_rirb_base_phys: usize,
cmd: CommandBuffer,
codecs: Vec<CodecAddr>,
outputs: Vec<WidgetAddr>,
inputs: Vec<WidgetAddr>,
@@ -152,14 +134,12 @@ pub struct IntelHDA {
output_pins: Vec<WidgetAddr>,
input_pins: Vec<WidgetAddr>,
beep_addr: WidgetAddr,
buff_desc: &'static mut [BufferDescriptorListEntry; 256],
buff_desc_phys: usize,
output_streams: Vec<OutputStream>,
buffs: Vec<Vec<StreamBuffer>>,
@@ -169,38 +149,29 @@ pub struct IntelHDA {
next_id: AtomicUsize,
}
impl IntelHDA {
pub unsafe fn new(base: usize, vend_prod:u32) -> Result<Self> {
let regs = &mut *(base as *mut Regs);
let buff_desc_phys = unsafe {
syscall::physalloc(0x1000)
.expect("Could not allocate physical memory for buffer descriptor list.")
};
let buff_desc_virt = unsafe {
let buff_desc_virt = unsafe {
syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE)
.expect("ihdad: failed to map address for buffer descriptor list.")
.expect("ihdad: failed to map address for buffer descriptor list.")
};
print!("Virt: {:016X}, Phys: {:016X}\n", buff_desc_virt, buff_desc_phys);
let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]);
let cmd_buff_address = unsafe {
syscall::physalloc(0x1000)
.expect("Could not allocate physical memory for CORB and RIRB.")
};
let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") };
print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address);
@@ -208,16 +179,15 @@ impl IntelHDA {
vend_prod: vend_prod,
base: base,
regs: regs,
cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff_address, cmd_buff_virt),
beep_addr: (0,0),
widget_map: HashMap::<WidgetAddr, HDANode>::new(),
codecs: Vec::<CodecAddr>::new(),
outputs: Vec::<WidgetAddr>::new(),
inputs: Vec::<WidgetAddr>::new(),
@@ -227,24 +197,20 @@ impl IntelHDA {
buff_desc: buff_desc,
buff_desc_phys: buff_desc_phys,
output_streams: Vec::<OutputStream>::new(),
buffs: Vec::<Vec<StreamBuffer>>::new(),
int_counter: 0,
handles: Mutex::new(BTreeMap::new()),
next_id: AtomicUsize::new(0),
next_id: AtomicUsize::new(0),
};
module.init();
// module.info();
module.enumerate();
module.configure();
print!("IHDA: Initialization finished.\n");
Ok(module)
@@ -255,14 +221,14 @@ impl IntelHDA {
self.reset_controller();
let use_immediate_command_interface = match self.vend_prod {
0x8086_2668 => false,
_ => true,
};
};
self.cmd.init(use_immediate_command_interface);
self.cmd.init(use_immediate_command_interface);
self.init_interrupts();
true
}
@@ -274,15 +240,10 @@ impl IntelHDA {
self.regs.intctl.write((1 << 31) | /* (1 << 30) |*/ (1 << 4));
}
pub fn irq(&mut self) -> bool {
pub fn irq(&mut self) -> bool {
self.int_counter += 1;
self.handle_interrupts();
true
self.handle_interrupts()
}
pub fn int_count(&self) -> usize {
@@ -294,12 +255,12 @@ impl IntelHDA {
let mut temp:u64;
node.addr = addr;
temp = self.cmd.cmd12( addr, 0xF00, 0x04);
node.subnode_count = (temp & 0xff) as u16;
node.subnode_start = ((temp >> 16) & 0xff) as u16;
if addr == (0,0) {
return node;
}
@@ -316,41 +277,39 @@ impl IntelHDA {
node.conn_list_len = (temp & 0xFF) as u8;
node.connections = self.node_get_connection_list(&node);
node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32;
node
}
pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec<WidgetAddr> {
let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E) & 0xFF) as u8;
// Highest bit is if addresses are represented in longer notation
// lower 7 is actual count
let count:u8 = len_field & 0x7F;
let use_long_addr: bool = (len_field >> 7) & 0x1 == 1;
let mut current: u8 = 0;
let mut list = Vec::<WidgetAddr>::new();
while current < count {
let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32;
if use_long_addr {
for i in 0..2 {
let addr_field = ((response >> (16 * i)) & 0xFFFF) as u16;
let addr = (addr_field & 0x7FFF);
let addr = addr_field & 0x7FFF;
if addr == 0 { break; }
if (addr_field >> 15) & 0x1 == 0x1 {
for i in (list.pop().unwrap().1 .. (addr + 1)) {
for i in list.pop().unwrap().1 .. (addr + 1) {
list.push((node.addr.0, i));
}
} else {
@@ -359,56 +318,50 @@ impl IntelHDA {
}
} else {
for i in 0..4 {
let addr_field = ((response >> (8 * i)) & 0xff) as u16;
let addr = (addr_field & 0x7F);
if addr == 0 { break; }
let addr = addr_field & 0x7F;
if addr == 0 { break; }
if (addr_field >> 7) & 0x1 == 0x1 {
for i in (list.pop().unwrap().1 .. (addr + 1)) {
for i in list.pop().unwrap().1 .. (addr + 1) {
list.push((node.addr.0, i));
}
} else {
list.push((node.addr.0, addr));
}
}
}
current = list.len() as u8;
}
list
}
pub fn enumerate(&mut self) {
self.output_pins.clear();
self.input_pins.clear();
let codec:u8 = 0;
let root = self.read_node((codec,0));
// print!("{}\n", root);
let root_count = root.subnode_count;
let root_start = root.subnode_start;
//FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio
for i in 0..root_count {
for i in 0..root_count {
let afg = self.read_node((codec, root_start + i));
// print!("{}\n", afg);
let afg_count = afg.subnode_count;
let afg_start = afg.subnode_start;
for j in 0..afg_count {
let mut widget = self.read_node((codec, afg_start + j));
widget.is_widget = true;
match widget.widget_type() {
@@ -419,26 +372,22 @@ impl IntelHDA {
let config = widget.configuration_default();
if config.is_output() {
self.output_pins.push(widget.addr);
} else if (config.is_input()) {
} else if config.is_input() {
self.input_pins.push(widget.addr);
}
print!("{:02X}{:02X} {}\n", widget.addr().0, widget.addr().1, config);
},
_ => {},
}
print!("{}\n", widget);
self.widget_map.insert(widget.addr(), widget);
}
}
}
}
pub fn find_best_output_pin(&self) -> Option<WidgetAddr>{
let outs = &self.output_pins;
if outs.len() == 0 {
@@ -448,10 +397,10 @@ impl IntelHDA {
} else {
// TODO: Somehow find the best.
// Slightly okay is find the speaker with the lowest sequence number.
for &out in outs {
let widget = self.widget_map.get(&out).unwrap();
let cd = widget.configuration_default();
if cd.sequence() == 0 && cd.default_device() == DefaultDevice::Speaker {
return Some(out);
@@ -462,8 +411,6 @@ impl IntelHDA {
}
}
pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option<Vec<WidgetAddr>>{
let widget = self.widget_map.get(&addr).unwrap();
if widget.widget_type() == HDAWidgetType::AudioOutput {
@@ -474,7 +421,7 @@ impl IntelHDA {
}else{
// TODO: do more than just first widget
let mut res = self.find_path_to_dac(widget.connections[0]);
let res = self.find_path_to_dac(widget.connections[0]);
match res {
Some(p) => {
let mut ret = p.clone();
@@ -486,11 +433,8 @@ impl IntelHDA {
}
}
}
}
/*
Here we update the buffers and split them into 128 byte sub chunks
because each BufferDescriptorList needs to be 128 byte aligned,
@@ -503,7 +447,7 @@ impl IntelHDA {
Fixed?
*/
pub fn update_sound_buffers(&mut self) {
/*
for i in 0..self.buffs.len(){
@@ -516,31 +460,22 @@ impl IntelHDA {
let r = self.get_output_stream_descriptor(0).unwrap();
self.output_streams.push(OutputStream::new(2, 0x4000, r));
self.output_streams.push(OutputStream::new(NUM_SUB_BUFFS, SUB_BUFF_SIZE, r));
let o = self.output_streams.get_mut(0).unwrap();
self.buff_desc[0].set_address(o.phys());
self.buff_desc[0].set_length(o.block_size() as u32);
self.buff_desc[0].set_interrupt_on_complete(true);
self.buff_desc[0].set_interrupt_on_complete(true);
self.buff_desc[1].set_address(o.phys() + o.block_size());
self.buff_desc[1].set_length(o.block_size() as u32);
self.buff_desc[1].set_interrupt_on_complete(true);
}
pub fn configure(&mut self) {
let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!");
//print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1);
let path = self.find_path_to_dac(outpin).unwrap();
@@ -552,7 +487,6 @@ impl IntelHDA {
// Pin enable
self.cmd.cmd12(pin, 0x707, 0x40);
// EAPD enable
self.cmd.cmd12(pin, 0x70C, 2);
@@ -561,16 +495,12 @@ impl IntelHDA {
self.update_sound_buffers();
//print!("Supported Formats: {:08X}\n", self.get_supported_formats((0,0x1)));
//print!("Capabilities: {:08X}\n", self.get_capabilities(path[0]));
let output = self.get_output_stream_descriptor(0).unwrap();
output.set_address(self.buff_desc_phys);
output.set_address(self.buff_desc_phys);
output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2);
output.set_cyclic_buffer_length(0x8000); // number of bytes
@@ -581,8 +511,8 @@ impl IntelHDA {
self.set_power_state(dac, 0); // Power state 0 is fully on
self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2);
self.cmd.cmd12(dac, 0xA00, 0);
// Unmute and set gain for pin complex and DAC
@@ -590,14 +520,14 @@ impl IntelHDA {
self.set_amplifier_gain_mute(pin, true, true, true, true, 0, false, 0x7f);
output.run();
}
/*
pub fn configure_vbox(&mut self) {
let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!");
print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1);
let path = self.find_path_to_dac(outpin).unwrap();
@@ -605,7 +535,7 @@ impl IntelHDA {
// Pin enable
self.cmd.cmd12((0,0xC), 0x707, 0x40);
// EAPD enable
self.cmd.cmd12((0,0xC), 0x70C, 2);
@@ -619,11 +549,11 @@ impl IntelHDA {
print!("Capabilities: {:08X}\n", self.get_capabilities((0,0x1)));
let output = self.get_output_stream_descriptor(0).unwrap();
output.set_address(self.buff_desc_phys);
output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2);
output.set_cyclic_buffer_length(0x8000);
output.set_cyclic_buffer_length(0x8000);
output.set_stream_number(1);
output.set_last_valid_index(1);
output.set_interrupt_on_completion(true);
@@ -631,8 +561,8 @@ impl IntelHDA {
self.set_power_state((0,0x3), 0); // Power state 0 is fully on
self.set_converter_format((0,0x3), &super::SR_44_1, BitsPerSample::Bits16, 2);
self.cmd.cmd12((0,0x3), 0xA00, 0);
// Unmute and set gain for pin complex and DAC
@@ -642,35 +572,29 @@ impl IntelHDA {
output.run();
self.beep(1);
}
*/
// BEEP!!
pub fn beep(&mut self, div:u8) {
let addr = self.beep_addr;
if addr != (0,0) {
let _ = self.cmd.cmd12(addr, 0xF0A, div);
}
}
pub fn read_beep(&mut self) -> u8 {
let addr = self.beep_addr;
if addr != (0,0) {
self.cmd.cmd12(addr, 0x70A, 0) as u8
}else{
0
}
}
pub fn reset_controller(&mut self) -> bool {
self.regs.statests.write(0xFFFF);
// 3.3.7
@@ -700,17 +624,17 @@ impl IntelHDA {
for i in 0..15 {
if (statests >> i) & 0x1 == 1 {
self.codecs.push(i as CodecAddr);
}
}
}
true
}
pub fn num_output_streams(&self) -> usize{
let gcap = self.regs.gcap.read();
((gcap >> 12) & 0xF) as usize
}
pub fn num_input_streams(&self) -> usize{
let gcap = self.regs.gcap.read();
((gcap >> 8) & 0xF) as usize
@@ -735,8 +659,6 @@ impl IntelHDA {
print!("IHDA: 64-Bit: {}\n", self.regs.gcap.read() & 1 == 1);
}
fn get_input_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> {
unsafe {
if index < self.num_input_streams() {
@@ -750,7 +672,7 @@ impl IntelHDA {
fn get_output_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> {
unsafe {
if index < self.num_output_streams() {
Some(&mut *((self.base + 0x80 +
Some(&mut *((self.base + 0x80 +
self.num_input_streams() * 0x20 +
index * 0x20) as *mut StreamDescriptorRegs))
}else{
@@ -763,7 +685,7 @@ impl IntelHDA {
fn get_bidirectional_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> {
unsafe {
if index < self.num_bidirectional_streams() {
Some(&mut *((self.base + 0x80 +
Some(&mut *((self.base + 0x80 +
self.num_input_streams() * 0x20 +
self.num_output_streams() * 0x20 +
index * 0x20) as *mut StreamDescriptorRegs))
@@ -802,38 +724,29 @@ impl IntelHDA {
self.cmd.cmd4(addr, 0x2, fmt);
}
fn set_amplifier_gain_mute(&mut self, addr: WidgetAddr, output:bool, input:bool, left:bool, right:bool, index:u8, mute:bool, gain: u8) {
let mut payload: u16 = 0;
if output { payload |= (1 << 15); }
if input { payload |= (1 << 14); }
if left { payload |= (1 << 13); }
if right { payload |= (1 << 12); }
if mute { payload |= (1 << 7); }
if output { payload |= 1 << 15; }
if input { payload |= 1 << 14; }
if left { payload |= 1 << 13; }
if right { payload |= 1 << 12; }
if mute { payload |= 1 << 7; }
payload |= ((index as u16) & 0x0F) << 8;
payload |= ((gain as u16) & 0x7F);
payload |= (gain as u16) & 0x7F;
self.cmd.cmd4(addr, 0x3, payload);
}
pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result<usize> {
pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result<Option<usize>> {
let output = self.get_output_stream_descriptor(index as usize).unwrap();
let os = self.output_streams.get_mut(index as usize).unwrap();
let mut output = self.get_output_stream_descriptor(index as usize).unwrap();
let mut os = self.output_streams.get_mut(index as usize).unwrap();
let sample_size:usize = output.sample_size();
//let sample_size:usize = output.sample_size();
let mut open_block = (output.link_position() as usize) / os.block_size();
if open_block == 0 {
open_block = 1;
} else {
@@ -841,43 +754,33 @@ impl IntelHDA {
}
//print!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}\n", output.status(), output.link_position(), output.control());
while open_block == os.current_block() {
open_block = (output.link_position() as usize) / os.block_size();
if open_block == 0 {
open_block = os.block_count() - 1;
} else {
open_block = open_block - 1;
}
thread::yield_now();
if open_block == os.current_block() {
Ok(None)
} else {
os.write_block(buf).map(|count| Some(count))
}
let len = min(os.block_size(), buf.len());
os.write_block(buf)
}
pub fn handle_interrupts(&mut self) {
pub fn handle_interrupts(&mut self) -> bool {
let intsts = self.regs.intsts.read();
let sis = intsts & 0x3FFFFFFF;
// print!("IHDA INTSTS: {:08X}\n", intsts);
let sis = intsts & 0x3FFFFFFF;
//print!("IHDA INTSTS: {:08X}\n", intsts);
if ((intsts >> 31) & 1) == 1 { // Global Interrupt Status
if ((intsts >> 30) & 1) == 1 { // Controller Interrupt Status
self.handle_controller_interrupt();
}
}
if sis != 0 {
self.handle_stream_interrupts(sis);
}
}
intsts != 0
}
pub fn handle_controller_interrupt(&mut self) {
}
pub fn handle_stream_interrupts(&mut self, sis: u32) {
@@ -887,78 +790,76 @@ impl IntelHDA {
for i in 0..iss {
if ((sis >> i) & 1 ) == 1 {
let mut input = self.get_input_stream_descriptor(i).unwrap();
let mut input = self.get_input_stream_descriptor(i).unwrap();
input.clear_interrupts();
}
}
for i in 0..oss {
if ((sis >> (i + iss)) & 1 ) == 1 {
let mut output = self.get_output_stream_descriptor(i).unwrap();
let mut output = self.get_output_stream_descriptor(i).unwrap();
output.clear_interrupts();
}
}
for i in 0..bss {
if ((sis >> (i + iss + oss)) & 1 ) == 1 {
let mut bid = self.get_bidirectional_stream_descriptor(i).unwrap();
let mut bid = self.get_bidirectional_stream_descriptor(i).unwrap();
bid.clear_interrupts();
}
}
}
fn validate_path(&mut self, path: &Vec<&str>) -> bool {
fn validate_path(&mut self, path: &Vec<&str>) -> bool {
print!("Path: {:?}\n", path);
let mut it = path.iter();
match it.next() {
Some(card_str) if (*card_str).starts_with("card") => {
Some(card_str) if (*card_str).starts_with("card") => {
match usize::from_str_radix(&(*card_str)[4..], 10) {
Ok(card_num) => {
print!("Card# {}\n", card_num);
match it.next() {
Some(codec_str) if (*codec_str).starts_with("codec#") => {
Some(codec_str) if (*codec_str).starts_with("codec#") => {
match usize::from_str_radix(&(*codec_str)[6..], 10) {
Ok(codec_num) => {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
//self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0));
Ok(_codec_num) => {
//let id = self.next_id.fetch_add(1, Ordering::SeqCst);
//self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0));
true
},
_ => false,
}
}
},
Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => {
Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => {
match usize::from_str_radix(&(*pcmout_str)[6..], 10) {
Ok(pcmout_num) => {
print!("pcmout {}\n", pcmout_num);
true
},
_ => false,
}
}
},
Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => {
Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => {
match usize::from_str_radix(&(*pcmin_str)[6..], 10) {
Ok(pcmin_num) => {
print!("pcmin {}\n", pcmin_num);
true
},
_ => false,
}
}
},
_ => false,
}
},
_ => false,
}
}
},
Some(cards_str) if *cards_str == "cards" => {
true
},
_ => false,
_ => false,
}
}
}
}
@@ -969,44 +870,43 @@ impl Drop for IntelHDA {
}
}
impl SchemeMut for IntelHDA {
fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
let path: Vec<&str>;
impl SchemeBlockMut for IntelHDA {
fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<Option<usize>> {
//let path: Vec<&str>;
/*
match str::from_utf8(_path) {
Ok(p) => {
path = p.split("/").collect();
if !self.validate_path(&path) {
return Err(Error::new(EINVAL));
},
Err(_) => {return Err(Error::new(EINVAL));},
}*/
// TODO:
if uid == 0 {
Ok(0)
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.handles.lock().insert(id, Handle::Todo);
Ok(Some(id))
} else {
Err(Error::new(EACCES))
}
}
fn write(&mut self, _id: usize, buf: &[u8]) -> Result<usize> {
//print!("Int count: {}\n", self.int_counter);
fn write(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
let index = {
let mut handles = self.handles.lock();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
0
};
self.write_to_output(0, buf)
//print!("Int count: {}\n", self.int_counter);
self.write_to_output(index, buf)
}
fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<usize> {
fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<Option<usize>> {
let mut handles = self.handles.lock();
match *handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::StrBuf(ref mut strbuf, ref mut size) => {
@@ -1017,29 +917,28 @@ impl SchemeMut for IntelHDA {
SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize,
_ => return Err(Error::new(EINVAL))
};
Ok(*size)
Ok(Some(*size))
},
_ => Err(Error::new(EINVAL)),
}
}
}
}
fn close(&mut self, _id: usize) -> Result<usize> {
let mut handles = self.handles.lock();
handles.remove(&_id).ok_or(Error::new(EBADF)).and(Ok(0))
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
//let mut handles = self.handles.lock();
//let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
let mut handles = self.handles.lock();
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
let mut i = 0;
let scheme_path = b"audio:";
let scheme_path = b"hda:";
while i < buf.len() && i < scheme_path.len() {
buf[i] = scheme_path[i];
i += 1;
}
Ok(i)
Ok(Some(i))
}
fn close(&mut self, id: usize) -> Result<Option<usize>> {
let mut handles = self.handles.lock();
handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0)))
}
}
@@ -15,6 +15,3 @@ pub use self::stream::BufferDescriptorListEntry;
pub use self::stream::BitsPerSample;
pub use self::stream::StreamBuffer;
pub use self::device::IntelHDA;
+24 -37
View File
@@ -1,50 +1,43 @@
use std::{mem, thread, ptr, fmt};
use std::{mem, fmt};
use super::common::*;
#[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,
// 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<WidgetAddr>,
pub is_widget: bool,
pub config_default: u32,
}
impl HDANode {
pub fn new() -> HDANode {
HDANode {
addr: (0,0),
@@ -76,7 +69,7 @@ impl HDANode {
Some(unsafe { mem::transmute( ((self.config_default >> 20) & 0xF) as u8 )} )
}
}
pub fn configuration_default(&self) -> ConfigurationDefault {
ConfigurationDefault::from_u32(self.config_default)
}
@@ -89,29 +82,23 @@ impl HDANode {
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.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) },
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.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}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count)
}
} else {
write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count)
}
}
}
@@ -1,17 +1,10 @@
use syscall::PHYSMAP_WRITE;
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 syscall::error::{Error, EIO, Result};
use syscall::io::{Mmio, Io};
use std::result;
use std::cmp::{max, min};
use std::cmp::min;
use std::ptr::copy_nonoverlapping;
use std::{mem, thread, ptr, fmt};
use std::ptr;
extern crate syscall;
@@ -177,7 +170,7 @@ impl StreamDescriptorRegs {
pub fn set_interrupt_on_completion(&mut self, enable:bool) {
let mut ctrl = self.control();
if enable {
ctrl |= (1 << 2);
ctrl |= 1 << 2;
} else {
ctrl &= !(1 << 2);
}
@@ -286,8 +279,6 @@ impl BufferDescriptorListEntry {
}
}
pub struct StreamBuffer {
phys: usize,
addr: usize,
@@ -365,7 +356,7 @@ impl StreamBuffer {
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);
//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);
}
@@ -381,8 +372,9 @@ impl Drop for StreamBuffer {
fn drop(&mut self) {
unsafe {
print!("IHDA: Deallocating buffer.\n");
syscall::physunmap(self.addr);
syscall::physfree(self.phys, self.block_len * self.block_cnt);
if syscall::physunmap(self.addr).is_ok() {
let _ = syscall::physfree(self.phys, self.block_len * self.block_cnt);
}
}
}
}
+21 -31
View File
@@ -6,22 +6,17 @@ extern crate spin;
extern crate syscall;
extern crate event;
use std::{env, usize, u16, thread};
use std::{env, usize};
use std::fs::File;
use std::io::{Read, Write, Result};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Scheme, SchemeMut};
use std::os::unix::io::{AsRawFd, FromRawFd};
use syscall::{PHYSMAP_WRITE, Packet, SchemeBlockMut};
use std::cell::RefCell;
use std::sync::Arc;
use event::EventQueue;
use syscall::error::EWOULDBLOCK;
pub mod HDA;
use HDA::IntelHDA;
pub mod hda;
/*
VEND:PROD
@@ -58,8 +53,8 @@ fn main() {
let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32);
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 device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") }));
let socket_fd = syscall::open(":hda", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda 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.");
@@ -71,35 +66,32 @@ fn main() {
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 |_event| -> Result<Option<usize>> {
let mut irq = [0; 8];
irq_file.read(&mut irq)?;
let _irq = unsafe { device_irq.borrow_mut().irq()};
if _irq {
if unsafe { device_irq.borrow_mut().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);
if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) {
let mut packet = todo.remove(i);
packet.a = a;
socket_irq.borrow_mut().write(&packet)?;
} else {
i += 1;
}
}
/*
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");
@@ -112,22 +104,20 @@ fn main() {
break;
}
let a = packet.a;
device.borrow_mut().handle(&mut packet);
if packet.a == (-EWOULDBLOCK) as usize {
if let Some(a) = device.borrow_mut().handle(&mut packet) {
packet.a = a;
todo.borrow_mut().push(packet);
socket_packet.borrow_mut().write(&packet)?;
} else {
socket_packet.borrow_mut().write(&mut packet)?;
todo.borrow_mut().push(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");