1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
//! Minimal support for //! [serial communication](https://en.wikipedia.org/wiki/Asynchronous_serial_communication) //! through [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter) //! devices, which are compatible to the [16550 UART](https://en.wikipedia.org/wiki/16550_UART). //! //! This crate supports port-mapped and memory mapped UARTS. //! //! ## Usage //! //! Depending on the system architecture, the UART can be either accessed through //! [port-mapped I/O](https://wiki.osdev.org/Port_IO) or //! [memory-mapped I/O](https://en.wikipedia.org/wiki/Memory-mapped_I/O). //! //! ### With port-mappd I/O //! //! The UART is accessed through port-mapped I/O on architectures such as `x86_64`. //! On these architectures, the [`SerialPort`] type can be used: //! //! //! ```no_run //! # #[cfg(target_arch = "x86_64")] //! # fn main() { //! use uart_16550::SerialPort; //! //! const SERIAL_IO_PORT: u16 = 0x3F8; //! //! let mut serial_port = unsafe { SerialPort::new(SERIAL_IO_PORT) }; //! serial_port.init(); //! //! // Now the serial port is ready to be used. To send a byte: //! serial_port.send(42); //! //! // To receive a byte: //! let data = serial_port.receive(); //! # } //! # #[cfg(not(target_arch = "x86_64"))] //! # fn main() {} //! ``` //! //! ### With memory mapped serial port //! //! Most other architectures, such as [RISC-V](https://en.wikipedia.org/wiki/RISC-V), use //! memory-mapped I/O for accessing the UARTs. On these architectures, the [`MmioSerialPort`] //! type can be used: //! //! ```no_run //! use uart_16550::MmioSerialPort; //! //! const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000; //! //! let mut serial_port = unsafe { MmioSerialPort::new(SERIAL_PORT_BASE_ADDRESS) }; //! serial_port.init(); //! //! // Now the serial port is ready to be used. To send a byte: //! serial_port.send(42); //! //! // To receive a byte: //! let data = serial_port.receive(); //! ``` #![no_std] #![warn(missing_docs)] #![cfg_attr(feature = "nightly", feature(const_ptr_offset))] #![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(not(any(feature = "stable", feature = "nightly")))] compile_error!("Either the `stable` or `nightly` feature must be enabled"); use bitflags::bitflags; macro_rules! wait_for { ($cond:expr) => { while !$cond { core::hint::spin_loop() } }; } /// Memory mapped implementation mod mmio; #[cfg(target_arch = "x86_64")] /// Port asm commands implementation mod port; pub use crate::mmio::MmioSerialPort; #[cfg(target_arch = "x86_64")] pub use crate::port::SerialPort; bitflags! { /// Interrupt enable flags struct IntEnFlags: u8 { const RECEIVED = 1; const SENT = 1 << 1; const ERRORED = 1 << 2; const STATUS_CHANGE = 1 << 3; // 4 to 7 are unused } } bitflags! { /// Line status flags struct LineStsFlags: u8 { const INPUT_FULL = 1; // 1 to 4 unknown const OUTPUT_EMPTY = 1 << 5; // 6 and 7 unknown } }