ihdad: add many more timeouts and error handling
This commit is contained in:
+116
-46
@@ -1,5 +1,7 @@
|
||||
use common::dma::Dma;
|
||||
use common::io::{Io, Mmio};
|
||||
use common::timeout::Timeout;
|
||||
use syscall::error::{Error, Result, EIO};
|
||||
|
||||
use super::common::*;
|
||||
|
||||
@@ -85,8 +87,8 @@ impl Corb {
|
||||
}
|
||||
|
||||
//Intel 4.4.1.3
|
||||
pub fn init(&mut self) {
|
||||
self.stop();
|
||||
pub fn init(&mut self) -> Result<()> {
|
||||
self.stop()?;
|
||||
//Determine CORB and RIRB size and allocate buffer
|
||||
|
||||
//3.3.24
|
||||
@@ -118,9 +120,11 @@ impl Corb {
|
||||
self.set_address(addr);
|
||||
self.regs.corbsize.write((corbsize_reg & 0xFC) | corbsize);
|
||||
|
||||
self.reset_read_pointer();
|
||||
self.reset_read_pointer()?;
|
||||
let old_wp = self.regs.corbwp.read();
|
||||
self.regs.corbwp.write(old_wp & 0xFF00);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
@@ -128,10 +132,16 @@ impl Corb {
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn stop(&mut self) {
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while self.regs.corbctl.readf(CORBRUN) {
|
||||
self.regs.corbctl.writef(CORBRUN, false);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on clearing CORBRUN");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr: usize) {
|
||||
@@ -139,36 +149,60 @@ impl Corb {
|
||||
self.regs.corbubase.write(((addr as u64) >> 32) as u32);
|
||||
}
|
||||
|
||||
pub fn reset_read_pointer(&mut self) {
|
||||
pub fn reset_read_pointer(&mut self) -> Result<()> {
|
||||
// 3.3.21
|
||||
|
||||
self.stop();
|
||||
self.stop()?;
|
||||
|
||||
// Set CORBRPRST to 1
|
||||
log::trace!("CORBRP {:X}", self.regs.corbrp.read());
|
||||
self.regs.corbrp.writef(CORBRPRST, true);
|
||||
log::trace!("CORBRP {:X}", self.regs.corbrp.read());
|
||||
|
||||
// Wait for it to become 1
|
||||
while !self.regs.corbrp.readf(CORBRPRST) {
|
||||
self.regs.corbrp.writef(CORBRPRST, true);
|
||||
{
|
||||
// Wait for it to become 1
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while !self.regs.corbrp.readf(CORBRPRST) {
|
||||
self.regs.corbrp.writef(CORBRPRST, true);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on setting CORBRPRST");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the bit again
|
||||
self.regs.corbrp.writef(CORBRPRST, false);
|
||||
|
||||
// Read back the bit until zero to verify that it is cleared.
|
||||
loop {
|
||||
if !self.regs.corbrp.readf(CORBRPRST) {
|
||||
break;
|
||||
{
|
||||
// Read back the bit until zero to verify that it is cleared.
|
||||
let timeout = Timeout::from_secs(1);
|
||||
loop {
|
||||
if !self.regs.corbrp.readf(CORBRPRST) {
|
||||
break;
|
||||
}
|
||||
self.regs.corbrp.writef(CORBRPRST, false);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on clearing CORBRPRST");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
self.regs.corbrp.writef(CORBRPRST, false);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_command(&mut self, cmd: u32) {
|
||||
// wait for the commands to finish
|
||||
while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {}
|
||||
fn send_command(&mut self, cmd: u32) -> Result<()> {
|
||||
{
|
||||
// wait for the commands to finish
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on CORB command");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
let write_pos: usize = ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count;
|
||||
unsafe {
|
||||
*self.corb_base.offset(write_pos as isize) = cmd;
|
||||
@@ -177,6 +211,7 @@ impl Corb {
|
||||
self.regs.corbwp.write(write_pos as u16);
|
||||
|
||||
log::trace!("Corb: {:08X}", cmd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +247,8 @@ impl Rirb {
|
||||
}
|
||||
}
|
||||
//Intel 4.4.1.3
|
||||
pub fn init(&mut self) {
|
||||
self.stop();
|
||||
pub fn init(&mut self) -> Result<()> {
|
||||
self.stop()?;
|
||||
|
||||
let rirbsize_reg = self.regs.rirbsize.read();
|
||||
let rirbszcap = (rirbsize_reg >> 4) & 0xF;
|
||||
@@ -247,16 +282,24 @@ impl Rirb {
|
||||
self.rirb_rp = 0;
|
||||
|
||||
self.regs.rintcnt.write(1);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL, true);
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while self.regs.rirbctl.readf(RIRBDMAEN) {
|
||||
self.regs.rirbctl.writef(RIRBDMAEN, false);
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on clearing RIRBDMAEN");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_address(&mut self, addr: usize) {
|
||||
@@ -268,9 +311,17 @@ impl Rirb {
|
||||
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) {}
|
||||
fn read_response(&mut self) -> Result<u64> {
|
||||
{
|
||||
// wait for response
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on RIRB response");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
let read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16;
|
||||
|
||||
let res: u64;
|
||||
@@ -279,7 +330,7 @@ impl Rirb {
|
||||
}
|
||||
self.rirb_rp = read_pos;
|
||||
log::trace!("Rirb: {:08X}", res);
|
||||
res
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,9 +354,17 @@ impl ImmediateCommand {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd(&mut self, cmd: u32) -> u64 {
|
||||
// wait for ready
|
||||
while self.regs.ics.readf(ICB) {}
|
||||
pub fn cmd(&mut self, cmd: u32) -> Result<u64> {
|
||||
{
|
||||
// wait for ready
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while self.regs.ics.readf(ICB) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on immediate command");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// write command
|
||||
self.regs.icoi.write(cmd);
|
||||
@@ -313,8 +372,16 @@ impl ImmediateCommand {
|
||||
// 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) {}
|
||||
{
|
||||
// wait for IRV bit to be set to indicate a response is latched
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while !self.regs.ics.readf(IRV) {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on immediate response");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
// read the result register twice, total of 8 bytes
|
||||
// highest 4 will most likely be zeros (so I've heard)
|
||||
@@ -324,7 +391,7 @@ impl ImmediateCommand {
|
||||
// clear the bit so we know when the next response comes
|
||||
self.regs.ics.writef(IRV, false);
|
||||
|
||||
res
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,18 +437,20 @@ impl CommandBuffer {
|
||||
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 init(&mut self, use_imm_cmds: bool) -> Result<()> {
|
||||
self.corb.init()?;
|
||||
self.rirb.init()?;
|
||||
self.set_use_imm_cmds(use_imm_cmds)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
self.corb.stop();
|
||||
self.rirb.stop();
|
||||
pub fn stop(&mut self) -> Result<()> {
|
||||
self.corb.stop()?;
|
||||
self.rirb.stop()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> u64 {
|
||||
pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> Result<u64> {
|
||||
let mut ncmd: u32 = 0;
|
||||
|
||||
ncmd |= (addr.0 as u32 & 0x00F) << 28;
|
||||
@@ -390,7 +459,7 @@ impl CommandBuffer {
|
||||
ncmd |= (data as u32 & 0x0FF) << 0;
|
||||
self.cmd(ncmd)
|
||||
}
|
||||
pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> u64 {
|
||||
pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> Result<u64> {
|
||||
let mut ncmd: u32 = 0;
|
||||
|
||||
ncmd |= (addr.0 as u32 & 0x000F) << 28;
|
||||
@@ -400,7 +469,7 @@ impl CommandBuffer {
|
||||
self.cmd(ncmd)
|
||||
}
|
||||
|
||||
pub fn cmd(&mut self, cmd: u32) -> u64 {
|
||||
pub fn cmd(&mut self, cmd: u32) -> Result<u64> {
|
||||
if self.use_immediate_cmd {
|
||||
self.cmd_imm(cmd)
|
||||
} else {
|
||||
@@ -408,24 +477,25 @@ impl CommandBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cmd_imm(&mut self, cmd: u32) -> u64 {
|
||||
pub fn cmd_imm(&mut self, cmd: u32) -> Result<u64> {
|
||||
self.icmd.cmd(cmd)
|
||||
}
|
||||
|
||||
pub fn cmd_buff(&mut self, cmd: u32) -> u64 {
|
||||
self.corb.send_command(cmd);
|
||||
pub fn cmd_buff(&mut self, cmd: u32) -> Result<u64> {
|
||||
self.corb.send_command(cmd)?;
|
||||
self.rirb.read_response()
|
||||
}
|
||||
|
||||
pub fn set_use_imm_cmds(&mut self, use_imm: bool) {
|
||||
pub fn set_use_imm_cmds(&mut self, use_imm: bool) -> Result<()> {
|
||||
self.use_immediate_cmd = use_imm;
|
||||
|
||||
if self.use_immediate_cmd {
|
||||
self.corb.stop();
|
||||
self.rirb.stop();
|
||||
self.corb.stop()?;
|
||||
self.rirb.stop()?;
|
||||
} else {
|
||||
self.corb.start();
|
||||
self.rirb.start();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use std::time::Duration;
|
||||
use common::dma::Dma;
|
||||
use common::io::{Io, Mmio};
|
||||
use common::timeout::Timeout;
|
||||
use syscall::error::{Error, Result, EACCES, EBADF, EIO, EINVAL};
|
||||
use syscall::error::{Error, Result, EACCES, EBADF, EIO, EINVAL, ENODEV};
|
||||
use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
use syscall::scheme::SchemeBlockMut;
|
||||
|
||||
@@ -207,9 +207,9 @@ impl IntelHDA {
|
||||
module.init()?;
|
||||
|
||||
module.info();
|
||||
module.enumerate();
|
||||
module.enumerate()?;
|
||||
|
||||
module.configure();
|
||||
module.configure()?;
|
||||
log::debug!("IHDA: Initialization finished.");
|
||||
Ok(module)
|
||||
}
|
||||
@@ -222,7 +222,7 @@ impl IntelHDA {
|
||||
_ => true,
|
||||
};
|
||||
|
||||
self.cmd.init(use_immediate_command_interface);
|
||||
self.cmd.init(use_immediate_command_interface)?;
|
||||
self.init_interrupts();
|
||||
|
||||
Ok(())
|
||||
@@ -248,42 +248,42 @@ impl IntelHDA {
|
||||
self.int_counter
|
||||
}
|
||||
|
||||
pub fn read_node(&mut self, addr: WidgetAddr) -> HDANode {
|
||||
pub fn read_node(&mut self, addr: WidgetAddr) -> Result<HDANode> {
|
||||
let mut node = HDANode::new();
|
||||
let mut temp: u64;
|
||||
|
||||
node.addr = addr;
|
||||
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x04);
|
||||
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;
|
||||
return Ok(node);
|
||||
}
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x04);
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x04)?;
|
||||
|
||||
node.function_group_type = (temp & 0xff) as u8;
|
||||
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x09);
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x09)?;
|
||||
node.capabilities = temp as u32;
|
||||
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x0E);
|
||||
temp = self.cmd.cmd12(addr, 0xF00, 0x0E)?;
|
||||
|
||||
node.conn_list_len = (temp & 0xFF) as u8;
|
||||
|
||||
node.connections = self.node_get_connection_list(&node);
|
||||
node.connections = self.node_get_connection_list(&node)?;
|
||||
|
||||
node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00) as u8;
|
||||
node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00)? as u8;
|
||||
|
||||
node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32;
|
||||
node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00)? as u32;
|
||||
|
||||
node
|
||||
Ok(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;
|
||||
pub fn node_get_connection_list(&mut self, node: &HDANode) -> Result<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
|
||||
@@ -296,7 +296,7 @@ impl IntelHDA {
|
||||
let mut list = Vec::<WidgetAddr>::new();
|
||||
|
||||
while current < count {
|
||||
let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32;
|
||||
let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current)? & 0xFFFFFFFF) as u32;
|
||||
|
||||
if use_long_addr {
|
||||
for i in 0..2 {
|
||||
@@ -337,16 +337,16 @@ impl IntelHDA {
|
||||
current = list.len() as u8;
|
||||
}
|
||||
|
||||
list
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
pub fn enumerate(&mut self) {
|
||||
pub fn enumerate(&mut self) -> Result<()> {
|
||||
self.output_pins.clear();
|
||||
self.input_pins.clear();
|
||||
|
||||
let codec: u8 = 0;
|
||||
|
||||
let root = self.read_node((codec, 0));
|
||||
let root = self.read_node((codec, 0))?;
|
||||
|
||||
log::debug!("{}", root);
|
||||
|
||||
@@ -355,13 +355,13 @@ impl IntelHDA {
|
||||
|
||||
//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 {
|
||||
let afg = self.read_node((codec, root_start + i));
|
||||
let afg = self.read_node((codec, root_start + i))?;
|
||||
log::debug!("{}", 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));
|
||||
let mut widget = self.read_node((codec, afg_start + j))?;
|
||||
widget.is_widget = true;
|
||||
match widget.widget_type() {
|
||||
HDAWidgetType::AudioOutput => self.outputs.push(widget.addr),
|
||||
@@ -382,15 +382,15 @@ impl IntelHDA {
|
||||
self.widget_map.insert(widget.addr(), widget);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_best_output_pin(&mut self) -> Option<WidgetAddr> {
|
||||
pub fn find_best_output_pin(&mut self) -> Result<WidgetAddr> {
|
||||
let outs = &self.output_pins;
|
||||
if outs.len() == 0 {
|
||||
None
|
||||
} else if outs.len() == 1 {
|
||||
Some(outs[0])
|
||||
} else {
|
||||
if outs.len() == 1 {
|
||||
return Ok(outs[0])
|
||||
} else if outs.len() > 1 {
|
||||
//TODO: change output based on "unsolicited response" interrupts
|
||||
// Check for devices in this order: Headphone, Speaker, Line Out
|
||||
for supported_device in &[DefaultDevice::HPOut, DefaultDevice::Speaker] {
|
||||
@@ -399,22 +399,22 @@ impl IntelHDA {
|
||||
let cd = widget.configuration_default();
|
||||
if cd.sequence() == 0 && &cd.default_device() == supported_device {
|
||||
// Check for jack detect bit
|
||||
let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C);
|
||||
let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C)?;
|
||||
if pin_caps & (1 << 2) != 0 {
|
||||
// Check for presence
|
||||
let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0);
|
||||
let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0)?;
|
||||
if pin_sense & (1 << 31) == 0 {
|
||||
// Skip if nothing is plugged in
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return Some(out);
|
||||
return Ok(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
Err(Error::new(ENODEV))
|
||||
}
|
||||
|
||||
pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option<Vec<WidgetAddr>> {
|
||||
@@ -466,8 +466,8 @@ impl IntelHDA {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configure(&mut self) {
|
||||
let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!");
|
||||
pub fn configure(&mut self) -> Result<()> {
|
||||
let outpin = self.find_best_output_pin()?;
|
||||
|
||||
log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1);
|
||||
|
||||
@@ -480,25 +480,25 @@ impl IntelHDA {
|
||||
|
||||
// Set power state 0 (on) for all widgets in path
|
||||
for &addr in &path {
|
||||
self.set_power_state(addr, 0);
|
||||
self.set_power_state(addr, 0)?;
|
||||
}
|
||||
|
||||
// Pin enable (0x80 = headphone amp enable, 0x40 = output enable)
|
||||
self.cmd.cmd12(pin, 0x707, 0xC0);
|
||||
self.cmd.cmd12(pin, 0x707, 0xC0)?;
|
||||
|
||||
// EAPD enable
|
||||
self.cmd.cmd12(pin, 0x70C, 2);
|
||||
self.cmd.cmd12(pin, 0x70C, 2)?;
|
||||
|
||||
// Set DAC stream and channel
|
||||
self.set_stream_channel(dac, 1, 0);
|
||||
self.set_stream_channel(dac, 1, 0)?;
|
||||
|
||||
self.update_sound_buffers();
|
||||
|
||||
log::debug!(
|
||||
"Supported Formats: {:08X}",
|
||||
self.get_supported_formats((0, 0x1))
|
||||
self.get_supported_formats((0, 0x1))?
|
||||
);
|
||||
log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0]));
|
||||
log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])?);
|
||||
|
||||
// Create output stream
|
||||
let output = self.get_output_stream_descriptor(0).unwrap();
|
||||
@@ -510,16 +510,16 @@ impl IntelHDA {
|
||||
output.set_interrupt_on_completion(true);
|
||||
|
||||
// Set DAC converter format
|
||||
self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2);
|
||||
self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2)?;
|
||||
|
||||
// Get DAC converter format
|
||||
//TODO: should validate?
|
||||
self.cmd.cmd12(dac, 0xA00, 0);
|
||||
self.cmd.cmd12(dac, 0xA00, 0)?;
|
||||
|
||||
// Unmute and set gain to 0db for input and output amplifiers on all widgets in path
|
||||
for &addr in &path {
|
||||
// Read widget capabilities
|
||||
let caps = self.cmd.cmd12(addr, 0xF00, 0x09);
|
||||
let caps = self.cmd.cmd12(addr, 0xF00, 0x09)?;
|
||||
|
||||
//TODO: do we need to set any other indexes?
|
||||
let left = true;
|
||||
@@ -530,28 +530,28 @@ impl IntelHDA {
|
||||
// Check for input amp
|
||||
if (caps & (1 << 1)) != 0 {
|
||||
// Read input capabilities
|
||||
let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D);
|
||||
let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D)?;
|
||||
let in_gain = (in_caps & 0x7f) as u8;
|
||||
// Set input gain
|
||||
let output = false;
|
||||
let input = true;
|
||||
self.set_amplifier_gain_mute(
|
||||
addr, output, input, left, right, index, mute, in_gain,
|
||||
);
|
||||
)?;
|
||||
log::debug!("Set {:X?} input gain to 0x{:X}", addr, in_gain);
|
||||
}
|
||||
|
||||
// Check for output amp
|
||||
if (caps & (1 << 2)) != 0 {
|
||||
// Read output capabilities
|
||||
let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12);
|
||||
let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12)?;
|
||||
let out_gain = (out_caps & 0x7f) as u8;
|
||||
// Set output gain
|
||||
let output = true;
|
||||
let input = false;
|
||||
self.set_amplifier_gain_mute(
|
||||
addr, output, input, left, right, index, mute, out_gain,
|
||||
);
|
||||
)?;
|
||||
log::debug!("Set {:X?} output gain to 0x{:X}", addr, out_gain);
|
||||
}
|
||||
}
|
||||
@@ -559,9 +559,15 @@ impl IntelHDA {
|
||||
//TODO: implement hda-verb?
|
||||
|
||||
output.run();
|
||||
log::debug!("Waiting for output 0 to start running...");
|
||||
while output.control() & (1 << 1) == 0 {
|
||||
//TODO: relax
|
||||
{
|
||||
log::debug!("Waiting for output 0 to start running...");
|
||||
let timeout = Timeout::from_secs(1);
|
||||
while output.control() & (1 << 1) == 0 {
|
||||
timeout.run().map_err(|()| {
|
||||
log::error!("timeout on output running");
|
||||
Error::new(EIO)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
log::debug!(
|
||||
@@ -570,6 +576,7 @@ impl IntelHDA {
|
||||
output.status(),
|
||||
output.link_position()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -644,17 +651,8 @@ impl IntelHDA {
|
||||
}
|
||||
}
|
||||
|
||||
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) -> Result<()> {
|
||||
self.cmd.stop();
|
||||
self.cmd.stop()?;
|
||||
|
||||
self.regs.statests.write(0x7FFF);
|
||||
|
||||
@@ -800,21 +798,23 @@ impl IntelHDA {
|
||||
self.regs.dpubase.write((addr_val >> 32) as u32);
|
||||
}
|
||||
|
||||
fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel: u8) {
|
||||
fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel: u8) -> Result<()> {
|
||||
let val = ((stream & 0xF) << 4) | (channel & 0xF);
|
||||
self.cmd.cmd12(addr, 0x706, val);
|
||||
self.cmd.cmd12(addr, 0x706, val)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_power_state(&mut self, addr: WidgetAddr, state: u8) {
|
||||
self.cmd.cmd12(addr, 0x705, state & 0xF) as u32;
|
||||
fn set_power_state(&mut self, addr: WidgetAddr, state: u8) -> Result<()> {
|
||||
self.cmd.cmd12(addr, 0x705, state & 0xF)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_supported_formats(&mut self, addr: WidgetAddr) -> u32 {
|
||||
self.cmd.cmd12(addr, 0xF00, 0x0A) as u32
|
||||
fn get_supported_formats(&mut self, addr: WidgetAddr) -> Result<u32> {
|
||||
Ok(self.cmd.cmd12(addr, 0xF00, 0x0A)? as u32)
|
||||
}
|
||||
|
||||
fn get_capabilities(&mut self, addr: WidgetAddr) -> u32 {
|
||||
self.cmd.cmd12(addr, 0xF00, 0x09) as u32
|
||||
fn get_capabilities(&mut self, addr: WidgetAddr) -> Result<u32> {
|
||||
Ok(self.cmd.cmd12(addr, 0xF00, 0x09)? as u32)
|
||||
}
|
||||
|
||||
fn set_converter_format(
|
||||
@@ -823,9 +823,10 @@ impl IntelHDA {
|
||||
sr: &super::SampleRate,
|
||||
bps: BitsPerSample,
|
||||
channels: u8,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
let fmt = super::format_to_u16(sr, bps, channels);
|
||||
self.cmd.cmd4(addr, 0x2, fmt);
|
||||
self.cmd.cmd4(addr, 0x2, fmt)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_amplifier_gain_mute(
|
||||
@@ -838,7 +839,7 @@ impl IntelHDA {
|
||||
index: u8,
|
||||
mute: bool,
|
||||
gain: u8,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
let mut payload: u16 = 0;
|
||||
|
||||
if output {
|
||||
@@ -859,7 +860,8 @@ impl IntelHDA {
|
||||
payload |= ((index as u16) & 0x0F) << 8;
|
||||
payload |= (gain as u16) & 0x7F;
|
||||
|
||||
self.cmd.cmd4(addr, 0x3, payload);
|
||||
self.cmd.cmd4(addr, 0x3, payload)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_to_output(&mut self, index: u8, buf: &[u8]) -> Result<Option<usize>> {
|
||||
|
||||
Reference in New Issue
Block a user