@@ -115,7 +115,20 @@ TU_ATTR_WEAK bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_si
115115//--------------------------------------------------------------------+
116116// Device Data
117117//--------------------------------------------------------------------+
118+
119+ // Per-control-transfer state: populated at process_setup_received() entry,
120+ // consumed asynchronously by usbd_control_xfer_cb() when the EP0 transfer completes.
121+ typedef struct {
122+ tusb_control_request_t request ;
123+ uint8_t * buffer ;
124+ uint16_t data_len ;
125+ uint16_t total_xferred ;
126+ usbd_control_xfer_cb_t complete_cb ;
127+ } usbd_control_xfer_t ;
128+
118129typedef struct {
130+ usbd_control_xfer_t ctrl_xfer ;
131+
119132 // Note: these may share an enum state
120133 volatile uint8_t connected ;
121134 volatile uint8_t addressed ;
@@ -142,6 +155,10 @@ typedef struct {
142155static usbd_device_t _usbd_dev ;
143156static volatile uint8_t _usbd_queued_setup ;
144157
158+ CFG_TUD_MEM_SECTION static struct {
159+ TUD_EPBUF_DEF (buf , CFG_TUD_ENDPOINT0_BUFSIZE );
160+ } _ctrl_epbuf ;
161+
145162//--------------------------------------------------------------------+
146163// Class Driver
147164//--------------------------------------------------------------------+
@@ -405,7 +422,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event,
405422//--------------------------------------------------------------------+
406423// Prototypes
407424//--------------------------------------------------------------------+
408- static bool process_control_request (uint8_t rhport , tusb_control_request_t const * p_request );
425+ static bool process_setup_received (uint8_t rhport , tusb_control_request_t const * p_request );
409426static bool process_set_config (uint8_t rhport , uint8_t cfg_num );
410427static bool process_get_descriptor (uint8_t rhport , tusb_control_request_t const * p_request );
411428
@@ -420,8 +437,6 @@ static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_req
420437#endif
421438
422439// Control Endpoint
423- static void usbd_control_reset (void );
424- static void usbd_control_set_complete_callback (usbd_control_xfer_cb_t fp );
425440static bool usbd_control_xfer_cb (uint8_t rhport , uint8_t ep_addr , xfer_result_t result , uint32_t xferred_bytes );
426441
427442//--------------------------------------------------------------------+
@@ -458,17 +473,6 @@ static char const *const _usbd_event_str[DCD_EVENT_COUNT] = {
458473 "Func Call"
459474};
460475
461- // for usbd_control to print the name of control complete driver
462- void usbd_driver_print_control_complete_name (usbd_control_xfer_cb_t callback ) {
463- for (uint8_t i = 0 ; i < TOTAL_DRIVER_COUNT ; i ++ ) {
464- usbd_class_driver_t const * driver = get_driver (i );
465- if (driver && driver -> control_xfer_cb == callback ) {
466- TU_LOG_USBD ("%s control complete\r\n" , driver -> name );
467- return ;
468- }
469- }
470- }
471-
472476#endif
473477
474478//--------------------------------------------------------------------+
@@ -608,9 +612,7 @@ bool tud_deinit(uint8_t rhport) {
608612 }
609613 }
610614
611- // Clear device data
612- tu_varclr (& _usbd_dev );
613- usbd_control_reset ();
615+ tu_varclr (& _usbd_dev ); // Clear device data
614616
615617 // Deinit device queue & task
616618 osal_queue_delete (_usbd_q );
@@ -645,7 +647,6 @@ static void configuration_reset(uint8_t rhport) {
645647
646648static void usbd_reset (uint8_t rhport ) {
647649 configuration_reset (rhport );
648- usbd_control_reset ();
649650}
650651
651652bool tud_task_event_ready (void ) {
@@ -731,7 +732,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
731732 _usbd_dev .ep_status [0 ][TUSB_DIR_IN ].claimed = 0 ;
732733
733734 // Process control request
734- if (!process_control_request (event .rhport , & event .setup_received )) {
735+ if (!process_setup_received (event .rhport , & event .setup_received )) {
735736 TU_LOG_USBD (" Stall EP0\r\n" );
736737 // Failed -> stall both control endpoint IN and OUT
737738 dcd_edpt_stall (event .rhport , 0 );
@@ -817,20 +818,6 @@ TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_r
817818 (void ) request ;
818819}
819820
820- typedef struct {
821- tusb_control_request_t request ;
822- uint8_t * buffer ;
823- uint16_t data_len ;
824- uint16_t total_xferred ;
825- usbd_control_xfer_cb_t complete_cb ;
826- } usbd_control_xfer_t ;
827-
828- static usbd_control_xfer_t _ctrl_xfer ;
829-
830- CFG_TUD_MEM_SECTION static struct {
831- TUD_EPBUF_DEF (buf , CFG_TUD_ENDPOINT0_BUFSIZE );
832- } _ctrl_epbuf ;
833-
834821uint8_t * usbd_get_ctrl_buf (void ) {
835822 return _ctrl_epbuf .buf ;
836823}
@@ -850,13 +837,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool status_stage_xact(uint8_t rhport, uint8
850837// Queue a transaction in Data Stage. Each transaction has up to Endpoint0's max
851838// packet size. This function can also transfer a zero-length packet.
852839static bool data_stage_xact (uint8_t rhport ) {
853- const uint16_t xact_len = tu_min16 (_ctrl_xfer .data_len - _ctrl_xfer .total_xferred , CFG_TUD_ENDPOINT0_BUFSIZE );
840+ usbd_control_xfer_t * const ctrl_xfer = & _usbd_dev .ctrl_xfer ;
841+ const uint16_t xact_len = tu_min16 (ctrl_xfer -> data_len - ctrl_xfer -> total_xferred , CFG_TUD_ENDPOINT0_BUFSIZE );
854842 uint8_t ep_addr = TU_EP0_OUT ;
855843
856- if (_ctrl_xfer . request .bmRequestType_bit .direction == TUSB_DIR_IN ) {
844+ if (ctrl_xfer -> request .bmRequestType_bit .direction == TUSB_DIR_IN ) {
857845 ep_addr = TU_EP0_IN ;
858- if (0u != xact_len && _ctrl_xfer . buffer != _ctrl_epbuf .buf ) {
859- TU_VERIFY (0 == tu_memcpy_s (_ctrl_epbuf .buf , CFG_TUD_ENDPOINT0_BUFSIZE , _ctrl_xfer . buffer , xact_len ));
846+ if (0u != xact_len && ctrl_xfer -> buffer != _ctrl_epbuf .buf ) {
847+ TU_VERIFY (0 == tu_memcpy_s (_ctrl_epbuf .buf , CFG_TUD_ENDPOINT0_BUFSIZE , ctrl_xfer -> buffer , xact_len ));
860848 }
861849 }
862850
@@ -865,20 +853,21 @@ static bool data_stage_xact(uint8_t rhport) {
865853
866854// Status phase
867855bool tud_control_status (uint8_t rhport , const tusb_control_request_t * request ) {
868- // _ctrl_xfer fields are pre-initialized at process_control_request entry
856+ // _usbd_dev.ctrl_xfer fields are pre-initialized at process_setup_received entry
869857 (void ) request ;
870- return status_stage_xact (rhport , status_stage_ep (& _ctrl_xfer .request ));
858+ return status_stage_xact (rhport , status_stage_ep (& _usbd_dev . ctrl_xfer .request ));
871859}
872860
873861// Transmit data to/from the control endpoint. If wLength is zero, a status packet is sent instead.
874862bool tud_control_xfer (uint8_t rhport , const tusb_control_request_t * request , void * buffer , uint16_t len ) {
875- // _ctrl_xfer. request and reset fields are pre-initialized at process_control_request entry
863+ // _usbd_dev.ctrl_xfer. request and reset fields are pre-initialized at process_setup_received entry
876864 (void ) request ;
877- _ctrl_xfer .buffer = (uint8_t * ) buffer ;
878- _ctrl_xfer .data_len = tu_min16 (len , _ctrl_xfer .request .wLength );
865+ usbd_control_xfer_t * const ctrl_xfer = & _usbd_dev .ctrl_xfer ;
866+ ctrl_xfer -> buffer = (uint8_t * ) buffer ;
867+ ctrl_xfer -> data_len = tu_min16 (len , ctrl_xfer -> request .wLength );
879868
880- if (_ctrl_xfer . request .wLength > 0U ) {
881- if (_ctrl_xfer . data_len > 0U ) {
869+ if (ctrl_xfer -> request .wLength > 0U ) {
870+ if (ctrl_xfer -> data_len > 0U ) {
882871 TU_ASSERT (buffer );
883872 }
884873 TU_ASSERT (data_stage_xact (rhport ));
@@ -890,57 +879,46 @@ bool tud_control_xfer(uint8_t rhport, const tusb_control_request_t* request, voi
890879 return true;
891880}
892881
893- static void usbd_control_reset (void ) {
894- tu_varclr (& _ctrl_xfer );
895- }
896-
897- static void usbd_control_set_complete_callback (usbd_control_xfer_cb_t fp ) {
898- _ctrl_xfer .complete_cb = fp ;
899- }
900-
901882// Callback when a transaction completes on the DATA stage or Status stage of EP0
902883static bool usbd_control_xfer_cb (uint8_t rhport , uint8_t ep_addr , xfer_result_t result , uint32_t xferred_bytes ) {
903884 (void ) result ;
885+ usbd_control_xfer_t * const ctrl_xfer = & _usbd_dev .ctrl_xfer ;
904886
905887 // Status Stage complete: ep_addr matches the resolved Status stage endpoint
906- uint8_t const ep_status = status_stage_ep (& _ctrl_xfer . request );
888+ uint8_t const ep_status = status_stage_ep (& ctrl_xfer -> request );
907889 if (ep_addr == ep_status ) {
908890 TU_ASSERT (0 == xferred_bytes );
909891
910892 // invoke optional dcd hook if available
911- dcd_edpt0_status_complete (rhport , & _ctrl_xfer . request );
893+ dcd_edpt0_status_complete (rhport , & ctrl_xfer -> request );
912894
913- if (NULL != _ctrl_xfer .complete_cb ) {
914- // TODO refactor with usbd_driver_print_control_complete_name
915- _ctrl_xfer .complete_cb (rhport , CONTROL_STAGE_ACK , & _ctrl_xfer .request );
895+ if (NULL != ctrl_xfer -> complete_cb ) {
896+ ctrl_xfer -> complete_cb (rhport , CONTROL_STAGE_ACK , & ctrl_xfer -> request );
916897 }
917898
918899 return true;
919900 }
920901
921902 // Data stage progress
922- if (_ctrl_xfer . request .bmRequestType_bit .direction == TUSB_DIR_OUT ) {
923- TU_VERIFY (_ctrl_xfer . buffer );
924- if (_ctrl_xfer . buffer != _ctrl_epbuf .buf ) {
925- memcpy (_ctrl_xfer . buffer , _ctrl_epbuf .buf , xferred_bytes );
903+ if (ctrl_xfer -> request .bmRequestType_bit .direction == TUSB_DIR_OUT ) {
904+ TU_VERIFY (ctrl_xfer -> buffer );
905+ if (ctrl_xfer -> buffer != _ctrl_epbuf .buf ) {
906+ memcpy (ctrl_xfer -> buffer , _ctrl_epbuf .buf , xferred_bytes );
926907 }
927- TU_LOG_MEM (CFG_TUD_LOG_LEVEL , _ctrl_xfer . buffer , xferred_bytes , 2 );
908+ TU_LOG_MEM (CFG_TUD_LOG_LEVEL , ctrl_xfer -> buffer , xferred_bytes , 2 );
928909 }
929910
930- _ctrl_xfer . total_xferred += (uint16_t ) xferred_bytes ;
931- _ctrl_xfer . buffer += xferred_bytes ;
911+ ctrl_xfer -> total_xferred += (uint16_t ) xferred_bytes ;
912+ ctrl_xfer -> buffer += xferred_bytes ;
932913
933914 // Data Stage complete when wLength reached or short packet (incl. ZLP) seen
934- if ((_ctrl_xfer . request .wLength == _ctrl_xfer . total_xferred ) ||
915+ if ((ctrl_xfer -> request .wLength == ctrl_xfer -> total_xferred ) ||
935916 (xferred_bytes < CFG_TUD_ENDPOINT0_BUFSIZE )) {
936917 bool is_ok = true;
937918
938- if (NULL != _ctrl_xfer .complete_cb ) {
939- #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
940- usbd_driver_print_control_complete_name (_ctrl_xfer .complete_cb );
941- #endif
919+ if (NULL != ctrl_xfer -> complete_cb ) {
942920 // Callback can still stall control in status phase, e.g. OUT data doesn't make sense
943- is_ok = _ctrl_xfer . complete_cb (rhport , CONTROL_STAGE_DATA , & _ctrl_xfer . request );
921+ is_ok = ctrl_xfer -> complete_cb (rhport , CONTROL_STAGE_DATA , & ctrl_xfer -> request );
944922 }
945923
946924 if (is_ok ) {
@@ -964,27 +942,28 @@ static bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t
964942
965943// Helper to invoke class driver control request handler
966944static bool invoke_class_control (uint8_t rhport , usbd_class_driver_t const * driver , tusb_control_request_t const * request ) {
967- usbd_control_set_complete_callback ( driver -> control_xfer_cb ) ;
945+ _usbd_dev . ctrl_xfer . complete_cb = driver -> control_xfer_cb ;
968946 TU_LOG_USBD (" %s control request\r\n" , driver -> name );
969947 return driver -> control_xfer_cb (rhport , CONTROL_STAGE_SETUP , request );
970948}
971949
972950// This handles the actual request and its response.
973951// Returns false if unable to complete the request, causing caller to stall control endpoints.
974- static bool process_control_request (uint8_t rhport , tusb_control_request_t const * p_request ) {
952+ static bool process_setup_received (uint8_t rhport , tusb_control_request_t const * p_request ) {
975953 // Initialize control transfer state for this request. The request copy must be
976954 // visible to usbd_control_xfer_cb when the (asynchronous) status ZLP completes,
977955 // since the SETUP packet event has already gone out of scope by then.
978- _ctrl_xfer .request = * p_request ;
979- _ctrl_xfer .buffer = NULL ;
980- _ctrl_xfer .total_xferred = 0 ;
981- _ctrl_xfer .data_len = 0 ;
982- _ctrl_xfer .complete_cb = NULL ;
956+ usbd_control_xfer_t * const ctrl_xfer = & _usbd_dev .ctrl_xfer ;
957+ ctrl_xfer -> request = * p_request ;
958+ ctrl_xfer -> buffer = NULL ;
959+ ctrl_xfer -> total_xferred = 0 ;
960+ ctrl_xfer -> data_len = 0 ;
961+ ctrl_xfer -> complete_cb = NULL ;
983962 TU_ASSERT (p_request -> bmRequestType_bit .type < TUSB_REQ_TYPE_INVALID );
984963
985964 // Vendor request
986965 if ( p_request -> bmRequestType_bit .type == TUSB_REQ_TYPE_VENDOR ) {
987- usbd_control_set_complete_callback ( tud_vendor_control_xfer_cb ) ;
966+ ctrl_xfer -> complete_cb = tud_vendor_control_xfer_cb ;
988967 return tud_vendor_control_xfer_cb (rhport , CONTROL_STAGE_SETUP , p_request );
989968 }
990969
@@ -1022,8 +1001,6 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
10221001 // Depending on mcu, status phase could be sent either before or after changing device address,
10231002 // or even require stack to not response with status at all
10241003 // Therefore DCD must take full responsibility to response and include zlp status packet if needed.
1025- // _ctrl_xfer.request was already populated at process_control_request() entry, so the
1026- // status ZLP that the DCD queues will be recognized by usbd_control_xfer_cb().
10271004 dcd_set_address (rhport , (uint8_t ) p_request -> wValue );
10281005 _usbd_dev .addressed = 1 ;
10291006 break ;
@@ -1092,7 +1069,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
10921069 uint8_t const selector = tu_u16_high (p_request -> wIndex );
10931070 TU_VERIFY (TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE );
10941071
1095- usbd_control_set_complete_callback ( process_test_mode_cb ) ;
1072+ ctrl_xfer -> complete_cb = process_test_mode_cb ;
10961073 tud_control_status (rhport , p_request );
10971074 break ;
10981075 }
@@ -1161,7 +1138,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
11611138 TU_VERIFY (TUSB_REQ_TYPE_STANDARD == p_request -> bmRequestType_bit .type );
11621139
11631140 // Clear complete callback if driver set since it can also stall the request.
1164- usbd_control_set_complete_callback ( NULL ) ;
1141+ ctrl_xfer -> complete_cb = NULL ;
11651142
11661143 switch (p_request -> bRequest ) { //-V2520
11671144 case TUSB_REQ_GET_INTERFACE : {
@@ -1219,7 +1196,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
12191196 // STD request must always be ACKed regardless of driver returned value
12201197 // Also clear complete callback if driver set since it can also stall the request.
12211198 (void ) invoke_class_control (rhport , driver , p_request );
1222- usbd_control_set_complete_callback ( NULL ) ;
1199+ ctrl_xfer -> complete_cb = NULL ;
12231200
12241201 // skip ZLP status if driver already did that
12251202 if (!_usbd_dev .ep_status [0 ][TUSB_DIR_IN ].busy ) {
0 commit comments