88#include "shared-bindings/usb/core/Device.h"
99
1010#include "tusb_config.h"
11+ #include "supervisor/port.h"
12+ #include "supervisor/port_heap.h"
1113
1214#include "lib/tinyusb/src/host/hcd.h"
1315#include "lib/tinyusb/src/host/usbh.h"
@@ -33,6 +35,39 @@ void tuh_umount_cb(uint8_t dev_addr) {
3335
3436static xfer_result_t _xfer_result ;
3537static size_t _actual_len ;
38+
39+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
40+ // Helper to ensure buffer is DMA-capable for transfer operations
41+ static uint8_t * _ensure_dma_buffer (usb_core_device_obj_t * self , const uint8_t * buffer , size_t len , bool for_write ) {
42+ if (port_buffer_is_dma_capable (buffer )) {
43+ return (uint8_t * )buffer ; // Already DMA-capable, use directly
44+ }
45+
46+ // Need to allocate/reallocate temporary buffer in DMA-capable memory
47+ if (self -> temp_buffer_size < len ) {
48+ self -> temp_buffer = port_realloc (self -> temp_buffer , len , true); // true = DMA capable
49+ if (self -> temp_buffer == NULL ) {
50+ self -> temp_buffer_size = 0 ;
51+ return NULL ; // Allocation failed
52+ }
53+ self -> temp_buffer_size = len ;
54+ }
55+
56+ // Copy data to DMA buffer if writing
57+ if (for_write && buffer != NULL ) {
58+ memcpy (self -> temp_buffer , buffer , len );
59+ }
60+
61+ return self -> temp_buffer ;
62+ }
63+
64+ // Copy data back from DMA buffer to original buffer after read
65+ static void _copy_from_dma_buffer (usb_core_device_obj_t * self , uint8_t * original_buffer , size_t len ) {
66+ if (!port_buffer_is_dma_capable (original_buffer ) && self -> temp_buffer != NULL ) {
67+ memcpy (original_buffer , self -> temp_buffer , len );
68+ }
69+ }
70+ #endif
3671bool common_hal_usb_core_device_construct (usb_core_device_obj_t * self , uint8_t device_address ) {
3772 if (!tuh_inited ()) {
3873 mp_raise_RuntimeError (MP_ERROR_TEXT ("No usb host port initialized" ));
@@ -46,6 +81,10 @@ bool common_hal_usb_core_device_construct(usb_core_device_obj_t *self, uint8_t d
4681 }
4782 self -> device_address = device_address ;
4883 self -> first_langid = 0 ;
84+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
85+ self -> temp_buffer = NULL ;
86+ self -> temp_buffer_size = 0 ;
87+ #endif
4988 _xfer_result = XFER_RESULT_INVALID ;
5089 return true;
5190}
@@ -65,6 +104,14 @@ void common_hal_usb_core_device_deinit(usb_core_device_obj_t *self) {
65104 self -> open_endpoints [i ] = 0 ;
66105 }
67106 }
107+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
108+ // Clean up temporary buffer
109+ if (self -> temp_buffer != NULL ) {
110+ port_free (self -> temp_buffer );
111+ self -> temp_buffer = NULL ;
112+ self -> temp_buffer_size = 0 ;
113+ }
114+ #endif
68115 self -> device_address = 0 ;
69116}
70117
@@ -399,10 +446,22 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t
399446 mp_raise_usb_core_USBError (NULL );
400447 return 0 ;
401448 }
449+
450+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
451+ // Ensure buffer is in DMA-capable memory
452+ uint8_t * dma_buffer = _ensure_dma_buffer (self , buffer , len , true); // true = for write
453+ if (dma_buffer == NULL ) {
454+ mp_raise_msg (& mp_type_MemoryError , MP_ERROR_TEXT ("Could not allocate DMA capable buffer" ));
455+ return 0 ;
456+ }
457+ #else
458+ uint8_t * dma_buffer = (uint8_t * )buffer ; // All memory is DMA-capable
459+ #endif
460+
402461 tuh_xfer_t xfer ;
403462 xfer .daddr = self -> device_address ;
404463 xfer .ep_addr = endpoint ;
405- xfer .buffer = ( uint8_t * ) buffer ;
464+ xfer .buffer = dma_buffer ;
406465 xfer .buflen = len ;
407466 return _xfer (& xfer , timeout );
408467}
@@ -412,12 +471,33 @@ mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t e
412471 mp_raise_usb_core_USBError (NULL );
413472 return 0 ;
414473 }
474+
475+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
476+ // Ensure buffer is in DMA-capable memory
477+ uint8_t * dma_buffer = _ensure_dma_buffer (self , buffer , len , false); // false = for read
478+ if (dma_buffer == NULL ) {
479+ mp_raise_msg (& mp_type_MemoryError , MP_ERROR_TEXT ("Could not allocate DMA capable buffer" ));
480+ return 0 ;
481+ }
482+ #else
483+ uint8_t * dma_buffer = buffer ; // All memory is DMA-capable
484+ #endif
485+
415486 tuh_xfer_t xfer ;
416487 xfer .daddr = self -> device_address ;
417488 xfer .ep_addr = endpoint ;
418- xfer .buffer = buffer ;
489+ xfer .buffer = dma_buffer ;
419490 xfer .buflen = len ;
420- return _xfer (& xfer , timeout );
491+ mp_int_t result = _xfer (& xfer , timeout );
492+
493+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
494+ // Copy data back to original buffer if needed
495+ if (result > 0 ) {
496+ _copy_from_dma_buffer (self , buffer , result );
497+ }
498+ #endif
499+
500+ return result ;
421501}
422502
423503mp_int_t common_hal_usb_core_device_ctrl_transfer (usb_core_device_obj_t * self ,
@@ -426,6 +506,23 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
426506 uint8_t * buffer , mp_int_t len , mp_int_t timeout ) {
427507 // Timeout is in ms.
428508
509+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
510+ // Determine if this is a write (host-to-device) or read (device-to-host) transfer
511+ bool is_write = (bmRequestType & 0x80 ) == 0 ; // Bit 7: 0=host-to-device, 1=device-to-host
512+
513+ // Ensure buffer is in DMA-capable memory
514+ uint8_t * dma_buffer = NULL ;
515+ if (len > 0 && buffer != NULL ) {
516+ dma_buffer = _ensure_dma_buffer (self , buffer , len , is_write );
517+ if (dma_buffer == NULL ) {
518+ mp_raise_msg (& mp_type_MemoryError , MP_ERROR_TEXT ("Could not allocate DMA capable buffer" ));
519+ return 0 ;
520+ }
521+ }
522+ #else
523+ uint8_t * dma_buffer = buffer ; // All memory is DMA-capable
524+ #endif
525+
429526 tusb_control_request_t request = {
430527 .bmRequestType = bmRequestType ,
431528 .bRequest = bRequest ,
@@ -437,7 +534,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
437534 .daddr = self -> device_address ,
438535 .ep_addr = 0 ,
439536 .setup = & request ,
440- .buffer = buffer ,
537+ .buffer = dma_buffer ,
441538 .complete_cb = _transfer_done_cb ,
442539 };
443540
@@ -446,7 +543,16 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self,
446543 mp_raise_usb_core_USBError (NULL );
447544 return 0 ;
448545 }
449- return (mp_int_t )_handle_timed_transfer_callback (& xfer , timeout );
546+ mp_int_t result = (mp_int_t )_handle_timed_transfer_callback (& xfer , timeout );
547+
548+ #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE
549+ // Copy data back to original buffer if this was a read transfer and we got data
550+ if ((bmRequestType & 0x80 ) != 0 && result > 0 && buffer != NULL ) { // Read transfer (device-to-host)
551+ _copy_from_dma_buffer (self , buffer , result );
552+ }
553+ #endif
554+
555+ return result ;
450556}
451557
452558bool common_hal_usb_core_device_is_kernel_driver_active (usb_core_device_obj_t * self , mp_int_t interface ) {
0 commit comments