Conductor
Ahora vamos a utilizar la nueva estructura de Registers
en nuestro controlador.
/// Controlador para un UART PL011. #[derive(Debug)] pub struct Uart { registers: *mut Registers, } impl Uart { /// Construye una instancia nueva del controlador de UART para un dispositivo PL011 en la /// dirección base proporcionada. /// /// # Seguridad /// /// La dirección base debe apuntar a los 8 registros de control MMIO de un /// dispositivo PL011, que debe asignarse al espacio de direcciones del proceso /// como memoria del dispositivo y no tener ningún otro alias. pub unsafe fn new(base_address: *mut u32) -> Self { Self { registers: base_address as *mut Registers } } /// Escribe un solo byte en el UART. pub fn write_byte(&self, byte: u8) { // Espera hasta que haya espacio en el búfer de 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 { // Escribe en el búfer de TX. addr_of_mut!((*self.registers).dr).write_volatile(byte.into()); } // Espera hasta que el UART esté libre. while self.read_flag_register().contains(Flags::BUSY) {} } /// Lee y devuelve un byte pendiente o `None` si no se ha recibido nada ///. 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 { addr_of!((*self.registers).dr).read_volatile() }; // TAREA: Comprueba si hay condiciones de error en los bits 8 a 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 { addr_of!((*self.registers).fr).read_volatile() } } }
- Fíjate en el uso de
addr_of!
yaddr_of_mut!
para llevar punteros a campos individuales sin crear una referencia intermedia. Sería una acción insegura.