드라이버
이제 드라이버에서 새로운 Registers 구조체를 사용해 보겠습니다.
/// PL011 UART용 드라이버
#[derive(Debug)]
pub struct Uart {
registers: *mut Registers,
}
impl Uart {
/// 지정된 기본 주소에 PL011 기기에 대한 UART 드라이버의 새 인스턴스를
/// 생성합니다.
///
/// # 안전
///
/// 지정된 기본 주소는 PL011 기기의
/// MMIO 제어 레지스터 8개를 가리켜야 하며,
/// 이는 프로세스의 주소 공간에 기기 메모리로
/// 매핑되어야 하며 다른 별칭은 없어야 합니다.
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 버퍼에 씁니다.
addr_of_mut!((*self.registers).dr).write_volatile(byte.into());
}
// UART가 더 이상 사용 중이 아닐 때까지 기다립니다.
while self.read_flag_register().contains(Flags::BUSY) {}
}
/// Reads and returns a pending byte, or `None` if nothing has been
/// received.
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: 비트 8~11에서 오류 상태를 확인합니다.
Some(data as u8)
}
}
fn read_flag_register(&self) -> Flags {
// self.registers가 적절하게 매핑된 PL011 기기의 제어 레지스터를
// 가리키고 있으므로 안전합니다.
unsafe { addr_of!((*self.registers).fr).read_volatile() }
}
}
addr_of!/addr_of_mut!를 사용하여 중간 참조를 만들지 않고 개별 필드 포인터를 가져오는 것은 불안정할 수 있습니다.