Skip to main content

dma_api/
map_single.rs

1use core::{num::NonZeroUsize, ptr::NonNull};
2
3use alloc::vec::Vec;
4
5use crate::{DeviceDma, DmaDirection, DmaError, DmaMapHandle};
6
7/// 映射单个连续内存区域的 DMA 数组。
8///
9/// `SArrayPtr<T>` 将现有的缓冲区(如栈数组或堆分配的 slice)映射为 DMA 可访问区域。
10/// 与 `DArray<T>` 不同,此类型提供手动缓存同步控制。
11///
12/// # 缓存同步
13///
14/// **重要**: `SArrayPtr` **不会**在每次访问时自动同步缓存。
15/// 你必须使用特定方法进行缓存同步:
16/// - `to_vec()`: 读取前自动失效整个范围
17/// - `copy_from_slice()`: 写入后自动刷新整个范围
18/// - `read()`/`set()`: **不**执行自动缓存同步
19///
20/// # 生命周期
21///
22/// `SArrayPtr` 在离开作用域时自动解除 DMA 映射,但**不会**自动同步缓存。
23/// 必须在映射解除前手动完成必要的缓存同步操作。
24///
25/// # 类型参数
26///
27/// - `T`: 数组元素类型
28///
29/// # 示例
30///
31/// ```rust,ignore
32/// use dma_api::{DeviceDma, DmaDirection};
33///
34/// let mut buffer = [0u8; 4096];
35/// let device = DeviceDma::new(0xFFFFFFFF, &my_dma_impl);
36///
37/// // 映射用于 DMA 写入
38/// let mut mapping = device.map_single_array(&buffer, 64, DmaDirection::ToDevice)?;
39///
40/// // 必须手动刷新缓存
41/// mapping.copy_from_slice(&data);
42///
43/// // ... 启动 DMA 传输 ...
44///
45/// // 映射在作用域结束时自动解映射
46/// ```
47pub struct SArrayPtr<T> {
48    handle: DmaMapHandle,
49    osal: DeviceDma,
50    pub direction: DmaDirection,
51    _marker: core::marker::PhantomData<*mut T>,
52}
53
54impl<T> SArrayPtr<T> {
55    /// Create a new SArrayPtr from a raw pointer and size.
56    pub(crate) fn map_single(
57        os: &DeviceDma,
58        buff: &[T],
59        align: usize,
60        direction: DmaDirection,
61    ) -> Result<Self, DmaError> {
62        let addr = NonNull::new(buff.as_ptr() as *mut u8).ok_or(DmaError::NullPointer)?;
63        let size =
64            NonZeroUsize::new(core::mem::size_of_val(buff)).ok_or(DmaError::ZeroSizedBuffer)?;
65        let handle = unsafe { os._map_single(addr, size, align, direction)? };
66
67        Ok(Self {
68            handle,
69            osal: os.clone(),
70            direction,
71            _marker: core::marker::PhantomData,
72        })
73    }
74
75    /// 从 slice 复制数据到映射的缓冲区。
76    ///
77    /// 复制完成后刷新整个缓冲区的 CPU 缓存(ToDevice/Bidirectional)。
78    /// 这是手动同步缓存的主要方式之一。
79    ///
80    /// # 参数
81    ///
82    /// - `src`: 源 slice
83    ///
84    /// # Panics
85    ///
86    /// 如果源 slice 大于 DMA 缓冲区大小则 panic
87    pub fn copy_from_slice(&mut self, src: &[T]) {
88        assert!(
89            core::mem::size_of_val(src) <= self.handle.size(),
90            "Source slice is larger than DMA buffer"
91        );
92        unsafe {
93            let dest_ptr = self.handle.cpu_addr.cast::<T>();
94            dest_ptr
95                .as_ptr()
96                .copy_from_nonoverlapping(src.as_ptr(), src.len());
97        }
98        self.osal
99            .confirm_write(&self.handle, 0, self.handle.size(), self.direction);
100    }
101
102    /// 获取 DMA 地址。
103    ///
104    /// 返回设备用于访问此 DMA 缓冲区的物理/DMA 地址。
105    ///
106    /// # 返回
107    ///
108    /// DMA 地址
109    pub fn dma_addr(&self) -> crate::DmaAddr {
110        self.handle.dma_addr
111    }
112
113    /// 获取数组长度(元素个数)。
114    ///
115    /// # 返回
116    ///
117    /// 数组中的元素个数
118    pub fn len(&self) -> usize {
119        self.handle.size() / core::mem::size_of::<T>()
120    }
121
122    /// 检查数组是否为空。
123    ///
124    /// # 返回
125    ///
126    /// 如果数组长度为 0 返回 `true`,否则返回 `false`
127    pub fn is_empty(&self) -> bool {
128        self.len() == 0
129    }
130
131    /// 读取指定索引的元素(不自动同步缓存)。
132    ///
133    /// **注意**: 此方法**不会**自动同步缓存。
134    /// 如果需要缓存同步,请使用 `to_vec()` 方法。
135    ///
136    /// # 参数
137    ///
138    /// - `index`: 元素索引
139    ///
140    /// # 返回
141    ///
142    /// 如果索引有效返回 `Some(T)`,否则返回 `None`
143    pub fn read(&self, index: usize) -> Option<T> {
144        if index >= self.len() {
145            return None;
146        }
147
148        unsafe {
149            let offset = index * core::mem::size_of::<T>();
150            self.osal.prepare_read(
151                &self.handle,
152                offset,
153                core::mem::size_of::<T>(),
154                self.direction,
155            );
156            let ptr = self.handle.cpu_addr.cast::<T>().add(index);
157            Some(ptr.read())
158        }
159    }
160
161    /// 设置指定索引的元素值(不自动同步缓存)。
162    ///
163    /// **注意**: 此方法**不会**自动同步缓存。
164    /// 写入后请使用 `copy_from_slice()` 或手动刷新缓存。
165    ///
166    /// # 参数
167    ///
168    /// - `index`: 元素索引
169    /// - `value`: 要写入的值
170    ///
171    /// # Panics
172    ///
173    /// 如果 `index >= self.len()` 则 panic
174    pub fn set(&mut self, index: usize, value: T) {
175        assert!(
176            index < self.len(),
177            "index out of range, index: {},len: {}",
178            index,
179            self.len()
180        );
181
182        unsafe {
183            let ptr = self.handle.cpu_addr.cast::<T>().add(index);
184            ptr.write(value);
185        }
186
187        self.osal.confirm_write(
188            &self.handle,
189            index * core::mem::size_of::<T>(),
190            core::mem::size_of::<T>(),
191            self.direction,
192        );
193    }
194
195    /// 将整个数组转换为 Vec(自动同步缓存)。
196    ///
197    /// 这是读取映射数据并同步缓存的主要方式。
198    /// 读取前会自动使 CPU 缓存失效(FromDevice/Bidirectional)。
199    ///
200    /// # 返回
201    ///
202    /// 包含所有元素的 Vec
203    pub fn to_vec(&self) -> Vec<T> {
204        let mut vec: Vec<T> = Vec::with_capacity(self.len());
205        self.osal
206            .prepare_read(&self.handle, 0, self.handle.size(), self.direction);
207        unsafe {
208            let src_ptr = self.handle.cpu_addr.as_ptr().cast::<T>();
209            let dst_ptr = vec.as_mut_ptr();
210            dst_ptr.copy_from_nonoverlapping(src_ptr, self.len());
211            vec.set_len(self.len());
212        }
213        vec
214    }
215
216    pub fn prepare_read_all(&self) {
217        self.osal
218            .prepare_read(&self.handle, 0, self.handle.size(), self.direction);
219    }
220
221    pub fn confirm_write_all(&self) {
222        self.osal
223            .confirm_write(&self.handle, 0, self.handle.size(), self.direction);
224    }
225}
226
227impl<T> Drop for SArrayPtr<T> {
228    fn drop(&mut self) {
229        unsafe {
230            self.osal.unmap_single(self.handle);
231        }
232    }
233}