Driver
Now let’s use the new Registers struct in our driver.
/// 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 at the/// given base address.////// # Safety////// The given base address 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(base_address: *mut u32) -> Self {Self { registers: base_address as *mut Registers }}/// Writes a single byte to the UART.pub fn write_byte(&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(&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() }}}
- Note the use of
&raw const/&raw mutto get pointers to individual fields without creating an intermediate reference, which would be unsound.