Add DWC2 Test Mode SUpport
This commit is contained in:
@@ -195,6 +195,7 @@
|
|||||||
#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
|
#elif TU_CHECK_MCU(OPT_MCU_STM32F7)
|
||||||
#define TUP_USBIP_DWC2
|
#define TUP_USBIP_DWC2
|
||||||
#define TUP_USBIP_DWC2_STM32
|
#define TUP_USBIP_DWC2_STM32
|
||||||
|
#define TUP_USBIP_DWC2_TEST_MODE_SUPPORT
|
||||||
|
|
||||||
// FS has 6, HS has 9
|
// FS has 6, HS has 9
|
||||||
#define TUP_DCD_ENDPOINT_MAX 9
|
#define TUP_DCD_ENDPOINT_MAX 9
|
||||||
@@ -262,6 +263,7 @@
|
|||||||
#define TUP_USBIP_DWC2
|
#define TUP_USBIP_DWC2
|
||||||
#define TUP_USBIP_DWC2_STM32
|
#define TUP_USBIP_DWC2_STM32
|
||||||
#define TUP_DCD_ENDPOINT_MAX 6
|
#define TUP_DCD_ENDPOINT_MAX 6
|
||||||
|
#define TUP_USBIP_DWC2_TEST_MODE_SUPPORT
|
||||||
|
|
||||||
#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
|
#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
|
||||||
#define TUP_USBIP_FSDEV
|
#define TUP_USBIP_FSDEV
|
||||||
|
@@ -58,6 +58,7 @@ typedef enum
|
|||||||
|
|
||||||
DCD_EVENT_SETUP_RECEIVED,
|
DCD_EVENT_SETUP_RECEIVED,
|
||||||
DCD_EVENT_XFER_COMPLETE,
|
DCD_EVENT_XFER_COMPLETE,
|
||||||
|
DCD_EVENT_TEST_MODE,
|
||||||
|
|
||||||
// Not an DCD event, just a convenient way to defer ISR function
|
// Not an DCD event, just a convenient way to defer ISR function
|
||||||
USBD_EVENT_FUNC_CALL,
|
USBD_EVENT_FUNC_CALL,
|
||||||
@@ -97,9 +98,23 @@ typedef struct TU_ATTR_ALIGNED(4)
|
|||||||
void (*func) (void*);
|
void (*func) (void*);
|
||||||
void* param;
|
void* param;
|
||||||
}func_call;
|
}func_call;
|
||||||
|
|
||||||
|
// TEST MODE
|
||||||
|
struct {
|
||||||
|
uint8_t selector;
|
||||||
|
}test_mode;
|
||||||
};
|
};
|
||||||
} dcd_event_t;
|
} dcd_event_t;
|
||||||
|
|
||||||
|
typedef enum _test_mode_selector
|
||||||
|
{
|
||||||
|
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");
|
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@@ -149,6 +164,12 @@ void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
|
|||||||
// Enable/Disable Start-of-frame interrupt. Default is disabled
|
// Enable/Disable Start-of-frame interrupt. Default is disabled
|
||||||
void dcd_sof_enable(uint8_t rhport, bool en);
|
void dcd_sof_enable(uint8_t rhport, bool en);
|
||||||
|
|
||||||
|
// Check if the test mode is supported
|
||||||
|
bool dcd_test_mode_supported(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;
|
||||||
|
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
// Endpoint API
|
// Endpoint API
|
||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
@@ -240,6 +261,13 @@ static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_i
|
|||||||
dcd_event_handler(&event, in_isr);
|
dcd_event_handler(&event, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TU_ATTR_ALWAYS_INLINE static inline void dcd_event_enter_test_mode(uint8_t rhport, uint8_t test_selector, bool in_isr)
|
||||||
|
{
|
||||||
|
dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_TEST_MODE };
|
||||||
|
event.test_mode.selector = test_selector;
|
||||||
|
dcd_event_handler(&event, in_isr);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -587,6 +587,11 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr)
|
|||||||
if ( event.func_call.func ) event.func_call.func(event.func_call.param);
|
if ( event.func_call.func ) event.func_call.func(event.func_call.param);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DCD_EVENT_TEST_MODE:
|
||||||
|
TU_LOG_USBD(": Enter Test Mode with selector index = %d)\r\n", event.test_mode.selector);
|
||||||
|
if (dcd_enter_test_mode) dcd_enter_test_mode(event.rhport, event.test_mode.selector);
|
||||||
|
break;
|
||||||
|
|
||||||
case DCD_EVENT_SOF:
|
case DCD_EVENT_SOF:
|
||||||
default:
|
default:
|
||||||
TU_BREAKPOINT();
|
TU_BREAKPOINT();
|
||||||
@@ -725,14 +730,50 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TUSB_REQ_SET_FEATURE:
|
case TUSB_REQ_SET_FEATURE:
|
||||||
// Only support remote wakeup for device feature
|
// Handle the feature selector
|
||||||
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
|
switch(p_request->wValue)
|
||||||
|
{
|
||||||
|
// Support for remote wakeup
|
||||||
|
case TUSB_REQ_FEATURE_REMOTE_WAKEUP:
|
||||||
|
TU_LOG_USBD(" Enable Remote Wakeup\r\n");
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
// Host may enable remote wake up before suspending especially HID device
|
break;
|
||||||
_usbd_dev.remote_wakeup_en = true;
|
|
||||||
tud_control_status(rhport, p_request);
|
// Support for TEST_MODE
|
||||||
|
case TUSB_REQ_FEATURE_TEST_MODE:
|
||||||
|
// Only handle the test mode is supported and valid
|
||||||
|
if (!dcd_enter_test_mode || !dcd_test_mode_supported || 0 != tu_u16_low(p_request->wIndex))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t selector = tu_u16_high(p_request->wIndex);
|
||||||
|
|
||||||
|
// Stall request if the selected test mode isn't supported
|
||||||
|
if (!dcd_test_mode_supported(selector))
|
||||||
|
{
|
||||||
|
TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TU_LOG_USBD(" Schedule Test Mode (test selector index: %d)\r\n", selector);
|
||||||
|
|
||||||
|
// Acknowledge request
|
||||||
|
tud_control_status(rhport, p_request);
|
||||||
|
|
||||||
|
// Schedule the execution of the test mode so that the request can be answered
|
||||||
|
dcd_event_enter_test_mode(rhport, selector, false);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Stall unsupported feature selector
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TUSB_REQ_CLEAR_FEATURE:
|
case TUSB_REQ_CLEAR_FEATURE:
|
||||||
|
@@ -1351,4 +1351,34 @@ void dcd_int_handler(uint8_t rhport)
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(TUP_USBIP_DWC2_TEST_MODE_SUPPORT)
|
||||||
|
|
||||||
|
bool dcd_test_mode_supported(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) {
|
||||||
|
// Disable test mode if not supported
|
||||||
|
if (!dcd_test_mode_supported(test_selector)) {
|
||||||
|
test_selector = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay the entering a bit so there is enough time to acknowledge request
|
||||||
|
uint32_t count = SystemCoreClock / 20000;
|
||||||
|
while (count--) __NOP();
|
||||||
|
|
||||||
|
// 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_SUPPORT */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user