use core::ptr::NonNull;
use crate::proto::unsafe_protocol;
use crate::util::opt_nonnull_to_ptr;
use crate::{Event, Result, Status, StatusExt};
pub use uefi_raw::protocol::block::{BlockIo2Protocol, BlockIoProtocol, Lba};
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(BlockIoProtocol::GUID)]
pub struct BlockIO(BlockIoProtocol);
impl BlockIO {
#[must_use]
pub const fn media(&self) -> &BlockIOMedia {
unsafe { &*self.0.media.cast::<BlockIOMedia>() }
}
pub fn reset(&mut self, extended_verification: bool) -> Result {
unsafe { (self.0.reset)(&mut self.0, extended_verification.into()) }.to_result()
}
pub fn read_blocks(&self, media_id: u32, lba: Lba, buffer: &mut [u8]) -> Result {
let buffer_size = buffer.len();
unsafe {
(self.0.read_blocks)(
&self.0,
media_id,
lba,
buffer_size,
buffer.as_mut_ptr().cast(),
)
}
.to_result()
}
pub fn write_blocks(&mut self, media_id: u32, lba: Lba, buffer: &[u8]) -> Result {
let buffer_size = buffer.len();
unsafe {
(self.0.write_blocks)(
&mut self.0,
media_id,
lba,
buffer_size,
buffer.as_ptr().cast(),
)
}
.to_result()
}
pub fn flush_blocks(&mut self) -> Result {
unsafe { (self.0.flush_blocks)(&mut self.0) }.to_result()
}
}
#[repr(transparent)]
#[derive(Debug)]
pub struct BlockIOMedia(uefi_raw::protocol::block::BlockIoMedia);
impl BlockIOMedia {
#[must_use]
pub const fn media_id(&self) -> u32 {
self.0.media_id
}
#[must_use]
pub fn is_removable_media(&self) -> bool {
self.0.removable_media.into()
}
#[must_use]
pub fn is_media_present(&self) -> bool {
self.0.media_present.into()
}
#[must_use]
pub fn is_logical_partition(&self) -> bool {
self.0.logical_partition.into()
}
#[must_use]
pub fn is_read_only(&self) -> bool {
self.0.read_only.into()
}
#[must_use]
pub fn is_write_caching(&self) -> bool {
self.0.write_caching.into()
}
#[must_use]
pub const fn block_size(&self) -> u32 {
self.0.block_size
}
#[must_use]
pub const fn io_align(&self) -> u32 {
self.0.io_align
}
#[must_use]
pub const fn last_block(&self) -> Lba {
self.0.last_block
}
#[must_use]
pub const fn lowest_aligned_lba(&self) -> Lba {
self.0.lowest_aligned_lba
}
#[must_use]
pub const fn logical_blocks_per_physical_block(&self) -> u32 {
self.0.logical_blocks_per_physical_block
}
#[must_use]
pub const fn optimal_transfer_length_granularity(&self) -> u32 {
self.0.optimal_transfer_length_granularity
}
}
#[repr(C)]
#[derive(Debug)]
pub struct BlockIO2Token {
pub event: Option<Event>,
pub transaction_status: Status,
}
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(BlockIo2Protocol::GUID)]
pub struct BlockIO2(BlockIo2Protocol);
impl BlockIO2 {
#[must_use]
pub const fn media(&self) -> &BlockIOMedia {
unsafe { &*self.0.media.cast::<BlockIOMedia>() }
}
pub fn reset(&mut self, extended_verification: bool) -> Result {
unsafe { (self.0.reset)(&mut self.0, extended_verification.into()) }.to_result()
}
pub unsafe fn read_blocks_ex(
&self,
media_id: u32,
lba: Lba,
token: Option<NonNull<BlockIO2Token>>,
len: usize,
buffer: *mut u8,
) -> Result {
let token = opt_nonnull_to_ptr(token);
unsafe { (self.0.read_blocks_ex)(&self.0, media_id, lba, token.cast(), len, buffer.cast()) }
.to_result()
}
pub unsafe fn write_blocks_ex(
&mut self,
media_id: u32,
lba: Lba,
token: Option<NonNull<BlockIO2Token>>,
len: usize,
buffer: *const u8,
) -> Result {
let token = opt_nonnull_to_ptr(token);
unsafe {
(self.0.write_blocks_ex)(&mut self.0, media_id, lba, token.cast(), len, buffer.cast())
}
.to_result()
}
pub fn flush_blocks_ex(&mut self, token: Option<NonNull<BlockIO2Token>>) -> Result {
let token = opt_nonnull_to_ptr(token);
unsafe { (self.0.flush_blocks_ex)(&mut self.0, token.cast()) }.to_result()
}
}