From 4901917ea3015fb4704e64e2f296cad649bdf2d2 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 30 Apr 2020 15:18:49 +0200 Subject: [PATCH] esp_rom: add USB related headers from the ROM code --- components/esp_rom/esp32s2/ld/esp32s2.rom.ld | 7 +- components/esp_rom/include/esp32s2/rom/uart.h | 11 +- .../esp_rom/include/esp32s2/rom/usb/cdc_acm.h | 262 ++++++++++++ .../esp32s2/rom/usb/chip_usb_dw_wrapper.h | 30 ++ .../esp_rom/include/esp32s2/rom/usb/cpio.h | 180 ++++++++ .../esp_rom/include/esp32s2/rom/usb/usb_cdc.h | 174 ++++++++ .../include/esp32s2/rom/usb/usb_common.h | 244 +++++++++++ .../esp_rom/include/esp32s2/rom/usb/usb_dc.h | 392 +++++++++++++++++ .../include/esp32s2/rom/usb/usb_descriptor.h | 34 ++ .../include/esp32s2/rom/usb/usb_device.h | 402 ++++++++++++++++++ .../esp_rom/include/esp32s2/rom/usb/usb_dfu.h | 147 +++++++ .../include/esp32s2/rom/usb/usb_os_glue.h | 40 ++ .../include/esp32s2/rom/usb/usb_persist.h | 50 +++ 13 files changed, 1971 insertions(+), 2 deletions(-) create mode 100644 components/esp_rom/include/esp32s2/rom/usb/cdc_acm.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/chip_usb_dw_wrapper.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/cpio.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_cdc.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_common.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_dc.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_descriptor.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_device.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_dfu.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_os_glue.h create mode 100644 components/esp_rom/include/esp32s2/rom/usb/usb_persist.h diff --git a/components/esp_rom/esp32s2/ld/esp32s2.rom.ld b/components/esp_rom/esp32s2/ld/esp32s2.rom.ld index 5583e5c1e5..445d033bfa 100644 --- a/components/esp_rom/esp32s2/ld/esp32s2.rom.ld +++ b/components/esp_rom/esp32s2/ld/esp32s2.rom.ld @@ -570,6 +570,11 @@ PROVIDE ( rom_txiq_set_reg = 0x4000bf64 ); PROVIDE ( rom_tx_paon_set = 0x40009db8 ); PROVIDE ( rom_tx_pwr_backoff = 0x4000ceb8 ); PROVIDE ( rom_txtone_linear_pwr = 0x4000c0b0 ); +PROVIDE ( rom_usb_dev = 0x3ffffb9c ); /* static "usb_dev" */ +PROVIDE ( rom_usb_dev_end = 0x3ffffc78 ); /* end of "usb_dev" */ +PROVIDE ( rom_usb_dw_ctrl = 0x3ffffa74 ); /* static "usb_dw_ctrl" */ +PROVIDE ( rom_usb_dw_ctrl_end = 0x3ffffb9c ); /* end of "usb_dw_ctrl" */ +PROVIDE ( rom_usb_curr_desc = 0x3ffffa54 ); /* static "s_curr_descr" */ PROVIDE ( rom_wait_rfpll_cal_end = 0x4000af3c ); PROVIDE ( rom_wifi_11g_rate_chg = 0x4000d260 ); PROVIDE ( rom_wifi_rifs_mode_en = 0x40009d2c ); @@ -646,7 +651,7 @@ PROVIDE ( string0_descr = 0x3ffaeeae ); PROVIDE ( str_manu_descr = 0x3ffaee9a ); PROVIDE ( str_prod_descr = 0x3ffaee88 ); PROVIDE ( str_serial_descr = 0x3ffaee84 ); -PROVIDE ( s_usb_osglue = 0x3ffffcdc ); +PROVIDE ( rom_usb_osglue = 0x3ffffcdc ); PROVIDE ( _SyscallException = 0x4000732a ); PROVIDE ( syscall_table_ptr_pro = 0x3ffffd78 ); PROVIDE ( tdefl_compress = 0x400041dc ); diff --git a/components/esp_rom/include/esp32s2/rom/uart.h b/components/esp_rom/include/esp32s2/rom/uart.h index 0c23c976b5..bea0bce251 100644 --- a/components/esp_rom/include/esp32s2/rom/uart.h +++ b/components/esp_rom/include/esp32s2/rom/uart.h @@ -162,6 +162,14 @@ typedef struct { int received; } UartDevice; +typedef enum { + ROM_UART_0, + ROM_UART_1, + ROM_UART_USB +} rom_uart_num_t; + +#define CDC_ACM_WORK_BUF_MIN 128 + /** * @brief Init uart device struct value and reset uart0/uart1 rx. * Please do not call this function in SDK. @@ -428,7 +436,8 @@ uint8_t UartConnCheck(uint8_t uart_no); /** * @brief Initialize the USB ACM UART - * Needs to be fed a buffer of at least 128 bytes, plus any rx buffer you may want to have. + * Needs to be fed a buffer of at least 128 bytes (CDC_ACM_WORK_BUF_MIN), + * plus any rx buffer you may want to have. * * @param cdc_acm_work_mem Pointer to work mem for CDC-ACM code * @param cdc_acm_work_mem_len Length of work mem diff --git a/components/esp_rom/include/esp32s2/rom/usb/cdc_acm.h b/components/esp_rom/include/esp32s2/rom/usb/cdc_acm.h new file mode 100644 index 0000000000..90d71e8177 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/cdc_acm.h @@ -0,0 +1,262 @@ +/******************************************************************************* + * + * Copyright(c) 2015,2016 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void cdc_acm_device; +extern cdc_acm_device *uart_acm_dev; + +#define ACM_BYTES_PER_TX 64 + +//ACM statuses are negative to distinguish from USB_DC_* status codes +#define ACM_STATUS_LINESTATE_CHANGED -1 +#define ACM_STATUS_LINECODING_CHANGED -2 +#define ACM_STATUS_TX -3 +#define ACM_STATUS_RX -4 + +typedef void(*uart_irq_callback_t)(cdc_acm_device *dev, int status); + +/** + * @brief Get amount of received characters in buffer + * + * @returns character count + */ + +int cdc_acm_rx_fifo_cnt(cdc_acm_device *dev); + + +/* + * @brief Poll the device for input. + * + * @return -ENOTSUP Since underlying USB device controller always uses + * interrupts, polled mode UART APIs are not implemented for the UART interface + * exported by CDC ACM driver. Apps should use fifo_read API instead. + */ + +int cdc_acm_poll_in(cdc_acm_device *dev, unsigned char *c); + +/* + * @brief Output a character in polled mode. + * + * The UART poll method for USB UART is simulated by waiting till + * we get the next BULK In upcall from the USB device controller or 100 ms. + * + * @return the same character which is sent + */ +unsigned char cdc_acm_poll_out(cdc_acm_device *dev, unsigned char c); + +/** + * @brief Fill FIFO with data + * + * @param dev CDC ACM device struct. + * @param tx_data Data to transmit. + * @param len Number of bytes to send. + * + * @return Number of bytes sent. + */ +int cdc_acm_fifo_fill(cdc_acm_device *dev, const uint8_t *tx_data, int len); + +/** + * @brief Read data from FIFO + * + * @param dev CDC ACM device struct. + * @param rx_data Pointer to data container. + * @param size Container size. + * + * @return Number of bytes read. + */ +int cdc_acm_fifo_read(cdc_acm_device *dev, uint8_t *rx_data, const int size); + +/** + * @brief Enable TX interrupt + * + * @param dev CDC ACM device struct. + * + * @return N/A. + */ +void cdc_acm_irq_tx_enable(cdc_acm_device *dev); + +/** + * @brief Disable TX interrupt + * + * @param dev CDC ACM device struct. + * + * @return N/A. + */ +void cdc_acm_irq_tx_disable(cdc_acm_device *dev); + +/** + * @brief Check if Tx IRQ has been raised + * + * @param dev CDC ACM device struct. + * + * @return 1 if a Tx IRQ is pending, 0 otherwise. + */ +int cdc_acm_irq_tx_ready(cdc_acm_device *dev); + +/** + * @brief Enable RX interrupt + * + * @param dev CDC ACM device struct. + * + * @return N/A + */ +void cdc_acm_irq_rx_enable(cdc_acm_device *dev); + +/** + * @brief Disable RX interrupt + * + * @param dev CDC ACM device struct. + * + * @return N/A. + */ +void cdc_acm_irq_rx_disable(cdc_acm_device *dev); + +/** + * @brief Enable line state interrupt + * + * @param dev CDC ACM device struct. + * + * @return N/A. + */ +void cdc_acm_irq_state_enable(cdc_acm_device *dev); + +/** + * @brief Disable line state interrupt + * + * @param dev CDC ACM device struct. + * + * @return N/A. + */ +void cdc_acm_irq_state_disable(cdc_acm_device *dev); + + +/** + * @brief Check if Rx IRQ has been raised + * + * @param dev CDC ACM device struct. + * + * @return 1 if an IRQ is ready, 0 otherwise. + */ +int cdc_acm_irq_rx_ready(cdc_acm_device *dev); + +/** + * @brief Check if Tx or Rx IRQ is pending + * + * @param dev CDC ACM device struct. + * + * @return 1 if a Tx or Rx IRQ is pending, 0 otherwise. + */ +int cdc_acm_irq_is_pending(cdc_acm_device *dev); + +/** + * @brief Set the callback function pointer for IRQ. + * + * @param dev CDC ACM device struct. + * @param cb Callback function pointer. + * + * @return N/A + */ +void cdc_acm_irq_callback_set(cdc_acm_device *dev, uart_irq_callback_t cb); + +/** + * @brief Manipulate line control for UART. + * + * @param dev CDC ACM device struct + * @param ctrl The line control to be manipulated + * @param val Value to set the line control + * + * @return 0 if successful, failed otherwise. + */ +int cdc_acm_line_ctrl_set(cdc_acm_device *dev, uint32_t ctrl, uint32_t val); + +/** + * @brief Manipulate line control for UART. + * + * @param dev CDC ACM device struct + * @param ctrl The line control to be manipulated + * @param val Value to set the line control + * + * @return 0 if successful, failed otherwise. + */ +int cdc_acm_line_ctrl_get(cdc_acm_device *dev, uint32_t ctrl, uint32_t *val); + + +/** + * @brief Initialize UART channel + * + * This routine is called to reset the chip in a quiescent state. + * It is assumed that this function is called only once per UART. + * + * @param mem_chunk Memory chunk to use for internal use + * @param mem_chunk_size Size of the memory chunk in bytes + * + * @return dev or NULL + */ +cdc_acm_device *cdc_acm_init(void *mem_chunk, int mem_chunk_size); + + +/** Common line controls for UART.*/ +#define LINE_CTRL_BAUD_RATE (1 << 0) +#define LINE_CTRL_RTS (1 << 1) +#define LINE_CTRL_DTR (1 << 2) +#define LINE_CTRL_DCD (1 << 3) +#define LINE_CTRL_DSR (1 << 4) + +/* Common communication errors for UART.*/ + +/** @brief Overrun error */ +#define UART_ERROR_OVERRUN (1 << 0) + +/** @brief Parity error */ +#define UART_ERROR_PARITY (1 << 1) + +/** @brief Framing error */ +#define UART_ERROR_FRAMING (1 << 2) + +/** + * @brief Break interrupt error: + * + * A break interrupt was received. This happens when the serial input is + * held at a logic '0' state for longer than the sum of start time + data bits + * + parity + stop bits. + */ +#define UART_ERROR_BREAK (1 << 3) + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/chip_usb_dw_wrapper.h b/components/esp_rom/include/esp32s2/rom/usb/chip_usb_dw_wrapper.h new file mode 100644 index 0000000000..a7c5064359 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/chip_usb_dw_wrapper.h @@ -0,0 +1,30 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int chip_usb_dw_init(void); +int chip_usb_dw_did_persist(void); +void chip_usb_dw_prepare_persist(void); +uint32_t chip_usb_get_persist_flags(void); +void chip_usb_set_persist_flags(uint32_t flags); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/cpio.h b/components/esp_rom/include/esp32s2/rom/usb/cpio.h new file mode 100644 index 0000000000..5603b3f541 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/cpio.h @@ -0,0 +1,180 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * Archive to parse cpio data in the newc and crc formats. Generate a cpio archive like that by e.g. + * find . | cpio -o -H newc > archive.cpio + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define CPIO_MODE_FILETYPE_MASK 0xF000 +#define CPIO_MODE_FILETYPE_SOCKET 0xC000 +#define CPIO_MODE_FILETYPE_SYMLINK 0xA000 +#define CPIO_MODE_FILETYPE_REGULAR 0x8000 +#define CPIO_MODE_FILETYPE_BLOCKDEV 0x6000 +#define CPIO_MODE_FILETYPE_DIR 0x4000 +#define CPIO_MODE_FILETYPE_CHARDEV 0x2000 +#define CPIO_MODE_FILETYPE_FIFO 0x1000 +#define CPIO_MODE_SUID 0x0800 +#define CPIO_MODE_SGID 0x0400 +#define CPIO_MODE_STICKY 0x0200 + +typedef struct { + size_t filesize; + char *name; + uint32_t mode; + uint32_t check; +} cpio_file_t; + +typedef enum { + CPIO_RET_MORE = 0, + CPIO_RET_DONE, + CPIO_RET_ERR +} cpio_ret_t; + +typedef struct cpio_handle_data_t cpio_handle_data_t; +typedef cpio_handle_data_t *cpio_handle_t; + +typedef enum { + CPIO_RSN_FILE_ALL = 0, + CPIO_RSN_FILE_INITIAL, + CPIO_RSN_FILE_MORE, + CPIO_RSN_FILE_END +} cpio_callback_reason_t; + + +/** + * Callback for cpio file data. + * + * This callback will be called by the library to indicate data for a file is available. + * + * For files in the cpio archive that fit entirely in the internal buffer, or when no internal + * buffer is available, are entirely contained in the buffer fed to cpio_feed(), this callback + * is only called once, with reason=CPIO_RNS_FILE_ALL. fileinfo will contain the information + * for that specific file (name, size, ...), buff_offset will be 0, buff_len is the file + * size and buff contains all the information for the file. + * + * For files that do not fit in the buffer, this callback will be called multiple times. + * The initial time with reason=CPIO_RSN_FILE_INITIAL, when more data is available with + * CPIO_RSN_FILE_MORE and finally with CPIO_RSN_FILE_END. For these calls, fileinfo + * will again contain file information. buff will be the information contained in the + * file at offset buff_offset, and the lenght of this buffer will be in buff_len. + * + * The library guarantees to feed all file data to the callback consequitively, so + * within the same file, the buff_offset from a call will always be (buff_offset+buff_len) + * from the call before that. If cpio_start is + * + * The library also guarantees every file in the cpio archive will either generate a single + * callback call with CPIO_RSN_ALL, or multiple with in sequence CPIO_RSN_FILE_INITIAL, 0 or + * more CPIO_RSN_FILE_MORE and finally a CPIO_RSN_FILE_END. + * + * When a non-zero buffer size is passed to cpio_start, the library guarantees that all callback + * calls with a reason of CPIO_RSN_FILE_INITIAL and CPIO_RSN_FILE_MORE will have a buffer + * filled with exactly this amount of bytes. + * + */ +typedef void (*cpio_callback_t)(cpio_callback_reason_t reason, cpio_file_t *fileinfo, size_t buff_offset, size_t buff_len, char *buff, void *arg); + + +/** + * @brief Initialize a cpio handle. + * + * Call this to start parsing a cpio archive. You can set the callback that handles the + * files/data here. + * + * @param callback The callback that will handle the data of the files inside the cpio archive + * + * @param cbarg User-supplied argument. The callback will be called with this as an argument. + * + * @param buflen Length of internal buffer used. + * If this is zero, the callback will be called with data that lives in the data buffer + * supplied to the cpio library by whomever called cpio_feed(). Because this library has + * no power over that buffer, the callback can be passed as little as 1 and as many as + * INT_MAX bytes at a time. + * If this is non-zero, the library will allocate an internal buffer of this size. All + * cpio_feed()-calls will be rebuffered, and the callback is guaranteed to only be called + * with this many bytes in the buffer, given there's enough data in the file to fill it. + * + * @param memchunk Chunk of memory to allocate everything (handle, I/O buffer, filename buffer) in. Minimum size + * (estimate) is 160+buflen+sizeof(largest filename/path). + * @param memchunklen Size of the mem chunk + * + * @return + * - Success: A pointer to a cpio handle + * - Error: NULL + * + */ +cpio_handle_t cpio_start(cpio_callback_t callback, void *cbarg, size_t buflen, void *memchunk, int memchunklen); + +/** + * @brief Feed data from a cpio archive into the library + * + * This routine is used to feed consecutive data of the cpio archive into the library. While processing, + * the library can call the callback function one or more times if needed. + * + * @param cpio Handle obtained by calling cpio_start() + * + * @param buffer Pointer to buffer containing cpio archive data + * + * @param len Length of the buffer, in bytes + * + * @return + * - CPIO_RET_MORE: CPIO archive isn't done yet, please feed more data. + * - CPIO_RET_DONE: CPUI archive is finished. + * - CPIO_RET_ERR: Invalid CPIO archive data; decoding aborted. + * + */ +cpio_ret_t cpio_feed(cpio_handle_t cpio, char *buffer, int len); + +/** + * @brief Indicate there is no more cpio data to be fed into the archive + * + * This call is to be called when the source data is exhausted. Normally, the library can find the end of the + * cpio archive by looking for the end marker, + * + * @param timer_conf Pointer of LEDC timer configure struct + * + * + * @return + * - CPIO_RET_DONE on success + * - CPIO_RET_ERR when cpio archive is invalid + * + */ +cpio_ret_t cpio_done(cpio_handle_t cpio); + + +/** + * @brief Free the memory allocated for a cpio handle. + * + * @param cpio Handle obtained by calling cpio_start() + * + * @return + * - CPIO_RET_DONE on success + * + */ +cpio_ret_t cpio_destroy(cpio_handle_t cpio); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_cdc.h b/components/esp_rom/include/esp32s2/rom/usb/usb_cdc.h new file mode 100644 index 0000000000..c241bcfe06 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_cdc.h @@ -0,0 +1,174 @@ +/* usb_cdc.h - USB CDC-ACM and CDC-ECM public header */ + +/* + * Copyright (c) 2017 PHYTEC Messtechnik GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +/** + * @file + * @brief USB Communications Device Class (CDC) public header + * + * Header follows the Class Definitions for + * Communications Devices Specification (CDC120-20101103-track.pdf), + * PSTN Devices Specification (PSTN120.pdf) and + * Ethernet Control Model Devices Specification (ECM120.pdf). + * Header is limited to ACM and ECM Subclasses. + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** CDC Specification release number in BCD format */ +#define CDC_SRN_1_20 0x0120 + +/** Communications Class Subclass Codes */ +#define ACM_SUBCLASS 0x02 +#define ECM_SUBCLASS 0x06 +#define EEM_SUBCLASS 0x0c + +/** Communications Class Protocol Codes */ +#define AT_CMD_V250_PROTOCOL 0x01 +#define EEM_PROTOCOL 0x07 + +/** + * @brief Data Class Interface Codes + * @note CDC120-20101103-track.pdf, 4.5, Table 6 + */ +#define DATA_INTERFACE_CLASS 0x0A + +/** + * @brief Values for the bDescriptorType Field + * @note CDC120-20101103-track.pdf, 5.2.3, Table 12 + */ +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +/** + * @brief bDescriptor SubType for Communications + * Class Functional Descriptors + * @note CDC120-20101103-track.pdf, 5.2.3, Table 13 + */ +#define HEADER_FUNC_DESC 0x00 +#define CALL_MANAGEMENT_FUNC_DESC 0x01 +#define ACM_FUNC_DESC 0x02 +#define UNION_FUNC_DESC 0x06 +#define ETHERNET_FUNC_DESC 0x0F + +/** + * @brief PSTN Subclass Specific Requests + * for ACM devices + * @note PSTN120.pdf, 6.3, Table 13 + */ +#define CDC_SEND_ENC_CMD 0x00 +#define CDC_GET_ENC_RSP 0x01 +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 + +/** Control Signal Bitmap Values for SetControlLineState */ +#define SET_CONTROL_LINE_STATE_RTS 0x02 +#define SET_CONTROL_LINE_STATE_DTR 0x01 + +/** UART State Bitmap Values */ +#define SERIAL_STATE_OVERRUN 0x40 +#define SERIAL_STATE_PARITY 0x20 +#define SERIAL_STATE_FRAMING 0x10 +#define SERIAL_STATE_RING 0x08 +#define SERIAL_STATE_BREAK 0x04 +#define SERIAL_STATE_TX_CARRIER 0x02 +#define SERIAL_STATE_RX_CARRIER 0x01 + +/** + * @brief Class-Specific Request Codes for Ethernet subclass + * @note ECM120.pdf, 6.2, Table 6 + */ +#define SET_ETHERNET_MULTICAST_FILTERS 0x40 +#define SET_ETHERNET_PM_FILTER 0x41 +#define GET_ETHERNET_PM_FILTER 0x42 +#define SET_ETHERNET_PACKET_FILTER 0x43 +#define GET_ETHERNET_STATISTIC 0x44 + +/** Ethernet Packet Filter Bitmap */ +#define PACKET_TYPE_MULTICAST 0x10 +#define PACKET_TYPE_BROADCAST 0x08 +#define PACKET_TYPE_DIRECTED 0x04 +#define PACKET_TYPE_ALL_MULTICAST 0x02 +#define PACKET_TYPE_PROMISCUOUS 0x01 + +/** Header Functional Descriptor */ +struct cdc_header_descriptor { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint16_t bcdCDC; +} __packed; + +/** Union Interface Functional Descriptor */ +struct cdc_union_descriptor { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bControlInterface; + uint8_t bSubordinateInterface0; +} __packed; + +/** Call Management Functional Descriptor */ +struct cdc_cm_descriptor { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; + uint8_t bDataInterface; +} __packed; + +/** Abstract Control Management Functional Descriptor */ +struct cdc_acm_descriptor { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t bmCapabilities; +} __packed; + + +/** Data structure for GET_LINE_CODING / SET_LINE_CODING class requests */ +struct cdc_acm_line_coding { + uint32_t dwDTERate; + uint8_t bCharFormat; + uint8_t bParityType; + uint8_t bDataBits; +} __packed; + +/** Data structure for the notification about SerialState */ +struct cdc_acm_notification { + uint8_t bmRequestType; + uint8_t bNotificationType; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint16_t data; +} __packed; + +/** Ethernet Networking Functional Descriptor */ +struct cdc_ecm_descriptor { + uint8_t bFunctionLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubtype; + uint8_t iMACAddress; + uint32_t bmEthernetStatistics; + uint16_t wMaxSegmentSize; + uint16_t wNumberMCFilters; + uint8_t bNumberPowerFilters; +} __packed; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_common.h b/components/esp_rom/include/esp32s2/rom/usb/usb_common.h new file mode 100644 index 0000000000..1fc65d9eab --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_common.h @@ -0,0 +1,244 @@ +/*************************************************************************** + * + * + * Copyright(c) 2015,2016 Intel Corporation. + * Copyright(c) 2017 PHYTEC Messtechnik GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +/** + * @file + * @brief useful constants and macros for the USB application + * + * This file contains useful constants and macros for the USB applications. + */ + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BCD(x) ((((x) / 10) << 4) | ((x) / 10)) + +/* Descriptor size in bytes */ +#define USB_DEVICE_DESC_SIZE 18 +#define USB_CONFIGURATION_DESC_SIZE 9 +#define USB_INTERFACE_DESC_SIZE 9 +#define USB_ENDPOINT_DESC_SIZE 7 +#define USB_STRING_DESC_SIZE 4 +#define USB_HID_DESC_SIZE 9 +#define USB_DFU_DESC_SIZE 9 +#define USB_DEVICE_QUAL_DESC_SIZE 10 +#define USB_INTERFACE_ASSOC_DESC_SIZE 8 + +/* Descriptor type */ +#define USB_DEVICE_DESC 0x01 +#define USB_CONFIGURATION_DESC 0x02 +#define USB_STRING_DESC 0x03 +#define USB_INTERFACE_DESC 0x04 +#define USB_ENDPOINT_DESC 0x05 +#define USB_DEVICE_QUAL_DESC 0x06 +#define USB_INTERFACE_ASSOC_DESC 0x0B +#define USB_DEVICE_CAPABILITY_DESC 0x10 +#define USB_HID_DESC 0x21 +#define USB_HID_REPORT_DESC 0x22 +#define USB_DFU_FUNCTIONAL_DESC 0x21 +#define USB_ASSOCIATION_DESC 0x0B +#define USB_BINARY_OBJECT_STORE_DESC 0x0F + +/* Useful define */ +#define USB_1_1 0x0110 +#define USB_2_0 0x0200 +/* Set USB version to 2.1 so that the host will request the BOS descriptor */ +#define USB_2_1 0x0210 + +#define BCDDEVICE_RELNUM (BCD(KERNEL_VERSION_MAJOR) << 8 | \ + BCD(KERNEL_VERSION_MINOR)) + +/* 100mA max power, per 2mA units */ +/* USB 1.1 spec indicates 100mA(max) per unit load, up to 5 loads */ +#define MAX_LOW_POWER 0x32 +#define MAX_HIGH_POWER 0xFA + +/* bmAttributes: + * D7:Reserved, always 1, + * D6:Self-Powered -> 1, + * D5:Remote Wakeup -> 0, + * D4...0:Reserved -> 0 + */ +#define USB_CONFIGURATION_ATTRIBUTES 0xC0 + +/* Classes */ +#define COMMUNICATION_DEVICE_CLASS 0x02 +#define COMMUNICATION_DEVICE_CLASS_DATA 0x0A +#define HID_CLASS 0x03 +#define MASS_STORAGE_CLASS 0x08 +#define WIRELESS_DEVICE_CLASS 0xE0 +#define MISC_CLASS 0xEF +#define CUSTOM_CLASS 0xFF +#define DFU_DEVICE_CLASS 0xFE + +/* Sub-classes */ +#define CDC_NCM_SUBCLASS 0x0d +#define BOOT_INTERFACE_SUBCLASS 0x01 +#define SCSI_TRANSPARENT_SUBCLASS 0x06 +#define DFU_INTERFACE_SUBCLASS 0x01 +#define RF_SUBCLASS 0x01 +#define CUSTOM_SUBCLASS 0xFF +#define COMMON_SUBCLASS 0x02 +/* Misc subclasses */ +#define MISC_RNDIS_SUBCLASS 0x04 +#define CDC_ABSTRACT_CONTROL_MODEL 0x02 + +/* Protocols */ +#define V25TER_PROTOCOL 0x01 +#define MOUSE_PROTOCOL 0x02 +#define BULK_ONLY_PROTOCOL 0x50 +#define DFU_RUNTIME_PROTOCOL 0x01 +#define DFU_MODE_PROTOCOL 0x02 +#define BLUETOOTH_PROTOCOL 0x01 +/* CDC ACM protocols */ +#define ACM_VENDOR_PROTOCOL 0xFF +/* Misc protocols */ +#define MISC_ETHERNET_PROTOCOL 0x01 +#define IAD_PROTOCOL 0x01 + +/** Standard Device Descriptor */ +struct usb_device_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} __packed; + +/** Unicode (UTF16LE) String Descriptor */ +struct usb_string_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bString; +} __packed; + +/** Association Descriptor */ +struct usb_association_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} __packed; + +/** Standard Configuration Descriptor */ +struct usb_cfg_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} __packed; + +/** Standard Interface Descriptor */ +struct usb_if_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} __packed; + +/** Standard Endpoint Descriptor */ +struct usb_ep_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} __packed; + +struct string_descriptor_zero { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wBcdLang[]; +} __packed; + +struct string_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bString[]; +} __packed; + +#define ROM_MAX_CFG_DESC_CNT 1 + +struct rom_usb_descriptors { + const struct usb_device_descriptor *device_descr; + const void *config_descr[ROM_MAX_CFG_DESC_CNT]; + int string_count; // including string_descriptor_zero + const struct string_descriptor_zero *string0_descr; + const struct string_descriptor *string_descrs[]; +}; + +/* Descriptors defined in the ROM */ +extern struct usb_device_descriptor general_device_descr; +extern const void* acm_config_descr; +extern const void* dfu_config_descr; +extern const struct string_descriptor str_manu_descr; +extern const struct string_descriptor str_prod_descr; +extern const struct string_descriptor_zero string0_descr; +extern const struct rom_usb_descriptors acm_usb_descriptors; +extern const struct rom_usb_descriptors dfu_usb_descriptors; +extern const struct rom_usb_descriptors *rom_usb_curr_desc; + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_dc.h b/components/esp_rom/include/esp32s2/rom/usb/usb_dc.h new file mode 100644 index 0000000000..f20e897c71 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_dc.h @@ -0,0 +1,392 @@ +/* usb_dc.h - USB device controller driver interface */ + +/* + * Copyright (c) 2016 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USB device controller APIs + * + * This file contains the USB device controller APIs. All device controller + * drivers should implement the APIs described in this file. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * USB endpoint direction and number. + */ + +#define USB_EP_DIR_MASK 0x80 +#define USB_EP_DIR_IN 0x80 +#define USB_EP_DIR_OUT 0x00 + +/** + * USB Driver Status Codes + */ +enum usb_dc_status_code { + USB_DC_ERROR, /* USB error reported by the controller */ + USB_DC_RESET, /* USB reset */ + /* USB connection established, hardware enumeration is completed */ + USB_DC_CONNECTED, + USB_DC_CONFIGURED, /* USB configuration done */ + USB_DC_DISCONNECTED, /* USB connection lost */ + USB_DC_SUSPEND, /* USB connection suspended by the HOST */ + USB_DC_RESUME, /* USB connection resumed by the HOST */ + USB_DC_INTERFACE, /* USB interface selected */ + USB_DC_SET_HALT, /* Set Feature ENDPOINT_HALT received */ + USB_DC_CLEAR_HALT, /* Clear Feature ENDPOINT_HALT received */ + USB_DC_UNKNOWN /* Initial USB connection status */ +}; + +/** + * USB Endpoint Callback Status Codes + */ +enum usb_dc_ep_cb_status_code { + USB_DC_EP_SETUP, /* SETUP received */ + /* Out transaction on this EP, data is available for read */ + USB_DC_EP_DATA_OUT, + USB_DC_EP_DATA_IN, /* In transaction done on this EP */ +}; + +/** + * USB Endpoint type + */ +enum usb_dc_ep_type { + USB_DC_EP_CONTROL = 0, /* Control type endpoint */ + USB_DC_EP_ISOCHRONOUS, /* Isochronous type endpoint */ + USB_DC_EP_BULK, /* Bulk type endpoint */ + USB_DC_EP_INTERRUPT /* Interrupt type endpoint */ +}; + +/** + * USB Endpoint Configuration. + */ +struct usb_dc_ep_cfg_data { + /** The number associated with the EP in the device + * configuration structure + * IN EP = 0x80 | \ + * OUT EP = 0x00 | \ + */ + uint8_t ep_addr; + uint16_t ep_mps; /** Endpoint max packet size */ + enum usb_dc_ep_type ep_type; /** Endpoint type */ +}; + +/** + * Callback function signature for the USB Endpoint status + */ +typedef void (*usb_dc_ep_callback)(uint8_t ep, + enum usb_dc_ep_cb_status_code cb_status); + +/** + * Callback function signature for the device + */ +typedef void (*usb_dc_status_callback)(enum usb_dc_status_code cb_status, + uint8_t *param); + +/** + * @brief attach USB for device connection + * + * Function to attach USB for device connection. Upon success, the USB PLL + * is enabled, and the USB device is now capable of transmitting and receiving + * on the USB bus and of generating interrupts. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_attach(void); + +/** + * @brief detach the USB device + * + * Function to detach the USB device. Upon success, the USB hardware PLL + * is powered down and USB communication is disabled. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_detach(void); + +/** + * @brief reset the USB device + * + * This function returns the USB device and firmware back to it's initial state. + * N.B. the USB PLL is handled by the usb_detach function + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_reset(void); + +/** + * @brief set USB device address + * + * @param[in] addr device address + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_set_address(const uint8_t addr); + +/** + * @brief set USB device controller status callback + * + * Function to set USB device controller status callback. The registered + * callback is used to report changes in the status of the device controller. + * + * @param[in] cb callback function + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_set_status_callback(const usb_dc_status_callback cb); + +/** + * @brief check endpoint capabilities + * + * Function to check capabilities of an endpoint. usb_dc_ep_cfg_data structure + * provides the endpoint configuration parameters: endpoint address, + * endpoint maximum packet size and endpoint type. + * The driver should check endpoint capabilities and return 0 if the + * endpoint configuration is possible. + * + * @param[in] cfg Endpoint config + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data *const cfg); + +/** + * @brief configure endpoint + * + * Function to configure an endpoint. usb_dc_ep_cfg_data structure provides + * the endpoint configuration parameters: endpoint address, endpoint maximum + * packet size and endpoint type. + * + * @param[in] cfg Endpoint config + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const cfg); + +/** + * @brief set stall condition for the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_set_stall(const uint8_t ep); + +/** + * @brief clear stall condition for the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_clear_stall(const uint8_t ep); + +/** + * @brief check if selected endpoint is stalled + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[out] stalled Endpoint stall status + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled); + +/** + * @brief halt the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_halt(const uint8_t ep); + +/** + * @brief enable the selected endpoint + * + * Function to enable the selected endpoint. Upon success interrupts are + * enabled for the corresponding endpoint and the endpoint is ready for + * transmitting/receiving data. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_enable(const uint8_t ep); + +/** + * @brief disable the selected endpoint + * + * Function to disable the selected endpoint. Upon success interrupts are + * disabled for the corresponding endpoint and the endpoint is no longer able + * for transmitting/receiving data. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_disable(const uint8_t ep); + +/** + * @brief flush the selected endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_flush(const uint8_t ep); + +/** + * @brief write data to the specified endpoint + * + * This function is called to write data to the specified endpoint. The supplied + * usb_ep_callback function will be called when data is transmitted out. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data pointer to data to write + * @param[in] data_len length of data requested to write. This may + * be zero for a zero length status packet. + * @param[out] ret_bytes bytes scheduled for transmission. This value + * may be NULL if the application expects all + * bytes to be written + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data, + const uint32_t data_len, uint32_t *const ret_bytes); + + + +/** + * @brief Indicate if the write to an IN endpoint (using usb_dc_ep_write) would block + * to wait until the endpoint has enoug space + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 when writable, 0 when not, negative errno code on fail. + */ +int usb_dc_ep_write_would_block(const uint8_t ep); + + +/** + * @brief read data from the specified endpoint + * + * This function is called by the Endpoint handler function, after an OUT + * interrupt has been received for that EP. The application must only call this + * function through the supplied usb_ep_callback function. This function clears + * the ENDPOINT NAK, if all data in the endpoint FIFO has been read, + * so as to accept more data from host. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data pointer to data buffer to write to + * @param[in] max_data_len max length of data to read + * @param[out] read_bytes Number of bytes read. If data is NULL and + * max_data_len is 0 the number of bytes + * available for read should be returned. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, + const uint32_t max_data_len, uint32_t *const read_bytes); + +/** + * @brief set callback function for the specified endpoint + * + * Function to set callback function for notification of data received and + * available to application or transmit done on the selected endpoint, + * NULL if callback not required by application code. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] cb callback function + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb); + +/** + * @brief read data from the specified endpoint + * + * This is similar to usb_dc_ep_read, the difference being that, it doesn't + * clear the endpoint NAKs so that the consumer is not bogged down by further + * upcalls till he is done with the processing of the data. The caller should + * reactivate ep by invoking usb_dc_ep_read_continue() do so. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data pointer to data buffer to write to + * @param[in] max_data_len max length of data to read + * @param[out] read_bytes Number of bytes read. If data is NULL and + * max_data_len is 0 the number of bytes + * available for read should be returned. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len, + uint32_t *read_bytes); + + +/** + * @brief Continue reading data from the endpoint + * + * Clear the endpoint NAK and enable the endpoint to accept more data + * from the host. Usually called after usb_dc_ep_read_wait() when the consumer + * is fine to accept more data. Thus these calls together acts as flow control + * mechanism. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_dc_ep_read_continue(uint8_t ep); + +/** + * @brief Get endpoint max packet size + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return enpoint max packet size (mps) + */ +int usb_dc_ep_mps(uint8_t ep); + + + +//Hack - fake interrupts by pollinfg +void usb_dc_check_poll_for_interrupts(void); + + +//Prepare for USB persist. You should reboot after this. +int usb_dc_prepare_persist(void); + + +void usb_dw_isr_handler(void); + + +int usb_dc_ep_write_would_block(const uint8_t ep); + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_descriptor.h b/components/esp_rom/include/esp32s2/rom/usb/usb_descriptor.h new file mode 100644 index 0000000000..942a1968cc --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_descriptor.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define USB_DESCRIPTOR_TYPE_ACM 0 +#define USB_DESCRIPTOR_TYPE_DFU 1 + +void usb_set_current_descriptor(int descriptor_type); + +bool usb_get_descriptor(uint16_t type_index, uint16_t lang_id, + int32_t *len, uint8_t **data); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_device.h b/components/esp_rom/include/esp32s2/rom/usb/usb_device.h new file mode 100644 index 0000000000..51801b5d57 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_device.h @@ -0,0 +1,402 @@ +/* + * LPCUSB, an USB device driver for LPC microcontrollers + * Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl) + * Copyright (c) 2016 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * @brief USB device core layer APIs and structures + * + * This file contains the USB device core layer APIs and structures. + */ + +#pragma once + +#include +#include +#include "usb_dc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************* + * USB configuration + **************************************************************************/ + +#define MAX_PACKET_SIZE0 64 /**< maximum packet size for EP 0 */ +//Note: for FS this should be 8, 16, 32, 64 bytes. HS can go up to 512. + +/************************************************************************* + * USB application interface + **************************************************************************/ + +/** setup packet definitions */ +struct usb_setup_packet { + uint8_t bmRequestType; /**< characteristics of the specific request */ + uint8_t bRequest; /**< specific request */ + uint16_t wValue; /**< request specific parameter */ + uint16_t wIndex; /**< request specific parameter */ + uint16_t wLength; /**< length of data transferred in data phase */ +} __packed; + + +_Static_assert(sizeof(struct usb_setup_packet) == 8, "USB setup packet struct size error"); + +/** + * Callback function signature for the device + */ +typedef void (*usb_status_callback)(enum usb_dc_status_code status_code, + uint8_t *param); + +/** + * Callback function signature for the USB Endpoint status + */ +typedef void (*usb_ep_callback)(uint8_t ep, + enum usb_dc_ep_cb_status_code cb_status); + +/** + * Function which handles Class specific requests corresponding to an + * interface number specified in the device descriptor table + */ +typedef int (*usb_request_handler) (struct usb_setup_packet *detup, + int32_t *transfer_len, uint8_t **payload_data); + +/** + * Function for interface runtime configuration + */ +typedef void (*usb_interface_config)(uint8_t bInterfaceNumber); + +/* + * USB Endpoint Configuration + */ +struct usb_ep_cfg_data { + /** + * Callback function for notification of data received and + * available to application or transmit done, NULL if callback + * not required by application code + */ + usb_ep_callback ep_cb; + /** + * The number associated with the EP in the device configuration + * structure + * IN EP = 0x80 | \ + * OUT EP = 0x00 | \ + */ + uint8_t ep_addr; +}; + +/** + * USB Interface Configuration + */ +struct usb_interface_cfg_data { + /** Handler for USB Class specific Control (EP 0) communications */ + usb_request_handler class_handler; + /** Handler for USB Vendor specific commands */ + usb_request_handler vendor_handler; + /** + * The custom request handler gets a first chance at handling + * the request before it is handed over to the 'chapter 9' request + * handler + */ + usb_request_handler custom_handler; + /** + * This data area, allocated by the application, is used to store + * Class specific command data and must be large enough to store the + * largest payload associated with the largest supported Class' + * command set. This data area may be used for USB IN or OUT + * communications + */ + uint8_t *payload_data; + /** + * This data area, allocated by the application, is used to store + * Vendor specific payload + */ + uint8_t *vendor_data; +}; + +/* + * @brief USB device configuration + * + * The Application instantiates this with given parameters added + * using the "usb_set_config" function. Once this function is called + * changes to this structure will result in undefined behaviour. This structure + * may only be updated after calls to usb_deconfig + */ +struct usb_cfg_data { + /** + * USB device description, see + * http://www.beyondlogic.org/usbnutshell/usb5.shtml#DeviceDescriptors + */ + const uint8_t *usb_device_description; + /** Pointer to interface descriptor */ + const void *interface_descriptor; + /** Function for interface runtime configuration */ + usb_interface_config interface_config; + /** Callback to be notified on USB connection status change */ + usb_status_callback cb_usb_status; + /** USB interface (Class) handler and storage space */ + struct usb_interface_cfg_data interface; + /** Number of individual endpoints in the device configuration */ + uint8_t num_endpoints; + /** + * Pointer to an array of endpoint structs of length equal to the + * number of EP associated with the device description, + * not including control endpoints + */ + struct usb_ep_cfg_data *endpoint; +}; + +/* + * @brief configure USB controller + * + * Function to configure USB controller. + * Configuration parameters must be valid or an error is returned + * + * @param[in] config Pointer to configuration structure + * + * @return 0 on success, negative errno code on fail + */ +int usb_set_config(struct usb_cfg_data *config); + +/* + * @brief return the USB device to it's initial state + * + * @return 0 on success, negative errno code on fail + */ +int usb_deconfig(void); + +/* + * @brief enable USB for host/device connection + * + * Function to enable USB for host/device connection. + * Upon success, the USB module is no longer clock gated in hardware, + * it is now capable of transmitting and receiving on the USB bus and + * of generating interrupts. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_enable(struct usb_cfg_data *config); + +/* + * @brief disable the USB device. + * + * Function to disable the USB device. + * Upon success, the specified USB interface is clock gated in hardware, + * it is no longer capable of generating interrupts. + * + * @return 0 on success, negative errno code on fail + */ +int usb_disable(void); + +/* + * @brief Check if a write to an in ep would block until there is enough space + * in the fifo + * + * @param[in] ep Endpoint address corresponding to the one listed in the + * device configuration table + * + * @return 0 if free to write, 1 if a write would block, negative errno code on fail + */ +int usb_write_would_block(uint8_t ep); + +/* + * @brief write data to the specified endpoint + * + * Function to write data to the specified endpoint. The supplied + * usb_ep_callback will be called when transmission is done. + * + * @param[in] ep Endpoint address corresponding to the one listed in the + * device configuration table + * @param[in] data Pointer to data to write + * @param[in] data_len Length of data requested to write. This may be zero for + * a zero length status packet. + * @param[out] bytes_ret Bytes written to the EP FIFO. This value may be NULL if + * the application expects all bytes to be written + * + * @return 0 on success, negative errno code on fail + */ +int usb_write(uint8_t ep, const uint8_t *data, uint32_t data_len, + uint32_t *bytes_ret); + +/* + * @brief read data from the specified endpoint + * + * This function is called by the Endpoint handler function, after an + * OUT interrupt has been received for that EP. The application must + * only call this function through the supplied usb_ep_callback function. + * + * @param[in] ep Endpoint address corresponding to the one listed in + * the device configuration table + * @param[in] data Pointer to data buffer to write to + * @param[in] max_data_len Max length of data to read + * @param[out] ret_bytes Number of bytes read. If data is NULL and + * max_data_len is 0 the number of bytes available + * for read is returned. + * + * @return 0 on success, negative errno code on fail + */ +int usb_read(uint8_t ep, uint8_t *data, uint32_t max_data_len, + uint32_t *ret_bytes); + +/* + * @brief set STALL condition on the specified endpoint + * + * This function is called by USB device class handler code to set stall + * conditionin on endpoint. + * + * @param[in] ep Endpoint address corresponding to the one listed in + * the device configuration table + * + * @return 0 on success, negative errno code on fail + */ +int usb_ep_set_stall(uint8_t ep); + + +/* + * @brief clears STALL condition on the specified endpoint + * + * This function is called by USB device class handler code to clear stall + * conditionin on endpoint. + * + * @param[in] ep Endpoint address corresponding to the one listed in + * the device configuration table + * + * @return 0 on success, negative errno code on fail + */ +int usb_ep_clear_stall(uint8_t ep); + +/** + * @brief read data from the specified endpoint + * + * This is similar to usb_ep_read, the difference being that, it doesn't + * clear the endpoint NAKs so that the consumer is not bogged down by further + * upcalls till he is done with the processing of the data. The caller should + * reactivate ep by invoking usb_ep_read_continue() do so. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data pointer to data buffer to write to + * @param[in] max_data_len max length of data to read + * @param[out] read_bytes Number of bytes read. If data is NULL and + * max_data_len is 0 the number of bytes + * available for read should be returned. + * + * @return 0 on success, negative errno code on fail. + */ +int usb_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len, + uint32_t *read_bytes); + + +/** + * @brief Continue reading data from the endpoint + * + * Clear the endpoint NAK and enable the endpoint to accept more data + * from the host. Usually called after usb_ep_read_wait() when the consumer + * is fine to accept more data. Thus these calls together acts as flow control + * mechanism. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +int usb_ep_read_continue(uint8_t ep); + +/** + * Callback function signature for transfer completion. + */ +typedef void (*usb_transfer_callback)(uint8_t ep, int tsize, void *priv); + +/* USB transfer flags */ +#define USB_TRANS_READ BIT(0) /** Read transfer flag */ +#define USB_TRANS_WRITE BIT(1) /** Write transfer flag */ +#define USB_TRANS_NO_ZLP BIT(2) /** No zero-length packet flag */ + +/** + * @brief Transfer management endpoint callback + * + * If a USB class driver wants to use high-level transfer functions, driver + * needs to register this callback as usb endpoint callback. + */ +void usb_transfer_ep_callback(uint8_t ep, enum usb_dc_ep_cb_status_code); + +/** + * @brief Start a transfer + * + * Start a usb transfer to/from the data buffer. This function is asynchronous + * and can be executed in IRQ context. The provided callback will be called + * on transfer completion (or error) in thread context. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data Pointer to data buffer to write-to/read-from + * @param[in] dlen Size of data buffer + * @param[in] flags Transfer flags (USB_TRANS_READ, USB_TRANS_WRITE...) + * @param[in] cb Function called on transfer completion/failure + * @param[in] priv Data passed back to the transfer completion callback + * + * @return 0 on success, negative errno code on fail. + */ +int usb_transfer(uint8_t ep, uint8_t *data, size_t dlen, unsigned int flags, + usb_transfer_callback cb, void *priv); + +/** + * @brief Start a transfer and block-wait for completion + * + * Synchronous version of usb_transfer, wait for transfer completion before + * returning. + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * @param[in] data Pointer to data buffer to write-to/read-from + * @param[in] dlen Size of data buffer + * @param[in] flags Transfer flags + + * + * @return number of bytes transferred on success, negative errno code on fail. + */ +int usb_transfer_sync(uint8_t ep, uint8_t *data, size_t dlen, unsigned int flags); + +/** + * @brief Cancel any ongoing transfer on the specified endpoint + * + * @param[in] ep Endpoint address corresponding to the one + * listed in the device configuration table + * + * @return 0 on success, negative errno code on fail. + */ +void usb_cancel_transfer(uint8_t ep); + + +void usb_dev_resume(int configuration); +int usb_dev_get_configuration(void); + + +#ifdef __cplusplus +} +#endif + diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_dfu.h b/components/esp_rom/include/esp32s2/rom/usb/usb_dfu.h new file mode 100644 index 0000000000..dec7ea93a3 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_dfu.h @@ -0,0 +1,147 @@ +/*************************************************************************** + * + * Copyright(c) 2015,2016 Intel Corporation. + * Copyright(c) 2017 PHYTEC Messtechnik GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************/ + +/** + * @file + * @brief USB Device Firmware Upgrade (DFU) public header + * + * Header follows the Device Class Specification for + * Device Firmware Upgrade Version 1.1 + */ + +#pragma once + +#include +#include +#include "usb_device.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** DFU Class Subclass */ +#define DFU_SUBCLASS 0x01 + +/** DFU Class runtime Protocol */ +#define DFU_RT_PROTOCOL 0x01 + +/** DFU Class DFU mode Protocol */ +#define DFU_MODE_PROTOCOL 0x02 + +/** + * @brief DFU Class Specific Requests + */ +#define DFU_DETACH 0x00 +#define DFU_DNLOAD 0x01 +#define DFU_UPLOAD 0x02 +#define DFU_GETSTATUS 0x03 +#define DFU_CLRSTATUS 0x04 +#define DFU_GETSTATE 0x05 +#define DFU_ABORT 0x06 + +/** DFU FUNCTIONAL descriptor type */ +#define DFU_FUNC_DESC 0x21 + +/** DFU attributes DFU Functional Descriptor */ +#define DFU_ATTR_WILL_DETACH 0x08 +#define DFU_ATTR_MANIFESTATION_TOLERANT 0x04 +#define DFU_ATTR_CAN_UPLOAD 0x02 +#define DFU_ATTR_CAN_DNLOAD 0x01 + +/** DFU Specification release */ +#define DFU_VERSION 0x0110 + +/** Run-Time Functional Descriptor */ +struct dfu_runtime_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bmAttributes; + uint16_t wDetachTimeOut; + uint16_t wTransferSize; + uint16_t bcdDFUVersion; +} __packed; + +/** bStatus values for the DFU_GETSTATUS response */ +enum dfu_status { + statusOK, + errTARGET, + errFILE, + errWRITE, + errERASE, + errCHECK_ERASED, + errPROG, + errVERIFY, + errADDRESS, + errNOTDONE, + errFIRMWARE, + errVENDOR, + errUSB, + errPOR, + errUNKNOWN, + errSTALLEDPKT +}; + +/** bState values for the DFU_GETSTATUS response */ +enum dfu_state { + appIDLE, + appDETACH, + dfuIDLE, + dfuDNLOAD_SYNC, + dfuDNBUSY, + dfuDNLOAD_IDLE, + dfuMANIFEST_SYNC, + dfuMANIFEST, + dfuMANIFEST_WAIT_RST, + dfuUPLOAD_IDLE, + dfuERROR, +}; + +/* + These callbacks are made public so the ACM driver can call them to handle the switch to DFU. +*/ + +int dfu_class_handle_req(struct usb_setup_packet *pSetup, + int32_t *data_len, uint8_t **data); +void dfu_status_cb(enum usb_dc_status_code status, uint8_t *param); +int usb_dfu_init(void); +int dfu_custom_handle_req(struct usb_setup_packet *pSetup, + int32_t *data_len, uint8_t **data); + + +typedef void(*usb_dfu_detach_routine_t)(int delay); +void usb_dfu_set_detach_cb(usb_dfu_detach_routine_t cb); + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_os_glue.h b/components/esp_rom/include/esp32s2/rom/usb/usb_os_glue.h new file mode 100644 index 0000000000..74d9b2a778 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_os_glue.h @@ -0,0 +1,40 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void(*usb_osglue_intdisena_routine_t)(void); +typedef int(*usb_osglue_wait_routine_t)(int delay_us); + +typedef struct { + /* Disable USB interrupt */ + usb_osglue_intdisena_routine_t int_dis_proc; + /* Enable USB interrupt */ + usb_osglue_intdisena_routine_t int_ena_proc; + /* Wait for a set amount of uS. Return the amount actually waited. If delay_us is 0, just yield.*/ + usb_osglue_wait_routine_t wait_proc; +} usb_osglue_data_t; + +extern usb_osglue_data_t rom_usb_osglue; + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_rom/include/esp32s2/rom/usb/usb_persist.h b/components/esp_rom/include/esp32s2/rom/usb/usb_persist.h new file mode 100644 index 0000000000..bcf11b7c48 --- /dev/null +++ b/components/esp_rom/include/esp32s2/rom/usb/usb_persist.h @@ -0,0 +1,50 @@ +// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// USB persistence flags. + +//This bit indicates persistence has been enabled, that is, the USB initialization routines should not +//reset the USB device as the device still is initialized and the host detected it with the same cdcacm/dfu +//descriptor as the ROM uses; we can just re-initialize the software side and have at 'er. +#define USBDC_PERSIST_ENA (1<<31) + +//This bit indicates to the ROM that we rebooted because of a request to go into DFU mode; the ROM should +//honour this request. +#define USBDC_BOOT_DFU (1<<30) + + +//This being non-0 indicates a memory location where a 'testament' is stored, aka a piece of text that should be output +//after a reboot. Can contain core dump info or something. +#define USBDC_TESTAMENT_LOC_MASK 0x7FFFF //bits 19-0; this is added to a base address of 0x3FF80000. + +//The testament is a FIFO. The ROM will output all data between textstart and textend; if textend is lower than textstart it will +//output everything from textstart to memend, then memstart to textend. +typedef struct { + char *memstart; //start of memory region + char *memend; //end of memory region + char *textstart; //start of text to output + char *textend; +} usbdc_testament_t; + +#ifdef __cplusplus +} +#endif