diff --git a/audio/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs index 6ada5f43c8..f968f0dcce 100644 --- a/audio/ihdad/src/hda/cmdbuff.rs +++ b/audio/ihdad/src/hda/cmdbuff.rs @@ -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 { + { + // 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 { + { + // 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 { 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 { 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 { 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 { 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 { + 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(()) } } diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index 9bbd3c8226..df50cf13bd 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -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 { 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 { - 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> { + 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::::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 { + pub fn find_best_output_pin(&mut self) -> Result { 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> { @@ -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 { + 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 { + 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> {