Driver

Agora vamos usar o novo struct Registers em nosso driver.

/// Driver para um UART PL011.
#[derive(Debug)]
pub struct Uart {
    registers: *mut Registers,
}

impl Uart {
    /// Constrói uma nova instùncia do driver UART para um dispositivo PL011 no endereço
    /// base fornecido.
    ///
    /// # Segurança
    ///
    /// O endereço base fornecido deve apontar para os 8 registradores de controle MMIO de um
    /// dispositivo PL011, que deve ser mapeado no espaço de endereços do processo
    /// como memĂłria de dispositivo e nĂŁo ter nenhum outro alias.
    pub unsafe fn new(base_address: *mut u32) -> Self {
        Self { registers: base_address as *mut Registers }
    }

    /// Grava um Ășnico byte no UART.
    pub fn write_byte(&self, byte: u8) {
        // Aguarde até que haja espaço no buffer TX.
        while self.read_flag_register().contains(Flags::TXFF) {}

        // Seguro porque sabemos que self.registers aponta para o controle
        // registradores de um dispositivo PL011 que estĂĄ mapeado adequadamente.
        unsafe {
            // Escreva no buffer TX.
            addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
        }

        // Aguarde até que o UART não esteja mais ocupado.
        while self.read_flag_register().contains(Flags::BUSY) {}
    }

    /// LĂȘ e retorna um byte pendente ou `None` se nada foi
    /// recebido.
    pub fn read_byte(&self) -> Option<u8> {
        if self.read_flag_register().contains(Flags::RXFE) {
            None
        } else {
            let data = unsafe { addr_of!((*self.registers).dr).read_volatile() };
            // TODO: Verifique as condiçÔes de erro nos bits 8-11.
            Some(data as u8)
        }
    }

    fn read_flag_register(&self) -> Flags {
        // Seguro porque sabemos que self.registers aponta para o controle
        // registradores de um dispositivo PL011 que estĂĄ mapeado adequadamente.
        unsafe { addr_of!((*self.registers).fr).read_volatile() }
    }
}
  • Observe o uso de addr_of! / addr_of_mut! para obter ponteiros para campos individuais sem criar uma referĂȘncia intermediĂĄria, o que seria incorreto.