Skip to content

Commit b301f79

Browse files
committed
refactor usbd.c: centralize control transfer state management into _usbd_dev structure and remove usbd_control_reset
1 parent 9d3ad33 commit b301f79

1 file changed

Lines changed: 60 additions & 83 deletions

File tree

src/device/usbd.c

Lines changed: 60 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
118129
typedef 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 {
142155
static usbd_device_t _usbd_dev;
143156
static 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);
409426
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
410427
static 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);
425440
static 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

646648
static void usbd_reset(uint8_t rhport) {
647649
configuration_reset(rhport);
648-
usbd_control_reset();
649650
}
650651

651652
bool 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-
834821
uint8_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.
852839
static 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
867855
bool 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.
874862
bool 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
902883
static 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
966944
static 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

Comments
 (0)