ドライバ
新しく定義した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 mutto get pointers to individual fields without creating an intermediate reference, which would be unsound.