summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-06-27 20:49:40 +0200
committerHiFiPhile <[email protected]>2024-06-27 20:49:40 +0200
commiteefca229b64bddf07ae862248f4a1071984a7fe1 (patch)
tree57e8686adc49dda0d19a8fc1b34e45548ec399ed /src/device
parent02ec4866105eca3f95e7392e538caf97ebb902b4 (diff)
parent13dedddd1963e67251f75b3e3ebd654d74d8aa56 (diff)
Merge branch 'master' of https://github.com/hathach/tinyusb into dwc2_dma
Diffstat (limited to 'src/device')
-rw-r--r--src/device/dcd.h33
-rw-r--r--src/device/usbd.c166
-rw-r--r--src/device/usbd.h12
-rw-r--r--src/device/usbd_pvt.h18
4 files changed, 167 insertions, 62 deletions
diff --git a/src/device/dcd.h b/src/device/dcd.h
index d4f105aa3..f6735b077 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_DCD_H_
-#define _TUSB_DCD_H_
+#ifndef TUSB_DCD_H_
+#define TUSB_DCD_H_
#include "common/tusb_common.h"
#include "osal/osal.h"
@@ -36,14 +36,6 @@
#endif
//--------------------------------------------------------------------+
-// Configuration
-//--------------------------------------------------------------------+
-
-#ifndef CFG_TUD_ENDPPOINT_MAX
- #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX
-#endif
-
-//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
@@ -97,6 +89,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");
//--------------------------------------------------------------------+
@@ -141,14 +141,21 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr);
void dcd_remote_wakeup(uint8_t rhport);
// Connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport) TU_ATTR_WEAK;
+void dcd_connect(uint8_t rhport);
// Disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
+void dcd_disconnect(uint8_t rhport);
// 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
//--------------------------------------------------------------------+
@@ -239,4 +246,4 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t
}
#endif
-#endif /* _TUSB_DCD_H_ */
+#endif
diff --git a/src/device/usbd.c b/src/device/usbd.c
index e51aa0fc4..800d9c824 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -45,15 +45,27 @@
//--------------------------------------------------------------------+
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
+ (void)rhport;
+ (void)eventid;
+ (void)in_isr;
+}
+
+TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) {
+ (void)frame_count;
+}
+
TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) {
(void) rhport;
return false;
}
-TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
- (void)rhport;
- (void)eventid;
- (void)in_isr;
+TU_ATTR_WEAK void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+}
+
+TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
}
//--------------------------------------------------------------------+
@@ -76,6 +88,7 @@ typedef struct {
volatile uint8_t cfg_num; // current active configuration (0x00 is not configured)
uint8_t speed;
volatile uint8_t setup_count;
+ volatile uint8_t sof_consumer;
uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
@@ -90,16 +103,16 @@ tu_static usbd_device_t _usbd_dev;
// Class Driver
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
- #define DRIVER_NAME(_name) .name = _name,
+ #define DRIVER_NAME(_name) _name
#else
- #define DRIVER_NAME(_name)
+ #define DRIVER_NAME(_name) NULL
#endif
// Built-in class drivers
tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_CDC
{
- DRIVER_NAME("CDC")
+ .name = DRIVER_NAME("CDC"),
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
@@ -112,7 +125,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_MSC
{
- DRIVER_NAME("MSC")
+ .name = DRIVER_NAME("MSC"),
.init = mscd_init,
.deinit = NULL,
.reset = mscd_reset,
@@ -125,7 +138,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_HID
{
- DRIVER_NAME("HID")
+ .name = DRIVER_NAME("HID"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
@@ -138,7 +151,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_AUDIO
{
- DRIVER_NAME("AUDIO")
+ .name = DRIVER_NAME("AUDIO"),
.init = audiod_init,
.deinit = audiod_deinit,
.reset = audiod_reset,
@@ -151,7 +164,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_VIDEO
{
- DRIVER_NAME("VIDEO")
+ .name = DRIVER_NAME("VIDEO"),
.init = videod_init,
.deinit = videod_deinit,
.reset = videod_reset,
@@ -164,7 +177,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_MIDI
{
- DRIVER_NAME("MIDI")
+ .name = DRIVER_NAME("MIDI"),
.init = midid_init,
.deinit = midid_deinit,
.open = midid_open,
@@ -177,7 +190,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_VENDOR
{
- DRIVER_NAME("VENDOR")
+ .name = DRIVER_NAME("VENDOR"),
.init = vendord_init,
.deinit = vendord_deinit,
.reset = vendord_reset,
@@ -190,7 +203,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_USBTMC
{
- DRIVER_NAME("TMC")
+ .name = DRIVER_NAME("TMC"),
.init = usbtmcd_init_cb,
.deinit = usbtmcd_deinit,
.reset = usbtmcd_reset_cb,
@@ -203,7 +216,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_DFU_RUNTIME
{
- DRIVER_NAME("DFU-RUNTIME")
+ .name = DRIVER_NAME("DFU-RUNTIME"),
.init = dfu_rtd_init,
.deinit = dfu_rtd_deinit,
.reset = dfu_rtd_reset,
@@ -216,7 +229,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_DFU
{
- DRIVER_NAME("DFU")
+ .name = DRIVER_NAME("DFU"),
.init = dfu_moded_init,
.deinit = dfu_moded_deinit,
.reset = dfu_moded_reset,
@@ -229,7 +242,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
{
- DRIVER_NAME("NET")
+ .name = DRIVER_NAME("NET"),
.init = netd_init,
.deinit = netd_deinit,
.reset = netd_reset,
@@ -242,7 +255,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_BTH
{
- DRIVER_NAME("BTH")
+ .name = DRIVER_NAME("BTH"),
.init = btd_init,
.deinit = btd_deinit,
.reset = btd_reset,
@@ -275,6 +288,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8
return driver;
}
+
//--------------------------------------------------------------------+
// DCD Event
//--------------------------------------------------------------------+
@@ -307,7 +321,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event,
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);
@@ -371,17 +387,19 @@ bool tud_remote_wakeup(void) {
}
bool tud_disconnect(void) {
- TU_VERIFY(dcd_disconnect);
dcd_disconnect(_usbd_rhport);
return true;
}
bool tud_connect(void) {
- TU_VERIFY(dcd_connect);
dcd_connect(_usbd_rhport);
return true;
}
+void tud_sof_cb_enable(bool en) {
+ usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en);
+}
+
//--------------------------------------------------------------------+
// USBD Task
//--------------------------------------------------------------------+
@@ -393,7 +411,7 @@ bool tud_init(uint8_t rhport) {
// skip if already initialized
if (tud_inited()) return true;
- TU_LOG_USBD("USBD init on controller %u\r\n", rhport);
+ TU_LOG_USBD("USBD init on controller %u, Highspeed = %u\r\n", rhport, TUD_OPT_HIGH_SPEED);
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
@@ -612,6 +630,12 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
break;
case DCD_EVENT_SOF:
+ if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
+ TU_LOG_USBD("\r\n");
+ tud_sof_cb(event.sof.frame_count);
+ }
+ break;
+
default:
TU_BREAKPOINT();
break;
@@ -702,6 +726,9 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// already configured: need to clear all endpoints and driver first
TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
+ // disable SOF
+ dcd_sof_enable(rhport, false);
+
// close all non-control endpoints, cancel all pending transfers if any
dcd_edpt_close_all(rhport);
@@ -732,14 +759,47 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
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");
- 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;
- // Host may enable remote wake up before suspending especially HID device
- _usbd_dev.remote_wakeup_en = true;
- tud_control_status(rhport, p_request);
+#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));
+
+ 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;
+ }
break;
case TUSB_REQ_CLEAR_FEATURE:
@@ -1067,6 +1127,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
}
}
+#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
//--------------------------------------------------------------------+
@@ -1101,6 +1175,14 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr)
break;
case DCD_EVENT_SOF:
+ // SOF driver handler in ISR context
+ for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
+ usbd_class_driver_t const* driver = get_driver(i);
+ if (driver && driver->sof) {
+ driver->sof(event->rhport, event->sof.frame_count);
+ }
+ }
+
// Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
// which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
if (_usbd_dev.suspended) {
@@ -1110,15 +1192,10 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr)
queue_event(&event_resume, in_isr);
}
- // SOF driver handler in ISR context
- for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
- usbd_class_driver_t const* driver = get_driver(i);
- if (driver && driver->sof) {
- driver->sof(event->rhport, event->sof.frame_count);
- }
+ if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
+ dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF, .sof.frame_count = event->sof.frame_count};
+ queue_event(&event_sof, in_isr);
}
-
- // skip osal queue for SOF in usbd task
break;
case DCD_EVENT_SETUP_RECEIVED:
@@ -1355,12 +1432,21 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
return;
}
-void usbd_sof_enable(uint8_t rhport, bool en) {
+void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) {
rhport = _usbd_rhport;
- // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more.
- // Only if all drivers switched off SOF calls the SOF interrupt may be disabled
- dcd_sof_enable(rhport, en);
+ uint8_t consumer_old = _usbd_dev.sof_consumer;
+ // Keep track how many class instances need the SOF interrupt
+ if (en) {
+ _usbd_dev.sof_consumer |= (uint8_t)(1 << consumer);
+ } else {
+ _usbd_dev.sof_consumer &= (uint8_t)(~(1 << consumer));
+ }
+
+ // Test logically unequal
+ if(!_usbd_dev.sof_consumer != !consumer_old) {
+ dcd_sof_enable(rhport, _usbd_dev.sof_consumer);
+ }
}
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 0197628e2..e47f674ea 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -60,7 +60,7 @@ void tud_task (void) {
// Check if there is pending events need processing by tud_task()
bool tud_task_event_ready(void);
-#ifndef _TUSB_DCD_H_
+#ifndef TUSB_DCD_H_
extern void dcd_int_handler(uint8_t rhport);
#endif
@@ -97,6 +97,9 @@ bool tud_disconnect(void);
// Return false on unsupported MCUs
bool tud_connect(void);
+// Enable or disable the Start Of Frame callback support
+void tud_sof_cb_enable(bool en);
+
// Carry out Data and Status stage of control transfer
// - If len = 0, it is equivalent to sending status only
// - If len > wLength : it will be truncated
@@ -152,6 +155,9 @@ TU_ATTR_WEAK void tud_resume_cb(void);
// Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext()
void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
+// Invoked when a new (micro) frame started
+void tud_sof_cb(uint32_t frame_count);
+
// Invoked when received control request with VENDOR TYPE
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
@@ -221,8 +227,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
/* CDC Call */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
- /* CDC ACM: support line request */\
- 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
+ /* CDC ACM: support line request + send break */\
+ 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 6,\
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index 47752f32c..335d46cd8 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -23,8 +23,8 @@
*
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_USBD_PVT_H_
-#define _TUSB_USBD_PVT_H_
+#ifndef TUSB_USBD_PVT_H_
+#define TUSB_USBD_PVT_H_
#include "osal/osal.h"
#include "common/tusb_fifo.h"
@@ -36,14 +36,20 @@
#define TU_LOG_USBD(...) TU_LOG(CFG_TUD_LOG_LEVEL, __VA_ARGS__)
//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+typedef enum {
+ SOF_CONSUMER_USER = 0,
+ SOF_CONSUMER_AUDIO,
+} sof_consumer_t;
+
+//--------------------------------------------------------------------+
// Class Driver API
//--------------------------------------------------------------------+
typedef struct {
- #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
char const* name;
- #endif
-
void (* init ) (void);
bool (* deinit ) (void);
void (* reset ) (uint8_t rhport);
@@ -111,7 +117,7 @@ bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) {
}
// Enable SOF interrupt
-void usbd_sof_enable(uint8_t rhport, bool en);
+void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en);
/*------------------------------------------------------------------*/
/* Helper