Merge branch 'master' into fork/atoktoto/midihost
# Conflicts: # hw/bsp/rp2040/family.cmake # src/class/midi/midi.h # src/class/midi/midi_device.c # src/device/usbd_control.c # src/host/hcd.h # src/host/usbh.c # src/host/usbh.h
This commit is contained in:
136
src/device/dcd.h
136
src/device/dcd.h
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
@@ -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"
|
||||
@@ -35,43 +35,28 @@
|
||||
extern "C" {
|
||||
#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,
|
||||
|
||||
typedef enum {
|
||||
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;
|
||||
|
||||
typedef struct TU_ATTR_ALIGNED(4)
|
||||
{
|
||||
typedef struct TU_ATTR_ALIGNED(4) {
|
||||
uint8_t rhport;
|
||||
uint8_t event_id;
|
||||
|
||||
union
|
||||
{
|
||||
union {
|
||||
// BUS RESET
|
||||
struct {
|
||||
tusb_speed_t speed;
|
||||
@@ -102,12 +87,31 @@ typedef struct TU_ATTR_ALIGNED(4)
|
||||
|
||||
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Memory API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// clean/flush data cache: write cache -> memory.
|
||||
// Required before an DMA TX transfer to make sure data is in memory
|
||||
bool dcd_dcache_clean(const void* addr, uint32_t data_size);
|
||||
|
||||
// invalidate data cache: mark cache as invalid, next read will read from memory
|
||||
// Required BOTH before and after an DMA RX transfer
|
||||
bool dcd_dcache_invalidate(const void* addr, uint32_t data_size);
|
||||
|
||||
// clean and invalidate data cache
|
||||
// Required before an DMA transfer where memory is both read/write by DMA
|
||||
bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// 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);
|
||||
|
||||
// Interrupt Handler
|
||||
void dcd_int_handler(uint8_t rhport);
|
||||
@@ -125,21 +129,25 @@ 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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when a control transfer's status stage is complete.
|
||||
// May help DCD to prepare for next control transfer, this API is optional.
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
|
||||
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request);
|
||||
|
||||
// Configure endpoint's registers according to descriptor
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep);
|
||||
@@ -149,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);
|
||||
|
||||
@@ -167,6 +171,20 @@ 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
|
||||
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
|
||||
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)
|
||||
//--------------------------------------------------------------------+
|
||||
@@ -175,44 +193,46 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
|
||||
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 };
|
||||
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;
|
||||
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 };
|
||||
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;
|
||||
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 };
|
||||
memcpy(&event.setup_received, setup, 8);
|
||||
|
||||
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;
|
||||
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 };
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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 };
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_isr) {
|
||||
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);
|
||||
}
|
||||
@@ -221,4 +241,4 @@ static inline void dcd_event_sof(uint8_t rhport, uint32_t frame_count, bool in_i
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_DCD_H_ */
|
||||
#endif
|
||||
|
||||
1208
src/device/usbd.c
1208
src/device/usbd.c
File diff suppressed because it is too large
Load Diff
@@ -37,8 +37,23 @@ extern "C" {
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Init device stack
|
||||
bool tud_init (uint8_t rhport);
|
||||
// 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
|
||||
#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);
|
||||
|
||||
// Check if device stack is already initialized
|
||||
bool tud_inited(void);
|
||||
@@ -50,15 +65,14 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr);
|
||||
|
||||
// Task function should be called in main/rtos loop
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
void tud_task (void)
|
||||
{
|
||||
void tud_task (void) {
|
||||
tud_task_ext(UINT32_MAX, false);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -80,8 +94,7 @@ bool tud_suspended(void);
|
||||
|
||||
// Check if device is ready to transfer
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool tud_ready(void)
|
||||
{
|
||||
bool tud_ready(void) {
|
||||
return tud_mounted() && !tud_suspended();
|
||||
}
|
||||
|
||||
@@ -96,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
|
||||
@@ -105,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
|
||||
@@ -122,34 +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
|
||||
@@ -217,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 */\
|
||||
@@ -293,7 +315,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
/* MIDI Streaming (MS) Interface */\
|
||||
9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 0, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\
|
||||
/* MS Header */\
|
||||
7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN)
|
||||
7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0100), U16_TO_U8S_LE(7 + (_numcables) * TUD_MIDI_DESC_JACK_LEN + 2 * TUD_MIDI_DESC_EP_LEN(_numcables))
|
||||
|
||||
#define TUD_MIDI_JACKID_IN_EMB(_cablenum) \
|
||||
(uint8_t)(((_cablenum) - 1) * 4 + 1)
|
||||
@@ -317,6 +339,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EMBEDDED, TUD_MIDI_JACKID_OUT_EMB(_cablenum), 1, TUD_MIDI_JACKID_IN_EXT(_cablenum), 1, _stridx,\
|
||||
/* MS Out Jack (External), connected to In Jack Embedded */\
|
||||
9, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_OUT_JACK, MIDI_JACK_EXTERNAL, TUD_MIDI_JACKID_OUT_EXT(_cablenum), 1, TUD_MIDI_JACKID_IN_EMB(_cablenum), 1, _stridx
|
||||
|
||||
#define TUD_MIDI_DESC_JACK(_cablenum) TUD_MIDI_DESC_JACK_DESC(_cablenum, 0)
|
||||
|
||||
#define TUD_MIDI_DESC_EP_LEN(_numcables) (9 + 4 + (_numcables))
|
||||
@@ -346,8 +369,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
|
||||
/* Standard Interface Association Descriptor (IAD) */
|
||||
#define TUD_AUDIO_DESC_IAD_LEN 8
|
||||
#define TUD_AUDIO_DESC_IAD(_firstitfs, _nitfs, _stridx) \
|
||||
TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitfs, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
|
||||
#define TUD_AUDIO_DESC_IAD(_firstitf, _nitfs, _stridx) \
|
||||
TUD_AUDIO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, _firstitf, _nitfs, TUSB_CLASS_AUDIO, AUDIO_FUNCTION_SUBCLASS_UNDEFINED, AUDIO_FUNC_PROTOCOL_CODE_V2, _stridx
|
||||
|
||||
/* Standard AC Interface Descriptor(4.7.1) */
|
||||
#define TUD_AUDIO_DESC_STD_AC_LEN 9
|
||||
@@ -391,6 +414,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
|
||||
// For more channels, add definitions here
|
||||
|
||||
/* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */
|
||||
#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7
|
||||
#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \
|
||||
TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval
|
||||
|
||||
/* Standard AS Interface Descriptor(4.9.1) */
|
||||
#define TUD_AUDIO_DESC_STD_AS_INT_LEN 9
|
||||
#define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \
|
||||
@@ -418,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, (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_NO_SYNC | 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
|
||||
@@ -442,7 +470,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
|
||||
#define TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
|
||||
/* Standard Interface Association Descriptor (IAD) */\
|
||||
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
|
||||
TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
|
||||
/* Standard AC Interface Descriptor(4.7.1) */\
|
||||
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
|
||||
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
|
||||
@@ -466,7 +494,7 @@ 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*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\
|
||||
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_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),\
|
||||
/* 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)
|
||||
|
||||
@@ -491,7 +519,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
|
||||
#define TUD_AUDIO_MIC_FOUR_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \
|
||||
/* Standard Interface Association Descriptor (IAD) */\
|
||||
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
|
||||
TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
|
||||
/* Standard AC Interface Descriptor(4.7.1) */\
|
||||
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
|
||||
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
|
||||
@@ -515,7 +543,7 @@ 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*/ _epin, /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 0x01),\
|
||||
TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_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),\
|
||||
/* 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)
|
||||
|
||||
@@ -537,9 +565,9 @@ 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(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
|
||||
TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00),\
|
||||
/* Standard AC Interface Descriptor(4.7.1) */\
|
||||
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
|
||||
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
|
||||
@@ -551,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),\
|
||||
@@ -563,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*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 0x04 : 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) \
|
||||
@@ -603,7 +631,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
/* optional interrupt endpoint */ \
|
||||
// _int_pollingInterval : for LS/FS, expressed in frames (1ms each). 16 may be a good number?
|
||||
#define TUD_USBTMC_INT_DESCRIPTOR(_ep_interrupt, _ep_interrupt_size, _int_pollingInterval ) \
|
||||
7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), 0x16
|
||||
7, TUSB_DESC_ENDPOINT, _ep_interrupt, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(_ep_interrupt_size), _int_pollingInterval
|
||||
|
||||
#define TUD_USBTMC_INT_DESCRIPTOR_LEN (7u)
|
||||
|
||||
@@ -648,7 +676,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
#define TUD_DFU_DESC_LEN(_alt_count) (9 + (_alt_count) * 9)
|
||||
|
||||
// Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size
|
||||
// Note: Alternate count must be numberic or macro, string index is increased by one for each Alt interface
|
||||
// Note: Alternate count must be numeric or macro, string index is increased by one for each Alt interface
|
||||
#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \
|
||||
TU_XSTRCAT(_TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \
|
||||
/* Function */ \
|
||||
@@ -772,10 +800,6 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
|
||||
#define TUD_BT_PROTOCOL_PRIMARY_CONTROLLER 0x01
|
||||
#define TUD_BT_PROTOCOL_AMP_CONTROLLER 0x02
|
||||
|
||||
#ifndef CFG_TUD_BTH_ISO_ALT_COUNT
|
||||
#define CFG_TUD_BTH_ISO_ALT_COUNT 0
|
||||
#endif
|
||||
|
||||
// Length of template descriptor: 38 bytes + number of ISO alternatives * 23
|
||||
#define TUD_BTH_DESC_LEN (8 + 9 + 7 + 7 + 7 + (CFG_TUD_BTH_ISO_ALT_COUNT) * (9 + 7 + 7))
|
||||
|
||||
|
||||
@@ -32,98 +32,90 @@
|
||||
#include "tusb.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback);
|
||||
#endif
|
||||
//--------------------------------------------------------------------+
|
||||
// Callback weak stubs (called if application does not provide)
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t* request) {
|
||||
(void) rhport;
|
||||
(void) request;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum {
|
||||
EDPT_CTRL_OUT = 0x00,
|
||||
EDPT_CTRL_IN = 0x80
|
||||
EDPT_CTRL_IN = 0x80
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
tusb_control_request_t request;
|
||||
|
||||
uint8_t* buffer;
|
||||
uint16_t data_len;
|
||||
uint16_t total_xferred;
|
||||
|
||||
usbd_control_xfer_cb_t complete_cb;
|
||||
} usbd_control_xfer_t;
|
||||
|
||||
static usbd_control_xfer_t _ctrl_xfer;
|
||||
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
static uint8_t _usbd_ctrl_buf[/*CFG_TUD_ENDPOINT0_SIZE*/ 64];
|
||||
CFG_TUD_MEM_SECTION static struct {
|
||||
TUD_EPBUF_DEF(buf, CFG_TUD_ENDPOINT0_SIZE);
|
||||
} _ctrl_epbuf;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Queue ZLP status transaction
|
||||
static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
static inline bool status_stage_xact(uint8_t rhport, const tusb_control_request_t* request) {
|
||||
// Opposite to endpoint in Data Phase
|
||||
uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
|
||||
const uint8_t ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
|
||||
return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
|
||||
}
|
||||
|
||||
// Status phase
|
||||
bool tud_control_status(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = NULL;
|
||||
bool tud_control_status(uint8_t rhport, const tusb_control_request_t* request) {
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = NULL;
|
||||
_ctrl_xfer.total_xferred = 0;
|
||||
_ctrl_xfer.data_len = 0;
|
||||
_ctrl_xfer.data_len = 0;
|
||||
|
||||
return _status_stage_xact(rhport, request);
|
||||
return status_stage_xact(rhport, request);
|
||||
}
|
||||
|
||||
// Queue a transaction in Data Stage
|
||||
// Each transaction has up to Endpoint0's max packet size.
|
||||
// This function can also transfer an zero-length packet
|
||||
static bool _data_stage_xact(uint8_t rhport)
|
||||
{
|
||||
uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, CFG_TUD_ENDPOINT0_SIZE);
|
||||
|
||||
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_SIZE);
|
||||
uint8_t ep_addr = EDPT_CTRL_OUT;
|
||||
|
||||
if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN )
|
||||
{
|
||||
if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) {
|
||||
ep_addr = EDPT_CTRL_IN;
|
||||
if ( xact_len ) memcpy(_usbd_ctrl_buf, _ctrl_xfer.buffer, xact_len);
|
||||
if (xact_len) {
|
||||
TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len));
|
||||
}
|
||||
}
|
||||
|
||||
return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len);
|
||||
return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _ctrl_epbuf.buf : NULL, xact_len);
|
||||
}
|
||||
|
||||
// Transmit data to/from the control endpoint.
|
||||
// If the request's wLength is zero, a status packet is sent instead.
|
||||
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len)
|
||||
{
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = (uint8_t*) buffer;
|
||||
bool tud_control_xfer(uint8_t rhport, const tusb_control_request_t* request, void* buffer, uint16_t len) {
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = (uint8_t*) buffer;
|
||||
_ctrl_xfer.total_xferred = 0U;
|
||||
_ctrl_xfer.data_len = tu_min16(len, request->wLength);
|
||||
_ctrl_xfer.data_len = tu_min16(len, request->wLength);
|
||||
|
||||
if (request->wLength > 0U)
|
||||
{
|
||||
if(_ctrl_xfer.data_len > 0U)
|
||||
{
|
||||
if (request->wLength > 0U) {
|
||||
if (_ctrl_xfer.data_len > 0U) {
|
||||
TU_ASSERT(buffer);
|
||||
}
|
||||
|
||||
// TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len);
|
||||
|
||||
// Data stage
|
||||
TU_ASSERT( _data_stage_xact(rhport) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Status stage
|
||||
TU_ASSERT( _status_stage_xact(rhport, request) );
|
||||
TU_ASSERT(data_stage_xact(rhport));
|
||||
} else {
|
||||
TU_ASSERT(status_stage_xact(rhport, request));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -132,49 +124,42 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const * request, vo
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
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);
|
||||
void usbd_control_set_request(const tusb_control_request_t* 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 result, uint32_t xferred_bytes);
|
||||
|
||||
void usbd_control_reset(void)
|
||||
{
|
||||
void usbd_control_reset(void) {
|
||||
tu_varclr(&_ctrl_xfer);
|
||||
}
|
||||
|
||||
// Set complete callback
|
||||
void usbd_control_set_complete_callback( usbd_control_xfer_cb_t fp )
|
||||
{
|
||||
void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp) {
|
||||
_ctrl_xfer.complete_cb = fp;
|
||||
}
|
||||
|
||||
// for dcd_set_address where DCD is responsible for status response
|
||||
void usbd_control_set_request(tusb_control_request_t const *request)
|
||||
{
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = NULL;
|
||||
void usbd_control_set_request(const tusb_control_request_t* request) {
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = NULL;
|
||||
_ctrl_xfer.total_xferred = 0;
|
||||
_ctrl_xfer.data_len = 0;
|
||||
_ctrl_xfer.data_len = 0;
|
||||
}
|
||||
|
||||
// callback when a transaction complete on
|
||||
// - DATA stage of control endpoint or
|
||||
// - Status stage
|
||||
bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result, 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) 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 )
|
||||
{
|
||||
if (tu_edpt_dir(ep_addr) != _ctrl_xfer.request.bmRequestType_bit.direction) {
|
||||
TU_ASSERT(0 == xferred_bytes);
|
||||
|
||||
// invoke optional dcd hook if available
|
||||
if (dcd_edpt0_status_complete) dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request);
|
||||
dcd_edpt0_status_complete(rhport, &_ctrl_xfer.request);
|
||||
|
||||
if (_ctrl_xfer.complete_cb)
|
||||
{
|
||||
if (_ctrl_xfer.complete_cb) {
|
||||
// TODO refactor with usbd_driver_print_control_complete_name
|
||||
_ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_ACK, &_ctrl_xfer.request);
|
||||
}
|
||||
@@ -182,11 +167,10 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( _ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT )
|
||||
{
|
||||
if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) {
|
||||
TU_VERIFY(_ctrl_xfer.buffer);
|
||||
memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes);
|
||||
TU_LOG_MEM(2, _usbd_ctrl_buf, xferred_bytes, 2);
|
||||
memcpy(_ctrl_xfer.buffer, _ctrl_epbuf.buf, xferred_bytes);
|
||||
TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
}
|
||||
|
||||
_ctrl_xfer.total_xferred += (uint16_t) xferred_bytes;
|
||||
@@ -194,37 +178,31 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
|
||||
|
||||
// Data Stage is complete when all request's length are transferred or
|
||||
// a short packet is sent including zero-length packet.
|
||||
if ( (_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE) )
|
||||
{
|
||||
if ((_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) ||
|
||||
(xferred_bytes < CFG_TUD_ENDPOINT0_SIZE)) {
|
||||
// DATA stage is complete
|
||||
bool is_ok = true;
|
||||
|
||||
// invoke complete callback if set
|
||||
// callback can still stall control in status phase e.g out data does not make sense
|
||||
if ( _ctrl_xfer.complete_cb )
|
||||
{
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
if (_ctrl_xfer.complete_cb) {
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
usbd_driver_print_control_complete_name(_ctrl_xfer.complete_cb);
|
||||
#endif
|
||||
|
||||
is_ok = _ctrl_xfer.complete_cb(rhport, CONTROL_STAGE_DATA, &_ctrl_xfer.request);
|
||||
}
|
||||
|
||||
if ( is_ok )
|
||||
{
|
||||
// Send status
|
||||
TU_ASSERT( _status_stage_xact(rhport, &_ctrl_xfer.request) );
|
||||
}else
|
||||
{
|
||||
if (is_ok) {
|
||||
TU_ASSERT(status_stage_xact(rhport, &_ctrl_xfer.request));
|
||||
} else {
|
||||
// Stall both IN and OUT control endpoint
|
||||
dcd_edpt_stall(rhport, EDPT_CTRL_OUT);
|
||||
dcd_edpt_stall(rhport, EDPT_CTRL_IN);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// More data to transfer
|
||||
TU_ASSERT( _data_stage_xact(rhport) );
|
||||
TU_ASSERT(data_stage_xact(rhport));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
@@ -23,27 +23,36 @@
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
#ifndef USBD_PVT_H_
|
||||
#define 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" {
|
||||
#endif
|
||||
|
||||
#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 >= 2
|
||||
typedef struct {
|
||||
char const* name;
|
||||
#endif
|
||||
|
||||
void (* init ) (void);
|
||||
bool (* deinit ) (void);
|
||||
void (* reset ) (uint8_t rhport);
|
||||
uint16_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t max_len);
|
||||
bool (* control_xfer_cb ) (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
|
||||
@@ -52,7 +61,7 @@ typedef struct
|
||||
} usbd_class_driver_t;
|
||||
|
||||
// Invoked when initializing device stack to get additional class drivers.
|
||||
// Can optionally implemented by application to extend/overwrite class driver support.
|
||||
// Can be implemented by application to extend/overwrite class driver support.
|
||||
// Note: The drivers array must be accessible at all time when stack is active
|
||||
usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) TU_ATTR_WEAK;
|
||||
|
||||
@@ -96,26 +105,35 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr);
|
||||
// Check if endpoint is stalled
|
||||
bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr);
|
||||
|
||||
// Allocate packet buffer used by ISO endpoints
|
||||
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size);
|
||||
|
||||
// Configure and enable an ISO endpoint according to descriptor
|
||||
bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
|
||||
|
||||
// Check if endpoint is ready (not busy and not stalled)
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) {
|
||||
return !usbd_edpt_busy(rhport, ep_addr) && !usbd_edpt_stalled(rhport, 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
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in);
|
||||
void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr );
|
||||
void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr);
|
||||
|
||||
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* USBD_PVT_H_ */
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user