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