From 17dd119582d2e4092d9c2c8a0c03b98adb28eb49 Mon Sep 17 00:00:00 2001 From: Burkhard Mittelbach Date: Thu, 5 Oct 2023 05:59:27 +0200 Subject: [PATCH] Add try_create and loopback_test for SerialPort fixes #30 --- src/port.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/port.rs b/src/port.rs index d9c07f2..749824c 100644 --- a/src/port.rs +++ b/src/port.rs @@ -64,6 +64,56 @@ impl SerialPort { Self(base) } + /// Creates a new serial port interface on the given I/O base port and initializes it. + /// + /// This function returns `Err(())` if the serial port fails a simple loopback test. + /// + /// This function is unsafe because the caller must ensure that the given base address + /// really points to a serial port device and that the caller has the necessary rights + /// to perform the I/O operation. + pub unsafe fn try_create(base: u16) -> Result { + let mut port = unsafe { Self::new(base) }; + + port.init(); + + port.loopback_test()?; + + Ok(port) + } + + /// Tests that the serial port is working. + /// + /// This function temporarily sets the serial port into loopback mode and + /// performse a simple write and read, checking that the same + /// value is read. If not this function returns `Err(())`. + pub fn loopback_test(&mut self) -> Result<(), ()> { + unsafe { + // Disable interrupts + x86::io::outb(self.port_int_en(), 0x00); + + // Set the serial port into loopback mode + x86::io::outb(self.port_modem_ctrl(), 0x1e); + + // write `0xae` to the data port + x86::io::outb(self.port_data(), 0xae); + + // read back the value we just wrote + let loopback = x86::io::inb(self.port_data()); + if loopback != 0xae { + return Err(()); + } + + // Mark data terminal ready, signal request to send + // and enable auxilliary output #2 (used as interrupt line for CPU) + x86::io::outb(self.port_modem_ctrl(), 0x0b); + + // Enable interrupts + x86::io::outb(self.port_int_en(), 0x01); + } + + Ok(()) + } + /// Initializes the serial port. /// /// The default configuration of [38400/8-N-1](https://en.wikipedia.org/wiki/8-N-1) is used.