You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-07-03 21:39:51 +02:00
168 lines
4.7 KiB
Rust
168 lines
4.7 KiB
Rust
![]() |
// Copyright 2023 Google LLC
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
#![allow(dead_code)]
|
||
|
|
||
|
use core::fmt::{self, Write};
|
||
|
|
||
|
// ANCHOR: Flags
|
||
|
use bitflags::bitflags;
|
||
|
|
||
|
bitflags! {
|
||
|
/// Flags from the UART flag register.
|
||
|
#[repr(transparent)]
|
||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
|
struct Flags: u16 {
|
||
|
/// Clear to send.
|
||
|
const CTS = 1 << 0;
|
||
|
/// Data set ready.
|
||
|
const DSR = 1 << 1;
|
||
|
/// Data carrier detect.
|
||
|
const DCD = 1 << 2;
|
||
|
/// UART busy transmitting data.
|
||
|
const BUSY = 1 << 3;
|
||
|
/// Receive FIFO is empty.
|
||
|
const RXFE = 1 << 4;
|
||
|
/// Transmit FIFO is full.
|
||
|
const TXFF = 1 << 5;
|
||
|
/// Receive FIFO is full.
|
||
|
const RXFF = 1 << 6;
|
||
|
/// Transmit FIFO is empty.
|
||
|
const TXFE = 1 << 7;
|
||
|
/// Ring indicator.
|
||
|
const RI = 1 << 8;
|
||
|
}
|
||
|
}
|
||
|
// ANCHOR_END: Flags
|
||
|
|
||
|
bitflags! {
|
||
|
/// Flags from the UART Receive Status Register / Error Clear Register.
|
||
|
#[repr(transparent)]
|
||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||
|
struct ReceiveStatus: u16 {
|
||
|
/// Framing error.
|
||
|
const FE = 1 << 0;
|
||
|
/// Parity error.
|
||
|
const PE = 1 << 1;
|
||
|
/// Break error.
|
||
|
const BE = 1 << 2;
|
||
|
/// Overrun error.
|
||
|
const OE = 1 << 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ANCHOR: Registers
|
||
|
#[repr(C, align(4))]
|
||
|
pub struct Registers {
|
||
|
dr: u16,
|
||
|
_reserved0: [u8; 2],
|
||
|
rsr: ReceiveStatus,
|
||
|
_reserved1: [u8; 19],
|
||
|
fr: Flags,
|
||
|
_reserved2: [u8; 6],
|
||
|
ilpr: u8,
|
||
|
_reserved3: [u8; 3],
|
||
|
ibrd: u16,
|
||
|
_reserved4: [u8; 2],
|
||
|
fbrd: u8,
|
||
|
_reserved5: [u8; 3],
|
||
|
lcr_h: u8,
|
||
|
_reserved6: [u8; 3],
|
||
|
cr: u16,
|
||
|
_reserved7: [u8; 3],
|
||
|
ifls: u8,
|
||
|
_reserved8: [u8; 3],
|
||
|
imsc: u16,
|
||
|
_reserved9: [u8; 2],
|
||
|
ris: u16,
|
||
|
_reserved10: [u8; 2],
|
||
|
mis: u16,
|
||
|
_reserved11: [u8; 2],
|
||
|
icr: u16,
|
||
|
_reserved12: [u8; 2],
|
||
|
dmacr: u8,
|
||
|
_reserved13: [u8; 3],
|
||
|
}
|
||
|
// ANCHOR_END: Registers
|
||
|
|
||
|
// ANCHOR: Uart
|
||
|
/// Driver for a PL011 UART.
|
||
|
#[derive(Debug)]
|
||
|
pub struct Uart {
|
||
|
registers: *mut Registers,
|
||
|
}
|
||
|
|
||
|
impl Uart {
|
||
|
/// Constructs a new instance of the UART driver for a PL011 device with the
|
||
|
/// given set of registers.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// The given pointer must point to the 8 MMIO control registers of a PL011
|
||
|
/// device, which must be mapped into the address space of the process as
|
||
|
/// device memory and not have any other aliases.
|
||
|
pub unsafe fn new(registers: *mut Registers) -> Self {
|
||
|
Self { registers }
|
||
|
}
|
||
|
|
||
|
/// Writes a single byte to the UART.
|
||
|
pub fn write_byte(&mut self, byte: u8) {
|
||
|
// Wait until there is room in the TX buffer.
|
||
|
while self.read_flag_register().contains(Flags::TXFF) {}
|
||
|
|
||
|
// SAFETY: We know that self.registers points to the control registers
|
||
|
// of a PL011 device which is appropriately mapped.
|
||
|
unsafe {
|
||
|
// Write to the TX buffer.
|
||
|
(&raw mut (*self.registers).dr).write_volatile(byte.into());
|
||
|
}
|
||
|
|
||
|
// Wait until the UART is no longer busy.
|
||
|
while self.read_flag_register().contains(Flags::BUSY) {}
|
||
|
}
|
||
|
|
||
|
/// Reads and returns a pending byte, or `None` if nothing has been
|
||
|
/// received.
|
||
|
pub fn read_byte(&mut self) -> Option<u8> {
|
||
|
if self.read_flag_register().contains(Flags::RXFE) {
|
||
|
None
|
||
|
} else {
|
||
|
// SAFETY: We know that self.registers points to the control
|
||
|
// registers of a PL011 device which is appropriately mapped.
|
||
|
let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
|
||
|
// TODO: Check for error conditions in bits 8-11.
|
||
|
Some(data as u8)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn read_flag_register(&self) -> Flags {
|
||
|
// SAFETY: We know that self.registers points to the control registers
|
||
|
// of a PL011 device which is appropriately mapped.
|
||
|
unsafe { (&raw const (*self.registers).fr).read_volatile() }
|
||
|
}
|
||
|
}
|
||
|
// ANCHOR_END: Uart
|
||
|
|
||
|
impl Write for Uart {
|
||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||
|
for c in s.as_bytes() {
|
||
|
self.write_byte(*c);
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Safe because it just contains a pointer to device memory, which can be
|
||
|
// accessed from any context.
|
||
|
unsafe impl Send for Uart {}
|