summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
authorZixun LI <[email protected]>2026-05-03 14:36:25 +0200
committerGitHub <[email protected]>2026-05-03 14:36:25 +0200
commitea2de8be7e939fdffd73efd75cc2e2051ca495a9 (patch)
treef2801e76d9643eb277ba49498f0fedeee9aa2e6b /src/device
parent5c0c1662464e48681533e8ecc1217613fb6e3820 (diff)
parent939c2f91c200db2bf9874c2e6c50b3530f8a6725 (diff)
Merge branch 'master' into copilot/upgrade-net-lwip-webserver-descriptors
Diffstat (limited to 'src/device')
-rw-r--r--src/device/dcd.h5
-rw-r--r--src/device/usbd.c2
-rw-r--r--src/device/usbd_control.c37
3 files changed, 26 insertions, 18 deletions
diff --git a/src/device/dcd.h b/src/device/dcd.h
index 850c37bc2..f861eb258 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -219,6 +219,11 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport
event.rhport = rhport;
event.event_id = DCD_EVENT_SETUP_RECEIVED;
(void) memcpy(&event.setup_received, setup, sizeof(tusb_control_request_t));
+ // USB wire format is little-endian. Convert multi-byte fields to host byte order
+ // so the stack always sees correct values regardless of CPU endianness.
+ event.setup_received.wValue = tu_le16toh(event.setup_received.wValue);
+ event.setup_received.wIndex = tu_le16toh(event.setup_received.wIndex);
+ event.setup_received.wLength = tu_le16toh(event.setup_received.wLength);
dcd_event_handler(&event, in_isr);
}
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 3c14175f6..da0ffb4c6 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -1212,7 +1212,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
TU_LOG_USBD(" String[%u]\r\n", desc_index);
// String Descriptor always uses the desc set from user
- uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex));
+ uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex);
TU_VERIFY(desc_str);
// first byte of descriptor is its size
diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c
index 87593d4a7..b14d08a9c 100644
--- a/src/device/usbd_control.c
+++ b/src/device/usbd_control.c
@@ -44,10 +44,6 @@ TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_r
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-enum {
- EDPT_CTRL_OUT = 0x00,
- EDPT_CTRL_IN = 0x80
-};
typedef struct {
tusb_control_request_t request;
@@ -71,11 +67,16 @@ uint8_t* usbd_get_ctrl_buf(void) {
// Application API
//--------------------------------------------------------------------+
+// Endpoint used for the Status stage of a control transfer.
+// Per USB 2.0 ยง9.3.1, when wLength == 0 the Direction bit is ignored and the Status stage
+// is always IN. Otherwise the Status stage is opposite to the Data stage direction.
+TU_ATTR_ALWAYS_INLINE static inline uint8_t status_stage_ep(const tusb_control_request_t* request) {
+ return (request->wLength != 0 && request->bmRequestType_bit.direction) ? TU_EP0_OUT : TU_EP0_IN;
+}
+
// Queue ZLP status transaction
-static inline bool status_stage_xact(uint8_t rhport, const tusb_control_request_t* request) {
- // Opposite to endpoint in Data Phase
- const uint8_t ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
- return usbd_edpt_xfer(rhport, ep_addr, NULL, 0, false);
+TU_ATTR_ALWAYS_INLINE static inline bool status_stage_xact(uint8_t rhport, uint8_t ep_status) {
+ return usbd_edpt_xfer(rhport, ep_status, NULL, 0, false);
}
// Status phase
@@ -85,7 +86,7 @@ bool tud_control_status(uint8_t rhport, const tusb_control_request_t* request) {
_ctrl_xfer.total_xferred = 0;
_ctrl_xfer.data_len = 0;
- return status_stage_xact(rhport, request);
+ return status_stage_xact(rhport, status_stage_ep(request));
}
// Queue a transaction in Data Stage
@@ -93,10 +94,10 @@ bool tud_control_status(uint8_t rhport, const tusb_control_request_t* request) {
// This function can also transfer an zero-length packet
static bool data_stage_xact(uint8_t rhport) {
const uint16_t xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_BUFSIZE);
- uint8_t ep_addr = EDPT_CTRL_OUT;
+ uint8_t ep_addr = TU_EP0_OUT;
if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) {
- ep_addr = EDPT_CTRL_IN;
+ ep_addr = TU_EP0_IN;
if (0u != xact_len && _ctrl_xfer.buffer != _ctrl_epbuf.buf) {
TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_BUFSIZE, _ctrl_xfer.buffer, xact_len));
}
@@ -119,7 +120,7 @@ bool tud_control_xfer(uint8_t rhport, const tusb_control_request_t* request, voi
}
TU_ASSERT(data_stage_xact(rhport));
} else {
- TU_ASSERT(status_stage_xact(rhport, request));
+ TU_ASSERT(status_stage_xact(rhport, TU_EP0_IN));
}
return true;
@@ -156,8 +157,9 @@ void usbd_control_set_request(const tusb_control_request_t* request) {
bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) result;
- // Endpoint Address is opposite to direction bit, this is Status Stage complete event
- if (tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction) {
+ // Status Stage complete: endpoint matches the Status stage endpoint
+ uint8_t const ep_status = status_stage_ep(&_ctrl_xfer.request);
+ if (ep_addr == ep_status) {
TU_ASSERT(0 == xferred_bytes);
// invoke optional dcd hook if available
@@ -171,6 +173,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
return true;
}
+ // Data stage complete
if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) {
TU_VERIFY(_ctrl_xfer.buffer);
if (_ctrl_xfer.buffer != _ctrl_epbuf.buf) {
@@ -200,11 +203,11 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
}
if (is_ok) {
- TU_ASSERT(status_stage_xact(rhport, &_ctrl_xfer.request));
+ TU_ASSERT(status_stage_xact(rhport, ep_status));
} else {
// Stall both IN and OUT control endpoint
- dcd_edpt_stall(rhport, EDPT_CTRL_OUT);
- dcd_edpt_stall(rhport, EDPT_CTRL_IN);
+ dcd_edpt_stall(rhport, TU_EP0_OUT);
+ dcd_edpt_stall(rhport, TU_EP0_IN);
}
} else {
// More data to transfer