diff options
Diffstat (limited to 'src/device')
| -rw-r--r-- | src/device/dcd.h | 84 | ||||
| -rw-r--r-- | src/device/usbd.c | 285 | ||||
| -rw-r--r-- | src/device/usbd.h | 56 | ||||
| -rw-r--r-- | src/device/usbd_control.c | 2 | ||||
| -rw-r--r-- | src/device/usbd_pvt.h | 19 |
5 files changed, 288 insertions, 158 deletions
diff --git a/src/device/dcd.h b/src/device/dcd.h index d4f105aa3..d01f82e01 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,31 +36,19 @@ #endif //--------------------------------------------------------------------+ -// Configuration -//--------------------------------------------------------------------+ - -#ifndef CFG_TUD_ENDPPOINT_MAX - #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX -#endif - -//--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF PROTYPES //--------------------------------------------------------------------+ typedef enum { - DCD_EVENT_INVALID = 0, - DCD_EVENT_BUS_RESET, - DCD_EVENT_UNPLUGGED, - DCD_EVENT_SOF, - DCD_EVENT_SUSPEND, // TODO LPM Sleep L1 support - DCD_EVENT_RESUME, - - DCD_EVENT_SETUP_RECEIVED, - DCD_EVENT_XFER_COMPLETE, - - // Not an DCD event, just a convenient way to defer ISR function - USBD_EVENT_FUNC_CALL, - + DCD_EVENT_INVALID = 0, // 0 + DCD_EVENT_BUS_RESET, // 1 + DCD_EVENT_UNPLUGGED, // 2 + DCD_EVENT_SOF, // 3 + DCD_EVENT_SUSPEND, // 4 TODO LPM Sleep L1 support + DCD_EVENT_RESUME, // 5 + DCD_EVENT_SETUP_RECEIVED, // 6 + DCD_EVENT_XFER_COMPLETE, // 7 + USBD_EVENT_FUNC_CALL, // 8 Not an DCD event, just a convenient way to defer ISR function DCD_EVENT_COUNT } dcd_eventid_t; @@ -120,7 +108,7 @@ void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_W //--------------------------------------------------------------------+ // Initialize controller to device mode -void dcd_init(uint8_t rhport); +bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); // Deinitialize controller, unset device mode. bool dcd_deinit(uint8_t rhport); @@ -141,14 +129,18 @@ 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 +// Put device into a test mode (needs power cycle to quit) +void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector); +#endif //--------------------------------------------------------------------+ // Endpoint API //--------------------------------------------------------------------+ @@ -165,10 +157,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc // required for multiple configuration support. void dcd_edpt_close_all (uint8_t rhport); -// Close an endpoint. -// Since it is weak, caller must TU_ASSERT this function's existence before calling it. -void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; - // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); @@ -183,12 +171,19 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); // This API never calls with control endpoints, since it is auto cleared when receiving setup packet void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); +#ifdef TUP_DCD_EDPT_ISO_ALLOC // Allocate packet buffer used by ISO endpoints // Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering -TU_ATTR_WEAK bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); +bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size); // Configure and enable an ISO endpoint according to descriptor -TU_ATTR_WEAK bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); +bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep); + +#else +// Close an endpoint. +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr); + +#endif //--------------------------------------------------------------------+ // Event API (implemented by stack) @@ -199,38 +194,45 @@ extern void dcd_event_handler(dcd_event_t const * event, bool in_isr); // helper to send bus signal event TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr) { - dcd_event_t event = { .rhport = rhport, .event_id = eid }; + dcd_event_t event; + event.rhport = rhport; + event.event_id = eid; dcd_event_handler(&event, in_isr); } // helper to send bus reset event TU_ATTR_ALWAYS_INLINE static inline void dcd_event_bus_reset (uint8_t rhport, tusb_speed_t speed, bool in_isr) { - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_BUS_RESET }; + dcd_event_t event; + event.rhport = rhport; + event.event_id = DCD_EVENT_BUS_RESET; event.bus_reset.speed = speed; dcd_event_handler(&event, in_isr); } // helper to send setup received TU_ATTR_ALWAYS_INLINE static inline void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr) { - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SETUP_RECEIVED }; + dcd_event_t event; + event.rhport = rhport; + event.event_id = DCD_EVENT_SETUP_RECEIVED; memcpy(&event.setup_received, setup, sizeof(tusb_control_request_t)); - dcd_event_handler(&event, in_isr); } // helper to send transfer complete event TU_ATTR_ALWAYS_INLINE static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr) { - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_XFER_COMPLETE }; - + dcd_event_t event; + event.rhport = rhport; + event.event_id = DCD_EVENT_XFER_COMPLETE; event.xfer_complete.ep_addr = ep_addr; event.xfer_complete.len = xferred_bytes; event.xfer_complete.result = result; - dcd_event_handler(&event, in_isr); } TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) { - dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SOF }; + dcd_event_t event; + event.rhport = rhport; + event.event_id = DCD_EVENT_SOF; event.sof.frame_count = frame_count; dcd_event_handler(&event, in_isr); } @@ -239,4 +241,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..a730b745b 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -45,15 +45,60 @@ //--------------------------------------------------------------------+ // 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 uint8_t const* tud_descriptor_bos_cb(void) { + return NULL; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void) { + return NULL; +} + +TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) { + (void) index; + return NULL; +} + +TU_ATTR_WEAK void tud_mount_cb(void) { +} + +TU_ATTR_WEAK void tud_umount_cb(void) { +} + +TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en) { + (void) remote_wakeup_en; +} + +TU_ATTR_WEAK void tud_resume_cb(void) { +} + +TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { + (void) rhport; + (void) stage; + (void) request; + return false; +} + 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; } //--------------------------------------------------------------------+ @@ -75,7 +120,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 @@ -85,21 +130,22 @@ typedef struct { }usbd_device_t; tu_static usbd_device_t _usbd_dev; +static volatile uint8_t _usbd_queued_setup; //--------------------------------------------------------------------+ // 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 +158,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 +171,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 +184,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 +197,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 +210,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 +223,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 +236,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 +249,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 +262,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 +275,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 +288,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 +321,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8 return driver; } + //--------------------------------------------------------------------+ // DCD Event //--------------------------------------------------------------------+ @@ -308,6 +355,16 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const 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) { + TU_VERIFY(CONTROL_STAGE_ACK == stage); + uint8_t const selector = tu_u16_high(request->wIndex); + TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector); + dcd_enter_test_mode(rhport, (tusb_feature_test_mode_t) selector); + return true; +} +#endif + // from usbd_control.c void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const *request); @@ -371,17 +428,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 //--------------------------------------------------------------------+ @@ -389,17 +448,21 @@ bool tud_inited(void) { return _usbd_rhport != RHPORT_INVALID; } -bool tud_init(uint8_t rhport) { - // skip if already initialized - if (tud_inited()) return true; +bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + if (tud_inited()) { + return true; // skip if already initialized + } + TU_ASSERT(rh_init); - TU_LOG_USBD("USBD init on controller %u\r\n", rhport); + TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, + rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full"); 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)); TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t)); tu_varclr(&_usbd_dev); + _usbd_queued_setup = 0; #if OSAL_MUTEX_REQUIRED // Init device mutex @@ -427,15 +490,16 @@ bool tud_init(uint8_t rhport) { _usbd_rhport = rhport; // Init device controller driver - dcd_init(rhport); + TU_ASSERT(dcd_init(rhport, rh_init)); dcd_int_enable(rhport); return true; } bool tud_deinit(uint8_t rhport) { - // skip if not initialized - if (!tud_inited()) return true; + if (!tud_inited()) { + return true; // skip if not initialized + } TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport); @@ -497,7 +561,7 @@ bool tud_task_event_ready(void) { * int main(void) { application_init(); - tusb_init(); + tusb_init(0, TUSB_ROLE_DEVICE); while(1) { // the mainloop application_code(); @@ -531,13 +595,14 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { case DCD_EVENT_UNPLUGGED: TU_LOG_USBD("\r\n"); usbd_reset(event.rhport); - if (tud_umount_cb) tud_umount_cb(); + tud_umount_cb(); break; case DCD_EVENT_SETUP_RECEIVED: - _usbd_dev.setup_count--; + TU_ASSERT(_usbd_queued_setup > 0,); + _usbd_queued_setup--; TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8); - if (_usbd_dev.setup_count) { + if (_usbd_queued_setup) { TU_LOG_USBD(" Skipped since there is other SETUP in queue\r\n"); break; } @@ -591,7 +656,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected if (_usbd_dev.connected) { TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en); - if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en); + tud_suspend_cb(_usbd_dev.remote_wakeup_en); } else { TU_LOG_USBD(" Skipped\r\n"); } @@ -600,7 +665,7 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) { case DCD_EVENT_RESUME: if (_usbd_dev.connected) { TU_LOG_USBD("\r\n"); - if (tud_resume_cb) tud_resume_cb(); + tud_resume_cb(); } else { TU_LOG_USBD(" Skipped\r\n"); } @@ -612,6 +677,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; @@ -643,8 +714,6 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const // Vendor request if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) { - TU_VERIFY(tud_vendor_control_xfer_cb); - usbd_control_set_complete_callback(tud_vendor_control_xfer_cb); return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request); } @@ -671,7 +740,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const } if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) { - // Non standard request is not supported + // Non-standard request is not supported TU_BREAKPOINT(); return false; } @@ -702,6 +771,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); @@ -712,17 +784,23 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const _usbd_dev.speed = speed; // restore speed } + _usbd_dev.cfg_num = cfg_num; + // Handle the new configuration and execute the corresponding callback if ( cfg_num ) { // switch to new configuration if not zero - TU_ASSERT( process_set_config(rhport, cfg_num) ); - if ( tud_mount_cb ) tud_mount_cb(); + if (!process_set_config(rhport, cfg_num)) { + TU_MESS_FAILED(); + TU_BREAKPOINT(); + _usbd_dev.cfg_num = 0; + return false; + } + tud_mount_cb(); } else { - if ( tud_umount_cb ) tud_umount_cb(); + tud_umount_cb(); } } - _usbd_dev.cfg_num = cfg_num; tud_control_status(rhport, p_request); } break; @@ -732,14 +810,31 @@ 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); + switch(p_request->wValue) { + 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 + case TUSB_REQ_FEATURE_TEST_MODE: { + // Only handle the test mode if supported and valid + TU_VERIFY(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 const selector = tu_u16_high(p_request->wIndex); + TU_VERIFY(TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE); + + usbd_control_set_complete_callback(process_test_mode_cb); + tud_control_status(rhport, p_request); + break; + } + #endif /* CFG_TUD_TEST_MODE */ + + // Stall unsupported feature selector + default: return false; + } break; case TUSB_REQ_CLEAR_FEATURE: @@ -969,39 +1064,34 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const switch(desc_type) { - case TUSB_DESC_DEVICE: - { + case TUSB_DESC_DEVICE: { TU_LOG_USBD(" Device\r\n"); void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb(); + TU_ASSERT(desc_device); // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has. // This only happens with the very first get device descriptor and EP0 size = 8 or 16. if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed && - ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) - { + ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) { // Hack here: we modify the request length to prevent usbd_control response with zlp // since we are responding with 1 packet & less data than wLength. tusb_control_request_t mod_request = *p_request; mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE; return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE); - }else - { + }else { return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t)); } } // break; // unreachable - case TUSB_DESC_BOS: - { + case TUSB_DESC_BOS: { TU_LOG_USBD(" BOS\r\n"); // requested by host if USB > 2.0 ( i.e 2.1 or 3.x ) - if (!tud_descriptor_bos_cb) return false; - uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb(); - TU_ASSERT(desc_bos); + TU_VERIFY(desc_bos); // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) ); @@ -1011,24 +1101,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const // break; // unreachable case TUSB_DESC_CONFIGURATION: - case TUSB_DESC_OTHER_SPEED_CONFIG: - { + case TUSB_DESC_OTHER_SPEED_CONFIG: { uintptr_t desc_config; - if ( desc_type == TUSB_DESC_CONFIGURATION ) - { + if ( desc_type == TUSB_DESC_CONFIGURATION ) { TU_LOG_USBD(" Configuration[%u]\r\n", desc_index); desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index); - }else - { + TU_ASSERT(desc_config); + }else { // Host only request this after getting Device Qualifier descriptor TU_LOG_USBD(" Other Speed Configuration\r\n"); - TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index); + TU_VERIFY(desc_config); } - TU_ASSERT(desc_config); - // Use offsetof to avoid pointer to the odd/misaligned address uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) ); @@ -1049,16 +1135,10 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const } // break; // unreachable - case TUSB_DESC_DEVICE_QUALIFIER: - { + case TUSB_DESC_DEVICE_QUALIFIER: { TU_LOG_USBD(" Device Qualifier\r\n"); - - TU_VERIFY( tud_descriptor_device_qualifier_cb ); - uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); TU_VERIFY(desc_qualifier); - - // first byte of descriptor is its size return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier)); } // break; // unreachable @@ -1101,6 +1181,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,19 +1198,14 @@ 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: - _usbd_dev.setup_count++; + _usbd_queued_setup++; send = true; break; @@ -1339,9 +1422,12 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) { * In progress transfers on this EP may be delivered after this call. */ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC + (void) rhport; (void) ep_addr; + // ISO alloc/activate Should be used instead +#else rhport = _usbd_rhport; - TU_ASSERT(dcd_edpt_close, /**/); TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr); @@ -1351,34 +1437,47 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) { _usbd_dev.ep_status[epnum][dir].stalled = 0; _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; +#endif 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) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC rhport = _usbd_rhport; - TU_ASSERT(dcd_edpt_iso_alloc); TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX); - return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size); +#else + (void) rhport; (void) ep_addr; (void) largest_packet_size; + return false; +#endif } bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) { +#ifdef TUP_DCD_EDPT_ISO_ALLOC rhport = _usbd_rhport; uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress); uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress); - TU_ASSERT(dcd_edpt_iso_activate); TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX); TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed)); @@ -1386,6 +1485,10 @@ bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) _usbd_dev.ep_status[epnum][dir].busy = 0; _usbd_dev.ep_status[epnum][dir].claimed = 0; return dcd_edpt_iso_activate(rhport, desc_ep); +#else + (void) rhport; (void) desc_ep; + return false; +#endif } #endif diff --git a/src/device/usbd.h b/src/device/usbd.h index 0197628e2..de6007fb3 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -37,8 +37,20 @@ extern "C" { // Application API //--------------------------------------------------------------------+ +// New API to replace tud_init() to init device stack on specific roothub port +bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); + // Init device stack on roothub port -bool tud_init (uint8_t rhport); +#if TUSB_VERSION_NUMBER > 2000 // 0.20.0 +TU_ATTR_DEPRECATED("Please use tusb_init(rhport, rh_init) instead") +#endif +TU_ATTR_ALWAYS_INLINE static inline bool tud_init (uint8_t rhport) { + const tusb_rhport_init_t rh_init = { + .role = TUSB_ROLE_DEVICE, + .speed = TUD_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL + }; + return tud_rhport_init(rhport, &rh_init); +} // Deinit device stack on roothub port bool tud_deinit(uint8_t rhport); @@ -60,7 +72,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 +109,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 @@ -106,7 +121,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request); //--------------------------------------------------------------------+ -// Application Callbacks (WEAK is optional) +// Application Callbacks //--------------------------------------------------------------------+ // Invoked when received GET DEVICE DESCRIPTOR request @@ -123,37 +138,40 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid); // Invoked when received GET BOS DESCRIPTOR request // Application return pointer to descriptor -TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void); +uint8_t const * tud_descriptor_bos_cb(void); // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. // device_qualifier descriptor describes information about a high-speed capable device that would // change if the device were operating at the other speed. If not highspeed capable stall this request. -TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void); +uint8_t const* tud_descriptor_device_qualifier_cb(void); // Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request // Application return pointer to descriptor, whose contents must exist long enough for transfer to complete // Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa -TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); // Invoked when device is mounted (configured) -TU_ATTR_WEAK void tud_mount_cb(void); +void tud_mount_cb(void); // Invoked when device is unmounted -TU_ATTR_WEAK void tud_umount_cb(void); +void tud_umount_cb(void); // Invoked when usb bus is suspended // Within 7ms, device must draw an average of current less than 2.5 mA from bus -TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en); +void tud_suspend_cb(bool remote_wakeup_en); // Invoked when usb bus is resumed -TU_ATTR_WEAK void tud_resume_cb(void); +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); +bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); //--------------------------------------------------------------------+ // Binary Device Object Store (BOS) Descriptor Templates @@ -221,8 +239,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 */\ @@ -428,8 +446,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */ #define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN 7 -#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _interval) \ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(4), _interval +#define TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(_ep, _epsize, _interval) \ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN, TUSB_DESC_ENDPOINT, _ep, (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_NO_SYNC | (uint8_t)TUSB_ISO_EP_ATT_EXPLICIT_FB), U16_TO_U8S_LE(_epsize), _interval // AUDIO simple descriptor (UAC2) for 1 microphone input // - 1 Input Terminal, 1 Feature Unit (Mute and Volume Control), 1 Output Terminal, 1 Clock Source @@ -547,7 +565,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP_LEN) -#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize, _epfb) \ +#define TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epoutsize, _epfb, _epfbsize) \ /* Standard Interface Association Descriptor (IAD) */\ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ @@ -561,7 +579,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Output Terminal Descriptor(4.7.2.5) */\ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ /* Feature Unit Descriptor(4.7.2.8) */\ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ @@ -573,11 +591,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_interval*/ 1)\ + TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ 1) // Calculate wMaxPacketSize of Endpoints #define TUD_AUDIO_EP_SIZE(_maxFrequency, _nBytesPerSample, _nChannels) \ diff --git a/src/device/usbd_control.c b/src/device/usbd_control.c index 35cce1f7e..b1fd357aa 100644 --- a/src/device/usbd_control.c +++ b/src/device/usbd_control.c @@ -137,7 +137,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, voi void usbd_control_reset(void); void usbd_control_set_request(tusb_control_request_t const* request); void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp); -bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); void usbd_control_reset(void) { tu_varclr(&_ctrl_xfer); diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 47752f32c..90f37db3e 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -23,11 +23,12 @@ * * 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" +#include "common/tusb_private.h" #ifdef __cplusplus extern "C" { @@ -36,14 +37,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 +118,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 |
