Skip to content

Commit 6c5e129

Browse files
committed
Add try_create and loopback_test for SerialPort
fixes rust-osdev#30
1 parent 378d468 commit 6c5e129

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

src/port.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,65 @@ impl SerialPort {
6464
Self(base)
6565
}
6666

67+
/// Creates a new serial port interface on the given I/O base port and initializes it.
68+
///
69+
/// This function returns `Err(())` if the serial port fails a simple loopback test.
70+
///
71+
/// This function is unsafe because the caller must ensure that the given base address
72+
/// really points to a serial port device and that the caller has the necessary rights
73+
/// to perform the I/O operation.
74+
pub unsafe fn try_create(base: u16) -> Result<Self, ()> {
75+
let mut port = unsafe { Self::new(base) };
76+
77+
port.init();
78+
79+
port.loopback_test()?;
80+
81+
Ok(port)
82+
}
83+
84+
/// Tests that the serial port is working.
85+
///
86+
/// This function temporarily sets the serial port into loopback mode and
87+
/// performse a simple write and read, checking that the same
88+
/// value is read. If not this function returns `Err(())`.
89+
pub fn loopback_test(&mut self) -> Result<(), ()> {
90+
self.loopback_test_with(0xae)
91+
}
92+
93+
/// Tests that the serial port is working.
94+
///
95+
/// This function temporarily sets the serial port into loopback mode and
96+
/// performse a simple write of `data` and read, checking that the same
97+
/// value is read. If not this function returns `Err(())`.
98+
pub fn loopback_test_with(&mut self, data: u8) -> Result<(), ()> {
99+
unsafe {
100+
// Disable interrupts
101+
x86::io::outb(self.port_int_en(), 0x00);
102+
103+
// Set the serial port into loopback mode
104+
x86::io::outb(self.port_modem_ctrl(), 0x1e);
105+
106+
// write `data` to the data port
107+
x86::io::outb(self.port_data(), data);
108+
109+
// read back the value we just wrote
110+
let loopback = x86::io::inb(self.port_data());
111+
if loopback != data {
112+
return Err(());
113+
}
114+
115+
// Mark data terminal ready, signal request to send
116+
// and enable auxilliary output #2 (used as interrupt line for CPU)
117+
x86::io::outb(self.port_modem_ctrl(), 0x0b);
118+
119+
// Enable interrupts
120+
x86::io::outb(self.port_int_en(), 0x01);
121+
}
122+
123+
Ok(())
124+
}
125+
67126
/// Initializes the serial port.
68127
///
69128
/// The default configuration of [38400/8-N-1](https://en.wikipedia.org/wiki/8-N-1) is used.

0 commit comments

Comments
 (0)