Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DWC2 Test Mode Support #2416

Merged
merged 10 commits into from May 13, 2024
Merged
3 changes: 3 additions & 0 deletions src/common/tusb_mcu.h
Expand Up @@ -195,6 +195,7 @@
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
#define TUP_USBIP_DWC2_TEST_MODE

// For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
#define TUP_DCD_ENDPOINT_MAX 6
Expand All @@ -209,6 +210,7 @@
// MCU with on-chip HS Phy
#if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx)
#define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
#define TUP_USBIP_DWC2_TEST_MODE
#endif

#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
Expand Down Expand Up @@ -277,6 +279,7 @@
defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
#define TUP_DCD_ENDPOINT_MAX 9
#define TUP_RHPORT_HIGHSPEED 1
#define TUP_USBIP_DWC2_TEST_MODE
#else
#define TUP_DCD_ENDPOINT_MAX 6
#endif
Expand Down
15 changes: 15 additions & 0 deletions src/device/dcd.h
Expand Up @@ -97,6 +97,14 @@ typedef struct TU_ATTR_ALIGNED(4) {
};
} dcd_event_t;

typedef enum {
TEST_J = 1,
TEST_K,
TEST_SE0_NAK,
TEST_PACKET,
TEST_FORCE_ENABLE,
} test_mode_t;

//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");

//--------------------------------------------------------------------+
Expand Down Expand Up @@ -149,6 +157,13 @@ void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
// Enable/Disable Start-of-frame interrupt. Default is disabled
void dcd_sof_enable(uint8_t rhport, bool en);

#if CFG_TUD_TEST_MODE
// Check if the test mode is supported, returns true is test mode selector is supported
bool dcd_check_test_mode_support(test_mode_t test_selector) TU_ATTR_WEAK;

// Put device into a test mode (needs power cycle to quit)
void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) TU_ATTR_WEAK;
#endif
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
Expand Down
63 changes: 56 additions & 7 deletions src/device/usbd.c
Expand Up @@ -313,7 +313,9 @@
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);

#if CFG_TUD_TEST_MODE
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
#endif
// from usbd_control.c
void usbd_control_reset(void);
void usbd_control_set_request(tusb_control_request_t const *request);
Expand Down Expand Up @@ -753,14 +755,47 @@
break;

case TUSB_REQ_SET_FEATURE:
// Only support remote wakeup for device feature
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
// Handle the feature selector
switch(p_request->wValue)
{
// Support for remote wakeup
case TUSB_REQ_FEATURE_REMOTE_WAKEUP:
TU_LOG_USBD(" Enable Remote Wakeup\r\n");

// Host may enable remote wake up before suspending especially HID device
_usbd_dev.remote_wakeup_en = true;
tud_control_status(rhport, p_request);
break;

TU_LOG_USBD(" Enable Remote Wakeup\r\n");
#if CFG_TUD_TEST_MODE
// Support for TEST_MODE
case TUSB_REQ_FEATURE_TEST_MODE: {
// Only handle the test mode if supported and valid
TU_VERIFY(dcd_enter_test_mode && dcd_check_test_mode_support && 0 == tu_u16_low(p_request->wIndex));

// Host may enable remote wake up before suspending especially HID device
_usbd_dev.remote_wakeup_en = true;
tud_control_status(rhport, p_request);
uint8_t selector = tu_u16_high(p_request->wIndex);

// Stall request if the selected test mode isn't supported
if (!dcd_check_test_mode_support((test_mode_t)selector))
{
TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector);

return false;
}

// Acknowledge request
tud_control_status(rhport, p_request);

TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector);

usbd_control_set_complete_callback(process_test_mode_cb);
break;
}
#endif /* CFG_TUD_TEST_MODE */

// Stall unsupported feature selector
default: return false;
}
Dismissed Show dismissed Hide dismissed
Dismissed Show dismissed Hide dismissed
break;

case TUSB_REQ_CLEAR_FEATURE:
Expand Down Expand Up @@ -1088,6 +1123,20 @@
}
}

#if CFG_TUD_TEST_MODE
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
// At this point it should already be ensured that dcd_enter_test_mode() is defined

// Only enter the test mode after the request for it has completed
TU_VERIFY(CONTROL_STAGE_ACK == stage);

dcd_enter_test_mode(rhport, (test_mode_t)tu_u16_high(request->wIndex));

return true;
}
#endif /* CFG_TUD_TEST_MODE */

//--------------------------------------------------------------------+
// DCD Event Handler
//--------------------------------------------------------------------+
Expand Down
21 changes: 21 additions & 0 deletions src/portable/synopsys/dwc2/dcd_dwc2.c
Expand Up @@ -1195,4 +1195,25 @@ void dcd_int_handler(uint8_t rhport) {
// }
}

#if defined(TUP_USBIP_DWC2_TEST_MODE) && CFG_TUD_TEST_MODE

bool dcd_check_test_mode_support(test_mode_t test_selector) {
// Check if test mode selector is unsupported
if (TEST_FORCE_ENABLE < test_selector || TEST_J > test_selector) {
return false;
}

return true;
}

void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) {
// Get port address...
dwc2_regs_t* dwc2 = DWC2_REG(rhport);

// Enable the test mode
dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (test_selector << DCTL_TCTL_Pos);
}

#endif /* TUP_USBIP_DWC2_TEST_MODE && CFG_TUD_TEST_MODE */

#endif
5 changes: 5 additions & 0 deletions src/tusb_option.h
Expand Up @@ -364,6 +364,11 @@
#define CFG_TUD_INTERFACE_MAX 16
#endif

// USB 2.0 compliance test mode support
#ifndef CFG_TUD_TEST_MODE
#define CFG_TUD_TEST_MODE 0
#endif

//------------- Device Class Driver -------------//
#ifndef CFG_TUD_BTH
#define CFG_TUD_BTH 0
Expand Down