dma_heap/
lib.rs

1// Copyright 2020-2021, Cerno
2// Licensed under the MIT License
3// See the LICENSE file or <http://opensource.org/licenses/MIT>
4
5#![cfg_attr(
6    feature = "nightly",
7    feature(non_exhaustive_omitted_patterns_lint, strict_provenance_lints)
8)]
9#![cfg_attr(
10    feature = "nightly",
11    warn(
12        fuzzy_provenance_casts,
13        lossy_provenance_casts,
14        unnameable_types,
15        non_exhaustive_omitted_patterns,
16    )
17)]
18#![doc = include_str!("../README.md")]
19#![allow(unsafe_code)]
20
21use core::fmt;
22use std::{
23    fs::File,
24    io,
25    os::{fd::AsFd as _, unix::io::OwnedFd},
26    path::PathBuf,
27};
28
29mod ioctl;
30use ioctl::dma_heap_alloc;
31use log::debug;
32
33/// Various Types of DMA-Buf Heap
34#[derive(Clone, Debug)]
35pub enum HeapKind {
36    /// A Heap backed by the Contiguous Memory Allocator in the Linux kernel, returning physically
37    /// contiguous, cached, buffers
38    Cma,
39
40    /// A Heap backed by the vmalloc allocator in the Linux kernel, returning virtually contiguous,
41    /// cached, buffers
42    System,
43
44    /// The Path to a custom Heap Type.
45    Custom(PathBuf),
46}
47
48impl fmt::Display for HeapKind {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        match self {
51            HeapKind::Cma => f.write_str("CMA"),
52            HeapKind::System => f.write_str("System"),
53            HeapKind::Custom(p) => f.write_fmt(format_args!("Custom Heap ({})", p.display())),
54        }
55    }
56}
57
58/// Our DMA-Buf Heap
59#[derive(Debug)]
60pub struct Heap {
61    file: File,
62    name: HeapKind,
63}
64
65impl Heap {
66    /// Opens A DMA-Buf Heap of the specified type
67    ///
68    /// # Errors
69    ///
70    /// Will return [Error] if the Heap Type is not found in the system, or if the open call fails.
71    pub fn new(name: HeapKind) -> io::Result<Self> {
72        let path = match &name {
73            HeapKind::Cma => PathBuf::from("/dev/dma_heap/linux,cma"),
74            HeapKind::System => PathBuf::from("/dev/dma_heap/system"),
75            HeapKind::Custom(p) => p.clone(),
76        };
77
78        debug!("Using the {name} DMA-Buf Heap, at {}", path.display());
79
80        let file = File::open(&path)?;
81
82        debug!("Heap found!");
83
84        Ok(Self { file, name })
85    }
86
87    /// Allocates a DMA-Buf from the Heap with the specified size
88    ///
89    /// # Panics
90    ///
91    /// If the errno returned by the underlying `ioctl()` cannot be decoded
92    /// into an `std::io::Error`.
93    ///
94    /// # Errors
95    ///
96    /// Will return [Error] if the underlying ioctl fails.
97    pub fn allocate(&self, len: usize) -> io::Result<OwnedFd> {
98        debug!("Allocating Buffer of size {} on {} Heap", len, self.name);
99
100        let fd = dma_heap_alloc(self.file.as_fd(), len)?;
101
102        debug!("Allocation succeeded, Buffer File Descriptor {fd:#?}");
103
104        Ok(fd)
105    }
106}