Skip to content

rust-osdev/uart_16550

Repository files navigation

uart_16550

Simple yet highly configurable low-level driver for 16550 UART devices, typically known and used as serial ports or COM ports. Easy integration into Rust while providing fine-grained control where needed (e.g., for kernel drivers).

The "serial device" or "COM port" in typical x86 machines is almost always backed by a 16550 UART devices, may it be physical or emulated. This crate offers convenient and powerful abstractions for these devices, and also works for other architectures, such as ARM or RISC-V, by offering support for MMIO-mapped devices.

Serial ports are especially useful for debugging or operating system learning projects. See [Uart16550] to get started.

Features

  • ✅ Full configure, transmit, receive, and interrupt support for UART 16550–compatible devices
  • ✅ High-level, ergonomic abstractions and types paired with support for plain integers
  • ✅ Very easy to integrate, highly configurable when needed
  • ✅ Validated on real hardware as well as across different virtual machines
  • ✅ Fully type-safe and derived directly from the official specification
  • ✅ Supports both x86 port-mapped I/O and memory-mapped I/O (MMIO)
  • no_std-compatible and allocation-free by design

Focus, Scope & Limitations

While serial ports are often used in conjunction with VT102-like terminal emulation, the primary focus of this crate is strict specification compliance and convenient direct access to the underlying hardware for transmitting and receiving bytes, including all necessary device configuration.

For basic terminal-related functionality, such as newline normalization and backspace handling, we provide Uart16550Tty as a basic convenience layer.

Overview

Use Uart16550Tty for a quick start. For more fine-grained low-level control, please have a look at Uart16550 instead.

Example (Minimalistic)

use uart_16550::{Config, Uart16550Tty};
use core::fmt::Write;

fn main() {
  // SAFETY: The address is valid and we have exclusive access.
  let mut uart = unsafe { Uart16550Tty::new_mmio(0x1000 as *mut _, 4, Config::default()).expect("should initialize device") };
  //                                    ^ or `new_port(0x3f8, Config::default())`
  uart.write_str("hello world\nhow's it going?");
}

Example (More low-level control)

use uart_16550::{Config, Uart16550};

fn main() {
  // SAFETY: The address is valid and we have exclusive access.
  let mut uart = unsafe { Uart16550::new_mmio(0x1000 as *mut _, 4).expect("should be valid port") };
  //                                 ^ or `new_port(0x3f8)`
  uart.init(Config::default()).expect("should init device successfully");
  uart.test_loopback().expect("should have working loopback mode");
  uart.check_connected().expect("should have physically connected receiver");
  uart.send_bytes_exact(b"hello world!");
}

License

This project is licensed under either of

Changelog

See CHANGELOG.md.

About

Simple yet highly configurable low-level driver for 16550 UART devices, typically known and used as serial ports or COM ports.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Sponsor this project

 

Contributors

Languages