summaryrefslogtreecommitdiff
path: root/src/class
diff options
context:
space:
mode:
authorHa Thach <[email protected]>2023-01-30 11:40:53 +0700
committerGitHub <[email protected]>2023-01-30 11:40:53 +0700
commit88f3279c3cc0394c81783170413bb0ecd6e0dd43 (patch)
tree719ee474bfc8972b56a5d07352bdebaf64d98341 /src/class
parent9f440e5c6946f46d2fa09af1f4c42768ac64ef78 (diff)
parent00c007ed685f797776597673f438e7472cbba202 (diff)
Merge branch 'master' into port-ft90x
Diffstat (limited to 'src/class')
-rw-r--r--src/class/audio/audio.h2
-rw-r--r--src/class/cdc/cdc.h38
-rw-r--r--src/class/cdc/cdc_device.c13
-rw-r--r--src/class/cdc/cdc_device.h5
-rw-r--r--src/class/cdc/cdc_host.c498
-rw-r--r--src/class/cdc/cdc_host.h199
-rw-r--r--src/class/cdc/cdc_rndis_host.c2
-rw-r--r--src/class/hid/hid.h9
-rw-r--r--src/class/hid/hid_device.h27
-rw-r--r--src/class/hid/hid_host.c3
-rw-r--r--src/class/hid/hid_host.h2
-rw-r--r--src/class/msc/msc_host.c17
-rw-r--r--src/class/msc/msc_host.h2
-rw-r--r--src/class/net/ecm_rndis_device.c2
-rw-r--r--src/class/net/ncm_device.c2
-rw-r--r--src/class/usbtmc/usbtmc.h2
-rw-r--r--src/class/usbtmc/usbtmc_device.c85
-rw-r--r--src/class/usbtmc/usbtmc_device.h2
-rw-r--r--src/class/video/video_device.c4
19 files changed, 679 insertions, 235 deletions
diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h
index 6f9c1a6b5..ba497906b 100644
--- a/src/class/audio/audio.h
+++ b/src/class/audio/audio.h
@@ -721,11 +721,13 @@ typedef struct TU_ATTR_PACKED
uint8_t bLength ; ///< Size of this descriptor, in bytes: 17.
uint8_t bDescriptorType ; ///< Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
uint8_t bDescriptorSubType ; ///< Descriptor SubType. Value: AUDIO_CS_AC_INTERFACE_INPUT_TERMINAL.
+ uint8_t bTerminalID ; ///< Constant uniquely identifying the Terminal within the audio function. This value is used in all requests to address this terminal.
uint16_t wTerminalType ; ///< Constant characterizing the type of Terminal. See: audio_terminal_type_t for USB streaming and audio_terminal_input_type_t for other input types.
uint8_t bAssocTerminal ; ///< ID of the Output Terminal to which this Input Terminal is associated.
uint8_t bCSourceID ; ///< ID of the Clock Entity to which this Input Terminal is connected.
uint8_t bNrChannels ; ///< Number of logical output channels in the Terminal’s output audio channel cluster.
uint32_t bmChannelConfig ; ///< Describes the spatial location of the logical channels. See:audio_channel_config_t.
+ uint8_t iChannelNames ; ///< Index of a string descriptor, describing the name of the first logical channel.
uint16_t bmControls ; ///< See: audio_terminal_input_control_pos_t.
uint8_t iTerminal ; ///< Index of a string descriptor, describing the Input Terminal.
} audio_desc_input_terminal_t;
diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h
index e345139ea..2fecde3ca 100644
--- a/src/class/cdc/cdc.h
+++ b/src/class/cdc/cdc.h
@@ -41,16 +41,6 @@
/** \defgroup ClassDriver_CDC_Common Common Definitions
* @{ */
-// TODO remove
-/// CDC Pipe ID, used to indicate which pipe the API is addressing to (Notification, Out, In)
-typedef enum
-{
- CDC_PIPE_NOTIFICATION , ///< Notification pipe
- CDC_PIPE_DATA_IN , ///< Data in pipe
- CDC_PIPE_DATA_OUT , ///< Data out pipe
- CDC_PIPE_ERROR , ///< Invalid Pipe ID
-}cdc_pipeid_t;
-
//--------------------------------------------------------------------+
// CDC Communication Interface Class
//--------------------------------------------------------------------+
@@ -192,8 +182,30 @@ typedef enum
CDC_REQUEST_MDLM_SEMANTIC_MODEL = 0x60,
}cdc_management_request_t;
+enum
+{
+ CDC_CONTROL_LINE_STATE_DTR = 0x01,
+ CDC_CONTROL_LINE_STATE_RTS = 0x02,
+};
+
+enum
+{
+ CDC_LINE_CONDING_STOP_BITS_1 = 0, // 1 bit
+ CDC_LINE_CONDING_STOP_BITS_1_5 = 1, // 1.5 bits
+ CDC_LINE_CONDING_STOP_BITS_2 = 2, // 2 bits
+};
+
+enum
+{
+ CDC_LINE_CODING_PARITY_NONE = 0,
+ CDC_LINE_CODING_PARITY_ODD = 1,
+ CDC_LINE_CODING_PARITY_EVEN = 2,
+ CDC_LINE_CODING_PARITY_MARK = 3,
+ CDC_LINE_CODING_PARITY_SPACE = 4,
+};
+
//--------------------------------------------------------------------+
-// Management Elemenent Notification (Notification Endpoint)
+// Management Element Notification (Notification Endpoint)
//--------------------------------------------------------------------+
/// 6.3 Notification Codes
@@ -390,8 +402,8 @@ TU_VERIFY_STATIC(sizeof(cdc_line_coding_t) == 7, "size is not correct");
typedef struct TU_ATTR_PACKED
{
- uint16_t dte_is_present : 1; ///< Indicates to DCE if DTE is presentor not. This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR.
- uint16_t half_duplex_carrier_control : 1;
+ uint16_t dtr : 1;
+ uint16_t rts : 1;
uint16_t : 14;
} cdc_line_control_state_t;
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index fab6f0035..8d10a416c 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -62,10 +62,8 @@ typedef struct
uint8_t rx_ff_buf[CFG_TUD_CDC_RX_BUFSIZE];
uint8_t tx_ff_buf[CFG_TUD_CDC_TX_BUFSIZE];
-#if CFG_FIFO_MUTEX
- osal_mutex_def_t rx_ff_mutex;
- osal_mutex_def_t tx_ff_mutex;
-#endif
+ OSAL_MUTEX_DEF(rx_ff_mutex);
+ OSAL_MUTEX_DEF(tx_ff_mutex);
// Endpoint Transfer buffer
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE];
@@ -171,7 +169,8 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) bufsize);
// flush if queue more than packet size
- if ( tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE )
+ // may need to suppress -Wunreachable-code since most of the time CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE
+ if ( (tu_fifo_count(&p_cdc->tx_ff) >= BULK_PACKET_SIZE) || ((CFG_TUD_CDC_TX_BUFSIZE < BULK_PACKET_SIZE) && tu_fifo_full(&p_cdc->tx_ff)) )
{
tud_cdc_n_write_flush(itf);
}
@@ -247,10 +246,8 @@ void cdcd_init(void)
// In this way, the most current data is prioritized.
tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true);
-#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&p_cdc->rx_ff, NULL, osal_mutex_create(&p_cdc->rx_ff_mutex));
tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex), NULL);
-#endif
}
}
@@ -435,7 +432,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
// Received new data
if ( ep_addr == p_cdc->ep_out )
{
- tu_fifo_write_n(&p_cdc->rx_ff, &p_cdc->epout_buf, (uint16_t) xferred_bytes);
+ tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes);
// Check for wanted char and invoke callback if needed
if ( tud_cdc_rx_wanted_cb && (((signed char) p_cdc->wanted_char) != -1) )
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
index fbc7162a3..f8a004df4 100644
--- a/src/class/cdc/cdc_device.h
+++ b/src/class/cdc/cdc_device.h
@@ -27,7 +27,6 @@
#ifndef _TUSB_CDC_DEVICE_H_
#define _TUSB_CDC_DEVICE_H_
-#include "common/tusb_common.h"
#include "cdc.h"
//--------------------------------------------------------------------+
@@ -81,7 +80,7 @@ int32_t tud_cdc_n_read_char (uint8_t itf);
// Clear the received FIFO
void tud_cdc_n_read_flush (uint8_t itf);
-// Get a byte from FIFO at the specified position without removing it
+// Get a byte from FIFO without removing it
bool tud_cdc_n_peek (uint8_t itf, uint8_t* ui8);
// Write bytes to TX FIFO, data may remain in the FIFO for a while
@@ -135,7 +134,7 @@ TU_ATTR_WEAK void tud_cdc_rx_cb(uint8_t itf);
// Invoked when received `wanted_char`
TU_ATTR_WEAK void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
-// Invoked when space becomes available in TX buffer
+// Invoked when a TX is complete and therefore space becomes available in TX buffer
TU_ATTR_WEAK void tud_cdc_tx_complete_cb(uint8_t itf);
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index ee824cb4e..e9c3d34cb 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -33,96 +33,260 @@
#include "cdc_host.h"
+
+// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
+#define CDCH_DEBUG 2
+
+#define TU_LOG_CDCH(...) TU_LOG(CDCH_DEBUG, __VA_ARGS__)
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+
typedef struct {
- uint8_t itf_num;
- uint8_t itf_protocol;
+ uint8_t daddr;
+ uint8_t bInterfaceNumber;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ cdc_acm_capability_t acm_capability;
uint8_t ep_notif;
- uint8_t ep_in;
- uint8_t ep_out;
- cdc_acm_capability_t acm_capability;
+ cdc_line_coding_t line_coding; // Baudrate, stop bits, parity, data width
+ uint8_t line_state; // DTR (bit0), RTS (bit1)
-} cdch_data_t;
+ tuh_xfer_cb_t user_control_cb;
+
+ struct {
+ tu_edpt_stream_t tx;
+ tu_edpt_stream_t rx;
+
+ uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE];
+
+ uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE];
+ } stream;
+
+} cdch_interface_t;
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
-static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX];
-static inline cdch_data_t* get_itf(uint8_t dev_addr)
+CFG_TUSB_MEM_SECTION
+static cdch_interface_t cdch_data[CFG_TUH_CDC];
+
+static inline cdch_interface_t* get_itf(uint8_t idx)
{
- return &cdch_data[dev_addr-1];
+ TU_ASSERT(idx < CFG_TUH_CDC, NULL);
+ cdch_interface_t* p_cdc = &cdch_data[idx];
+
+ return (p_cdc->daddr != 0) ? p_cdc : NULL;
}
-bool tuh_cdc_mounted(uint8_t dev_addr)
+static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr)
{
- cdch_data_t* cdc = get_itf(dev_addr);
- return cdc->ep_in && cdc->ep_out;
+ for(uint8_t i=0; i<CFG_TUH_CDC; i++)
+ {
+ cdch_interface_t* p_cdc = &cdch_data[i];
+ if ( (p_cdc->daddr == daddr) &&
+ (ep_addr == p_cdc->ep_notif || ep_addr == p_cdc->stream.rx.ep_addr || ep_addr == p_cdc->stream.tx.ep_addr))
+ {
+ return i;
+ }
+ }
+
+ return TUSB_INDEX_INVALID;
}
-bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
+
+static cdch_interface_t* find_new_itf(void)
{
- if ( !tuh_cdc_mounted(dev_addr) ) return false;
+ for(uint8_t i=0; i<CFG_TUH_CDC; i++)
+ {
+ if (cdch_data[i].daddr == 0) return &cdch_data[i];
+ }
- cdch_data_t const * p_cdc = get_itf(dev_addr);
+ return NULL;
+}
- switch (pipeid)
+//--------------------------------------------------------------------+
+// APPLICATION API
+//--------------------------------------------------------------------+
+
+uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num)
+{
+ for(uint8_t i=0; i<CFG_TUH_CDC; i++)
{
- case CDC_PIPE_NOTIFICATION:
- return usbh_edpt_busy(dev_addr, p_cdc->ep_notif );
+ const cdch_interface_t* p_cdc = &cdch_data[i];
+
+ if (p_cdc->daddr == daddr && p_cdc->bInterfaceNumber == itf_num) return i;
+ }
- case CDC_PIPE_DATA_IN:
- return usbh_edpt_busy(dev_addr, p_cdc->ep_in );
+ return TUSB_INDEX_INVALID;
+}
- case CDC_PIPE_DATA_OUT:
- return usbh_edpt_busy(dev_addr, p_cdc->ep_out );
+bool tuh_cdc_itf_get_info(uint8_t idx, tuh_cdc_itf_info_t* info)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc && info);
- default:
- return false;
- }
+ info->daddr = p_cdc->daddr;
+ info->bInterfaceNumber = p_cdc->bInterfaceNumber;
+ info->bInterfaceSubClass = p_cdc->bInterfaceSubClass;
+ info->bInterfaceProtocol = p_cdc->bInterfaceProtocol;
+
+ return true;
+}
+
+bool tuh_cdc_mounted(uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ return p_cdc != NULL;
+}
+
+bool tuh_cdc_get_dtr(uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_DTR) ? true : false;
+}
+
+bool tuh_cdc_get_rts(uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return (p_cdc->line_state & CDC_CONTROL_LINE_STATE_RTS) ? true : false;
+}
+
+bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ *line_coding = p_cdc->line_coding;
+
+ return true;
}
//--------------------------------------------------------------------+
-// APPLICATION API (parameter validation needed)
+// Write
//--------------------------------------------------------------------+
-bool tuh_cdc_serial_is_mounted(uint8_t dev_addr)
+
+uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize)
{
- // TODO consider all AT Command as serial candidate
- return tuh_cdc_mounted(dev_addr) &&
- (cdch_data[dev_addr-1].itf_protocol <= CDC_COMM_PROTOCOL_ATCOMMAND_CDMA);
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize);
}
-bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify)
+uint32_t tuh_cdc_write_flush(uint8_t idx)
{
- (void) is_notify;
- TU_VERIFY( tuh_cdc_mounted(dev_addr) );
- TU_VERIFY( p_data != NULL && length);
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
- uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
- if ( usbh_edpt_busy(dev_addr, ep_out) ) return false;
+ return tu_edpt_stream_write_xfer(&p_cdc->stream.tx);
+}
- return usbh_edpt_xfer(dev_addr, ep_out, (void*)(uintptr_t) p_data, (uint16_t) length);
+bool tuh_cdc_write_clear(uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return tu_edpt_stream_clear(&p_cdc->stream.tx);
+}
+
+uint32_t tuh_cdc_write_available(uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return tu_edpt_stream_write_available(&p_cdc->stream.tx);
}
-bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify)
+//--------------------------------------------------------------------+
+// Read
+//--------------------------------------------------------------------+
+
+uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize)
{
- (void) is_notify;
- TU_VERIFY( tuh_cdc_mounted(dev_addr) );
- TU_VERIFY( p_buffer != NULL && length );
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize);
+}
+
+uint32_t tuh_cdc_read_available(uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return tu_edpt_stream_read_available(&p_cdc->stream.rx);
+}
+
+bool tuh_cdc_peek(uint8_t idx, uint8_t* ch)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ return tu_edpt_stream_peek(&p_cdc->stream.rx, ch);
+}
+
+bool tuh_cdc_read_clear (uint8_t idx)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc);
+
+ bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx);
+ tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+ return ret;
+}
+
+//--------------------------------------------------------------------+
+// Control Endpoint API
+//--------------------------------------------------------------------+
+
+// internal control complete to update state such as line state, encoding
+static void cdch_internal_control_complete(tuh_xfer_t* xfer)
+{
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_ASSERT(p_cdc, );
+
+ if (xfer->result == XFER_RESULT_SUCCESS)
+ {
+ switch(xfer->setup->bRequest)
+ {
+ case CDC_REQUEST_SET_CONTROL_LINE_STATE:
+ p_cdc->line_state = (uint8_t) tu_le16toh(xfer->setup->wValue);
+ break;
+
+ case CDC_REQUEST_SET_LINE_CODING:
+ {
+ uint16_t const len = tu_min16(sizeof(cdc_line_coding_t), tu_le16toh(xfer->setup->wLength));
+ memcpy(&p_cdc->line_coding, xfer->buffer, len);
+ }
+ break;
- uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
- if ( usbh_edpt_busy(dev_addr, ep_in) ) return false;
+ default: break;
+ }
+ }
- return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, (uint16_t) length);
+ xfer->complete_cb = p_cdc->user_control_cb;
+ xfer->complete_cb(xfer);
}
-bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb)
+bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
- cdch_data_t const * p_cdc = get_itf(dev_addr);
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request);
+
+ TU_LOG_CDCH("CDC Set Control Line State\r\n");
tusb_control_request_t const request =
{
@@ -133,36 +297,154 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xf
.direction = TUSB_DIR_OUT
},
.bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE,
- .wValue = tu_htole16((uint16_t) ((dtr ? 1u : 0u) | (rts ? 2u : 0u))),
- .wIndex = tu_htole16(p_cdc->itf_num),
+ .wValue = tu_htole16(line_state),
+ .wIndex = tu_htole16((uint16_t) p_cdc->bInterfaceNumber),
.wLength = 0
};
+ p_cdc->user_control_cb = complete_cb;
tuh_xfer_t xfer =
{
- .daddr = dev_addr,
+ .daddr = p_cdc->daddr,
.ep_addr = 0,
.setup = &request,
.buffer = NULL,
- .complete_cb = complete_cb,
- .user_data = 0
+ .complete_cb = cdch_internal_control_complete,
+ .user_data = user_data
+ };
+
+ return tuh_control_xfer(&xfer);
+}
+
+bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ cdch_interface_t* p_cdc = get_itf(idx);
+ TU_VERIFY(p_cdc && p_cdc->acm_capability.support_line_request);
+
+ TU_LOG_CDCH("CDC Set Line Conding\r\n");
+
+ tusb_control_request_t const request =
+ {
+ .bmRequestType_bit =
+ {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_OUT
+ },
+ .bRequest = CDC_REQUEST_SET_LINE_CODING,
+ .wValue = 0,
+ .wIndex = tu_htole16(p_cdc->bInterfaceNumber),
+ .wLength = tu_htole16(sizeof(cdc_line_coding_t))
+ };
+
+ // use usbh enum buf to hold line coding since user line_coding variable may not live long enough
+ // for the transfer to complete
+ uint8_t* enum_buf = usbh_get_enum_buf();
+ memcpy(enum_buf, line_coding, sizeof(cdc_line_coding_t));
+
+ p_cdc->user_control_cb = complete_cb;
+ tuh_xfer_t xfer =
+ {
+ .daddr = p_cdc->daddr,
+ .ep_addr = 0,
+ .setup = &request,
+ .buffer = enum_buf,
+ .complete_cb = cdch_internal_control_complete,
+ .user_data = user_data
};
return tuh_control_xfer(&xfer);
}
//--------------------------------------------------------------------+
-// USBH-CLASS DRIVER API
+// CLASS-USBH API
//--------------------------------------------------------------------+
+
void cdch_init(void)
{
tu_memclr(cdch_data, sizeof(cdch_data));
+
+ for(size_t i=0; i<CFG_TUH_CDC; i++)
+ {
+ cdch_interface_t* p_cdc = &cdch_data[i];
+
+ tu_edpt_stream_init(&p_cdc->stream.tx, true, true, false,
+ p_cdc->stream.tx_ff_buf, CFG_TUH_CDC_TX_BUFSIZE,
+ p_cdc->stream.tx_ep_buf, CFG_TUH_CDC_TX_EPSIZE);
+
+ tu_edpt_stream_init(&p_cdc->stream.rx, true, false, false,
+ p_cdc->stream.rx_ff_buf, CFG_TUH_CDC_RX_BUFSIZE,
+ p_cdc->stream.rx_ep_buf, CFG_TUH_CDC_RX_EPSIZE);
+ }
+}
+
+void cdch_close(uint8_t daddr)
+{
+ for(uint8_t idx=0; idx<CFG_TUH_CDC; idx++)
+ {
+ cdch_interface_t* p_cdc = &cdch_data[idx];
+ if (p_cdc->daddr == daddr)
+ {
+ // Invoke application callback
+ if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx);
+
+ //tu_memclr(p_cdc, sizeof(cdch_interface_t));
+ p_cdc->daddr = 0;
+ p_cdc->bInterfaceNumber = 0;
+ tu_edpt_stream_close(&p_cdc->stream.tx);
+ tu_edpt_stream_close(&p_cdc->stream.rx);
+ }
+ }
}
-bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
+bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+{
+ // TODO handle stall response, retry failed transfer ...
+ TU_ASSERT(event == XFER_RESULT_SUCCESS);
+
+ uint8_t const idx = get_idx_by_ep_addr(daddr, ep_addr);
+ cdch_interface_t * p_cdc = get_itf(idx);
+ TU_ASSERT(p_cdc);
+
+ if ( ep_addr == p_cdc->stream.tx.ep_addr )
+ {
+ // invoke tx complete callback to possibly refill tx fifo
+ if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx);
+
+ if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) )
+ {
+ // If there is no data left, a ZLP should be sent if:
+ // - xferred_bytes is multiple of EP Packet size and not zero
+ tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes);
+ }
+ }
+ else if ( ep_addr == p_cdc->stream.rx.ep_addr )
+ {
+ tu_edpt_stream_read_xfer_complete(&p_cdc->stream.rx, xferred_bytes);
+
+ // invoke receive callback
+ if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx);
+
+ // prepare for next transfer if needed
+ tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+ }else if ( ep_addr == p_cdc->ep_notif )
+ {
+ // TODO handle notification endpoint
+ }else
+ {
+ TU_ASSERT(false);
+ }
+
+ return true;
+}
+
+//--------------------------------------------------------------------+
+// Enumeration
+//--------------------------------------------------------------------+
+
+bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{
(void) rhport;
- (void) max_len;
// Only support ACM subclass
// Protocol 0xFF can be RNDIS device for windows XP
@@ -170,17 +452,22 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
0xFF != itf_desc->bInterfaceProtocol);
- cdch_data_t * p_cdc = get_itf(dev_addr);
+ uint8_t const * p_desc_end = ((uint8_t const*) itf_desc) + max_len;
- p_cdc->itf_num = itf_desc->bInterfaceNumber;
- p_cdc->itf_protocol = itf_desc->bInterfaceProtocol;
+ cdch_interface_t * p_cdc = find_new_itf();
+ TU_VERIFY(p_cdc);
- //------------- Communication Interface -------------//
- uint16_t drv_len = tu_desc_len(itf_desc);
+ p_cdc->daddr = daddr;
+ p_cdc->bInterfaceNumber = itf_desc->bInterfaceNumber;
+ p_cdc->bInterfaceSubClass = itf_desc->bInterfaceSubClass;
+ p_cdc->bInterfaceProtocol = itf_desc->bInterfaceProtocol;
+ p_cdc->line_state = 0;
+
+ //------------- Control Interface -------------//
uint8_t const * p_desc = tu_desc_next(itf_desc);
// Communication Functional Descriptors
- while( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
+ while( (p_desc < p_desc_end) && (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc)) )
{
if ( CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT == cdc_functional_desc_typeof(p_desc) )
{
@@ -188,19 +475,18 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
p_cdc->acm_capability = ((cdc_desc_func_acm_t const *) p_desc)->bmCapabilities;
}
- drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
- if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
+ // Open notification endpoint of control interface if any
+ if (itf_desc->bNumEndpoints == 1)
{
- // notification endpoint
+ TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc));
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
+ TU_ASSERT( tuh_edpt_open(daddr, desc_ep) );
p_cdc->ep_notif = desc_ep->bEndpointAddress;
- drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
@@ -209,52 +495,96 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const *) p_desc)->bInterfaceClass) )
{
// next to endpoint descriptor
- drv_len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
// data endpoints expected to be in pairs
for(uint32_t i=0; i<2; i++)
{
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
- TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
+ TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
+ TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
- TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
+ TU_ASSERT(tuh_edpt_open(daddr, desc_ep));
if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
{
- p_cdc->ep_in = desc_ep->bEndpointAddress;
+ tu_edpt_stream_open(&p_cdc->stream.rx, daddr, desc_ep);
}else
{
- p_cdc->ep_out = desc_ep->bEndpointAddress;
+ tu_edpt_stream_open(&p_cdc->stream.tx, daddr, desc_ep);
}
- drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next( p_desc );
+ p_desc = tu_desc_next(p_desc);
}
}
return true;
}
-bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num)
+enum
{
- (void) dev_addr; (void) itf_num;
- return true;
-}
+ CONFIG_SET_CONTROL_LINE_STATE,
+ CONFIG_SET_LINE_CODING,
+ CONFIG_COMPLETE
+};
-bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
+static void process_cdc_config(tuh_xfer_t* xfer)
{
- (void) ep_addr;
- tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes );
- return true;
+ uintptr_t const state = xfer->user_data;
+ uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
+ uint8_t const idx = tuh_cdc_itf_get_index(xfer->daddr, itf_num);
+ TU_ASSERT(idx != TUSB_INDEX_INVALID, );
+
+ switch(state)
+ {
+ case CONFIG_SET_CONTROL_LINE_STATE:
+ #if CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+ TU_ASSERT( tuh_cdc_set_control_line_state(idx, CFG_TUH_CDC_LINE_CONTROL_ON_ENUM, process_cdc_config, CONFIG_SET_LINE_CODING), );
+ break;
+ #endif
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_SET_LINE_CODING:
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+ {
+ cdc_line_coding_t line_coding = CFG_TUH_CDC_LINE_CODING_ON_ENUM;
+ TU_ASSERT( tuh_cdc_set_line_coding(idx, &line_coding, process_cdc_config, CONFIG_COMPLETE), );
+ break;
+ }
+ #endif
+ TU_ATTR_FALLTHROUGH;
+
+ case CONFIG_COMPLETE:
+ if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
+
+ // Prepare for incoming data
+ cdch_interface_t* p_cdc = get_itf(idx);
+ tu_edpt_stream_read_xfer(&p_cdc->stream.rx);
+
+ // notify usbh that driver enumeration is complete
+ // itf_num+1 to account for data interface as well
+ usbh_driver_set_config_complete(xfer->daddr, itf_num+1);
+ break;
+
+ default: break;
+ }
}
-void cdch_close(uint8_t dev_addr)
+bool cdch_set_config(uint8_t daddr, uint8_t itf_num)
{
- TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
+ // fake transfer to kick-off process
+ tusb_control_request_t request;
+ request.wIndex = tu_htole16((uint16_t) itf_num);
+
+ tuh_xfer_t xfer;
+ xfer.daddr = daddr;
+ xfer.result = XFER_RESULT_SUCCESS;
+ xfer.setup = &request;
+ xfer.user_data = CONFIG_SET_CONTROL_LINE_STATE;
- cdch_data_t * p_cdc = get_itf(dev_addr);
- tu_memclr(p_cdc, sizeof(cdch_data_t));
+ process_cdc_config(&xfer);
+
+ return true;
}
#endif
diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h
index 33dbd2efb..c759527e6 100644
--- a/src/class/cdc/cdc_host.h
+++ b/src/class/cdc/cdc_host.h
@@ -34,89 +34,156 @@
#endif
//--------------------------------------------------------------------+
-// CDC APPLICATION PUBLIC API
+// Class Driver Configuration
//--------------------------------------------------------------------+
-/** \ingroup ClassDriver_CDC Communication Device Class (CDC)
- * \addtogroup CDC_Serial Serial
- * @{
- * \defgroup CDC_Serial_Host Host
- * @{ */
-bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb);
+// Set Line Control state on enumeration/mounted: DTR ( bit 0), RTS (bit 1)
+#ifndef CFG_TUH_CDC_LINE_CONTROL_ON_ENUM
+#define CFG_TUH_CDC_LINE_CONTROL_ON_ENUM 0
+#endif
+
+// Set Line Coding on enumeration/mounted, value for cdc_line_coding_t
+//#ifndef CFG_TUH_CDC_LINE_CODING_ON_ENUM
+//#define CFG_TUH_CDC_LINE_CODING_ON_ENUM { 115200, CDC_LINE_CONDING_STOP_BITS_1, CDC_LINE_CODING_PARITY_NONE, 8 }
+//#endif
+
+// RX FIFO size
+#ifndef CFG_TUH_CDC_RX_BUFSIZE
+#define CFG_TUH_CDC_RX_BUFSIZE USBH_EPSIZE_BULK_MAX
+#endif
+
+// RX Endpoint size
+#ifndef CFG_TUH_CDC_RX_EPSIZE
+#define CFG_TUH_CDC_RX_EPSIZE USBH_EPSIZE_BULK_MAX
+#endif
+
+// TX FIFO size
+#ifndef CFG_TUH_CDC_TX_BUFSIZE
+#define CFG_TUH_CDC_TX_BUFSIZE USBH_EPSIZE_BULK_MAX
+#endif
+
+// TX Endpoint size
+#ifndef CFG_TUH_CDC_TX_EPSIZE
+#define CFG_TUH_CDC_TX_EPSIZE USBH_EPSIZE_BULK_MAX
+#endif
+
+//--------------------------------------------------------------------+
+// Application API
+//--------------------------------------------------------------------+
-static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
+typedef struct
{
- return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb);
-}
+ uint8_t daddr;
+ uint8_t bInterfaceNumber;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+} tuh_cdc_itf_info_t;
+
+// Get Interface index from device address + interface number
+// return TUSB_INDEX_INVALID (0xFF) if not found
+uint8_t tuh_cdc_itf_get_index(uint8_t daddr, uint8_t itf_num);
+
+// Get Interface information
+// return true if index is correct and interface is currently mounted
+bool tuh_cdc_itf_get_info(uint8_t idx, tuh_cdc_itf_info_t* info);
+
+// Check if a interface is mounted
+bool tuh_cdc_mounted(uint8_t idx);
+
+// Get current DTR status
+bool tuh_cdc_get_dtr(uint8_t idx);
+
+// Get current RTS status
+bool tuh_cdc_get_rts(uint8_t idx);
-static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
+// Check if interface is connected (DTR active)
+TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx)
{
- return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb);
+ return tuh_cdc_get_dtr(idx);
}
-/** \brief Check if device support CDC Serial interface or not
- * \param[in] dev_addr device address
- * \retval true if device supports
- * \retval false if device does not support or is not mounted
- */
-bool tuh_cdc_serial_is_mounted(uint8_t dev_addr);
+// Get local (saved/cached) version of line coding.
+// This function should return correct values if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding()
+// are invoked previously or CFG_TUH_CDC_LINE_CODING_ON_ENUM is defined.
+// NOTE: This function does not make any USB transfer request to device.
+bool tuh_cdc_get_local_line_coding(uint8_t idx, cdc_line_coding_t* line_coding);
-/** \brief Check if the interface is currently busy or not
- * \param[in] dev_addr device address
- * \param[in] pipeid value from \ref cdc_pipeid_t to indicate target pipe.
- * \retval true if the interface is busy, meaning the stack is still transferring/waiting data from/to device
- * \retval false if the interface is not busy, meaning the stack successfully transferred data from/to device
- * \note This function is used to check if previous transfer is complete (success or error), so that the next transfer
- * can be scheduled. User needs to make sure the corresponding interface is mounted
- * (by \ref tuh_cdc_serial_is_mounted) before calling this function.
- */
-bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid);
+//--------------------------------------------------------------------+
+// Write API
+//--------------------------------------------------------------------+
-/** \brief Perform USB OUT transfer to device
- * \param[in] dev_addr device address
- * \param[in] p_data Buffer containing data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
- * \param[in] length Number of bytes to be transferred via USB bus
- * \retval TUSB_ERROR_NONE on success
- * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device
- * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request)
- * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct
- * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the
- * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION.
- */
-bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool is_notify);
+// Get the number of bytes available for writing
+uint32_t tuh_cdc_write_available(uint8_t idx);
-/** \brief Perform USB IN transfer to get data from device
- * \param[in] dev_addr device address
- * \param[in] p_buffer Buffer containing received data. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION)
- * \param[in] length Number of bytes to be transferred via USB bus
- * \retval TUSB_ERROR_NONE on success
- * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device
- * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request)
- * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct
- * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the
- * interface's callback function. \a p_data must be declared with \ref CFG_TUSB_MEM_SECTION.
- */
-bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is_notify);
+// Write to cdc interface
+uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize);
+
+// Force sending data if possible, return number of forced bytes
+uint32_t tuh_cdc_write_flush(uint8_t idx);
+
+// Clear the transmit FIFO
+bool tuh_cdc_write_clear(uint8_t idx);
+
+//--------------------------------------------------------------------+
+// Read API
+//--------------------------------------------------------------------+
+
+// Get the number of bytes available for reading
+uint32_t tuh_cdc_read_available(uint8_t idx);
+
+// Read from cdc interface
+uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize);
+
+// Get a byte from RX FIFO without removing it
+bool tuh_cdc_peek(uint8_t idx, uint8_t* ch);
+
+// Clear the received FIFO
+bool tuh_cdc_read_clear (uint8_t idx);
+
+//--------------------------------------------------------------------+
+// Control Endpoint (Request) API
+// Each Function will make a USB transfer request to/from device
+//--------------------------------------------------------------------+
+
+// Request to Set Control Line State: DTR (bit 0), RTS (bit 1)
+bool tuh_cdc_set_control_line_state(uint8_t idx, uint16_t line_state, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Request to Set Line Coding
+bool tuh_cdc_set_line_coding(uint8_t idx, cdc_line_coding_t const* line_coding, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
+
+// Request to Get Line Coding
+// Should only use if tuh_cdc_set_line_coding() / tuh_cdc_get_line_coding() never got invoked and
+// CFG_TUH_CDC_LINE_CODING_ON_ENUM is not defined
+// bool tuh_cdc_get_line_coding(uint8_t idx, cdc_line_coding_t* coding);
+
+// Connect by set both DTR, RTS
+static inline bool tuh_cdc_connect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return tuh_cdc_set_control_line_state(idx, CDC_CONTROL_LINE_STATE_DTR | CDC_CONTROL_LINE_STATE_RTS, complete_cb, user_data);
+}
+
+// Disconnect by clear both DTR, RTS
+static inline bool tuh_cdc_disconnect(uint8_t idx, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
+{
+ return tuh_cdc_set_control_line_state(idx, 0x00, complete_cb, user_data);
+}
//--------------------------------------------------------------------+
// CDC APPLICATION CALLBACKS
//--------------------------------------------------------------------+
-/** \brief Callback function that is invoked when an transferring event occurred
- * \param[in] dev_addr Address of device
- * \param[in] event an value from \ref xfer_result_t
- * \param[in] pipe_id value from \ref cdc_pipeid_t indicate the pipe
- * \param[in] xferred_bytes Number of bytes transferred via USB bus
- * \note event can be one of following
- * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully.
- * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error.
- * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device.
- * \note
- */
-void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes);
+// Invoked when a device with CDC interface is mounted
+// idx is index of cdc interface in the internal pool.
+TU_ATTR_WEAK extern void tuh_cdc_mount_cb(uint8_t idx);
+
+// Invoked when a device with CDC interface is unmounted
+TU_ATTR_WEAK extern void tuh_cdc_umount_cb(uint8_t idx);
+
+// Invoked when received new data
+TU_ATTR_WEAK extern void tuh_cdc_rx_cb(uint8_t idx);
-/// @} // group CDC_Serial_Host
-/// @}
+// Invoked when a TX is complete and therefore space becomes available in TX buffer
+TU_ATTR_WEAK extern void tuh_cdc_tx_complete_cb(uint8_t idx);
//--------------------------------------------------------------------+
// Internal Class Driver API
diff --git a/src/class/cdc/cdc_rndis_host.c b/src/class/cdc/cdc_rndis_host.c
index 8f28f51ac..44de85b45 100644
--- a/src/class/cdc/cdc_rndis_host.c
+++ b/src/class/cdc/cdc_rndis_host.c
@@ -117,7 +117,7 @@ void rndish_init(void)
//------------- Task creation -------------//
- //------------- semaphore creation for notificaiton pipe -------------//
+ //------------- semaphore creation for notification pipe -------------//
for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
{
rndish_data[i].sem_notification_hdl = osal_semaphore_create( OSAL_SEM_REF(rndish_data[i].semaphore_notification) );
diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h
index 44a464be1..d9b0ead10 100644
--- a/src/class/hid/hid.h
+++ b/src/class/hid/hid.h
@@ -708,6 +708,7 @@ enum {
HID_USAGE_PAGE_MSR = 0x8e,
HID_USAGE_PAGE_CAMERA = 0x90,
HID_USAGE_PAGE_ARCADE = 0x91,
+ HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page
HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF
};
@@ -844,6 +845,14 @@ enum
HID_USAGE_CONSUMER_AC_PAN = 0x0238,
};
+/// HID Usage Table: FIDO Alliance Page (0xF1D0)
+enum
+{
+ HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection
+ HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report
+ HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report
+};
+
/*--------------------------------------------------------------------
* ASCII to KEYCODE Conversion
* Expand to array of [128][2] (shift, keycode)
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
index 3143b1024..eeef6d3ba 100644
--- a/src/class/hid/hid_device.h
+++ b/src/class/hid/hid_device.h
@@ -182,7 +182,7 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
/* Report ID if any */\
__VA_ARGS__ \
- /* 8 bits Modifier Keys (Shfit, Control, Alt) */ \
+ /* 8 bits Modifier Keys (Shift, Control, Alt) */ \
HID_USAGE_PAGE ( HID_USAGE_PAGE_KEYBOARD ) ,\
HID_USAGE_MIN ( 224 ) ,\
HID_USAGE_MAX ( 231 ) ,\
@@ -352,6 +352,31 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
HID_COLLECTION_END \
+// FIDO U2F Authenticator Descriptor Template
+// - 1st parameter is report size, which is 64 bytes maximum in U2F
+// - 2nd parameter is HID_REPORT_ID(n) (optional)
+#define TUD_HID_REPORT_DESC_FIDO_U2F(report_size, ...) \
+ HID_USAGE_PAGE_N ( HID_USAGE_PAGE_FIDO, 2 ) ,\
+ HID_USAGE ( HID_USAGE_FIDO_U2FHID ) ,\
+ HID_COLLECTION ( HID_COLLECTION_APPLICATION ) ,\
+ /* Report ID if any */ \
+ __VA_ARGS__ \
+ /* Usage Data In */ \
+ HID_USAGE ( HID_USAGE_FIDO_DATA_IN ) ,\
+ HID_LOGICAL_MIN ( 0 ) ,\
+ HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\
+ HID_REPORT_SIZE ( 8 ) ,\
+ HID_REPORT_COUNT ( report_size ) ,\
+ HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+ /* Usage Data Out */ \
+ HID_USAGE ( HID_USAGE_FIDO_DATA_OUT ) ,\
+ HID_LOGICAL_MIN ( 0 ) ,\
+ HID_LOGICAL_MAX_N ( 0xff, 2 ) ,\
+ HID_REPORT_SIZE ( 8 ) ,\
+ HID_REPORT_COUNT ( report_size ) ,\
+ HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
+ HID_COLLECTION_END \
+
// HID Generic Input & Output
// - 1st parameter is report size (mandatory)
// - 2nd parameter is report id HID_REPORT_ID(n) (optional)
diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index ca745464c..42b5e2f4e 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -62,6 +62,7 @@ typedef struct
hidh_interface_t instances[CFG_TUH_HID];
} hidh_device_t;
+CFG_TUSB_MEM_SECTION
static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX];
//------------- Internal prototypes -------------//
@@ -258,7 +259,7 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) )
{
- usbh_edpt_claim(dev_addr, hid_itf->ep_in);
+ usbh_edpt_release(dev_addr, hid_itf->ep_in);
return false;
}
diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h
index fe09b03b2..ffc601d77 100644
--- a/src/class/hid/hid_host.h
+++ b/src/class/hid/hid_host.h
@@ -89,7 +89,7 @@ uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance);
bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol);
// Set Report using control endpoint
-// report_type is either Intput, Output or Feature, (value from hid_report_type_t)
+// report_type is either Input, Output or Feature, (value from hid_report_type_t)
bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len);
//--------------------------------------------------------------------+
diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c
index 9e88ebc30..6724e486c 100644
--- a/src/class/msc/msc_host.c
+++ b/src/class/msc/msc_host.c
@@ -33,6 +33,11 @@
#include "msc_host.h"
+// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
+#define MSCH_DEBUG 2
+
+#define TU_LOG_MSCH(...) TU_LOG(MSCH_DEBUG, __VA_ARGS__)
+
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
@@ -200,7 +205,7 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_
return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg);
}
-bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
+bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
{
msc_cbw_t cbw;
cbw_init(&cbw, lun);
@@ -217,7 +222,7 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms
memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len);
- return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb, arg);
+ return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
}
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
@@ -417,7 +422,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
p_msc->configured = true;
//------------- Get Max Lun -------------//
- TU_LOG2("MSC Get Max Lun\r\n");
+ TU_LOG_MSCH("MSC Get Max Lun\r\n");
tusb_control_request_t const request =
{
.bmRequestType_bit =
@@ -456,7 +461,7 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer)
p_msc->max_lun++; // MAX LUN is minus 1 by specs
// TODO multiple LUN support
- TU_LOG2("SCSI Test Unit Ready\r\n");
+ TU_LOG_MSCH("SCSI Test Unit Ready\r\n");
uint8_t const lun = 0;
tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0);
}
@@ -469,14 +474,14 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d
if (csw->status == 0)
{
// Unit is ready, read its capacity
- TU_LOG2("SCSI Read Capacity\r\n");
+ TU_LOG_MSCH("SCSI Read Capacity\r\n");
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0);
}else
{
// Note: During enumeration, some device fails Test Unit Ready and require a few retries
// with Request Sense to start working !!
// TODO limit number of retries
- TU_LOG2("SCSI Request Sense\r\n");
+ TU_LOG_MSCH("SCSI Request Sense\r\n");
TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0));
}
diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h
index 416e4318b..5134b63c2 100644
--- a/src/class/msc/msc_host.h
+++ b/src/class/msc/msc_host.h
@@ -85,7 +85,7 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_
// Perform SCSI Request Sense 10 command
// Complete callback is invoked when SCSI op is complete.
-bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
+bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
// Perform SCSI Read 10 command. Read n blocks starting from LBA to buffer
// Complete callback is invoked when SCSI op is complete.
diff --git a/src/class/net/ecm_rndis_device.c b/src/class/net/ecm_rndis_device.c
index 5f316762f..c7428bcda 100644
--- a/src/class/net/ecm_rndis_device.c
+++ b/src/class/net/ecm_rndis_device.c
@@ -51,7 +51,7 @@ typedef struct
bool ecm_mode;
- // Endpoint descriptor use to open/close when receving SetInterface
+ // Endpoint descriptor use to open/close when receiving SetInterface
// TODO since configuration descriptor may not be long-lived memory, we should
// keep a copy of endpoint attribute instead
uint8_t const * ecm_desc_epdata;
diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c
index 00892b49c..1cbc0ce01 100644
--- a/src/class/net/ncm_device.c
+++ b/src/class/net/ncm_device.c
@@ -392,7 +392,7 @@ bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
if (NCM_GET_NTB_PARAMETERS == request->bRequest)
{
- tud_control_xfer(rhport, request, (void*)&ntb_parameters, sizeof(ntb_parameters));
+ tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters));
}
break;
diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h
index e7016ae24..fd52d766e 100644
--- a/src/class/usbtmc/usbtmc.h
+++ b/src/class/usbtmc/usbtmc.h
@@ -158,7 +158,7 @@ enum {
USBTMC_BULK_IN_ERR_DATA_TOO_SHORT = 4u,
USBTMC_BULK_IN_ERR_DATA_TOO_LONG = 5u,
};
-// bult-in halt errors
+// built-in halt errors
enum {
USBTMC_BULK_IN_ERR = 1u, ///< receives a USBTMC command message that expects a response while a
/// Bulk-IN transfer is in progress
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
index af4a92732..0cf0743a7 100644
--- a/src/class/usbtmc/usbtmc_device.c
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -157,12 +157,14 @@ static bool handle_devMsgOut(uint8_t rhport, void *data, size_t len, size_t pack
static uint8_t termChar;
static uint8_t termCharRequested = false;
-osal_mutex_def_t usbtmcLockBuffer;
-static osal_mutex_t usbtmcLock;
+#if OSAL_MUTEX_REQUIRED
+static OSAL_MUTEX_DEF(usbtmcLockBuffer);
+#endif
+osal_mutex_t usbtmcLock;
// Our own private lock, mostly for the state variable.
-#define criticalEnter() do {osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0)
-#define criticalLeave() do {osal_mutex_unlock(usbtmcLock); } while (0)
+#define criticalEnter() do { (void) osal_mutex_lock(usbtmcLock,OSAL_TIMEOUT_WAIT_FOREVER); } while (0)
+#define criticalLeave() do { (void) osal_mutex_unlock(usbtmcLock); } while (0)
bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState)
{
@@ -362,9 +364,9 @@ bool tud_usbtmc_start_bus_read()
case STATE_RCV:
break;
default:
- TU_VERIFY(false);
+ return false;
}
- TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, 64));
+ TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_state.ep_bulk_out_buf, (uint16_t)usbtmc_state.ep_bulk_out_wMaxPacketSize));
return true;
}
@@ -464,53 +466,52 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
switch(usbtmc_state.state)
{
case STATE_IDLE:
- TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t));
- msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf);
- uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse);
- TU_VERIFY(msg->header.bTag == invInvTag);
- TU_VERIFY(msg->header.bTag != 0x00);
+ {
+ TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t));
+ msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf);
+ uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse);
+ TU_VERIFY(msg->header.bTag == invInvTag);
+ TU_VERIFY(msg->header.bTag != 0x00);
- switch(msg->header.MsgID) {
- case USBTMC_MSGID_DEV_DEP_MSG_OUT:
- if(!handle_devMsgOutStart(rhport, msg, xferred_bytes))
- {
- usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
- TU_VERIFY(false);
- }
- break;
+ switch(msg->header.MsgID) {
+ case USBTMC_MSGID_DEV_DEP_MSG_OUT:
+ if(!handle_devMsgOutStart(rhport, msg, xferred_bytes))
+ {
+ usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+ return false;
+ }
+ break;
- case USBTMC_MSGID_DEV_DEP_MSG_IN:
- TU_VERIFY(handle_devMsgIn(msg, xferred_bytes));
- break;
+ case USBTMC_MSGID_DEV_DEP_MSG_IN:
+ TU_VERIFY(handle_devMsgIn(msg, xferred_bytes));
+ break;
#if (CFG_TUD_USBTMC_ENABLE_488)
- case USBTMC_MSGID_USB488_TRIGGER:
- // Spec says we halt the EP if we didn't declare we support it.
- TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger);
- TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg));
+ case USBTMC_MSGID_USB488_TRIGGER:
+ // Spec says we halt the EP if we didn't declare we support it.
+ TU_VERIFY(usbtmc_state.capabilities->bmIntfcCapabilities488.supportsTrigger);
+ TU_VERIFY(tud_usbtmc_msg_trigger_cb(msg));
- break;
+ break;
#endif
- case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT:
- case USBTMC_MSGID_VENDOR_SPECIFIC_IN:
- default:
- usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
- TU_VERIFY(false);
- return false;
+ case USBTMC_MSGID_VENDOR_SPECIFIC_MSG_OUT:
+ case USBTMC_MSGID_VENDOR_SPECIFIC_IN:
+ default:
+ usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
+ return false;
+ }
+ return true;
}
- return true;
-
case STATE_RCV:
if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes))
{
usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
- TU_VERIFY(false);
+ return false;
}
return true;
case STATE_ABORTING_BULK_OUT:
- TU_VERIFY(false);
- return false; // Should be stalled by now, shouldn't have received a packet.
+ return false;
case STATE_TX_REQUESTED:
case STATE_TX_INITIATED:
@@ -518,7 +519,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
case STATE_ABORTING_BULK_IN_SHORTED:
case STATE_ABORTING_BULK_IN_ABORTED:
default:
- TU_VERIFY(false);
+ return false;
}
}
else if(ep_addr == usbtmc_state.ep_bulk_in)
@@ -567,7 +568,6 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
default:
TU_ASSERT(false);
- return false;
}
}
else if (ep_addr == usbtmc_state.ep_int_in) {
@@ -599,7 +599,7 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
// At this point, a transfer MAY be in progress. Based on USB spec, when clearing bulk EP HALT,
// the EP transfer buffer needs to be cleared and DTOG needs to be reset, even if
- // the EP is not halted. The only USBD API interface to do this is to stall and then unstall the EP.
+ // the EP is not halted. The only USBD API interface to do this is to stall and then un-stall the EP.
if(ep_addr == usbtmc_state.ep_bulk_out)
{
criticalEnter();
@@ -871,16 +871,13 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
case USB488_bREQUEST_LOCAL_LOCKOUT:
{
TU_VERIFY(request->bmRequestType == 0xA1); // in,class,interface
- TU_VERIFY(false);
return false;
}
#endif
default:
- TU_VERIFY(false);
return false;
}
- TU_VERIFY(false);
}
#endif /* CFG_TUD_TSMC */
diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h
index 144b3315d..c1298ddb8 100644
--- a/src/class/usbtmc/usbtmc_device.h
+++ b/src/class/usbtmc/usbtmc_device.h
@@ -36,7 +36,7 @@
#endif
/***********************************************
- * Functions to be implemeted by the class implementation
+ * Functions to be implemented by the class implementation
*/
// In order to proceed, app must call call tud_usbtmc_start_bus_read(rhport) during or soon after:
diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c
index a6d2724c1..e17d0a90f 100644
--- a/src/class/video/video_device.c
+++ b/src/class/video/video_device.c
@@ -917,7 +917,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
switch (request->bRequest) {
case VIDEO_REQUEST_SET_CUR:
if (stage == CONTROL_STAGE_SETUP) {
- TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)),
VIDEO_ERROR_UNKNOWN);
} else if (stage == CONTROL_STAGE_DATA) {
@@ -973,7 +973,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
switch (request->bRequest) {
case VIDEO_REQUEST_SET_CUR:
if (stage == CONTROL_STAGE_SETUP) {
- TU_VERIFY(sizeof(video_probe_and_commit_control_t) == request->wLength, VIDEO_ERROR_UNKNOWN);
+ TU_VERIFY(sizeof(video_probe_and_commit_control_t) >= request->wLength, VIDEO_ERROR_UNKNOWN);
TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
} else if (stage == CONTROL_STAGE_DATA) {
TU_VERIFY(_update_streaming_parameters(self, (video_probe_and_commit_control_t*)self->ep_buf), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);