@@ -205,6 +205,15 @@ impl<const SIZE: usize> Io<SIZE> {
205205 }
206206 }
207207
208+ #[ inline]
209+ const fn length_valid ( offset : usize , length : usize , size : usize ) -> bool {
210+ if let Some ( end) = offset. checked_add ( length) {
211+ end <= size
212+ } else {
213+ false
214+ }
215+ }
216+
208217 #[ inline]
209218 fn io_addr < U > ( & self , offset : usize ) -> Result < usize > {
210219 if !Self :: offset_valid :: < U > ( offset, self . maxsize ( ) ) {
@@ -223,6 +232,46 @@ impl<const SIZE: usize> Io<SIZE> {
223232 self . addr ( ) + offset
224233 }
225234
235+ /// Copy memory block from an i/o memory by filling the specified buffer with it.
236+ ///
237+ /// # Examples
238+ /// ```
239+ /// use kernel::io::mem::IoMem;
240+ /// use kernel::io::mem::Resource;
241+ ///
242+ /// fn test(device: &Device, res: Resource) -> Result {
243+ /// // Create an i/o memory block of at least 100 bytes.
244+ /// let devres_mem = IoMem::<100>::new(res, device)?;
245+ /// // aquire access to memory block
246+ /// let mem = devres_mem.try_access()?;
247+ ///
248+ /// let mut buffer: [u8; 32] = [0; 32];
249+ ///
250+ /// // Memcpy 16 bytes from an offset 10 of i/o memory block into the buffer.
251+ /// mem.try_memcpy_fromio(&mut buffer[..16], 10)?;
252+ ///
253+ /// Ok(())
254+ /// }
255+ /// ```
256+ pub fn try_memcpy_fromio ( & self , buffer : & mut [ u8 ] , offset : usize ) -> Result {
257+ if buffer. len ( ) == 0 || !Self :: length_valid ( offset, buffer. len ( ) , self . maxsize ( ) ) {
258+ return Err ( EINVAL ) ;
259+ }
260+ let addr = self . io_addr :: < crate :: ffi:: c_char > ( offset) ?;
261+
262+ // SAFETY:
263+ // - The type invariants guarantee that `adr` is a valid pointer.
264+ // - The bounds of `buffer` are checked with a call to `length_valid`.
265+ unsafe {
266+ bindings:: memcpy_fromio (
267+ buffer. as_mut_ptr ( ) as * mut _ ,
268+ addr as * const _ ,
269+ buffer. len ( ) as _ ,
270+ )
271+ } ;
272+ Ok ( ( ) )
273+ }
274+
226275 define_read ! ( read8, try_read8, readb -> u8 ) ;
227276 define_read ! ( read16, try_read16, readw -> u16 ) ;
228277 define_read ! ( read32, try_read32, readl -> u32 ) ;
0 commit comments