ドライバ
新しく定義した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.