드라이버

이제 드라이버에서 새로운 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!를 사용하여 중간 참조를 만들지 않고 개별 필드 포인터를 가져오는 것은 불안정할 수 있습니다.