Merge pull request #498 from adafruit/update-tinyusb-1cfc88dbcb8cff6f926aef02c5609880169ec94c
Update tinyusb to commit 334ac8072650e3b18278042c2c2b402db73c7359
This commit is contained in:
commit
8ef30202e5
78 changed files with 6252 additions and 3955 deletions
|
|
@ -38,7 +38,9 @@ Following core has TinyUSB as either the primary usb stack or selectable via men
|
|||
- [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino)
|
||||
- [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd)
|
||||
- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico)
|
||||
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
|
||||
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) additional Tools menu is needed
|
||||
- `USB Mode=USB-OTG (TinyUSB)` for S3 and P4
|
||||
- `USB CDC On Boot=Enabled`, `USB Firmware MSC On Boot=Disabled`, `USB DFU On Boot=Disabled`
|
||||
- [openwch/arduino_core_ch32](https://github.com/openwch/arduino_core_ch32)
|
||||
|
||||
Note: For ESP32 port, version before v3.0 requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards. This limitation is not the case for version from v3.0.
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
#endif
|
||||
|
||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// USBHost is defined in usbh_helper.h
|
||||
#include "usbh_helper.h"
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
*/
|
||||
|
||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
// USBHost is defined in usbh_helper.h
|
||||
#include "usbh_helper.h"
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*********************************************************************/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "Adafruit_InternalFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
const int chipSelect = 10;
|
||||
|
|
|
|||
|
|
@ -25,11 +25,6 @@
|
|||
#ifndef ADAFRUIT_TINYUSB_H_
|
||||
#define ADAFRUIT_TINYUSB_H_
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
// Device
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
extern "C" {
|
||||
|
||||
uint32_t tusb_time_millis_api(void) { return millis(); }
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
#include "Adafruit_USBH_MSC.h"
|
||||
#include "tusb.h"
|
||||
|
||||
#if __has_include("SdFat.h")
|
||||
#if __has_include("SdFat_Adafruit_Fork.h")
|
||||
|
||||
Adafruit_USBH_MSC_BlockDevice::Adafruit_USBH_MSC_BlockDevice() {
|
||||
_daddr = _lun = 0;
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@
|
|||
#include "tusb.h"
|
||||
|
||||
// define SdFat host helper class if SdFat library is available
|
||||
#if __has_include("SdFat.h")
|
||||
#if __has_include("SdFat_Adafruit_Fork.h")
|
||||
|
||||
#include "SdFat.h"
|
||||
#include "SdFat_Adafruit_Fork.h"
|
||||
|
||||
class Adafruit_USBH_MSC_BlockDevice : public FsBlockDeviceInterface {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -38,17 +38,42 @@ extern "C" {
|
|||
// libraries, this file is used to make it compatible with ESP32 Arduino core.
|
||||
|
||||
// This file also contains additional configuration for EPS32 in addition to
|
||||
// tools/sdk/esp32xx/include/arduino_tinyusb/include/tusb_config.h
|
||||
// tools/esp32-arduino-libs/esp32xx/include/arduino_tinyusb/include/tusb_config.h
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// ESP32 out-of-sync
|
||||
//--------------------------------------------------------------------+
|
||||
#include "esp_arduino_version.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(2, 0, 8)
|
||||
#error "ESP32 Arduino core version 2.0.8 or later is required"
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
// Note: it is possible to use tinyusb + max3421e as host controller
|
||||
// with no OTG USB MCU such as eps32, c3 etc...
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#define CFG_TUSB_MCU OPT_MCU_ESP32S2
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define CFG_TUSB_MCU OPT_MCU_ESP32S3
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#define CFG_TUSB_MCU OPT_MCU_ESP32P4
|
||||
#else
|
||||
#define CFG_TUSB_MCU OPT_MCU_ESP32
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
#define CFG_TUD_MAX_SPEED OPT_MODE_HIGH_SPEED
|
||||
#define CFG_TUH_MAX_SPEED OPT_MODE_HIGH_SPEED
|
||||
#else
|
||||
#define CFG_TUD_MAX_SPEED OPT_MODE_FULL_SPEED
|
||||
#define CFG_TUH_MAX_SPEED OPT_MODE_FULL_SPEED
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_FREERTOS
|
||||
// clang-format off
|
||||
|
|
@ -64,12 +89,6 @@ extern "C" {
|
|||
#define CFG_TUH_LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
// Note: it is possible to use tinyusb + max3421e as host controller
|
||||
// with no OTG USB MCU such as eps32, c3 etc...
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef CFG_TUSB_DEBUG
|
||||
#define CFG_TUSB_DEBUG 0
|
||||
#endif
|
||||
|
|
@ -77,12 +96,43 @@ extern "C" {
|
|||
// For selectively disable device log (when > CFG_TUSB_DEBUG)
|
||||
// #define CFG_TUD_LOG_LEVEL 3
|
||||
|
||||
#define CFG_TUSB_MEM_SECTION
|
||||
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DEVICE CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
#define CFG_TUD_ENABLED 1
|
||||
|
||||
// device configuration is configured in BSP
|
||||
// sdk/include/arduino_tinyusb/include/tusb_config.h
|
||||
#define CFG_TUD_CDC 2
|
||||
#define CFG_TUD_MSC 1
|
||||
#define CFG_TUD_HID 2
|
||||
#define CFG_TUD_MIDI 1
|
||||
#define CFG_TUD_VENDOR 1
|
||||
#define CFG_TUD_VIDEO 1
|
||||
#define CFG_TUD_VIDEO_STREAMING 1
|
||||
|
||||
// video streaming endpoint buffer size
|
||||
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE \
|
||||
CONFIG_TINYUSB_VIDEO_STREAMING_BUFSIZE
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE CONFIG_TINYUSB_CDC_RX_BUFSIZE
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE CONFIG_TINYUSB_CDC_TX_BUFSIZE
|
||||
|
||||
// MSC Buffer size of Device Mass storage
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE CONFIG_TINYUSB_MSC_BUFSIZE
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_BUFSIZE CONFIG_TINYUSB_HID_BUFSIZE
|
||||
|
||||
// MIDI FIFO size of TX and RX
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE CONFIG_TINYUSB_MIDI_RX_BUFSIZE
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE CONFIG_TINYUSB_MIDI_TX_BUFSIZE
|
||||
|
||||
// Vendor FIFO size of TX and RX
|
||||
#define CFG_TUD_VENDOR_RX_BUFSIZE CONFIG_TINYUSB_VENDOR_RX_BUFSIZE
|
||||
#define CFG_TUD_VENDOR_TX_BUFSIZE CONFIG_TINYUSB_VENDOR_TX_BUFSIZE
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Host Configuration
|
||||
|
|
@ -90,7 +140,6 @@ extern "C" {
|
|||
|
||||
// Enable host stack with MAX3421E (host shield)
|
||||
#define CFG_TUH_ENABLED 1
|
||||
#define CFG_TUH_MAX_SPEED OPT_MODE_FULL_SPEED
|
||||
#define CFG_TUH_MAX3421 1
|
||||
|
||||
#ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ extern "C" {
|
|||
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||
|
||||
// MIDI FIFO size of TX and RX
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE 128
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE 128
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE 64
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE 64
|
||||
|
||||
// Vendor FIFO size of TX and RX
|
||||
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -203,6 +203,9 @@
|
|||
#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1
|
||||
#endif
|
||||
|
||||
// Audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74)
|
||||
#define CFG_TUD_AUDIO_INTERRUPT_EP_SZ 6
|
||||
|
||||
// Use software encoding/decoding
|
||||
|
||||
// The software coding feature of the driver is not mandatory. It is useful if, for instance, you have two I2S streams which need to be interleaved
|
||||
|
|
|
|||
|
|
@ -31,20 +31,13 @@
|
|||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "bth_device.h"
|
||||
#include <device/usbd_pvt.h>
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_ev;
|
||||
uint8_t ep_acl_in;
|
||||
|
|
@ -55,17 +48,18 @@ typedef struct
|
|||
|
||||
// Previous amount of bytes sent when issuing ZLP
|
||||
uint32_t prev_xferred_bytes;
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUSB_MEM_ALIGN bt_hci_cmd_t hci_cmd;
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_BTH_DATA_EPSIZE];
|
||||
|
||||
} btd_interface_t;
|
||||
|
||||
typedef struct {
|
||||
TUD_EPBUF_DEF(epout_buf, CFG_TUD_BTH_DATA_EPSIZE);
|
||||
TUD_EPBUF_TYPE_DEF(bt_hci_cmd_t, hci_cmd);
|
||||
} btd_epbuf_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUD_MEM_SECTION btd_interface_t _btd_itf;
|
||||
static btd_interface_t _btd_itf;
|
||||
CFG_TUD_MEM_SECTION static btd_epbuf_t _btd_epbuf;
|
||||
|
||||
static bool bt_tx_data(uint8_t ep, void *data, uint16_t len)
|
||||
{
|
||||
|
|
@ -158,7 +152,7 @@ uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_
|
|||
itf_desc = (tusb_desc_interface_t const *)tu_desc_next(tu_desc_next(desc_ep));
|
||||
|
||||
// Prepare for incoming data from host
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0);
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_epbuf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE), 0);
|
||||
|
||||
drv_len = hci_itf_size;
|
||||
|
||||
|
|
@ -249,14 +243,16 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c
|
|||
}
|
||||
else return false;
|
||||
|
||||
return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd));
|
||||
return tud_control_xfer(rhport, request, &_btd_epbuf.hci_cmd, sizeof(bt_hci_cmd_t));
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_DATA )
|
||||
{
|
||||
// Handle class request only
|
||||
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd)));
|
||||
if (tud_bt_hci_cmd_cb) {
|
||||
tud_bt_hci_cmd_cb(&_btd_epbuf.hci_cmd, tu_min16(request->wLength, sizeof(bt_hci_cmd_t)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -267,10 +263,10 @@ bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
|
|||
// received new data from host
|
||||
if (ep_addr == _btd_itf.ep_acl_out)
|
||||
{
|
||||
if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_itf.epout_buf, xferred_bytes);
|
||||
if (tud_bt_acl_data_received_cb) tud_bt_acl_data_received_cb(_btd_epbuf.epout_buf, xferred_bytes);
|
||||
|
||||
// prepare for next data
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_itf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE));
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, _btd_itf.ep_acl_out, _btd_epbuf.epout_buf, CFG_TUD_BTH_DATA_EPSIZE));
|
||||
}
|
||||
else if (ep_addr == _btd_itf.ep_ev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_CDC)
|
||||
|
|
@ -72,22 +67,27 @@ typedef struct {
|
|||
|
||||
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];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE];
|
||||
} cdcd_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)
|
||||
|
||||
typedef struct {
|
||||
TUD_EPBUF_DEF(epout, CFG_TUD_CDC_EP_BUFSIZE);
|
||||
TUD_EPBUF_DEF(epin, CFG_TUD_CDC_EP_BUFSIZE);
|
||||
} cdcd_epbuf_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUD_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
|
||||
static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
|
||||
CFG_TUD_MEM_SECTION static cdcd_epbuf_t _cdcd_epbuf[CFG_TUD_CDC];
|
||||
|
||||
static tud_cdc_configure_fifo_t _cdcd_fifo_cfg;
|
||||
|
||||
static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
|
||||
uint8_t const rhport = 0;
|
||||
static bool _prep_out_transaction(uint8_t itf) {
|
||||
const uint8_t rhport = 0;
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
|
||||
|
||||
// Skip if usb is not ready yet
|
||||
TU_VERIFY(tud_ready() && p_cdc->ep_out);
|
||||
|
|
@ -98,7 +98,7 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
|
|||
// TODO Actually we can still carry out the transfer, keeping count of received bytes
|
||||
// and slowly move it to the FIFO when read().
|
||||
// This pre-check reduces endpoint claiming
|
||||
TU_VERIFY(available >= sizeof(p_cdc->epout_buf));
|
||||
TU_VERIFY(available >= CFG_TUD_CDC_EP_BUFSIZE);
|
||||
|
||||
// claim endpoint
|
||||
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_out));
|
||||
|
|
@ -106,9 +106,9 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
|
|||
// fifo can be changed before endpoint is claimed
|
||||
available = tu_fifo_remaining(&p_cdc->rx_ff);
|
||||
|
||||
if ( available >= sizeof(p_cdc->epout_buf) ) {
|
||||
return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, sizeof(p_cdc->epout_buf));
|
||||
}else {
|
||||
if (available >= CFG_TUD_CDC_EP_BUFSIZE) {
|
||||
return usbd_edpt_xfer(rhport, p_cdc->ep_out, p_epbuf->epout, CFG_TUD_CDC_EP_BUFSIZE);
|
||||
} else {
|
||||
// Release endpoint since we don't make any transfer
|
||||
usbd_edpt_release(rhport, p_cdc->ep_out);
|
||||
return false;
|
||||
|
|
@ -119,7 +119,7 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) {
|
|||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tud_cdc_configure_fifo(tud_cdc_configure_fifo_t const* cfg) {
|
||||
bool tud_cdc_configure_fifo(const tud_cdc_configure_fifo_t* cfg) {
|
||||
TU_VERIFY(cfg);
|
||||
_cdcd_fifo_cfg = (*cfg);
|
||||
return true;
|
||||
|
|
@ -156,7 +156,7 @@ uint32_t tud_cdc_n_available(uint8_t itf) {
|
|||
uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) {
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
uint32_t num_read = tu_fifo_read_n(&p_cdc->rx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
|
||||
_prep_out_transaction(p_cdc);
|
||||
_prep_out_transaction(itf);
|
||||
return num_read;
|
||||
}
|
||||
|
||||
|
|
@ -167,13 +167,13 @@ bool tud_cdc_n_peek(uint8_t itf, uint8_t* chr) {
|
|||
void tud_cdc_n_read_flush(uint8_t itf) {
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
tu_fifo_clear(&p_cdc->rx_ff);
|
||||
_prep_out_transaction(p_cdc);
|
||||
_prep_out_transaction(itf);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) {
|
||||
uint32_t tud_cdc_n_write(uint8_t itf, const void* buffer, uint32_t bufsize) {
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
uint16_t ret = tu_fifo_write_n(&p_cdc->tx_ff, buffer, (uint16_t) TU_MIN(bufsize, UINT16_MAX));
|
||||
|
||||
|
|
@ -191,23 +191,26 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize) {
|
|||
|
||||
uint32_t tud_cdc_n_write_flush(uint8_t itf) {
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
|
||||
|
||||
// Skip if usb is not ready yet
|
||||
TU_VERIFY(tud_ready(), 0);
|
||||
|
||||
// No data to send
|
||||
if (!tu_fifo_count(&p_cdc->tx_ff)) return 0;
|
||||
if (!tu_fifo_count(&p_cdc->tx_ff)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t const rhport = 0;
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
// Claim the endpoint
|
||||
TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_in), 0);
|
||||
|
||||
// Pull data from FIFO
|
||||
uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf));
|
||||
const uint16_t count = tu_fifo_read_n(&p_cdc->tx_ff, p_epbuf->epin, CFG_TUD_CDC_EP_BUFSIZE);
|
||||
|
||||
if (count) {
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0);
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, p_cdc->ep_in, p_epbuf->epin, count), 0);
|
||||
return count;
|
||||
} else {
|
||||
// Release endpoint since we don't make any transfer
|
||||
|
|
@ -291,32 +294,37 @@ void cdcd_reset(uint8_t rhport) {
|
|||
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
|
||||
|
||||
tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);
|
||||
if (!_cdcd_fifo_cfg.rx_persistent) tu_fifo_clear(&p_cdc->rx_ff);
|
||||
if (!_cdcd_fifo_cfg.tx_persistent) tu_fifo_clear(&p_cdc->tx_ff);
|
||||
if (!_cdcd_fifo_cfg.rx_persistent) {
|
||||
tu_fifo_clear(&p_cdc->rx_ff);
|
||||
}
|
||||
if (!_cdcd_fifo_cfg.tx_persistent) {
|
||||
tu_fifo_clear(&p_cdc->tx_ff);
|
||||
}
|
||||
tu_fifo_set_overwritable(&p_cdc->tx_ff, true);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
|
||||
uint16_t cdcd_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16_t max_len) {
|
||||
// Only support ACM subclass
|
||||
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
|
||||
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass, 0);
|
||||
|
||||
// Find available interface
|
||||
cdcd_interface_t* p_cdc = NULL;
|
||||
for (uint8_t cdc_id = 0; cdc_id < CFG_TUD_CDC; cdc_id++) {
|
||||
if (_cdcd_itf[cdc_id].ep_in == 0) {
|
||||
p_cdc = &_cdcd_itf[cdc_id];
|
||||
cdcd_interface_t* p_cdc;
|
||||
uint8_t cdc_id;
|
||||
for (cdc_id = 0; cdc_id < CFG_TUD_CDC; cdc_id++) {
|
||||
p_cdc = &_cdcd_itf[cdc_id];
|
||||
if (p_cdc->ep_in == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_ASSERT(p_cdc, 0);
|
||||
TU_ASSERT(cdc_id < CFG_TUD_CDC, 0);
|
||||
|
||||
//------------- Control Interface -------------//
|
||||
p_cdc->itf_num = itf_desc->bInterfaceNumber;
|
||||
|
||||
uint16_t drv_len = sizeof(tusb_desc_interface_t);
|
||||
uint8_t const* p_desc = tu_desc_next(itf_desc);
|
||||
const uint8_t* p_desc = tu_desc_next(itf_desc);
|
||||
|
||||
// Communication Functional Descriptors
|
||||
while (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) {
|
||||
|
|
@ -326,7 +334,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
|
||||
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
|
||||
// notification endpoint
|
||||
tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc;
|
||||
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
|
||||
|
||||
TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0);
|
||||
p_cdc->ep_notif = desc_ep->bEndpointAddress;
|
||||
|
|
@ -337,7 +345,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
|
||||
//------------- Data Interface (if any) -------------//
|
||||
if ((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) &&
|
||||
(TUSB_CLASS_CDC_DATA == ((tusb_desc_interface_t const*) p_desc)->bInterfaceClass)) {
|
||||
(TUSB_CLASS_CDC_DATA == ((const tusb_desc_interface_t*) p_desc)->bInterfaceClass)) {
|
||||
// next to endpoint descriptor
|
||||
drv_len += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
|
|
@ -349,7 +357,7 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
_prep_out_transaction(p_cdc);
|
||||
_prep_out_transaction(cdc_id);
|
||||
|
||||
return drv_len;
|
||||
}
|
||||
|
|
@ -357,19 +365,21 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
// Invoked when a control transfer occurred on an interface of this class
|
||||
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
|
||||
bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request) {
|
||||
// Handle class request only
|
||||
TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
uint8_t itf = 0;
|
||||
cdcd_interface_t* p_cdc = _cdcd_itf;
|
||||
uint8_t itf;
|
||||
cdcd_interface_t* p_cdc;
|
||||
|
||||
// Identify which interface to use
|
||||
for (;; itf++, p_cdc++) {
|
||||
if (itf >= TU_ARRAY_SIZE(_cdcd_itf)) return false;
|
||||
|
||||
if (p_cdc->itf_num == request->wIndex) break;
|
||||
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
|
||||
p_cdc = &_cdcd_itf[itf];
|
||||
if (p_cdc->itf_num == request->wIndex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_VERIFY(itf < CFG_TUD_CDC);
|
||||
|
||||
switch (request->bRequest) {
|
||||
case CDC_REQUEST_SET_LINE_CODING:
|
||||
|
|
@ -377,7 +387,9 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
TU_LOG_DRV(" Set Line Coding\r\n");
|
||||
tud_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
if (tud_cdc_line_coding_cb) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
|
||||
if (tud_cdc_line_coding_cb) {
|
||||
tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -408,7 +420,9 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
TU_LOG_DRV(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
|
||||
|
||||
// Invoke callback
|
||||
if (tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, dtr, rts);
|
||||
if (tud_cdc_line_state_cb) {
|
||||
tud_cdc_line_state_cb(itf, dtr, rts);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -417,7 +431,9 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
tud_control_status(rhport, request);
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
TU_LOG_DRV(" Send Break\r\n");
|
||||
if (tud_cdc_send_break_cb) tud_cdc_send_break_cb(itf, request->wValue);
|
||||
if (tud_cdc_send_break_cb) {
|
||||
tud_cdc_send_break_cb(itf, request->wValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -437,28 +453,33 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
|
|||
// Identify which interface to use
|
||||
for (itf = 0; itf < CFG_TUD_CDC; itf++) {
|
||||
p_cdc = &_cdcd_itf[itf];
|
||||
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) break;
|
||||
if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_ASSERT(itf < CFG_TUD_CDC);
|
||||
cdcd_epbuf_t* p_epbuf = &_cdcd_epbuf[itf];
|
||||
|
||||
// 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_epbuf->epout, (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)) {
|
||||
for (uint32_t i = 0; i < xferred_bytes; i++) {
|
||||
if ((p_cdc->wanted_char == p_cdc->epout_buf[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) {
|
||||
if ((p_cdc->wanted_char == p_epbuf->epout[i]) && !tu_fifo_empty(&p_cdc->rx_ff)) {
|
||||
tud_cdc_rx_wanted_cb(itf, p_cdc->wanted_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invoke receive callback (if there is still data)
|
||||
if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) tud_cdc_rx_cb(itf);
|
||||
if (tud_cdc_rx_cb && !tu_fifo_empty(&p_cdc->rx_ff)) {
|
||||
tud_cdc_rx_cb(itf);
|
||||
}
|
||||
|
||||
// prepare for OUT transaction
|
||||
_prep_out_transaction(p_cdc);
|
||||
_prep_out_transaction(itf);
|
||||
}
|
||||
|
||||
// Data sent to host, we continue to fetch from tx fifo to send.
|
||||
|
|
@ -466,7 +487,9 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
|
|||
// Though maybe the baudrate is not really important !!!
|
||||
if (ep_addr == p_cdc->ep_in) {
|
||||
// invoke transmit callback to possibly refill tx fifo
|
||||
if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf);
|
||||
if (tud_cdc_tx_complete_cb) {
|
||||
tud_cdc_tx_complete_cb(itf);
|
||||
}
|
||||
|
||||
if (0 == tud_cdc_n_write_flush(itf)) {
|
||||
// If there is no data left, a ZLP should be sent if
|
||||
|
|
|
|||
|
|
@ -204,6 +204,9 @@ TU_ATTR_WEAK void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts);
|
|||
TU_ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding);
|
||||
|
||||
// Invoked when received send break
|
||||
// \param[in] itf interface for which send break was received.
|
||||
// \param[in] duration_ms the length of time, in milliseconds, of the break signal. If a value of FFFFh, then the
|
||||
// device will send a break until another SendBreak request is received with value 0000h.
|
||||
TU_ATTR_WEAK void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -27,38 +27,6 @@
|
|||
* - Heiko Kuester: CH34x support
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
|
||||
#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST
|
||||
// List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID
|
||||
#define CFG_TUH_CDC_FTDI_VID_PID_LIST \
|
||||
{0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \
|
||||
{0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \
|
||||
{0x0403, 0xCD18}
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST
|
||||
// List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID
|
||||
#define CFG_TUH_CDC_CP210X_VID_PID_LIST \
|
||||
{0x10C4, 0xEA60}, {0x10C4, 0xEA70}
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST
|
||||
// List of product IDs that can use the CH34X CDC driver
|
||||
#define CFG_TUH_CDC_CH34X_VID_PID_LIST \
|
||||
{ 0x1a86, 0x5523 }, /* ch341 chip */ \
|
||||
{ 0x1a86, 0x7522 }, /* ch340k chip */ \
|
||||
{ 0x1a86, 0x7523 }, /* ch340 chip */ \
|
||||
{ 0x1a86, 0xe523 }, /* ch330 chip */ \
|
||||
{ 0x4348, 0x5523 }, /* ch340 custom chip */ \
|
||||
{ 0x2184, 0x0057 }, /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */ \
|
||||
{ 0x9986, 0x7523 } /* overtaken from Linux Kernel driver /drivers/usb/serial/ch341.c */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUH_ENABLED && CFG_TUH_CDC)
|
||||
|
|
@ -105,15 +73,17 @@ typedef struct {
|
|||
tu_edpt_stream_t rx;
|
||||
|
||||
uint8_t tx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
|
||||
CFG_TUH_MEM_ALIGN uint8_t tx_ep_buf[CFG_TUH_CDC_TX_EPSIZE];
|
||||
|
||||
uint8_t rx_ff_buf[CFG_TUH_CDC_TX_BUFSIZE];
|
||||
CFG_TUH_MEM_ALIGN uint8_t rx_ep_buf[CFG_TUH_CDC_TX_EPSIZE];
|
||||
} stream;
|
||||
} cdch_interface_t;
|
||||
|
||||
CFG_TUH_MEM_SECTION
|
||||
typedef struct {
|
||||
TUH_EPBUF_DEF(tx, CFG_TUH_CDC_TX_EPSIZE);
|
||||
TUH_EPBUF_DEF(rx, CFG_TUH_CDC_TX_EPSIZE);
|
||||
} cdch_epbuf_t;
|
||||
|
||||
static cdch_interface_t cdch_data[CFG_TUH_CDC];
|
||||
CFG_TUH_MEM_SECTION static cdch_epbuf_t cdch_epbuf[CFG_TUH_CDC];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Serial Driver
|
||||
|
|
@ -658,13 +628,14 @@ bool 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];
|
||||
cdch_epbuf_t* epbuf = &cdch_epbuf[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);
|
||||
epbuf->tx, 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);
|
||||
epbuf->rx, CFG_TUH_CDC_RX_EPSIZE);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -686,7 +657,9 @@ void cdch_close(uint8_t daddr) {
|
|||
TU_LOG_DRV(" CDCh close addr = %u index = %u\r\n", daddr, idx);
|
||||
|
||||
// Invoke application callback
|
||||
if (tuh_cdc_umount_cb) tuh_cdc_umount_cb(idx);
|
||||
if (tuh_cdc_umount_cb) {
|
||||
tuh_cdc_umount_cb(idx);
|
||||
}
|
||||
|
||||
p_cdc->daddr = 0;
|
||||
p_cdc->bInterfaceNumber = 0;
|
||||
|
|
@ -707,7 +680,9 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
|
|||
|
||||
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 (tuh_cdc_tx_complete_cb) {
|
||||
tuh_cdc_tx_complete_cb(idx);
|
||||
}
|
||||
|
||||
if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) {
|
||||
// If there is no data left, a ZLP should be sent if:
|
||||
|
|
@ -727,7 +702,9 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t
|
|||
}
|
||||
|
||||
// invoke receive callback
|
||||
if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx);
|
||||
if (tuh_cdc_rx_cb) {
|
||||
tuh_cdc_rx_cb(idx);
|
||||
}
|
||||
|
||||
// prepare for next transfer if needed
|
||||
tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx);
|
||||
|
|
@ -770,9 +747,8 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
|
|||
if (TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
|
||||
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass) {
|
||||
return acm_open(daddr, itf_desc, max_len);
|
||||
}
|
||||
else if (SERIAL_DRIVER_COUNT > 1 &&
|
||||
TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) {
|
||||
} else if (SERIAL_DRIVER_COUNT > 1 &&
|
||||
TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass) {
|
||||
uint16_t vid, pid;
|
||||
TU_VERIFY(tuh_vid_pid_get(daddr, &vid, &pid));
|
||||
|
||||
|
|
@ -792,7 +768,9 @@ bool cdch_open(uint8_t rhport, uint8_t daddr, tusb_desc_interface_t const *itf_d
|
|||
static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t itf_num) {
|
||||
TU_LOG_DRV("CDCh Set Configure complete\r\n");
|
||||
p_cdc->mounted = true;
|
||||
if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx);
|
||||
if (tuh_cdc_mount_cb) {
|
||||
tuh_cdc_mount_cb(idx);
|
||||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx);
|
||||
|
|
|
|||
|
|
@ -89,8 +89,7 @@ bool tuh_cdc_get_dtr(uint8_t idx);
|
|||
bool tuh_cdc_get_rts(uint8_t idx);
|
||||
|
||||
// Check if interface is connected (DTR active)
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx)
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tuh_cdc_connected(uint8_t idx) {
|
||||
return tuh_cdc_get_dtr(idx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_DFU)
|
||||
|
|
@ -52,8 +47,7 @@
|
|||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t attrs;
|
||||
uint8_t alt;
|
||||
|
||||
|
|
@ -63,69 +57,65 @@ typedef struct
|
|||
bool flashing_in_progress;
|
||||
uint16_t block;
|
||||
uint16_t length;
|
||||
|
||||
CFG_TUSB_MEM_ALIGN uint8_t transfer_buf[CFG_TUD_DFU_XFER_BUFSIZE];
|
||||
} dfu_state_ctx_t;
|
||||
|
||||
// Only a single dfu state is allowed
|
||||
CFG_TUD_MEM_SECTION tu_static dfu_state_ctx_t _dfu_ctx;
|
||||
static dfu_state_ctx_t _dfu_ctx;
|
||||
|
||||
static void reset_state(void)
|
||||
{
|
||||
CFG_TUD_MEM_SECTION static struct {
|
||||
TUD_EPBUF_DEF(transfer_buf, CFG_TUD_DFU_XFER_BUFSIZE);
|
||||
} _dfu_epbuf;
|
||||
|
||||
static void reset_state(void) {
|
||||
_dfu_ctx.state = DFU_IDLE;
|
||||
_dfu_ctx.status = DFU_STATUS_OK;
|
||||
_dfu_ctx.flashing_in_progress = false;
|
||||
}
|
||||
|
||||
static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout);
|
||||
static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
|
||||
static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
|
||||
static bool reply_getstatus(uint8_t rhport, const tusb_control_request_t* request, dfu_state_t state, dfu_status_t status, uint32_t timeout);
|
||||
static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request);
|
||||
static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Debug
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
|
||||
tu_static tu_lookup_entry_t const _dfu_request_lookup[] =
|
||||
{
|
||||
{ .key = DFU_REQUEST_DETACH , .data = "DETACH" },
|
||||
{ .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" },
|
||||
{ .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" },
|
||||
{ .key = DFU_REQUEST_GETSTATUS , .data = "GETSTATUS" },
|
||||
{ .key = DFU_REQUEST_CLRSTATUS , .data = "CLRSTATUS" },
|
||||
{ .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" },
|
||||
{ .key = DFU_REQUEST_ABORT , .data = "ABORT" },
|
||||
tu_static tu_lookup_entry_t const _dfu_request_lookup[] = {
|
||||
{ .key = DFU_REQUEST_DETACH , .data = "DETACH" },
|
||||
{ .key = DFU_REQUEST_DNLOAD , .data = "DNLOAD" },
|
||||
{ .key = DFU_REQUEST_UPLOAD , .data = "UPLOAD" },
|
||||
{ .key = DFU_REQUEST_GETSTATUS, .data = "GETSTATUS" },
|
||||
{ .key = DFU_REQUEST_CLRSTATUS, .data = "CLRSTATUS" },
|
||||
{ .key = DFU_REQUEST_GETSTATE , .data = "GETSTATE" },
|
||||
{ .key = DFU_REQUEST_ABORT , .data = "ABORT" },
|
||||
};
|
||||
|
||||
tu_static tu_lookup_table_t const _dfu_request_table =
|
||||
{
|
||||
tu_static tu_lookup_table_t const _dfu_request_table = {
|
||||
.count = TU_ARRAY_SIZE(_dfu_request_lookup),
|
||||
.items = _dfu_request_lookup
|
||||
};
|
||||
|
||||
tu_static tu_lookup_entry_t const _dfu_state_lookup[] =
|
||||
{
|
||||
{ .key = APP_IDLE , .data = "APP_IDLE" },
|
||||
{ .key = APP_DETACH , .data = "APP_DETACH" },
|
||||
{ .key = DFU_IDLE , .data = "IDLE" },
|
||||
{ .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" },
|
||||
{ .key = DFU_DNBUSY , .data = "DNBUSY" },
|
||||
{ .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" },
|
||||
{ .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" },
|
||||
{ .key = DFU_MANIFEST , .data = "MANIFEST" },
|
||||
{ .key = DFU_MANIFEST_WAIT_RESET , .data = "MANIFEST_WAIT_RESET" },
|
||||
{ .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" },
|
||||
{ .key = DFU_ERROR , .data = "ERROR" },
|
||||
tu_static tu_lookup_entry_t const _dfu_state_lookup[] = {
|
||||
{ .key = APP_IDLE , .data = "APP_IDLE" },
|
||||
{ .key = APP_DETACH , .data = "APP_DETACH" },
|
||||
{ .key = DFU_IDLE , .data = "IDLE" },
|
||||
{ .key = DFU_DNLOAD_SYNC , .data = "DNLOAD_SYNC" },
|
||||
{ .key = DFU_DNBUSY , .data = "DNBUSY" },
|
||||
{ .key = DFU_DNLOAD_IDLE , .data = "DNLOAD_IDLE" },
|
||||
{ .key = DFU_MANIFEST_SYNC , .data = "MANIFEST_SYNC" },
|
||||
{ .key = DFU_MANIFEST , .data = "MANIFEST" },
|
||||
{ .key = DFU_MANIFEST_WAIT_RESET, .data = "MANIFEST_WAIT_RESET" },
|
||||
{ .key = DFU_UPLOAD_IDLE , .data = "UPLOAD_IDLE" },
|
||||
{ .key = DFU_ERROR , .data = "ERROR" },
|
||||
};
|
||||
|
||||
tu_static tu_lookup_table_t const _dfu_state_table =
|
||||
{
|
||||
tu_static tu_lookup_table_t const _dfu_state_table = {
|
||||
.count = TU_ARRAY_SIZE(_dfu_state_lookup),
|
||||
.items = _dfu_state_lookup
|
||||
};
|
||||
|
||||
tu_static tu_lookup_entry_t const _dfu_status_lookup[] =
|
||||
{
|
||||
tu_static tu_lookup_entry_t const _dfu_status_lookup[] = {
|
||||
{ .key = DFU_STATUS_OK , .data = "OK" },
|
||||
{ .key = DFU_STATUS_ERR_TARGET , .data = "errTARGET" },
|
||||
{ .key = DFU_STATUS_ERR_FILE , .data = "errFILE" },
|
||||
|
|
@ -144,8 +134,7 @@ tu_static tu_lookup_entry_t const _dfu_status_lookup[] =
|
|||
{ .key = DFU_STATUS_ERR_STALLEDPKT , .data = "errSTALLEDPKT" },
|
||||
};
|
||||
|
||||
tu_static tu_lookup_table_t const _dfu_status_table =
|
||||
{
|
||||
tu_static tu_lookup_table_t const _dfu_status_table = {
|
||||
.count = TU_ARRAY_SIZE(_dfu_status_lookup),
|
||||
.items = _dfu_status_lookup
|
||||
};
|
||||
|
|
@ -155,13 +144,10 @@ tu_static tu_lookup_table_t const _dfu_status_table =
|
|||
//--------------------------------------------------------------------+
|
||||
// USBD Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void dfu_moded_reset(uint8_t rhport)
|
||||
{
|
||||
void dfu_moded_reset(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
|
||||
_dfu_ctx.attrs = 0;
|
||||
_dfu_ctx.alt = 0;
|
||||
|
||||
reset_state();
|
||||
}
|
||||
|
||||
|
|
@ -173,19 +159,17 @@ bool dfu_moded_deinit(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
|
||||
{
|
||||
uint16_t dfu_moded_open(uint8_t rhport, const tusb_desc_interface_t* itf_desc, uint16_t max_len) {
|
||||
(void) rhport;
|
||||
|
||||
//------------- Interface (with Alt) descriptor -------------//
|
||||
uint8_t const itf_num = itf_desc->bInterfaceNumber;
|
||||
const uint8_t itf_num = itf_desc->bInterfaceNumber;
|
||||
uint8_t alt_count = 0;
|
||||
|
||||
uint16_t drv_len = 0;
|
||||
TU_VERIFY(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU, 0);
|
||||
|
||||
while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU)
|
||||
{
|
||||
while(itf_desc->bInterfaceSubClass == TUD_DFU_APP_SUBCLASS && itf_desc->bInterfaceProtocol == DFU_PROTOCOL_DFU) {
|
||||
TU_ASSERT(max_len > drv_len, 0);
|
||||
|
||||
// Alternate must have the same interface number
|
||||
|
|
@ -196,18 +180,18 @@ uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc,
|
|||
alt_count++;
|
||||
|
||||
drv_len += tu_desc_len(itf_desc);
|
||||
itf_desc = (tusb_desc_interface_t const *) tu_desc_next(itf_desc);
|
||||
itf_desc = (const tusb_desc_interface_t*) tu_desc_next(itf_desc);
|
||||
}
|
||||
|
||||
//------------- DFU Functional descriptor -------------//
|
||||
tusb_desc_dfu_functional_t const *func_desc = (tusb_desc_dfu_functional_t const *) itf_desc;
|
||||
const tusb_desc_dfu_functional_t*func_desc = (const tusb_desc_dfu_functional_t*) itf_desc;
|
||||
TU_ASSERT(tu_desc_type(func_desc) == TUSB_DESC_FUNCTIONAL, 0);
|
||||
drv_len += sizeof(tusb_desc_dfu_functional_t);
|
||||
|
||||
_dfu_ctx.attrs = func_desc->bAttributes;
|
||||
|
||||
// CFG_TUD_DFU_XFER_BUFSIZE has to be set to the buffer size used in TUD_DFU_DESCRIPTOR
|
||||
uint16_t const transfer_size = tu_le16toh( tu_unaligned_read16((uint8_t const*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) );
|
||||
const uint16_t transfer_size = tu_le16toh( tu_unaligned_read16((const uint8_t*) func_desc + offsetof(tusb_desc_dfu_functional_t, wTransferSize)) );
|
||||
TU_ASSERT(transfer_size <= CFG_TUD_DFU_XFER_BUFSIZE, drv_len);
|
||||
|
||||
return drv_len;
|
||||
|
|
@ -216,99 +200,85 @@ uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc,
|
|||
// Invoked when a control transfer occurred on an interface of this class
|
||||
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
|
||||
{
|
||||
bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request) {
|
||||
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
|
||||
|
||||
TU_LOG_DRV(" DFU State : %s, Status: %s\r\n", tu_lookup_find(&_dfu_state_table, _dfu_ctx.state), tu_lookup_find(&_dfu_status_table, _dfu_ctx.status));
|
||||
|
||||
if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
|
||||
{
|
||||
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
|
||||
// Standard request include GET/SET_INTERFACE
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
switch (request->bRequest) {
|
||||
case TUSB_REQ_SET_INTERFACE:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
// Switch Alt interface and reset state machine
|
||||
_dfu_ctx.alt = (uint8_t) request->wValue;
|
||||
_dfu_ctx.alt = (uint8_t)request->wValue;
|
||||
reset_state();
|
||||
return tud_control_status(rhport, request);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_INTERFACE:
|
||||
if(stage == CONTROL_STAGE_SETUP)
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
return tud_control_xfer(rhport, request, &_dfu_ctx.alt, 1);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
// unsupported request
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
else if ( request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS )
|
||||
{
|
||||
} else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
|
||||
TU_LOG_DRV(" DFU Request: %s\r\n", tu_lookup_find(&_dfu_request_table, request->bRequest));
|
||||
|
||||
// Class request
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
switch (request->bRequest) {
|
||||
case DFU_REQUEST_DETACH:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
tud_control_status(rhport, request);
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
if (tud_dfu_detach_cb) {
|
||||
tud_dfu_detach_cb();
|
||||
}
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_ACK )
|
||||
{
|
||||
if ( tud_dfu_detach_cb ) tud_dfu_detach_cb();
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_REQUEST_CLRSTATUS:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
reset_state();
|
||||
tud_control_status(rhport, request);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_REQUEST_GETSTATE:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
tud_control_xfer(rhport, request, &_dfu_ctx.state, 1);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_REQUEST_ABORT:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
reset_state();
|
||||
tud_control_status(rhport, request);
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
if (tud_dfu_abort_cb) {
|
||||
tud_dfu_abort_cb(_dfu_ctx.alt);
|
||||
}
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_ACK )
|
||||
{
|
||||
if ( tud_dfu_abort_cb ) tud_dfu_abort_cb(_dfu_ctx.alt);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_REQUEST_UPLOAD:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_UPLOAD);
|
||||
TU_VERIFY(tud_dfu_upload_cb);
|
||||
TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE);
|
||||
|
||||
uint16_t const xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_ctx.transfer_buf, request->wLength);
|
||||
const uint16_t xfer_len = tud_dfu_upload_cb(_dfu_ctx.alt, request->wValue, _dfu_epbuf.transfer_buf,
|
||||
request->wLength);
|
||||
|
||||
return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, xfer_len);
|
||||
return tud_control_xfer(rhport, request, _dfu_epbuf.transfer_buf, xfer_len);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_REQUEST_DNLOAD:
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(_dfu_ctx.attrs & DFU_ATTR_CAN_DOWNLOAD);
|
||||
TU_VERIFY(_dfu_ctx.state == DFU_IDLE || _dfu_ctx.state == DFU_DNLOAD_IDLE);
|
||||
TU_VERIFY(request->wLength <= CFG_TUD_DFU_XFER_BUFSIZE);
|
||||
|
|
@ -317,104 +287,86 @@ bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_reque
|
|||
_dfu_ctx.flashing_in_progress = true;
|
||||
|
||||
// save block and length for flashing
|
||||
_dfu_ctx.block = request->wValue;
|
||||
_dfu_ctx.block = request->wValue;
|
||||
_dfu_ctx.length = request->wLength;
|
||||
|
||||
if ( request->wLength )
|
||||
{
|
||||
if (request->wLength) {
|
||||
// Download with payload -> transition to DOWNLOAD SYNC
|
||||
_dfu_ctx.state = DFU_DNLOAD_SYNC;
|
||||
return tud_control_xfer(rhport, request, _dfu_ctx.transfer_buf, request->wLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return tud_control_xfer(rhport, request, _dfu_epbuf.transfer_buf, request->wLength);
|
||||
} else {
|
||||
// Download is complete -> transition to MANIFEST SYNC
|
||||
_dfu_ctx.state = DFU_MANIFEST_SYNC;
|
||||
return tud_control_status(rhport, request);
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_REQUEST_GETSTATUS:
|
||||
switch ( _dfu_ctx.state )
|
||||
{
|
||||
switch (_dfu_ctx.state) {
|
||||
case DFU_DNLOAD_SYNC:
|
||||
return process_download_get_status(rhport, stage, request);
|
||||
break;
|
||||
break;
|
||||
|
||||
case DFU_MANIFEST_SYNC:
|
||||
return process_manifest_get_status(rhport, stage, request);
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( stage == CONTROL_STAGE_SETUP ) return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0);
|
||||
break;
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
return reply_getstatus(rhport, request, _dfu_ctx.state, _dfu_ctx.status, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default: return false; // stall unsupported request
|
||||
}
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
return false; // unsupported request
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tud_dfu_finish_flashing(uint8_t status)
|
||||
{
|
||||
void tud_dfu_finish_flashing(uint8_t status) {
|
||||
_dfu_ctx.flashing_in_progress = false;
|
||||
|
||||
if ( status == DFU_STATUS_OK )
|
||||
{
|
||||
if (_dfu_ctx.state == DFU_DNBUSY)
|
||||
{
|
||||
if (status == DFU_STATUS_OK) {
|
||||
if (_dfu_ctx.state == DFU_DNBUSY) {
|
||||
_dfu_ctx.state = DFU_DNLOAD_SYNC;
|
||||
}
|
||||
else if (_dfu_ctx.state == DFU_MANIFEST)
|
||||
{
|
||||
} else if (_dfu_ctx.state == DFU_MANIFEST) {
|
||||
_dfu_ctx.state = (_dfu_ctx.attrs & DFU_ATTR_MANIFESTATION_TOLERANT)
|
||||
? DFU_MANIFEST_SYNC : DFU_MANIFEST_WAIT_RESET;
|
||||
? DFU_MANIFEST_SYNC
|
||||
: DFU_MANIFEST_WAIT_RESET;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// failed while flashing, move to dfuError
|
||||
_dfu_ctx.state = DFU_ERROR;
|
||||
_dfu_ctx.status = (dfu_status_t)status;
|
||||
}
|
||||
}
|
||||
|
||||
static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
|
||||
{
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
static bool process_download_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request) {
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
// only transition to next state on CONTROL_STAGE_ACK
|
||||
dfu_state_t next_state;
|
||||
uint32_t timeout;
|
||||
|
||||
if ( _dfu_ctx.flashing_in_progress )
|
||||
{
|
||||
if (_dfu_ctx.flashing_in_progress) {
|
||||
next_state = DFU_DNBUSY;
|
||||
timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t) next_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, (uint8_t)next_state);
|
||||
} else {
|
||||
next_state = DFU_DNLOAD_IDLE;
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout);
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_ACK )
|
||||
{
|
||||
if ( _dfu_ctx.flashing_in_progress )
|
||||
{
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
if (_dfu_ctx.flashing_in_progress) {
|
||||
_dfu_ctx.state = DFU_DNBUSY;
|
||||
tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_ctx.transfer_buf, _dfu_ctx.length);
|
||||
}else
|
||||
{
|
||||
tud_dfu_download_cb(_dfu_ctx.alt, _dfu_ctx.block, _dfu_epbuf.transfer_buf, _dfu_ctx.length);
|
||||
} else {
|
||||
_dfu_ctx.state = DFU_DNLOAD_IDLE;
|
||||
}
|
||||
}
|
||||
|
|
@ -422,36 +374,26 @@ static bool process_download_get_status(uint8_t rhport, uint8_t stage, tusb_cont
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
|
||||
{
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request) {
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
// only transition to next state on CONTROL_STAGE_ACK
|
||||
dfu_state_t next_state;
|
||||
uint32_t timeout;
|
||||
|
||||
if ( _dfu_ctx.flashing_in_progress )
|
||||
{
|
||||
if (_dfu_ctx.flashing_in_progress) {
|
||||
next_state = DFU_MANIFEST;
|
||||
timeout = tud_dfu_get_timeout_cb(_dfu_ctx.alt, next_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
next_state = DFU_IDLE;
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
return reply_getstatus(rhport, request, next_state, _dfu_ctx.status, timeout);
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_ACK )
|
||||
{
|
||||
if ( _dfu_ctx.flashing_in_progress )
|
||||
{
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
if (_dfu_ctx.flashing_in_progress) {
|
||||
_dfu_ctx.state = DFU_MANIFEST;
|
||||
tud_dfu_manifest_cb(_dfu_ctx.alt);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_dfu_ctx.state = DFU_IDLE;
|
||||
}
|
||||
}
|
||||
|
|
@ -459,15 +401,15 @@ static bool process_manifest_get_status(uint8_t rhport, uint8_t stage, tusb_cont
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool reply_getstatus(uint8_t rhport, tusb_control_request_t const * request, dfu_state_t state, dfu_status_t status, uint32_t timeout)
|
||||
{
|
||||
static bool reply_getstatus(uint8_t rhport, const tusb_control_request_t* request, dfu_state_t state,
|
||||
dfu_status_t status, uint32_t timeout) {
|
||||
dfu_status_response_t resp;
|
||||
resp.bStatus = (uint8_t) status;
|
||||
resp.bStatus = (uint8_t)status;
|
||||
resp.bwPollTimeout[0] = TU_U32_BYTE0(timeout);
|
||||
resp.bwPollTimeout[1] = TU_U32_BYTE1(timeout);
|
||||
resp.bwPollTimeout[2] = TU_U32_BYTE2(timeout);
|
||||
resp.bState = (uint8_t) state;
|
||||
resp.iString = 0;
|
||||
resp.bState = (uint8_t)state;
|
||||
resp.iString = 0;
|
||||
|
||||
return tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_DFU_RUNTIME)
|
||||
|
|
@ -63,9 +58,8 @@ bool dfu_rtd_deinit(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void dfu_rtd_reset(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
void dfu_rtd_reset(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
|
||||
|
|
|
|||
|
|
@ -325,6 +325,29 @@ typedef enum
|
|||
|
||||
/// @}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Digitizer Stylus Pen
|
||||
//--------------------------------------------------------------------+
|
||||
/** \addtogroup ClassDriver_HID_Stylus Stylus
|
||||
* @{ */
|
||||
|
||||
// Standard Stylus Pen Report.
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t attr; /**< Attribute mask for describing current status of the stylus pen. */
|
||||
uint16_t x; /**< Current x position of the mouse. */
|
||||
uint16_t y; /**< Current y position of the mouse. */
|
||||
} hid_stylus_report_t;
|
||||
|
||||
// Standard Stylus Pen Attributes Bitmap.
|
||||
typedef enum
|
||||
{
|
||||
STYLUS_ATTR_TIP_SWITCH = TU_BIT(0), ///< Tip switch
|
||||
STYLUS_ATTR_IN_RANGE = TU_BIT(1), ///< In-range bit.
|
||||
} hid_stylus_attr_bm_t;
|
||||
|
||||
/// @}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Keyboard
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -740,6 +763,21 @@ enum {
|
|||
|
||||
//--------------------------------------------------------------------+
|
||||
// Usage Table
|
||||
/* Usage Types Data
|
||||
Sel Selector Array
|
||||
SV Static Value Constant, Variable, Absolute
|
||||
SF Static Flag Constant, Variable, Absolute
|
||||
DV Dynamic Value Constant, Variable, Absolute
|
||||
DF Dynamic Flag Constant, Variable, Absolute
|
||||
*/
|
||||
/* Usage Types Collection
|
||||
NAry Named Array Logical
|
||||
CA Collection Application Application
|
||||
CL Collection Logical Logical
|
||||
CP Collection Physical Physical
|
||||
US Usage Switch Logical
|
||||
UM Usage Modifier Logical
|
||||
*/
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// HID Usage Table - Table 1: Usage Page Summary
|
||||
|
|
@ -759,8 +797,14 @@ enum {
|
|||
HID_USAGE_PAGE_DIGITIZER = 0x0d,
|
||||
HID_USAGE_PAGE_PID = 0x0f,
|
||||
HID_USAGE_PAGE_UNICODE = 0x10,
|
||||
HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14,
|
||||
HID_USAGE_PAGE_MEDICAL = 0x40,
|
||||
HID_USAGE_PAGE_SOC = 0x11,
|
||||
HID_USAGE_PAGE_EYE_AND_HEAD_TRACKERS = 0x12,
|
||||
// 0x13 is reserved
|
||||
HID_USAGE_PAGE_AUXILIARY_DISPLAY = 0x14,
|
||||
// 0x15 - 0x1f is reserved
|
||||
HID_USAGE_PAGE_SENSORS = 0x20,
|
||||
// 0x21 - 0x3f is reserved
|
||||
HID_USAGE_PAGE_MEDICAL_INSTRUMENT = 0x40,
|
||||
HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59,
|
||||
HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83
|
||||
HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87
|
||||
|
|
@ -846,7 +890,6 @@ enum {
|
|||
HID_USAGE_DESKTOP_SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7
|
||||
};
|
||||
|
||||
|
||||
/// HID Usage Table: Consumer Page (0x0C)
|
||||
/// Only contains controls that supported by Windows (whole list is too long)
|
||||
enum {
|
||||
|
|
@ -905,6 +948,237 @@ enum {
|
|||
HID_USAGE_CONSUMER_AC_PAN = 0x0238,
|
||||
};
|
||||
|
||||
/// HID Usage Table: Digitizer Page (0x0D)
|
||||
enum {
|
||||
HID_USAGE_DIGITIZER_UNDEFINED = 0x00,
|
||||
HID_USAGE_DIGITIZER_DIGITIZER = 0x01, // CA
|
||||
HID_USAGE_DIGITIZER_PEN = 0x02, // CA
|
||||
HID_USAGE_DIGITIZER_LIGHT_PEN = 0x03, // CA
|
||||
HID_USAGE_DIGITIZER_TOUCH_SCREEN = 0x04, // CA
|
||||
HID_USAGE_DIGITIZER_TOUCH_PAD = 0x05, // CA
|
||||
HID_USAGE_DIGITIZER_WHITEBOARD = 0x06, // CA
|
||||
HID_USAGE_DIGITIZER_COORDINATE_MEASURING_MACHINE = 0x07, // CA
|
||||
HID_USAGE_DIGITIZER_3D_DIGITIZER = 0x08, // CA
|
||||
HID_USAGE_DIGITIZER_STEREO_PLOTTER = 0x09, // CA
|
||||
HID_USAGE_DIGITIZER_ARTICULATED_ARM = 0x0A, // CA
|
||||
HID_USAGE_DIGITIZER_ARMATURE = 0x0B, // CA
|
||||
HID_USAGE_DIGITIZER_MULTIPLE_POINT_DIGITIZER = 0x0C, // CA
|
||||
HID_USAGE_DIGITIZER_FREE_SPACE_WAND = 0x0D, // CA
|
||||
HID_USAGE_DIGITIZER_DEVICE_CONFIGURATION = 0x0E, // CA
|
||||
HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_DIGITIZER = 0x0F, // CA
|
||||
// Reserved (0x10 - 0x1F)
|
||||
HID_USAGE_DIGITIZER_STYLUS = 0x20, // CA/CL
|
||||
HID_USAGE_DIGITIZER_PUCK = 0x21, // CL
|
||||
HID_USAGE_DIGITIZER_FINGER = 0x22, // CL
|
||||
HID_USAGE_DIGITIZER_DEVICE_SETTINGS = 0x23, // CL
|
||||
HID_USAGE_DIGITIZER_CHARACTER_GESTURE = 0x24, // CL
|
||||
// Reserved (0x25 - 0x2F)
|
||||
HID_USAGE_DIGITIZER_TIP_PRESSURE = 0x30, // DV
|
||||
HID_USAGE_DIGITIZER_BARREL_PRESSURE = 0x31, // DV
|
||||
HID_USAGE_DIGITIZER_IN_RANGE = 0x32, // MC
|
||||
HID_USAGE_DIGITIZER_TOUCH = 0x33, // MC
|
||||
HID_USAGE_DIGITIZER_UNTOUCH = 0x34, // OSC
|
||||
HID_USAGE_DIGITIZER_TAP = 0x35, // OSC
|
||||
HID_USAGE_DIGITIZER_QUALITY = 0x36, // DV
|
||||
HID_USAGE_DIGITIZER_DATA_VALID = 0x37, // MC
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_INDEX = 0x38, // DV
|
||||
HID_USAGE_DIGITIZER_TABLET_FUNCTION_KEYS = 0x39, // CL
|
||||
HID_USAGE_DIGITIZER_PROGRAM_CHANGE_KEYS = 0x3A, // CL
|
||||
HID_USAGE_DIGITIZER_BATTERY_STRENGTH = 0x3B, // DV
|
||||
HID_USAGE_DIGITIZER_INVERT = 0x3C, // MC
|
||||
HID_USAGE_DIGITIZER_X_TILT = 0x3D, // DV
|
||||
HID_USAGE_DIGITIZER_Y_TILT = 0x3E, // DV
|
||||
HID_USAGE_DIGITIZER_AZIMUTH = 0x3F, // DV
|
||||
HID_USAGE_DIGITIZER_ALTITUDE = 0x40, // DV
|
||||
HID_USAGE_DIGITIZER_TWIST = 0x41, // DV
|
||||
HID_USAGE_DIGITIZER_TIP_SWITCH = 0x42, // MC
|
||||
HID_USAGE_DIGITIZER_SECONDARY_TIP_SWITCH = 0x43, // MC
|
||||
HID_USAGE_DIGITIZER_BARREL_SWITCH = 0x44, // MC
|
||||
HID_USAGE_DIGITIZER_ERASER = 0x45, // MC
|
||||
HID_USAGE_DIGITIZER_TABLET_PICK = 0x46, // MC
|
||||
HID_USAGE_DIGITIZER_TOUCH_VALID = 0x47, // MC
|
||||
HID_USAGE_DIGITIZER_WIDTH = 0x48, // DV
|
||||
HID_USAGE_DIGITIZER_HEIGHT = 0x49, // DV
|
||||
// Reserved (0x4A - 0x50)
|
||||
HID_USAGE_DIGITIZER_CONTACT_IDENTIFIER = 0x51, // DV
|
||||
HID_USAGE_DIGITIZER_DEVICE_MODE = 0x52, // DV
|
||||
HID_USAGE_DIGITIZER_DEVICE_IDENTIFIER = 0x53, // DV/SV
|
||||
HID_USAGE_DIGITIZER_CONTACT_COUNT = 0x54, // DV
|
||||
HID_USAGE_DIGITIZER_CONTACT_COUNT_MAXIMUM = 0x55, // SV
|
||||
HID_USAGE_DIGITIZER_SCAN_TIME = 0x56, // DV
|
||||
HID_USAGE_DIGITIZER_SURFACE_SWITCH = 0x57, // DF
|
||||
HID_USAGE_DIGITIZER_BUTTON_SWITCH = 0x58, // DF
|
||||
HID_USAGE_DIGITIZER_PAD_TYPE = 0x59, // SF
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_NUMBER = 0x5B, // SV
|
||||
HID_USAGE_DIGITIZER_PREFERRED_COLOR = 0x5C, // DV
|
||||
HID_USAGE_DIGITIZER_PREFERRED_COLOR_LOCKED = 0x5D, // MC
|
||||
HID_USAGE_DIGITIZER_PREFERRED_LINE_WIDTH = 0x5E, // DV
|
||||
HID_USAGE_DIGITIZER_PREFERRED_LINE_WIDTH_LOCKED = 0x5F, // MC
|
||||
HID_USAGE_DIGITIZER_LATENCY_MODE = 0x60, // DF
|
||||
HID_USAGE_DIGITIZER_GESTURE_CHARACTER_QUALITY = 0x61, // DV
|
||||
HID_USAGE_DIGITIZER_CHARACTER_GESTURE_DATA_LENGTH = 0x62, // DV
|
||||
HID_USAGE_DIGITIZER_CHARACTER_GESTURE_DATA = 0x63, // DV
|
||||
HID_USAGE_DIGITIZER_GESTURE_CHARACTER_ENCODING = 0x64, // NAry
|
||||
HID_USAGE_DIGITIZER_UTF8_CHARACTER_GESTURE_ENCODING = 0x65, // Sel
|
||||
HID_USAGE_DIGITIZER_UTF16_LE_CHARACTER_GESTURE_ENCODING = 0x66, // Sel
|
||||
HID_USAGE_DIGITIZER_UTF16_BE_CHARACTER_GESTURE_ENCODING = 0x67, // Sel
|
||||
HID_USAGE_DIGITIZER_UTF32_LE_CHARACTER_GESTURE_ENCODING = 0x68, // Sel
|
||||
HID_USAGE_DIGITIZER_UTF32_BE_CHARACTER_GESTURE_ENCODING = 0x69, // Sel
|
||||
HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_VENDOR_ID = 0x6A, // SV
|
||||
HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_VERSION = 0x6B, // SV
|
||||
HID_USAGE_DIGITIZER_CAPACITIVE_HEAT_MAP_FRAME_DATA = 0x6C, // DV
|
||||
HID_USAGE_DIGITIZER_GESTURE_CHARACTER_ENABLE = 0x6D, // DF
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_SERIAL_NUMBER_PART2 = 0x6E, // SV
|
||||
HID_USAGE_DIGITIZER_NO_PREFERRED_COLOR = 0x6F, // DF
|
||||
HID_USAGE_DIGITIZER_PREFERRED_LINE_STYLE = 0x70, // NAry
|
||||
HID_USAGE_DIGITIZER_PREFERRED_LINE_STYLE_LOCKED = 0x71, // MC
|
||||
HID_USAGE_DIGITIZER_INK = 0x72, // Sel
|
||||
HID_USAGE_DIGITIZER_PENCIL = 0x73, // Sel
|
||||
HID_USAGE_DIGITIZER_HIGHLIGHTER = 0x74, // Sel
|
||||
HID_USAGE_DIGITIZER_CHISEL_MARKER = 0x75, // Sel
|
||||
HID_USAGE_DIGITIZER_BRUSH = 0x76, // Sel
|
||||
HID_USAGE_DIGITIZER_NO_PREFERENCE = 0x77, // Sel
|
||||
// Reserved (0x78 - 0x7F)
|
||||
HID_USAGE_DIGITIZER_DIGITIZER_DIAGNOSTIC = 0x80, // CL
|
||||
HID_USAGE_DIGITIZER_DIGITIZER_ERROR = 0x81, // NAry
|
||||
HID_USAGE_DIGITIZER_ERR_NORMAL_STATUS = 0x82, // Sel
|
||||
HID_USAGE_DIGITIZER_ERR_TRANSDUCERS_EXCEEDED = 0x83, // Sel
|
||||
HID_USAGE_DIGITIZER_ERR_FULL_TRANS_FEATURES_UNAVAILABLE = 0x84, // Sel
|
||||
HID_USAGE_DIGITIZER_ERR_CHARGE_LOW = 0x85, // Sel
|
||||
// Reserved (0x86 - 0x8F)
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_SOFTWARE_INFO = 0x90, // CL
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_VENDOR_ID = 0x91, // SV
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_PRODUCT_ID = 0x92, // SV
|
||||
HID_USAGE_DIGITIZER_DEVICE_SUPPORTED_PROTOCOLS = 0x93, // NAry/CL
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_SUPPORTED_PROTOCOLS = 0x94, // NAry/CL
|
||||
HID_USAGE_DIGITIZER_NO_PROTOCOL = 0x95, // Sel
|
||||
HID_USAGE_DIGITIZER_WACOM_AES_PROTOCOL = 0x96, // Sel
|
||||
HID_USAGE_DIGITIZER_USI_PROTOCOL = 0x97, // Sel
|
||||
HID_USAGE_DIGITIZER_MICROSOFT_PEN_PROTOCOL = 0x98, // Sel
|
||||
// Reserved (0x99 - 0x9F)
|
||||
HID_USAGE_DIGITIZER_SUPPORTED_REPORT_RATES = 0xA0, // SV/CL
|
||||
HID_USAGE_DIGITIZER_REPORT_RATE = 0xA1, // DV
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_CONNECTED = 0xA2, // SF
|
||||
HID_USAGE_DIGITIZER_SWITCH_DISABLED = 0xA3, // Sel
|
||||
HID_USAGE_DIGITIZER_SWITCH_UNIMPLEMENTED = 0xA4, // Sel
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_SWITCHES = 0xA5, // CL
|
||||
HID_USAGE_DIGITIZER_TRANSDUCER_INDEX_SELECTOR = 0xA6, // DV
|
||||
// Reserved (0xA7 - 0xAF)
|
||||
HID_USAGE_DIGITIZER_BUTTON_PRESS_THRESHOLD = 0xB0, // DV
|
||||
|
||||
// Reserved (0xB1 - 0xFFFF)
|
||||
};
|
||||
|
||||
/// HID Usage Table: Physical Input Device Page (0x0F)
|
||||
enum {
|
||||
HID_USAGE_PID_UNDEFINED = 0x00,
|
||||
HID_USAGE_PID_PHYSICAL_INPUT_DEVICE = 0x01,
|
||||
HID_USAGE_PID_NORMAL = 0x20,
|
||||
HID_USAGE_PID_SET_EFFECT_REPORT = 0x21,
|
||||
HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_INDEX = 0x22,
|
||||
HID_USAGE_PID_PARAMETER_BLOCK_OFFSET = 0x23,
|
||||
HID_USAGE_PID_ROM_FLAG = 0x24,
|
||||
HID_USAGE_PID_EFFECT_TYPE = 0x25,
|
||||
HID_USAGE_PID_ET_CONSTANTFORCE = 0x26,
|
||||
HID_USAGE_PID_ET_RAMP = 0x27,
|
||||
HID_USAGE_PID_ET_CUSTOMFORCE = 0x28,
|
||||
HID_USAGE_PID_ET_SQUARE = 0x30,
|
||||
HID_USAGE_PID_ET_SINE = 0x31,
|
||||
HID_USAGE_PID_ET_TRIANGLE = 0x32,
|
||||
HID_USAGE_PID_ET_SAWTOOTH_UP = 0x33,
|
||||
HID_USAGE_PID_ET_SAWTOOTH_DOWN = 0x34,
|
||||
HID_USAGE_PID_ET_SPRING = 0x40,
|
||||
HID_USAGE_PID_ET_DAMPER = 0x41,
|
||||
HID_USAGE_PID_ET_INERTIA = 0x42,
|
||||
HID_USAGE_PID_ET_FRICTION = 0x43,
|
||||
HID_USAGE_PID_DURATION = 0x50,
|
||||
HID_USAGE_PID_SAMPLE_PERIOD = 0x51,
|
||||
HID_USAGE_PID_GAIN = 0x52,
|
||||
HID_USAGE_PID_TRIGGER_BUTTON = 0x53,
|
||||
HID_USAGE_PID_TRIGGER_REPEAT_INTERVAL = 0x54,
|
||||
HID_USAGE_PID_AXES_ENABLE = 0x55,
|
||||
HID_USAGE_PID_DIRECTION_ENABLE = 0x56,
|
||||
HID_USAGE_PID_DIRECTION = 0x57,
|
||||
HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_OFFSET = 0x58,
|
||||
HID_USAGE_PID_BLOCK_TYPE = 0x59,
|
||||
HID_USAGE_PID_SET_ENVELOPE_REPORT = 0x5a,
|
||||
HID_USAGE_PID_ATTACK_LEVEL = 0x5b,
|
||||
HID_USAGE_PID_ATTACK_TIME = 0x5c,
|
||||
HID_USAGE_PID_FADE_LEVEL = 0x5d,
|
||||
HID_USAGE_PID_FADE_TIME = 0x5e,
|
||||
HID_USAGE_PID_SET_CONDITION_REPORT = 0x5f,
|
||||
HID_USAGE_PID_CENTERPOINT_OFFSET = 0x60,
|
||||
HID_USAGE_PID_POSITIVE_COEFFICIENT = 0x61,
|
||||
HID_USAGE_PID_NEGATIVE_COEFFICIENT = 0x62,
|
||||
HID_USAGE_PID_POSITIVE_SATURATION = 0x63,
|
||||
HID_USAGE_PID_NEGATIVE_SATURATION = 0x64,
|
||||
HID_USAGE_PID_DEAD_BAND = 0x65,
|
||||
HID_USAGE_PID_DOWNLOAD_FORCE_SAMPLE = 0x66,
|
||||
HID_USAGE_PID_ISOCH_CUSTOMFORCE_ENABLE = 0x67,
|
||||
HID_USAGE_PID_CUSTOMFORCE_DATA_REPORT = 0x68,
|
||||
HID_USAGE_PID_CUSTOMFORCE_DATA = 0x69,
|
||||
HID_USAGE_PID_CUSTOMFORCE_VENDOR_DEFINED_DATA = 0x6a,
|
||||
HID_USAGE_PID_SET_CUSTOMFORCE_REPORT = 0x6b,
|
||||
HID_USAGE_PID_CUSTOMFORCE_DATA_OFFSET = 0x6c,
|
||||
HID_USAGE_PID_SAMPLE_COUNT = 0x6d,
|
||||
HID_USAGE_PID_SET_PERIODIC_REPORT = 0x6e,
|
||||
HID_USAGE_PID_OFFSET = 0x6f,
|
||||
HID_USAGE_PID_MAGNITUDE = 0x70,
|
||||
HID_USAGE_PID_PHASE = 0x71,
|
||||
HID_USAGE_PID_PERIOD = 0x72,
|
||||
HID_USAGE_PID_SET_CONSTANTFORCE_REPORT = 0x73,
|
||||
HID_USAGE_PID_SET_RAMPFORCE_REPORT = 0x74,
|
||||
HID_USAGE_PID_RAMP_START = 0x75,
|
||||
HID_USAGE_PID_RAMP_END = 0x76,
|
||||
HID_USAGE_PID_EFFECT_OPERATION_REPORT = 0x77,
|
||||
HID_USAGE_PID_EFFECT_OPERATION = 0x78,
|
||||
HID_USAGE_PID_OP_EFFECT_START = 0x79,
|
||||
HID_USAGE_PID_OP_EFFECT_START_SOLO = 0x7a,
|
||||
HID_USAGE_PID_OP_EFFECT_STOP = 0x7b,
|
||||
HID_USAGE_PID_LOOP_COUNT = 0x7c,
|
||||
HID_USAGE_PID_DEVICE_GAIN_REPORT = 0x7d,
|
||||
HID_USAGE_PID_DEVICE_GAIN = 0x7e,
|
||||
HID_USAGE_PID_PARAMETER_BLOCK_POOLS_REPORT = 0x7f,
|
||||
HID_USAGE_PID_RAM_POOL_SIZE = 0x80,
|
||||
HID_USAGE_PID_ROM_POOL_SIZE = 0x81,
|
||||
HID_USAGE_PID_ROM_EFFECT_BLOCK_COUNT = 0x82,
|
||||
HID_USAGE_PID_SIMULTANEOUS_EFFECTS_MAX = 0x83,
|
||||
HID_USAGE_PID_POOL_ALIGNMENT = 0x84,
|
||||
HID_USAGE_PID_PARAMETER_BLOCK_MOVE_REPORT = 0x85,
|
||||
HID_USAGE_PID_MOVE_SOURCE = 0x86,
|
||||
HID_USAGE_PID_MOVE_DESTINATION = 0x87,
|
||||
HID_USAGE_PID_MOVE_LENGTH = 0x88,
|
||||
HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_REPORT = 0x89,
|
||||
HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_LOAD_STATUS = 0x8b,
|
||||
HID_USAGE_PID_BLOCK_LOAD_SUCCESS = 0x8c,
|
||||
HID_USAGE_PID_BLOCK_LOAD_FULL = 0x8d,
|
||||
HID_USAGE_PID_BLOCK_LOAD_ERROR = 0x8e,
|
||||
HID_USAGE_PID_BLOCK_HANDLE = 0x8f,
|
||||
HID_USAGE_PID_EFFECT_PARAMETER_BLOCK_FREE_REPORT = 0x90,
|
||||
HID_USAGE_PID_TYPE_SPECIFIC_BLOCK_HANDLE = 0x91,
|
||||
HID_USAGE_PID_PID_STATE_REPORT = 0x92,
|
||||
HID_USAGE_PID_EFFECT_PLAYING = 0x94,
|
||||
HID_USAGE_PID_PID_DEVICE_CONTROL_REPORT = 0x95,
|
||||
HID_USAGE_PID_PID_DEVICE_CONTROL = 0x96,
|
||||
HID_USAGE_PID_DC_ENABLE_ACTUATORS = 0x97,
|
||||
HID_USAGE_PID_DC_DISABLE_ACTUATORS = 0x98,
|
||||
HID_USAGE_PID_DC_STOP_ALL_EFFECTS = 0x99,
|
||||
HID_USAGE_PID_DC_RESET = 0x9a,
|
||||
HID_USAGE_PID_DC_PAUSE = 0x9b,
|
||||
HID_USAGE_PID_DC_CONTINUE = 0x9c,
|
||||
HID_USAGE_PID_DEVICE_PAUSED = 0x9f,
|
||||
HID_USAGE_PID_ACTUATORS_ENABLED = 0xa0,
|
||||
HID_USAGE_PID_SAFETY_SWITCH = 0xa4,
|
||||
HID_USAGE_PID_ACTUATOR_OVERRIDE_SWITCH = 0xa5,
|
||||
HID_USAGE_PID_ACTUATOR_POWER = 0xa6,
|
||||
HID_USAGE_PID_START_DELAY = 0xa7,
|
||||
HID_USAGE_PID_PARAMETER_BLOCK_SIZE = 0xa8,
|
||||
HID_USAGE_PID_DEVICEMANAGED_POOL = 0xa9,
|
||||
HID_USAGE_PID_SHARED_PARAMETER_BLOCKS = 0xaa,
|
||||
HID_USAGE_PID_CREATE_NEW_EFFECT_PARAMETER_BLOCK_REPORT = 0xab,
|
||||
HID_USAGE_PID_RAM_POOL_AVAILABLE = 0xac,
|
||||
};
|
||||
|
||||
/// HID Usage Table - Lighting And Illumination Page (0x59)
|
||||
enum {
|
||||
HID_USAGE_LIGHTING_LAMP_ARRAY = 0x01,
|
||||
|
|
|
|||
|
|
@ -51,14 +51,17 @@ typedef struct {
|
|||
|
||||
// TODO save hid descriptor since host can specifically request this after enumeration
|
||||
// Note: HID descriptor may be not available from application after enumeration
|
||||
tusb_hid_descriptor_hid_t const *hid_descriptor;
|
||||
|
||||
uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
|
||||
const tusb_hid_descriptor_hid_t*hid_descriptor;
|
||||
} hidd_interface_t;
|
||||
|
||||
CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
|
||||
typedef struct {
|
||||
TUD_EPBUF_DEF(ctrl , CFG_TUD_HID_EP_BUFSIZE);
|
||||
TUD_EPBUF_DEF(epin , CFG_TUD_HID_EP_BUFSIZE);
|
||||
TUD_EPBUF_DEF(epout, CFG_TUD_HID_EP_BUFSIZE);
|
||||
} hidd_epbuf_t;
|
||||
|
||||
static hidd_interface_t _hidd_itf[CFG_TUD_HID];
|
||||
CFG_TUD_MEM_SECTION static hidd_epbuf_t _hidd_epbuf[CFG_TUD_HID];
|
||||
|
||||
/*------------- Helpers -------------*/
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t get_index_by_itfnum(uint8_t itf_num) {
|
||||
|
|
@ -108,22 +111,24 @@ bool tud_hid_n_ready(uint8_t instance) {
|
|||
}
|
||||
|
||||
bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len) {
|
||||
uint8_t const rhport = 0;
|
||||
TU_VERIFY(instance < CFG_TUD_HID);
|
||||
const uint8_t rhport = 0;
|
||||
hidd_interface_t *p_hid = &_hidd_itf[instance];
|
||||
hidd_epbuf_t *p_epbuf = &_hidd_epbuf[instance];
|
||||
|
||||
// claim endpoint
|
||||
TU_VERIFY(usbd_edpt_claim(rhport, p_hid->ep_in));
|
||||
|
||||
// prepare data
|
||||
if (report_id) {
|
||||
p_hid->epin_buf[0] = report_id;
|
||||
TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf + 1, CFG_TUD_HID_EP_BUFSIZE - 1, report, len));
|
||||
p_epbuf->epin[0] = report_id;
|
||||
TU_VERIFY(0 == tu_memcpy_s(p_epbuf->epin + 1, CFG_TUD_HID_EP_BUFSIZE - 1, report, len));
|
||||
len++;
|
||||
} else {
|
||||
TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len));
|
||||
TU_VERIFY(0 == tu_memcpy_s(p_epbuf->epin, CFG_TUD_HID_EP_BUFSIZE, report, len));
|
||||
}
|
||||
|
||||
return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len);
|
||||
return usbd_edpt_xfer(rhport, p_hid->ep_in, p_epbuf->epin, len);
|
||||
}
|
||||
|
||||
uint8_t tud_hid_n_interface_protocol(uint8_t instance) {
|
||||
|
|
@ -189,6 +194,16 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
|
|||
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
||||
}
|
||||
|
||||
bool tud_hid_n_stylus_report(uint8_t instance, uint8_t report_id, uint8_t attrs, uint16_t x, uint16_t y) {
|
||||
hid_stylus_report_t report = {
|
||||
.attr = attrs,
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-CLASS API
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -214,15 +229,16 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16
|
|||
TU_ASSERT(max_len >= drv_len, 0);
|
||||
|
||||
// Find available interface
|
||||
hidd_interface_t *p_hid = NULL;
|
||||
hidd_interface_t *p_hid;
|
||||
uint8_t hid_id;
|
||||
for (hid_id = 0; hid_id < CFG_TUD_HID; hid_id++) {
|
||||
if (_hidd_itf[hid_id].ep_in == 0) {
|
||||
p_hid = &_hidd_itf[hid_id];
|
||||
p_hid = &_hidd_itf[hid_id];
|
||||
if (p_hid->ep_in == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_ASSERT(p_hid, 0);
|
||||
TU_ASSERT(hid_id < CFG_TUD_HID, 0);
|
||||
hidd_epbuf_t *p_epbuf = &_hidd_epbuf[hid_id];
|
||||
|
||||
uint8_t const *p_desc = (uint8_t const *)desc_itf;
|
||||
|
||||
|
|
@ -247,10 +263,7 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16
|
|||
|
||||
// Prepare for output endpoint
|
||||
if (p_hid->ep_out) {
|
||||
if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) {
|
||||
TU_LOG_FAILED();
|
||||
TU_BREAKPOINT();
|
||||
}
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_epbuf->epout, CFG_TUD_HID_EP_BUFSIZE), drv_len);
|
||||
}
|
||||
|
||||
return drv_len;
|
||||
|
|
@ -264,8 +277,8 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
|
||||
uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex);
|
||||
TU_VERIFY(hid_itf < CFG_TUD_HID);
|
||||
|
||||
hidd_interface_t *p_hid = &_hidd_itf[hid_itf];
|
||||
hidd_epbuf_t *p_epbuf = &_hidd_epbuf[hid_itf];
|
||||
|
||||
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
|
||||
//------------- STD Request -------------//
|
||||
|
|
@ -291,7 +304,7 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
uint8_t const report_type = tu_u16_high(request->wValue);
|
||||
uint8_t const report_id = tu_u16_low(request->wValue);
|
||||
|
||||
uint8_t* report_buf = p_hid->ctrl_buf;
|
||||
uint8_t* report_buf = p_epbuf->ctrl;
|
||||
uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
|
||||
uint16_t xferlen = 0;
|
||||
|
||||
|
|
@ -305,19 +318,19 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
|
||||
TU_ASSERT(xferlen > 0);
|
||||
|
||||
tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen);
|
||||
tud_control_xfer(rhport, request, p_epbuf->ctrl, xferlen);
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_REQ_CONTROL_SET_REPORT:
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf));
|
||||
tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength);
|
||||
TU_VERIFY(request->wLength <= CFG_TUD_HID_EP_BUFSIZE);
|
||||
tud_control_xfer(rhport, request, p_epbuf->ctrl, request->wLength);
|
||||
} else if (stage == CONTROL_STAGE_ACK) {
|
||||
uint8_t const report_type = tu_u16_high(request->wValue);
|
||||
uint8_t const report_id = tu_u16_low(request->wValue);
|
||||
|
||||
uint8_t const* report_buf = p_hid->ctrl_buf;
|
||||
uint8_t const* report_buf = p_epbuf->ctrl;
|
||||
uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
|
||||
|
||||
// If host request a specific Report ID, extract report ID in buffer before invoking callback
|
||||
|
|
@ -371,8 +384,8 @@ bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
}
|
||||
|
||||
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
uint8_t instance = 0;
|
||||
hidd_interface_t *p_hid = _hidd_itf;
|
||||
uint8_t instance;
|
||||
hidd_interface_t *p_hid;
|
||||
|
||||
// Identify which interface to use
|
||||
for (instance = 0; instance < CFG_TUD_HID; instance++) {
|
||||
|
|
@ -382,24 +395,25 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
|
|||
}
|
||||
}
|
||||
TU_ASSERT(instance < CFG_TUD_HID);
|
||||
hidd_epbuf_t *p_epbuf = &_hidd_epbuf[instance];
|
||||
|
||||
if (ep_addr == p_hid->ep_in) {
|
||||
// Input report
|
||||
if (XFER_RESULT_SUCCESS == result) {
|
||||
tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes);
|
||||
tud_hid_report_complete_cb(instance, p_epbuf->epin, (uint16_t) xferred_bytes);
|
||||
} else {
|
||||
tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_INPUT, p_hid->epin_buf, (uint16_t) xferred_bytes);
|
||||
tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_INPUT, p_epbuf->epin, (uint16_t) xferred_bytes);
|
||||
}
|
||||
} else {
|
||||
// Output report
|
||||
if (XFER_RESULT_SUCCESS == result) {
|
||||
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes);
|
||||
tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_epbuf->epout, (uint16_t)xferred_bytes);
|
||||
} else {
|
||||
tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t) xferred_bytes);
|
||||
tud_hid_report_failed_cb(instance, HID_REPORT_TYPE_OUTPUT, p_epbuf->epout, (uint16_t) xferred_bytes);
|
||||
}
|
||||
|
||||
// prepare for new transfer
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
|
||||
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_epbuf->epout, CFG_TUD_HID_EP_BUFSIZE));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t but
|
|||
// use template layout report TUD_HID_REPORT_DESC_GAMEPAD
|
||||
bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
|
||||
|
||||
// STYLUS PEN: convenient helper to send absolute stylus pen report if application
|
||||
bool tud_hid_n_stylus_report(uint8_t instance, uint8_t report_id, uint8_t attrs, uint16_t x, uint16_t y);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application API (Single Port)
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -114,6 +117,10 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_gamepad_report(uint8_t report_i
|
|||
return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool tud_hid_stylus_report(uint8_t report_id, uint8_t attrs, uint16_t x, uint16_t y) {
|
||||
return tud_hid_n_stylus_report(0, report_id, attrs, x, y);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -257,6 +264,41 @@ void tud_hid_report_failed_cb(uint8_t instance, hid_report_type_t report_type, u
|
|||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Stylus Pen Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_STYLUS_PEN(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DIGITIZER ) , \
|
||||
HID_USAGE ( HID_USAGE_DIGITIZER_TOUCH_SCREEN ) , \
|
||||
HID_COLLECTION ( HID_COLLECTION_APPLICATION ) , \
|
||||
/* Report ID if any */\
|
||||
__VA_ARGS__ \
|
||||
HID_USAGE ( HID_USAGE_DIGITIZER_STYLUS ) , \
|
||||
HID_COLLECTION ( HID_COLLECTION_PHYSICAL ) , \
|
||||
HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_TIP_SWITCH ) , \
|
||||
HID_USAGE_PAGE ( HID_USAGE_DIGITIZER_IN_RANGE ) , \
|
||||
HID_LOGICAL_MIN ( 0 ), \
|
||||
HID_LOGICAL_MAX ( 1 ), \
|
||||
HID_REPORT_SIZE ( 1 ), \
|
||||
HID_REPORT_COUNT( 2 ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), \
|
||||
HID_REPORT_SIZE ( 1 ), \
|
||||
HID_REPORT_COUNT( 6 ), \
|
||||
HID_INPUT ( HID_CONSTANT | HID_ARRAY | HID_ABSOLUTE), \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ), \
|
||||
HID_PHYSICAL_MAX_N( 0x7fff, 2 ), \
|
||||
HID_LOGICAL_MAX_N ( 0x7fff, 2 ), \
|
||||
HID_REPORT_SIZE ( 16 ), \
|
||||
HID_REPORT_COUNT( 1 ), \
|
||||
HID_UNIT_EXPONENT( 0x0f ), \
|
||||
HID_UNIT ( HID_VARIABLE | HID_NONLINEAR ), \
|
||||
HID_PHYSICAL_MIN( 0 ), \
|
||||
HID_PHYSICAL_MAX( 0 ), \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_X ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), \
|
||||
HID_USAGE ( HID_USAGE_DESKTOP_Y ), \
|
||||
HID_INPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ), \
|
||||
HID_COLLECTION_END , \
|
||||
HID_COLLECTION_END \
|
||||
|
||||
// Absolute Mouse Report Descriptor Template
|
||||
#define TUD_HID_REPORT_DESC_ABSMOUSE(...) \
|
||||
HID_USAGE_PAGE ( HID_USAGE_PAGE_DESKTOP ) ,\
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUH_ENABLED && CFG_TUH_HID)
|
||||
|
|
@ -50,12 +45,11 @@
|
|||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint8_t daddr;
|
||||
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
bool mounted; // Enumeration is complete
|
||||
|
||||
bool mounted; // Enumeration is complete
|
||||
uint8_t itf_protocol; // None, Keyboard, Mouse
|
||||
uint8_t protocol_mode; // Boot (0) or Report protocol (1)
|
||||
|
||||
|
|
@ -64,15 +58,17 @@ typedef struct {
|
|||
|
||||
uint16_t epin_size;
|
||||
uint16_t epout_size;
|
||||
|
||||
CFG_TUH_MEM_ALIGN uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE];
|
||||
CFG_TUH_MEM_ALIGN uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE];
|
||||
} hidh_interface_t;
|
||||
|
||||
CFG_TUH_MEM_SECTION
|
||||
tu_static hidh_interface_t _hidh_itf[CFG_TUH_HID];
|
||||
typedef struct {
|
||||
TUH_EPBUF_DEF(epin, CFG_TUH_HID_EPIN_BUFSIZE);
|
||||
TUH_EPBUF_DEF(epout, CFG_TUH_HID_EPOUT_BUFSIZE);
|
||||
} hidh_epbuf_t;
|
||||
|
||||
tu_static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT;
|
||||
static hidh_interface_t _hidh_itf[CFG_TUH_HID];
|
||||
CFG_TUH_MEM_SECTION static hidh_epbuf_t _hidh_epbuf[CFG_TUH_HID];
|
||||
|
||||
static uint8_t _hidh_default_protocol = HID_PROTOCOL_BOOT;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Helper
|
||||
|
|
@ -83,6 +79,10 @@ TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_hid_itf(uint8_t daddr,
|
|||
return (p_hid->daddr == daddr) ? p_hid : NULL;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline hidh_epbuf_t* get_hid_epbuf(uint8_t idx) {
|
||||
return &_hidh_epbuf[idx];
|
||||
}
|
||||
|
||||
// Get instance ID by endpoint address
|
||||
static uint8_t get_idx_by_epaddr(uint8_t daddr, uint8_t ep_addr) {
|
||||
for (uint8_t idx = 0; idx < CFG_TUH_HID; idx++) {
|
||||
|
|
@ -358,11 +358,12 @@ bool tuh_hid_receive_ready(uint8_t dev_addr, uint8_t idx) {
|
|||
bool tuh_hid_receive_report(uint8_t daddr, uint8_t idx) {
|
||||
hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
|
||||
TU_VERIFY(p_hid);
|
||||
hidh_epbuf_t* epbuf = get_hid_epbuf(idx);
|
||||
|
||||
// claim endpoint
|
||||
TU_VERIFY(usbh_edpt_claim(daddr, p_hid->ep_in));
|
||||
|
||||
if (!usbh_edpt_xfer(daddr, p_hid->ep_in, p_hid->epin_buf, p_hid->epin_size)) {
|
||||
if (!usbh_edpt_xfer(daddr, p_hid->ep_in, epbuf->epin, p_hid->epin_size)) {
|
||||
usbh_edpt_release(daddr, p_hid->ep_in);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -386,6 +387,7 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo
|
|||
|
||||
hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
|
||||
TU_VERIFY(p_hid);
|
||||
hidh_epbuf_t* epbuf = get_hid_epbuf(idx);
|
||||
|
||||
if (p_hid->ep_out == 0) {
|
||||
// This HID does not have an out endpoint (other than control)
|
||||
|
|
@ -401,16 +403,16 @@ bool tuh_hid_send_report(uint8_t daddr, uint8_t idx, uint8_t report_id, const vo
|
|||
|
||||
if (report_id == 0) {
|
||||
// No report ID in transmission
|
||||
memcpy(&p_hid->epout_buf[0], report, len);
|
||||
memcpy(&epbuf->epout[0], report, len);
|
||||
} else {
|
||||
p_hid->epout_buf[0] = report_id;
|
||||
memcpy(&p_hid->epout_buf[1], report, len);
|
||||
epbuf->epout[0] = report_id;
|
||||
memcpy(&epbuf->epout[1], report, len);
|
||||
++len; // 1 more byte for report_id
|
||||
}
|
||||
|
||||
TU_LOG3_MEM(p_hid->epout_buf, len, 2);
|
||||
TU_LOG3_MEM(epbuf->epout, len, 2);
|
||||
|
||||
if (!usbh_edpt_xfer(daddr, p_hid->ep_out, p_hid->epout_buf, len)) {
|
||||
if (!usbh_edpt_xfer(daddr, p_hid->ep_out, epbuf->epout, len)) {
|
||||
usbh_edpt_release(daddr, p_hid->ep_out);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -439,14 +441,15 @@ bool hidh_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
|
|||
|
||||
hidh_interface_t* p_hid = get_hid_itf(daddr, idx);
|
||||
TU_VERIFY(p_hid);
|
||||
hidh_epbuf_t* epbuf = get_hid_epbuf(idx);
|
||||
|
||||
if (dir == TUSB_DIR_IN) {
|
||||
TU_LOG_DRV(" Get Report callback (%u, %u)\r\n", daddr, idx);
|
||||
TU_LOG3_MEM(p_hid->epin_buf, xferred_bytes, 2);
|
||||
tuh_hid_report_received_cb(daddr, idx, p_hid->epin_buf, (uint16_t) xferred_bytes);
|
||||
TU_LOG3_MEM(epbuf->epin, xferred_bytes, 2);
|
||||
tuh_hid_report_received_cb(daddr, idx, epbuf->epin, (uint16_t) xferred_bytes);
|
||||
} else {
|
||||
if (tuh_hid_report_sent_cb) {
|
||||
tuh_hid_report_sent_cb(daddr, idx, p_hid->epout_buf, (uint16_t) xferred_bytes);
|
||||
tuh_hid_report_sent_cb(daddr, idx, epbuf->epout, (uint16_t) xferred_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_MIDI)
|
||||
|
|
@ -45,15 +40,13 @@
|
|||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t buffer[4];
|
||||
uint8_t index;
|
||||
uint8_t total;
|
||||
}midid_stream_t;
|
||||
} midid_stream_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
|
@ -75,36 +68,36 @@ typedef struct
|
|||
osal_mutex_def_t rx_ff_mutex;
|
||||
osal_mutex_def_t tx_ff_mutex;
|
||||
#endif
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_MIDI_EP_BUFSIZE];
|
||||
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_MIDI_EP_BUFSIZE];
|
||||
|
||||
} midid_interface_t;
|
||||
|
||||
#define ITF_MEM_RESET_SIZE offsetof(midid_interface_t, rx_ff)
|
||||
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUD_MEM_SECTION static struct {
|
||||
TUD_EPBUF_DEF(epin, CFG_TUD_MIDI_EP_BUFSIZE);
|
||||
TUD_EPBUF_DEF(epout, CFG_TUD_MIDI_EP_BUFSIZE);
|
||||
} _midid_epbuf[CFG_TUD_MIDI];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUD_MEM_SECTION midid_interface_t _midid_itf[CFG_TUD_MIDI];
|
||||
static midid_interface_t _midid_itf[CFG_TUD_MIDI];
|
||||
|
||||
bool tud_midi_n_mounted (uint8_t itf)
|
||||
{
|
||||
bool tud_midi_n_mounted (uint8_t itf) {
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
return midi->ep_in && midi->ep_out;
|
||||
}
|
||||
|
||||
static void _prep_out_transaction (midid_interface_t* p_midi)
|
||||
{
|
||||
uint8_t const rhport = 0;
|
||||
static void _prep_out_transaction(uint8_t idx) {
|
||||
const uint8_t rhport = 0;
|
||||
midid_interface_t* p_midi = &_midid_itf[idx];
|
||||
uint16_t available = tu_fifo_remaining(&p_midi->rx_ff);
|
||||
|
||||
// Prepare for incoming data but only allow what we can store in the ring buffer.
|
||||
// TODO Actually we can still carry out the transfer, keeping count of received bytes
|
||||
// and slowly move it to the FIFO when read().
|
||||
// This pre-check reduces endpoint claiming
|
||||
TU_VERIFY(available >= sizeof(p_midi->epout_buf), );
|
||||
TU_VERIFY(available >= CFG_TUD_MIDI_EP_BUFSIZE, );
|
||||
|
||||
// claim endpoint
|
||||
TU_VERIFY(usbd_edpt_claim(rhport, p_midi->ep_out), );
|
||||
|
|
@ -112,8 +105,8 @@ static void _prep_out_transaction (midid_interface_t* p_midi)
|
|||
// fifo can be changed before endpoint is claimed
|
||||
available = tu_fifo_remaining(&p_midi->rx_ff);
|
||||
|
||||
if ( available >= sizeof(p_midi->epout_buf) ) {
|
||||
usbd_edpt_xfer(rhport, p_midi->ep_out, p_midi->epout_buf, sizeof(p_midi->epout_buf));
|
||||
if ( available >= CFG_TUD_MIDI_EP_BUFSIZE ) {
|
||||
usbd_edpt_xfer(rhport, p_midi->ep_out, _midid_epbuf[idx].epout, CFG_TUD_MIDI_EP_BUFSIZE);
|
||||
}else
|
||||
{
|
||||
// Release endpoint since we don't make any transfer
|
||||
|
|
@ -129,7 +122,7 @@ uint32_t tud_midi_n_available(uint8_t itf, uint8_t cable_num)
|
|||
(void) cable_num;
|
||||
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
midid_stream_t const* stream = &midi->stream_read;
|
||||
const midid_stream_t* stream = &midi->stream_read;
|
||||
|
||||
// when using with packet API stream total & index are both zero
|
||||
return tu_fifo_count(&midi->rx_ff) + (uint8_t) (stream->total - stream->index);
|
||||
|
|
@ -210,8 +203,8 @@ bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
|
|||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
TU_VERIFY(midi->ep_out);
|
||||
|
||||
uint32_t const num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4);
|
||||
_prep_out_transaction(midi);
|
||||
const uint32_t num_read = tu_fifo_read_n(&midi->rx_ff, packet, 4);
|
||||
_prep_out_transaction(itf);
|
||||
return (num_read == 4);
|
||||
}
|
||||
|
||||
|
|
@ -219,31 +212,31 @@ bool tud_midi_n_packet_read (uint8_t itf, uint8_t packet[4])
|
|||
// WRITE API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static uint32_t write_flush(midid_interface_t* midi)
|
||||
{
|
||||
// No data to send
|
||||
if ( !tu_fifo_count(&midi->tx_ff) ) return 0;
|
||||
static uint32_t write_flush(uint8_t idx) {
|
||||
midid_interface_t* midi = &_midid_itf[idx];
|
||||
|
||||
uint8_t const rhport = 0;
|
||||
if (!tu_fifo_count(&midi->tx_ff)) {
|
||||
return 0; // No data to send
|
||||
}
|
||||
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
// skip if previous transfer not complete
|
||||
TU_VERIFY( usbd_edpt_claim(rhport, midi->ep_in), 0 );
|
||||
|
||||
uint16_t count = tu_fifo_read_n(&midi->tx_ff, midi->epin_buf, CFG_TUD_MIDI_EP_BUFSIZE);
|
||||
uint16_t count = tu_fifo_read_n(&midi->tx_ff, _midid_epbuf[idx].epin, CFG_TUD_MIDI_EP_BUFSIZE);
|
||||
|
||||
if (count)
|
||||
{
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, midi->epin_buf, count), 0 );
|
||||
if (count) {
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, midi->ep_in, _midid_epbuf[idx].epin, count), 0 );
|
||||
return count;
|
||||
}else
|
||||
{
|
||||
}else {
|
||||
// Release endpoint since we don't make any transfer
|
||||
usbd_edpt_release(rhport, midi->ep_in);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const* buffer, uint32_t bufsize)
|
||||
uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, const uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
TU_VERIFY(midi->ep_in, 0);
|
||||
|
|
@ -253,14 +246,13 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
|
|||
uint32_t i = 0;
|
||||
while ( (i < bufsize) && (tu_fifo_remaining(&midi->tx_ff) >= 4) )
|
||||
{
|
||||
uint8_t const data = buffer[i];
|
||||
const uint8_t data = buffer[i];
|
||||
i++;
|
||||
|
||||
if ( stream->index == 0 )
|
||||
{
|
||||
//------------- New event packet -------------//
|
||||
|
||||
uint8_t const msg = data >> 4;
|
||||
const uint8_t msg = data >> 4;
|
||||
|
||||
stream->index = 2;
|
||||
stream->buffer[1] = data;
|
||||
|
|
@ -345,9 +337,11 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
|
|||
if ( stream->index == stream->total )
|
||||
{
|
||||
// zeroes unused bytes
|
||||
for(uint8_t idx = stream->total; idx < 4; idx++) stream->buffer[idx] = 0;
|
||||
for (uint8_t idx = stream->total; idx < 4; idx++) {
|
||||
stream->buffer[idx] = 0;
|
||||
}
|
||||
|
||||
uint16_t const count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4);
|
||||
const uint16_t count = tu_fifo_write_n(&midi->tx_ff, stream->buffer, 4);
|
||||
|
||||
// complete current event packet, reset stream
|
||||
stream->index = stream->total = 0;
|
||||
|
|
@ -357,20 +351,21 @@ uint32_t tud_midi_n_stream_write(uint8_t itf, uint8_t cable_num, uint8_t const*
|
|||
}
|
||||
}
|
||||
|
||||
write_flush(midi);
|
||||
write_flush(itf);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
bool tud_midi_n_packet_write (uint8_t itf, uint8_t const packet[4])
|
||||
{
|
||||
bool tud_midi_n_packet_write (uint8_t itf, const uint8_t packet[4]) {
|
||||
midid_interface_t* midi = &_midid_itf[itf];
|
||||
TU_VERIFY(midi->ep_in);
|
||||
|
||||
if (tu_fifo_remaining(&midi->tx_ff) < 4) return false;
|
||||
if (tu_fifo_remaining(&midi->tx_ff) < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
tu_fifo_write_n(&midi->tx_ff, packet, 4);
|
||||
write_flush(midi);
|
||||
write_flush(itf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -434,7 +429,7 @@ void midid_reset(uint8_t rhport)
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len)
|
||||
uint16_t midid_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len)
|
||||
{
|
||||
// 1st Interface is Audio Control v1
|
||||
TU_VERIFY(TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass &&
|
||||
|
|
@ -442,7 +437,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
|
|||
AUDIO_FUNC_PROTOCOL_CODE_UNDEF == desc_itf->bInterfaceProtocol, 0);
|
||||
|
||||
uint16_t drv_len = tu_desc_len(desc_itf);
|
||||
uint8_t const * p_desc = tu_desc_next(desc_itf);
|
||||
const uint8_t* p_desc = tu_desc_next(desc_itf);
|
||||
|
||||
// Skip Class Specific descriptors
|
||||
while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
|
||||
|
|
@ -453,7 +448,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
|
|||
|
||||
// 2nd Interface is MIDI Streaming
|
||||
TU_VERIFY(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0);
|
||||
tusb_desc_interface_t const * desc_midi = (tusb_desc_interface_t const *) p_desc;
|
||||
const tusb_desc_interface_t* desc_midi = (const tusb_desc_interface_t*) p_desc;
|
||||
|
||||
TU_VERIFY(TUSB_CLASS_AUDIO == desc_midi->bInterfaceClass &&
|
||||
AUDIO_SUBCLASS_MIDI_STREAMING == desc_midi->bInterfaceSubClass &&
|
||||
|
|
@ -461,11 +456,10 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
|
|||
|
||||
// Find available interface
|
||||
midid_interface_t * p_midi = NULL;
|
||||
for(uint8_t i=0; i<CFG_TUD_MIDI; i++)
|
||||
{
|
||||
if ( _midid_itf[i].ep_in == 0 && _midid_itf[i].ep_out == 0 )
|
||||
{
|
||||
p_midi = &_midid_itf[i];
|
||||
uint8_t idx;
|
||||
for(idx=0; idx<CFG_TUD_MIDI; idx++) {
|
||||
if ( _midid_itf[idx].ep_in == 0 && _midid_itf[idx].ep_out == 0 ) {
|
||||
p_midi = &_midid_itf[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -484,8 +478,8 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
|
|||
{
|
||||
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
||||
{
|
||||
TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0);
|
||||
uint8_t ep_addr = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
TU_ASSERT(usbd_edpt_open(rhport, (const tusb_desc_endpoint_t*) p_desc), 0);
|
||||
uint8_t ep_addr = ((const tusb_desc_endpoint_t*) p_desc)->bEndpointAddress;
|
||||
|
||||
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN)
|
||||
{
|
||||
|
|
@ -506,7 +500,7 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
|
|||
}
|
||||
|
||||
// Prepare for incoming data
|
||||
_prep_out_transaction(p_midi);
|
||||
_prep_out_transaction(idx);
|
||||
|
||||
return drv_len;
|
||||
}
|
||||
|
|
@ -514,14 +508,9 @@ uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint
|
|||
// Invoked when a control transfer occurred on an interface of this class
|
||||
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) stage;
|
||||
(void) request;
|
||||
|
||||
// driver doesn't support any request yet
|
||||
return false;
|
||||
bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_request_t* request) {
|
||||
(void) rhport; (void) stage; (void) request;
|
||||
return false; // driver doesn't support any request yet
|
||||
}
|
||||
|
||||
bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
|
|
@ -529,40 +518,37 @@ bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32
|
|||
(void) result;
|
||||
(void) rhport;
|
||||
|
||||
uint8_t itf;
|
||||
uint8_t idx;
|
||||
midid_interface_t* p_midi;
|
||||
|
||||
// Identify which interface to use
|
||||
for (itf = 0; itf < CFG_TUD_MIDI; itf++)
|
||||
{
|
||||
p_midi = &_midid_itf[itf];
|
||||
if ( ( ep_addr == p_midi->ep_out ) || ( ep_addr == p_midi->ep_in ) ) break;
|
||||
for (idx = 0; idx < CFG_TUD_MIDI; idx++) {
|
||||
p_midi = &_midid_itf[idx];
|
||||
if ((ep_addr == p_midi->ep_out) || (ep_addr == p_midi->ep_in)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_ASSERT(itf < CFG_TUD_MIDI);
|
||||
TU_ASSERT(idx < CFG_TUD_MIDI);
|
||||
|
||||
// receive new data
|
||||
if ( ep_addr == p_midi->ep_out )
|
||||
{
|
||||
tu_fifo_write_n(&p_midi->rx_ff, p_midi->epout_buf, (uint16_t) xferred_bytes);
|
||||
if (ep_addr == p_midi->ep_out) {
|
||||
tu_fifo_write_n(&p_midi->rx_ff, _midid_epbuf[idx].epout, (uint16_t)xferred_bytes);
|
||||
|
||||
// invoke receive callback if available
|
||||
if (tud_midi_rx_cb) tud_midi_rx_cb(itf);
|
||||
if (tud_midi_rx_cb) {
|
||||
tud_midi_rx_cb(idx);
|
||||
}
|
||||
|
||||
// prepare for next
|
||||
// TODO for now ep_out is not used by public API therefore there is no race condition,
|
||||
// and does not need to claim like ep_in
|
||||
_prep_out_transaction(p_midi);
|
||||
}
|
||||
else if ( ep_addr == p_midi->ep_in )
|
||||
{
|
||||
if (0 == write_flush(p_midi))
|
||||
{
|
||||
_prep_out_transaction(idx);
|
||||
} else if (ep_addr == p_midi->ep_in) {
|
||||
if (0 == write_flush(idx)) {
|
||||
// If there is no data left, a ZLP should be sent if
|
||||
// xferred_bytes is multiple of EP size and not zero
|
||||
if ( !tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE)) )
|
||||
{
|
||||
if ( usbd_edpt_claim(rhport, p_midi->ep_in) )
|
||||
{
|
||||
if (!tu_fifo_count(&p_midi->tx_ff) && xferred_bytes && (0 == (xferred_bytes % CFG_TUD_MIDI_EP_BUFSIZE))) {
|
||||
if (usbd_edpt_claim(rhport, p_midi->ep_in)) {
|
||||
usbd_edpt_xfer(rhport, p_midi->ep_in, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUH_ENABLED && CFG_TUH_MSC
|
||||
|
|
@ -59,38 +54,37 @@ typedef struct {
|
|||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
uint8_t max_lun;
|
||||
|
||||
volatile bool configured; // Receive SET_CONFIGURE
|
||||
volatile bool mounted; // Enumeration is complete
|
||||
|
||||
struct {
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
} capacity[CFG_TUH_MSC_MAXLUN];
|
||||
|
||||
//------------- SCSI -------------//
|
||||
// SCSI command data
|
||||
uint8_t stage;
|
||||
void* buffer;
|
||||
tuh_msc_complete_cb_t complete_cb;
|
||||
uintptr_t complete_arg;
|
||||
|
||||
CFG_TUH_MEM_ALIGN msc_cbw_t cbw;
|
||||
CFG_TUH_MEM_ALIGN msc_csw_t csw;
|
||||
struct {
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
} capacity[CFG_TUH_MSC_MAXLUN];
|
||||
} msch_interface_t;
|
||||
|
||||
CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
|
||||
typedef struct {
|
||||
TUH_EPBUF_TYPE_DEF(msc_cbw_t, cbw);
|
||||
TUH_EPBUF_TYPE_DEF(msc_csw_t, csw);
|
||||
} msch_epbuf_t;
|
||||
|
||||
// buffer used to read scsi information when mounted
|
||||
// largest response data currently is inquiry TODO Inquiry is not part of enum anymore
|
||||
CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN
|
||||
static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
|
||||
static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
|
||||
CFG_TUH_MEM_SECTION static msch_epbuf_t _msch_epbuf[CFG_TUH_DEVICE_MAX];
|
||||
|
||||
// FIXME potential nul reference
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
static inline msch_interface_t* get_itf(uint8_t dev_addr) {
|
||||
return &_msch_itf[dev_addr - 1];
|
||||
TU_ATTR_ALWAYS_INLINE static inline msch_interface_t* get_itf(uint8_t daddr) {
|
||||
return &_msch_itf[daddr - 1];
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline msch_epbuf_t* get_epbuf(uint8_t daddr) {
|
||||
return &_msch_epbuf[daddr - 1];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -138,14 +132,15 @@ bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data,
|
|||
|
||||
// claim endpoint
|
||||
TU_VERIFY(usbh_edpt_claim(daddr, p_msc->ep_out));
|
||||
msch_epbuf_t* epbuf = get_epbuf(daddr);
|
||||
|
||||
p_msc->cbw = *cbw;
|
||||
p_msc->stage = MSC_STAGE_CMD;
|
||||
epbuf->cbw = *cbw;
|
||||
p_msc->buffer = data;
|
||||
p_msc->complete_cb = complete_cb;
|
||||
p_msc->complete_arg = arg;
|
||||
p_msc->stage = MSC_STAGE_CMD;
|
||||
|
||||
if (!usbh_edpt_xfer(daddr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))) {
|
||||
if (!usbh_edpt_xfer(daddr, p_msc->ep_out, (uint8_t*) &epbuf->cbw, sizeof(msc_cbw_t))) {
|
||||
usbh_edpt_release(daddr, p_msc->ep_out);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -291,6 +286,7 @@ bool tuh_msc_reset(uint8_t dev_addr) {
|
|||
//--------------------------------------------------------------------+
|
||||
bool msch_init(void) {
|
||||
TU_LOG_DRV("sizeof(msch_interface_t) = %u\r\n", sizeof(msch_interface_t));
|
||||
TU_LOG_DRV("sizeof(msch_epbuf_t) = %u\r\n", sizeof(msch_epbuf_t));
|
||||
tu_memclr(_msch_itf, sizeof(_msch_itf));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -308,7 +304,9 @@ void msch_close(uint8_t dev_addr) {
|
|||
|
||||
// invoke Application Callback
|
||||
if (p_msc->mounted) {
|
||||
if (tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
|
||||
if (tuh_msc_umount_cb) {
|
||||
tuh_msc_umount_cb(dev_addr);
|
||||
}
|
||||
}
|
||||
|
||||
tu_memclr(p_msc, sizeof(msch_interface_t));
|
||||
|
|
@ -316,30 +314,28 @@ void msch_close(uint8_t dev_addr) {
|
|||
|
||||
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
msc_cbw_t const * cbw = &p_msc->cbw;
|
||||
msc_csw_t * csw = &p_msc->csw;
|
||||
msch_epbuf_t* epbuf = get_epbuf(dev_addr);
|
||||
msc_cbw_t const * cbw = &epbuf->cbw;
|
||||
msc_csw_t * csw = &epbuf->csw;
|
||||
|
||||
switch (p_msc->stage) {
|
||||
case MSC_STAGE_CMD:
|
||||
// Must be Command Block
|
||||
TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
|
||||
|
||||
if (cbw->total_bytes && p_msc->buffer) {
|
||||
// Data stage if any
|
||||
p_msc->stage = MSC_STAGE_DATA;
|
||||
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
|
||||
} else {
|
||||
// Status stage
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
TU_ATTR_FALLTHROUGH; // fallthrough to status stage
|
||||
|
||||
case MSC_STAGE_DATA:
|
||||
// Status stage
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) csw, (uint16_t) sizeof(msc_csw_t)));
|
||||
break;
|
||||
|
||||
case MSC_STAGE_STATUS:
|
||||
|
|
@ -404,10 +400,9 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* de
|
|||
return true;
|
||||
}
|
||||
|
||||
bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
bool msch_set_config(uint8_t daddr, uint8_t itf_num) {
|
||||
msch_interface_t* p_msc = get_itf(daddr);
|
||||
TU_ASSERT(p_msc->itf_num == itf_num);
|
||||
|
||||
p_msc->configured = true;
|
||||
|
||||
//------------- Get Max Lun -------------//
|
||||
|
|
@ -424,11 +419,12 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
|||
.wLength = 1
|
||||
};
|
||||
|
||||
uint8_t* enum_buf = usbh_get_enum_buf();
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = dev_addr,
|
||||
.daddr = daddr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
.buffer = _msch_buffer,
|
||||
.buffer = enum_buf,
|
||||
.complete_cb = config_get_maxlun_complete,
|
||||
.user_data = 0
|
||||
};
|
||||
|
|
@ -441,9 +437,13 @@ static void config_get_maxlun_complete(tuh_xfer_t* xfer) {
|
|||
uint8_t const daddr = xfer->daddr;
|
||||
msch_interface_t* p_msc = get_itf(daddr);
|
||||
|
||||
// STALL means zero
|
||||
p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0;
|
||||
p_msc->max_lun++; // MAX LUN is minus 1 by specs
|
||||
// MAXLUN's response is minus 1 by specs, STALL means 1
|
||||
if (XFER_RESULT_SUCCESS == xfer->result) {
|
||||
uint8_t* enum_buf = usbh_get_enum_buf();
|
||||
p_msc->max_lun = enum_buf[0] + 1;
|
||||
} else {
|
||||
p_msc->max_lun = 1;
|
||||
}
|
||||
|
||||
TU_LOG_DRV(" Max LUN = %u\r\n", p_msc->max_lun);
|
||||
|
||||
|
|
@ -456,18 +456,19 @@ static void config_get_maxlun_complete(tuh_xfer_t* xfer) {
|
|||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||
msc_cbw_t const* cbw = cb_data->cbw;
|
||||
msc_csw_t const* csw = cb_data->csw;
|
||||
uint8_t* enum_buf = usbh_get_enum_buf();
|
||||
|
||||
if (csw->status == 0) {
|
||||
// Unit is ready, read its capacity
|
||||
TU_LOG_DRV("SCSI Read Capacity\r\n");
|
||||
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer),
|
||||
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) (uintptr_t) enum_buf,
|
||||
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_LOG_DRV("SCSI Request Sense\r\n");
|
||||
TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, _msch_buffer, config_request_sense_complete, 0));
|
||||
TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, enum_buf, config_request_sense_complete, 0));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -485,19 +486,20 @@ static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_dat
|
|||
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||
msc_cbw_t const* cbw = cb_data->cbw;
|
||||
msc_csw_t const* csw = cb_data->csw;
|
||||
|
||||
TU_ASSERT(csw->status == 0);
|
||||
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
uint8_t* enum_buf = usbh_get_enum_buf();
|
||||
|
||||
// Capacity response field: Block size and Last LBA are both Big-Endian
|
||||
scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer);
|
||||
scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) (uintptr_t) enum_buf;
|
||||
p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1;
|
||||
p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
|
||||
|
||||
// Mark enumeration is complete
|
||||
p_msc->mounted = true;
|
||||
if (tuh_msc_mount_cb) tuh_msc_mount_cb(dev_addr);
|
||||
if (tuh_msc_mount_cb) {
|
||||
tuh_msc_mount_cb(dev_addr);
|
||||
}
|
||||
|
||||
// notify usbh that driver enumeration is complete
|
||||
usbh_driver_set_config_complete(dev_addr, p_msc->itf_num);
|
||||
|
|
|
|||
|
|
@ -73,10 +73,12 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
|
|||
// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
|
||||
// Complete callback is invoked when SCSI op is complete.
|
||||
// return true if success, false if there is already pending operation.
|
||||
// NOTE: buffer must be accessible by USB/DMA controller, aligned correctly and multiple of cache line if enabled
|
||||
bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
||||
|
||||
// Perform SCSI Inquiry command
|
||||
// Complete callback is invoked when SCSI op is complete.
|
||||
// NOTE: response must be accessible by USB/DMA controller, aligned correctly and multiple of cache line if enabled
|
||||
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
||||
|
||||
// Perform SCSI Test Unit Ready command
|
||||
|
|
@ -85,14 +87,17 @@ 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.
|
||||
// NOTE: response must be accessible by USB/DMA controller, aligned correctly and multiple of cache line if enabled
|
||||
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.
|
||||
// NOTE: buffer must be accessible by USB/DMA controller, aligned correctly and multiple of cache line if enabled
|
||||
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);
|
||||
|
||||
// Perform SCSI Write 10 command. Write n blocks starting from LBA to device
|
||||
// Complete callback is invoked when SCSI op is complete.
|
||||
// NOTE: buffer must be accessible by USB/DMA controller, aligned correctly and multiple of cache line if enabled
|
||||
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
||||
|
||||
// Perform SCSI Read Capacity 10 command
|
||||
|
|
@ -116,7 +121,7 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
|
|||
bool msch_init (void);
|
||||
bool msch_deinit (void);
|
||||
bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
|
||||
bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool msch_set_config (uint8_t daddr, uint8_t itf_num);
|
||||
void msch_close (uint8_t dev_addr);
|
||||
bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,18 @@
|
|||
#include "net_device.h"
|
||||
#include "rndis_protocol.h"
|
||||
|
||||
void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */
|
||||
extern void rndis_class_set_handler(uint8_t *data, int size); /* found in ./misc/networking/rndis_reports.c */
|
||||
|
||||
#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
|
||||
#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
|
||||
|
||||
#define NETD_PACKET_SIZE (CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN)
|
||||
#define NETD_CONTROL_SIZE 120
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface
|
||||
uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active
|
||||
|
||||
|
|
@ -55,78 +60,44 @@ typedef struct
|
|||
// 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;
|
||||
|
||||
} netd_interface_t;
|
||||
|
||||
#define CFG_TUD_NET_PACKET_PREFIX_LEN sizeof(rndis_data_packet_t)
|
||||
#define CFG_TUD_NET_PACKET_SUFFIX_LEN 0
|
||||
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static
|
||||
uint8_t received[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
|
||||
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static
|
||||
uint8_t transmitted[CFG_TUD_NET_PACKET_PREFIX_LEN + CFG_TUD_NET_MTU + CFG_TUD_NET_PACKET_PREFIX_LEN];
|
||||
|
||||
struct ecm_notify_struct
|
||||
{
|
||||
typedef struct ecm_notify_struct {
|
||||
tusb_control_request_t header;
|
||||
uint32_t downlink, uplink;
|
||||
};
|
||||
} ecm_notify_t;
|
||||
|
||||
tu_static const struct ecm_notify_struct ecm_notify_nc =
|
||||
{
|
||||
.header = {
|
||||
.bmRequestType = 0xA1,
|
||||
.bRequest = 0 /* NETWORK_CONNECTION aka NetworkConnection */,
|
||||
.wValue = 1 /* Connected */,
|
||||
.wLength = 0,
|
||||
},
|
||||
};
|
||||
typedef struct {
|
||||
TUD_EPBUF_DEF(rx, NETD_PACKET_SIZE);
|
||||
TUD_EPBUF_DEF(tx, NETD_PACKET_SIZE);
|
||||
|
||||
tu_static const struct ecm_notify_struct ecm_notify_csc =
|
||||
{
|
||||
.header = {
|
||||
.bmRequestType = 0xA1,
|
||||
.bRequest = 0x2A /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */,
|
||||
.wLength = 8,
|
||||
},
|
||||
.downlink = 9728000,
|
||||
.uplink = 9728000,
|
||||
};
|
||||
|
||||
// TODO remove CFG_TUD_MEM_SECTION, control internal buffer is already in this special section
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static union
|
||||
{
|
||||
uint8_t rndis_buf[120];
|
||||
struct ecm_notify_struct ecm_buf;
|
||||
} notify;
|
||||
TUD_EPBUF_DEF(notify, sizeof(ecm_notify_t));
|
||||
TUD_EPBUF_DEF(ctrl, NETD_CONTROL_SIZE);
|
||||
} netd_epbuf_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
// TODO remove CFG_TUD_MEM_SECTION
|
||||
CFG_TUD_MEM_SECTION tu_static netd_interface_t _netd_itf;
|
||||
static netd_interface_t _netd_itf;
|
||||
CFG_TUD_MEM_SECTION static netd_epbuf_t _netd_epbuf;
|
||||
static bool can_xmit;
|
||||
|
||||
tu_static bool can_xmit;
|
||||
|
||||
void tud_network_recv_renew(void)
|
||||
{
|
||||
usbd_edpt_xfer(0, _netd_itf.ep_out, received, sizeof(received));
|
||||
void tud_network_recv_renew(void) {
|
||||
usbd_edpt_xfer(0, _netd_itf.ep_out, _netd_epbuf.rx, NETD_PACKET_SIZE);
|
||||
}
|
||||
|
||||
static void do_in_xfer(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
static void do_in_xfer(uint8_t *buf, uint16_t len) {
|
||||
can_xmit = false;
|
||||
usbd_edpt_xfer(0, _netd_itf.ep_in, buf, len);
|
||||
}
|
||||
|
||||
void netd_report(uint8_t *buf, uint16_t len)
|
||||
{
|
||||
uint8_t const rhport = 0;
|
||||
void netd_report(uint8_t *buf, uint16_t len) {
|
||||
const uint8_t rhport = 0;
|
||||
len = tu_min16(len, sizeof(ecm_notify_t));
|
||||
|
||||
// skip if previous report not yet acknowledged by host
|
||||
if ( usbd_edpt_busy(rhport, _netd_itf.ep_notif) ) return;
|
||||
usbd_edpt_xfer(rhport, _netd_itf.ep_notif, buf, len);
|
||||
TU_VERIFY(usbd_edpt_claim(rhport, _netd_itf.ep_notif), );
|
||||
memcpy(_netd_epbuf.notify, buf, len);
|
||||
usbd_edpt_xfer(rhport, _netd_itf.ep_notif, _netd_epbuf.notify, len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -140,15 +111,12 @@ bool netd_deinit(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void netd_reset(uint8_t rhport)
|
||||
{
|
||||
void netd_reset(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
|
||||
netd_init();
|
||||
}
|
||||
|
||||
uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
|
||||
{
|
||||
uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
|
||||
bool const is_rndis = (TUD_RNDIS_ITF_CLASS == itf_desc->bInterfaceClass &&
|
||||
TUD_RNDIS_ITF_SUBCLASS == itf_desc->bInterfaceSubClass &&
|
||||
TUD_RNDIS_ITF_PROTOCOL == itf_desc->bInterfaceProtocol);
|
||||
|
|
@ -172,21 +140,19 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
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 (TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len) {
|
||||
drv_len += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
// notification endpoint (if any)
|
||||
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
||||
{
|
||||
TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
|
||||
if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) {
|
||||
TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0);
|
||||
|
||||
_netd_itf.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
|
||||
_netd_itf.ep_notif = ((tusb_desc_endpoint_t const*)p_desc)->bEndpointAddress;
|
||||
|
||||
drv_len += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
//------------- Data Interface -------------//
|
||||
|
|
@ -196,27 +162,24 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
// - 1 : IN & OUT endpoints for active networking
|
||||
TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0);
|
||||
|
||||
do
|
||||
{
|
||||
do {
|
||||
tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0);
|
||||
|
||||
drv_len += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}while( _netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len) );
|
||||
} while (_netd_itf.ecm_mode && (TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len));
|
||||
|
||||
// Pair of endpoints
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0);
|
||||
|
||||
if ( _netd_itf.ecm_mode )
|
||||
{
|
||||
if (_netd_itf.ecm_mode) {
|
||||
// ECM by default is in-active, save the endpoint attribute
|
||||
// to open later when received setInterface
|
||||
_netd_itf.ecm_desc_epdata = p_desc;
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// Open endpoint pair for RNDIS
|
||||
TU_ASSERT( usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0 );
|
||||
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in), 0);
|
||||
|
||||
tud_network_init_cb();
|
||||
|
||||
|
|
@ -232,38 +195,50 @@ uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1
|
|||
return drv_len;
|
||||
}
|
||||
|
||||
static void ecm_report(bool nc)
|
||||
{
|
||||
notify.ecm_buf = (nc) ? ecm_notify_nc : ecm_notify_csc;
|
||||
notify.ecm_buf.header.wIndex = _netd_itf.itf_num;
|
||||
netd_report((uint8_t *)¬ify.ecm_buf, (nc) ? sizeof(notify.ecm_buf.header) : sizeof(notify.ecm_buf));
|
||||
static void ecm_report(bool nc) {
|
||||
const ecm_notify_t ecm_notify_nc = {
|
||||
.header = {
|
||||
.bmRequestType = 0xA1,
|
||||
.bRequest = 0, /* NETWORK_CONNECTION aka NetworkConnection */
|
||||
.wValue = 1, /* Connected */
|
||||
.wLength = 0,
|
||||
},
|
||||
};
|
||||
|
||||
const ecm_notify_t ecm_notify_csc = {
|
||||
.header = {
|
||||
.bmRequestType = 0xA1,
|
||||
.bRequest = 0x2A, /* CONNECTION_SPEED_CHANGE aka ConnectionSpeedChange */
|
||||
.wLength = 8,
|
||||
},
|
||||
.downlink = 9728000,
|
||||
.uplink = 9728000,
|
||||
};
|
||||
|
||||
ecm_notify_t notify = (nc) ? ecm_notify_nc : ecm_notify_csc;
|
||||
notify.header.wIndex = _netd_itf.itf_num;
|
||||
netd_report((uint8_t *)¬ify, (nc) ? sizeof(notify.header) : sizeof(notify));
|
||||
}
|
||||
|
||||
// Invoked when a control transfer occurred on an interface of this class
|
||||
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
|
||||
{
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
switch ( request->bmRequestType_bit.type )
|
||||
{
|
||||
bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
switch (request->bmRequestType_bit.type) {
|
||||
case TUSB_REQ_TYPE_STANDARD:
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
case TUSB_REQ_GET_INTERFACE:
|
||||
{
|
||||
uint8_t const req_itfnum = (uint8_t) request->wIndex;
|
||||
switch (request->bRequest) {
|
||||
case TUSB_REQ_GET_INTERFACE: {
|
||||
uint8_t const req_itfnum = (uint8_t)request->wIndex;
|
||||
TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum);
|
||||
|
||||
tud_control_xfer(rhport, request, &_netd_itf.itf_data_alt, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_INTERFACE:
|
||||
{
|
||||
uint8_t const req_itfnum = (uint8_t) request->wIndex;
|
||||
uint8_t const req_alt = (uint8_t) request->wValue;
|
||||
case TUSB_REQ_SET_INTERFACE: {
|
||||
uint8_t const req_itfnum = (uint8_t)request->wIndex;
|
||||
uint8_t const req_alt = (uint8_t)request->wValue;
|
||||
|
||||
// Only valid for Data Interface with Alternate is either 0 or 1
|
||||
TU_VERIFY(_netd_itf.itf_num+1 == req_itfnum && req_alt < 2);
|
||||
|
|
@ -273,14 +248,14 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
|
||||
_netd_itf.itf_data_alt = req_alt;
|
||||
|
||||
if ( _netd_itf.itf_data_alt )
|
||||
{
|
||||
if (_netd_itf.itf_data_alt) {
|
||||
// TODO since we don't actually close endpoint
|
||||
// hack here to not re-open it
|
||||
if ( _netd_itf.ep_in == 0 && _netd_itf.ep_out == 0 )
|
||||
{
|
||||
if (_netd_itf.ep_in == 0 && _netd_itf.ep_out == 0) {
|
||||
TU_ASSERT(_netd_itf.ecm_desc_epdata);
|
||||
TU_ASSERT( usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &_netd_itf.ep_in) );
|
||||
TU_ASSERT(
|
||||
usbd_open_edpt_pair(rhport, _netd_itf.ecm_desc_epdata, 2, TUSB_XFER_BULK, &_netd_itf.ep_out, &
|
||||
_netd_itf.ep_in));
|
||||
|
||||
// TODO should be merge with RNDIS's after endpoint opened
|
||||
// Also should have opposite callback for application to disable network !!
|
||||
|
|
@ -288,8 +263,7 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
can_xmit = true; // we are ready to transmit a packet
|
||||
tud_network_recv_renew(); // prepare for incoming packets
|
||||
}
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// TODO close the endpoint pair
|
||||
// For now pretend that we did, this should have no harm since host won't try to
|
||||
// communicate with the endpoints again
|
||||
|
|
@ -303,50 +277,39 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
// unsupported request
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case TUSB_REQ_TYPE_CLASS:
|
||||
TU_VERIFY (_netd_itf.itf_num == request->wIndex);
|
||||
TU_VERIFY(_netd_itf.itf_num == request->wIndex);
|
||||
|
||||
if (_netd_itf.ecm_mode)
|
||||
{
|
||||
if (_netd_itf.ecm_mode) {
|
||||
/* the only required CDC-ECM Management Element Request is SetEthernetPacketFilter */
|
||||
if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest)
|
||||
{
|
||||
if (0x43 /* SET_ETHERNET_PACKET_FILTER */ == request->bRequest) {
|
||||
tud_control_xfer(rhport, request, NULL, 0);
|
||||
ecm_report(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (request->bmRequestType_bit.direction == TUSB_DIR_IN)
|
||||
{
|
||||
rndis_generic_msg_t *rndis_msg = (rndis_generic_msg_t *) ((void*) notify.rndis_buf);
|
||||
} else {
|
||||
if (request->bmRequestType_bit.direction == TUSB_DIR_IN) {
|
||||
rndis_generic_msg_t* rndis_msg = (rndis_generic_msg_t*)((void*)_netd_epbuf.ctrl);
|
||||
uint32_t msglen = tu_le32toh(rndis_msg->MessageLength);
|
||||
TU_ASSERT(msglen <= sizeof(notify.rndis_buf));
|
||||
tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) msglen);
|
||||
}
|
||||
else
|
||||
{
|
||||
tud_control_xfer(rhport, request, notify.rndis_buf, (uint16_t) sizeof(notify.rndis_buf));
|
||||
TU_ASSERT(msglen <= NETD_CONTROL_SIZE);
|
||||
tud_control_xfer(rhport, request, _netd_epbuf.ctrl, (uint16_t)msglen);
|
||||
} else {
|
||||
tud_control_xfer(rhport, request, _netd_epbuf.ctrl, NETD_CONTROL_SIZE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
// unsupported request
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_DATA )
|
||||
{
|
||||
} else if (stage == CONTROL_STAGE_DATA) {
|
||||
// Handle RNDIS class control OUT only
|
||||
if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
|
||||
request->bmRequestType_bit.direction == TUSB_DIR_OUT &&
|
||||
_netd_itf.itf_num == request->wIndex)
|
||||
{
|
||||
if ( !_netd_itf.ecm_mode )
|
||||
{
|
||||
rndis_class_set_handler(notify.rndis_buf, request->wLength);
|
||||
request->bmRequestType_bit.direction == TUSB_DIR_OUT &&
|
||||
_netd_itf.itf_num == request->wIndex) {
|
||||
if (!_netd_itf.ecm_mode) {
|
||||
rndis_class_set_handler(_netd_epbuf.ctrl, request->wLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,92 +317,77 @@ bool netd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
|
|||
return true;
|
||||
}
|
||||
|
||||
static void handle_incoming_packet(uint32_t len)
|
||||
{
|
||||
uint8_t *pnt = received;
|
||||
static void handle_incoming_packet(uint32_t len) {
|
||||
uint8_t* pnt = _netd_epbuf.rx;
|
||||
uint32_t size = 0;
|
||||
|
||||
if (_netd_itf.ecm_mode)
|
||||
{
|
||||
if (_netd_itf.ecm_mode) {
|
||||
size = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
rndis_data_packet_t *r = (rndis_data_packet_t *) ((void*) pnt);
|
||||
if (len >= sizeof(rndis_data_packet_t))
|
||||
if ( (r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len))
|
||||
if ( (r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len)
|
||||
{
|
||||
pnt = &received[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)];
|
||||
} else {
|
||||
rndis_data_packet_t* r = (rndis_data_packet_t*)((void*)pnt);
|
||||
if (len >= sizeof(rndis_data_packet_t)) {
|
||||
if ((r->MessageType == REMOTE_NDIS_PACKET_MSG) && (r->MessageLength <= len)) {
|
||||
if ((r->DataOffset + offsetof(rndis_data_packet_t, DataOffset) + r->DataLength) <= len) {
|
||||
pnt = &_netd_epbuf.rx[r->DataOffset + offsetof(rndis_data_packet_t, DataOffset)];
|
||||
size = r->DataLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tud_network_recv_cb(pnt, (uint16_t) size))
|
||||
{
|
||||
if (!tud_network_recv_cb(pnt, (uint16_t)size)) {
|
||||
/* if a buffer was never handled by user code, we must renew on the user's behalf */
|
||||
tud_network_recv_renew();
|
||||
}
|
||||
}
|
||||
|
||||
bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) result;
|
||||
bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
(void)rhport;
|
||||
(void)result;
|
||||
|
||||
/* new packet received */
|
||||
if ( ep_addr == _netd_itf.ep_out )
|
||||
{
|
||||
if (ep_addr == _netd_itf.ep_out) {
|
||||
handle_incoming_packet(xferred_bytes);
|
||||
}
|
||||
|
||||
/* data transmission finished */
|
||||
if ( ep_addr == _netd_itf.ep_in )
|
||||
{
|
||||
if (ep_addr == _netd_itf.ep_in) {
|
||||
/* TinyUSB requires the class driver to implement ZLP (since ZLP usage is class-specific) */
|
||||
|
||||
if ( xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE)) )
|
||||
{
|
||||
if (xferred_bytes && (0 == (xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE))) {
|
||||
do_in_xfer(NULL, 0); /* a ZLP is needed */
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
/* we're finally finished */
|
||||
can_xmit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( _netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif) )
|
||||
{
|
||||
if (sizeof(notify.ecm_buf.header) == xferred_bytes) ecm_report(false);
|
||||
if (_netd_itf.ecm_mode && (ep_addr == _netd_itf.ep_notif)) {
|
||||
if (sizeof(tusb_control_request_t) == xferred_bytes) {
|
||||
ecm_report(false);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tud_network_can_xmit(uint16_t size)
|
||||
{
|
||||
bool tud_network_can_xmit(uint16_t size) {
|
||||
(void)size;
|
||||
|
||||
return can_xmit;
|
||||
}
|
||||
|
||||
void tud_network_xmit(void *ref, uint16_t arg)
|
||||
{
|
||||
uint8_t *data;
|
||||
uint16_t len;
|
||||
|
||||
if (!can_xmit)
|
||||
void tud_network_xmit(void *ref, uint16_t arg) {
|
||||
if (!can_xmit) {
|
||||
return;
|
||||
}
|
||||
|
||||
len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN;
|
||||
data = transmitted + len;
|
||||
uint16_t len = (_netd_itf.ecm_mode) ? 0 : CFG_TUD_NET_PACKET_PREFIX_LEN;
|
||||
uint8_t* data = _netd_epbuf.tx + len;
|
||||
|
||||
len += tud_network_xmit_cb(data, ref, arg);
|
||||
|
||||
if (!_netd_itf.ecm_mode)
|
||||
{
|
||||
rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) transmitted);
|
||||
if (!_netd_itf.ecm_mode) {
|
||||
rndis_data_packet_t *hdr = (rndis_data_packet_t *) ((void*) _netd_epbuf.tx);
|
||||
memset(hdr, 0, sizeof(rndis_data_packet_t));
|
||||
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
|
||||
hdr->MessageLength = len;
|
||||
|
|
@ -447,7 +395,7 @@ void tud_network_xmit(void *ref, uint16_t arg)
|
|||
hdr->DataLength = len - sizeof(rndis_data_packet_t);
|
||||
}
|
||||
|
||||
do_in_xfer(transmitted, len);
|
||||
do_in_xfer(_netd_epbuf.tx, len);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -155,9 +155,10 @@ typedef union TU_ATTR_PACKED {
|
|||
uint8_t data[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
|
||||
} recv_ntb_t;
|
||||
|
||||
struct ncm_notify_t {
|
||||
typedef struct {
|
||||
tusb_control_request_t header;
|
||||
uint32_t downlink, uplink;
|
||||
};
|
||||
uint32_t downlink;
|
||||
uint32_t uplink;
|
||||
} ncm_notify_t;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ typedef struct {
|
|||
uint8_t rhport; // storage of \a rhport because some callbacks are done without it
|
||||
|
||||
// recv handling
|
||||
CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; // actual recv NTBs
|
||||
recv_ntb_t *recv_free_ntb[RECV_NTB_N]; // free list of recv NTBs
|
||||
recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic
|
||||
recv_ntb_t *recv_tinyusb_ntb; // buffer for the running transfer TinyUSB -> driver
|
||||
|
|
@ -97,7 +96,6 @@ typedef struct {
|
|||
uint16_t recv_glue_ntb_datagram_ndx; // index into \a recv_glue_ntb_datagram
|
||||
|
||||
// xmit handling
|
||||
CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; // actual xmit NTBs
|
||||
xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; // free list of xmit NTBs
|
||||
xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB
|
||||
xmit_ntb_t *xmit_tinyusb_ntb; // buffer for the running transfer driver -> TinyUSB
|
||||
|
|
@ -110,11 +108,28 @@ typedef struct {
|
|||
NOTIFICATION_SPEED,
|
||||
NOTIFICATION_CONNECTED,
|
||||
NOTIFICATION_DONE
|
||||
} notification_xmit_state; // state of notification transmission
|
||||
bool notification_xmit_is_running; // notification is currently transmitted
|
||||
} notification_xmit_state; // state of notification transmission
|
||||
bool notification_xmit_is_running; // notification is currently transmitted
|
||||
|
||||
// misc
|
||||
bool tud_network_recv_renew_active; // tud_network_recv_renew() is active (avoid recursive invocations)
|
||||
bool tud_network_recv_renew_process_again; // tud_network_recv_renew() should process again
|
||||
} ncm_interface_t;
|
||||
|
||||
CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN tu_static ncm_interface_t ncm_interface;
|
||||
typedef struct {
|
||||
struct {
|
||||
TUD_EPBUF_TYPE_DEF(recv_ntb_t, ntb);
|
||||
} recv[RECV_NTB_N];
|
||||
|
||||
struct {
|
||||
TUD_EPBUF_TYPE_DEF(xmit_ntb_t, ntb);
|
||||
} xmit[XMIT_NTB_N];
|
||||
|
||||
TUD_EPBUF_TYPE_DEF(ncm_notify_t, epnotif);
|
||||
} ncm_epbuf_t;
|
||||
|
||||
static ncm_interface_t ncm_interface;
|
||||
CFG_TUD_MEM_SECTION static ncm_epbuf_t ncm_epbuf;
|
||||
|
||||
/**
|
||||
* This is the NTB parameter structure
|
||||
|
|
@ -122,7 +137,7 @@ CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN tu_static ncm_interface_t ncm_interface;
|
|||
* \attention
|
||||
* We are lucky, that byte order is correct
|
||||
*/
|
||||
CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = {
|
||||
TU_ATTR_ALIGNED(4) static const ntb_parameters_t ntb_parameters = {
|
||||
.wLength = sizeof(ntb_parameters_t),
|
||||
.bmNtbFormatsSupported = 0x01,// 16-bit NTB supported
|
||||
.dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE,
|
||||
|
|
@ -152,30 +167,6 @@ CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN tu_static const ntb_parameters_t ntb_param
|
|||
//
|
||||
// everything about notifications
|
||||
//
|
||||
tu_static struct ncm_notify_t ncm_notify_connected = {
|
||||
.header = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN},
|
||||
.bRequest = CDC_NOTIF_NETWORK_CONNECTION,
|
||||
.wValue = 1 /* Connected */,
|
||||
.wLength = 0,
|
||||
},
|
||||
};
|
||||
|
||||
tu_static struct ncm_notify_t ncm_notify_speed_change = {
|
||||
.header = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN},
|
||||
.bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE,
|
||||
.wLength = 8,
|
||||
},
|
||||
.downlink = TUD_OPT_HIGH_SPEED ? 480000000 : 12000000,
|
||||
.uplink = TUD_OPT_HIGH_SPEED ? 480000000 : 12000000,
|
||||
};
|
||||
|
||||
/**
|
||||
* Transmit next notification to the host (if appropriate).
|
||||
|
|
@ -190,14 +181,53 @@ static void notification_xmit(uint8_t rhport, bool force_next) {
|
|||
|
||||
if (ncm_interface.notification_xmit_state == NOTIFICATION_SPEED) {
|
||||
TU_LOG_DRV(" NOTIFICATION_SPEED\n");
|
||||
ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num;
|
||||
usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
|
||||
ncm_notify_t notify_speed_change = {
|
||||
.header = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN
|
||||
},
|
||||
.bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE,
|
||||
.wValue = 0,
|
||||
.wIndex = ncm_interface.itf_num,
|
||||
.wLength = 8
|
||||
}
|
||||
};
|
||||
if (tud_speed_get() == TUSB_SPEED_HIGH) {
|
||||
notify_speed_change.downlink = 480000000;
|
||||
notify_speed_change.uplink = 480000000;
|
||||
} else {
|
||||
notify_speed_change.downlink = 12000000;
|
||||
notify_speed_change.uplink = 12000000;
|
||||
}
|
||||
|
||||
uint16_t notif_len = sizeof(notify_speed_change.header) + notify_speed_change.header.wLength;
|
||||
ncm_epbuf.epnotif = notify_speed_change;
|
||||
usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t*) &ncm_epbuf.epnotif, notif_len);
|
||||
|
||||
ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;
|
||||
ncm_interface.notification_xmit_is_running = true;
|
||||
} else if (ncm_interface.notification_xmit_state == NOTIFICATION_CONNECTED) {
|
||||
TU_LOG_DRV(" NOTIFICATION_CONNECTED\n");
|
||||
ncm_notify_connected.header.wIndex = ncm_interface.itf_num;
|
||||
usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
|
||||
ncm_notify_t notify_connected = {
|
||||
.header = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN
|
||||
},
|
||||
.bRequest = CDC_NOTIF_NETWORK_CONNECTION,
|
||||
.wValue = 1 /* Connected */,
|
||||
.wIndex = ncm_interface.itf_num,
|
||||
.wLength = 0,
|
||||
},
|
||||
};
|
||||
|
||||
uint16_t notif_len = sizeof(notify_connected.header) + notify_connected.header.wLength;
|
||||
ncm_epbuf.epnotif = notify_connected;
|
||||
usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_epbuf.epnotif, notif_len);
|
||||
|
||||
ncm_interface.notification_xmit_state = NOTIFICATION_DONE;
|
||||
ncm_interface.notification_xmit_is_running = true;
|
||||
} else {
|
||||
|
|
@ -360,7 +390,7 @@ static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size
|
|||
if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB) {
|
||||
return false;
|
||||
}
|
||||
if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) {
|
||||
if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_IN_NTB_MAX_SIZE) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -644,7 +674,7 @@ static void recv_transfer_datagram_to_glue_logic(void) {
|
|||
bool tud_network_can_xmit(uint16_t size) {
|
||||
TU_LOG_DRV("tud_network_can_xmit(%d)\n", size);
|
||||
|
||||
TU_ASSERT(size <= CFG_TUD_NCM_OUT_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)), false);
|
||||
TU_ASSERT(size <= CFG_TUD_NCM_IN_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)), false);
|
||||
|
||||
if (xmit_requested_datagram_fits_into_current_ntb(size) || xmit_setup_next_glue_ntb()) {
|
||||
// -> everything is fine
|
||||
|
|
@ -679,7 +709,7 @@ void tud_network_xmit(void *ref, uint16_t arg) {
|
|||
|
||||
ntb->nth.wBlockLength += (uint16_t) (size + XMIT_ALIGN_OFFSET(size));
|
||||
|
||||
if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) {
|
||||
if (ntb->nth.wBlockLength > CFG_TUD_NCM_IN_NTB_MAX_SIZE) {
|
||||
TU_LOG_DRV("(EE) tud_network_xmit: buffer overflow\n"); // must not happen (really)
|
||||
return;
|
||||
}
|
||||
|
|
@ -689,18 +719,36 @@ void tud_network_xmit(void *ref, uint16_t arg) {
|
|||
|
||||
/**
|
||||
* Keep the receive logic busy and transfer pending packets to the glue logic.
|
||||
* Avoid recursive calls due to wrong expectations of the net glue logic,
|
||||
* see https://github.com/hathach/tinyusb/issues/2711
|
||||
*/
|
||||
void tud_network_recv_renew(void) {
|
||||
TU_LOG_DRV("tud_network_recv_renew()\n");
|
||||
|
||||
recv_transfer_datagram_to_glue_logic();
|
||||
ncm_interface.tud_network_recv_renew_process_again = true;
|
||||
|
||||
if (ncm_interface.tud_network_recv_renew_active) {
|
||||
TU_LOG_DRV("Re-entrant into tud_network_recv_renew, will process later\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while (ncm_interface.tud_network_recv_renew_process_again) {
|
||||
ncm_interface.tud_network_recv_renew_process_again = false;
|
||||
|
||||
// If the current function is called within recv_transfer_datagram_to_glue_logic,
|
||||
// tud_network_recv_renew_process_again will become true, and the loop will run again
|
||||
// Otherwise the loop will not run again
|
||||
ncm_interface.tud_network_recv_renew_active = true;
|
||||
recv_transfer_datagram_to_glue_logic();
|
||||
ncm_interface.tud_network_recv_renew_active = false;
|
||||
}
|
||||
recv_try_to_start_new_reception(ncm_interface.rhport);
|
||||
} // tud_network_recv_renew
|
||||
|
||||
/**
|
||||
* Same as tud_network_recv_renew() but knows \a rhport
|
||||
*/
|
||||
void tud_network_recv_renew_r(uint8_t rhport) {
|
||||
static void tud_network_recv_renew_r(uint8_t rhport) {
|
||||
TU_LOG_DRV("tud_network_recv_renew_r(%d)\n", rhport);
|
||||
|
||||
ncm_interface.rhport = rhport;
|
||||
|
|
@ -721,10 +769,10 @@ void netd_init(void) {
|
|||
memset(&ncm_interface, 0, sizeof(ncm_interface));
|
||||
|
||||
for (int i = 0; i < XMIT_NTB_N; ++i) {
|
||||
ncm_interface.xmit_free_ntb[i] = ncm_interface.xmit_ntb + i;
|
||||
ncm_interface.xmit_free_ntb[i] = &ncm_epbuf.xmit[i].ntb;
|
||||
}
|
||||
for (int i = 0; i < RECV_NTB_N; ++i) {
|
||||
ncm_interface.recv_free_ntb[i] = ncm_interface.recv_ntb + i;
|
||||
ncm_interface.recv_free_ntb[i] = &ncm_epbuf.recv[i].ntb;
|
||||
}
|
||||
} // netd_init
|
||||
|
||||
|
|
@ -809,7 +857,8 @@ bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
|
|||
// - if there is a free receive buffer, initiate reception
|
||||
if (!recv_validate_datagram(ncm_interface.recv_tinyusb_ntb, xferred_bytes)) {
|
||||
// verification failed: ignore NTB and return it to free
|
||||
TU_LOG_DRV("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n");
|
||||
TU_LOG_DRV("Invalid datatagram. Ignoring NTB\n");
|
||||
recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb);
|
||||
} else {
|
||||
// packet ok -> put it into ready list
|
||||
recv_put_ntb_into_ready_list(ncm_interface.recv_tinyusb_ntb);
|
||||
|
|
|
|||
|
|
@ -67,11 +67,6 @@
|
|||
// Ability to defer status byte transmission
|
||||
// Transmission of status byte in response to USB488 SRQ condition
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_USBTMC)
|
||||
|
|
@ -136,14 +131,6 @@ typedef struct
|
|||
uint8_t ep_int_in;
|
||||
uint32_t ep_bulk_in_wMaxPacketSize;
|
||||
uint32_t ep_bulk_out_wMaxPacketSize;
|
||||
// IN buffer is only used for first packet, not the remainder
|
||||
// in order to deal with prepending header
|
||||
CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE];
|
||||
// OUT buffer receives one packet at a time
|
||||
CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE];
|
||||
// Buffer int msg to ensure alignment and placement correctness
|
||||
CFG_TUSB_MEM_ALIGN uint8_t ep_int_in_buf[CFG_TUD_USBTMC_INT_EP_SIZE];
|
||||
|
||||
uint32_t transfer_size_remaining; // also used for requested length for bulk IN.
|
||||
uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes)
|
||||
|
||||
|
|
@ -155,11 +142,23 @@ typedef struct
|
|||
usbtmc_capabilities_specific_t const * capabilities;
|
||||
} usbtmc_interface_state_t;
|
||||
|
||||
CFG_TUD_MEM_SECTION tu_static usbtmc_interface_state_t usbtmc_state =
|
||||
{
|
||||
.itf_id = 0xFF,
|
||||
typedef struct {
|
||||
// IN buffer is only used for first packet, not the remainder in order to deal with prepending header
|
||||
TUD_EPBUF_DEF(epin, USBTMCD_BUFFER_SIZE);
|
||||
|
||||
// OUT buffer receives one packet at a time
|
||||
TUD_EPBUF_DEF(epout, USBTMCD_BUFFER_SIZE);
|
||||
|
||||
// Buffer int msg
|
||||
TUD_EPBUF_DEF(epnotif, CFG_TUD_USBTMC_INT_EP_SIZE);
|
||||
} usbtmc_epbuf_t;
|
||||
|
||||
static usbtmc_interface_state_t usbtmc_state = {
|
||||
.itf_id = 0xFF,
|
||||
};
|
||||
|
||||
CFG_TUD_MEM_SECTION static usbtmc_epbuf_t usbtmc_epbuf;
|
||||
|
||||
// We need all headers to fit in a single packet in this implementation, 32 bytes will fit all standard USBTMC headers
|
||||
TU_VERIFY_STATIC(USBTMCD_BUFFER_SIZE >= 32u,"USBTMC dev buffer size too small");
|
||||
|
||||
|
|
@ -181,7 +180,7 @@ osal_mutex_t usbtmcLock;
|
|||
#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)
|
||||
static bool atomicChangeState(usbtmcd_state_enum expectedState, usbtmcd_state_enum newState)
|
||||
{
|
||||
bool ret = true;
|
||||
criticalEnter();
|
||||
|
|
@ -210,7 +209,7 @@ bool tud_usbtmc_transmit_dev_msg_data(
|
|||
bool endOfMessage,
|
||||
bool usingTermChar)
|
||||
{
|
||||
const unsigned int txBufLen = sizeof(usbtmc_state.ep_bulk_in_buf);
|
||||
const unsigned int txBufLen = USBTMCD_BUFFER_SIZE;
|
||||
|
||||
#ifndef NDEBUG
|
||||
TU_ASSERT(len > 0u);
|
||||
|
|
@ -225,7 +224,7 @@ bool tud_usbtmc_transmit_dev_msg_data(
|
|||
#endif
|
||||
|
||||
TU_VERIFY(usbtmc_state.state == STATE_TX_REQUESTED);
|
||||
usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_state.ep_bulk_in_buf;
|
||||
usbtmc_msg_dev_dep_msg_in_header_t *hdr = (usbtmc_msg_dev_dep_msg_in_header_t*)usbtmc_epbuf.epin;
|
||||
tu_varclr(hdr);
|
||||
hdr->header.MsgID = USBTMC_MSGID_DEV_DEP_MSG_IN;
|
||||
hdr->header.bTag = usbtmc_state.lastBulkInTag;
|
||||
|
|
@ -240,7 +239,7 @@ bool tud_usbtmc_transmit_dev_msg_data(
|
|||
len : (txBufLen - headerLen);
|
||||
const size_t packetLen = headerLen + dataLen;
|
||||
|
||||
memcpy((uint8_t*)(usbtmc_state.ep_bulk_in_buf) + headerLen, data, dataLen);
|
||||
memcpy((uint8_t*)(usbtmc_epbuf.epin) + headerLen, data, dataLen);
|
||||
usbtmc_state.transfer_size_remaining = len - dataLen;
|
||||
usbtmc_state.transfer_size_sent = dataLen;
|
||||
usbtmc_state.devInBuffer = (uint8_t const*) data + (dataLen);
|
||||
|
|
@ -248,7 +247,7 @@ bool tud_usbtmc_transmit_dev_msg_data(
|
|||
bool stateChanged =
|
||||
atomicChangeState(STATE_TX_REQUESTED, (packetLen >= txBufLen) ? STATE_TX_INITIATED : STATE_TX_SHORTED);
|
||||
TU_VERIFY(stateChanged);
|
||||
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen));
|
||||
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_in, usbtmc_epbuf.epin, (uint16_t)packetLen));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -260,8 +259,8 @@ bool tud_usbtmc_transmit_notification_data(const void * data, size_t len)
|
|||
#endif
|
||||
TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in));
|
||||
|
||||
TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0);
|
||||
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, (uint16_t)len));
|
||||
TU_VERIFY(tu_memcpy_s(usbtmc_epbuf.epnotif, CFG_TUD_USBTMC_INT_EP_SIZE, data, len) == 0);
|
||||
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_epbuf.epnotif, (uint16_t)len));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +400,7 @@ bool tud_usbtmc_start_bus_read(void)
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
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));
|
||||
TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_bulk_out, usbtmc_epbuf.epout, (uint16_t)usbtmc_state.ep_bulk_out_wMaxPacketSize));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -506,7 +505,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||
case STATE_IDLE:
|
||||
{
|
||||
TU_VERIFY(xferred_bytes >= sizeof(usbtmc_msg_generic_t));
|
||||
msg = (usbtmc_msg_generic_t*)(usbtmc_state.ep_bulk_out_buf);
|
||||
msg = (usbtmc_msg_generic_t*)(usbtmc_epbuf.epout);
|
||||
uint8_t invInvTag = (uint8_t)~(msg->header.bTagInverse);
|
||||
TU_VERIFY(msg->header.bTag == invInvTag);
|
||||
TU_VERIFY(msg->header.bTag != 0x00);
|
||||
|
|
@ -541,7 +540,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||
return true;
|
||||
}
|
||||
case STATE_RCV:
|
||||
if(!handle_devMsgOut(rhport, usbtmc_state.ep_bulk_out_buf, xferred_bytes, xferred_bytes))
|
||||
if(!handle_devMsgOut(rhport, usbtmc_epbuf.epout, xferred_bytes, xferred_bytes))
|
||||
{
|
||||
usbd_edpt_stall(rhport, usbtmc_state.ep_bulk_out);
|
||||
return false;
|
||||
|
|
@ -570,24 +569,23 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||
break;
|
||||
|
||||
case STATE_TX_INITIATED:
|
||||
if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf))
|
||||
if(usbtmc_state.transfer_size_remaining >= USBTMCD_BUFFER_SIZE)
|
||||
{
|
||||
// Copy buffer to ensure alignment correctness
|
||||
memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf));
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in,
|
||||
usbtmc_state.ep_bulk_in_buf, sizeof(usbtmc_state.ep_bulk_in_buf)));
|
||||
usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf);
|
||||
usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf);
|
||||
usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf);
|
||||
memcpy(usbtmc_epbuf.epin, usbtmc_state.devInBuffer, USBTMCD_BUFFER_SIZE);
|
||||
TU_VERIFY(usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_epbuf.epin, USBTMCD_BUFFER_SIZE));
|
||||
usbtmc_state.devInBuffer += USBTMCD_BUFFER_SIZE;
|
||||
usbtmc_state.transfer_size_remaining -= USBTMCD_BUFFER_SIZE;
|
||||
usbtmc_state.transfer_size_sent += USBTMCD_BUFFER_SIZE;
|
||||
}
|
||||
else // last packet
|
||||
{
|
||||
size_t packetLen = usbtmc_state.transfer_size_remaining;
|
||||
memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining);
|
||||
memcpy(usbtmc_epbuf.epin, usbtmc_state.devInBuffer, usbtmc_state.transfer_size_remaining);
|
||||
usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.transfer_size_remaining);
|
||||
usbtmc_state.transfer_size_remaining = 0;
|
||||
usbtmc_state.devInBuffer = NULL;
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf, (uint16_t)packetLen) );
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_epbuf.epin, (uint16_t)packetLen) );
|
||||
if(((packetLen % usbtmc_state.ep_bulk_in_wMaxPacketSize) != 0) || (packetLen == 0 ))
|
||||
{
|
||||
usbtmc_state.state = STATE_TX_SHORTED;
|
||||
|
|
@ -597,7 +595,7 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||
|
||||
case STATE_ABORTING_BULK_IN:
|
||||
// need to send short packet (ZLP?)
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u));
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_epbuf.epin,(uint16_t)0u));
|
||||
usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED;
|
||||
return true;
|
||||
|
||||
|
|
@ -749,7 +747,7 @@ bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request
|
|||
if(usbtmc_state.transfer_size_sent == 0)
|
||||
{
|
||||
// Send short packet, nothing is in the buffer yet
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_state.ep_bulk_in_buf,(uint16_t)0u));
|
||||
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in, usbtmc_epbuf.epin,(uint16_t)0u));
|
||||
usbtmc_state.state = STATE_ABORTING_BULK_IN_SHORTED;
|
||||
}
|
||||
TU_VERIFY(tud_usbtmc_initiate_abort_bulk_in_cb(&(rsp.USBTMC_status)));
|
||||
|
|
|
|||
69
src/class/vendor/vendor_device.c
vendored
69
src/class/vendor/vendor_device.c
vendored
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_VENDOR)
|
||||
|
|
@ -45,16 +40,12 @@ typedef struct {
|
|||
uint8_t itf_num;
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
// Endpoint Transfer buffer
|
||||
CFG_TUD_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE];
|
||||
CFG_TUD_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE];
|
||||
|
||||
struct {
|
||||
tu_edpt_stream_t stream;
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
uint8_t ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
|
||||
#endif
|
||||
}tx;
|
||||
} tx;
|
||||
|
||||
struct {
|
||||
tu_edpt_stream_t stream;
|
||||
|
|
@ -65,10 +56,17 @@ typedef struct {
|
|||
|
||||
} vendord_interface_t;
|
||||
|
||||
CFG_TUD_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
||||
|
||||
#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num))
|
||||
|
||||
static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
|
||||
|
||||
typedef struct {
|
||||
TUD_EPBUF_DEF(epout, CFG_TUD_VENDOR_EPSIZE);
|
||||
TUD_EPBUF_DEF(epin, CFG_TUD_VENDOR_EPSIZE);
|
||||
} vendord_epbuf_t;
|
||||
|
||||
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Application API
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -99,7 +97,7 @@ bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) {
|
|||
uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) {
|
||||
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t* p_itf = &_vendord_itf[itf];
|
||||
uint8_t const rhport = 0;
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
return tu_edpt_stream_read(rhport, &p_itf->rx.stream, buffer, bufsize);
|
||||
}
|
||||
|
|
@ -107,7 +105,7 @@ uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) {
|
|||
void tud_vendor_n_read_flush (uint8_t itf) {
|
||||
TU_VERIFY(itf < CFG_TUD_VENDOR, );
|
||||
vendord_interface_t* p_itf = &_vendord_itf[itf];
|
||||
uint8_t const rhport = 0;
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
tu_edpt_stream_clear(&p_itf->rx.stream);
|
||||
tu_edpt_stream_read_xfer(rhport, &p_itf->rx.stream);
|
||||
|
|
@ -116,10 +114,10 @@ void tud_vendor_n_read_flush (uint8_t itf) {
|
|||
//--------------------------------------------------------------------+
|
||||
// Write API
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) {
|
||||
uint32_t tud_vendor_n_write (uint8_t itf, const void* buffer, uint32_t bufsize) {
|
||||
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t* p_itf = &_vendord_itf[itf];
|
||||
uint8_t const rhport = 0;
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
return tu_edpt_stream_write(rhport, &p_itf->tx.stream, buffer, (uint16_t) bufsize);
|
||||
}
|
||||
|
|
@ -127,7 +125,7 @@ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize)
|
|||
uint32_t tud_vendor_n_write_flush (uint8_t itf) {
|
||||
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t* p_itf = &_vendord_itf[itf];
|
||||
uint8_t const rhport = 0;
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
return tu_edpt_stream_write_xfer(rhport, &p_itf->tx.stream);
|
||||
}
|
||||
|
|
@ -135,7 +133,7 @@ uint32_t tud_vendor_n_write_flush (uint8_t itf) {
|
|||
uint32_t tud_vendor_n_write_available (uint8_t itf) {
|
||||
TU_VERIFY(itf < CFG_TUD_VENDOR, 0);
|
||||
vendord_interface_t* p_itf = &_vendord_itf[itf];
|
||||
uint8_t const rhport = 0;
|
||||
const uint8_t rhport = 0;
|
||||
|
||||
return tu_edpt_stream_write_available(rhport, &p_itf->tx.stream);
|
||||
}
|
||||
|
|
@ -148,6 +146,7 @@ void vendord_init(void) {
|
|||
|
||||
for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
|
||||
vendord_interface_t* p_itf = &_vendord_itf[i];
|
||||
vendord_epbuf_t* p_epbuf = &_vendord_epbuf[i];
|
||||
|
||||
uint8_t* rx_ff_buf =
|
||||
#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
|
||||
|
|
@ -158,7 +157,7 @@ void vendord_init(void) {
|
|||
|
||||
tu_edpt_stream_init(&p_itf->rx.stream, false, false, false,
|
||||
rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE,
|
||||
p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE);
|
||||
p_epbuf->epout, CFG_TUD_VENDOR_EPSIZE);
|
||||
|
||||
uint8_t* tx_ff_buf =
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
|
|
@ -169,7 +168,7 @@ void vendord_init(void) {
|
|||
|
||||
tu_edpt_stream_init(&p_itf->tx.stream, false, true, false,
|
||||
tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE,
|
||||
p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE);
|
||||
p_epbuf->epin, CFG_TUD_VENDOR_EPSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +194,7 @@ void vendord_reset(uint8_t rhport) {
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) {
|
||||
uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint16_t max_len) {
|
||||
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0);
|
||||
const uint8_t* p_desc = tu_desc_next(desc_itf);
|
||||
const uint8_t* desc_end = p_desc + max_len;
|
||||
|
|
@ -242,25 +241,29 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui
|
|||
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
(void) result;
|
||||
|
||||
uint8_t itf = 0;
|
||||
vendord_interface_t* p_itf = _vendord_itf;
|
||||
uint8_t itf;
|
||||
vendord_interface_t* p_vendor;
|
||||
|
||||
for ( ; ; itf++, p_itf++) {
|
||||
if (itf >= CFG_TUD_VENDOR) return false;
|
||||
if ((ep_addr == p_itf->rx.stream.ep_addr) || (ep_addr == p_itf->tx.stream.ep_addr)) break;
|
||||
for (itf = 0; itf < CFG_TUD_VENDOR; itf++) {
|
||||
p_vendor = &_vendord_itf[itf];
|
||||
if ((ep_addr == p_vendor->rx.stream.ep_addr) || (ep_addr == p_vendor->tx.stream.ep_addr)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TU_VERIFY(itf < CFG_TUD_VENDOR);
|
||||
vendord_epbuf_t* p_epbuf = &_vendord_epbuf[itf];
|
||||
|
||||
if ( ep_addr == p_itf->rx.stream.ep_addr ) {
|
||||
if ( ep_addr == p_vendor->rx.stream.ep_addr ) {
|
||||
// Received new data: put into stream's fifo
|
||||
tu_edpt_stream_read_xfer_complete(&p_itf->rx.stream, xferred_bytes);
|
||||
tu_edpt_stream_read_xfer_complete(&p_vendor->rx.stream, xferred_bytes);
|
||||
|
||||
// Invoked callback if any
|
||||
if (tud_vendor_rx_cb) {
|
||||
tud_vendor_rx_cb(itf, p_itf->epout_buf, (uint16_t) xferred_bytes);
|
||||
tud_vendor_rx_cb(itf, p_epbuf->epout, (uint16_t) xferred_bytes);
|
||||
}
|
||||
|
||||
tu_edpt_stream_read_xfer(rhport, &p_itf->rx.stream);
|
||||
} else if ( ep_addr == p_itf->tx.stream.ep_addr ) {
|
||||
tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream);
|
||||
} else if ( ep_addr == p_vendor->tx.stream.ep_addr ) {
|
||||
// Send complete
|
||||
if (tud_vendor_tx_cb) {
|
||||
tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
|
||||
|
|
@ -268,9 +271,9 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
|
|||
|
||||
#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
|
||||
// try to send more if possible
|
||||
if ( 0 == tu_edpt_stream_write_xfer(rhport, &p_itf->tx.stream) ) {
|
||||
if ( 0 == tu_edpt_stream_write_xfer(rhport, &p_vendor->tx.stream) ) {
|
||||
// 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(rhport, &p_itf->tx.stream, xferred_bytes);
|
||||
tu_edpt_stream_write_zlp_if_needed(rhport, &p_vendor->tx.stream, xferred_bytes);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -540,28 +540,32 @@ typedef struct TU_ATTR_PACKED {
|
|||
|
||||
TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not correct");
|
||||
|
||||
#define TUD_VIDEO_DESC_IAD_LEN 8
|
||||
#define TUD_VIDEO_DESC_STD_VC_LEN 9
|
||||
#define TUD_VIDEO_DESC_CS_VC_LEN 12
|
||||
#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8
|
||||
#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9
|
||||
#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18
|
||||
#define TUD_VIDEO_DESC_STD_VS_LEN 9
|
||||
#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13
|
||||
#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9
|
||||
#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27
|
||||
#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26
|
||||
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6
|
||||
#define TUD_VIDEO_DESC_IAD_LEN 8
|
||||
#define TUD_VIDEO_DESC_STD_VC_LEN 9
|
||||
#define TUD_VIDEO_DESC_CS_VC_LEN 12
|
||||
#define TUD_VIDEO_DESC_INPUT_TERM_LEN 8
|
||||
#define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9
|
||||
#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18
|
||||
#define TUD_VIDEO_DESC_STD_VS_LEN 9
|
||||
#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13
|
||||
#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9
|
||||
#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27
|
||||
#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11
|
||||
#define TUD_VIDEO_DESC_CS_VS_FMT_FRAME_BASED_LEN 28
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_CONT_LEN 38
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_DISC_LEN 26
|
||||
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6
|
||||
|
||||
/* 2.2 compression formats */
|
||||
#define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
|
||||
#define TUD_VIDEO_GUID_NV12 0x4E,0x56,0x31,0x32,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
|
||||
#define TUD_VIDEO_GUID_M420 0x4D,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
|
||||
#define TUD_VIDEO_GUID_I420 0x49,0x34,0x32,0x30,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
|
||||
#define TUD_VIDEO_GUID_H264 0x48,0x32,0x36,0x34,0x00,0x00,0x10,0x00,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71
|
||||
|
||||
#define TUD_VIDEO_DESC_IAD(_firstitf, _nitfs, _stridx) \
|
||||
TUD_VIDEO_DESC_IAD_LEN, TUSB_DESC_INTERFACE_ASSOCIATION, \
|
||||
|
|
@ -656,6 +660,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
|
|||
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
|
||||
U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
|
||||
|
||||
/* Motion-Frame-Based 3.1.1 Table 3-1 */
|
||||
#define TUD_VIDEO_DESC_CS_VS_FMT_FRAME_BASED(_fmtidx, _numfrmdesc, _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp, _variablesize) \
|
||||
TUD_VIDEO_DESC_CS_VS_FMT_FRAME_BASED_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED, \
|
||||
_fmtidx, _numfrmdesc, TUD_VIDEO_GUID(_guid), _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp, _variablesize
|
||||
|
||||
/* Motion-Frame-Based 3.1.1 Table 3-2 and 3-3 */
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _frminterval, _bytesperline, _minfrminterval, _maxfrminterval, _frmintervalstep) \
|
||||
TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_FRAME_BASED, \
|
||||
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
|
||||
U32_TO_U8S_LE(_frminterval), 0, U32_TO_U8S_LE(_bytesperline), \
|
||||
U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep)
|
||||
|
||||
/* Motion-Frame-Based 3.1.1 Table 3-2 and 3-4 */
|
||||
#define TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _frminterval, _bytesperline, ...) \
|
||||
TUD_VIDEO_DESC_CS_VS_FRM_FRAME_BASED_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \
|
||||
TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_FRAME_BASED, \
|
||||
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
|
||||
U32_TO_U8S_LE(_frminterval), U32_TO_U8S_LE(_bytesperline), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
|
||||
|
||||
/* 3.9.2.6 */
|
||||
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \
|
||||
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \
|
||||
|
|
|
|||
|
|
@ -25,11 +25,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
|
||||
|
|
@ -121,34 +116,32 @@ typedef struct TU_ATTR_PACKED {
|
|||
uint8_t state; /* 0:probing 1:committed 2:streaming */
|
||||
|
||||
video_probe_and_commit_control_t probe_commit_payload; /* Probe and Commit control */
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */
|
||||
} videod_streaming_interface_t;
|
||||
|
||||
typedef struct {
|
||||
TUD_EPBUF_DEF(buf, CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE);
|
||||
} videod_streaming_epbuf_t;
|
||||
|
||||
/* video control interface */
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t const *beg; /* The head of the first video control interface descriptor */
|
||||
uint16_t len; /* Byte length of the descriptors */
|
||||
uint16_t cur; /* offset for current video control interface */
|
||||
uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */
|
||||
uint8_t error_code; /* error code */
|
||||
uint8_t power_mode;
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
// CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */
|
||||
|
||||
const uint8_t*beg; /* The head of the first video control interface descriptor */
|
||||
uint16_t len; /* Byte length of the descriptors */
|
||||
uint16_t cur; /* offset for current video control interface */
|
||||
uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */
|
||||
uint8_t error_code; /* error code */
|
||||
uint8_t power_mode;
|
||||
} videod_interface_t;
|
||||
|
||||
#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
CFG_TUD_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
|
||||
CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
|
||||
static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
|
||||
|
||||
tu_static uint8_t const _cap_get = 0x1u; /* support for GET */
|
||||
tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
|
||||
static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
|
||||
CFG_TUD_MEM_SECTION static videod_streaming_epbuf_t _videod_streaming_epbuf[CFG_TUD_VIDEO_STREAMING];
|
||||
|
||||
static uint8_t const _cap_get = 0x1u; /* support for GET */
|
||||
static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Debug
|
||||
|
|
@ -469,6 +462,9 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
|
|||
case VIDEO_CS_ITF_VS_FORMAT_MJPEG:
|
||||
break;
|
||||
|
||||
case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED:
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
|
||||
|
|
@ -494,6 +490,10 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
|
|||
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
|
||||
break;
|
||||
|
||||
case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED:
|
||||
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
param->dwMaxVideoFrameSize = frame_size;
|
||||
|
|
@ -583,6 +583,10 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
|
|||
frmnum = fmt->mjpeg.bDefaultFrameIndex;
|
||||
break;
|
||||
|
||||
case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED:
|
||||
frmnum = fmt->frame_based.bDefaultFrameIndex;
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -601,6 +605,10 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
|
|||
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
|
||||
break;
|
||||
|
||||
case VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED:
|
||||
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
param->dwMaxVideoFrameSize = frame_size;
|
||||
|
|
@ -821,21 +829,20 @@ static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint
|
|||
}
|
||||
|
||||
/** Prepare the next packet payload. */
|
||||
static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
|
||||
{
|
||||
static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm, uint8_t* ep_buf) {
|
||||
uint_fast16_t remaining = stm->bufsize - stm->offset;
|
||||
uint_fast16_t hdr_len = stm->ep_buf[0];
|
||||
uint_fast16_t hdr_len = ep_buf[0];
|
||||
uint_fast16_t pkt_len = stm->max_payload_transfer_size;
|
||||
if (hdr_len + remaining < pkt_len) {
|
||||
pkt_len = hdr_len + remaining;
|
||||
}
|
||||
TU_ASSERT(pkt_len >= hdr_len);
|
||||
uint_fast16_t data_len = pkt_len - hdr_len;
|
||||
memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
|
||||
memcpy(&ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
|
||||
stm->offset += data_len;
|
||||
remaining -= data_len;
|
||||
if (!remaining) {
|
||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
|
||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*) ep_buf;
|
||||
hdr->EndOfFrame = 1;
|
||||
}
|
||||
return hdr_len + data_len;
|
||||
|
|
@ -1006,7 +1013,8 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||
tusb_control_request_t const *request,
|
||||
uint_fast8_t stm_idx) {
|
||||
(void)rhport;
|
||||
videod_streaming_interface_t *self = &_videod_streaming_itf[stm_idx];
|
||||
videod_streaming_interface_t *stm = &_videod_streaming_itf[stm_idx];
|
||||
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[stm_idx];
|
||||
|
||||
uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
|
||||
TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vs_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
|
||||
|
|
@ -1018,7 +1026,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||
case VIDEO_REQUEST_GET_CUR:
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
/* TODO */
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &stm->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
|
||||
}
|
||||
return VIDEO_ERROR_NONE;
|
||||
|
||||
|
|
@ -1033,17 +1041,17 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||
break;
|
||||
|
||||
case VIDEO_VS_CTL_PROBE:
|
||||
if (self->state != VS_STATE_PROBING) {
|
||||
self->state = VS_STATE_PROBING;
|
||||
if (stm->state != VS_STATE_PROBING) {
|
||||
stm->state = VS_STATE_PROBING;
|
||||
}
|
||||
|
||||
switch (request->bRequest) {
|
||||
case VIDEO_REQUEST_SET_CUR:
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)),
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)),
|
||||
VIDEO_ERROR_UNKNOWN);
|
||||
} else if (stage == CONTROL_STAGE_DATA) {
|
||||
TU_VERIFY(_update_streaming_parameters(self, &self->probe_commit_payload),
|
||||
TU_VERIFY(_update_streaming_parameters(stm, &stm->probe_commit_payload),
|
||||
VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||
}
|
||||
return VIDEO_ERROR_NONE;
|
||||
|
|
@ -1051,7 +1059,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||
case VIDEO_REQUEST_GET_CUR:
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||
}
|
||||
return VIDEO_ERROR_NONE;
|
||||
|
||||
|
|
@ -1061,8 +1069,8 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||
case VIDEO_REQUEST_GET_DEF:
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
||||
video_probe_and_commit_control_t tmp = self->probe_commit_payload;
|
||||
TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||
video_probe_and_commit_control_t tmp = stm->probe_commit_payload;
|
||||
TU_VERIFY(_negotiate_streaming_parameters(stm, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
|
||||
}
|
||||
return VIDEO_ERROR_NONE;
|
||||
|
|
@ -1090,23 +1098,23 @@ 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(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||
} else if (stage == CONTROL_STAGE_DATA) {
|
||||
video_probe_and_commit_control_t *param = &self->probe_commit_payload;
|
||||
TU_VERIFY(_update_streaming_parameters(self, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||
video_probe_and_commit_control_t *param = &stm->probe_commit_payload;
|
||||
TU_VERIFY(_update_streaming_parameters(stm, param), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE);
|
||||
/* Set the negotiated value */
|
||||
self->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
|
||||
stm->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
|
||||
int ret = VIDEO_ERROR_NONE;
|
||||
if (tud_video_commit_cb) {
|
||||
ret = tud_video_commit_cb(self->index_vc, self->index_vs, param);
|
||||
ret = tud_video_commit_cb(stm->index_vc, stm->index_vs, param);
|
||||
}
|
||||
if (VIDEO_ERROR_NONE == ret) {
|
||||
self->state = VS_STATE_COMMITTED;
|
||||
self->buffer = NULL;
|
||||
self->bufsize = 0;
|
||||
self->offset = 0;
|
||||
stm->state = VS_STATE_COMMITTED;
|
||||
stm->buffer = NULL;
|
||||
stm->bufsize = 0;
|
||||
stm->offset = 0;
|
||||
/* initialize payload header */
|
||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)self->ep_buf;
|
||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm_epbuf->buf;
|
||||
hdr->bHeaderLength = sizeof(*hdr);
|
||||
hdr->bmHeaderInfo = 0;
|
||||
}
|
||||
|
|
@ -1116,7 +1124,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
|
|||
case VIDEO_REQUEST_GET_CUR:
|
||||
if (stage == CONTROL_STAGE_SETUP) {
|
||||
TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &self->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||
TU_VERIFY(tud_control_xfer(rhport, request, &stm->probe_commit_payload, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN);
|
||||
}
|
||||
return VIDEO_ERROR_NONE;
|
||||
|
||||
|
|
@ -1204,12 +1212,14 @@ bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize)
|
||||
{
|
||||
bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize) {
|
||||
TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
|
||||
TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
|
||||
|
||||
if (!buffer || !bufsize) return false;
|
||||
videod_streaming_interface_t *stm = _get_instance_streaming(ctl_idx, stm_idx);
|
||||
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[ctl_idx];
|
||||
|
||||
if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
|
||||
if (stm->state == VS_STATE_PROBING) return false;
|
||||
|
||||
|
|
@ -1226,14 +1236,14 @@ bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *bu
|
|||
|
||||
TU_VERIFY( usbd_edpt_claim(0, ep_addr) );
|
||||
/* update the packet header */
|
||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm->ep_buf;
|
||||
tusb_video_payload_header_t *hdr = (tusb_video_payload_header_t*)stm_epbuf->buf;
|
||||
hdr->FrameID ^= 1;
|
||||
hdr->EndOfFrame = 0;
|
||||
/* update the packet data */
|
||||
stm->buffer = (uint8_t*)buffer;
|
||||
stm->bufsize = bufsize;
|
||||
uint_fast16_t pkt_len = _prepare_in_payload(stm);
|
||||
TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
|
||||
uint_fast16_t pkt_len = _prepare_in_payload(stm, stm_epbuf->buf);
|
||||
TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm_epbuf->buf, (uint16_t) pkt_len), 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1247,7 +1257,7 @@ void videod_init(void) {
|
|||
}
|
||||
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
|
||||
videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
|
||||
tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
|
||||
tu_memclr(stm, sizeof(videod_streaming_interface_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1263,7 +1273,7 @@ void videod_reset(uint8_t rhport) {
|
|||
}
|
||||
for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
|
||||
videod_streaming_interface_t *stm = &_videod_streaming_itf[i];
|
||||
tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
|
||||
tu_memclr(stm, sizeof(videod_streaming_interface_t));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1312,7 +1322,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin
|
|||
#ifdef TUP_DCD_EDPT_ISO_ALLOC
|
||||
/* Allocate ISO endpoints */
|
||||
uint16_t ep_size = 0;
|
||||
uint16_t ep_addr = 0;
|
||||
uint8_t ep_addr = 0;
|
||||
uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg;
|
||||
uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end;
|
||||
while (p_desc < p_desc_end) {
|
||||
|
|
@ -1397,13 +1407,14 @@ bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
|
|||
uint8_t const *desc = ctl->beg;
|
||||
if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break;
|
||||
}
|
||||
|
||||
TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING);
|
||||
videod_streaming_epbuf_t *stm_epbuf = &_videod_streaming_epbuf[itf];
|
||||
|
||||
if (stm->offset < stm->bufsize) {
|
||||
/* Claim the endpoint */
|
||||
TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0);
|
||||
uint_fast16_t pkt_len = _prepare_in_payload(stm);
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
|
||||
uint_fast16_t pkt_len = _prepare_in_payload(stm, stm_epbuf->buf);
|
||||
TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm_epbuf->buf, (uint16_t) pkt_len), 0);
|
||||
} else {
|
||||
stm->buffer = NULL;
|
||||
stm->bufsize = 0;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ extern "C" {
|
|||
// CFG_TUD_VIDEO > 1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tud_video_n_connected(uint_fast8_t ctl_idx);
|
||||
|
||||
/** Return true if streaming
|
||||
*
|
||||
* @param[in] ctl_idx Destination control interface index
|
||||
|
|
|
|||
|
|
@ -123,11 +123,15 @@ TU_ATTR_ALWAYS_INLINE static inline int tu_memcpy_s(void *dest, size_t destsz, c
|
|||
|
||||
//------------- Bytes -------------//
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32(uint8_t b3, uint8_t b2, uint8_t b1, uint8_t b0) {
|
||||
return ( ((uint32_t) b3) << 24) | ( ((uint32_t) b2) << 16) | ( ((uint32_t) b1) << 8) | b0;
|
||||
return (((uint32_t)b3) << 24) | (((uint32_t)b2) << 16) | (((uint32_t)b1) << 8) | b0;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_u32_from_u16(uint16_t high, uint16_t low) {
|
||||
return (((uint32_t)high) << 16) | low;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_u16(uint8_t high, uint8_t low) {
|
||||
return (uint16_t) ((((uint16_t) high) << 8) | low);
|
||||
return (uint16_t)((((uint16_t)high) << 8) | low);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_u32_byte3(uint32_t ui32) { return TU_U32_BYTE3(ui32); }
|
||||
|
|
@ -172,7 +176,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned32(uint32_t value) { retur
|
|||
TU_ATTR_ALWAYS_INLINE static inline bool tu_is_aligned64(uint64_t value) { return (value & 0x3FUL) == 0; }
|
||||
|
||||
//------------- Mathematics -------------//
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return (v + d -1)/d; }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_div_ceil(uint32_t v, uint32_t d) { return TU_DIV_CEIL(v, d); }
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_round_up(uint32_t v, uint32_t f) { return tu_div_ceil(v, f) * f; }
|
||||
|
||||
// log2 of a value is its MSB's position
|
||||
// TODO use clz TODO remove
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@
|
|||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f))
|
||||
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
|
||||
#ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
|
||||
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
|
||||
#endif
|
||||
|
|
@ -189,6 +189,7 @@
|
|||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
|
||||
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
|
||||
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
|
||||
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
|
||||
|
|
@ -216,6 +217,7 @@
|
|||
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
|
||||
#define TU_ATTR_PACKED __attribute__ ((packed))
|
||||
#define TU_ATTR_WEAK __attribute__ ((weak))
|
||||
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
|
||||
#ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
|
||||
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
|
||||
#endif
|
||||
|
|
@ -244,6 +246,7 @@
|
|||
#define TU_ATTR_SECTION(sec_name)
|
||||
#define TU_ATTR_PACKED
|
||||
#define TU_ATTR_WEAK
|
||||
// #define TU_ATTR_WEAK_ALIAS(f)
|
||||
#define TU_ATTR_ALWAYS_INLINE
|
||||
#define TU_ATTR_DEPRECATED(mess)
|
||||
#define TU_ATTR_UNUSED
|
||||
|
|
|
|||
|
|
@ -108,12 +108,20 @@
|
|||
#define TUP_DCD_ENDPOINT_MAX 16
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_MIMXRT1XXX)
|
||||
#include "fsl_device_registers.h"
|
||||
|
||||
#define TUP_USBIP_CHIPIDEA_HS
|
||||
#define TUP_USBIP_EHCI
|
||||
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
#define TUP_RHPORT_HIGHSPEED 1
|
||||
|
||||
#if __CORTEX_M == 7
|
||||
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 1
|
||||
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 1
|
||||
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE 32
|
||||
#endif
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_KINETIS_KL, OPT_MCU_KINETIS_K32L, OPT_MCU_KINETIS_K)
|
||||
#define TUP_USBIP_CHIPIDEA_FS
|
||||
#define TUP_USBIP_CHIPIDEA_FS_KINETIS
|
||||
|
|
@ -169,6 +177,7 @@
|
|||
defined (STM32F107xB) || defined (STM32F107xC)
|
||||
#define TUP_USBIP_DWC2
|
||||
#define TUP_USBIP_DWC2_STM32
|
||||
#define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
|
||||
|
||||
#define TUP_DCD_ENDPOINT_MAX 4
|
||||
#elif defined(STM32F102x6) || defined(STM32F102xB) || \
|
||||
|
|
@ -237,6 +246,11 @@
|
|||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
|
||||
#define TUP_USBIP_FSDEV
|
||||
#define TUP_USBIP_FSDEV_STM32
|
||||
|
|
@ -298,6 +312,16 @@
|
|||
#define TUP_USBIP_FSDEV_STM32
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS)
|
||||
#define TUP_USBIP_DWC2
|
||||
#define TUP_USBIP_DWC2_STM32
|
||||
|
||||
// FS has 6, HS has 9
|
||||
#define TUP_DCD_ENDPOINT_MAX 9
|
||||
|
||||
// MCU with on-chip HS Phy
|
||||
#define TUP_RHPORT_HIGHSPEED 1
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Sony
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -343,6 +367,11 @@
|
|||
#define TUP_USBIP_DWC2
|
||||
#define TUP_USBIP_DWC2_ESP32
|
||||
#define TUP_DCD_ENDPOINT_MAX 7 // only 5 TX FIFO for endpoint IN
|
||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
||||
|
||||
// Disable slave if DMA is enabled
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
|
||||
#define TUP_USBIP_DWC2
|
||||
|
|
@ -350,11 +379,24 @@
|
|||
#define TUP_RHPORT_HIGHSPEED 1 // port0 FS, port1 HS
|
||||
#define TUP_DCD_ENDPOINT_MAX 16 // FS 7 ep, HS 16 ep
|
||||
|
||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
||||
|
||||
// Disable slave if DMA is enabled
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
|
||||
|
||||
// Enable dcache if DMA is enabled
|
||||
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
|
||||
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
|
||||
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 64
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2)
|
||||
#if (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421))
|
||||
#error "MCUs are only supported with CFG_TUH_MAX3421 enabled"
|
||||
#endif
|
||||
|
||||
#define TUP_DCD_ENDPOINT_MAX 0
|
||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT freertos/
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Dialog
|
||||
|
|
@ -366,6 +408,7 @@
|
|||
// Raspberry Pi
|
||||
//--------------------------------------------------------------------+
|
||||
#elif TU_CHECK_MCU(OPT_MCU_RP2040)
|
||||
#define TUP_DCD_EDPT_ISO_ALLOC
|
||||
#define TUP_DCD_ENDPOINT_MAX 16
|
||||
|
||||
#define TU_ATTR_FAST_FUNC __attribute__((section(".time_critical.tinyusb")))
|
||||
|
|
@ -535,7 +578,7 @@
|
|||
#define TUP_DCD_EDPT_ISO_ALLOC
|
||||
#endif
|
||||
|
||||
#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA == 0
|
||||
#if defined(TUP_USBIP_DWC2) // && CFG_TUD_DWC2_DMA_ENABLE == 0
|
||||
#define TUP_MEM_CONST_ADDR
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _TUSB_PRIVATE_H_
|
||||
#define _TUSB_PRIVATE_H_
|
||||
#ifndef TUSB_PRIVATE_H_
|
||||
#define TUSB_PRIVATE_H_
|
||||
|
||||
// Internal Helper used by Host and Device Stack
|
||||
|
||||
|
|
@ -34,6 +33,13 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TUP_USBIP_CONTROLLER_NUM 2
|
||||
extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
volatile uint8_t busy : 1;
|
||||
volatile uint8_t stalled : 1;
|
||||
|
|
@ -163,4 +169,4 @@ bool tu_edpt_stream_peek(tu_edpt_stream_t* s, uint8_t* ch) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_PRIVATE_H_ */
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,14 +35,51 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
//------------- Device DCache declaration -------------//
|
||||
#define TUD_EPBUF_DCACHE_SIZE(_size) (CFG_TUD_MEM_DCACHE_ENABLE ? \
|
||||
(TU_DIV_CEIL(_size, CFG_TUD_MEM_DCACHE_LINE_SIZE) * CFG_TUD_MEM_DCACHE_LINE_SIZE) : (_size))
|
||||
|
||||
// Declare an endpoint buffer with uint8_t[size]
|
||||
#define TUD_EPBUF_DEF(_name, _size) \
|
||||
union { \
|
||||
CFG_TUD_MEM_ALIGN uint8_t _name[_size]; \
|
||||
uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(_size)]; \
|
||||
}
|
||||
|
||||
// Declare an endpoint buffer with a type
|
||||
#define TUD_EPBUF_TYPE_DEF(_type, _name) \
|
||||
union { \
|
||||
CFG_TUD_MEM_ALIGN _type _name; \
|
||||
uint8_t _name##_dcache_padding[TUD_EPBUF_DCACHE_SIZE(sizeof(_type))]; \
|
||||
}
|
||||
|
||||
//------------- Host DCache declaration -------------//
|
||||
#define TUH_EPBUF_DCACHE_SIZE(_size) (CFG_TUH_MEM_DCACHE_ENABLE ? \
|
||||
(TU_DIV_CEIL(_size, CFG_TUH_MEM_DCACHE_LINE_SIZE) * CFG_TUH_MEM_DCACHE_LINE_SIZE) : (_size))
|
||||
|
||||
// Declare an endpoint buffer with uint8_t[size]
|
||||
#define TUH_EPBUF_DEF(_name, _size) \
|
||||
union { \
|
||||
CFG_TUH_MEM_ALIGN uint8_t _name[_size]; \
|
||||
uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(_size)]; \
|
||||
}
|
||||
|
||||
// Declare an endpoint buffer with a type
|
||||
#define TUH_EPBUF_TYPE_DEF(_type, _name) \
|
||||
union { \
|
||||
CFG_TUH_MEM_ALIGN _type _name; \
|
||||
uint8_t _name##_dcache_padding[TUH_EPBUF_DCACHE_SIZE(sizeof(_type))]; \
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* CONSTANTS
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
typedef enum {
|
||||
TUSB_ROLE_INVALID = 0,
|
||||
TUSB_ROLE_DEVICE,
|
||||
TUSB_ROLE_HOST,
|
||||
TUSB_ROLE_DEVICE = 0x1,
|
||||
TUSB_ROLE_HOST = 0x2,
|
||||
} tusb_role_t;
|
||||
|
||||
/// defined base on EHCI specs value for Endpoint Speed
|
||||
|
|
@ -56,10 +93,10 @@ typedef enum {
|
|||
|
||||
/// defined base on USB Specs Endpoint's bmAttributes
|
||||
typedef enum {
|
||||
TUSB_XFER_CONTROL = 0 ,
|
||||
TUSB_XFER_ISOCHRONOUS ,
|
||||
TUSB_XFER_BULK ,
|
||||
TUSB_XFER_INTERRUPT
|
||||
TUSB_XFER_CONTROL = 0,
|
||||
TUSB_XFER_ISOCHRONOUS = 1,
|
||||
TUSB_XFER_BULK = 2,
|
||||
TUSB_XFER_INTERRUPT = 3
|
||||
} tusb_xfer_type_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -224,10 +261,10 @@ enum {
|
|||
// USB 2.0 Spec Table 9-7: Test Mode Selectors
|
||||
typedef enum {
|
||||
TUSB_FEATURE_TEST_J = 1,
|
||||
TUSB_FEATURE_TEST_K,
|
||||
TUSB_FEATURE_TEST_SE0_NAK,
|
||||
TUSB_FEATURE_TEST_PACKET,
|
||||
TUSB_FEATURE_TEST_FORCE_ENABLE,
|
||||
TUSB_FEATURE_TEST_K = 2,
|
||||
TUSB_FEATURE_TEST_SE0_NAK = 3,
|
||||
TUSB_FEATURE_TEST_PACKET = 4,
|
||||
TUSB_FEATURE_TEST_FORCE_ENABLE = 5,
|
||||
} tusb_feature_test_mode_t;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -264,10 +301,10 @@ typedef enum {
|
|||
} microsoft_os_20_type_t;
|
||||
|
||||
enum {
|
||||
CONTROL_STAGE_IDLE,
|
||||
CONTROL_STAGE_SETUP,
|
||||
CONTROL_STAGE_DATA,
|
||||
CONTROL_STAGE_ACK
|
||||
CONTROL_STAGE_IDLE = 0,
|
||||
CONTROL_STAGE_SETUP, // 1
|
||||
CONTROL_STAGE_DATA, // 2
|
||||
CONTROL_STAGE_ACK // 3
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -425,7 +462,7 @@ TU_VERIFY_STATIC( sizeof(tusb_desc_interface_assoc_t) == 8, "size is not correct
|
|||
typedef struct TU_ATTR_PACKED {
|
||||
uint8_t bLength ; ///< Size of this descriptor in bytes
|
||||
uint8_t bDescriptorType ; ///< Descriptor Type
|
||||
uint16_t unicode_string[];
|
||||
uint16_t utf16le[];
|
||||
} tusb_desc_string_t;
|
||||
|
||||
// USB Binary Device Object Store (BOS)
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \
|
||||
} while(0)
|
||||
|
||||
#elif defined(__riscv) && !TUP_MCU_ESPRESSIF
|
||||
#elif defined(__riscv) && !TUSB_MCU_VENDOR_ESPRESSIF
|
||||
#define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0)
|
||||
|
||||
#elif defined(_mips)
|
||||
|
|
|
|||
|
|
@ -93,15 +93,15 @@ typedef struct TU_ATTR_ALIGNED(4) {
|
|||
|
||||
// clean/flush data cache: write cache -> memory.
|
||||
// Required before an DMA TX transfer to make sure data is in memory
|
||||
void dcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
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
|
||||
void dcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
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
|
||||
void dcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
|
|
@ -51,9 +46,7 @@
|
|||
// Weak stubs: invoked if no strong implementation is available
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
|
||||
(void) rhport;
|
||||
(void) eventid;
|
||||
(void) in_isr;
|
||||
(void) rhport; (void) eventid; (void) in_isr;
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) {
|
||||
|
|
@ -106,6 +99,21 @@ TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport) {
|
|||
(void) rhport;
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK bool dcd_dcache_invalidate(const void* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_WEAK bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Device Data
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
|
|
@ -40,7 +35,7 @@
|
|||
//--------------------------------------------------------------------+
|
||||
// Callback weak stubs (called if application does not provide)
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_WEAK 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, const tusb_control_request_t* request) {
|
||||
(void) rhport;
|
||||
(void) request;
|
||||
}
|
||||
|
|
@ -49,10 +44,6 @@ TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request
|
|||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
|
||||
extern void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback);
|
||||
#endif
|
||||
|
||||
enum {
|
||||
EDPT_CTRL_OUT = 0x00,
|
||||
EDPT_CTRL_IN = 0x80
|
||||
|
|
@ -66,54 +57,53 @@ typedef struct {
|
|||
usbd_control_xfer_cb_t complete_cb;
|
||||
} usbd_control_xfer_t;
|
||||
|
||||
tu_static usbd_control_xfer_t _ctrl_xfer;
|
||||
static usbd_control_xfer_t _ctrl_xfer;
|
||||
|
||||
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE];
|
||||
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) {
|
||||
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;
|
||||
|
||||
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) {
|
||||
ep_addr = EDPT_CTRL_IN;
|
||||
if (xact_len) {
|
||||
TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, 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) {
|
||||
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;
|
||||
|
|
@ -123,14 +113,9 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, voi
|
|||
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));
|
||||
TU_ASSERT(data_stage_xact(rhport));
|
||||
} else {
|
||||
// Status stage
|
||||
TU_ASSERT(_status_stage_xact(rhport, request));
|
||||
TU_ASSERT(status_stage_xact(rhport, request));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -140,7 +125,7 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, voi
|
|||
// USBD API
|
||||
//--------------------------------------------------------------------+
|
||||
void usbd_control_reset(void);
|
||||
void usbd_control_set_request(tusb_control_request_t const* request);
|
||||
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);
|
||||
|
||||
|
|
@ -154,7 +139,7 @@ void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp) {
|
|||
}
|
||||
|
||||
// for dcd_set_address where DCD is responsible for status response
|
||||
void usbd_control_set_request(tusb_control_request_t const* request) {
|
||||
void usbd_control_set_request(const tusb_control_request_t* request) {
|
||||
_ctrl_xfer.request = (*request);
|
||||
_ctrl_xfer.buffer = NULL;
|
||||
_ctrl_xfer.total_xferred = 0;
|
||||
|
|
@ -184,8 +169,8 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
|
|||
|
||||
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(CFG_TUD_LOG_LEVEL, _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;
|
||||
|
|
@ -209,8 +194,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
|
|||
}
|
||||
|
||||
if (is_ok) {
|
||||
// Send status
|
||||
TU_ASSERT(_status_stage_xact(rhport, &_ctrl_xfer.request));
|
||||
TU_ASSERT(status_stage_xact(rhport, &_ctrl_xfer.request));
|
||||
} else {
|
||||
// Stall both IN and OUT control endpoint
|
||||
dcd_edpt_stall(rhport, EDPT_CTRL_OUT);
|
||||
|
|
@ -218,7 +202,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
|
|||
}
|
||||
} else {
|
||||
// More data to transfer
|
||||
TU_ASSERT(_data_stage_xact(rhport));
|
||||
TU_ASSERT(data_stage_xact(rhport));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -127,6 +127,11 @@ void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en);
|
|||
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);
|
||||
|
||||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -103,15 +103,15 @@ typedef struct {
|
|||
|
||||
// clean/flush data cache: write cache -> memory.
|
||||
// Required before an DMA TX transfer to make sure data is in memory
|
||||
bool hcd_dcache_clean(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool hcd_dcache_clean(void const* 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 hcd_dcache_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool hcd_dcache_invalidate(void const* addr, uint32_t data_size);
|
||||
|
||||
// clean and invalidate data cache
|
||||
// Required before an DMA transfer where memory is both read/write by DMA
|
||||
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) TU_ATTR_WEAK;
|
||||
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
|
|
|
|||
391
src/host/hub.c
391
src/host/hub.c
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if (CFG_TUH_ENABLED && CFG_TUH_HUB)
|
||||
|
|
@ -45,29 +40,36 @@
|
|||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t port_count;
|
||||
|
||||
CFG_TUH_MEM_ALIGN uint8_t status_change;
|
||||
CFG_TUH_MEM_ALIGN hub_port_status_response_t port_status;
|
||||
CFG_TUH_MEM_ALIGN hub_status_response_t hub_status;
|
||||
// from hub descriptor
|
||||
uint8_t bNbrPorts;
|
||||
uint8_t bPwrOn2PwrGood_2ms; // port power on to good, in 2ms unit
|
||||
// uint16_t wHubCharacteristics;
|
||||
|
||||
hub_port_status_response_t port_status;
|
||||
} hub_interface_t;
|
||||
|
||||
CFG_TUH_MEM_SECTION static hub_interface_t hub_data[CFG_TUH_HUB];
|
||||
CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)];
|
||||
typedef struct {
|
||||
TUH_EPBUF_DEF(status_change, 4); // interrupt endpoint
|
||||
TUH_EPBUF_DEF(ctrl_buf, CFG_TUH_HUB_BUFSIZE);
|
||||
} hub_epbuf_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
static inline hub_interface_t* get_itf(uint8_t dev_addr)
|
||||
{
|
||||
return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX];
|
||||
static hub_interface_t hub_itfs[CFG_TUH_HUB];
|
||||
CFG_TUH_MEM_SECTION static hub_epbuf_t hub_epbufs[CFG_TUH_HUB];
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline hub_interface_t* get_hub_itf(uint8_t daddr) {
|
||||
return &hub_itfs[daddr-1-CFG_TUH_DEVICE_MAX];
|
||||
}
|
||||
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
static char const* const _hub_feature_str[] =
|
||||
{
|
||||
TU_ATTR_ALWAYS_INLINE static inline hub_epbuf_t* get_hub_epbuf(uint8_t daddr) {
|
||||
return &hub_epbufs[daddr-1-CFG_TUH_DEVICE_MAX];
|
||||
}
|
||||
|
||||
#if CFG_TUSB_DEBUG >= HUB_DEBUG
|
||||
static char const* const _hub_feature_str[] = {
|
||||
[HUB_FEATURE_PORT_CONNECTION ] = "PORT_CONNECTION",
|
||||
[HUB_FEATURE_PORT_ENABLE ] = "PORT_ENABLE",
|
||||
[HUB_FEATURE_PORT_SUSPEND ] = "PORT_SUSPEND",
|
||||
|
|
@ -89,12 +91,9 @@ static char const* const _hub_feature_str[] =
|
|||
// HUB
|
||||
//--------------------------------------------------------------------+
|
||||
bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
tusb_control_request_t const request = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_OUT
|
||||
|
|
@ -105,8 +104,7 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
|||
.wLength = 0
|
||||
};
|
||||
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = hub_addr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
|
|
@ -115,18 +113,15 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
|||
.user_data = user_data
|
||||
};
|
||||
|
||||
TU_LOG2("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
TU_LOG_DRV("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
|
||||
TU_ASSERT(tuh_control_xfer(&xfer));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
tusb_control_request_t const request = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_OUT
|
||||
|
|
@ -137,8 +132,7 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
|||
.wLength = 0
|
||||
};
|
||||
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = hub_addr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
|
|
@ -147,18 +141,15 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
|||
.user_data = user_data
|
||||
};
|
||||
|
||||
TU_LOG2("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
|
||||
TU_LOG_DRV("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
tusb_control_request_t const request = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = (hub_port == 0) ? TUSB_REQ_RCPT_DEVICE : TUSB_REQ_RCPT_OTHER,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN
|
||||
|
|
@ -166,11 +157,10 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
|||
.bRequest = HUB_REQUEST_GET_STATUS,
|
||||
.wValue = 0,
|
||||
.wIndex = hub_port,
|
||||
.wLength = 4
|
||||
.wLength = tu_htole16(4)
|
||||
};
|
||||
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = hub_addr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
|
|
@ -179,7 +169,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
|||
.user_data = user_data
|
||||
};
|
||||
|
||||
TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
|
||||
TU_LOG_DRV("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
|
||||
TU_VERIFY( tuh_control_xfer(&xfer) );
|
||||
return true;
|
||||
}
|
||||
|
|
@ -188,7 +178,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
|||
// CLASS-USBH API (don't require to verify parameters)
|
||||
//--------------------------------------------------------------------+
|
||||
bool hub_init(void) {
|
||||
tu_memclr(hub_data, sizeof(hub_data));
|
||||
tu_memclr(hub_itfs, sizeof(hub_itfs));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -196,40 +186,32 @@ bool hub_deinit(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
|
||||
{
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
|
||||
(void) rhport;
|
||||
|
||||
TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
|
||||
0 == itf_desc->bInterfaceSubClass);
|
||||
TU_VERIFY(itf_desc->bInterfaceProtocol <= 1); // not support multiple TT yet
|
||||
|
||||
// hub driver does not support multiple TT yet
|
||||
TU_VERIFY(itf_desc->bInterfaceProtocol <= 1);
|
||||
|
||||
// msc driver length is fixed
|
||||
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
|
||||
TU_ASSERT(drv_len <= max_len);
|
||||
|
||||
//------------- Interrupt Status endpoint -------------//
|
||||
// Interrupt Status endpoint
|
||||
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
|
||||
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
|
||||
TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
|
||||
|
||||
TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
|
||||
|
||||
hub_interface_t* p_hub = get_itf(dev_addr);
|
||||
|
||||
hub_interface_t* p_hub = get_hub_itf(dev_addr);
|
||||
p_hub->itf_num = itf_desc->bInterfaceNumber;
|
||||
p_hub->ep_in = desc_ep->bEndpointAddress;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hub_close(uint8_t dev_addr)
|
||||
{
|
||||
void hub_close(uint8_t dev_addr) {
|
||||
TU_VERIFY(dev_addr > CFG_TUH_DEVICE_MAX, );
|
||||
hub_interface_t* p_hub = get_itf(dev_addr);
|
||||
hub_interface_t* p_hub = get_hub_itf(dev_addr);
|
||||
|
||||
if (p_hub->ep_in) {
|
||||
TU_LOG_DRV(" HUB close addr = %d\r\n", dev_addr);
|
||||
|
|
@ -237,30 +219,33 @@ void hub_close(uint8_t dev_addr)
|
|||
}
|
||||
}
|
||||
|
||||
bool hub_edpt_status_xfer(uint8_t dev_addr)
|
||||
{
|
||||
hub_interface_t* hub_itf = get_itf(dev_addr);
|
||||
return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1);
|
||||
}
|
||||
bool hub_edpt_status_xfer(uint8_t daddr) {
|
||||
hub_interface_t* p_hub = get_hub_itf(daddr);
|
||||
hub_epbuf_t* p_epbuf = get_hub_epbuf(daddr);
|
||||
|
||||
TU_VERIFY(usbh_edpt_claim(daddr, p_hub->ep_in));
|
||||
if (!usbh_edpt_xfer(daddr, p_hub->ep_in, p_epbuf->status_change, 1)) {
|
||||
usbh_edpt_release(daddr, p_hub->ep_in);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Set Configure
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void config_set_port_power (tuh_xfer_t* xfer);
|
||||
static void config_port_power_complete (tuh_xfer_t* xfer);
|
||||
|
||||
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
|
||||
{
|
||||
hub_interface_t* p_hub = get_itf(dev_addr);
|
||||
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
||||
hub_interface_t* p_hub = get_hub_itf(dev_addr);
|
||||
TU_ASSERT(itf_num == p_hub->itf_num);
|
||||
hub_epbuf_t* p_epbuf = get_hub_epbuf(dev_addr);
|
||||
|
||||
// Get Hub Descriptor
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
tusb_control_request_t const request = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_DEVICE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN
|
||||
|
|
@ -268,34 +253,33 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
|
|||
.bRequest = HUB_REQUEST_GET_DESCRIPTOR,
|
||||
.wValue = 0,
|
||||
.wIndex = 0,
|
||||
.wLength = sizeof(descriptor_hub_desc_t)
|
||||
.wLength = sizeof(hub_desc_cs_t)
|
||||
};
|
||||
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = dev_addr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
.buffer = _hub_buffer,
|
||||
.buffer = p_epbuf->ctrl_buf,
|
||||
.complete_cb = config_set_port_power,
|
||||
.user_data = 0
|
||||
};
|
||||
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
|
||||
TU_ASSERT(tuh_control_xfer(&xfer));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void config_set_port_power (tuh_xfer_t* xfer)
|
||||
{
|
||||
static void config_set_port_power (tuh_xfer_t* xfer) {
|
||||
TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
hub_interface_t* p_hub = get_hub_itf(daddr);
|
||||
hub_epbuf_t* p_epbuf = get_hub_epbuf(daddr);
|
||||
|
||||
// only use number of ports in hub descriptor
|
||||
descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer;
|
||||
p_hub->port_count = desc_hub->bNbrPorts;
|
||||
hub_desc_cs_t const* desc_hub = (hub_desc_cs_t const*) p_epbuf->ctrl_buf;
|
||||
p_hub->bNbrPorts = desc_hub->bNbrPorts;
|
||||
p_hub->bPwrOn2PwrGood_2ms = desc_hub->bPwrOn2PwrGood;
|
||||
|
||||
// May need to GET_STATUS
|
||||
|
||||
|
|
@ -304,22 +288,21 @@ static void config_set_port_power (tuh_xfer_t* xfer)
|
|||
hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
|
||||
}
|
||||
|
||||
static void config_port_power_complete (tuh_xfer_t* xfer)
|
||||
{
|
||||
static void config_port_power_complete (tuh_xfer_t* xfer) {
|
||||
TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
hub_interface_t* p_hub = get_hub_itf(daddr);
|
||||
|
||||
if (xfer->setup->wIndex == p_hub->port_count)
|
||||
{
|
||||
if (xfer->setup->wIndex == p_hub->bNbrPorts) {
|
||||
// All ports are power -> queue notification status endpoint and
|
||||
// complete the SET CONFIGURATION
|
||||
TU_ASSERT( usbh_edpt_xfer(daddr, p_hub->ep_in, &p_hub->status_change, 1), );
|
||||
|
||||
if (!hub_edpt_status_xfer(daddr)) {
|
||||
TU_MESS_FAILED();
|
||||
TU_BREAKPOINT();
|
||||
}
|
||||
usbh_driver_set_config_complete(daddr, p_hub->itf_num);
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// power next port
|
||||
uint8_t const hub_port = (uint8_t) (xfer->setup->wIndex + 1);
|
||||
hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
|
||||
|
|
@ -329,180 +312,162 @@ static void config_port_power_complete (tuh_xfer_t* xfer)
|
|||
//--------------------------------------------------------------------+
|
||||
// Connection Changes
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void hub_port_get_status_complete (tuh_xfer_t* xfer);
|
||||
static void hub_get_status_complete (tuh_xfer_t* xfer);
|
||||
static void get_status_complete (tuh_xfer_t* xfer);
|
||||
static void port_get_status_complete (tuh_xfer_t* xfer);
|
||||
static void port_clear_feature_complete_stub(tuh_xfer_t* xfer);
|
||||
static void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
|
||||
static void connection_port_reset_complete (tuh_xfer_t* xfer);
|
||||
|
||||
// callback as response of interrupt endpoint polling
|
||||
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
|
||||
bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
(void) xferred_bytes;
|
||||
(void) ep_addr;
|
||||
TU_VERIFY(result == XFER_RESULT_SUCCESS);
|
||||
|
||||
hub_interface_t* p_hub = get_itf(dev_addr);
|
||||
bool processed = false; // true if new status is processed
|
||||
|
||||
uint8_t const status_change = p_hub->status_change;
|
||||
TU_LOG2(" Hub Status Change = 0x%02X\r\n", status_change);
|
||||
if (result == XFER_RESULT_SUCCESS) {
|
||||
hub_interface_t* p_hub = get_hub_itf(daddr);
|
||||
hub_epbuf_t *p_epbuf = get_hub_epbuf(daddr);
|
||||
const uint8_t status_change = p_epbuf->status_change[0];
|
||||
TU_LOG_DRV(" Hub Status Change = 0x%02X\r\n", status_change);
|
||||
|
||||
if ( status_change == 0 ) {
|
||||
// The status change event was neither for the hub, nor for any of its ports.
|
||||
// This shouldn't happen, but it does with some devices.
|
||||
// Initiate the next interrupt poll here.
|
||||
return hub_edpt_status_xfer(dev_addr);
|
||||
}
|
||||
|
||||
if (tu_bit_test(status_change, 0)) {
|
||||
// Hub bit 0 is for the hub device events
|
||||
if (hub_port_get_status(dev_addr, 0, &p_hub->hub_status, hub_get_status_complete, 0) == false) {
|
||||
//Hub status control transfer failed, retry
|
||||
hub_edpt_status_xfer(dev_addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Hub bits 1 to n are hub port events
|
||||
for (uint8_t port=1; port <= p_hub->port_count; port++) {
|
||||
if ( tu_bit_test(status_change, port) ) {
|
||||
if (hub_port_get_status(dev_addr, port, &p_hub->port_status, hub_port_get_status_complete, 0) == false) {
|
||||
//Hub status control transfer failed, retry
|
||||
hub_edpt_status_xfer(dev_addr);
|
||||
if (status_change == 0) {
|
||||
// The status change event was neither for the hub, nor for any of its ports.
|
||||
// This shouldn't happen, but it does with some devices. Re-Initiate the interrupt poll.
|
||||
processed = false;
|
||||
} else if (tu_bit_test(status_change, 0)) {
|
||||
// Hub bit 0 is for the hub device events
|
||||
processed = hub_get_status(daddr, p_epbuf->ctrl_buf, get_status_complete, 0);
|
||||
} else {
|
||||
// Hub bits 1 to n are hub port events
|
||||
for (uint8_t port=1; port <= p_hub->bNbrPorts; port++) {
|
||||
if (tu_bit_test(status_change, port)) {
|
||||
processed = hub_port_get_status(daddr, port, p_epbuf->ctrl_buf, port_get_status_complete, 0);
|
||||
break; // after completely processed one port, we will re-queue the status poll and handle next one
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: next status transfer is queued by usbh.c after handling this request
|
||||
// If new status event is processed: next status pool is queued by usbh.c after handled this request
|
||||
// Otherwise re-queue the status poll here
|
||||
if (!processed) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void hub_clear_feature_complete_stub(tuh_xfer_t* xfer)
|
||||
{
|
||||
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
|
||||
static void port_clear_feature_complete_stub(tuh_xfer_t* xfer) {
|
||||
hub_edpt_status_xfer(xfer->daddr);
|
||||
}
|
||||
|
||||
static void hub_get_status_complete (tuh_xfer_t* xfer)
|
||||
{
|
||||
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
|
||||
static void get_status_complete(tuh_xfer_t *xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
TU_ASSERT(port_num == 0 , );
|
||||
bool processed = false; // true if new status is processed
|
||||
if (xfer->result == XFER_RESULT_SUCCESS) {
|
||||
hub_status_response_t hub_status = *((const hub_status_response_t *) (uintptr_t) xfer->buffer);
|
||||
|
||||
TU_LOG2("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, p_hub->hub_status.change.value);
|
||||
TU_LOG_DRV("HUB Got hub status, addr = %u, status = %04x\r\n", daddr, hub_status.change.value);
|
||||
|
||||
if (p_hub->hub_status.change.local_power_source)
|
||||
{
|
||||
TU_LOG2("HUB Local Power Change, addr = %u\r\n", daddr);
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, hub_clear_feature_complete_stub, 0);
|
||||
if (hub_status.change.local_power_source) {
|
||||
TU_LOG_DRV(" Local Power Change\r\n");
|
||||
processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_LOCAL_POWER_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (hub_status.change.over_current) {
|
||||
TU_LOG_DRV(" Over Current\r\n");
|
||||
processed = hub_clear_feature(daddr, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
}
|
||||
}
|
||||
else if (p_hub->hub_status.change.over_current)
|
||||
{
|
||||
TU_LOG1("HUB Over Current, addr = %u\r\n", daddr);
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_HUB_OVER_CURRENT_CHANGE, hub_clear_feature_complete_stub, 0);
|
||||
|
||||
if (!processed) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), );
|
||||
}
|
||||
}
|
||||
|
||||
static void hub_port_get_status_complete (tuh_xfer_t* xfer)
|
||||
{
|
||||
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
|
||||
static void port_get_status_complete(tuh_xfer_t *xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
bool processed = false; // true if new status is processed
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
if (xfer->result == XFER_RESULT_SUCCESS) {
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
hub_interface_t *p_hub = get_hub_itf(daddr);
|
||||
p_hub->port_status = *((const hub_port_status_response_t *) (uintptr_t) xfer->buffer);
|
||||
|
||||
// Connection change
|
||||
if (p_hub->port_status.change.connection)
|
||||
{
|
||||
// Port is powered and enabled
|
||||
//TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
|
||||
// Clear port status change interrupts
|
||||
if (p_hub->port_status.change.connection) {
|
||||
// Connection change
|
||||
// Port is powered and enabled
|
||||
//TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
|
||||
|
||||
// Acknowledge Port Connection Change
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
|
||||
}else
|
||||
{
|
||||
// Clear other port status change interrupts. TODO Not currently handled - just cleared.
|
||||
if (p_hub->port_status.change.port_enable)
|
||||
{
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, hub_clear_feature_complete_stub, 0);
|
||||
// Acknowledge Port Connection Change
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
|
||||
} else if (p_hub->port_status.change.port_enable) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_ENABLE_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (p_hub->port_status.change.suspend) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (p_hub->port_status.change.over_current) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
} else if (p_hub->port_status.change.reset) {
|
||||
processed = hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, port_clear_feature_complete_stub, 0);
|
||||
}
|
||||
else if (p_hub->port_status.change.suspend)
|
||||
{
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_SUSPEND_CHANGE, hub_clear_feature_complete_stub, 0);
|
||||
}
|
||||
else if (p_hub->port_status.change.over_current)
|
||||
{
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_OVER_CURRENT_CHANGE, hub_clear_feature_complete_stub, 0);
|
||||
}
|
||||
else if (p_hub->port_status.change.reset)
|
||||
{
|
||||
hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_RESET_CHANGE, hub_clear_feature_complete_stub, 0);
|
||||
}
|
||||
// Other changes are: L1 state
|
||||
// TODO clear change
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// prepare for next hub status
|
||||
// TODO continue with status_change, or maybe we can do it again with status
|
||||
hub_edpt_status_xfer(daddr);
|
||||
}
|
||||
if (!processed) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), );
|
||||
}
|
||||
}
|
||||
|
||||
static void connection_clear_conn_change_complete (tuh_xfer_t* xfer)
|
||||
{
|
||||
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
|
||||
static void connection_clear_conn_change_complete (tuh_xfer_t* xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
if (xfer->result != XFER_RESULT_SUCCESS) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( p_hub->port_status.status.connection )
|
||||
{
|
||||
hub_interface_t *p_hub = get_hub_itf(daddr);
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
|
||||
if (p_hub->port_status.status.connection) {
|
||||
// Reset port if attach event
|
||||
hub_port_reset(daddr, port_num, connection_port_reset_complete, 0);
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// submit detach event
|
||||
hcd_event_t event =
|
||||
{
|
||||
const hcd_event_t event = {
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = HCD_EVENT_DEVICE_REMOVE,
|
||||
.connection =
|
||||
{
|
||||
.connection = {
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
|
||||
hcd_event_handler(&event, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void connection_port_reset_complete (tuh_xfer_t* xfer)
|
||||
{
|
||||
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
|
||||
static void connection_port_reset_complete (tuh_xfer_t* xfer) {
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
// hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
if (xfer->result != XFER_RESULT_SUCCESS) {
|
||||
// retry port reset if failed
|
||||
if (!tuh_control_xfer(xfer)) {
|
||||
TU_ASSERT(hub_edpt_status_xfer(daddr), ); // back to status poll if failed to queue request
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
|
||||
// submit attach event
|
||||
hcd_event_t event =
|
||||
{
|
||||
hcd_event_t event = {
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = HCD_EVENT_DEVICE_ATTACH,
|
||||
.connection =
|
||||
{
|
||||
.connection = {
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
|
||||
hcd_event_handler(&event, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
186
src/host/hub.h
186
src/host/hub.h
|
|
@ -24,17 +24,8 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup group_class
|
||||
* \defgroup ClassDriver_Hub Hub (Host only)
|
||||
* \details Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether
|
||||
* a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed
|
||||
* by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application.
|
||||
* \note Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_HUB_H_
|
||||
#define _TUSB_HUB_H_
|
||||
#ifndef TUSB_HUB_H_
|
||||
#define TUSB_HUB_H_
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
|
|
@ -42,63 +33,23 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
//D1...D0: Logical Power Switching Mode
|
||||
//00: Ganged power switching (all ports’power at
|
||||
//once)
|
||||
//01: Individual port power switching
|
||||
//1X: Reserved. Used only on 1.0 compliant hubs
|
||||
//that implement no power switching
|
||||
//D2: Identifies a Compound Device
|
||||
//0: Hub is not part of a compound device.
|
||||
//1: Hub is part of a compound device.
|
||||
//D4...D3: Over-current Protection Mode
|
||||
//00: Global Over-current Protection. The hub
|
||||
//reports over-current as a summation of all
|
||||
//ports’current draw, without a breakdown of
|
||||
//individual port over-current status.
|
||||
//01: Individual Port Over-current Protection. The
|
||||
//hub reports over-current on a per-port basis.
|
||||
//Each port has an over-current status.
|
||||
//1X: No Over-current Protection. This option is
|
||||
//allowed only for bus-powered hubs that do not
|
||||
//implement over-current protection.
|
||||
//--------------------------------------------------------------------+
|
||||
// Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#ifndef CFG_TUH_HUB_BUFSIZE
|
||||
#define CFG_TUH_HUB_BUFSIZE 12
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//D6...D5: TT Think TIme
|
||||
//00: TT requires at most 8 FS bit times of inter
|
||||
//transaction gap on a full-/low-speed
|
||||
//downstream bus.
|
||||
//01: TT requires at most 16 FS bit times.
|
||||
//10: TT requires at most 24 FS bit times.
|
||||
//11: TT requires at most 32 FS bit times.
|
||||
//D7: Port Indicators Supported
|
||||
//0: Port Indicators are not supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request has no effect.
|
||||
//1: Port Indicators are supported on its
|
||||
//downstream facing ports and the
|
||||
//PORT_INDICATOR request controls the
|
||||
//indicators. See Section 11.5.3.
|
||||
//D15...D8: Reserved
|
||||
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint8_t bNbrPorts;
|
||||
uint16_t wHubCharacteristics;
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
uint8_t DeviceRemovable; // bitmap each bit for a port (from bit1)
|
||||
uint8_t PortPwrCtrlMask; // just for compatibility, should be 0xff
|
||||
} descriptor_hub_desc_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
enum {
|
||||
HUB_REQUEST_GET_STATUS = 0 ,
|
||||
HUB_REQUEST_CLEAR_FEATURE = 1 ,
|
||||
|
||||
// 2 is reserved
|
||||
HUB_REQUEST_SET_FEATURE = 3 ,
|
||||
|
||||
// 4-5 are reserved
|
||||
HUB_REQUEST_GET_DESCRIPTOR = 6 ,
|
||||
HUB_REQUEST_SET_DESCRIPTOR = 7 ,
|
||||
HUB_REQUEST_CLEAR_TT_BUFFER = 8 ,
|
||||
|
|
@ -118,10 +69,10 @@ enum{
|
|||
HUB_FEATURE_PORT_SUSPEND = 2,
|
||||
HUB_FEATURE_PORT_OVER_CURRENT = 3,
|
||||
HUB_FEATURE_PORT_RESET = 4,
|
||||
|
||||
// 5-7 are reserved
|
||||
HUB_FEATURE_PORT_POWER = 8,
|
||||
HUB_FEATURE_PORT_LOW_SPEED = 9,
|
||||
|
||||
// 10-15 are reserved
|
||||
HUB_FEATURE_PORT_CONNECTION_CHANGE = 16,
|
||||
HUB_FEATURE_PORT_ENABLE_CHANGE = 17,
|
||||
HUB_FEATURE_PORT_SUSPEND_CHANGE = 18,
|
||||
|
|
@ -131,6 +82,41 @@ enum{
|
|||
HUB_FEATURE_PORT_INDICATOR = 22
|
||||
};
|
||||
|
||||
enum {
|
||||
HUB_CHARS_POWER_GANGED_SWITCHING = 0,
|
||||
HUB_CHARS_POWER_INDIVIDUAL_SWITCHING = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
HUB_CHARS_OVER_CURRENT_GLOBAL = 0,
|
||||
HUB_CHARS_OVER_CURRENT_INDIVIDUAL = 1,
|
||||
};
|
||||
|
||||
typedef struct TU_ATTR_PACKED{
|
||||
uint8_t bLength ; ///< Size of descriptor
|
||||
uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
|
||||
uint8_t bNbrPorts;
|
||||
uint16_t wHubCharacteristics;
|
||||
uint8_t bPwrOn2PwrGood;
|
||||
uint8_t bHubContrCurrent;
|
||||
uint8_t DeviceRemovable; // bitmap each bit for a port (from bit1)
|
||||
uint8_t PortPwrCtrlMask; // just for compatibility, should be 0xff
|
||||
} hub_desc_cs_t;
|
||||
TU_VERIFY_STATIC(sizeof(hub_desc_cs_t) == 9, "size is not correct");
|
||||
TU_VERIFY_STATIC(CFG_TUH_HUB_BUFSIZE >= sizeof(hub_desc_cs_t), "buffer is not big enough");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint8_t logical_power_switching_mode : 2; // [0..1] gannged or individual power switching
|
||||
uint8_t compound_device : 1; // [2] hub is part of compound device
|
||||
uint8_t over_current_protect_mode : 2; // [3..4] global or individual port over-current protection
|
||||
uint8_t tt_think_time : 2; // [5..6] TT think time
|
||||
uint8_t port_indicator_supported : 1; // [7] port indicator supported
|
||||
};
|
||||
uint8_t rsv1;
|
||||
} hub_characteristics_t;
|
||||
TU_VERIFY_STATIC(sizeof(hub_characteristics_t) == 2, "size is not correct");
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
|
||||
typedef struct {
|
||||
union{
|
||||
|
|
@ -143,48 +129,52 @@ typedef struct {
|
|||
uint16_t value;
|
||||
} status, change;
|
||||
} hub_status_response_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct");
|
||||
|
||||
// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
|
||||
typedef struct {
|
||||
union {
|
||||
union TU_ATTR_PACKED {
|
||||
struct TU_ATTR_PACKED {
|
||||
uint16_t connection : 1;
|
||||
uint16_t port_enable : 1;
|
||||
uint16_t suspend : 1;
|
||||
uint16_t over_current : 1;
|
||||
uint16_t reset : 1;
|
||||
// Bit 0-4 are for change & status
|
||||
uint16_t connection : 1; // [0] 0 = no device, 1 = device connected
|
||||
uint16_t port_enable : 1; // [1] port is enabled
|
||||
uint16_t suspend : 1; // [2]
|
||||
uint16_t over_current : 1; // [3] over-current exists
|
||||
uint16_t reset : 1; // [4] 0 = no reset, 1 = resetting
|
||||
|
||||
uint16_t : 3;
|
||||
uint16_t port_power : 1;
|
||||
uint16_t low_speed : 1;
|
||||
uint16_t high_speed : 1;
|
||||
uint16_t port_test_mode : 1;
|
||||
uint16_t port_indicator_control : 1;
|
||||
uint16_t TU_RESERVED : 3;
|
||||
// From Bit 5 are for status only
|
||||
uint16_t rsv5_7 : 3; // [5..7] reserved
|
||||
uint16_t port_power : 1; // [8] 0 = port is off, 1 = port is on
|
||||
uint16_t low_speed : 1; // [9] low speed device attached
|
||||
uint16_t high_speed : 1; // [10] high speed device attached
|
||||
uint16_t port_test_mode : 1; // [11] port in test mode
|
||||
uint16_t port_indicator_control : 1; // [12] 0: default color, 1: indicator is software controlled
|
||||
uint16_t TU_RESERVED : 3; // [13..15] reserved
|
||||
};
|
||||
|
||||
uint16_t value;
|
||||
} status, change;
|
||||
} hub_port_status_response_t;
|
||||
|
||||
TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
|
||||
|
||||
// Clear feature
|
||||
bool hub_port_clear_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
//--------------------------------------------------------------------+
|
||||
// HUB API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Set feature
|
||||
bool hub_port_set_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
// Clear port feature
|
||||
bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
// Set port feature
|
||||
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
// Get port status
|
||||
bool hub_port_get_status (uint8_t hub_addr, uint8_t hub_port, void* resp,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void *resp,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
// Get status from Interrupt endpoint
|
||||
bool hub_edpt_status_xfer(uint8_t dev_addr);
|
||||
bool hub_edpt_status_xfer(uint8_t daddr);
|
||||
|
||||
// Reset a port
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
|
|
@ -192,13 +182,23 @@ bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb_t complete_c
|
|||
return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_data);
|
||||
}
|
||||
|
||||
// Clear Reset Change
|
||||
// Clear Port Reset Change
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
|
||||
}
|
||||
|
||||
// Get Hub status
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool hub_get_status(uint8_t hub_addr, void* resp, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
return hub_port_get_status(hub_addr, 0, resp, complete_cb, user_data);
|
||||
}
|
||||
|
||||
// Clear Hub feature
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool hub_clear_feature(uint8_t hub_addr, uint8_t feature, tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
return hub_port_clear_feature(hub_addr, 0, feature, complete_cb, user_data);
|
||||
}
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -206,13 +206,11 @@ bool hub_init (void);
|
|||
bool hub_deinit (void);
|
||||
bool hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
|
||||
bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool hub_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
bool hub_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hub_close (uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HUB_H_ */
|
||||
|
||||
/** @} */
|
||||
#endif
|
||||
|
|
|
|||
549
src/host/usbh.c
549
src/host/usbh.c
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
|
|
@ -49,6 +44,10 @@
|
|||
#define CFG_TUH_INTERFACE_MAX 8
|
||||
#endif
|
||||
|
||||
enum {
|
||||
USBH_CONTROL_RETRY_MAX = 3,
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Weak stubs: invoked if no strong implementation is available
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -70,31 +69,20 @@ TU_ATTR_WEAK void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_is
|
|||
(void) in_isr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// ESP32 out-of-sync
|
||||
//--------------------------------------------------------------------+
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
TU_ATTR_WEAK bool hcd_dcache_clean(const void* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(2, 0, 14) && !defined(PLATFORMIO)
|
||||
extern bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
|
||||
#endif
|
||||
TU_ATTR_WEAK bool hcd_dcache_invalidate(const void* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef TU_LOG_BUF
|
||||
#if CFG_TUSB_DEBUG >= CFG_TUH_LOG_LEVEL
|
||||
static inline void tu_print_buf(uint8_t const* buf, uint32_t bufsize) {
|
||||
for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
|
||||
}
|
||||
#define TU_LOG_BUF(lvl, _buf, _bufsize) tu_print_buf(_buf, _bufsize)
|
||||
#else
|
||||
#define TU_LOG_BUF(lvl, _buf, _bufsize)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // ESP32
|
||||
|
||||
#ifndef TU_LOG_USBH
|
||||
#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__)
|
||||
#endif
|
||||
TU_ATTR_WEAK bool hcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
|
||||
(void) addr; (void) data_size;
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD common data structure
|
||||
|
|
@ -168,65 +156,65 @@ typedef struct {
|
|||
#endif
|
||||
|
||||
static usbh_class_driver_t const usbh_class_drivers[] = {
|
||||
#if CFG_TUH_CDC
|
||||
{
|
||||
.name = DRIVER_NAME("CDC"),
|
||||
.init = cdch_init,
|
||||
.deinit = cdch_deinit,
|
||||
.open = cdch_open,
|
||||
.set_config = cdch_set_config,
|
||||
.xfer_cb = cdch_xfer_cb,
|
||||
.close = cdch_close
|
||||
},
|
||||
#endif
|
||||
#if CFG_TUH_CDC
|
||||
{
|
||||
.name = DRIVER_NAME("CDC"),
|
||||
.init = cdch_init,
|
||||
.deinit = cdch_deinit,
|
||||
.open = cdch_open,
|
||||
.set_config = cdch_set_config,
|
||||
.xfer_cb = cdch_xfer_cb,
|
||||
.close = cdch_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_MSC
|
||||
{
|
||||
.name = DRIVER_NAME("MSC"),
|
||||
.init = msch_init,
|
||||
.deinit = msch_deinit,
|
||||
.open = msch_open,
|
||||
.set_config = msch_set_config,
|
||||
.xfer_cb = msch_xfer_cb,
|
||||
.close = msch_close
|
||||
},
|
||||
#endif
|
||||
#if CFG_TUH_MSC
|
||||
{
|
||||
.name = DRIVER_NAME("MSC"),
|
||||
.init = msch_init,
|
||||
.deinit = msch_deinit,
|
||||
.open = msch_open,
|
||||
.set_config = msch_set_config,
|
||||
.xfer_cb = msch_xfer_cb,
|
||||
.close = msch_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_HID
|
||||
{
|
||||
.name = DRIVER_NAME("HID"),
|
||||
.init = hidh_init,
|
||||
.deinit = hidh_deinit,
|
||||
.open = hidh_open,
|
||||
.set_config = hidh_set_config,
|
||||
.xfer_cb = hidh_xfer_cb,
|
||||
.close = hidh_close
|
||||
},
|
||||
#endif
|
||||
#if CFG_TUH_HID
|
||||
{
|
||||
.name = DRIVER_NAME("HID"),
|
||||
.init = hidh_init,
|
||||
.deinit = hidh_deinit,
|
||||
.open = hidh_open,
|
||||
.set_config = hidh_set_config,
|
||||
.xfer_cb = hidh_xfer_cb,
|
||||
.close = hidh_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_HUB
|
||||
{
|
||||
.name = DRIVER_NAME("HUB"),
|
||||
.init = hub_init,
|
||||
.deinit = hub_deinit,
|
||||
.open = hub_open,
|
||||
.set_config = hub_set_config,
|
||||
.xfer_cb = hub_xfer_cb,
|
||||
.close = hub_close
|
||||
},
|
||||
#endif
|
||||
#if CFG_TUH_HUB
|
||||
{
|
||||
.name = DRIVER_NAME("HUB"),
|
||||
.init = hub_init,
|
||||
.deinit = hub_deinit,
|
||||
.open = hub_open,
|
||||
.set_config = hub_set_config,
|
||||
.xfer_cb = hub_xfer_cb,
|
||||
.close = hub_close
|
||||
},
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_VENDOR
|
||||
{
|
||||
.name = DRIVER_NAME("VENDOR"),
|
||||
.init = cush_init,
|
||||
.deinit = cush_deinit,
|
||||
.open = cush_open,
|
||||
.set_config = cush_set_config,
|
||||
.xfer_cb = cush_isr,
|
||||
.close = cush_close
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUH_VENDOR
|
||||
{
|
||||
.name = DRIVER_NAME("VENDOR"),
|
||||
.init = cush_init,
|
||||
.deinit = cush_deinit,
|
||||
.open = cush_open,
|
||||
.set_config = cush_set_config,
|
||||
.xfer_cb = cush_isr,
|
||||
.close = cush_close
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
|
||||
|
|
@ -280,25 +268,28 @@ static usbh_device_t _usbh_devices[TOTAL_DEVICES];
|
|||
OSAL_QUEUE_DEF(usbh_int_set, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t);
|
||||
static osal_queue_t _usbh_q;
|
||||
|
||||
CFG_TUH_MEM_SECTION CFG_TUH_MEM_ALIGN
|
||||
static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
|
||||
|
||||
// Control transfers: since most controllers do not support multiple control transfers
|
||||
// on multiple devices concurrently and control transfers are not used much except for
|
||||
// enumeration, we will only execute control transfers one at a time.
|
||||
CFG_TUH_MEM_SECTION struct {
|
||||
CFG_TUH_MEM_ALIGN tusb_control_request_t request;
|
||||
static struct {
|
||||
uint8_t* buffer;
|
||||
tuh_xfer_cb_t complete_cb;
|
||||
uintptr_t user_data;
|
||||
|
||||
uint8_t daddr;
|
||||
volatile uint8_t stage;
|
||||
uint8_t daddr;
|
||||
volatile uint16_t actual_len;
|
||||
}_ctrl_xfer;
|
||||
uint8_t failed_count;
|
||||
} _ctrl_xfer;
|
||||
|
||||
typedef struct {
|
||||
TUH_EPBUF_TYPE_DEF(tusb_control_request_t, request);
|
||||
TUH_EPBUF_DEF(ctrl, CFG_TUH_ENUMERATION_BUFSIZE);
|
||||
} usbh_epbuf_t;
|
||||
|
||||
CFG_TUH_MEM_SECTION static usbh_epbuf_t _usbh_epbuf;
|
||||
|
||||
//------------- Helper Function -------------//
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline usbh_device_t* get_device(uint8_t dev_addr) {
|
||||
TU_VERIFY(dev_addr > 0 && dev_addr <= TOTAL_DEVICES, NULL);
|
||||
return &_usbh_devices[dev_addr-1];
|
||||
|
|
@ -309,15 +300,6 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
|
|||
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
||||
static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
// TODO rework time-related function later
|
||||
// weak and overridable
|
||||
TU_ATTR_WEAK void osal_task_delay(uint32_t msec) {
|
||||
const uint32_t start = hcd_frame_number(_usbh_controller);
|
||||
while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {}
|
||||
}
|
||||
#endif
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(hcd_event_t const * event, bool in_isr) {
|
||||
TU_ASSERT(osal_queue_send(_usbh_q, event, in_isr));
|
||||
tuh_event_hook_cb(event->rhport, event->event_id, in_isr);
|
||||
|
|
@ -334,6 +316,15 @@ bool tuh_mounted(uint8_t dev_addr) {
|
|||
return dev->configured;
|
||||
}
|
||||
|
||||
bool tuh_connected(uint8_t daddr) {
|
||||
if (daddr == 0) {
|
||||
return _dev0.enumerating; // dev0 is connected if still enumerating
|
||||
} else {
|
||||
const usbh_device_t* dev = get_device(daddr);
|
||||
return dev && dev->connected;
|
||||
}
|
||||
}
|
||||
|
||||
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) {
|
||||
*vid = *pid = 0;
|
||||
|
||||
|
|
@ -443,7 +434,9 @@ bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||
}
|
||||
|
||||
bool tuh_deinit(uint8_t rhport) {
|
||||
if (!tuh_rhport_is_active(rhport)) return true;
|
||||
if (!tuh_rhport_is_active(rhport)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// deinit host controller
|
||||
hcd_int_disable(rhport);
|
||||
|
|
@ -478,9 +471,9 @@ bool tuh_deinit(uint8_t rhport) {
|
|||
}
|
||||
|
||||
bool tuh_task_event_ready(void) {
|
||||
// Skip if stack is not initialized
|
||||
if ( !tuh_inited() ) return false;
|
||||
|
||||
if (!tuh_inited()) {
|
||||
return false; // Skip if stack is not initialized
|
||||
}
|
||||
return !osal_queue_empty(_usbh_q);
|
||||
}
|
||||
|
||||
|
|
@ -489,13 +482,11 @@ bool tuh_task_event_ready(void) {
|
|||
* This should be called periodically within the mainloop or rtos thread.
|
||||
*
|
||||
@code
|
||||
int main(void)
|
||||
{
|
||||
int main(void) {
|
||||
application_init();
|
||||
tusb_init(0, TUSB_ROLE_HOST);
|
||||
|
||||
while(1) // the mainloop
|
||||
{
|
||||
while(1) { // the mainloop
|
||||
application_code();
|
||||
tuh_task(); // tinyusb host task
|
||||
}
|
||||
|
|
@ -506,7 +497,9 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
|
|||
(void) in_isr; // not implemented yet
|
||||
|
||||
// Skip if stack is not initialized
|
||||
if (!tuh_inited()) return;
|
||||
if (!tuh_inited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop until there is no more events in the queue
|
||||
while (1) {
|
||||
|
|
@ -515,20 +508,30 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
|
|||
|
||||
switch (event.event_id) {
|
||||
case HCD_EVENT_DEVICE_ATTACH:
|
||||
// due to the shared _usbh_ctrl_buf, we must complete enumerating one device before enumerating another one.
|
||||
// due to the shared control buffer, we must complete enumerating one device before enumerating another one.
|
||||
// TODO better to have an separated queue for newly attached devices
|
||||
if (_dev0.enumerating) {
|
||||
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
|
||||
// Some device can cause multiple duplicated attach events
|
||||
// drop current enumerating and start over for a proper port reset
|
||||
if (event.rhport == _dev0.rhport && event.connection.hub_addr == _dev0.hub_addr &&
|
||||
event.connection.hub_port == _dev0.hub_port) {
|
||||
// abort/cancel current enumeration and start new one
|
||||
TU_LOG1("[%u:] USBH Device Attach (duplicated)\r\n", event.rhport);
|
||||
tuh_edpt_abort_xfer(0, 0);
|
||||
enum_new_device(&event);
|
||||
} else {
|
||||
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
|
||||
|
||||
bool is_empty = osal_queue_empty(_usbh_q);
|
||||
queue_event(&event, in_isr);
|
||||
bool is_empty = osal_queue_empty(_usbh_q);
|
||||
queue_event(&event, in_isr);
|
||||
|
||||
if (is_empty) {
|
||||
// Exit if this is the only event in the queue, otherwise we may loop forever
|
||||
return;
|
||||
if (is_empty) {
|
||||
// Exit if this is the only event in the queue, otherwise we may loop forever
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
|
||||
TU_LOG1("[%u:] USBH Device Attach\r\n", event.rhport);
|
||||
_dev0.enumerating = 1;
|
||||
enum_new_device(&event);
|
||||
}
|
||||
|
|
@ -630,17 +633,9 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer) {
|
|||
|
||||
// TODO timeout_ms is not supported yet
|
||||
bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
||||
// EP0 with setup packet
|
||||
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup);
|
||||
|
||||
// Check if device is still connected (enumerating for dev0)
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
if ( daddr == 0 ) {
|
||||
if (!_dev0.enumerating) return false;
|
||||
} else {
|
||||
usbh_device_t const* dev = get_device(daddr);
|
||||
if (dev && dev->connected == 0) return false;
|
||||
}
|
||||
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup); // EP0 with setup packet
|
||||
const uint8_t daddr = xfer->daddr;
|
||||
TU_VERIFY(tuh_connected(daddr)); // Check if device is still connected (enumerating for dev0)
|
||||
|
||||
// pre-check to help reducing mutex lock
|
||||
TU_VERIFY(_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
|
||||
|
|
@ -648,14 +643,15 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
|||
|
||||
bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
|
||||
if (is_idle) {
|
||||
_ctrl_xfer.stage = CONTROL_STAGE_SETUP;
|
||||
_ctrl_xfer.daddr = daddr;
|
||||
_ctrl_xfer.actual_len = 0;
|
||||
_ctrl_xfer.stage = CONTROL_STAGE_SETUP;
|
||||
_ctrl_xfer.daddr = daddr;
|
||||
_ctrl_xfer.actual_len = 0;
|
||||
_ctrl_xfer.failed_count = 0;
|
||||
|
||||
_ctrl_xfer.request = (*xfer->setup);
|
||||
_ctrl_xfer.buffer = xfer->buffer;
|
||||
_ctrl_xfer.complete_cb = xfer->complete_cb;
|
||||
_ctrl_xfer.user_data = xfer->user_data;
|
||||
_ctrl_xfer.buffer = xfer->buffer;
|
||||
_ctrl_xfer.complete_cb = xfer->complete_cb;
|
||||
_ctrl_xfer.user_data = xfer->user_data;
|
||||
_usbh_epbuf.request = (*xfer->setup);
|
||||
}
|
||||
|
||||
(void) osal_mutex_unlock(_usbh_mutex);
|
||||
|
|
@ -669,7 +665,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
|||
TU_LOG_BUF_USBH(xfer->setup, 8);
|
||||
|
||||
if (xfer->complete_cb) {
|
||||
TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.request) );
|
||||
TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) &_usbh_epbuf.request));
|
||||
}else {
|
||||
// blocking if complete callback is not provided
|
||||
// change callback to internal blocking, and result as user argument
|
||||
|
|
@ -679,7 +675,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
|||
_ctrl_xfer.user_data = (uintptr_t) &result;
|
||||
_ctrl_xfer.complete_cb = _control_blocking_complete_cb;
|
||||
|
||||
TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t*) &_ctrl_xfer.request) );
|
||||
TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t *) &_usbh_epbuf.request));
|
||||
|
||||
while (result == XFER_RESULT_INVALID) {
|
||||
// Note: this can be called within an callback ie. part of tuh_task()
|
||||
|
|
@ -711,7 +707,7 @@ static void _control_xfer_complete(uint8_t daddr, xfer_result_t result) {
|
|||
TU_LOG_USBH("\r\n");
|
||||
|
||||
// duplicate xfer since user can execute control transfer within callback
|
||||
tusb_control_request_t const request = _ctrl_xfer.request;
|
||||
tusb_control_request_t const request = _usbh_epbuf.request;
|
||||
tuh_xfer_t xfer_temp = {
|
||||
.daddr = daddr,
|
||||
.ep_addr = 0,
|
||||
|
|
@ -734,30 +730,48 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
|
|||
(void) ep_addr;
|
||||
|
||||
const uint8_t rhport = usbh_get_rhport(daddr);
|
||||
tusb_control_request_t const * request = &_ctrl_xfer.request;
|
||||
tusb_control_request_t const * request = &_usbh_epbuf.request;
|
||||
|
||||
if (XFER_RESULT_SUCCESS != result) {
|
||||
TU_LOG_USBH("[%u:%u] Control %s, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes);
|
||||
TU_LOG_BUF_USBH(request, 8);
|
||||
switch (result) {
|
||||
case XFER_RESULT_STALLED:
|
||||
TU_LOG_USBH("[%u:%u] Control STALLED, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, xferred_bytes);
|
||||
TU_LOG_BUF_USBH(request, 8);
|
||||
_control_xfer_complete(daddr, result);
|
||||
break;
|
||||
|
||||
// terminate transfer if any stage failed
|
||||
_control_xfer_complete(daddr, result);
|
||||
}else {
|
||||
switch(_ctrl_xfer.stage) {
|
||||
case CONTROL_STAGE_SETUP:
|
||||
if (request->wLength) {
|
||||
// DATA stage: initial data toggle is always 1
|
||||
_set_control_xfer_stage(CONTROL_STAGE_DATA);
|
||||
TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) );
|
||||
return true;
|
||||
}
|
||||
case XFER_RESULT_FAILED:
|
||||
if (tuh_connected(daddr) && _ctrl_xfer.failed_count < USBH_CONTROL_RETRY_MAX) {
|
||||
TU_LOG_USBH("[%u:%u] Control FAILED %u/%u, retrying\r\n", rhport, daddr, _ctrl_xfer.failed_count+1, USBH_CONTROL_RETRY_MAX);
|
||||
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
_ctrl_xfer.stage = CONTROL_STAGE_SETUP;
|
||||
_ctrl_xfer.failed_count++;
|
||||
_ctrl_xfer.actual_len = 0; // reset actual_len
|
||||
(void) osal_mutex_unlock(_usbh_mutex);
|
||||
|
||||
TU_ASSERT(hcd_setup_send(rhport, daddr, (uint8_t const *) request));
|
||||
} else {
|
||||
TU_LOG_USBH("[%u:%u] Control FAILED, xferred_bytes = %" PRIu32 "\r\n", rhport, daddr, xferred_bytes);
|
||||
TU_LOG_BUF_USBH(request, 8);
|
||||
_control_xfer_complete(daddr, result);
|
||||
}
|
||||
break;
|
||||
|
||||
case XFER_RESULT_SUCCESS:
|
||||
switch(_ctrl_xfer.stage) {
|
||||
case CONTROL_STAGE_SETUP:
|
||||
if (request->wLength) {
|
||||
// DATA stage: initial data toggle is always 1
|
||||
_set_control_xfer_stage(CONTROL_STAGE_DATA);
|
||||
TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) );
|
||||
return true;
|
||||
}
|
||||
TU_ATTR_FALLTHROUGH;
|
||||
|
||||
case CONTROL_STAGE_DATA:
|
||||
if (request->wLength) {
|
||||
TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr);
|
||||
TU_LOG_MEM_USBH(_ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
}
|
||||
case CONTROL_STAGE_DATA:
|
||||
if (request->wLength) {
|
||||
TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, daddr);
|
||||
TU_LOG_MEM_USBH(_ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
}
|
||||
|
||||
_ctrl_xfer.actual_len = (uint16_t) xferred_bytes;
|
||||
|
||||
|
|
@ -766,23 +780,26 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
|
|||
TU_ASSERT( hcd_edpt_xfer(rhport, daddr, tu_edpt_addr(0, 1 - request->bmRequestType_bit.direction), NULL, 0) );
|
||||
break;
|
||||
|
||||
case CONTROL_STAGE_ACK: {
|
||||
// Abort all pending transfers if SET_CONFIGURATION request
|
||||
// NOTE: should we force closing all non-control endpoints in the future?
|
||||
if (request->bRequest == TUSB_REQ_SET_CONFIGURATION && request->bmRequestType == 0x00) {
|
||||
for(uint8_t epnum=1; epnum<CFG_TUH_ENDPOINT_MAX; epnum++) {
|
||||
for(uint8_t dir=0; dir<2; dir++) {
|
||||
tuh_edpt_abort_xfer(daddr, tu_edpt_addr(epnum, dir));
|
||||
case CONTROL_STAGE_ACK: {
|
||||
// Abort all pending transfers if SET_CONFIGURATION request
|
||||
// NOTE: should we force closing all non-control endpoints in the future?
|
||||
if (request->bRequest == TUSB_REQ_SET_CONFIGURATION && request->bmRequestType == 0x00) {
|
||||
for(uint8_t epnum=1; epnum<CFG_TUH_ENDPOINT_MAX; epnum++) {
|
||||
for(uint8_t dir=0; dir<2; dir++) {
|
||||
tuh_edpt_abort_xfer(daddr, tu_edpt_addr(epnum, dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_control_xfer_complete(daddr, result);
|
||||
break;
|
||||
}
|
||||
|
||||
_control_xfer_complete(daddr, result);
|
||||
break;
|
||||
default: return false; // unsupported stage
|
||||
}
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
default: return false; // unsupported result
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -809,24 +826,26 @@ bool tuh_edpt_xfer(tuh_xfer_t* xfer) {
|
|||
}
|
||||
|
||||
bool tuh_edpt_abort_xfer(uint8_t daddr, uint8_t ep_addr) {
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
TU_VERIFY(dev);
|
||||
|
||||
TU_LOG_USBH("[%u] Aborted transfer on EP %02X\r\n", daddr, ep_addr);
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
const uint8_t epnum = tu_edpt_number(ep_addr);
|
||||
const uint8_t dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
if (epnum == 0) {
|
||||
// Also include dev0 for aborting enumerating
|
||||
const uint8_t rhport = usbh_get_rhport(daddr);
|
||||
|
||||
if ( epnum == 0 ) {
|
||||
// control transfer: only 1 control at a time, check if we are aborting the current one
|
||||
TU_VERIFY(daddr == _ctrl_xfer.daddr && _ctrl_xfer.stage != CONTROL_STAGE_IDLE);
|
||||
TU_VERIFY(hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr));
|
||||
// reset control transfer state to idle
|
||||
_set_control_xfer_stage(CONTROL_STAGE_IDLE);
|
||||
hcd_edpt_abort_xfer(rhport, daddr, ep_addr);
|
||||
_set_control_xfer_stage(CONTROL_STAGE_IDLE); // reset control transfer state to idle
|
||||
} else {
|
||||
// non-control skip if not busy
|
||||
TU_VERIFY(dev->ep_status[epnum][dir].busy);
|
||||
TU_VERIFY(hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr));
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
TU_VERIFY(dev);
|
||||
|
||||
TU_VERIFY(dev->ep_status[epnum][dir].busy); // non-control skip if not busy
|
||||
hcd_edpt_abort_xfer(dev->rhport, daddr, ep_addr);
|
||||
|
||||
// mark as ready and release endpoint if transfer is aborted
|
||||
dev->ep_status[epnum][dir].busy = false;
|
||||
tu_edpt_release(&dev->ep_status[epnum][dir], _usbh_mutex);
|
||||
|
|
@ -845,7 +864,7 @@ uint8_t usbh_get_rhport(uint8_t dev_addr) {
|
|||
}
|
||||
|
||||
uint8_t *usbh_get_enum_buf(void) {
|
||||
return _usbh_ctrl_buf;
|
||||
return _usbh_epbuf.ctrl;
|
||||
}
|
||||
|
||||
void usbh_int_set(bool enabled) {
|
||||
|
|
@ -901,7 +920,6 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr) {
|
|||
}
|
||||
|
||||
// Submit an transfer
|
||||
// TODO call usbh_edpt_release if failed
|
||||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
(void) complete_cb;
|
||||
|
|
@ -1264,13 +1282,17 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
|
|||
removing_hubs |= TU_BIT(dev_id - CFG_TUH_DEVICE_MAX);
|
||||
} else {
|
||||
// Invoke callback before closing driver (maybe call it later ?)
|
||||
if (tuh_umount_cb) tuh_umount_cb(daddr);
|
||||
if (tuh_umount_cb) {
|
||||
tuh_umount_cb(daddr);
|
||||
}
|
||||
}
|
||||
|
||||
// Close class driver
|
||||
for (uint8_t drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
|
||||
usbh_class_driver_t const* driver = get_driver(drv_id);
|
||||
if (driver) driver->close(daddr);
|
||||
if (driver) {
|
||||
driver->close(daddr);
|
||||
}
|
||||
}
|
||||
|
||||
hcd_device_close(rhport, daddr);
|
||||
|
|
@ -1307,14 +1329,14 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
|
|||
// Enumeration Process
|
||||
// is a lengthy process with a series of control transfer to configure
|
||||
// newly attached device.
|
||||
// NOTE: due to the shared _usbh_ctrl_buf, we must complete enumerating
|
||||
// NOTE: due to the shared control buffer, we must complete enumerating
|
||||
// one device before enumerating another one.
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
enum {
|
||||
ENUM_RESET_DELAY = 50, // USB specs: 10 to 50ms
|
||||
ENUM_CONTACT_DEBOUNCING_DELAY = 450, // when plug/unplug a device, physical connection can be bouncing and may
|
||||
// generate a series of attach/detach event. This delay wait for stable connection
|
||||
ENUM_RESET_DELAY_MS = 50, // USB specs: 10 to 50ms
|
||||
ENUM_DEBOUNCING_DELAY_MS = 450, // when plug/unplug a device, physical connection can be bouncing and may
|
||||
// generate a series of attach/detach event. This delay wait for stable connection
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -1327,8 +1349,11 @@ enum {
|
|||
ENUM_HUB_GET_STATUS_2,
|
||||
ENUM_HUB_CLEAR_RESET_2,
|
||||
ENUM_SET_ADDR,
|
||||
|
||||
ENUM_GET_DEVICE_DESC,
|
||||
ENUM_GET_STRING_LANGUAGE_ID,
|
||||
ENUM_GET_STRING_MANUFACTURER,
|
||||
ENUM_GET_STRING_PRODUCT,
|
||||
ENUM_GET_STRING_SERIAL,
|
||||
ENUM_GET_9BYTE_CONFIG_DESC,
|
||||
ENUM_GET_FULL_CONFIG_DESC,
|
||||
ENUM_SET_CONFIG,
|
||||
|
|
@ -1341,25 +1366,25 @@ static void enum_full_complete(void);
|
|||
|
||||
// process device enumeration
|
||||
static void process_enumeration(tuh_xfer_t* xfer) {
|
||||
// Retry a few times with transfers in enumeration since device can be unstable when starting up
|
||||
enum {
|
||||
ATTEMPT_COUNT_MAX = 3,
|
||||
ATTEMPT_DELAY_MS = 100
|
||||
};
|
||||
// Retry a few times while enumerating since device can be unstable when starting up
|
||||
static uint8_t failed_count = 0;
|
||||
if (XFER_RESULT_FAILED == xfer->result) {
|
||||
enum {
|
||||
ATTEMPT_COUNT_MAX = 3,
|
||||
ATTEMPT_DELAY_MS = 100
|
||||
};
|
||||
|
||||
if (XFER_RESULT_SUCCESS != xfer->result) {
|
||||
// retry if not reaching max attempt
|
||||
failed_count++;
|
||||
bool retry = _dev0.enumerating && (failed_count < ATTEMPT_COUNT_MAX);
|
||||
if ( retry ) {
|
||||
failed_count++;
|
||||
osal_task_delay(ATTEMPT_DELAY_MS); // delay a bit
|
||||
TU_LOG1("Enumeration attempt %u\r\n", failed_count);
|
||||
if (retry) {
|
||||
tusb_time_delay_ms_api(ATTEMPT_DELAY_MS); // delay a bit
|
||||
TU_LOG1("Enumeration attempt %u/%u\r\n", failed_count+1, ATTEMPT_COUNT_MAX);
|
||||
retry = tuh_control_xfer(xfer);
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
enum_full_complete();
|
||||
enum_full_complete(); // complete as failed
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -1368,6 +1393,8 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
uintptr_t const state = xfer->user_data;
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
uint16_t langid = 0x0409; // default is English
|
||||
|
||||
switch (state) {
|
||||
#if CFG_TUH_HUB
|
||||
|
|
@ -1375,7 +1402,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
|
||||
case ENUM_HUB_CLEAR_RESET_1: {
|
||||
hub_port_status_response_t port_status;
|
||||
memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
|
||||
memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t));
|
||||
|
||||
if (!port_status.status.connection) {
|
||||
// device unplugged while delaying, nothing else to do
|
||||
|
|
@ -1395,14 +1422,14 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
}
|
||||
|
||||
case ENUM_HUB_GET_STATUS_2:
|
||||
osal_task_delay(ENUM_RESET_DELAY);
|
||||
TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf,
|
||||
tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS);
|
||||
TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl,
|
||||
process_enumeration, ENUM_HUB_CLEAR_RESET_2),);
|
||||
break;
|
||||
|
||||
case ENUM_HUB_CLEAR_RESET_2: {
|
||||
hub_port_status_response_t port_status;
|
||||
memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
|
||||
memcpy(&port_status, _usbh_epbuf.ctrl, sizeof(hub_port_status_response_t));
|
||||
|
||||
// Acknowledge Port Reset Change if Reset Successful
|
||||
if (port_status.change.reset) {
|
||||
|
|
@ -1420,7 +1447,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
|
||||
// Get first 8 bytes of device descriptor for Control Endpoint size
|
||||
TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n");
|
||||
TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8,
|
||||
TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_epbuf.ctrl, 8,
|
||||
process_enumeration, ENUM_SET_ADDR),);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1433,7 +1460,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
if (_dev0.hub_addr == 0) {
|
||||
// connected directly to roothub
|
||||
hcd_port_reset( _dev0.rhport );
|
||||
osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
|
||||
tusb_time_delay_ms_api(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
|
||||
// sof of controller may not running while resetting
|
||||
hcd_port_reset_end(_dev0.rhport);
|
||||
// TODO: fall through to SET ADDRESS, refactor later
|
||||
|
|
@ -1455,10 +1482,9 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
|
||||
case ENUM_GET_DEVICE_DESC: {
|
||||
// Allow 2ms for address recovery time, Ref USB Spec 9.2.6.3
|
||||
osal_task_delay(2);
|
||||
|
||||
uint8_t const new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue);
|
||||
tusb_time_delay_ms_api(2);
|
||||
|
||||
const uint8_t new_addr = (uint8_t) tu_le16toh(xfer->setup->wValue);
|
||||
usbh_device_t* new_dev = get_device(new_addr);
|
||||
TU_ASSERT(new_dev,);
|
||||
new_dev->addressed = 1;
|
||||
|
|
@ -1471,34 +1497,80 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
|
||||
// Get full device descriptor
|
||||
TU_LOG_USBH("Get Device Descriptor\r\n");
|
||||
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t),
|
||||
process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC),);
|
||||
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_epbuf.ctrl, sizeof(tusb_desc_device_t),
|
||||
process_enumeration, ENUM_GET_STRING_LANGUAGE_ID),);
|
||||
break;
|
||||
}
|
||||
|
||||
case ENUM_GET_9BYTE_CONFIG_DESC: {
|
||||
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
case ENUM_GET_STRING_LANGUAGE_ID: {
|
||||
// save the received device descriptor
|
||||
TU_ASSERT(dev,);
|
||||
|
||||
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
|
||||
dev->vid = desc_device->idVendor;
|
||||
dev->pid = desc_device->idProduct;
|
||||
dev->i_manufacturer = desc_device->iManufacturer;
|
||||
dev->i_product = desc_device->iProduct;
|
||||
dev->i_serial = desc_device->iSerialNumber;
|
||||
|
||||
// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf);
|
||||
tuh_descriptor_get_string_langid(daddr, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
process_enumeration, ENUM_GET_STRING_MANUFACTURER);
|
||||
break;
|
||||
}
|
||||
|
||||
case ENUM_GET_STRING_MANUFACTURER: {
|
||||
TU_ASSERT(dev,);
|
||||
const tusb_desc_string_t* desc_langid = (tusb_desc_string_t const*) _usbh_epbuf.ctrl;
|
||||
if (desc_langid->bLength >= 4) {
|
||||
langid = tu_le16toh(desc_langid->utf16le[0]);
|
||||
}
|
||||
if (dev->i_manufacturer != 0) {
|
||||
tuh_descriptor_get_string(daddr, dev->i_manufacturer, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
process_enumeration, ENUM_GET_STRING_PRODUCT);
|
||||
break;
|
||||
} else {
|
||||
TU_ATTR_FALLTHROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
case ENUM_GET_STRING_PRODUCT: {
|
||||
TU_ASSERT(dev,);
|
||||
if (state == ENUM_GET_STRING_PRODUCT) {
|
||||
langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
|
||||
}
|
||||
if (dev->i_product != 0) {
|
||||
tuh_descriptor_get_string(daddr, dev->i_product, 0x0409, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
process_enumeration, ENUM_GET_STRING_SERIAL);
|
||||
break;
|
||||
} else {
|
||||
TU_ATTR_FALLTHROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
case ENUM_GET_STRING_SERIAL: {
|
||||
TU_ASSERT(dev,);
|
||||
if (state == ENUM_GET_STRING_SERIAL) {
|
||||
langid = tu_le16toh(xfer->setup->wIndex); // if not fall through, get langid from previous setup packet
|
||||
}
|
||||
if (dev->i_serial != 0) {
|
||||
tuh_descriptor_get_string(daddr, dev->i_serial, langid, _usbh_epbuf.ctrl, CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC);
|
||||
break;
|
||||
} else {
|
||||
TU_ATTR_FALLTHROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
case ENUM_GET_9BYTE_CONFIG_DESC: {
|
||||
// Get 9-byte for total length
|
||||
uint8_t const config_idx = CONFIG_NUM - 1;
|
||||
TU_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n");
|
||||
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, 9,
|
||||
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, 9,
|
||||
process_enumeration, ENUM_GET_FULL_CONFIG_DESC),);
|
||||
break;
|
||||
}
|
||||
|
||||
case ENUM_GET_FULL_CONFIG_DESC: {
|
||||
uint8_t const* desc_config = _usbh_ctrl_buf;
|
||||
uint8_t const* desc_config = _usbh_epbuf.ctrl;
|
||||
|
||||
// Use offsetof to avoid pointer to the odd/misaligned address
|
||||
uint16_t const total_len = tu_le16toh(
|
||||
|
|
@ -1510,7 +1582,7 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
// Get full configuration descriptor
|
||||
uint8_t const config_idx = CONFIG_NUM - 1;
|
||||
TU_LOG_USBH("Get Configuration[0] Descriptor\r\n");
|
||||
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, total_len,
|
||||
TU_ASSERT(tuh_descriptor_get_configuration(daddr, config_idx, _usbh_epbuf.ctrl, total_len,
|
||||
process_enumeration, ENUM_SET_CONFIG),);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1521,14 +1593,13 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
|
||||
case ENUM_CONFIG_DRIVER: {
|
||||
TU_LOG_USBH("Device configured\r\n");
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
TU_ASSERT(dev,);
|
||||
|
||||
dev->configured = 1;
|
||||
|
||||
// Parse configuration & set up drivers
|
||||
// driver_open() must not make any usb transfer
|
||||
TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_ctrl_buf),);
|
||||
TU_ASSERT(_parse_configuration_descriptor(daddr, (tusb_desc_configuration_t*) _usbh_epbuf.ctrl),);
|
||||
|
||||
// Start the Set Configuration process for interfaces (itf = TUSB_INDEX_INVALID_8)
|
||||
// Since driver can perform control transfer within its set_config, this is done asynchronously.
|
||||
|
|
@ -1545,20 +1616,25 @@ static void process_enumeration(tuh_xfer_t* xfer) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool enum_new_device(hcd_event_t* event) {
|
||||
_dev0.rhport = event->rhport;
|
||||
_dev0.hub_addr = event->connection.hub_addr;
|
||||
_dev0.hub_port = event->connection.hub_port;
|
||||
|
||||
if (_dev0.hub_addr == 0) {
|
||||
// connected/disconnected directly with roothub
|
||||
// connected directly to roothub
|
||||
hcd_port_reset(_dev0.rhport);
|
||||
osal_task_delay(ENUM_RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
|
||||
// sof of controller may not running while resetting
|
||||
|
||||
// Since we are in middle of rhport reset, frame number is not available yet.
|
||||
// need to depend on tusb_time_millis_api()
|
||||
tusb_time_delay_ms_api(ENUM_RESET_DELAY_MS);
|
||||
|
||||
hcd_port_reset_end(_dev0.rhport);
|
||||
|
||||
// wait until device connection is stable TODO non blocking
|
||||
osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);
|
||||
tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS);
|
||||
|
||||
// device unplugged while delaying
|
||||
if (!hcd_port_connect_status(_dev0.rhport)) {
|
||||
|
|
@ -1579,13 +1655,12 @@ static bool enum_new_device(hcd_event_t* event) {
|
|||
}
|
||||
#if CFG_TUH_HUB
|
||||
else {
|
||||
// connected/disconnected via external hub
|
||||
// connected via external hub
|
||||
// wait until device connection is stable TODO non blocking
|
||||
osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);
|
||||
tusb_time_delay_ms_api(ENUM_DEBOUNCING_DELAY_MS);
|
||||
|
||||
// ENUM_HUB_GET_STATUS
|
||||
//TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete, 0) );
|
||||
TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf,
|
||||
TU_ASSERT(hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_epbuf.ctrl,
|
||||
process_enumeration, ENUM_HUB_CLEAR_RESET_1));
|
||||
}
|
||||
#endif // hub
|
||||
|
|
@ -1613,7 +1688,7 @@ static uint8_t get_new_address(bool is_hub) {
|
|||
}
|
||||
|
||||
static bool enum_request_set_addr(void) {
|
||||
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
|
||||
tusb_desc_device_t const* desc_device = (tusb_desc_device_t const*) _usbh_epbuf.ctrl;
|
||||
|
||||
// Get new address
|
||||
uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
|
||||
|
|
@ -1662,6 +1737,13 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
|||
|
||||
// parse each interfaces
|
||||
while( p_desc < desc_end ) {
|
||||
if ( 0 == tu_desc_len(p_desc) ) {
|
||||
// A zero length descriptor indicates that the device is off spec (e.g. wrong wTotalLength).
|
||||
// Parsed interfaces should still be usable
|
||||
TU_LOG_USBH("Encountered a zero-length descriptor after %" PRIu32 "bytes\r\n", (uint32_t)p_desc - (uint32_t)desc_cfg);
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t assoc_itf_count = 1;
|
||||
|
||||
// Class will always starts with Interface Association (if any) and then Interface descriptor
|
||||
|
|
@ -1772,8 +1854,9 @@ static void enum_full_complete(void) {
|
|||
_dev0.enumerating = 0;
|
||||
|
||||
#if CFG_TUH_HUB
|
||||
// get next hub status
|
||||
if (_dev0.hub_addr) hub_edpt_status_xfer(_dev0.hub_addr);
|
||||
if (_dev0.hub_addr) {
|
||||
hub_edpt_status_xfer(_dev0.hub_addr); // get next hub status
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,8 +96,6 @@ typedef union {
|
|||
// APPLICATION CALLBACK
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device);
|
||||
|
||||
// Invoked when a device is mounted (configured)
|
||||
TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
|
||||
|
||||
|
|
@ -185,6 +183,10 @@ tusb_speed_t tuh_speed_get(uint8_t daddr);
|
|||
// Check if device is connected and configured
|
||||
bool tuh_mounted(uint8_t daddr);
|
||||
|
||||
// Check if device is connected which mean device has at least 1 successful transfer
|
||||
// Note: It may not be addressed/configured/mounted yet
|
||||
bool tuh_connected(uint8_t daddr);
|
||||
|
||||
// Check if device is suspended
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool tuh_suspended(uint8_t daddr) {
|
||||
|
|
@ -263,6 +265,13 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_
|
|||
bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
// Get language id string descriptor (control transfer)
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool tuh_descriptor_get_string_langid(uint8_t daddr, void* buffer, uint16_t len,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data) {
|
||||
return tuh_descriptor_get_string(daddr, 0, 0, buffer, len, complete_cb, user_data);
|
||||
}
|
||||
|
||||
// Get manufacturer string descriptor (control transfer)
|
||||
// true on success, false if there is on-going control transfer or incorrect parameters
|
||||
bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
|
||||
|
|
@ -302,6 +311,12 @@ uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8
|
|||
// return transfer result
|
||||
uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len);
|
||||
|
||||
// Sync (blocking) version of tuh_descriptor_get_string_langid()
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
uint8_t tuh_descriptor_get_string_langid_sync(uint8_t daddr, void* buffer, uint16_t len) {
|
||||
return tuh_descriptor_get_string_sync(daddr, 0, 0, buffer, len);
|
||||
}
|
||||
|
||||
// Sync (blocking) version of tuh_descriptor_get_manufacturer_string()
|
||||
// return transfer result
|
||||
uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
|
||||
|
|
|
|||
|
|
@ -27,11 +27,6 @@
|
|||
#ifndef _TUSB_USBH_PVT_H_
|
||||
#define _TUSB_USBH_PVT_H_
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "osal/osal.h"
|
||||
#include "common/tusb_fifo.h"
|
||||
#include "common/tusb_private.h"
|
||||
|
|
@ -40,11 +35,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Level where CFG_TUSB_DEBUG must be at least for USBH is logged
|
||||
#ifndef CFG_TUH_LOG_LEVEL
|
||||
#define CFG_TUH_LOG_LEVEL 2
|
||||
#endif
|
||||
|
||||
#define TU_LOG_USBH(...) TU_LOG(CFG_TUH_LOG_LEVEL, __VA_ARGS__)
|
||||
#define TU_LOG_MEM_USBH(...) TU_LOG_MEM(CFG_TUH_LOG_LEVEL, __VA_ARGS__)
|
||||
#define TU_LOG_BUF_USBH(...) TU_LOG_BUF(CFG_TUH_LOG_LEVEL, __VA_ARGS__)
|
||||
|
|
@ -93,8 +83,8 @@ void usbh_defer_func(osal_task_func_t func, void *param, bool in_isr);
|
|||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) {
|
||||
TU_ATTR_ALWAYS_INLINE static inline
|
||||
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) {
|
||||
return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ typedef void (*osal_task_func_t)( void * );
|
|||
#include "osal_rtthread.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_RTX4
|
||||
#include "osal_rtx4.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_ZEPHYR
|
||||
#include "osal_zephyr.h"
|
||||
#elif CFG_TUSB_OS == OPT_OS_CUSTOM
|
||||
#include "tusb_os_custom.h" // implemented by application
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -137,18 +137,6 @@ typedef osal_queue_def_t* osal_queue_t;
|
|||
.ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
|
||||
}
|
||||
|
||||
// lock queue by disable USB interrupt
|
||||
TU_ATTR_ALWAYS_INLINE static inline void _osal_q_lock(osal_queue_t qhdl) {
|
||||
// disable dcd/hcd interrupt
|
||||
qhdl->interrupt_set(false);
|
||||
}
|
||||
|
||||
// unlock queue
|
||||
TU_ATTR_ALWAYS_INLINE static inline void _osal_q_unlock(osal_queue_t qhdl) {
|
||||
// enable dcd/hcd interrupt
|
||||
qhdl->interrupt_set(true);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
||||
tu_fifo_clear(&qdef->ff);
|
||||
return (osal_queue_t) qdef;
|
||||
|
|
@ -162,22 +150,22 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
|
|||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
|
||||
(void) msec; // not used, always behave as msec = 0
|
||||
|
||||
_osal_q_lock(qhdl);
|
||||
bool success = tu_fifo_read(&qhdl->ff, data);
|
||||
_osal_q_unlock(qhdl);
|
||||
qhdl->interrupt_set(false);
|
||||
const bool success = tu_fifo_read(&qhdl->ff, data);
|
||||
qhdl->interrupt_set(true);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
|
||||
if (!in_isr) {
|
||||
_osal_q_lock(qhdl);
|
||||
qhdl->interrupt_set(false);
|
||||
}
|
||||
|
||||
bool success = tu_fifo_write(&qhdl->ff, data);
|
||||
const bool success = tu_fifo_write(&qhdl->ff, data);
|
||||
|
||||
if (!in_isr) {
|
||||
_osal_q_unlock(qhdl);
|
||||
qhdl->interrupt_set(true);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
|
|
|||
123
src/osal/osal_zephyr.h
Normal file
123
src/osal/osal_zephyr.h
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2025 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
#ifndef TUSB_OSAL_ZEPHYR_H
|
||||
#define TUSB_OSAL_ZEPHYR_H
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TASK API
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
|
||||
k_msleep(msec);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Binary Semaphore API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct k_sem osal_semaphore_def_t, * osal_semaphore_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) {
|
||||
k_sem_init(semdef, 0, 255);
|
||||
return semdef;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
|
||||
(void) semd_hdl;
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
|
||||
(void) in_isr;
|
||||
k_sem_give(sem_hdl);
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
|
||||
return 0 == k_sem_take(sem_hdl, K_MSEC(msec));
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl) {
|
||||
k_sem_reset(sem_hdl);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MUTEX API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct k_mutex osal_mutex_def_t, *osal_mutex_t;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
|
||||
if ( 0 == k_mutex_init(mdef) ) {
|
||||
return mdef;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
|
||||
(void) mutex_hdl;
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_lock(osal_mutex_t mutex_hdl, uint32_t msec) {
|
||||
return 0 == k_mutex_lock(mutex_hdl, K_MSEC(msec));
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hdl) {
|
||||
return 0 == k_mutex_unlock(mutex_hdl);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// QUEUE API
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct k_msgq osal_queue_def_t, * osal_queue_t;
|
||||
|
||||
// role device/host is used by OS NONE for mutex (disable usb isr) only
|
||||
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) K_MSGQ_DEFINE(_name, sizeof(_type), _depth, 4)
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
|
||||
// K_MSGQ_DEFINE already initializes the queue
|
||||
return (osal_queue_t) qdef;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
|
||||
(void) qhdl;
|
||||
return true;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
|
||||
return 0 == k_msgq_get(qhdl, data, K_MSEC(msec));
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
|
||||
return 0 == k_msgq_put(qhdl, data, in_isr ? K_NO_WAIT : K_FOREVER);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_empty(osal_queue_t qhdl) {
|
||||
return 0 == k_msgq_num_used_get(qhdl);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
|
|||
//--------------------------------------------------------------------+
|
||||
// Interrupt Handler
|
||||
//--------------------------------------------------------------------+
|
||||
void maybe_transfer_complete(void) {
|
||||
static void maybe_transfer_complete(void) {
|
||||
uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
|
||||
|
||||
for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@
|
|||
#endif
|
||||
|
||||
#include "nrf.h"
|
||||
#include "nrf_clock.h"
|
||||
#include "nrfx_usbd_errata.h"
|
||||
#include "nrfx_clock.h"
|
||||
#include "nrf_erratas.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
@ -530,7 +530,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
|||
/*------------------------------------------------------------------*/
|
||||
/* Interrupt Handler
|
||||
*------------------------------------------------------------------*/
|
||||
void bus_reset(void) {
|
||||
static void bus_reset(void) {
|
||||
// 6.35.6 USB controller automatically disabled all endpoints (except control)
|
||||
NRF_USBD->EPOUTEN = 1UL;
|
||||
NRF_USBD->EPINEN = 1UL;
|
||||
|
|
@ -901,6 +901,7 @@ static void hfclk_disable(void) {
|
|||
// Therefore this function must be called to handle USB power event by
|
||||
// - nrfx_power_usbevt_init() : if Softdevice is not used or enabled
|
||||
// - SoftDevice SOC event : if SD is used and enabled
|
||||
void tusb_hal_nrf_power_event(uint32_t event);
|
||||
void tusb_hal_nrf_power_event(uint32_t event) {
|
||||
// Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h
|
||||
enum {
|
||||
|
|
@ -925,7 +926,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
|
|||
|
||||
#ifdef NRF52_SERIES // NRF53 does not need this errata
|
||||
// ERRATA 171, 187, 166
|
||||
if (nrfx_usbd_errata_187()) {
|
||||
if (nrf52_errata_187()) {
|
||||
// CRITICAL_REGION_ENTER();
|
||||
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
|
||||
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
|
||||
|
|
@ -937,7 +938,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
|
|||
// CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
if (nrfx_usbd_errata_171()) {
|
||||
if (nrf52_errata_171()) {
|
||||
// CRITICAL_REGION_ENTER();
|
||||
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
|
||||
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
|
||||
|
|
@ -973,7 +974,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
|
|||
__DSB(); // for sync
|
||||
|
||||
#ifdef NRF52_SERIES
|
||||
if (nrfx_usbd_errata_171()) {
|
||||
if (nrf52_errata_171()) {
|
||||
// CRITICAL_REGION_ENTER();
|
||||
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
|
||||
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
|
||||
|
|
@ -986,7 +987,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
|
|||
// CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
if (nrfx_usbd_errata_187()) {
|
||||
if (nrf52_errata_187()) {
|
||||
// CRITICAL_REGION_ENTER();
|
||||
if (*((volatile uint32_t*) (0x4006EC00)) == 0x00000000) {
|
||||
*((volatile uint32_t*) (0x4006EC00)) = 0x00009375;
|
||||
|
|
@ -998,7 +999,7 @@ void tusb_hal_nrf_power_event(uint32_t event) {
|
|||
// CRITICAL_REGION_EXIT();
|
||||
}
|
||||
|
||||
if (nrfx_usbd_errata_166()) {
|
||||
if (nrf52_errata_166()) {
|
||||
*((volatile uint32_t*) (NRF_USBD_BASE + 0x800)) = 0x7E3;
|
||||
*((volatile uint32_t*) (NRF_USBD_BASE + 0x804)) = 0x40;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@
|
|||
/*------------------------------------------------------------------*/
|
||||
/* Low level controller
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// Init these in dcd_init
|
||||
static uint8_t* next_buffer_ptr;
|
||||
|
||||
|
|
@ -66,58 +65,31 @@ TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(
|
|||
return hw_endpoint_get_by_num(num, dir);
|
||||
}
|
||||
|
||||
static void _hw_endpoint_alloc(struct hw_endpoint* ep, uint8_t transfer_type) {
|
||||
// size must be multiple of 64
|
||||
uint size = tu_div_ceil(ep->wMaxPacketSize, 64) * 64u;
|
||||
// Allocate from the USB buffer space (max 3840 bytes)
|
||||
static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) {
|
||||
// round up size to multiple of 64
|
||||
size = tu_round_up(ep->wMaxPacketSize, 64);
|
||||
|
||||
// double buffered Bulk endpoint
|
||||
if (transfer_type == TUSB_XFER_BULK) {
|
||||
if (ep->transfer_type == TUSB_XFER_BULK) {
|
||||
size *= 2u;
|
||||
}
|
||||
|
||||
// assign buffer
|
||||
ep->hw_data_buf = next_buffer_ptr;
|
||||
next_buffer_ptr += size;
|
||||
|
||||
assert(((uintptr_t) next_buffer_ptr & 0b111111u) == 0);
|
||||
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
|
||||
hard_assert(hw_data_offset(next_buffer_ptr) <= USB_DPRAM_MAX);
|
||||
|
||||
pico_info(" Allocated %d bytes at offset 0x%x (0x%p)\r\n", size, dpram_offset, ep->hw_data_buf);
|
||||
|
||||
// Fill in endpoint control register with buffer offset
|
||||
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
|
||||
hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
|
||||
pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
|
||||
}
|
||||
|
||||
// Enable endpoint
|
||||
TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) {
|
||||
uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
|
||||
*ep->endpoint_control = reg;
|
||||
}
|
||||
|
||||
static void _hw_endpoint_close(struct hw_endpoint* ep) {
|
||||
// Clear hardware registers and then zero the struct
|
||||
// Clears endpoint enable
|
||||
*ep->endpoint_control = 0;
|
||||
// Clears buffer available, etc
|
||||
*ep->buffer_control = 0;
|
||||
// Clear any endpoint state
|
||||
memset(ep, 0, sizeof(struct hw_endpoint));
|
||||
|
||||
// Reclaim buffer space if all endpoints are closed
|
||||
bool reclaim_buffers = true;
|
||||
for (uint8_t i = 1; i < USB_MAX_ENDPOINTS; i++) {
|
||||
if (hw_endpoint_get_by_num(i, TUSB_DIR_OUT)->hw_data_buf != NULL ||
|
||||
hw_endpoint_get_by_num(i, TUSB_DIR_IN)->hw_data_buf != NULL) {
|
||||
reclaim_buffers = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reclaim_buffers) {
|
||||
next_buffer_ptr = &usb_dpram->epx_data[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void hw_endpoint_close(uint8_t ep_addr) {
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
_hw_endpoint_close(ep);
|
||||
}
|
||||
|
||||
// main processing for dcd_edpt_iso_activate
|
||||
static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
|
||||
|
|
@ -156,9 +128,18 @@ static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t t
|
|||
} else {
|
||||
ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// alloc a buffer and fill in endpoint control register
|
||||
_hw_endpoint_alloc(ep, transfer_type);
|
||||
// Init, allocate buffer and enable endpoint
|
||||
static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type);
|
||||
const uint8_t num = tu_edpt_number(ep_addr);
|
||||
if (num != 0) {
|
||||
// EP0 is already enabled
|
||||
hw_endpoint_alloc(ep, ep->wMaxPacketSize);
|
||||
hw_endpoint_enable(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,6 +148,32 @@ static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_by
|
|||
hw_endpoint_xfer_start(ep, buffer, total_bytes);
|
||||
}
|
||||
|
||||
static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
|
||||
// Abort any pending transfer
|
||||
// Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
|
||||
// Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
|
||||
const uint8_t dir = tu_edpt_dir(ep->ep_addr);
|
||||
const uint8_t epnum = tu_edpt_number(ep->ep_addr);
|
||||
const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
|
||||
if (rp2040_chip_version() >= 2) {
|
||||
usb_hw_set->abort = abort_mask;
|
||||
while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
|
||||
}
|
||||
|
||||
uint32_t buf_ctrl = USB_BUF_CTRL_SEL; // reset to buffer 0
|
||||
if (ep->next_pid) {
|
||||
buf_ctrl |= USB_BUF_CTRL_DATA1_PID;
|
||||
}
|
||||
|
||||
_hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
|
||||
if (rp2040_chip_version() >= 2) {
|
||||
usb_hw_clear->abort_done = abort_mask;
|
||||
usb_hw_clear->abort = abort_mask;
|
||||
}
|
||||
}
|
||||
|
||||
static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
|
||||
uint32_t remaining_buffers = usb_hw->buf_status;
|
||||
pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
|
||||
|
|
@ -197,25 +204,10 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) {
|
|||
// setup transfer. Also clear a stall in case
|
||||
for (uint8_t dir = 0; dir < 2; dir++) {
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir);
|
||||
if (ep->active) {
|
||||
// Abort any pending transfer from a prior control transfer per USB specs
|
||||
// Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
|
||||
// Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
|
||||
uint32_t const abort_mask = (dir ? USB_EP_ABORT_EP0_IN_BITS : USB_EP_ABORT_EP0_OUT_BITS);
|
||||
if (rp2040_chip_version() >= 2) {
|
||||
usb_hw_set->abort = abort_mask;
|
||||
while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
|
||||
}
|
||||
|
||||
_hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_DATA1_PID | USB_BUF_CTRL_SEL);
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
|
||||
if (rp2040_chip_version() >= 2) {
|
||||
usb_hw_clear->abort_done = abort_mask;
|
||||
usb_hw_clear->abort = abort_mask;
|
||||
}
|
||||
}
|
||||
ep->next_pid = 1u;
|
||||
if (ep->active) {
|
||||
hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -387,8 +379,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||
|
||||
// Init control endpoints
|
||||
tu_memclr(hw_endpoints[0], 2 * sizeof(hw_endpoint_t));
|
||||
hw_endpoint_init(0x0, 64, TUSB_XFER_CONTROL);
|
||||
hw_endpoint_init(0x80, 64, TUSB_XFER_CONTROL);
|
||||
hw_endpoint_open(0x0, 64, TUSB_XFER_CONTROL);
|
||||
hw_endpoint_open(0x80, 64, TUSB_XFER_CONTROL);
|
||||
|
||||
// Init non-control endpoints
|
||||
reset_non_control_endpoints();
|
||||
|
|
@ -493,9 +485,36 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
|
|||
}
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(__unused uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
|
||||
assert(rhport == 0);
|
||||
hw_endpoint_init(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), desc_edpt->bmAttributes.xfer);
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
|
||||
(void) rhport;
|
||||
const uint8_t xfer_type = desc_edpt->bmAttributes.xfer;
|
||||
TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS);
|
||||
hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
// New API: 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) {
|
||||
(void) rhport;
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
|
||||
hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
|
||||
hw_endpoint_alloc(ep, largest_packet_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
// New API: Configure and enable an ISO endpoint according to descriptor
|
||||
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
|
||||
(void) rhport;
|
||||
struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress);
|
||||
TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously
|
||||
|
||||
if (ep->active) {
|
||||
hw_endpoint_abort_xfer(ep); // abort any pending transfer
|
||||
}
|
||||
|
||||
ep->wMaxPacketSize = ep_desc->wMaxPacketSize;
|
||||
hw_endpoint_enable(ep);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -540,12 +559,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
|||
}
|
||||
}
|
||||
|
||||
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
pico_trace("dcd_edpt_close %02x\r\n", ep_addr);
|
||||
hw_endpoint_close(ep_addr);
|
||||
}
|
||||
|
||||
void __tusb_irq_path_func(dcd_int_handler)(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
dcd_rp2040_irq();
|
||||
|
|
|
|||
|
|
@ -459,28 +459,33 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport)
|
|||
}
|
||||
|
||||
// Close all opened endpoint belong to this device
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
|
||||
pico_trace("hcd_device_close %d\n", dev_addr);
|
||||
(void) rhport;
|
||||
|
||||
if (dev_addr == 0) return;
|
||||
// reset epx if it is currently active with unplugged device
|
||||
if (epx.configured && epx.active && epx.dev_addr == dev_addr) {
|
||||
epx.configured = false;
|
||||
*epx.endpoint_control = 0;
|
||||
*epx.buffer_control = 0;
|
||||
hw_endpoint_reset_transfer(&epx);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++)
|
||||
{
|
||||
hw_endpoint_t* ep = &ep_pool[i];
|
||||
// dev0 only has ep0
|
||||
if (dev_addr != 0) {
|
||||
for (size_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) {
|
||||
hw_endpoint_t *ep = &ep_pool[i];
|
||||
if (ep->dev_addr == dev_addr && ep->configured) {
|
||||
// in case it is an interrupt endpoint, disable it
|
||||
usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1));
|
||||
usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0;
|
||||
|
||||
if (ep->dev_addr == dev_addr && ep->configured)
|
||||
{
|
||||
// in case it is an interrupt endpoint, disable it
|
||||
usb_hw_clear->int_ep_ctrl = (1 << (ep->interrupt_num + 1));
|
||||
usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = 0;
|
||||
|
||||
// unconfigure the endpoint
|
||||
ep->configured = false;
|
||||
*ep->endpoint_control = 0;
|
||||
*ep->buffer_control = 0;
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
// unconfigure the endpoint
|
||||
ep->configured = false;
|
||||
*ep->endpoint_control = 0;
|
||||
*ep->buffer_control = 0;
|
||||
hw_endpoint_reset_transfer(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -557,7 +562,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
|||
}
|
||||
|
||||
// If a normal transfer (non-interrupt) then initiate using
|
||||
// sie ctrl registers. Otherwise interrupt ep registers should
|
||||
// sie ctrl registers. Otherwise, interrupt ep registers should
|
||||
// already be configured
|
||||
if ( ep == &epx )
|
||||
{
|
||||
|
|
@ -597,13 +602,12 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
|
|||
(void) rhport;
|
||||
|
||||
// Copy data into setup packet buffer
|
||||
for ( uint8_t i = 0; i < 8; i++ )
|
||||
{
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
usbh_dpram->setup_packet[i] = setup_packet[i];
|
||||
}
|
||||
|
||||
// Configure EP0 struct with setup info for the trans complete
|
||||
struct hw_endpoint * ep = _hw_endpoint_allocate(0);
|
||||
struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL);
|
||||
TU_ASSERT(ep);
|
||||
|
||||
// EPX should be inactive
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoi
|
|||
*ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
|
||||
// 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control
|
||||
// Don't need delay in host mode as host is in charge
|
||||
if ( !is_host_mode()) {
|
||||
if (!is_host_mode()) {
|
||||
busy_wait_at_least_cycles(12);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
* F102, F103 512 byte buffer; no internal D+ pull-up (maybe many more changes?)
|
||||
* F302xB/C, F303xB/C, F373 512 byte buffer; no internal D+ pull-up
|
||||
* F302x6/8, F302xD/E2, F303xD/E 1024 byte buffer; no internal D+ pull-up
|
||||
* C0 2048 byte buffer; 32-bit bus; host mode
|
||||
* G0 2048 byte buffer; 32-bit bus; host mode
|
||||
* G4 1024 byte buffer
|
||||
* H5 2048 byte buffer; 32-bit bus; host mode
|
||||
|
|
|
|||
|
|
@ -104,6 +104,20 @@
|
|||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
|
||||
#include "stm32c0xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
#define USB USB_DRD_FS
|
||||
#define USB_EP_CTR_RX USB_CHEP_VTRX
|
||||
#define USB_EP_CTR_TX USB_CHEP_VTTX
|
||||
#define USB_EPREG_MASK USB_CHEP_REG_MASK
|
||||
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||
#define USB_CNTR_RESUME USB_CNTR_L2RES
|
||||
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
|
||||
#define USB_CNTR_FSUSP USB_CNTR_SUSPEN
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
|
||||
#include "stm32h5xx.h"
|
||||
#define FSDEV_PMA_SIZE (2048u)
|
||||
|
|
@ -260,6 +274,8 @@ static const IRQn_Type fsdev_irq[] = {
|
|||
#else
|
||||
USB_UCPD1_2_IRQn,
|
||||
#endif
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
|
||||
USB_DRD_FS_IRQn,
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32G4, OPT_MCU_STM32L1)
|
||||
USB_HP_IRQn,
|
||||
USB_LP_IRQn,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
311
src/portable/synopsys/dwc2/dwc2_common.c
Normal file
311
src/portable/synopsys/dwc2/dwc2_common.c
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#define DWC2_COMMON_DEBUG 2
|
||||
|
||||
#if defined(TUP_USBIP_DWC2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
#include "device/dcd.h"
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
#include "host/hcd.h"
|
||||
#endif
|
||||
|
||||
#include "dwc2_common.h"
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
static void reset_core(dwc2_regs_t* dwc2) {
|
||||
// reset core
|
||||
dwc2->grstctl |= GRSTCTL_CSRST;
|
||||
|
||||
if ((dwc2->gsnpsid & DWC2_CORE_REV_MASK) < (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
|
||||
// prior v42.0 CSRST is self-clearing
|
||||
while (dwc2->grstctl & GRSTCTL_CSRST) {}
|
||||
} else {
|
||||
// From v4.20a CSRST bit is write only, CSRT_DONE (w1c) is introduced for checking.
|
||||
// CSRST must also be explicitly cleared
|
||||
while (!(dwc2->grstctl & GRSTCTL_CSRST_DONE)) {}
|
||||
dwc2->grstctl = (dwc2->grstctl & ~GRSTCTL_CSRST) | GRSTCTL_CSRST_DONE;
|
||||
}
|
||||
|
||||
while (!(dwc2->grstctl & GRSTCTL_AHBIDL)) {} // wait for AHB master IDLE
|
||||
}
|
||||
|
||||
static void phy_fs_init(dwc2_regs_t* dwc2) {
|
||||
TU_LOG(DWC2_COMMON_DEBUG, "Fullspeed PHY init\r\n");
|
||||
|
||||
uint32_t gusbcfg = dwc2->gusbcfg;
|
||||
|
||||
// Select FS PHY
|
||||
gusbcfg |= GUSBCFG_PHYSEL;
|
||||
dwc2->gusbcfg = gusbcfg;
|
||||
|
||||
// MCU specific PHY init before reset
|
||||
dwc2_phy_init(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED);
|
||||
|
||||
// Reset core after selecting PHY
|
||||
reset_core(dwc2);
|
||||
|
||||
// USB turnaround time is critical for certification where long cables and 5-Hubs are used.
|
||||
// So if you need the AHB to run at less than 30 MHz, and if USB turnaround time is not critical,
|
||||
// these bits can be programmed to a larger value. Default is 5
|
||||
gusbcfg &= ~GUSBCFG_TRDT_Msk;
|
||||
gusbcfg |= 5u << GUSBCFG_TRDT_Pos;
|
||||
dwc2->gusbcfg = gusbcfg;
|
||||
|
||||
// MCU specific PHY update post reset
|
||||
dwc2_phy_update(dwc2, GHWCFG2_HSPHY_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static void phy_hs_init(dwc2_regs_t* dwc2) {
|
||||
uint32_t gusbcfg = dwc2->gusbcfg;
|
||||
|
||||
// De-select FS PHY
|
||||
gusbcfg &= ~GUSBCFG_PHYSEL;
|
||||
|
||||
if (dwc2->ghwcfg2_bm.hs_phy_type == GHWCFG2_HSPHY_ULPI) {
|
||||
TU_LOG(DWC2_COMMON_DEBUG, "Highspeed ULPI PHY init\r\n");
|
||||
|
||||
// Select ULPI PHY (external)
|
||||
gusbcfg |= GUSBCFG_ULPI_UTMI_SEL;
|
||||
|
||||
// ULPI is always 8-bit interface
|
||||
gusbcfg &= ~GUSBCFG_PHYIF16;
|
||||
|
||||
// ULPI select single data rate
|
||||
gusbcfg &= ~GUSBCFG_DDRSEL;
|
||||
|
||||
// default internal VBUS Indicator and Drive
|
||||
gusbcfg &= ~(GUSBCFG_ULPIEVBUSD | GUSBCFG_ULPIEVBUSI);
|
||||
|
||||
// Disable FS/LS ULPI
|
||||
gusbcfg &= ~(GUSBCFG_ULPIFSLS | GUSBCFG_ULPICSM);
|
||||
} else {
|
||||
TU_LOG(DWC2_COMMON_DEBUG, "Highspeed UTMI+ PHY init\r\n");
|
||||
|
||||
// Select UTMI+ PHY (internal)
|
||||
gusbcfg &= ~GUSBCFG_ULPI_UTMI_SEL;
|
||||
|
||||
// Set 16-bit interface if supported
|
||||
if (dwc2->ghwcfg4_bm.phy_data_width) {
|
||||
gusbcfg |= GUSBCFG_PHYIF16; // 16 bit
|
||||
} else {
|
||||
gusbcfg &= ~GUSBCFG_PHYIF16; // 8 bit
|
||||
}
|
||||
}
|
||||
|
||||
// Apply config
|
||||
dwc2->gusbcfg = gusbcfg;
|
||||
|
||||
// mcu specific phy init
|
||||
dwc2_phy_init(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
|
||||
|
||||
// Reset core after selecting PHY
|
||||
reset_core(dwc2);
|
||||
|
||||
// Set turn-around, must after core reset otherwise it will be clear
|
||||
// - 9 if using 8-bit PHY interface
|
||||
// - 5 if using 16-bit PHY interface
|
||||
gusbcfg &= ~GUSBCFG_TRDT_Msk;
|
||||
gusbcfg |= (dwc2->ghwcfg4_bm.phy_data_width ? 5u : 9u) << GUSBCFG_TRDT_Pos;
|
||||
dwc2->gusbcfg = gusbcfg;
|
||||
|
||||
// MCU specific PHY update post reset
|
||||
dwc2_phy_update(dwc2, dwc2->ghwcfg2_bm.hs_phy_type);
|
||||
}
|
||||
|
||||
static bool check_dwc2(dwc2_regs_t* dwc2) {
|
||||
#if CFG_TUSB_DEBUG >= DWC2_COMMON_DEBUG
|
||||
// print guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4
|
||||
// Run 'python dwc2_info.py' and check dwc2_info.md for bit-field value and comparison with other ports
|
||||
volatile uint32_t const* p = (volatile uint32_t const*) &dwc2->guid;
|
||||
TU_LOG1("guid, gsnpsid, ghwcfg1, ghwcfg2, ghwcfg3, ghwcfg4\r\n");
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
TU_LOG1("0x%08" PRIX32 ", ", p[i]);
|
||||
}
|
||||
TU_LOG1("0x%08" PRIX32 "\r\n", p[5]);
|
||||
#endif
|
||||
|
||||
// For some reason: GD32VF103 gsnpsid and all hwcfg register are always zero (skip it)
|
||||
(void)dwc2;
|
||||
#if !TU_CHECK_MCU(OPT_MCU_GD32VF103)
|
||||
enum { GSNPSID_ID_MASK = TU_GENMASK(31, 16) };
|
||||
const uint32_t gsnpsid = dwc2->gsnpsid & GSNPSID_ID_MASK;
|
||||
TU_ASSERT(gsnpsid == DWC2_OTG_ID || gsnpsid == DWC2_FS_IOT_ID || gsnpsid == DWC2_HS_IOT_ID);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role) {
|
||||
(void)dwc2;
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
if (role == TUSB_ROLE_DEVICE && !TUD_OPT_HIGH_SPEED) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUH_ENABLED
|
||||
if (role == TUSB_ROLE_HOST && !TUH_OPT_HIGH_SPEED) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return dwc2->ghwcfg2_bm.hs_phy_type != GHWCFG2_HSPHY_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
/* dwc2 has several PHYs option
|
||||
* - UTMI+ is internal highspeed PHY, clock can be 30 Mhz (8-bit) or 60 Mhz (16-bit)
|
||||
* - ULPI is external highspeed PHY, clock is 60Mhz with only 8-bit interface
|
||||
* - Dedicated FS PHY is internal with clock 48Mhz.
|
||||
*
|
||||
* In addition, UTMI+/ULPI can be shared to run at fullspeed mode with 48Mhz
|
||||
*
|
||||
*/
|
||||
bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) {
|
||||
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
|
||||
|
||||
// Check Synopsys ID register, failed if controller clock/power is not enabled
|
||||
TU_ASSERT(check_dwc2(dwc2));
|
||||
|
||||
// disable global interrupt
|
||||
dwc2->gahbcfg &= ~GAHBCFG_GINT;
|
||||
|
||||
if (is_highspeed) {
|
||||
phy_hs_init(dwc2);
|
||||
} else {
|
||||
phy_fs_init(dwc2);
|
||||
}
|
||||
|
||||
/* Set HS/FS Timeout Calibration to 7 (max available value).
|
||||
* The number of PHY clocks that the application programs in
|
||||
* this field is added to the high/full speed interpacket timeout
|
||||
* duration in the core to account for any additional delays
|
||||
* introduced by the PHY. This can be required, because the delay
|
||||
* introduced by the PHY in generating the linestate condition
|
||||
* can vary from one PHY to another. */
|
||||
dwc2->gusbcfg |= (7ul << GUSBCFG_TOCAL_Pos);
|
||||
|
||||
// Enable PHY clock TODO stop/gate clock when suspended mode
|
||||
dwc2->pcgcctl &= ~(PCGCCTL_STOPPCLK | PCGCCTL_GATEHCLK | PCGCCTL_PWRCLMP | PCGCCTL_RSTPDWNMODULE);
|
||||
|
||||
dfifo_flush_tx(dwc2, 0x10); // all tx fifo
|
||||
dfifo_flush_rx(dwc2);
|
||||
|
||||
// Clear pending and disable all interrupts
|
||||
dwc2->gintsts = 0xFFFFFFFFU;
|
||||
dwc2->gotgint = 0xFFFFFFFFU;
|
||||
dwc2->gintmsk = 0;
|
||||
|
||||
TU_LOG(DWC2_COMMON_DEBUG, "DMA = %u\r\n", is_dma);
|
||||
|
||||
if (is_dma) {
|
||||
// DMA seems to be only settable after a core reset, and not possible to switch on-the-fly
|
||||
dwc2->gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_HBSTLEN_2;
|
||||
} else {
|
||||
dwc2->gintmsk |= GINTSTS_RXFLVL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// void dwc2_core_handle_common_irq(uint8_t rhport, bool in_isr) {
|
||||
// (void) in_isr;
|
||||
// dwc2_regs_t * const dwc2 = DWC2_REG(rhport);
|
||||
// const uint32_t int_mask = dwc2->gintmsk;
|
||||
// const uint32_t int_status = dwc2->gintsts & int_mask;
|
||||
//
|
||||
// // Device disconnect
|
||||
// if (int_status & GINTSTS_DISCINT) {
|
||||
// dwc2->gintsts = GINTSTS_DISCINT;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// DFIFO
|
||||
//--------------------------------------------------------------------
|
||||
// Read a single data packet from receive DFIFO
|
||||
void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len) {
|
||||
const volatile uint32_t* rx_fifo = dwc2->fifo[0];
|
||||
|
||||
// Reading full available 32 bit words from fifo
|
||||
uint16_t word_count = len >> 2;
|
||||
while (word_count--) {
|
||||
tu_unaligned_write32(dst, *rx_fifo);
|
||||
dst += 4;
|
||||
}
|
||||
|
||||
// Read the remaining 1-3 bytes from fifo
|
||||
const uint8_t bytes_rem = len & 0x03;
|
||||
if (bytes_rem != 0) {
|
||||
const uint32_t tmp = *rx_fifo;
|
||||
dst[0] = tu_u32_byte0(tmp);
|
||||
if (bytes_rem > 1) {
|
||||
dst[1] = tu_u32_byte1(tmp);
|
||||
}
|
||||
if (bytes_rem > 2) {
|
||||
dst[2] = tu_u32_byte2(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write a single data packet to DFIFO
|
||||
void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, const uint8_t* src, uint16_t len) {
|
||||
volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
|
||||
|
||||
// Pushing full available 32 bit words to fifo
|
||||
uint16_t word_count = len >> 2;
|
||||
while (word_count--) {
|
||||
*tx_fifo = tu_unaligned_read32(src);
|
||||
src += 4;
|
||||
}
|
||||
|
||||
// Write the remaining 1-3 bytes into fifo
|
||||
const uint8_t bytes_rem = len & 0x03;
|
||||
if (bytes_rem) {
|
||||
uint32_t tmp_word = src[0];
|
||||
if (bytes_rem > 1) {
|
||||
tmp_word |= (src[1] << 8);
|
||||
}
|
||||
if (bytes_rem > 2) {
|
||||
tmp_word |= (src[2] << 16);
|
||||
}
|
||||
|
||||
*tx_fifo = tmp_word;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
101
src/portable/synopsys/dwc2/dwc2_common.h
Normal file
101
src/portable/synopsys/dwc2/dwc2_common.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef TUSB_DWC2_COMMON_H
|
||||
#define TUSB_DWC2_COMMON_H
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "dwc2_type.h"
|
||||
|
||||
// Following symbols must be defined by port header
|
||||
// - _dwc2_controller[]: array of controllers
|
||||
// - DWC2_EP_MAX: largest EP counts of all controllers
|
||||
// - dwc2_phy_init/dwc2_phy_update: phy init called before and after core reset
|
||||
// - dwc2_dcd_int_enable/dwc2_dcd_int_disable
|
||||
// - dwc2_remote_wakeup_delay
|
||||
|
||||
#if defined(TUP_USBIP_DWC2_STM32)
|
||||
#include "dwc2_stm32.h"
|
||||
#elif defined(TUP_USBIP_DWC2_ESP32)
|
||||
#include "dwc2_esp32.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_GD32VF103)
|
||||
#include "dwc2_gd32.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_BCM2711, OPT_MCU_BCM2835, OPT_MCU_BCM2837)
|
||||
#include "dwc2_bcm.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_EFM32GG)
|
||||
#include "dwc2_efm32.h"
|
||||
#elif TU_CHECK_MCU(OPT_MCU_XMC4000)
|
||||
#include "dwc2_xmc.h"
|
||||
#else
|
||||
#error "Unsupported MCUs"
|
||||
#endif
|
||||
|
||||
enum {
|
||||
DWC2_CONTROLLER_COUNT = TU_ARRAY_SIZE(_dwc2_controller)
|
||||
};
|
||||
|
||||
enum {
|
||||
OTG_INT_COMMON = 0 // GINTSTS_DISCINT | GINTSTS_CONIDSTSCHNG
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Core/Controller
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_ALWAYS_INLINE static inline dwc2_regs_t* DWC2_REG(uint8_t rhport) {
|
||||
if (rhport >= DWC2_CONTROLLER_COUNT) {
|
||||
// user mis-configured, ignore and use first controller
|
||||
rhport = 0;
|
||||
}
|
||||
return (dwc2_regs_t*)_dwc2_controller[rhport].reg_base;
|
||||
}
|
||||
|
||||
bool dwc2_core_is_highspeed(dwc2_regs_t* dwc2, tusb_role_t role);
|
||||
bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma);
|
||||
void dwc2_core_handle_common_irq(uint8_t rhport, bool in_isr);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DFIFO
|
||||
//--------------------------------------------------------------------+
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_tx(dwc2_regs_t* dwc2, uint8_t fnum) {
|
||||
// flush TX fifo and wait for it cleared
|
||||
dwc2->grstctl = GRSTCTL_TXFFLSH | (fnum << GRSTCTL_TXFNUM_Pos);
|
||||
while (dwc2->grstctl & GRSTCTL_TXFFLSH_Msk) {}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dfifo_flush_rx(dwc2_regs_t* dwc2) {
|
||||
// flush RX fifo and wait for it cleared
|
||||
dwc2->grstctl = GRSTCTL_RXFFLSH;
|
||||
while (dwc2->grstctl & GRSTCTL_RXFFLSH_Msk) {}
|
||||
}
|
||||
|
||||
void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len);
|
||||
void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, uint8_t const* src, uint16_t len);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// DMA
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#endif
|
||||
|
|
@ -25,13 +25,14 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef _DWC2_ESP32_H_
|
||||
#define _DWC2_ESP32_H_
|
||||
#ifndef TUSB_DWC2_ESP32_H_
|
||||
#define TUSB_DWC2_ESP32_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_intr_alloc.h"
|
||||
|
|
@ -59,21 +60,37 @@ static const dwc2_controller_t _dwc2_controller[] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
static intr_handle_t usb_ih[TU_ARRAY_SIZE(_dwc2_controller)];
|
||||
|
||||
static void dcd_int_handler_wrap(void* arg) {
|
||||
const uint8_t rhport = (uint8_t)(uintptr_t) arg;
|
||||
dcd_int_handler(rhport);
|
||||
static void dwc2_int_handler_wrap(void* arg) {
|
||||
const uint8_t rhport = tu_u16_low((uint16_t)(uintptr_t)arg);
|
||||
const tusb_role_t role = (tusb_role_t) tu_u16_high((uint16_t)(uintptr_t)arg);
|
||||
#if CFG_TUD_ENABLED
|
||||
if (role == TUSB_ROLE_DEVICE) {
|
||||
dcd_int_handler(rhport);
|
||||
}
|
||||
#endif
|
||||
#if CFG_TUH_ENABLED && !CFG_TUH_MAX3421
|
||||
if (role == TUSB_ROLE_HOST) {
|
||||
hcd_int_handler(rhport, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) {
|
||||
esp_intr_alloc(_dwc2_controller[rhport].irqnum, ESP_INTR_FLAG_LOWMED,
|
||||
dcd_int_handler_wrap, (void*)(uintptr_t) rhport, &usb_ih[rhport]);
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
|
||||
if (enabled) {
|
||||
esp_intr_alloc(_dwc2_controller[rhport].irqnum, ESP_INTR_FLAG_LOWMED,
|
||||
dwc2_int_handler_wrap, (void*)(uintptr_t)tu_u16(role, rhport), &usb_ih[rhport]);
|
||||
} else {
|
||||
esp_intr_free(usb_ih[rhport]);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) {
|
||||
esp_intr_free(usb_ih[rhport]);
|
||||
}
|
||||
#define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true)
|
||||
#define dwc2_dcd_int_disable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, false)
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
|
|
@ -83,16 +100,57 @@ TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
|
|||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
|
||||
(void)dwc2;
|
||||
(void)hs_phy_type;
|
||||
// nothing to do
|
||||
// maybe usb_utmi_hal_init()
|
||||
|
||||
}
|
||||
|
||||
// MCU specific PHY update, it is called AFTER init() and core reset
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
|
||||
(void)dwc2;
|
||||
(void)hs_phy_type;
|
||||
// nothing to do
|
||||
// maybe usb_utmi_hal_disable()
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Data Cache
|
||||
//--------------------------------------------------------------------+
|
||||
#if CFG_TUD_DWC2_DMA_ENABLE || CFG_TUH_DWC2_DMA_ENABLE
|
||||
#if defined(SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE) && SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#include "esp_cache.h"
|
||||
|
||||
#if CFG_TUD_MEM_DCACHE_LINE_SIZE != CONFIG_CACHE_L1_CACHE_LINE_SIZE || \
|
||||
CFG_TUH_MEM_DCACHE_LINE_SIZE != CONFIG_CACHE_L1_CACHE_LINE_SIZE
|
||||
#error "CFG_TUD/TUH_MEM_DCACHE_LINE_SIZE must match CONFIG_CACHE_L1_CACHE_LINE_SIZE"
|
||||
#endif
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline uint32_t round_up_to_cache_line_size(uint32_t size) {
|
||||
if (size & (CONFIG_CACHE_L1_CACHE_LINE_SIZE-1)) {
|
||||
size = (size & ~(CONFIG_CACHE_L1_CACHE_LINE_SIZE-1)) + CONFIG_CACHE_L1_CACHE_LINE_SIZE;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean(const void* addr, uint32_t data_size) {
|
||||
const int flag = ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_C2M;
|
||||
data_size = round_up_to_cache_line_size(data_size);
|
||||
return ESP_OK == esp_cache_msync((void*)addr, data_size, flag);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_invalidate(const void* addr, uint32_t data_size) {
|
||||
const int flag = ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_M2C;
|
||||
data_size = round_up_to_cache_line_size(data_size);
|
||||
return ESP_OK == esp_cache_msync((void*)addr, data_size, flag);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline bool dwc2_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
|
||||
const int flag = ESP_CACHE_MSYNC_FLAG_TYPE_DATA | ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_DIR_M2C;
|
||||
data_size = round_up_to_cache_line_size(data_size);
|
||||
return ESP_OK == esp_cache_msync((void*)addr, data_size, flag);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -69,6 +69,14 @@ extern "C" {
|
|||
#define OTG_FS_IRQn OTG_HS_IRQn
|
||||
#endif
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS
|
||||
#include "stm32h7rsxx.h"
|
||||
#define EP_MAX_FS 6
|
||||
#define EP_FIFO_SIZE_FS 1280
|
||||
|
||||
#define EP_MAX_HS 9
|
||||
#define EP_FIFO_SIZE_HS 4096
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
|
||||
#include "stm32f7xx.h"
|
||||
#define EP_MAX_FS 6
|
||||
|
|
@ -124,13 +132,19 @@ static const dwc2_controller_t _dwc2_controller[] = {
|
|||
// SystemCoreClock is already included by family header
|
||||
// extern uint32_t SystemCoreClock;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_enable(uint8_t rhport) {
|
||||
NVIC_EnableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum);
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
|
||||
(void) role;
|
||||
const IRQn_Type irqn = (IRQn_Type) _dwc2_controller[rhport].irqnum;
|
||||
if (enabled) {
|
||||
NVIC_EnableIRQ(irqn);
|
||||
} else {
|
||||
NVIC_DisableIRQ(irqn);
|
||||
}
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_dcd_int_disable(uint8_t rhport) {
|
||||
NVIC_DisableIRQ((IRQn_Type) _dwc2_controller[rhport].irqnum);
|
||||
}
|
||||
#define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true)
|
||||
#define dwc2_dcd_int_disable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, false)
|
||||
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
|
||||
// try to delay for 1 ms
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@
|
|||
* opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_DWC2_TYPES_H_
|
||||
#define _TUSB_DWC2_TYPES_H_
|
||||
#ifndef TUSB_DWC2_TYPES_H_
|
||||
#define TUSB_DWC2_TYPES_H_
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
|
|
@ -86,6 +86,11 @@ typedef struct
|
|||
} HS_PHYC_GlobalTypeDef;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
GOTGCTL_OTG_VERSION_1_3 = 0,
|
||||
GOTGCTL_OTG_VERSION_2_0 = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
GHWCFG2_OPMODE_HNP_SRP = 0,
|
||||
GHWCFG2_OPMODE_SRP = 1,
|
||||
|
|
@ -122,8 +127,62 @@ enum {
|
|||
GHWCFFG4_PHY_DATA_WIDTH_8_16 = 2, // software selectable
|
||||
};
|
||||
|
||||
enum {
|
||||
HPRT_SPEED_HIGH = 0,
|
||||
HPRT_SPEED_FULL = 1,
|
||||
HPRT_SPEED_LOW = 2
|
||||
};
|
||||
|
||||
enum {
|
||||
GINTSTS_CMODE_DEVICE = 0,
|
||||
GINTSTS_CMODE_HOST = 1,
|
||||
};
|
||||
|
||||
enum {
|
||||
HCTSIZ_PID_DATA0 = 0, // 00b
|
||||
HCTSIZ_PID_DATA2 = 1, // 01b
|
||||
HCTSIZ_PID_DATA1 = 2, // 10b
|
||||
HCTSIZ_PID_SETUP = 3, // 11b
|
||||
};
|
||||
enum {
|
||||
HCTSIZ_PID_MDATA = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
GRXSTS_PKTSTS_GLOBAL_OUT_NAK = 1,
|
||||
GRXSTS_PKTSTS_RX_DATA = 2,
|
||||
GRXSTS_PKTSTS_RX_COMPLETE = 3,
|
||||
GRXSTS_PKTSTS_SETUP_DONE = 4,
|
||||
GRXSTS_PKTSTS_HOST_DATATOGGLE_ERR = 5,
|
||||
GRXSTS_PKTSTS_SETUP_RX = 6,
|
||||
GRXSTS_PKTSTS_HOST_CHANNEL_HALTED = 7
|
||||
};
|
||||
|
||||
// Same as TUSB_XFER_*
|
||||
enum {
|
||||
HCCHAR_EPTYPE_CONTROL = 0,
|
||||
HCCHAR_EPTYPE_ISOCHRONOUS = 1,
|
||||
HCCHAR_EPTYPE_BULK = 2,
|
||||
HCCHAR_EPTYPE_INTERRUPT = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
DCFG_SPEED_HIGH = 0, // Highspeed with 30/60 Mhz
|
||||
DCFG_SPEED_FULL_30_60MHZ = 1, // Fullspeed with UTMI+/ULPI 30/60 Mhz
|
||||
DCFG_SPEED_LOW = 2, // Lowspeed with FS PHY at 6 Mhz
|
||||
DCFG_SPEED_FULL_48MHZ = 3, // Fullspeed with dedicated FS PHY at 48 Mhz
|
||||
};
|
||||
|
||||
// Same as TUSB_XFER_*
|
||||
enum {
|
||||
DEPCTL_EPTYPE_CONTROL = 0,
|
||||
DEPCTL_EPTYPE_ISOCHRONOUS = 1,
|
||||
DEPCTL_EPTYPE_BULK = 2,
|
||||
DEPCTL_EPTYPE_INTERRUPT = 3
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Register bitfield definitions
|
||||
// Common Register Bitfield
|
||||
//--------------------------------------------------------------------
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t ses_req_scs : 1; // 0 Session request success
|
||||
|
|
@ -146,7 +205,7 @@ typedef struct TU_ATTR_PACKED {
|
|||
uint32_t ases_valid : 1; // 18 A-session valid
|
||||
uint32_t bses_valid : 1; // 19 B-session valid
|
||||
uint32_t otg_ver : 1; // 20 OTG version 0: v1.3, 1: v2.0
|
||||
uint32_t current_mode : 1; // 21 Current mode of operation 0: device, 1: host
|
||||
uint32_t current_mode : 1; // 21 Current mode of operation. Only from v3.00a
|
||||
uint32_t mult_val_id_bc : 5; // 22..26 Multi-valued input pin ID battery charger
|
||||
uint32_t chirp_en : 1; // 27 Chirp detection enable
|
||||
uint32_t rsv28_30 : 3; // 28.30: Reserved
|
||||
|
|
@ -192,7 +251,7 @@ typedef struct TU_ATTR_PACKED {
|
|||
based on the speed of enumeration. The number of bit times added per PHY clock are as follows:
|
||||
- High-speed: PHY clock One 30-MHz = 16 bit times, One 60-MHz = 8 bit times
|
||||
- Full-speed: PHY clock One 30-MHz = 0.4 bit times, One 60-MHz = 0.2 bit times, One 48-MHz = 0.25 bit times */
|
||||
uint32_t phy_if : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
|
||||
uint32_t phy_if16 : 1; // 3 PHY interface. 0: 8 bits, 1: 16 bits
|
||||
uint32_t ulpi_utmi_sel : 1; // 4 ULPI/UTMI select. 0: UTMI+, 1: ULPI
|
||||
uint32_t fs_intf_sel : 1; // 5 Fullspeed serial interface select. 0: 6-pin, 1: 3-pin
|
||||
uint32_t phy_sel : 1; // 6 HS/FS PHY selection. 0: HS UTMI+ or ULPI, 1: FS serial transceiver
|
||||
|
|
@ -240,10 +299,21 @@ typedef struct TU_ATTR_PACKED {
|
|||
} dwc2_grstctl_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_grstctl_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t ep_ch_num : 4; // 0..3 Endpoint/Channel Number
|
||||
uint32_t byte_count :11; // 4..14 Byte Count
|
||||
uint32_t dpid : 2; // 15..16 Data PID
|
||||
uint32_t packet_status : 4; // 17..20 Packet Status
|
||||
uint32_t frame_number : 4; // 21..24 Frame Number
|
||||
uint32_t rsv25_31 : 7; // 25..31 Reserved
|
||||
} dwc2_grxstsp_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_grxstsp_t) == 4, "incorrect size");
|
||||
|
||||
// Hardware Configuration
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t op_mode : 3; // 0..2 HNP/SRP Host/Device/OTG mode
|
||||
uint32_t arch : 2; // 3..4 Slave/External/Internal DMA
|
||||
uint32_t point2point : 1; // 5 0: support hub and split | 1: no hub, no split
|
||||
uint32_t single_point : 1; // 5 0: support hub and split | 1: no hub, no split
|
||||
uint32_t hs_phy_type : 2; // 6..7 0: not supported | 1: UTMI+ | 2: ULPI | 3: UTMI+ and ULPI
|
||||
uint32_t fs_phy_type : 2; // 8..9 0: not supported | 1: dedicated | 2: UTMI+ | 3: ULPI
|
||||
uint32_t num_dev_ep : 4; // 10..13 Number of device endpoints (excluding EP0)
|
||||
|
|
@ -301,56 +371,256 @@ typedef struct TU_ATTR_PACKED {
|
|||
}dwc2_ghwcfg4_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_ghwcfg4_t) == 4, "incorrect size");
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Host Register Bitfield
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
|
||||
uint32_t req_queue_available : 8; // 16..23 Number of spaces available in the NPT transmit request queue for both IN and OU
|
||||
// 24..31 is top entry in the request queue that is currently being processed by the MAC
|
||||
uint32_t qtop_terminate : 1; // 24 Last entry for selected channel
|
||||
uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
|
||||
uint32_t qtop_ch_num : 4; // 27..30 Channel number
|
||||
} dwc2_hnptxsts_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_hnptxsts_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t fifo_available : 16; // 0..15 Number of words available in the Tx FIFO
|
||||
uint32_t req_queue_available : 7; // 16..22 Number of spaces available in the PTX transmit request queue
|
||||
uint32_t qtop_terminate : 1; // 23 Last entry for selected channel
|
||||
uint32_t qtop_last_period : 1; // 24 Last entry for selected channel is a periodic entry
|
||||
uint32_t qtop_type : 2; // 25..26 Token (0) In/Out (1) ZLP, (2) Ping/cspit, (3) Channel halt command
|
||||
uint32_t qtop_ch_num : 4; // 27..30 Channel number
|
||||
uint32_t qtop_odd_frame : 1; // 31 Send in odd frame
|
||||
} dwc2_hptxsts_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_hptxsts_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t conn_status : 1; // 0 Port connect status
|
||||
uint32_t conn_detected : 1; // 1 Port connect detected
|
||||
uint32_t enable : 1; // 2 Port enable status
|
||||
uint32_t enable_change : 1; // 3 Port enable change
|
||||
uint32_t over_current_active : 1; // 4 Port Over-current active
|
||||
uint32_t over_current_change : 1; // 5 Port Over-current change
|
||||
uint32_t resume : 1; // 6 Port resume
|
||||
uint32_t suspend : 1; // 7 Port suspend
|
||||
uint32_t reset : 1; // 8 Port reset
|
||||
uint32_t rsv9 : 1; // 9 Reserved
|
||||
uint32_t line_status : 2; // 10..11 Line status
|
||||
uint32_t power : 1; // 12 Port power
|
||||
uint32_t test_control : 4; // 13..16 Port Test control
|
||||
uint32_t speed : 2; // 17..18 Port speed
|
||||
uint32_t rsv19_31 :13; // 19..31 Reserved
|
||||
}dwc2_hprt_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_hprt_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t ep_size : 11; // 0..10 Maximum packet size
|
||||
uint32_t ep_num : 4; // 11..14 Endpoint number
|
||||
uint32_t ep_dir : 1; // 15 Endpoint direction
|
||||
uint32_t rsv16 : 1; // 16 Reserved
|
||||
uint32_t low_speed_dev : 1; // 17 Low-speed device
|
||||
uint32_t ep_type : 2; // 18..19 Endpoint type
|
||||
uint32_t err_multi_count : 2; // 20..21 Error (splitEn = 1) / Multi (SplitEn = 0) count
|
||||
uint32_t dev_addr : 7; // 22..28 Device address
|
||||
uint32_t odd_frame : 1; // 29 Odd frame
|
||||
uint32_t disable : 1; // 30 Channel disable
|
||||
uint32_t enable : 1; // 31 Channel enable
|
||||
} dwc2_channel_char_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_channel_char_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t hub_port : 7; // 0..6 Hub port number
|
||||
uint32_t hub_addr : 7; // 7..13 Hub address
|
||||
uint32_t xact_pos : 2; // 14..15 Transaction position
|
||||
uint32_t split_compl : 1; // 16 Split completion
|
||||
uint32_t rsv17_30 : 14; // 17..30 Reserved
|
||||
uint32_t split_en : 1; // 31 Split enable
|
||||
} dwc2_channel_split_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_channel_split_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
|
||||
uint32_t packet_count : 10; // 19..28 Number of packets
|
||||
uint32_t pid : 2; // 29..30 Packet ID
|
||||
uint32_t do_ping : 1; // 31 Do PING
|
||||
} dwc2_channel_tsize_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_channel_tsize_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t num : 16; // 0..15 Frame number
|
||||
uint32_t remainning : 16; // 16..31 Frame remaining
|
||||
} dwc2_hfnum_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_hfnum_t) == 4, "incorrect size");
|
||||
|
||||
// Host Channel
|
||||
typedef struct {
|
||||
volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics
|
||||
volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control
|
||||
volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt
|
||||
volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask
|
||||
volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size
|
||||
volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address
|
||||
uint32_t reserved518; // 518 + 20*ch
|
||||
volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address
|
||||
union {
|
||||
volatile uint32_t hcchar; // 500 + 20*ch Host Channel Characteristics
|
||||
volatile dwc2_channel_char_t hcchar_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t hcsplt; // 504 + 20*ch Host Channel Split Control
|
||||
volatile dwc2_channel_split_t hcsplt_bm;
|
||||
};
|
||||
volatile uint32_t hcint; // 508 + 20*ch Host Channel Interrupt
|
||||
volatile uint32_t hcintmsk; // 50C + 20*ch Host Channel Interrupt Mask
|
||||
union {
|
||||
volatile uint32_t hctsiz; // 510 + 20*ch Host Channel Transfer Size
|
||||
volatile dwc2_channel_tsize_t hctsiz_bm;
|
||||
};
|
||||
volatile uint32_t hcdma; // 514 + 20*ch Host Channel DMA Address
|
||||
uint32_t reserved518; // 518 + 20*ch
|
||||
volatile uint32_t hcdmab; // 51C + 20*ch Host Channel DMA Address
|
||||
} dwc2_channel_t;
|
||||
|
||||
// Endpoint IN
|
||||
typedef struct {
|
||||
volatile uint32_t diepctl; // 900 + 20*ep Device IN Endpoint Control
|
||||
uint32_t reserved04; // 904
|
||||
volatile uint32_t diepint; // 908 + 20*ep Device IN Endpoint Interrupt
|
||||
uint32_t reserved0c; // 90C
|
||||
volatile uint32_t dieptsiz; // 910 + 20*ep Device IN Endpoint Transfer Size
|
||||
volatile uint32_t diepdma; // 914 + 20*ep Device IN Endpoint DMA Address
|
||||
volatile uint32_t dtxfsts; // 918 + 20*ep Device IN Endpoint Tx FIFO Status
|
||||
uint32_t reserved1c; // 91C
|
||||
} dwc2_epin_t;
|
||||
//--------------------------------------------------------------------
|
||||
// Device Register Bitfield
|
||||
//--------------------------------------------------------------------
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t speed : 2; // 0..1 Speed
|
||||
uint32_t nzsts_out_handshake : 1; // 2 Non-zero-length status OUT handshake
|
||||
uint32_t en_32khz_suspsend : 1; // 3 Enable 32-kHz SUSPEND mode
|
||||
uint32_t address : 7; // 4..10 Device address
|
||||
uint32_t period_frame_interval : 2; // 11..12 Periodic frame interval
|
||||
uint32_t en_out_nak : 1; // 13 Enable Device OUT NAK
|
||||
uint32_t xcvr_delay : 1; // 14 Transceiver delay
|
||||
uint32_t erratic_int_mask : 1; // 15 Erratic interrupt mask
|
||||
uint32_t rsv16 : 1; // 16 Reserved
|
||||
uint32_t ipg_iso_support : 1; // 17 Interpacket gap ISO support
|
||||
uint32_t epin_mismatch_count : 5; // 18..22 EP IN mismatch count
|
||||
uint32_t dma_desc : 1; // 23 Enable scatter/gatter DMA descriptor
|
||||
uint32_t period_schedule_interval : 2; // 24..25 Periodic schedule interval for scatter/gatter DMA
|
||||
uint32_t resume_valid : 6; // 26..31 Resume valid period
|
||||
} dwc2_dcfg_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_dcfg_t) == 4, "incorrect size");
|
||||
|
||||
// Endpoint OUT
|
||||
typedef struct {
|
||||
volatile uint32_t doepctl; // B00 + 20*ep Device OUT Endpoint Control
|
||||
uint32_t reserved04; // B04
|
||||
volatile uint32_t doepint; // B08 + 20*ep Device OUT Endpoint Interrupt
|
||||
uint32_t reserved0c; // B0C
|
||||
volatile uint32_t doeptsiz; // B10 + 20*ep Device OUT Endpoint Transfer Size
|
||||
volatile uint32_t doepdma; // B14 + 20*ep Device OUT Endpoint DMA Address
|
||||
uint32_t reserved18[2]; // B18..B1C
|
||||
} dwc2_epout_t;
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t remote_wakeup_signal : 1; // 0 Remote wakeup signal
|
||||
uint32_t soft_disconnet : 1; // 1 Soft disconnect
|
||||
uint32_t gnp_in_nak_status : 1; // 2 Global non-periodic NAK IN status
|
||||
uint32_t gout_nak_status : 1; // 3 Global OUT NAK status
|
||||
uint32_t test_control : 3; // 4..6 Test control
|
||||
uint32_t set_gnp_in_nak : 1; // 7 Set global non-periodic IN NAK
|
||||
uint32_t clear_gnp_in_nak : 1; // 8 Clear global non-periodic IN NAK
|
||||
uint32_t set_gout_nak : 1; // 9 Set global OUT NAK
|
||||
uint32_t clear_gout_nak : 1; // 10 Clear global OUT NAK
|
||||
uint32_t poweron_prog_done : 1; // 11 Power-on programming done
|
||||
uint32_t rsv12 : 1; // 12 Reserved
|
||||
uint32_t global_multi_count : 2; // 13..14 Global multi-count
|
||||
uint32_t ignore_frame_number : 1; // 15 Ignore frame number
|
||||
uint32_t nak_on_babble : 1; // 16 NAK on babble
|
||||
uint32_t en_cont_on_bna : 1; // 17 Enable continue on BNA
|
||||
uint32_t deep_sleep_besl_reject : 1; // 18 Deep sleep BESL reject
|
||||
uint32_t service_interval : 1; // 19 Service interval for ISO IN endpoint
|
||||
uint32_t rsv20_31 :12; // 20..31 Reserved
|
||||
} dwc2_dctl_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_dctl_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t suspend_status : 1; // 0 Suspend status
|
||||
uint32_t enum_speed : 2; // 1..2 Enumerated speed
|
||||
uint32_t erratic_err : 1; // 3 Erratic error
|
||||
uint32_t rsv4_7 : 4; // 4..7 Reserved
|
||||
uint32_t frame_number : 14; // 8..21 Frame/MicroFrame number
|
||||
uint32_t line_status : 2; // 22..23 Line status
|
||||
uint32_t rsv24_31 : 8; // 24..31 Reserved
|
||||
} dwc2_dsts_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_dsts_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t xfer_complete : 1; // 0 Transfer complete
|
||||
uint32_t disabled : 1; // 1 Endpoint disabled
|
||||
uint32_t ahb_err : 1; // 2 AHB error
|
||||
uint32_t timeout : 1; // 3 Timeout
|
||||
uint32_t in_rx_txfe : 1; // 4 IN token received when TxFIFO is empty
|
||||
uint32_t in_rx_ep_mismatch : 1; // 5 IN token received with EP mismatch
|
||||
uint32_t in_ep_nak_effective : 1; // 6 IN endpoint NAK effective
|
||||
uint32_t txfifo_empty : 1; // 7 TX FIFO empty
|
||||
uint32_t txfifo_underrun : 1; // 8 Tx FIFO under run
|
||||
uint32_t bna : 1; // 9 Buffer not available
|
||||
uint32_t rsv10 : 1; // 10 Reserved
|
||||
uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
|
||||
uint32_t babble_err : 1; // 12 Babble error
|
||||
uint32_t nak : 1; // 13 NAK
|
||||
uint32_t nyet : 1; // 14 NYET
|
||||
uint32_t rsv14_31 :17; // 15..31 Reserved
|
||||
} dwc2_diepint_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_diepint_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t mps : 11; // 0..10 Maximum packet size, EP0 only use 2 bit
|
||||
uint32_t next_ep : 4; // 11..14 Next endpoint number
|
||||
uint32_t active : 1; // 15 Active
|
||||
const uint32_t dpid_iso_odd : 1; // 16 DATA0/DATA1 for bulk/interrupt, odd frame for isochronous
|
||||
const uint32_t nak_status : 1; // 17 NAK status
|
||||
uint32_t type : 2; // 18..19 Endpoint type
|
||||
uint32_t rsv20 : 1; // 20 Reserved
|
||||
uint32_t stall : 1; // 21 Stall
|
||||
uint32_t tx_fifo_num : 4; // 22..25 Tx FIFO number (IN)
|
||||
uint32_t clear_nak : 1; // 26 Clear NAK
|
||||
uint32_t set_nak : 1; // 27 Set NAK
|
||||
uint32_t set_data0_iso_even : 1; // 28 Set DATA0 if bulk/interrupt, even frame for isochronous
|
||||
uint32_t set_data1_iso_odd : 1; // 29 Set DATA1 if bulk/interrupt, odd frame for isochronous
|
||||
uint32_t disable : 1; // 30 Disable
|
||||
uint32_t enable : 1; // 31 Enable
|
||||
} dwc2_depctl_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_depctl_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t xfer_complete : 1; // 0 Transfer complete
|
||||
uint32_t disabled : 1; // 1 Endpoint disabled
|
||||
uint32_t ahb_err : 1; // 2 AHB error
|
||||
uint32_t setup_phase_done : 1; // 3 Setup phase done
|
||||
uint32_t out_rx_ep_disabled : 1; // 4 OUT token received when endpoint disabled
|
||||
uint32_t status_phase_rx : 1; // 5 Status phase received
|
||||
uint32_t setup_b2b : 1; // 6 Setup packet back-to-back
|
||||
uint32_t rsv7 : 1; // 7 Reserved
|
||||
uint32_t out_packet_err : 1; // 8 OUT packet error
|
||||
uint32_t bna : 1; // 9 Buffer not available
|
||||
uint32_t rsv10 : 1; // 10 Reserved
|
||||
uint32_t iso_packet_drop : 1; // 11 Isochronous OUT packet drop status
|
||||
uint32_t babble_err : 1; // 12 Babble error
|
||||
uint32_t nak : 1; // 13 NAK
|
||||
uint32_t nyet : 1; // 14 NYET
|
||||
uint32_t setup_packet_rx : 1; // 15 Setup packet received (Buffer DMA Mode only)
|
||||
uint32_t rsv16_31 :16; // 16..31 Reserved
|
||||
} dwc2_doepint_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_doepint_t) == 4, "incorrect size");
|
||||
|
||||
typedef struct TU_ATTR_PACKED {
|
||||
uint32_t xfer_size : 19; // 0..18 Transfer size in bytes
|
||||
uint32_t packet_count : 10; // 19..28 Number of packets
|
||||
uint32_t mc_pid : 2; // 29..30 IN: Multi Count, OUT: PID
|
||||
} dwc2_ep_tsize_t;
|
||||
TU_VERIFY_STATIC(sizeof(dwc2_ep_tsize_t) == 4, "incorrect size");
|
||||
|
||||
// Device IN/OUT Endpoint
|
||||
typedef struct {
|
||||
union {
|
||||
volatile uint32_t diepctl;
|
||||
volatile uint32_t doepctl;
|
||||
|
||||
volatile uint32_t ctl;
|
||||
volatile dwc2_depctl_t ctl_bm;
|
||||
};
|
||||
uint32_t rsv04;
|
||||
union {
|
||||
volatile uint32_t intr;
|
||||
|
||||
volatile uint32_t diepint;
|
||||
volatile dwc2_diepint_t diepint_bm;
|
||||
|
||||
volatile uint32_t doepint;
|
||||
volatile dwc2_doepint_t doepint_bm;
|
||||
};
|
||||
uint32_t rsv0c;
|
||||
union {
|
||||
volatile uint32_t dieptsiz;
|
||||
volatile uint32_t doeptsiz;
|
||||
volatile uint32_t tsiz;
|
||||
volatile dwc2_ep_tsize_t tsiz_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t diepdma;
|
||||
|
|
@ -367,21 +637,43 @@ TU_VERIFY_STATIC(sizeof(dwc2_dep_t) == 0x20, "incorrect size");
|
|||
//--------------------------------------------------------------------
|
||||
typedef struct {
|
||||
//------------- Core Global -------------//
|
||||
union {
|
||||
volatile uint32_t gotgctl; // 000 OTG Control and Status
|
||||
volatile dwc2_gotgctl_t gotgctl_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t gotgint; // 004 OTG Interrupt
|
||||
volatile dwc2_gotgint_t gotgint_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t gahbcfg; // 008 AHB Configuration
|
||||
volatile dwc2_gahbcfg_t gahbcfg_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t gusbcfg; // 00c USB Configuration
|
||||
volatile dwc2_gusbcfg_t gusbcfg_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t grstctl; // 010 Reset
|
||||
volatile dwc2_grstctl_t grstctl_bm;
|
||||
};
|
||||
volatile uint32_t gintsts; // 014 Interrupt
|
||||
volatile uint32_t gintmsk; // 018 Interrupt Mask
|
||||
volatile uint32_t grxstsr; // 01c Receive Status Debug Read
|
||||
union {
|
||||
volatile uint32_t grxstsp; // 020 Receive Status Read/Pop
|
||||
volatile dwc2_grxstsp_t grxstsp_bm;
|
||||
};
|
||||
volatile uint32_t grxfsiz; // 024 Receive FIFO Size
|
||||
union {
|
||||
volatile uint32_t dieptxf0; // 028 EP0 Tx FIFO Size
|
||||
volatile uint32_t gnptxfsiz; // 028 Non-periodic Transmit FIFO Size
|
||||
};
|
||||
volatile uint32_t gnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status
|
||||
union {
|
||||
volatile uint32_t hnptxsts; // 02c Non-periodic Transmit FIFO/Queue Status
|
||||
volatile dwc2_hnptxsts_t hnptxsts_bm;
|
||||
volatile uint32_t gnptxsts;
|
||||
};
|
||||
volatile uint32_t gi2cctl; // 030 I2C Address
|
||||
volatile uint32_t gpvndctl; // 034 PHY Vendor Control
|
||||
union {
|
||||
|
|
@ -415,14 +707,23 @@ typedef struct {
|
|||
//------------ Host -------------//
|
||||
volatile uint32_t hcfg; // 400 Host Configuration
|
||||
volatile uint32_t hfir; // 404 Host Frame Interval
|
||||
union {
|
||||
volatile uint32_t hfnum; // 408 Host Frame Number / Frame Remaining
|
||||
volatile dwc2_hfnum_t hfnum_bm;
|
||||
};
|
||||
uint32_t reserved40c; // 40C
|
||||
union {
|
||||
volatile uint32_t hptxsts; // 410 Host Periodic TX FIFO / Queue Status
|
||||
volatile dwc2_hptxsts_t hptxsts_bm;
|
||||
};
|
||||
volatile uint32_t haint; // 414 Host All Channels Interrupt
|
||||
volatile uint32_t haintmsk; // 418 Host All Channels Interrupt Mask
|
||||
volatile uint32_t hflbaddr; // 41C Host Frame List Base Address
|
||||
uint32_t reserved420[8]; // 420..43F
|
||||
union {
|
||||
volatile uint32_t hprt; // 440 Host Port Control and Status
|
||||
volatile dwc2_hprt_t hprt_bm;
|
||||
};
|
||||
uint32_t reserved444[47]; // 444..4FF
|
||||
|
||||
//------------- Host Channel -------------//
|
||||
|
|
@ -430,12 +731,27 @@ typedef struct {
|
|||
uint32_t reserved700[64]; // 700..7FF
|
||||
|
||||
//------------- Device -----------//
|
||||
union {
|
||||
volatile uint32_t dcfg; // 800 Device Configuration
|
||||
volatile dwc2_dcfg_t dcfg_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t dctl; // 804 Device Control
|
||||
volatile dwc2_dctl_t dctl_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t dsts; // 808 Device Status (RO)
|
||||
volatile dwc2_dsts_t dsts_bm;
|
||||
};
|
||||
uint32_t reserved80c; // 80C
|
||||
union {
|
||||
volatile uint32_t diepmsk; // 810 Device IN Endpoint Interrupt Mask
|
||||
volatile dwc2_diepint_t diepmsk_bm;
|
||||
};
|
||||
union {
|
||||
volatile uint32_t doepmsk; // 814 Device OUT Endpoint Interrupt Mask
|
||||
volatile dwc2_doepint_t doepmsk_bm;
|
||||
};
|
||||
volatile uint32_t daint; // 818 Device All Endpoints Interrupt
|
||||
volatile uint32_t daintmsk; // 81C Device All Endpoints Interrupt Mask
|
||||
volatile uint32_t dtknqr1; // 820 Device IN token sequence learning queue read1
|
||||
|
|
@ -457,15 +773,15 @@ typedef struct {
|
|||
union {
|
||||
dwc2_dep_t ep[2][16]; // 0: IN, 1 OUT
|
||||
struct {
|
||||
dwc2_epin_t epin[16]; // 900..AFF IN Endpoints
|
||||
dwc2_epout_t epout[16]; // B00..CFF OUT Endpoints
|
||||
dwc2_dep_t epin[16]; // 900..AFF IN Endpoints
|
||||
dwc2_dep_t epout[16]; // B00..CFF OUT Endpoints
|
||||
};
|
||||
};
|
||||
uint32_t reservedd00[64]; // D00..DFF
|
||||
|
||||
//------------- Power Clock -------------//
|
||||
volatile uint32_t pcgctl; // E00 Power and Clock Gating Control
|
||||
volatile uint32_t pcgctl1; // E04
|
||||
volatile uint32_t pcgcctl; // E00 Power and Clock Gating Characteristic Control
|
||||
volatile uint32_t pcgcctl1; // E04 Power and Clock Gating Characteristic Control 1
|
||||
uint32_t reservede08[126]; // E08..FFF
|
||||
|
||||
//------------- FIFOs -------------//
|
||||
|
|
@ -478,7 +794,7 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, channel) == 0x0500, "incorrect size");
|
|||
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, dcfg ) == 0x0800, "incorrect size");
|
||||
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epin ) == 0x0900, "incorrect size");
|
||||
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, epout ) == 0x0B00, "incorrect size");
|
||||
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, pcgctl ) == 0x0E00, "incorrect size");
|
||||
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, pcgcctl) == 0x0E00, "incorrect size");
|
||||
TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
|
@ -542,14 +858,16 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GOTGCTL_OTGVER GOTGCTL_OTGVER_Msk // OTG version
|
||||
|
||||
/******************** Bit definition for HCFG register ********************/
|
||||
#define HCFG_FSLSPCS_Pos (0U)
|
||||
#define HCFG_FSLSPCS_Msk (0x3UL << HCFG_FSLSPCS_Pos) // 0x00000003
|
||||
#define HCFG_FSLSPCS HCFG_FSLSPCS_Msk // FS/LS PHY clock select
|
||||
#define HCFG_FSLSPCS_0 (0x1UL << HCFG_FSLSPCS_Pos) // 0x00000001
|
||||
#define HCFG_FSLSPCS_1 (0x2UL << HCFG_FSLSPCS_Pos) // 0x00000002
|
||||
#define HCFG_FSLSS_Pos (2U)
|
||||
#define HCFG_FSLSS_Msk (0x1UL << HCFG_FSLSS_Pos) // 0x00000004
|
||||
#define HCFG_FSLSS HCFG_FSLSS_Msk // FS- and LS-only support
|
||||
#define HCFG_FSLS_PHYCLK_SEL_Pos (0U)
|
||||
#define HCFG_FSLS_PHYCLK_SEL_Msk (0x3UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000003
|
||||
#define HCFG_FSLS_PHYCLK_SEL HCFG_FSLS_PHYCLK_SEL_Msk // FS/LS PHY clock select
|
||||
#define HCFG_FSLS_PHYCLK_SEL_30_60MHZ (0x0UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000000
|
||||
#define HCFG_FSLS_PHYCLK_SEL_48MHZ (0x1UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000001
|
||||
#define HCFG_FSLS_PHYCLK_SEL_6MHZ (0x2UL << HCFG_FSLS_PHYCLK_SEL_Pos) // 0x00000002
|
||||
|
||||
#define HCFG_FSLS_ONLY_Pos (2U)
|
||||
#define HCFG_FSLS_ONLY_Msk (0x1UL << HCFG_FSLS_ONLY_Pos) // 0x00000004
|
||||
#define HCFG_FSLS_ONLY HCFG_FSLS_ONLY_Msk // FS- and LS-only support
|
||||
|
||||
/******************** Bit definition for PCGCR register ********************/
|
||||
#define PCGCR_STPPCLK_Pos (0U)
|
||||
|
|
@ -664,6 +982,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define HFIR_FRIVL_Pos (0U)
|
||||
#define HFIR_FRIVL_Msk (0xFFFFUL << HFIR_FRIVL_Pos) // 0x0000FFFF
|
||||
#define HFIR_FRIVL HFIR_FRIVL_Msk // Frame interval
|
||||
#define HFIR_RELOAD_CTRL_Pos (16U) // available since v2.92a
|
||||
#define HFIR_RELOAD_CTRL_Msk (0x1UL << HFIR_RELOAD_CTRL_Pos)
|
||||
#define HFIR_RELOAD_CTRL HFIR_RELOAD_CTRL_Msk
|
||||
|
||||
/******************** Bit definition for HFNUM register ********************/
|
||||
#define HFNUM_FRNUM_Pos (0U)
|
||||
|
|
@ -708,19 +1029,17 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GAHBCFG_DMAEN_Pos (5U)
|
||||
#define GAHBCFG_DMAEN_Msk (0x1UL << GAHBCFG_DMAEN_Pos) // 0x00000020
|
||||
#define GAHBCFG_DMAEN GAHBCFG_DMAEN_Msk // DMA enable
|
||||
#define GAHBCFG_TXFELVL_Pos (7U)
|
||||
#define GAHBCFG_TXFELVL_Msk (0x1UL << GAHBCFG_TXFELVL_Pos) // 0x00000080
|
||||
#define GAHBCFG_TXFELVL GAHBCFG_TXFELVL_Msk // TxFIFO empty level
|
||||
#define GAHBCFG_PTXFELVL_Pos (8U)
|
||||
#define GAHBCFG_PTXFELVL_Msk (0x1UL << GAHBCFG_PTXFELVL_Pos) // 0x00000100
|
||||
#define GAHBCFG_PTXFELVL GAHBCFG_PTXFELVL_Msk // Periodic TxFIFO empty level
|
||||
|
||||
#define GSNPSID_ID_MASK TU_GENMASK(31, 16)
|
||||
#define GAHBCFG_TX_FIFO_EPMTY_LVL_Pos (7U)
|
||||
#define GAHBCFG_TX_FIFO_EPMTY_LVL_Msk (0x1UL << GAHBCFG_TX_FIFO_EPMTY_LVL_Pos) // 0x00000080
|
||||
#define GAHBCFG_TX_FIFO_EPMTY_LVL GAHBCFG_TX_FIFO_EPMTY_LVL_Msk // TxFIFO empty level
|
||||
#define GAHBCFG_PTX_FIFO_EPMTY_LVL_Pos (8U)
|
||||
#define GAHBCFG_PTX_FIFO_EPMTY_LVL_Msk (0x1UL << GAHBCFG_PTX_FIFO_EPMTY_LVL_Pos) // 0x00000100
|
||||
#define GAHBCFG_PTX_FIFO_EPMTY_LVL GAHBCFG_PTX_FIFO_EPMTY_LVL_Msk // Periodic TxFIFO empty level
|
||||
|
||||
/******************** Bit definition for GUSBCFG register ********************/
|
||||
#define GUSBCFG_TOCAL_Pos (0U)
|
||||
#define GUSBCFG_TOCAL_Msk (0x7UL << GUSBCFG_TOCAL_Pos) // 0x00000007
|
||||
#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // FS timeout calibration
|
||||
#define GUSBCFG_TOCAL GUSBCFG_TOCAL_Msk // HS/FS timeout calibration
|
||||
#define GUSBCFG_PHYIF16_Pos (3U)
|
||||
#define GUSBCFG_PHYIF16_Msk (0x1UL << GUSBCFG_PHYIF16_Pos) // 0x00000008
|
||||
#define GUSBCFG_PHYIF16 GUSBCFG_PHYIF16_Msk // PHY Interface (PHYIf)
|
||||
|
|
@ -804,8 +1123,8 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GRSTCTL_TXFNUM_2 (0x04UL << GRSTCTL_TXFNUM_Pos) // 0x00000100
|
||||
#define GRSTCTL_TXFNUM_3 (0x08UL << GRSTCTL_TXFNUM_Pos) // 0x00000200
|
||||
#define GRSTCTL_TXFNUM_4 (0x10UL << GRSTCTL_TXFNUM_Pos) // 0x00000400
|
||||
#define GRSTCTL_CSFTRST_DONE_Pos (29)
|
||||
#define GRSTCTL_CSFTRST_DONE (1u << GRSTCTL_CSFTRST_DONE_Pos) // Reset Done, only available from v4.20a
|
||||
#define GRSTCTL_CSRST_DONE_Pos (29)
|
||||
#define GRSTCTL_CSRST_DONE (1u << GRSTCTL_CSRST_DONE_Pos) // Reset Done, only available from v4.20a
|
||||
#define GRSTCTL_DMAREQ_Pos (30U)
|
||||
#define GRSTCTL_DMAREQ_Msk (0x1UL << GRSTCTL_DMAREQ_Pos) // 0x40000000
|
||||
#define GRSTCTL_DMAREQ GRSTCTL_DMAREQ_Msk // DMA request signal
|
||||
|
|
@ -926,9 +1245,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GINTSTS_RXFLVL_Pos (4U)
|
||||
#define GINTSTS_RXFLVL_Msk (0x1UL << GINTSTS_RXFLVL_Pos) // 0x00000010
|
||||
#define GINTSTS_RXFLVL GINTSTS_RXFLVL_Msk // RxFIFO nonempty
|
||||
#define GINTSTS_NPTXFE_Pos (5U)
|
||||
#define GINTSTS_NPTXFE_Msk (0x1UL << GINTSTS_NPTXFE_Pos) // 0x00000020
|
||||
#define GINTSTS_NPTXFE GINTSTS_NPTXFE_Msk // Nonperiodic TxFIFO empty
|
||||
#define GINTSTS_NPTX_FIFO_EMPTY_Pos (5U)
|
||||
#define GINTSTS_NPTX_FIFO_EMPTY_Msk (0x1UL << GINTSTS_NPTX_FIFO_EMPTY_Pos) // 0x00000020
|
||||
#define GINTSTS_NPTX_FIFO_EMPTY GINTSTS_NPTX_FIFO_EMPTY_Msk // Nonperiodic TxFIFO empty
|
||||
#define GINTSTS_GINAKEFF_Pos (6U)
|
||||
#define GINTSTS_GINAKEFF_Msk (0x1UL << GINTSTS_GINAKEFF_Pos) // 0x00000040
|
||||
#define GINTSTS_GINAKEFF GINTSTS_GINAKEFF_Msk // Global IN nonperiodic NAK effective
|
||||
|
|
@ -977,15 +1296,15 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GINTSTS_HCINT_Pos (25U)
|
||||
#define GINTSTS_HCINT_Msk (0x1UL << GINTSTS_HCINT_Pos) // 0x02000000
|
||||
#define GINTSTS_HCINT GINTSTS_HCINT_Msk // Host channels interrupt
|
||||
#define GINTSTS_PTXFE_Pos (26U)
|
||||
#define GINTSTS_PTXFE_Msk (0x1UL << GINTSTS_PTXFE_Pos) // 0x04000000
|
||||
#define GINTSTS_PTXFE GINTSTS_PTXFE_Msk // Periodic TxFIFO empty
|
||||
#define GINTSTS_PTX_FIFO_EMPTY_Pos (26U)
|
||||
#define GINTSTS_PTX_FIFO_EMPTY_Msk (0x1UL << GINTSTS_PTX_FIFO_EMPTY_Pos) // 0x04000000
|
||||
#define GINTSTS_PTX_FIFO_EMPTY GINTSTS_PTX_FIFO_EMPTY_Msk // Periodic TxFIFO empty
|
||||
#define GINTSTS_LPMINT_Pos (27U)
|
||||
#define GINTSTS_LPMINT_Msk (0x1UL << GINTSTS_LPMINT_Pos) // 0x08000000
|
||||
#define GINTSTS_LPMINT GINTSTS_LPMINT_Msk // LPM interrupt
|
||||
#define GINTSTS_CIDSCHG_Pos (28U)
|
||||
#define GINTSTS_CIDSCHG_Msk (0x1UL << GINTSTS_CIDSCHG_Pos) // 0x10000000
|
||||
#define GINTSTS_CIDSCHG GINTSTS_CIDSCHG_Msk // Connector ID status change
|
||||
#define GINTSTS_CONIDSTSCHNG_Pos (28U)
|
||||
#define GINTSTS_CONIDSTSCHNG_Msk (0x1UL << GINTSTS_CONIDSTSCHNG_Pos) // 0x10000000
|
||||
#define GINTSTS_CONIDSTSCHNG GINTSTS_CONIDSTSCHNG_Msk // Connector ID status change
|
||||
#define GINTSTS_DISCINT_Pos (29U)
|
||||
#define GINTSTS_DISCINT_Msk (0x1UL << GINTSTS_DISCINT_Pos) // 0x20000000
|
||||
#define GINTSTS_DISCINT GINTSTS_DISCINT_Msk // Disconnect detected interrupt
|
||||
|
|
@ -1069,9 +1388,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GINTMSK_LPMINTM_Pos (27U)
|
||||
#define GINTMSK_LPMINTM_Msk (0x1UL << GINTMSK_LPMINTM_Pos) // 0x08000000
|
||||
#define GINTMSK_LPMINTM GINTMSK_LPMINTM_Msk // LPM interrupt Mask
|
||||
#define GINTMSK_CIDSCHGM_Pos (28U)
|
||||
#define GINTMSK_CIDSCHGM_Msk (0x1UL << GINTMSK_CIDSCHGM_Pos) // 0x10000000
|
||||
#define GINTMSK_CIDSCHGM GINTMSK_CIDSCHGM_Msk // Connector ID status change mask
|
||||
#define GINTMSK_CONIDSTSCHNGM_Pos (28U)
|
||||
#define GINTMSK_CONIDSTSCHNGM_Msk (0x1UL << GINTMSK_CONIDSTSCHNGM_Pos) // 0x10000000
|
||||
#define GINTMSK_CONIDSTSCHNGM GINTMSK_CONIDSTSCHNGM_Msk // Connector ID status change mask
|
||||
#define GINTMSK_DISCINT_Pos (29U)
|
||||
#define GINTMSK_DISCINT_Msk (0x1UL << GINTMSK_DISCINT_Pos) // 0x20000000
|
||||
#define GINTMSK_DISCINT GINTMSK_DISCINT_Msk // Disconnect detected interrupt mask
|
||||
|
|
@ -1109,17 +1428,6 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define GRXSTSP_PKTSTS_Msk (0xFUL << GRXSTSP_PKTSTS_Pos) // 0x001E0000
|
||||
#define GRXSTSP_PKTSTS GRXSTSP_PKTSTS_Msk // OUT EP interrupt mask bits
|
||||
|
||||
#define GRXSTS_PKTSTS_GLOBALOUTNAK 1
|
||||
#define GRXSTS_PKTSTS_OUTRX 2
|
||||
#define GRXSTS_PKTSTS_HCHIN 2
|
||||
#define GRXSTS_PKTSTS_OUTDONE 3
|
||||
#define GRXSTS_PKTSTS_HCHIN_XFER_COMP 3
|
||||
#define GRXSTS_PKTSTS_SETUPDONE 4
|
||||
#define GRXSTS_PKTSTS_DATATOGGLEERR 5
|
||||
#define GRXSTS_PKTSTS_SETUPRX 6
|
||||
#define GRXSTS_PKTSTS_HCHHALTED 7
|
||||
|
||||
|
||||
/******************** Bit definition for DAINTMSK register ********************/
|
||||
#define DAINTMSK_IEPM_Pos (0U)
|
||||
#define DAINTMSK_IEPM_Msk (0xFFFFUL << DAINTMSK_IEPM_Pos) // 0x0000FFFF
|
||||
|
|
@ -1448,56 +1756,53 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define DIEPEACHMSK1_NAKM DIEPEACHMSK1_NAKM_Msk // NAK interrupt mask
|
||||
|
||||
/******************** Bit definition for HPRT register ********************/
|
||||
#define HPRT_PCSTS_Pos (0U)
|
||||
#define HPRT_PCSTS_Msk (0x1UL << HPRT_PCSTS_Pos) // 0x00000001
|
||||
#define HPRT_PCSTS HPRT_PCSTS_Msk // Port connect status
|
||||
#define HPRT_PCDET_Pos (1U)
|
||||
#define HPRT_PCDET_Msk (0x1UL << HPRT_PCDET_Pos) // 0x00000002
|
||||
#define HPRT_PCDET HPRT_PCDET_Msk // Port connect detected
|
||||
#define HPRT_PENA_Pos (2U)
|
||||
#define HPRT_PENA_Msk (0x1UL << HPRT_PENA_Pos) // 0x00000004
|
||||
#define HPRT_PENA HPRT_PENA_Msk // Port enable
|
||||
#define HPRT_PENCHNG_Pos (3U)
|
||||
#define HPRT_PENCHNG_Msk (0x1UL << HPRT_PENCHNG_Pos) // 0x00000008
|
||||
#define HPRT_PENCHNG HPRT_PENCHNG_Msk // Port enable/disable change
|
||||
#define HPRT_POCA_Pos (4U)
|
||||
#define HPRT_POCA_Msk (0x1UL << HPRT_POCA_Pos) // 0x00000010
|
||||
#define HPRT_POCA HPRT_POCA_Msk // Port overcurrent active
|
||||
#define HPRT_POCCHNG_Pos (5U)
|
||||
#define HPRT_POCCHNG_Msk (0x1UL << HPRT_POCCHNG_Pos) // 0x00000020
|
||||
#define HPRT_POCCHNG HPRT_POCCHNG_Msk // Port overcurrent change
|
||||
#define HPRT_PRES_Pos (6U)
|
||||
#define HPRT_PRES_Msk (0x1UL << HPRT_PRES_Pos) // 0x00000040
|
||||
#define HPRT_PRES HPRT_PRES_Msk // Port resume
|
||||
#define HPRT_PSUSP_Pos (7U)
|
||||
#define HPRT_PSUSP_Msk (0x1UL << HPRT_PSUSP_Pos) // 0x00000080
|
||||
#define HPRT_PSUSP HPRT_PSUSP_Msk // Port suspend
|
||||
#define HPRT_PRST_Pos (8U)
|
||||
#define HPRT_PRST_Msk (0x1UL << HPRT_PRST_Pos) // 0x00000100
|
||||
#define HPRT_PRST HPRT_PRST_Msk // Port reset
|
||||
|
||||
#define HPRT_PLSTS_Pos (10U)
|
||||
#define HPRT_PLSTS_Msk (0x3UL << HPRT_PLSTS_Pos) // 0x00000C00
|
||||
#define HPRT_PLSTS HPRT_PLSTS_Msk // Port line status
|
||||
#define HPRT_PLSTS_0 (0x1UL << HPRT_PLSTS_Pos) // 0x00000400
|
||||
#define HPRT_PLSTS_1 (0x2UL << HPRT_PLSTS_Pos) // 0x00000800
|
||||
#define HPRT_PPWR_Pos (12U)
|
||||
#define HPRT_PPWR_Msk (0x1UL << HPRT_PPWR_Pos) // 0x00001000
|
||||
#define HPRT_PPWR HPRT_PPWR_Msk // Port power
|
||||
|
||||
#define HPRT_PTCTL_Pos (13U)
|
||||
#define HPRT_PTCTL_Msk (0xFUL << HPRT_PTCTL_Pos) // 0x0001E000
|
||||
#define HPRT_PTCTL HPRT_PTCTL_Msk // Port test control
|
||||
#define HPRT_PTCTL_0 (0x1UL << HPRT_PTCTL_Pos) // 0x00002000
|
||||
#define HPRT_PTCTL_1 (0x2UL << HPRT_PTCTL_Pos) // 0x00004000
|
||||
#define HPRT_PTCTL_2 (0x4UL << HPRT_PTCTL_Pos) // 0x00008000
|
||||
#define HPRT_PTCTL_3 (0x8UL << HPRT_PTCTL_Pos) // 0x00010000
|
||||
|
||||
#define HPRT_PSPD_Pos (17U)
|
||||
#define HPRT_PSPD_Msk (0x3UL << HPRT_PSPD_Pos) // 0x00060000
|
||||
#define HPRT_PSPD HPRT_PSPD_Msk // Port speed
|
||||
#define HPRT_PSPD_0 (0x1UL << HPRT_PSPD_Pos) // 0x00020000
|
||||
#define HPRT_PSPD_1 (0x2UL << HPRT_PSPD_Pos) // 0x00040000
|
||||
#define HPRT_CONN_STATUS_Pos (0U)
|
||||
#define HPRT_CONN_STATUS_Msk (0x1UL << HPRT_CONN_STATUS_Pos) // 0x00000001
|
||||
#define HPRT_CONN_STATUS HPRT_CONN_STATUS_Msk // Port connect status
|
||||
#define HPRT_CONN_DETECT_Pos (1U)
|
||||
#define HPRT_CONN_DETECT_Msk (0x1UL << HPRT_CONN_DETECT_Pos) // 0x00000002
|
||||
#define HPRT_CONN_DETECT HPRT_CONN_DETECT_Msk // Port connect detected
|
||||
#define HPRT_ENABLE_Pos (2U)
|
||||
#define HPRT_ENABLE_Msk (0x1UL << HPRT_ENABLE_Pos) // 0x00000004
|
||||
#define HPRT_ENABLE HPRT_ENABLE_Msk // Port enable
|
||||
#define HPRT_ENABLE_CHANGE_Pos (3U)
|
||||
#define HPRT_ENABLE_CHANGE_Msk (0x1UL << HPRT_ENABLE_CHANGE_Pos) // 0x00000008
|
||||
#define HPRT_ENABLE_CHANGE HPRT_ENABLE_CHANGE_Msk // Port enable/disable change
|
||||
#define HPRT_OVER_CURRENT_ACTIVE_Pos (4U)
|
||||
#define HPRT_OVER_CURRENT_ACTIVE_Msk (0x1UL << HPRT_OVER_CURRENT_ACTIVE_Pos) // 0x00000010
|
||||
#define HPRT_OVER_CURRENT_ACTIVE HPRT_OVER_CURRENT_ACTIVE_Msk // Port overcurrent active
|
||||
#define HPRT_OVER_CURRENT_CHANGE_Pos (5U)
|
||||
#define HPRT_OVER_CURRENT_CHANGE_Msk (0x1UL << HPRT_OVER_CURRENT_CHANGE_Pos) // 0x00000020
|
||||
#define HPRT_OVER_CURRENT_CHANGE HPRT_OVER_CURRENT_CHANGE_Msk // Port overcurrent change
|
||||
#define HPRT_RESUME_Pos (6U)
|
||||
#define HPRT_RESUME_Msk (0x1UL << HPRT_RESUME_Pos) // 0x00000040
|
||||
#define HPRT_RESUME HPRT_RESUME_Msk // Port resume
|
||||
#define HPRT_SUSPEND_Pos (7U)
|
||||
#define HPRT_SUSPEND_Msk (0x1UL << HPRT_SUSPEND_Pos) // 0x00000080
|
||||
#define HPRT_SUSPEND HPRT_SUSPEND_Msk // Port suspend
|
||||
#define HPRT_RESET_Pos (8U)
|
||||
#define HPRT_RESET_Msk (0x1UL << HPRT_RESET_Pos) // 0x00000100
|
||||
#define HPRT_RESET HPRT_RESET_Msk // Port reset
|
||||
#define HPRT_LINE_STATUS_Pos (10U)
|
||||
#define HPRT_LINE_STATUS_Msk (0x3UL << HPRT_LINE_STATUS_Pos) // 0x00000C00
|
||||
#define HPRT_LINE_STATUS HPRT_LINE_STATUS_Msk // Port line status
|
||||
#define HPRT_LINE_STATUS_0 (0x1UL << HPRT_LINE_STATUS_Pos) // 0x00000400
|
||||
#define HPRT_LINE_STATUS_1 (0x2UL << HPRT_LINE_STATUS_Pos) // 0x00000800
|
||||
#define HPRT_POWER_Pos (12U)
|
||||
#define HPRT_POWER_Msk (0x1UL << HPRT_POWER_Pos) // 0x00001000
|
||||
#define HPRT_POWER HPRT_POWER_Msk // Port power
|
||||
#define HPRT_TEST_CONTROL_Pos (13U)
|
||||
#define HPRT_TEST_CONTROL_Msk (0xFUL << HPRT_TEST_CONTROL_Pos) // 0x0001E000
|
||||
#define HPRT_TEST_CONTROL HPRT_TEST_CONTROL_Msk // Port test control
|
||||
#define HPRT_TEST_CONTROL_0 (0x1UL << HPRT_TEST_CONTROL_Pos) // 0x00002000
|
||||
#define HPRT_TEST_CONTROL_1 (0x2UL << HPRT_TEST_CONTROL_Pos) // 0x00004000
|
||||
#define HPRT_TEST_CONTROL_2 (0x4UL << HPRT_TEST_CONTROL_Pos) // 0x00008000
|
||||
#define HPRT_TEST_CONTROL_3 (0x8UL << HPRT_TEST_CONTROL_Pos) // 0x00010000
|
||||
#define HPRT_SPEED_Pos (17U)
|
||||
#define HPRT_SPEED_Msk (0x3UL << HPRT_SPEED_Pos) // 0x00060000
|
||||
#define HPRT_SPEED HPRT_SPEED_Msk // Port speed
|
||||
#define HPRT_SPEED_0 (0x1UL << HPRT_SPEED_Pos) // 0x00020000
|
||||
#define HPRT_SPEED_1 (0x2UL << HPRT_SPEED_Pos) // 0x00040000
|
||||
|
||||
/******************** Bit definition for DOEPEACHMSK1 register ********************/
|
||||
#define DOEPEACHMSK1_XFRCM_Pos (0U)
|
||||
|
|
@ -1679,15 +1984,15 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define HCSPLT_SPLITEN HCSPLT_SPLITEN_Msk // Split enable
|
||||
|
||||
/******************** Bit definition for HCINT register ********************/
|
||||
#define HCINT_XFRC_Pos (0U)
|
||||
#define HCINT_XFRC_Msk (0x1UL << HCINT_XFRC_Pos) // 0x00000001
|
||||
#define HCINT_XFRC HCINT_XFRC_Msk // Transfer completed
|
||||
#define HCINT_CHH_Pos (1U)
|
||||
#define HCINT_CHH_Msk (0x1UL << HCINT_CHH_Pos) // 0x00000002
|
||||
#define HCINT_CHH HCINT_CHH_Msk // Channel halted
|
||||
#define HCINT_AHBERR_Pos (2U)
|
||||
#define HCINT_AHBERR_Msk (0x1UL << HCINT_AHBERR_Pos) // 0x00000004
|
||||
#define HCINT_AHBERR HCINT_AHBERR_Msk // AHB error
|
||||
#define HCINT_XFER_COMPLETE_Pos (0U)
|
||||
#define HCINT_XFER_COMPLETE_Msk (0x1UL << HCINT_XFER_COMPLETE_Pos) // 0x00000001
|
||||
#define HCINT_XFER_COMPLETE HCINT_XFER_COMPLETE_Msk // Transfer completed
|
||||
#define HCINT_HALTED_Pos (1U)
|
||||
#define HCINT_HALTED_Msk (0x1UL << HCINT_HALTED_Pos) // 0x00000002
|
||||
#define HCINT_HALTED HCINT_HALTED_Msk // Channel halted
|
||||
#define HCINT_AHB_ERR_Pos (2U)
|
||||
#define HCINT_AHB_ERR_Msk (0x1UL << HCINT_AHB_ERR_Pos) // 0x00000004
|
||||
#define HCINT_AHB_ERR HCINT_AHB_ERR_Msk // AHB error
|
||||
#define HCINT_STALL_Pos (3U)
|
||||
#define HCINT_STALL_Msk (0x1UL << HCINT_STALL_Pos) // 0x00000008
|
||||
#define HCINT_STALL HCINT_STALL_Msk // STALL response received interrupt
|
||||
|
|
@ -1700,18 +2005,27 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define HCINT_NYET_Pos (6U)
|
||||
#define HCINT_NYET_Msk (0x1UL << HCINT_NYET_Pos) // 0x00000040
|
||||
#define HCINT_NYET HCINT_NYET_Msk // Response received interrupt
|
||||
#define HCINT_TXERR_Pos (7U)
|
||||
#define HCINT_TXERR_Msk (0x1UL << HCINT_TXERR_Pos) // 0x00000080
|
||||
#define HCINT_TXERR HCINT_TXERR_Msk // Transaction error
|
||||
#define HCINT_BBERR_Pos (8U)
|
||||
#define HCINT_BBERR_Msk (0x1UL << HCINT_BBERR_Pos) // 0x00000100
|
||||
#define HCINT_BBERR HCINT_BBERR_Msk // Babble error
|
||||
#define HCINT_FRMOR_Pos (9U)
|
||||
#define HCINT_FRMOR_Msk (0x1UL << HCINT_FRMOR_Pos) // 0x00000200
|
||||
#define HCINT_FRMOR HCINT_FRMOR_Msk // Frame overrun
|
||||
#define HCINT_DTERR_Pos (10U)
|
||||
#define HCINT_DTERR_Msk (0x1UL << HCINT_DTERR_Pos) // 0x00000400
|
||||
#define HCINT_DTERR HCINT_DTERR_Msk // Data toggle error
|
||||
#define HCINT_XACT_ERR_Pos (7U)
|
||||
#define HCINT_XACT_ERR_Msk (0x1UL << HCINT_XACT_ERR_Pos) // 0x00000080
|
||||
#define HCINT_XACT_ERR HCINT_XACT_ERR_Msk // Transaction error
|
||||
#define HCINT_BABBLE_ERR_Pos (8U)
|
||||
#define HCINT_BABBLE_ERR_Msk (0x1UL << HCINT_BABBLE_ERR_Pos) // 0x00000100
|
||||
#define HCINT_BABBLE_ERR HCINT_BABBLE_ERR_Msk // Babble error
|
||||
#define HCINT_FARME_OVERRUN_Pos (9U)
|
||||
#define HCINT_FARME_OVERRUN_Msk (0x1UL << HCINT_FARME_OVERRUN_Pos) // 0x00000200
|
||||
#define HCINT_FARME_OVERRUN HCINT_FARME_OVERRUN_Msk // Frame overrun
|
||||
#define HCINT_DATATOGGLE_ERR_Pos (10U)
|
||||
#define HCINT_DATATOGGLE_ERR_Msk (0x1UL << HCINT_DATATOGGLE_ERR_Pos) // 0x00000400
|
||||
#define HCINT_DATATOGGLE_ERR HCINT_DATATOGGLE_ERR_Msk // Data toggle error
|
||||
#define HCINT_BUFFER_NA_Pos (11U)
|
||||
#define HCINT_BUFFER_NA_Msk (0x1UL << HCINT_BUFFER_NA_Pos) // 0x00000800
|
||||
#define HCINT_BUFFER_NA HCINT_BUFFER_NA_Msk // Buffer not available interrupt
|
||||
#define HCINT_XCS_XACT_ERR_Pos (12U)
|
||||
#define HCINT_XCS_XACT_ERR_Msk (0x1UL << HCINT_XCS_XACT_ERR_Pos) // 0x00001000
|
||||
#define HCINT_XCS_XACT_ERR HCINT_XCS_XACT_ERR_Msk // Excessive transaction error
|
||||
#define HCINT_DESC_ROLLOVER_Pos (13U)
|
||||
#define HCINT_DESC_ROLLOVER_Msk (0x1UL << HCINT_DESC_ROLLOVER_Pos) // 0x00002000
|
||||
#define HCINT_DESC_ROLLOVER HCINT_DESC_ROLLOVER_Msk // Descriptor rollover
|
||||
|
||||
/******************** Bit definition for DIEPINT register ********************/
|
||||
#define DIEPINT_XFRC_Pos (0U)
|
||||
|
|
@ -1754,41 +2068,6 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define DIEPINT_NAK_Msk (0x1UL << DIEPINT_NAK_Pos) // 0x00002000
|
||||
#define DIEPINT_NAK DIEPINT_NAK_Msk // NAK interrupt
|
||||
|
||||
/******************** Bit definition for HCINTMSK register ********************/
|
||||
#define HCINTMSK_XFRCM_Pos (0U)
|
||||
#define HCINTMSK_XFRCM_Msk (0x1UL << HCINTMSK_XFRCM_Pos) // 0x00000001
|
||||
#define HCINTMSK_XFRCM HCINTMSK_XFRCM_Msk // Transfer completed mask
|
||||
#define HCINTMSK_CHHM_Pos (1U)
|
||||
#define HCINTMSK_CHHM_Msk (0x1UL << HCINTMSK_CHHM_Pos) // 0x00000002
|
||||
#define HCINTMSK_CHHM HCINTMSK_CHHM_Msk // Channel halted mask
|
||||
#define HCINTMSK_AHBERR_Pos (2U)
|
||||
#define HCINTMSK_AHBERR_Msk (0x1UL << HCINTMSK_AHBERR_Pos) // 0x00000004
|
||||
#define HCINTMSK_AHBERR HCINTMSK_AHBERR_Msk // AHB error
|
||||
#define HCINTMSK_STALLM_Pos (3U)
|
||||
#define HCINTMSK_STALLM_Msk (0x1UL << HCINTMSK_STALLM_Pos) // 0x00000008
|
||||
#define HCINTMSK_STALLM HCINTMSK_STALLM_Msk // STALL response received interrupt mask
|
||||
#define HCINTMSK_NAKM_Pos (4U)
|
||||
#define HCINTMSK_NAKM_Msk (0x1UL << HCINTMSK_NAKM_Pos) // 0x00000010
|
||||
#define HCINTMSK_NAKM HCINTMSK_NAKM_Msk // NAK response received interrupt mask
|
||||
#define HCINTMSK_ACKM_Pos (5U)
|
||||
#define HCINTMSK_ACKM_Msk (0x1UL << HCINTMSK_ACKM_Pos) // 0x00000020
|
||||
#define HCINTMSK_ACKM HCINTMSK_ACKM_Msk // ACK response received/transmitted interrupt mask
|
||||
#define HCINTMSK_NYET_Pos (6U)
|
||||
#define HCINTMSK_NYET_Msk (0x1UL << HCINTMSK_NYET_Pos) // 0x00000040
|
||||
#define HCINTMSK_NYET HCINTMSK_NYET_Msk // response received interrupt mask
|
||||
#define HCINTMSK_TXERRM_Pos (7U)
|
||||
#define HCINTMSK_TXERRM_Msk (0x1UL << HCINTMSK_TXERRM_Pos) // 0x00000080
|
||||
#define HCINTMSK_TXERRM HCINTMSK_TXERRM_Msk // Transaction error mask
|
||||
#define HCINTMSK_BBERRM_Pos (8U)
|
||||
#define HCINTMSK_BBERRM_Msk (0x1UL << HCINTMSK_BBERRM_Pos) // 0x00000100
|
||||
#define HCINTMSK_BBERRM HCINTMSK_BBERRM_Msk // Babble error mask
|
||||
#define HCINTMSK_FRMORM_Pos (9U)
|
||||
#define HCINTMSK_FRMORM_Msk (0x1UL << HCINTMSK_FRMORM_Pos) // 0x00000200
|
||||
#define HCINTMSK_FRMORM HCINTMSK_FRMORM_Msk // Frame overrun mask
|
||||
#define HCINTMSK_DTERRM_Pos (10U)
|
||||
#define HCINTMSK_DTERRM_Msk (0x1UL << HCINTMSK_DTERRM_Pos) // 0x00000400
|
||||
#define HCINTMSK_DTERRM HCINTMSK_DTERRM_Msk // Data toggle error mask
|
||||
|
||||
/******************** Bit definition for DIEPTSIZ register ********************/
|
||||
|
||||
#define DIEPTSIZ_XFRSIZ_Pos (0U)
|
||||
|
|
@ -1810,11 +2089,9 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define HCTSIZ_DOPING_Pos (31U)
|
||||
#define HCTSIZ_DOPING_Msk (0x1UL << HCTSIZ_DOPING_Pos) // 0x80000000
|
||||
#define HCTSIZ_DOPING HCTSIZ_DOPING_Msk // Do PING
|
||||
#define HCTSIZ_DPID_Pos (29U)
|
||||
#define HCTSIZ_DPID_Msk (0x3UL << HCTSIZ_DPID_Pos) // 0x60000000
|
||||
#define HCTSIZ_DPID HCTSIZ_DPID_Msk // Data PID
|
||||
#define HCTSIZ_DPID_0 (0x1UL << HCTSIZ_DPID_Pos) // 0x20000000
|
||||
#define HCTSIZ_DPID_1 (0x2UL << HCTSIZ_DPID_Pos) // 0x40000000
|
||||
#define HCTSIZ_PID_Pos (29U)
|
||||
#define HCTSIZ_PID_Msk (0x3UL << HCTSIZ_PID_Pos) // 0x60000000
|
||||
#define HCTSIZ_PID HCTSIZ_PID_Msk // Data PID
|
||||
|
||||
/******************** Bit definition for DIEPDMA register ********************/
|
||||
#define DIEPDMA_DMAADDR_Pos (0U)
|
||||
|
|
@ -1973,32 +2250,32 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
|||
#define DOEPTSIZ_STUPCNT_1 (0x2UL << DOEPTSIZ_STUPCNT_Pos) // 0x40000000
|
||||
|
||||
/******************** Bit definition for PCGCTL register ********************/
|
||||
#define PCGCTL_IF_DEV_MODE TU_BIT(31)
|
||||
#define PCGCTL_P2HD_PRT_SPD_MASK (0x3ul << 29)
|
||||
#define PCGCTL_P2HD_PRT_SPD_SHIFT 29
|
||||
#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3ul << 27)
|
||||
#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
|
||||
#define PCGCTL_MAC_DEV_ADDR_MASK (0x7ful << 20)
|
||||
#define PCGCTL_MAC_DEV_ADDR_SHIFT 20
|
||||
#define PCGCTL_MAX_TERMSEL TU_BIT(19)
|
||||
#define PCGCTL_MAX_XCVRSELECT_MASK (0x3ul << 17)
|
||||
#define PCGCTL_MAX_XCVRSELECT_SHIFT 17
|
||||
#define PCGCTL_PORT_POWER TU_BIT(16)
|
||||
#define PCGCTL_PRT_CLK_SEL_MASK (0x3ul << 14)
|
||||
#define PCGCTL_PRT_CLK_SEL_SHIFT 14
|
||||
#define PCGCTL_ESS_REG_RESTORED TU_BIT(13)
|
||||
#define PCGCTL_EXTND_HIBER_SWITCH TU_BIT(12)
|
||||
#define PCGCTL_EXTND_HIBER_PWRCLMP TU_BIT(11)
|
||||
#define PCGCTL_ENBL_EXTND_HIBER TU_BIT(10)
|
||||
#define PCGCTL_RESTOREMODE TU_BIT(9)
|
||||
#define PCGCTL_RESETAFTSUSP TU_BIT(8)
|
||||
#define PCGCTL_DEEP_SLEEP TU_BIT(7)
|
||||
#define PCGCTL_PHY_IN_SLEEP TU_BIT(6)
|
||||
#define PCGCTL_ENBL_SLEEP_GATING TU_BIT(5)
|
||||
#define PCGCTL_RSTPDWNMODULE TU_BIT(3)
|
||||
#define PCGCTL_PWRCLMP TU_BIT(2)
|
||||
#define PCGCTL_GATEHCLK TU_BIT(1)
|
||||
#define PCGCTL_STOPPCLK TU_BIT(0)
|
||||
#define PCGCCTL_IF_DEV_MODE TU_BIT(31)
|
||||
#define PCGCCTL_P2HD_PRT_SPD_MASK (0x3ul << 29)
|
||||
#define PCGCCTL_P2HD_PRT_SPD_SHIFT 29
|
||||
#define PCGCCTL_P2HD_DEV_ENUM_SPD_MASK (0x3ul << 27)
|
||||
#define PCGCCTL_P2HD_DEV_ENUM_SPD_SHIFT 27
|
||||
#define PCGCCTL_MAC_DEV_ADDR_MASK (0x7ful << 20)
|
||||
#define PCGCCTL_MAC_DEV_ADDR_SHIFT 20
|
||||
#define PCGCCTL_MAX_TERMSEL TU_BIT(19)
|
||||
#define PCGCCTL_MAX_XCVRSELECT_MASK (0x3ul << 17)
|
||||
#define PCGCCTL_MAX_XCVRSELECT_SHIFT 17
|
||||
#define PCGCCTL_PORT_POWER TU_BIT(16)
|
||||
#define PCGCCTL_PRT_CLK_SEL_MASK (0x3ul << 14)
|
||||
#define PCGCCTL_PRT_CLK_SEL_SHIFT 14
|
||||
#define PCGCCTL_ESS_REG_RESTORED TU_BIT(13)
|
||||
#define PCGCCTL_EXTND_HIBER_SWITCH TU_BIT(12)
|
||||
#define PCGCCTL_EXTND_HIBER_PWRCLMP TU_BIT(11)
|
||||
#define PCGCCTL_ENBL_EXTND_HIBER TU_BIT(10)
|
||||
#define PCGCCTL_RESTOREMODE TU_BIT(9)
|
||||
#define PCGCCTL_RESETAFTSUSP TU_BIT(8)
|
||||
#define PCGCCTL_DEEP_SLEEP TU_BIT(7)
|
||||
#define PCGCCTL_PHY_IN_SLEEP TU_BIT(6)
|
||||
#define PCGCCTL_ENBL_SLEEP_GATING TU_BIT(5)
|
||||
#define PCGCCTL_RSTPDWNMODULE TU_BIT(3)
|
||||
#define PCGCCTL_PWRCLMP TU_BIT(2)
|
||||
#define PCGCCTL_GATEHCLK TU_BIT(1)
|
||||
#define PCGCCTL_STOPPCLK TU_BIT(0)
|
||||
|
||||
#define PCGCTL1_TIMER (0x3ul << 1)
|
||||
#define PCGCTL1_GATEEN TU_BIT(0)
|
||||
|
|
|
|||
1360
src/portable/synopsys/dwc2/hcd_dwc2.c
Normal file
1360
src/portable/synopsys/dwc2/hcd_dwc2.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -192,7 +192,8 @@ void dcd_int_handler(uint8_t rhport) {
|
|||
data.xfer[0][TUSB_DIR_OUT].max_size = 64;
|
||||
data.xfer[0][TUSB_DIR_IN].max_size = 64;
|
||||
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
|
||||
//dcd_event_bus_reset(rhport, (USBOTG_FS->BASE_CTRL & USBFS_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);
|
||||
dcd_event_bus_reset(rhport, (USBOTG_FS->UDEV_CTRL & USBFS_UDEV_CTRL_LOW_SPEED) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL, true);
|
||||
|
||||
USBOTG_FS->DEV_ADDR = 0x00;
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
|
||||
|
|
|
|||
38
src/tusb.c
38
src/tusb.c
|
|
@ -24,11 +24,6 @@
|
|||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
// ESP32 out-of-sync
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUH_ENABLED || CFG_TUD_ENABLED
|
||||
|
|
@ -44,14 +39,25 @@
|
|||
#include "host/usbh_pvt.h"
|
||||
#endif
|
||||
|
||||
#define TUP_USBIP_CONTROLLER_NUM 2
|
||||
tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM] = { TUSB_ROLE_INVALID };
|
||||
|
||||
static tusb_role_t _rhport_role[TUP_USBIP_CONTROLLER_NUM] = { 0 };
|
||||
//--------------------------------------------------------------------
|
||||
// Weak/Default API, can be overwritten by Application
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
TU_ATTR_WEAK void tusb_time_delay_ms_api(uint32_t ms) {
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_task_delay(ms);
|
||||
#else
|
||||
// delay using millis() (if implemented) and/or frame number if possible
|
||||
const uint32_t time_ms = tusb_time_millis_api();
|
||||
while ((tusb_time_millis_api() - time_ms) < ms) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Public API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
||||
// backward compatible called with tusb_init(void)
|
||||
#if defined(TUD_OPT_RHPORT) || defined(TUH_OPT_RHPORT)
|
||||
|
|
@ -62,8 +68,8 @@ bool tusb_rhport_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
|
||||
};
|
||||
TU_ASSERT ( tud_rhport_init(rhport, &dev_init) );
|
||||
_rhport_role[TUD_OPT_RHPORT] = TUSB_ROLE_DEVICE;
|
||||
TU_ASSERT ( tud_rhport_init(TUD_OPT_RHPORT, &dev_init) );
|
||||
_tusb_rhport_role[TUD_OPT_RHPORT] = TUSB_ROLE_DEVICE;
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_ENABLED && defined(TUH_OPT_RHPORT)
|
||||
|
|
@ -73,7 +79,7 @@ bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||
.speed = TUH_OPT_HIGH_SPEED ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL
|
||||
};
|
||||
TU_ASSERT( tuh_rhport_init(TUH_OPT_RHPORT, &host_init) );
|
||||
_rhport_role[TUH_OPT_RHPORT] = TUSB_ROLE_HOST;
|
||||
_tusb_rhport_role[TUH_OPT_RHPORT] = TUSB_ROLE_HOST;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
|
@ -82,6 +88,7 @@ bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||
|
||||
// new API with explicit rhport and role
|
||||
TU_ASSERT(rhport < TUP_USBIP_CONTROLLER_NUM && rh_init->role != TUSB_ROLE_INVALID);
|
||||
_tusb_rhport_role[rhport] = rh_init->role;
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
if (rh_init->role == TUSB_ROLE_DEVICE) {
|
||||
|
|
@ -95,7 +102,6 @@ bool tusb_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
|
|||
}
|
||||
#endif
|
||||
|
||||
_rhport_role[rhport] = rh_init->role;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -117,14 +123,14 @@ void tusb_int_handler(uint8_t rhport, bool in_isr) {
|
|||
TU_VERIFY(rhport < TUP_USBIP_CONTROLLER_NUM,);
|
||||
|
||||
#if CFG_TUD_ENABLED
|
||||
if (_rhport_role[rhport] == TUSB_ROLE_DEVICE) {
|
||||
if (_tusb_rhport_role[rhport] == TUSB_ROLE_DEVICE) {
|
||||
(void) in_isr;
|
||||
dcd_int_handler(rhport);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
if (_rhport_role[rhport] == TUSB_ROLE_HOST) {
|
||||
if (_tusb_rhport_role[rhport] == TUSB_ROLE_HOST) {
|
||||
hcd_int_handler(rhport, in_isr);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -252,6 +258,10 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf,
|
|||
p_desc = tu_desc_next(p_desc);
|
||||
|
||||
while (len < max_len) {
|
||||
if (tu_desc_len(p_desc) == 0) {
|
||||
// Escape infinite loop
|
||||
break;
|
||||
}
|
||||
// return on IAD regardless of itf count
|
||||
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION) {
|
||||
return len;
|
||||
|
|
|
|||
13
src/tusb.h
13
src/tusb.h
|
|
@ -127,10 +127,8 @@
|
|||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
// User API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
#if CFG_TUH_ENABLED || CFG_TUD_ENABLED
|
||||
|
||||
// Internal helper for backward compatible with tusb_init(void)
|
||||
|
|
@ -167,6 +165,15 @@ void tusb_int_handler(uint8_t rhport, bool in_isr);
|
|||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// API Implemented by user
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Get current milliseconds, required by some port/configuration without RTOS
|
||||
uint32_t tusb_time_millis_api(void);
|
||||
|
||||
// Delay in milliseconds, use tusb_time_millis_api() by default. required by some port/configuration with no RTOS
|
||||
void tusb_time_delay_ms_api(uint32_t ms);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,17 +39,7 @@
|
|||
#include "arduino/ports/rp2040/tusb_config_rp2040.h"
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
// Note: when compiling core Arduino IDEs will include tusb_config.h in the BSP
|
||||
// sdk/include/arduino_tinyusb/include. While compiling .c file in this library this
|
||||
// file will be used instead. For consistency: include the one in BSP here as well
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "../../arduino_tinyusb/include/tusb_config.h"
|
||||
#else
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#endif
|
||||
|
||||
// Note: For platformio prioritize this file over the one in BSP in all cases
|
||||
// do nothing since we force include "arduino/ports/esp32/tusb_config_esp32.h" in tusb_option.h
|
||||
|
||||
#elif defined(ARDUINO_ARCH_CH32) || defined(CH32V20x) || defined(CH32V30x)
|
||||
#include "arduino/ports/ch32/tusb_config_ch32.h"
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
// Version is release as major.minor.revision eg 1.0.0
|
||||
#define TUSB_VERSION_MAJOR 0
|
||||
#define TUSB_VERSION_MINOR 17
|
||||
#define TUSB_VERSION_MINOR 18
|
||||
#define TUSB_VERSION_REVISION 0
|
||||
|
||||
#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION)
|
||||
|
|
@ -92,6 +92,8 @@
|
|||
#define OPT_MCU_STM32L5 314 ///< ST L5
|
||||
#define OPT_MCU_STM32H5 315 ///< ST H5
|
||||
#define OPT_MCU_STM32U0 316 ///< ST U0
|
||||
#define OPT_MCU_STM32H7RS 317 ///< ST F7RS
|
||||
#define OPT_MCU_STM32C0 318 ///< ST C0
|
||||
|
||||
// Sony
|
||||
#define OPT_MCU_CXD56 400 ///< SONY CXD56
|
||||
|
|
@ -125,7 +127,8 @@
|
|||
#define OPT_MCU_ESP32C2 905 ///< Espressif ESP32-C2
|
||||
#define OPT_MCU_ESP32H2 906 ///< Espressif ESP32-H2
|
||||
#define OPT_MCU_ESP32P4 907 ///< Espressif ESP32-P4
|
||||
#define TUP_MCU_ESPRESSIF (CFG_TUSB_MCU >= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU
|
||||
#define TUSB_MCU_VENDOR_ESPRESSIF (CFG_TUSB_MCU >= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU
|
||||
#define TUP_MCU_ESPRESSIF TUSB_MCU_VENDOR_ESPRESSIF // for backward compatibility
|
||||
|
||||
// Dialog
|
||||
#define OPT_MCU_DA1469X 1000 ///< Dialog Semiconductor DA1469x
|
||||
|
|
@ -149,7 +152,7 @@
|
|||
#define OPT_MCU_RX63X 1400 ///< Renesas RX63N/631
|
||||
#define OPT_MCU_RX65X 1401 ///< Renesas RX65N/RX651
|
||||
#define OPT_MCU_RX72N 1402 ///< Renesas RX72N
|
||||
#define OPT_MCU_RAXXX 1403 ///< Renesas RAxxx families
|
||||
#define OPT_MCU_RAXXX 1403 ///< Renesas RA generic
|
||||
|
||||
// Mind Motion
|
||||
#define OPT_MCU_MM32F327X 1500 ///< Mind Motion MM32F327
|
||||
|
|
@ -212,6 +215,7 @@
|
|||
#define OPT_OS_PICO 5 ///< Raspberry Pi Pico SDK
|
||||
#define OPT_OS_RTTHREAD 6 ///< RT-Thread
|
||||
#define OPT_OS_RTX4 7 ///< Keil RTX 4
|
||||
#define OPT_OS_ZEPHYR 8 ///< Zephyr
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Mode and Speed
|
||||
|
|
@ -236,21 +240,52 @@
|
|||
// Allow to use command line to change the config name/location
|
||||
#ifdef CFG_TUSB_CONFIG_FILE
|
||||
#include CFG_TUSB_CONFIG_FILE
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
// ESP32 out-of-sync
|
||||
#include "arduino/ports/esp32/tusb_config_esp32.h"
|
||||
#else
|
||||
#include "tusb_config.h"
|
||||
#endif
|
||||
|
||||
#include "common/tusb_mcu.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBIP
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// DWC2 controller: use DMA for data transfer
|
||||
// For processors with data cache enabled, USB endpoint buffer region
|
||||
// (defined by CFG_TUSB_MEM_SECTION) must be declared as non-cacheable.
|
||||
// For example, on Cortex-M7 the MPU region can be configured as normal
|
||||
// non-cacheable, with RASR register value: TEX=1 C=0 B=0 S=0.
|
||||
#ifndef CFG_TUD_DWC2_DMA
|
||||
#define CFG_TUD_DWC2_DMA 0
|
||||
#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
|
||||
#ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT 1
|
||||
#endif
|
||||
|
||||
#define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// Enable DWC2 DMA for device
|
||||
#ifndef CFG_TUD_DWC2_DMA_ENABLE
|
||||
#ifndef CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
|
||||
#define CFG_TUD_DWC2_DMA_ENABLE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// Enable DWC2 Slave mode for host
|
||||
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
|
||||
#ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT 1
|
||||
#endif
|
||||
|
||||
#define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// Enable DWC2 DMA for host
|
||||
#ifndef CFG_TUH_DWC2_DMA_ENABLE
|
||||
#ifndef CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
|
||||
#define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#define CFG_TUH_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
// Enable PIO-USB software host controller
|
||||
|
|
@ -267,7 +302,6 @@
|
|||
#define CFG_TUH_MAX3421 0
|
||||
#endif
|
||||
|
||||
#include "common/tusb_mcu.h"
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// RootHub Mode detection
|
||||
|
|
@ -376,13 +410,25 @@
|
|||
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_MEM_DCACHE_LINE_SIZE
|
||||
#ifndef CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT
|
||||
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT
|
||||
#endif
|
||||
|
||||
// OS selection
|
||||
#ifndef CFG_TUSB_OS
|
||||
#define CFG_TUSB_OS OPT_OS_NONE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUSB_OS_INC_PATH
|
||||
#define CFG_TUSB_OS_INC_PATH
|
||||
#ifndef CFG_TUSB_OS_INC_PATH_DEFAULT
|
||||
#define CFG_TUSB_OS_INC_PATH_DEFAULT
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_OS_INC_PATH CFG_TUSB_OS_INC_PATH_DEFAULT
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
|
@ -399,6 +445,18 @@
|
|||
#define CFG_TUD_MEM_ALIGN CFG_TUSB_MEM_ALIGN
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_MEM_DCACHE_ENABLE
|
||||
#ifndef CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT
|
||||
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#define CFG_TUD_MEM_DCACHE_ENABLE CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_MEM_DCACHE_LINE_SIZE
|
||||
#define CFG_TUD_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||
#endif
|
||||
|
|
@ -506,6 +564,18 @@
|
|||
#define CFG_TUH_MEM_ALIGN CFG_TUSB_MEM_ALIGN
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_MEM_DCACHE_ENABLE
|
||||
#ifndef CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT
|
||||
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#define CFG_TUH_MEM_DCACHE_ENABLE CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_MEM_DCACHE_LINE_SIZE
|
||||
#define CFG_TUH_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE
|
||||
#endif
|
||||
|
||||
//------------- CLASS -------------//
|
||||
|
||||
#ifndef CFG_TUH_HUB
|
||||
|
|
|
|||
Loading…
Reference in a new issue