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