@@ -230,6 +230,15 @@ impl<const SIZE: usize> Io<SIZE> {
230230 }
231231 }
232232
233+ #[ inline]
234+ const fn length_valid ( offset : usize , length : usize , size : usize ) -> bool {
235+ if let Some ( end) = offset. checked_add ( length) {
236+ end <= size
237+ } else {
238+ false
239+ }
240+ }
241+
233242 #[ inline]
234243 fn io_addr < U > ( & self , offset : usize ) -> Result < usize > {
235244 if !Self :: offset_valid :: < U > ( offset, self . maxsize ( ) ) {
@@ -249,6 +258,46 @@ impl<const SIZE: usize> Io<SIZE> {
249258 self . addr ( ) + offset
250259 }
251260
261+ /// Copy memory block from an i/o memory by filling the specified buffer with it.
262+ ///
263+ /// # Examples
264+ /// ```
265+ /// use kernel::io::mem::IoMem;
266+ /// use kernel::io::mem::Resource;
267+ ///
268+ /// fn test(device: &Device, res: Resource) -> Result {
269+ /// // Create an i/o memory block of at least 100 bytes.
270+ /// let devres_mem = IoMem::<100>::new(res, device)?;
271+ /// // aquire access to memory block
272+ /// let mem = devres_mem.try_access()?;
273+ ///
274+ /// let mut buffer: [u8; 32] = [0; 32];
275+ ///
276+ /// // Memcpy 16 bytes from an offset 10 of i/o memory block into the buffer.
277+ /// mem.try_memcpy_fromio(&mut buffer[..16], 10)?;
278+ ///
279+ /// Ok(())
280+ /// }
281+ /// ```
282+ pub fn try_memcpy_fromio ( & self , buffer : & mut [ u8 ] , offset : usize ) -> Result {
283+ if buffer. len ( ) == 0 || !Self :: length_valid ( offset, buffer. len ( ) , self . maxsize ( ) ) {
284+ return Err ( EINVAL ) ;
285+ }
286+ let addr = self . io_addr :: < crate :: ffi:: c_char > ( offset) ?;
287+
288+ // SAFETY:
289+ // - The type invariants guarantee that `adr` is a valid pointer.
290+ // - The bounds of `buffer` are checked with a call to `length_valid`.
291+ unsafe {
292+ bindings:: memcpy_fromio (
293+ buffer. as_mut_ptr ( ) as * mut _ ,
294+ addr as * const _ ,
295+ buffer. len ( ) as _ ,
296+ )
297+ } ;
298+ Ok ( ( ) )
299+ }
300+
252301 define_read ! ( read8, try_read8, readb -> u8 ) ;
253302 define_read ! ( read16, try_read16, readw -> u16 ) ;
254303 define_read ! ( read32, try_read32, readl -> u32 ) ;
0 commit comments