ドライバ

新しく定義したRegisters 構造体を我々のドライバで使ってみましょう。

/// PL011 UART のドライバ。
#[derive(Debug)]
pub struct Uart {
    registers: *mut Registers,
}

impl Uart {
    /// 指定されたベースアドレスに存在する
    /// PL011 デバイス用の UART ドライバの新しいインスタンスを作成します。
    ///
    /// # 安全性
    ///
    /// 指定されたベースアドレスは PL011 デバイスの 8 つの MMIO 制御レジスタを指していなければなりません。
    /// これらはデバイスメモリとしてプロセスのアドレス空間に
    /// マッピングされ、他のエイリアスはありません。
    pub unsafe fn new(base_address: *mut u32) -> Self {
        Self { registers: base_address as *mut Registers }
    }

    /// UART に 1 バイトを書き込みます。
    pub fn write_byte(&self, byte: u8) {
        // TX バッファに空きができるまで待機します。
        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 {
            // 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 {
            // 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: ビット 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 mut to get pointers to individual fields without creating an intermediate reference, which would be unsound.