Skip to main content

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}