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