Драйвер

Тепер давайте використаємо нову структуру Registers у нашому драйвері.

/// Драйвер для PL011 UART.
#[derive(Debug)]
pub struct Uart {
    registers: *mut Registers,
}

impl Uart {
    /// Створює новий екземпляр драйвера UART для пристрою PL011
    /// за заданою базовою адресою.
    ///
    /// # Безпека
    ///
    /// Задана базова адреса повинна вказувати на 8 керуючих регістрів MMIO пристрою 
    /// PL011, які повинні бути відображені в адресному просторі процесу
    /// як пам'ять пристрою і не мати ніяких інших псевдонімів.
    pub unsafe fn new(base_address: *mut u32) -> Self {
        Self { registers: base_address as *mut Registers }
    }

    /// Записує один байт до UART.
    pub fn write_byte(&self, byte: u8) {
        // Чекаємо, поки не звільниться місце в буфері TX.
        while self.read_flag_register().contains(Flags::TXFF) {}

        // БЕЗПЕКА: ми знаємо, що self.registers вказує на керуючі
        // регістри пристрою PL011, який відповідним чином відображено.
        unsafe {
            // Записуємо в буфер TX.
            (&raw mut (*self.registers).dr).write_volatile(byte.into());
        }

        // Чекаємо, поки UART більше не буде зайнято.
        while self.read_flag_register().contains(Flags::BUSY) {}
    }

    /// Читає і повертає байт очікування, або `None`, якщо нічого не було
    /// отримано.
    pub fn read_byte(&self) -> Option<u8> {
        if self.read_flag_register().contains(Flags::RXFE) {
            None
        } else {
            // БЕЗПЕКА: ми знаємо, що self.registers вказує на керуючі
        // регістри пристрою PL011, який відповідним чином відображено.
            let data = unsafe { (&raw const (*self.registers).dr).read_volatile() };
            // TODO: Перевірити на наявність помилок у бітах 8-11.
            Some(data as u8)
        }
    }

    fn read_flag_register(&self) -> Flags {
        // БЕЗПЕКА: ми знаємо, що self.registers вказує на керуючі
        // регістри пристрою PL011, який відповідним чином відображено.
        unsafe { (&raw const (*self.registers).fr).read_volatile() }
    }
}
  • Зверніть увагу на використання &raw const / &raw mut для отримання вказівників на окремі поля без створення проміжного посилання, що було б нерозумним.