From c9722c4024b1b95772a05bb11733c5e89dca9bf0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 21 Jan 2023 16:14:04 -0700 Subject: [PATCH] More work on sb16 driver --- sb16d/src/device.rs | 241 ++++++++++++++++++++++++++++++-------------- sb16d/src/main.rs | 223 ++++++++++++++++++++-------------------- 2 files changed, 273 insertions(+), 191 deletions(-) diff --git a/sb16d/src/device.rs b/sb16d/src/device.rs index cb77b075a9..f016cde002 100644 --- a/sb16d/src/device.rs +++ b/sb16d/src/device.rs @@ -14,100 +14,187 @@ const NUM_SUB_BUFFS: usize = 32; const SUB_BUFF_SIZE: usize = 2048; enum Handle { - Todo, + Todo, } #[allow(dead_code)] -struct DspRegs { - /* 0x06 */ reset: WriteOnly>, - /* 0x0A */ read_data: ReadOnly>, - /* 0x0C */ write_data: WriteOnly>, - /* 0x0C */ write_status: ReadOnly>, - /* 0x0E */ read_status: ReadOnly>, -} - -impl DspRegs { - fn new(addr: u16) -> Self { - Self { - reset: WriteOnly::new(Pio::new(addr + 0x06)), - read_data: ReadOnly::new(Pio::new(addr + 0x0A)), - write_data: WriteOnly::new(Pio::new(addr + 0x0C)), - write_status: ReadOnly::new(Pio::new(addr + 0x0C)), - read_status: ReadOnly::new(Pio::new(addr + 0x0E)), - } - } -} - pub struct Sb16 { - dsp: DspRegs, - handles: Mutex>, - next_id: AtomicUsize, + handles: Mutex>, + next_id: AtomicUsize, + pub(crate) irqs: Vec, + dmas: Vec, + // Regs + /* 0x04 */ mixer_addr: WriteOnly>, + /* 0x05 */ mixer_data: Pio, + /* 0x06 */ dsp_reset: WriteOnly>, + /* 0x0A */ dsp_read_data: ReadOnly>, + /* 0x0C */ dsp_write_data: WriteOnly>, + /* 0x0C */ dsp_write_status: ReadOnly>, + /* 0x0E */ dsp_read_status: ReadOnly>, } impl Sb16 { - pub unsafe fn new(addr: u16) -> Result { - let mut module = Sb16 { - dsp: DspRegs::new(addr), - handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0), - }; + pub unsafe fn new(addr: u16) -> Result { + let mut module = Sb16 { + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), + irqs: Vec::new(), + dmas: Vec::new(), + // Regs + mixer_addr: WriteOnly::new(Pio::new(addr + 0x04)), + mixer_data: Pio::new(addr + 0x05), + dsp_reset: WriteOnly::new(Pio::new(addr + 0x06)), + dsp_read_data: ReadOnly::new(Pio::new(addr + 0x0A)), + dsp_write_data: WriteOnly::new(Pio::new(addr + 0x0C)), + dsp_write_status: ReadOnly::new(Pio::new(addr + 0x0C)), + dsp_read_status: ReadOnly::new(Pio::new(addr + 0x0E)), + }; - module.init()?; + module.init()?; - Ok(module) - } + Ok(module) + } - fn init(&mut self) -> Result<()> { - // Perform DSP reset - { - // Write 1 to reset port - self.dsp.reset.write(1); + fn mixer_read(&mut self, index: u8) -> u8 { + self.mixer_addr.write(index); + self.mixer_data.read() + } - // Wait 3us - thread::sleep(time::Duration::from_micros(3)); + fn mixer_write(&mut self, index: u8, value: u8) { + self.mixer_addr.write(index); + self.mixer_data.write(value); + } - // Write 0 to reset port - self.dsp.reset.write(0); + fn dsp_read(&mut self) -> Result { + // Bit 7 must be 1 before data can be sent + while ! self.dsp_read_status.readf(1 << 7) { + //TODO: timeout! + std::thread::yield_now(); + } - //TODO: Wait for ready byte (0xAA) using read status - thread::sleep(time::Duration::from_micros(100)); + Ok(self.dsp_read_data.read()) + } - let ready = self.dsp.read_data.read(); - if ready != 0xAA { - log::error!("ready byte was 0x{:02X} instead of 0xAA", ready); - return Err(Error::new(ENODEV)); - } - } + fn dsp_write(&mut self, value: u8) -> Result<()> { + // Bit 7 must be 0 before data can be sent + while self.dsp_write_status.readf(1 << 7) { + //TODO: timeout! + std::thread::yield_now(); + } - // Read DSP version - { - //TODO - } + self.dsp_write_data.write(value); + Ok(()) + } - Ok(()) - } + fn init(&mut self) -> Result<()> { + // Perform DSP reset + { + // Write 1 to reset port + self.dsp_reset.write(1); - pub fn irq(&mut self) -> bool { - //TODO - false - } + // Wait 3us + thread::sleep(time::Duration::from_micros(3)); + + // Write 0 to reset port + self.dsp_reset.write(0); + + //TODO: Wait for ready byte (0xAA) using read status + thread::sleep(time::Duration::from_micros(100)); + + let ready = self.dsp_read()?; + if ready != 0xAA { + log::error!("ready byte was 0x{:02X} instead of 0xAA", ready); + return Err(Error::new(ENODEV)); + } + } + + // Read DSP version + { + self.dsp_write(0xE1)?; + + let major = self.dsp_read()?; + let minor = self.dsp_read()?; + log::info!("DSP version {}.{:02}", major, minor); + + if major != 4 { + log::error!("Unsupported DSP major version {}", major); + return Err(Error::new(ENODEV)); + } + } + + // Get available IRQs and DMAs + { + self.irqs.clear(); + let irq_mask = self.mixer_read(0x80); + if (irq_mask & (1 << 0)) != 0 { + self.irqs.push(2); + } + if (irq_mask & (1 << 1)) != 0 { + self.irqs.push(5); + } + if (irq_mask & (1 << 2)) != 0 { + self.irqs.push(7); + } + if (irq_mask & (1 << 3)) != 0 { + self.irqs.push(10); + } + + self.dmas.clear(); + let dma_mask = self.mixer_read(0x81); + if (dma_mask & (1 << 0)) != 0 { + self.dmas.push(0); + } + if (dma_mask & (1 << 1)) != 0 { + self.dmas.push(1); + } + if (dma_mask & (1 << 3)) != 0 { + self.dmas.push(3); + } + if (dma_mask & (1 << 5)) != 0 { + self.dmas.push(5); + } + if (dma_mask & (1 << 6)) != 0 { + self.dmas.push(6); + } + if (dma_mask & (1 << 7)) != 0 { + self.dmas.push(7); + } + + log::info!("IRQs {:02X?} DMAs {:02X?}", self.irqs, self.dmas); + } + + // Set output sample rate to 44100 Hz (Redox OS standard) + { + let rate = 44100u16; + self.dsp_write(0x41)?; + self.dsp_write((rate >> 8) as u8)?; + self.dsp_write(rate as u8)?; + } + + Ok(()) + } + + pub fn irq(&mut self) -> bool { + //TODO + false + } } impl SchemeBlockMut for Sb16 { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 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 open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 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> { - //TODO - Err(Error::new(EBADF)) - } + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + //TODO + Err(Error::new(EBADF)) + } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let mut handles = self.handles.lock(); @@ -122,8 +209,8 @@ impl SchemeBlockMut for Sb16 { Ok(Some(i)) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) - } + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } } diff --git a/sb16d/src/main.rs b/sb16d/src/main.rs index 027eac1a11..5415e2fcb6 100644 --- a/sb16d/src/main.rs +++ b/sb16d/src/main.rs @@ -63,145 +63,140 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - let mut args = env::args().skip(1); + let mut args = env::args().skip(1); - //TODO: add addr to name? - let name = "sb16".to_string(); + let addr_str = args.next().unwrap_or("220".to_string()); + let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); - let addr_str = args.next().unwrap_or("220".to_string()); - let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); + print!("{}", format!(" + sb16 at 0x{:X}\n", addr)); - let irq_str = args.next().unwrap_or("5".to_string()); - let irq = irq_str.parse::().expect("sb16: failed to parse irq"); - - let dma_str = args.next().unwrap_or("1".to_string()); - let dma = dma_str.parse::().expect("sb16: failed to parse dma"); - - print!("{}", format!(" + sb16 at: ADDR 0x{:X}, IRQ {}, DMA {}\n", addr, irq, dma)); - - // Daemonize + // Daemonize redox_daemon::Daemon::new(move |daemon| { - let _logger_ref = setup_logging(); + let _logger_ref = setup_logging(); unsafe { syscall::iopl(3) }.expect("sb16d: failed to set I/O privilege level to Ring 3"); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("sb16d: failed to open IRQ file"); + let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + //TODO: error on multiple IRQs? + let mut irq_file = match device.borrow().irqs.first() { + Some(irq) => File::open(format!("irq:{}", irq)).expect("sb16d: failed to open IRQ file"), + None => panic!("sb16d: no IRQs found"), + }; daemon.ready().expect("sb16d: failed to signal readiness"); - let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); + let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); syscall::setrens(0, 0).expect("sb16d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let todo = Arc::new(RefCell::new(Vec::::new())); - let todo_irq = todo.clone(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + let device_irq = device.clone(); + let socket_irq = socket.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; - if device_irq.borrow_mut().irq() { - irq_file.write(&mut irq)?; + if 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() { - 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 mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + 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(None) - }).expect("sb16d: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + Ok(None) + }).expect("sb16d: failed to catch events on IRQ file"); + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_event| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } - if let Some(a) = device.borrow_mut().handle(&mut packet) { - packet.a = a; - socket_packet.borrow_mut().write(&packet)?; - } else { - todo.borrow_mut().push(packet); - } - } + if let Some(a) = device.borrow_mut().handle(&mut packet) { + packet.a = a; + socket_packet.borrow_mut().write(&packet)?; + } else { + todo.borrow_mut().push(packet); + } + } - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ - Ok(None) - }).expect("sb16d: failed to catch events on IRQ file"); + Ok(None) + }).expect("sb16d: failed to catch events on IRQ file"); - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: EventFlags::empty(), - }).expect("sb16d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("sb16d: failed to write event"); - } + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }).expect("sb16d: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("sb16d: failed to write event"); + } - loop { - { - //device_loop.borrow_mut().handle_interrupts(); - } - let event_count = event_queue.run().expect("sb16d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } + loop { + { + //device_loop.borrow_mut().handle_interrupts(); + } + let event_count = event_queue.run().expect("sb16d: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("sb16d: failed to write event"); - } + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("sb16d: failed to write event"); + } std::process::exit(0); - }).expect("sb16d: failed to daemonize"); + }).expect("sb16d: failed to daemonize"); }