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}