diff --git a/machine/src/platform/rpi3/fb.rs b/machine/src/platform/rpi3/fb.rs index e09fbd8..68fe44a 100644 --- a/machine/src/platform/rpi3/fb.rs +++ b/machine/src/platform/rpi3/fb.rs @@ -1,107 +1,70 @@ -use { - super::{ - mailbox::{channel, read, write, MailboxOps, RegisterBlock, Result}, - BcmHost, - }, - core::ops::Deref, -}; +use super::mailbox::{self, LocalMailboxStorage, Mailbox, MailboxError, MailboxOps}; /// FrameBuffer channel supported structure - use with mailbox::channel::FrameBuffer /// Must have the same alignment as the mailbox buffers. -#[repr(C)] -#[repr(align(16))] +type FrameBufferData = LocalMailboxStorage<10>; + +mod index { + pub const WIDTH: usize = 0; + pub const HEIGHT: usize = 1; + pub const VIRTUAL_WIDTH: usize = 2; + pub const VIRTUAL_HEIGHT: usize = 3; + pub const PITCH: usize = 4; + pub const DEPTH: usize = 5; + pub const X_OFFSET: usize = 6; + pub const Y_OFFSET: usize = 7; + pub const POINTER: usize = 8; // FIXME: could be 4096 for the alignment restriction. + pub const SIZE: usize = 9; +} + pub struct FrameBuffer { - pub width: u32, - pub height: u32, - pub vwidth: u32, - pub vheight: u32, - pub pitch: u32, - pub depth: u32, - pub x_offset: u32, - pub y_offset: u32, - pub pointer: u32, - pub size: u32, - // Must be after HW-dictated fields to not break structure alignment. - base_addr: usize, + mailbox: Mailbox<10, FrameBufferData>, } -// @todo rewrite in terms of using the Mailbox - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*FrameBuffer::ptr()).STATUS.read() } -/// ``` -impl Deref for FrameBuffer { - type Target = RegisterBlock; // mailbox RegisterBlock reused here - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl core::fmt::Debug for FrameBuffer { +impl core::fmt::Debug for FrameBufferData { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!( f, "\n\n\n#### FrameBuffer({}x{}, {}x{}, d{}, --{}--, +{}x{}, {}@{:x})\n\n\n", - self.width, - self.height, - self.vwidth, - self.vheight, - self.depth, - self.pitch, - self.x_offset, - self.y_offset, - self.size, - self.pointer, + self.storage[index::WIDTH], + self.storage[index::HEIGHT], + self.storage[index::VIRTUAL_WIDTH], + self.storage[index::VIRTUAL_HEIGHT], + self.storage[index::HEIGHT], + self.storage[index::PITCH], + self.storage[index::X_OFFSET], + self.storage[index::Y_OFFSET], + self.storage[index::SIZE], + self.storage[index::POINTER], ) } } impl FrameBuffer { - pub fn new(reg_base: usize, width: u32, height: u32, depth: u32) -> FrameBuffer { - FrameBuffer { - width, - height, - vwidth: width, - vheight: height, - pitch: 0, - depth, - x_offset: 0, - y_offset: 0, - pointer: 0, // could be 4096 for the alignment? - size: 0, - - base_addr: reg_base, - } + pub fn new( + base_addr: usize, + width: u32, + height: u32, + depth: u32, + ) -> Result { + let mut fb = FrameBuffer { + mailbox: unsafe { Mailbox::<10, FrameBufferData>::new(base_addr)? }, + }; + fb.mailbox.buffer.storage[index::WIDTH] = width; + fb.mailbox.buffer.storage[index::VIRTUAL_WIDTH] = width; + fb.mailbox.buffer.storage[index::HEIGHT] = height; + fb.mailbox.buffer.storage[index::VIRTUAL_HEIGHT] = height; + fb.mailbox.buffer.storage[index::DEPTH] = depth; + Ok(fb) } } impl MailboxOps for FrameBuffer { - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.base_addr as *const _ + fn write(&self, _channel: u32) -> mailbox::Result<()> { + self.mailbox.do_write(mailbox::channel::FrameBuffer) } - /// says: - /// **With the exception of the property tags mailbox channel,** - /// when passing memory addresses as the data part of a mailbox message, - /// the addresses should be **bus addresses as seen from the VC.** - fn write(&self, _channel: u32) -> Result<()> { - write( - self, - BcmHost::phys2bus(&self as *const _ as usize) as *const _, - channel::FrameBuffer, - ) - } - - fn read(&self, _channel: u32) -> Result<()> { - read(self, 0, channel::FrameBuffer) + fn read(&self, _channel: u32) -> mailbox::Result<()> { + unsafe { self.mailbox.do_read(mailbox::channel::FrameBuffer, 0) } } } diff --git a/machine/src/platform/rpi3/mailbox.rs b/machine/src/platform/rpi3/mailbox.rs index fe4c112..bac0533 100644 --- a/machine/src/platform/rpi3/mailbox.rs +++ b/machine/src/platform/rpi3/mailbox.rs @@ -13,16 +13,16 @@ use { super::BcmHost, - crate::println, + crate::{platform::MMIODerefWrapper, println}, core::{ - ops::Deref, - ptr::NonNull, + result::Result as CoreResult, sync::atomic::{compiler_fence, Ordering}, }, cortex_a::asm::barrier, + snafu::Snafu, tock_registers::{ interfaces::{Readable, Writeable}, - register_bitfields, + register_bitfields, register_structs, registers::{ReadOnly, WriteOnly}, }, }; @@ -31,15 +31,16 @@ use { /// The address for the buffer needs to be 16-byte aligned /// so that the VideoCore can handle it properly. /// The reason is that lowest 4 bits of the address will contain the channel number. -pub struct Mailbox { - // pub buffer: &'a mut [u32], - base_addr: usize, - buffer: NonNull<[u32]>, +pub struct Mailbox> { + registers: Registers, + pub buffer: Storage, } /// Mailbox that is ready to be called. /// This prevents invalid use of the mailbox until it is fully prepared. -pub struct PreparedMailbox(Mailbox); +pub struct PreparedMailbox>( + Mailbox, +); const MAILBOX_ALIGNMENT: usize = 16; const MAILBOX_ITEMS_COUNT: usize = 36; @@ -57,6 +58,9 @@ const CHANNEL_MASK: u32 = 0xf; // always for communication from VC to ARM and Mailbox 1 is for ARM to VC. // // The ARM should never write Mailbox 0 or read Mailbox 1. +// +// There are 32 mailboxes on the ARM, which could be used for in-processor or inter-processor comms, +// TODO: allow using all of them. register_bitfields! { u32, @@ -69,42 +73,35 @@ register_bitfields! { ] } -#[allow(non_snake_case)] -#[repr(C)] -pub struct RegisterBlock { - READ: ReadOnly, // 0x00 This is Mailbox0 read for ARM, can't write - __reserved_0: [u32; 5], // 0x04 - STATUS: ReadOnly, // 0x18 - __reserved_1: u32, // 0x1C - WRITE: WriteOnly, // 0x20 This is Mailbox1 write for ARM, can't read -} - -pub enum MailboxError { - Response, - Unknown, - Timeout, -} - -impl core::fmt::Display for MailboxError { - fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - write!( - f, - "{}", - match self { - MailboxError::Response => "ResponseError", - MailboxError::Unknown => "UnknownError", - MailboxError::Timeout => "Timeout", - } - ) +register_structs! { + #[allow(non_snake_case)] + pub RegisterBlock { + (0x00 => READ: ReadOnly), // This is Mailbox0 read for ARM, can't write + (0x04 => __reserved_1), + (0x18 => STATUS: ReadOnly), + (0x1c => __reserved_2), + (0x20 => WRITE: WriteOnly), // This is Mailbox1 write for ARM, can't read + (0x24 => @END), } } -pub type Result = ::core::result::Result; +// Hide RegisterBlock from public api. +type Registers = MMIODerefWrapper; + +#[derive(Snafu, Debug)] +pub enum MailboxError { + #[snafu(display("ResponseError"))] + Response, + #[snafu(display("UnknownError"))] + Unknown, + #[snafu(display("Timeout"))] + Timeout, +} + +pub type Result = CoreResult; /// Typical operations with a mailbox. pub trait MailboxOps { - /// Deref from self to a mailbox RegisterBlock. Used by Deref implementations. - fn ptr(&self) -> *const RegisterBlock; fn write(&self, channel: u32) -> Result<()>; fn read(&self, channel: u32) -> Result<()>; fn call(&self, channel: u32) -> Result<()> { @@ -113,6 +110,50 @@ pub trait MailboxOps { } } +pub trait MailboxStorage { + fn new() -> Self; +} + +pub trait MailboxStorageRef { + fn as_ref(&self) -> &[u32]; + fn as_mut(&mut self) -> &mut [u32]; + fn as_ptr(&self) -> *const u32; + fn value_at(&self, index: usize) -> u32; +} + +// TODO: allow from 2 to 36 slots (2 because you need at least an End tag) +#[repr(align(16))] // MAILBOX_ALIGNMENT +pub struct LocalMailboxStorage { + pub storage: [u32; N_SLOTS], +} + +impl MailboxStorage for LocalMailboxStorage { + fn new() -> Self { + Self { + storage: [0u32; N_SLOTS], + } + } +} + +impl MailboxStorageRef for LocalMailboxStorage { + fn as_ref(&self) -> &[u32] { + &self.storage + } + + fn as_mut(&mut self) -> &mut [u32] { + &mut self.storage + } + + fn as_ptr(&self) -> *const u32 { + self.storage.as_ptr() + } + + // @todo Probably need a ResultMailbox for accessing data after call()? + fn value_at(&self, index: usize) -> u32 { + self.storage[index] + } +} + /* * Source https://elinux.org/RPi_Framebuffer * Source for channels 8 and 9: https://github.com/raspberrypi/firmware/wiki/Mailboxes @@ -243,144 +284,39 @@ pub mod alpha_mode { pub const IGNORED: u32 = 2; } -pub fn write(regs: &RegisterBlock, buf: *const u32, channel: u32) -> Result<()> { - let mut count: u32 = 0; - let buf_ptr: u32 = buf as u32; - - // This address adjustment will be performed from the outside when necessary - // (see FrameBuffer for example). - // let buf_ptr = BcmHost::phys2bus(buf_ptr); not used for PropertyTags channel - - println!("Mailbox::write {:#08x}/{:#x}", buf_ptr, channel); - - // Insert a compiler fence that ensures that all stores to the - // mailbox buffer are finished before the GPU is signaled (which is - // done by a store operation as well). - compiler_fence(Ordering::Release); - - while regs.STATUS.is_set(STATUS::FULL) { - count += 1; - if count > (1 << 25) { - return Err(MailboxError::Timeout); - } - } - unsafe { - barrier::dmb(barrier::SY); - } - regs.WRITE - .set((buf_ptr & !CHANNEL_MASK) | (channel & CHANNEL_MASK)); - Ok(()) -} - -pub fn read(regs: &RegisterBlock, expected: u32, channel: u32) -> Result<()> { - loop { - let mut count: u32 = 0; - while regs.STATUS.is_set(STATUS::EMPTY) { - count += 1; - if count > (1 << 25) { - println!("Timed out waiting for mailbox response"); - return Err(MailboxError::Timeout); - } - } - - /* Read the data - * Data memory barriers as we've switched peripheral - */ - unsafe { - barrier::dmb(barrier::SY); - } - let data: u32 = regs.READ.get(); - unsafe { - barrier::dmb(barrier::SY); - } - - println!( - "Received mailbox response {:#08x}, expecting {:#08x}", - data, expected - ); - - // is it a response to our message? - if ((data & CHANNEL_MASK) == channel) && ((data & !CHANNEL_MASK) == expected) { - // is it a valid successful response? - return Ok(()); - } else { - // ignore invalid responses and loop again. - // will return Timeout above if no matching response is received. - } - } -} - -/// Deref to RegisterBlock -/// -/// Allows writing -/// ``` -/// self.STATUS.read() -/// ``` -/// instead of something along the lines of -/// ``` -/// unsafe { (*Mailbox::ptr()).STATUS.read() } -/// ``` -impl Deref for PreparedMailbox { - type Target = RegisterBlock; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr() } - } -} - -impl core::fmt::Debug for Mailbox { +impl core::fmt::Debug for Mailbox { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { - let count = unsafe { self.buffer.as_ref()[0] } / 4; - assert_eq!(unsafe { self.buffer.as_ref()[0] }, count * 4); + let count = self.buffer.as_ref()[0] / 4; + assert_eq!(self.buffer.as_ref()[0], count * 4); assert!(count <= 36); for i in 0usize..count as usize { - writeln!(f, "[{:02}] {:08x}", i, unsafe { self.buffer.as_ref()[i] })?; + writeln!(f, "[{:02}] {:08x}", i, self.buffer.value_at(i))?; } Ok(()) } } -impl core::fmt::Debug for PreparedMailbox { +impl core::fmt::Debug for PreparedMailbox { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { self.0.fmt(f) } } -impl Default for Mailbox { +impl Default for Mailbox { fn default() -> Self { - Self::new(MAILBOX_BASE).expect("Couldn't allocate a default mailbox") + unsafe { Self::new(MAILBOX_BASE) }.expect("Couldn't allocate a default mailbox") } } -// @todo Probably need a ResultMailbox for accessing data after call()? -impl PreparedMailbox { - pub fn value_at(&self, index: usize) -> u32 { - unsafe { self.0.buffer.as_ref()[index] } - } -} - -impl Mailbox { - /// Create a new mailbox in the DMA-able memory area. - #[allow(clippy::result_unit_err)] - pub fn new(base_addr: usize) -> ::core::result::Result { - use core::alloc::Allocator; - crate::DMA_ALLOCATOR - .lock(|dma| { - dma.allocate_zeroed( - core::alloc::Layout::from_size_align( - MAILBOX_ITEMS_COUNT * core::mem::size_of::(), - MAILBOX_ALIGNMENT, - ) - .unwrap(), // .map_err(|_| ())?, - ) - }) - .map(|ret| { - Ok(Mailbox { - base_addr, - buffer: ret.cast::<[u32; MAILBOX_ITEMS_COUNT]>(), - }) - }) - .map_err(|_| ())? +impl Mailbox { + /// Create a new mailbox locally in an aligned stack space. + /// # Safety + /// Caller is responsible for picking the correct MMIO register base address. + pub unsafe fn new(base_addr: usize) -> Result> { + Ok(Mailbox { + registers: Registers::new(base_addr), + buffer: Storage::new(), + }) } // Specific mailbox functions @@ -390,19 +326,17 @@ impl Mailbox { /// @returns index of the next available slot. #[inline] pub fn request(&mut self) -> usize { - unsafe { self.buffer.as_mut()[1] = REQUEST }; + self.buffer.as_mut()[1] = REQUEST; 2 } /// Mark mailbox payload as completed. /// Consumes the Mailbox and returns a Preparedmailbox that can be called. #[inline] - pub fn end(mut self, index: usize) -> PreparedMailbox { + pub fn end(mut self, index: usize) -> PreparedMailbox { // @todo return Result - unsafe { - self.buffer.as_mut()[index] = tag::End; - self.buffer.as_mut()[0] = (index as u32 + 1) * 4; - } + self.buffer.as_mut()[index] = tag::End; + self.buffer.as_mut()[0] = (index as u32 + 1) * 4; PreparedMailbox(self) } @@ -410,7 +344,7 @@ impl Mailbox { /// @returns index of the next available slot. #[inline] pub fn set_physical_wh(&mut self, index: usize, width: u32, height: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetPhysicalWH; buf[index + 1] = 8; // Buffer size // val buf size buf[index + 2] = 8; // Request size // val size @@ -423,7 +357,7 @@ impl Mailbox { /// @returns index of the next available slot. #[inline] pub fn set_virtual_wh(&mut self, index: usize, width: u32, height: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetVirtualWH; buf[index + 1] = 8; // Buffer size // val buf size buf[index + 2] = 8; // Request size // val size @@ -436,7 +370,7 @@ impl Mailbox { /// @returns index of the next available slot. #[inline] pub fn set_depth(&mut self, index: usize, depth: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetDepth; buf[index + 1] = 4; // Buffer size // val buf size buf[index + 2] = 4; // Request size // val size @@ -448,7 +382,7 @@ impl Mailbox { /// @returns index of the next available slot. #[inline] pub fn allocate_buffer_aligned(&mut self, index: usize, alignment: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::AllocateBuffer; buf[index + 1] = 8; // Buffer size // val buf size buf[index + 2] = 4; // Request size // val size @@ -461,7 +395,7 @@ impl Mailbox { /// @returns index of the next available slot. #[inline] pub fn set_led_on(&mut self, index: usize, enable: bool) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetGpioState; buf[index + 1] = 8; // Buffer size // val buf size buf[index + 2] = 0; // Response size // val size @@ -472,7 +406,7 @@ impl Mailbox { #[inline] pub fn set_clock_rate(&mut self, index: usize, channel: u32, rate: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetClockRate; buf[index + 1] = 12; // Buffer size // val buf size buf[index + 2] = 8; // Response size // val size @@ -488,7 +422,7 @@ impl Mailbox { /// and no tags will be returned. #[inline] pub fn set_pixel_order(&mut self, index: usize, order: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetPixelOrder; buf[index + 1] = 4; // Buffer size // val buf size buf[index + 2] = 4; // Response size // val size @@ -502,7 +436,7 @@ impl Mailbox { /// and no tags will be returned. #[inline] pub fn test_pixel_order(&mut self, index: usize, order: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::TestPixelOrder; buf[index + 1] = 4; // Buffer size // val buf size buf[index + 2] = 4; // Response size // val size @@ -512,7 +446,7 @@ impl Mailbox { #[inline] pub fn set_alpha_mode(&mut self, index: usize, mode: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetAlphaMode; buf[index + 1] = 4; // Buffer size // val buf size buf[index + 2] = 4; // Response size // val size @@ -522,7 +456,7 @@ impl Mailbox { #[inline] pub fn get_pitch(&mut self, index: usize) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::GetPitch; buf[index + 1] = 4; // Buffer size // val buf size buf[index + 2] = 4; // Response size // val size @@ -532,7 +466,7 @@ impl Mailbox { #[inline] pub fn set_device_power(&mut self, index: usize, device_id: u32, power_flags: u32) -> usize { - let buf = unsafe { self.buffer.as_mut() }; + let buf = self.buffer.as_mut(); buf[index] = tag::SetPowerState; buf[index + 1] = 8; // Buffer size // val buf size buf[index + 2] = 8; // Response size // val size @@ -540,42 +474,130 @@ impl Mailbox { buf[index + 4] = power_flags; // bit 0: off, bit 1: no wait index + 5 } -} -impl MailboxOps for PreparedMailbox { - /// Returns a pointer to the register block - fn ptr(&self) -> *const RegisterBlock { - self.0.base_addr as *const _ - } + // Actual work functions - fn write(&self, channel: u32) -> Result<()> { - write(self, self.0.buffer.as_ptr() as *const _, channel) - } + /// says: + /// **With the exception of the property tags mailbox channel,** + /// when passing memory addresses as the data part of a mailbox message, + /// the addresses should be **bus addresses as seen from the VC.** + pub fn do_write(&self, channel: u32) -> Result<()> { + let buf_ptr = self.buffer.as_ptr() as *const u32 as u32; + let buf_ptr = if channel != channel::PropertyTagsArmToVc { + BcmHost::phys2bus(buf_ptr as usize) as u32 + } else { + buf_ptr + }; - // @todo read() should probably consume PreparedMailbox completely ? - fn read(&self, channel: u32) -> Result<()> { - // SAFETY: buffer is HW-mutable in the read call below! - read( - self, - self.0.buffer.as_ptr() as *const [u32] as *const u32 as u32, - channel, - )?; + let mut count: u32 = 0; - match unsafe { self.0.buffer.as_ref()[1] } { - response::SUCCESS => { - println!("\n######\nMailbox::returning SUCCESS"); - Ok(()) - } - response::ERROR => { - println!("\n######\nMailbox::returning ResponseError"); - Err(MailboxError::Response) - } - _ => { - println!("\n######\nMailbox::returning UnknownError"); - println!("{:x}\n######", unsafe { self.0.buffer.as_ref()[1] }); - Err(MailboxError::Unknown) + println!("Mailbox::write {:#08x}/{:#x}", buf_ptr, channel); + + // Insert a compiler fence that ensures that all stores to the + // mailbox buffer are finished before the GPU is signaled (which is + // done by a store operation as well). + compiler_fence(Ordering::Release); + + while self.registers.STATUS.is_set(STATUS::FULL) { + count += 1; + if count > (1 << 25) { + return Err(MailboxError::Timeout); } } + unsafe { + barrier::dmb(barrier::SY); + } + self.registers + .WRITE + .set((buf_ptr & !CHANNEL_MASK) | (channel & CHANNEL_MASK)); + Ok(()) + } + + /// Perform the mailbox read. + /// + /// # Safety + /// + /// Buffer will be mutated by the hardware before read operation is completed. + pub unsafe fn do_read(&self, channel: u32, expected: u32) -> Result<()> { + loop { + let mut count: u32 = 0; + while self.registers.STATUS.is_set(STATUS::EMPTY) { + count += 1; + if count > (1 << 25) { + println!("Timed out waiting for mailbox response"); + return Err(MailboxError::Timeout); + } + } + + /* Read the data + * Data memory barriers as we've switched peripheral + */ + barrier::dmb(barrier::SY); + let data: u32 = self.registers.READ.get(); + barrier::dmb(barrier::SY); + + println!( + "Received mailbox response {:#08x}, expecting {:#08x}", + data, expected + ); + + // is it a response to our message? + if ((data & CHANNEL_MASK) == channel) && ((data & !CHANNEL_MASK) == expected) { + // is it a valid successful response? + return match self.buffer.value_at(1) { + response::SUCCESS => { + println!("\n######\nMailbox::returning SUCCESS"); + Ok(()) + } + response::ERROR => { + println!("\n######\nMailbox::returning ResponseError"); + Err(MailboxError::Response) + } + _ => { + println!("\n######\nMailbox::returning UnknownError"); + println!("{:x}\n######", self.buffer.value_at(1)); + Err(MailboxError::Unknown) + } + }; + } else { + // ignore invalid responses and loop again. + // will return Timeout above if no matching response is received. + } + } + } +} + +impl MailboxOps + for PreparedMailbox +{ + fn write(&self, channel: u32) -> Result<()> { + self.0.do_write(channel) + } + + // @todo read() should probably consume PreparedMailbox completely - because request is overwritten with response + fn read(&self, channel: u32) -> Result<()> { + unsafe { self.0.do_read(channel, self.0.buffer.as_ptr() as u32) } + } +} + +impl MailboxStorageRef + for PreparedMailbox +{ + fn as_ref(&self) -> &[u32] { + self.0.buffer.as_ref() + } + + fn as_mut(&mut self) -> &mut [u32] { + self.0.buffer.as_mut() + } + + fn as_ptr(&self) -> *const u32 { + self.0.buffer.as_ptr() + } + + // @todo Probably need a ResultMailbox for accessing data after call()? + fn value_at(&self, index: usize) -> u32 { + self.0.buffer.value_at(index) } } diff --git a/machine/src/platform/rpi3/power.rs b/machine/src/platform/rpi3/power.rs index 4d0d3b9..190612a 100644 --- a/machine/src/platform/rpi3/power.rs +++ b/machine/src/platform/rpi3/power.rs @@ -84,7 +84,7 @@ impl Power { pub fn off(&self, gpio: &gpio::GPIO) -> Result<()> { // power off devices one by one for dev_id in 0..16 { - let mut mbox = Mailbox::default(); + let mut mbox = Mailbox::<8>::default(); let index = mbox.request(); let index = mbox.set_device_power(index, dev_id, POWER_STATE_OFF | POWER_STATE_DO_NOT_WAIT); diff --git a/machine/src/platform/rpi3/vc.rs b/machine/src/platform/rpi3/vc.rs index e545fb2..4e48a6b 100644 --- a/machine/src/platform/rpi3/vc.rs +++ b/machine/src/platform/rpi3/vc.rs @@ -8,7 +8,7 @@ use { mailbox::{self, channel, response::VAL_LEN_FLAG, Mailbox, MailboxOps}, BcmHost, }, - crate::println, + crate::{platform::rpi3::mailbox::MailboxStorageRef, println}, core::convert::TryInto, snafu::Snafu, }; @@ -42,7 +42,7 @@ impl VC { * (if the base or size has changed) is implicitly freed. */ - let mut mbox = Mailbox::default(); + let mut mbox = Mailbox::<36>::default(); let index = mbox.request(); let index = mbox.set_physical_wh(index, w, h); let index = mbox.set_virtual_wh(index, w, h); @@ -67,7 +67,7 @@ impl VC { // SetPixelOrder doesn't work in QEMU, however TestPixelOrder does. // Apparently, QEMU doesn't care about intermixing Get/Set and Test tags either. - let mut mbox = Mailbox::default(); + let mut mbox = Mailbox::<36>::default(); let index = mbox.request(); #[cfg(qemu)] let index = mbox.test_pixel_order(index, 1); diff --git a/nucleus/src/main.rs b/nucleus/src/main.rs index dea9eae..7755f36 100644 --- a/nucleus/src/main.rs +++ b/nucleus/src/main.rs @@ -171,7 +171,7 @@ fn print_help() { } fn set_led(enable: bool) { - let mut mbox = Mailbox::default(); + let mut mbox = Mailbox::<8>::default(); let index = mbox.request(); let index = mbox.set_led_on(index, enable); let mbox = mbox.end(index);