#![doc = include_str!("../README.md")]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![deny(clippy::all)]
#![deny(clippy::pedantic)]
#![deny(clippy::cargo)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::cast_sign_loss)]
use std::{
fs::File,
os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd},
};
mod ioctl;
use ioctl::dma_heap_alloc;
use ioctl::dma_heap_allocation_data;
use log::debug;
use strum_macros::Display;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("The Requested DMA Heap Type ({0}) doesn't exist: {1}")]
Missing(HeapKind, String),
#[error("An Error occurred while accessing the DMA Heap")]
Access(std::io::Error),
#[error("The requested allocation is invalid: {0} bytes")]
InvalidAllocation(usize),
#[error("No Memory Left in the Heap")]
NoMemoryLeft,
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self::Access(err)
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Copy, Debug, Display)]
pub enum HeapKind {
Cma,
System,
}
#[derive(Debug)]
pub struct Heap {
file: File,
name: HeapKind,
}
impl Heap {
pub fn new(name: HeapKind) -> Result<Self> {
let path = match name {
HeapKind::Cma => "/dev/dma_heap/linux,cma",
HeapKind::System => "/dev/dma_heap/system",
};
debug!("Using the {} DMA-Buf Heap, at {}", name, path);
let file = File::open(path).map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => Error::Missing(name, String::from(path)),
_ => Error::from(err),
})?;
debug!("Heap found!");
Ok(Self { file, name })
}
pub fn allocate(&self, len: usize) -> Result<OwnedFd> {
let mut fd_flags = nix::fcntl::OFlag::empty();
fd_flags.insert(nix::fcntl::OFlag::O_CLOEXEC);
fd_flags.insert(nix::fcntl::OFlag::O_RDWR);
let mut data = dma_heap_allocation_data {
len: len as u64,
fd_flags: fd_flags.bits() as u32,
..dma_heap_allocation_data::default()
};
debug!("Allocating Buffer of size {} on {} Heap", len, self.name);
unsafe { dma_heap_alloc(self.file.as_raw_fd(), &mut data) }.map_err(|err| {
let err: std::io::Error = err.try_into().unwrap();
match err.kind() {
std::io::ErrorKind::InvalidInput => Error::InvalidAllocation(len),
std::io::ErrorKind::OutOfMemory => Error::NoMemoryLeft,
_ => Error::from(err),
}
})?;
debug!("Allocation succeeded, Buffer File Descriptor {}", data.fd);
Ok(unsafe { OwnedFd::from_raw_fd(data.fd as RawFd) })
}
}