Driver

Now let’s use the new Registers struct in our driver.

  1. /// Driver for a PL011 UART.
  2. #[derive(Debug)]
  3. pub struct Uart {
  4.     registers: *mut Registers,
  5. }
  6. impl Uart {
  7.     /// Constructs a new instance of the UART driver for a PL011 device at the
  8.     /// given base address.
  9.     ///
  10.     /// # Safety
  11.     ///
  12.     /// The given base address must point to the 8 MMIO control registers of a
  13.     /// PL011 device, which must be mapped into the address space of the process
  14.     /// as device memory and not have any other aliases.
  15.     pub unsafe fn new(base_address: *mut u32) -> Self {
  16.         Self { registers: base_address as *mut Registers }
  17.     }
  18.     /// Writes a single byte to the UART.
  19.     pub fn write_byte(&self, byte: u8) {
  20.         // Wait until there is room in the TX buffer.
  21.         while self.read_flag_register().contains(Flags::TXFF) {}
  22.         // SAFETY: We know that self.registers points to the control registers
  23.         // of a PL011 device which is appropriately mapped.
  24.         unsafe {
  25.             // Write to the TX buffer.
  26.             (&raw mut (*self.registers).dr).write_volatile(byte.into());
  27.         }
  28.         // Wait until the UART is no longer busy.
  29.         while self.read_flag_register().contains(Flags::BUSY) {}
  30.     }
  31.     /// Reads and returns a pending byte, or `None` if nothing has been
  32.     /// received.
  33.     pub fn read_byte(&self) -> Option<u8> {
  34.         if self.read_flag_register().contains(Flags::RXFE) {
  35.             None
  36.         } else {
  37.             // SAFETY: We know that self.registers points to the control
  38.             // registers of a PL011 device which is appropriately mapped.
  39.             let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
  40.             // TODO: Check for error conditions in bits 8-11.
  41.             Some(data as u8)
  42.         }
  43.     }
  44.     fn read_flag_register(&self) -> Flags {
  45.         // SAFETY: We know that self.registers points to the control registers
  46.         // of a PL011 device which is appropriately mapped.
  47.         unsafe { (&raw const (*self.registers).fr).read_volatile() }
  48.     }
  49. }
  • Note the use of &raw const / &raw mut to get pointers to individual fields without creating an intermediate reference, which would be unsound.