Merge 1c2f927d4b6c166d93abeffa3d1e37e5b2f2e28e into 65a8907828ad87acd6a8e3363f175a64337b65cd

This commit is contained in:
sakumisu 2025-04-15 18:04:24 +02:00 committed by GitHub
commit dd7ec56e53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 1228 additions and 0 deletions

3
.gitmodules vendored
View File

@ -13,3 +13,6 @@
[submodule "lib/btstack"]
path = lib/btstack
url = https://github.com/bluekitchen/btstack.git
[submodule "lib/cherryusb"]
path = lib/cherryusb
url = https://github.com/cherry-embedded/CherryUSB.git

1
lib/cherryusb Submodule

@ -0,0 +1 @@
Subproject commit 43e6b5b1b1f6af62497e740db8faee4499724627

View File

@ -120,6 +120,8 @@ if (NOT PICO_BARE_METAL)
pico_add_subdirectory(rp2_common/cmsis)
endif()
pico_add_subdirectory(rp2_common/tinyusb)
pico_add_subdirectory(rp2_common/cherryusb)
pico_add_subdirectory(rp2_common/pico_stdio_cherryusb)
pico_add_subdirectory(rp2_common/pico_stdio_usb)
pico_add_subdirectory(rp2_common/pico_i2c_slave)

View File

@ -0,0 +1,46 @@
if (DEFINED ENV{PICO_CHERRYUSB_PATH} AND (NOT PICO_CHERRYUSB_PATH))
set(PICO_CHERRYUSB_PATH $ENV{PICO_CHERRYUSB_PATH})
message("Using PICO_CHERRYUSB_PATH from environment ('${PICO_CHERRYUSB_PATH}')")
endif ()
set(CHERRYUSB_TEST_PATH "port/rp2040")
if (NOT PICO_CHERRYUSB_PATH)
set(PICO_CHERRYUSB_PATH ${PROJECT_SOURCE_DIR}/lib/cherryusb)
if (NOT EXISTS ${PICO_CHERRYUSB_PATH}/${CHERRYUSB_TEST_PATH})
message(WARNING "CherryUSB submodule has not been initialized; USB support will be unavailable
hint: try 'git submodule update --init' from your SDK directory (${PICO_SDK_PATH}).")
endif()
elseif (NOT EXISTS ${PICO_CHERRYUSB_PATH}/${CHERRYUSB_TEST_PATH})
message(WARNING "PICO_CHERRYUSB_PATH specified but content not present.")
endif()
if (EXISTS ${PICO_CHERRYUSB_PATH}/${CHERRYUSB_TEST_PATH})
message("CherryUSB available at ${PICO_CHERRYUSB_PATH}; enabling build support for USB.")
pico_register_common_scope_var(PICO_CHERRYUSB_PATH)
set(CONFIG_CHERRYUSB_DEVICE 1)
set(CONFIG_CHERRYUSB_DEVICE_CDC_ACM 1)
set(CONFIG_CHERRYUSB_DEVICE_HID 1)
set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
set(CONFIG_CHERRYUSB_DEVICE_DCD "rp2040")
include(${PICO_CHERRYUSB_PATH}/cherryusb.cmake)
pico_add_library(cherryusb_device NOFLAG)
target_include_directories(cherryusb_device_headers SYSTEM INTERFACE ${cherryusb_incs})
target_sources(cherryusb_device INTERFACE ${cherryusb_srcs})
set(CONFIG_CHERRYUSB_HOST 1)
set(CONFIG_CHERRYUSB_HOST_CDC_ACM 1)
set(CONFIG_CHERRYUSB_HOST_HID 1)
set(CONFIG_CHERRYUSB_HOST_MSC 1)
set(CONFIG_CHERRYUSB_OSAL "freertos")
set(CONFIG_CHERRYUSB_HOST_HCD "rp2040")
include(${PICO_CHERRYUSB_PATH}/cherryusb.cmake)
pico_add_library(cherryusb_host NOFLAG)
target_include_directories(cherryusb_host_headers SYSTEM INTERFACE ${cherryusb_incs})
target_sources(cherryusb_host INTERFACE ${cherryusb_srcs})
pico_promote_common_scope_vars()
endif()

View File

@ -106,6 +106,12 @@ SECTIONS
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
. = ALIGN(4);
} > FLASH

View File

@ -125,6 +125,12 @@ SECTIONS
*(SORT(.dtors.*))
*(.dtors)
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
. = ALIGN(4);
__ram_text_end__ = .;

View File

@ -106,6 +106,12 @@ SECTIONS
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
. = ALIGN(4);
} > FLASH

View File

@ -68,6 +68,12 @@ SECTIONS
*(SORT(.dtors.*))
*(.dtors)
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
} > RAM

View File

@ -141,6 +141,12 @@ SECTIONS
*(SORT(.dtors.*))
*(.dtors)
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
. = ALIGN(4);
__ram_text_end__ = .;

View File

@ -96,6 +96,12 @@ SECTIONS
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
. = ALIGN(4);
} > FLASH

View File

@ -69,6 +69,12 @@ SECTIONS
*(SORT(.dtors.*))
*(.dtors)
/* section information for usbh class */
. = ALIGN(4);
__usbh_class_info_start__ = .;
KEEP(*(.usbh_class_info))
__usbh_class_info_end__ = .;
*(.eh_frame*)
} > RAM

View File

@ -0,0 +1,25 @@
if (TARGET cherryusb_device)
pico_add_library(pico_stdio_usb)
target_include_directories(pico_stdio_usb_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
target_sources(pico_stdio_usb INTERFACE
${CMAKE_CURRENT_LIST_DIR}/stdio_usb.c
)
pico_mirrored_target_link_libraries(pico_stdio_usb INTERFACE
pico_stdio
pico_time
pico_unique_id
pico_usb_reset_interface
)
target_link_libraries(pico_stdio_usb INTERFACE
cherryusb_device
)
# PICO_CMAKE_CONFIG: PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS, Maximum number of milliseconds to wait during initialization for a CDC connection from the host (negative means indefinite) during initialization, type=int, default=0, group=pico_stdio_usb
if (PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS)
target_compile_definitions(pico_stdio_usb INTERFACE
PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS=${PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS}
)
endif()
endif()

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_STDIO_CHERRYUSB_H
#define _PICO_STDIO_CHERRYUSB_H
#include "pico/stdio.h"
/** \brief Support for stdin/stdout over USB serial (CDC)
* \defgroup pico_stdio_usb pico_stdio_usb
* \ingroup pico_stdio
*
* Linking this library or calling `pico_enable_stdio_usb(TARGET ENABLED)` in the CMake (which
* achieves the same thing) will add USB CDC to the drivers used for standard input/output
*
* Note this library is a developer convenience. It is not applicable in all cases; for one it takes full control of the USB device precluding your
* use of the USB in device or host mode. For this reason, this library will automatically disengage if you try to using it alongside \ref tinyusb_device or
* \ref tinyusb_host. It also takes control of a lower level IRQ and sets up a periodic background task.
*
* This library also includes (by default) functionality to enable the RP-series microcontroller to be reset over the USB interface.
*/
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_DEFAULT_CRLF, Default state of CR/LF translation for USB output, type=bool, default=PICO_STDIO_DEFAULT_CRLF, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_DEFAULT_CRLF
#define PICO_STDIO_CHERRYUSB_DEFAULT_CRLF PICO_STDIO_DEFAULT_CRLF
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_STDOUT_TIMEOUT_US, Number of microseconds to be blocked trying to write USB output before assuming the host has disappeared and discarding data, default=500000, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_STDOUT_TIMEOUT_US
#define PICO_STDIO_CHERRYUSB_STDOUT_TIMEOUT_US 500000
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_BAUD_RATE, Enable/disable resetting into BOOTSEL mode if the host sets the baud rate to a magic value (PICO_STDIO_CHERRYUSB_RESET_MAGIC_BAUD_RATE), type=bool, default=1 if application is not using TinyUSB directly, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_BAUD_RATE
#define PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_BAUD_RATE 1
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_MAGIC_BAUD_RATE, Baud rate that if selected causes a reset into BOOTSEL mode (if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_BAUD_RATE is set), default=1200, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_MAGIC_BAUD_RATE
#define PICO_STDIO_CHERRYUSB_RESET_MAGIC_BAUD_RATE 1200
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS, Maximum number of milliseconds to wait during initialization for a CDC connection from the host (negative means indefinite) during initialization, default=0, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS
#define PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS 0
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS, Number of extra milliseconds to wait when using PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS after a host CDC connection is detected (some host terminals seem to sometimes lose transmissions sent right after connection), default=50, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS
#define PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS 50
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_DEINIT_DELAY_MS, Number of milliseconds to wait before deinitializing stdio_usb, default=110, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_DEINIT_DELAY_MS
#define PICO_STDIO_CHERRYUSB_DEINIT_DELAY_MS 110
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED, Optionally define a pin to use as bootloader activity LED when BOOTSEL mode is entered via USB (either VIA_BAUD_RATE or VIA_VENDOR_INTERFACE), type=int, min=0, max=47 on RP2350B, 29 otherwise, group=pico_stdio_usb
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED_ACTIVE_LOW, Whether pin to use as bootloader activity LED when BOOTSEL mode is entered via USB (either VIA_BAUD_RATE or VIA_VENDOR_INTERFACE) is active low, type=bool, default=0, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_FIXED_ACTIVITY_LED_ACTIVE_LOW
#define PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_FIXED_ACTIVITY_LED_ACTIVE_LOW 0
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_FIXED_ACTIVITY_LED, Whether the pin specified by PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED is fixed or can be modified by picotool over the VENDOR USB interface, type=bool, default=0, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_FIXED_ACTIVITY_LED
#define PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_FIXED_ACTIVITY_LED 0
#endif
// Any modes disabled here can't be re-enabled by picotool via VENDOR_INTERFACE.
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK, Optionally disable either the mass storage interface (bit 0) or the PICOBOOT interface (bit 1) when entering BOOTSEL mode via USB (either VIA_BAUD_RATE or VIA_VENDOR_INTERFACE), type=int, min=0, max=3, default=0, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK
#define PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK 0u
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE, Enable/disable resetting into BOOTSEL mode via an additional VENDOR USB interface - enables picotool based reset, type=bool, default=1 if application is not using TinyUSB directly, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE
#define PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE 1
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL, If vendor reset interface is included allow rebooting to BOOTSEL mode, type=bool, default=1, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL
#define PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL 1
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT, If vendor reset interface is included allow rebooting with regular flash boot, type=bool, default=1, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT
#define PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT 1
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR, If vendor reset interface is included add support for Microsoft OS 2.0 Descriptor, type=bool, default=1, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
#define PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR 1
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_RESET_RESET_TO_FLASH_DELAY_MS, Delay in ms before rebooting via regular flash boot, default=100, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_RESET_RESET_TO_FLASH_DELAY_MS
#define PICO_STDIO_CHERRYUSB_RESET_RESET_TO_FLASH_DELAY_MS 100
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_CONNECTION_WITHOUT_DTR, Disable use of DTR for connection checking meaning connection is assumed to be valid, type=bool, default=0, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_CONNECTION_WITHOUT_DTR
#define PICO_STDIO_CHERRYUSB_CONNECTION_WITHOUT_DTR 0
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_DEVICE_SELF_POWERED, Set USB device as self powered device, type=bool, default=0, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_DEVICE_SELF_POWERED
#define PICO_STDIO_CHERRYUSB_DEVICE_SELF_POWERED 0
#endif
// PICO_CONFIG: PICO_STDIO_CHERRYUSB_SUPPORT_CHARS_AVAILABLE_CALLBACK, Enable USB STDIO support for stdio_set_chars_available_callback. Can be disabled to make use of USB CDC RX callback elsewhere, type=bool, default=1, group=pico_stdio_usb
#ifndef PICO_STDIO_CHERRYUSB_SUPPORT_CHARS_AVAILABLE_CALLBACK
#define PICO_STDIO_CHERRYUSB_SUPPORT_CHARS_AVAILABLE_CALLBACK 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern stdio_driver_t stdio_usb;
/*! \brief Explicitly initialize USB stdio and add it to the current set of stdin drivers
* \ingroup pico_stdio_usb
*
* \ref PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS can be set to cause this method to wait for a CDC connection
* from the host before returning, which is useful if you don't want any initial stdout output to be discarded
* before the connection is established.
*
* \return true if the USB CDC was initialized, false if an error occurred
*/
bool stdio_usb_init(void);
/*! \brief Explicitly deinitialize USB stdio and remove it from the current set of stdin drivers
* \ingroup pico_stdio_usb
*
* \return true if the USB CDC was deinitialized, false if an error occurred
*/
bool stdio_usb_deinit(void);
/*! \brief Check if there is an active stdio CDC connection to a host
* \ingroup pico_stdio_usb
*
* \return true if stdio is connected over CDC
*/
bool stdio_usb_connected(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,13 @@
/*
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_STDIO_CHERRYUSB_RESET_INTERFACE_H
#define _PICO_STDIO_CHERRYUSB_RESET_INTERFACE_H
// definitions have been moved here
#include "pico/usb_reset_interface.h"
#endif

View File

@ -0,0 +1,296 @@
/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef CHERRYUSB_CONFIG_EXAMPLES_COMMON_H
#define CHERRYUSB_CONFIG_EXAMPLES_COMMON_H
/* ================ USB common Configuration ================ */
#define CONFIG_USB_PRINTF(...)
#ifndef CONFIG_USB_DBG_LEVEL
#define CONFIG_USB_DBG_LEVEL USB_DBG_INFO
#endif
/* Enable print with color */
#define CONFIG_USB_PRINTF_COLOR_ENABLE
/* data align size when use dma or use dcache */
#ifndef CONFIG_USB_ALIGN_SIZE
#define CONFIG_USB_ALIGN_SIZE 4
#endif
//#define CONFIG_USB_DCACHE_ENABLE
/* attribute data into no cache ram */
#define USB_NOCACHE_RAM_SECTION
/* ================= USB Device Stack Configuration ================ */
/* Ep0 in and out transfer buffer */
#ifndef CONFIG_USBDEV_REQUEST_BUFFER_LEN
#define CONFIG_USBDEV_REQUEST_BUFFER_LEN 512
#endif
/* Setup packet log for debug */
// #define CONFIG_USBDEV_SETUP_LOG_PRINT
/* Send ep0 in data from user buffer instead of copying into ep0 reqdata
* Please note that user buffer must be aligned with CONFIG_USB_ALIGN_SIZE
*/
// #define CONFIG_USBDEV_EP0_INDATA_NO_COPY
/* Check if the input descriptor is correct */
// #define CONFIG_USBDEV_DESC_CHECK
/* Enable test mode */
// #define CONFIG_USBDEV_TEST_MODE
#ifndef CONFIG_USBDEV_MSC_MAX_LUN
#define CONFIG_USBDEV_MSC_MAX_LUN 1
#endif
#ifndef CONFIG_USBDEV_MSC_MAX_BUFSIZE
#define CONFIG_USBDEV_MSC_MAX_BUFSIZE 512
#endif
#ifndef CONFIG_USBDEV_MSC_MANUFACTURER_STRING
#define CONFIG_USBDEV_MSC_MANUFACTURER_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_PRODUCT_STRING
#define CONFIG_USBDEV_MSC_PRODUCT_STRING ""
#endif
#ifndef CONFIG_USBDEV_MSC_VERSION_STRING
#define CONFIG_USBDEV_MSC_VERSION_STRING "0.01"
#endif
/* move msc read & write from isr to while(1), you should call usbd_msc_polling in while(1) */
// #define CONFIG_USBDEV_MSC_POLLING
/* move msc read & write from isr to thread */
// #define CONFIG_USBDEV_MSC_THREAD
#ifndef CONFIG_USBDEV_MSC_PRIO
#define CONFIG_USBDEV_MSC_PRIO 4
#endif
#ifndef CONFIG_USBDEV_MSC_STACKSIZE
#define CONFIG_USBDEV_MSC_STACKSIZE 2048
#endif
#ifndef CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE
#define CONFIG_USBDEV_RNDIS_RESP_BUFFER_SIZE 156
#endif
/* rndis transfer buffer size, must be a multiple of (1536 + 44)*/
#ifndef CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE
#define CONFIG_USBDEV_RNDIS_ETH_MAX_FRAME_SIZE 1580
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_ID
#define CONFIG_USBDEV_RNDIS_VENDOR_ID 0x0000ffff
#endif
#ifndef CONFIG_USBDEV_RNDIS_VENDOR_DESC
#define CONFIG_USBDEV_RNDIS_VENDOR_DESC "CherryUSB"
#endif
#define CONFIG_USBDEV_RNDIS_USING_LWIP
/* ================ USB HOST Stack Configuration ================== */
#define CONFIG_USBHOST_MAX_RHPORTS 1
#define CONFIG_USBHOST_MAX_EXTHUBS 1
#define CONFIG_USBHOST_MAX_EHPORTS 4
#define CONFIG_USBHOST_MAX_INTERFACES 8
#define CONFIG_USBHOST_MAX_INTF_ALTSETTINGS 8
#define CONFIG_USBHOST_MAX_ENDPOINTS 4
#define CONFIG_USBHOST_MAX_CDC_ACM_CLASS 4
#define CONFIG_USBHOST_MAX_HID_CLASS 4
#define CONFIG_USBHOST_MAX_MSC_CLASS 2
#define CONFIG_USBHOST_MAX_AUDIO_CLASS 1
#define CONFIG_USBHOST_MAX_VIDEO_CLASS 1
#define CONFIG_USBHOST_DEV_NAMELEN 16
#ifndef CONFIG_USBHOST_PSC_PRIO
#define CONFIG_USBHOST_PSC_PRIO 0
#endif
#ifndef CONFIG_USBHOST_PSC_STACKSIZE
#define CONFIG_USBHOST_PSC_STACKSIZE 2048
#endif
//#define CONFIG_USBHOST_GET_STRING_DESC
// #define CONFIG_USBHOST_MSOS_ENABLE
#ifndef CONFIG_USBHOST_MSOS_VENDOR_CODE
#define CONFIG_USBHOST_MSOS_VENDOR_CODE 0x00
#endif
/* Ep0 max transfer buffer */
#ifndef CONFIG_USBHOST_REQUEST_BUFFER_LEN
#define CONFIG_USBHOST_REQUEST_BUFFER_LEN 512
#endif
#ifndef CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT
#define CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT 500
#endif
#ifndef CONFIG_USBHOST_MSC_TIMEOUT
#define CONFIG_USBHOST_MSC_TIMEOUT 5000
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RNDIS_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_CDC_NCM_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_ASIX_ETH_MAX_TX_SIZE (2048)
#endif
/* This parameter affects usb performance, and depends on (TCP_WND)tcp eceive windows size,
* you can change to 2K ~ 16K and must be larger than TCP RX windows size in order to avoid being overflow.
*/
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_RX_SIZE (2048)
#endif
/* Because lwip do not support multi pbuf at a time, so increasing this variable has no performance improvement */
#ifndef CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE
#define CONFIG_USBHOST_RTL8152_ETH_MAX_TX_SIZE (2048)
#endif
#define CONFIG_USBHOST_BLUETOOTH_HCI_H4
// #define CONFIG_USBHOST_BLUETOOTH_HCI_LOG
#ifndef CONFIG_USBHOST_BLUETOOTH_TX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_TX_SIZE 2048
#endif
#ifndef CONFIG_USBHOST_BLUETOOTH_RX_SIZE
#define CONFIG_USBHOST_BLUETOOTH_RX_SIZE 2048
#endif
/* ================ USB Device Port Configuration ================*/
#ifndef CONFIG_USBDEV_MAX_BUS
#define CONFIG_USBDEV_MAX_BUS 1 // for now, bus num must be 1 except hpm ip
#endif
#ifndef CONFIG_USBDEV_EP_NUM
#define CONFIG_USBDEV_EP_NUM 16
#endif
/* When your chip hardware supports high-speed and wants to initialize it in high-speed mode, the relevant IP will configure the internal or external high-speed PHY according to CONFIG_USB_HS. */
// #define CONFIG_USB_HS
/* ---------------- FSDEV Configuration ---------------- */
//#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2 // maybe 1 or 2, many chips may have a difference
/* ---------------- DWC2 Configuration ---------------- */
/* (5 * number of control endpoints + 8) + ((largest USB packet used / 4) + 1 for
* status information) + (2 * number of OUT endpoints) + 1 for Global NAK
*/
// #define CONFIG_USB_DWC2_RXALL_FIFO_SIZE (1024 / 4)
/* IN Endpoints Max packet Size / 4 */
// #define CONFIG_USB_DWC2_TX0_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX1_FIFO_SIZE (1024 / 4)
// #define CONFIG_USB_DWC2_TX2_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX3_FIFO_SIZE (64 / 4)
// #define CONFIG_USB_DWC2_TX4_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX5_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX6_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX7_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_TX8_FIFO_SIZE (0 / 4)
// #define CONFIG_USB_DWC2_DMA_ENABLE
/* ---------------- MUSB Configuration ---------------- */
// #define CONFIG_USB_MUSB_SUNXI
/* ================ USB Host Port Configuration ==================*/
#ifndef CONFIG_USBHOST_MAX_BUS
#define CONFIG_USBHOST_MAX_BUS 1
#endif
#ifndef CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USBHOST_PIPE_NUM 15
#endif
/* ---------------- EHCI Configuration ---------------- */
#define CONFIG_USB_EHCI_HCCR_OFFSET (0x0)
#define CONFIG_USB_EHCI_FRAME_LIST_SIZE 1024
#define CONFIG_USB_EHCI_QH_NUM CONFIG_USBHOST_PIPE_NUM
#define CONFIG_USB_EHCI_QTD_NUM 3
#define CONFIG_USB_EHCI_ITD_NUM 20
// #define CONFIG_USB_EHCI_HCOR_RESERVED_DISABLE
// #define CONFIG_USB_EHCI_CONFIGFLAG
// #define CONFIG_USB_EHCI_ISO
// #define CONFIG_USB_EHCI_WITH_OHCI
/* ---------------- OHCI Configuration ---------------- */
#define CONFIG_USB_OHCI_HCOR_OFFSET (0x0)
/* ---------------- XHCI Configuration ---------------- */
#define CONFIG_USB_XHCI_HCCR_OFFSET (0x0)
/* ---------------- DWC2 Configuration ---------------- */
/* largest non-periodic USB packet used / 4 */
// #define CONFIG_USB_DWC2_NPTX_FIFO_SIZE (512 / 4)
/* largest periodic USB packet used / 4 */
// #define CONFIG_USB_DWC2_PTX_FIFO_SIZE (1024 / 4)
/*
* (largest USB packet used / 4) + 1 for status information + 1 transfer complete +
* 1 location each for Bulk/Control endpoint for handling NAK/NYET scenario
*/
// #define CONFIG_USB_DWC2_RX_FIFO_SIZE ((1012 - CONFIG_USB_DWC2_NPTX_FIFO_SIZE - CONFIG_USB_DWC2_PTX_FIFO_SIZE))
/* ---------------- MUSB Configuration ---------------- */
// #define CONFIG_USB_MUSB_SUNXI
/* ================ USB Dcache Configuration ==================*/
#ifdef CONFIG_USB_DCACHE_ENABLE
/* style 1*/
// void usb_dcache_clean(uintptr_t addr, uint32_t size);
// void usb_dcache_invalidate(uintptr_t addr, uint32_t size);
// void usb_dcache_flush(uintptr_t addr, uint32_t size);
/* style 2*/
// #define usb_dcache_clean(addr, size)
// #define usb_dcache_invalidate(addr, size)
// #define usb_dcache_flush(addr, size)
#endif
#define CONFIG_USBDEV_ADVANCE_DESC
#endif

View File

@ -0,0 +1,647 @@
#ifndef LIB_CHERRYUSB_HOST
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE && !(PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL || PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT)
#warning PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE has been selected but neither PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL nor PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT have been selected.
#endif
#include "usbd_core.h"
#include "usbd_cdc_acm.h"
#include "pico/stdio_usb.h"
#include "pico/binary_info.h"
#include "pico/time.h"
#include "pico/stdio/driver.h"
#include "pico/mutex.h"
#include "hardware/irq.h"
#include "pico/unique_id.h"
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE
#include "pico/stdio_usb/reset_interface.h"
#include "hardware/watchdog.h"
#include "pico/bootrom.h"
#endif
/*!< endpoint address */
#define CDC_IN_EP 0x81
#define CDC_OUT_EP 0x02
#define CDC_INT_EP 0x83
#ifndef USBD_VID
#define USBD_VID (0x2E8A) // Raspberry Pi
#endif
#ifndef USBD_PID
#if PICO_RP2040
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC for RP2040
#else
#define USBD_PID (0x0009) // Raspberry Pi Pico SDK CDC
#endif
#endif
#ifndef USBD_MANUFACTURER
#define USBD_MANUFACTURER "Raspberry Pi"
#endif
#ifndef USBD_PRODUCT
#define USBD_PRODUCT "Pico"
#endif
#define TUD_RPI_RESET_DESC_LEN 9
#if !PICO_STDIO_CHERRYUSB_DEVICE_SELF_POWERED
#define USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE USB_CONFIG_BUS_POWERED
#define USBD_MAX_POWER_MA (250)
#else
#define USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE USB_CONFIG_SELF_POWERED
#define USBD_MAX_POWER_MA (1)
#endif
#define USBD_ITF_CDC (0) // needs 2 interfaces
#if !PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE
#define USBD_ITF_MAX (2)
#else
#define USBD_ITF_RPI_RESET (2)
#define USBD_ITF_MAX (3)
#endif
#define USBD_LANGID_STRING 1033
#if !PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE
/*!< config descriptor size */
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN)
#else
#define USB_CONFIG_SIZE (9 + CDC_ACM_DESCRIPTOR_LEN + TUD_RPI_RESET_DESC_LEN)
#endif
#ifdef CONFIG_USB_HS
#define CDC_MAX_MPS 512
#else
#define CDC_MAX_MPS 64
#endif
#define USBD_STR_0 (0x00)
#define USBD_STR_MANUF (0x01)
#define USBD_STR_PRODUCT (0x02)
#define USBD_STR_SERIAL (0x03)
#define USBD_STR_CDC (0x04)
#define USBD_STR_RPI_RESET (0x05)
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
#define USBD_WINUSB_VENDOR_CODE 0x01
#define USBD_WEBUSB_ENABLE 0
#define USBD_BULK_ENABLE 1
#define USBD_WINUSB_ENABLE 1
/* WinUSB Microsoft OS 2.0 descriptor sizes */
#define WINUSB_DESCRIPTOR_SET_HEADER_SIZE 10
#define WINUSB_FUNCTION_SUBSET_HEADER_SIZE 8
#define WINUSB_FEATURE_COMPATIBLE_ID_SIZE 20
#define FUNCTION_SUBSET_LEN 160
#define DEVICE_INTERFACE_GUIDS_FEATURE_LEN 132
#define USBD_WINUSB_DESC_SET_LEN (WINUSB_DESCRIPTOR_SET_HEADER_SIZE + USBD_WEBUSB_ENABLE * FUNCTION_SUBSET_LEN + USBD_BULK_ENABLE * FUNCTION_SUBSET_LEN)
__ALIGN_BEGIN const uint8_t USBD_WinUSBDescriptorSetDescriptor[] = {
WBVAL(WINUSB_DESCRIPTOR_SET_HEADER_SIZE), /* wLength */
WBVAL(WINUSB_SET_HEADER_DESCRIPTOR_TYPE), /* wDescriptorType */
0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
#if (USBD_WEBUSB_ENABLE)
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), // wLength
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), // wDescriptorType
0, // bFirstInterface USBD_WINUSB_IF_NUM
0, // bReserved
WBVAL(FUNCTION_SUBSET_LEN), // wSubsetLength
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), // wLength
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), // wDescriptorType
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, // CompatibleId
0, 0, 0, 0, 0, 0, 0, 0, // SubCompatibleId
WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), // wLength
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), // wDescriptorType
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), // wPropertyDataType
WBVAL(42), // wPropertyNameLength
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
WBVAL(80), // wPropertyDataLength
'{', 0,
'9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0,
'9', 0, 'C', 0, '7', 0, '7', 0, '-', 0,
'4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0,
'9', 0, '3', 0, '3', 0, 'B', 0, '-',
0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, '9', 0,
'}', 0, 0, 0, 0, 0
#endif
#if USBD_BULK_ENABLE
WBVAL(WINUSB_FUNCTION_SUBSET_HEADER_SIZE), /* wLength */
WBVAL(WINUSB_SUBSET_HEADER_FUNCTION_TYPE), /* wDescriptorType */
USBD_ITF_RPI_RESET, /* bFirstInterface USBD_ITF_RPI_RESET*/
0, /* bReserved */
WBVAL(FUNCTION_SUBSET_LEN), /* wSubsetLength */
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_SIZE), /* wLength */
WBVAL(WINUSB_FEATURE_COMPATIBLE_ID_TYPE), /* wDescriptorType */
'W', 'I', 'N', 'U', 'S', 'B', 0, 0, /* CompatibleId*/
0, 0, 0, 0, 0, 0, 0, 0, /* SubCompatibleId*/
WBVAL(DEVICE_INTERFACE_GUIDS_FEATURE_LEN), /* wLength */
WBVAL(WINUSB_FEATURE_REG_PROPERTY_TYPE), /* wDescriptorType */
WBVAL(WINUSB_PROP_DATA_TYPE_REG_MULTI_SZ), /* wPropertyDataType */
WBVAL(42), /* wPropertyNameLength */
'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0,
'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0,
'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0,
WBVAL(80), /* wPropertyDataLength */
'{', 0,
'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0, 'A', 0, 'D', 0, '-', 0,
'2', 0, '9', 0, '3', 0, 'B', 0, '-', 0,
'4', 0, '6', 0, '6', 0, '3', 0, '-', 0,
'A', 0, 'A', 0, '3', 0, '6', 0, '-',
0, '1', 0, 'A', 0, 'A', 0, 'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0, '7', 0, '6', 0,
'}', 0, 0, 0, 0, 0
#endif
};
#define USBD_NUM_DEV_CAPABILITIES (USBD_WEBUSB_ENABLE + USBD_WINUSB_ENABLE)
#define USBD_WEBUSB_DESC_LEN 24
#define USBD_WINUSB_DESC_LEN 28
#define USBD_BOS_WTOTALLENGTH (0x05 + \
USBD_WEBUSB_DESC_LEN * USBD_WEBUSB_ENABLE + \
USBD_WINUSB_DESC_LEN * USBD_WINUSB_ENABLE)
__ALIGN_BEGIN const uint8_t USBD_BinaryObjectStoreDescriptor[] = {
0x05, /* bLength */
0x0f, /* bDescriptorType */
WBVAL(USBD_BOS_WTOTALLENGTH), /* wTotalLength */
USBD_NUM_DEV_CAPABILITIES, /* bNumDeviceCaps */
#if (USBD_WEBUSB_ENABLE)
USBD_WEBUSB_DESC_LEN, /* bLength */
0x10, /* bDescriptorType */
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
0x00, /* bReserved */
0x38, 0xB6, 0x08, 0x34, /* PlatformCapabilityUUID */
0xA9, 0x09, 0xA0, 0x47,
0x8B, 0xFD, 0xA0, 0x76,
0x88, 0x15, 0xB6, 0x65,
WBVAL(0x0100), /* 1.00 */ /* bcdVersion */
USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
0, /* iLandingPage */
#endif
#if (USBD_WINUSB_ENABLE)
USBD_WINUSB_DESC_LEN, /* bLength */
0x10, /* bDescriptorType */
USB_DEVICE_CAPABILITY_PLATFORM, /* bDevCapabilityType */
0x00, /* bReserved */
0xDF, 0x60, 0xDD, 0xD8, /* PlatformCapabilityUUID */
0x89, 0x45, 0xC7, 0x4C,
0x9C, 0xD2, 0x65, 0x9D,
0x9E, 0x64, 0x8A, 0x9F,
0x00, 0x00, 0x03, 0x06, /* >= Win 8.1 */ /* dwWindowsVersion*/
WBVAL(USBD_WINUSB_DESC_SET_LEN), /* wDescriptorSetTotalLength */
USBD_WINUSB_VENDOR_CODE, /* bVendorCode */
0, /* bAltEnumCode */
#endif
};
struct usb_msosv2_descriptor msosv2_desc = {
.vendor_code = USBD_WINUSB_VENDOR_CODE,
.compat_id = USBD_WinUSBDescriptorSetDescriptor,
.compat_id_len = USBD_WINUSB_DESC_SET_LEN,
};
struct usb_bos_descriptor bos_desc = {
.string = USBD_BinaryObjectStoreDescriptor,
.string_len = USBD_BOS_WTOTALLENGTH
};
static int rp_vendor_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len) {
if (setup->wIndex == USBD_ITF_RPI_RESET) {
#if PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_BOOTSEL
if (setup->bRequest == RESET_REQUEST_BOOTSEL) {
#ifdef PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED
int gpio = PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED;
bool active_low = PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED_ACTIVE_LOW;
#else
int gpio = -1;
bool active_low = false;
#endif
#if !PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_FIXED_ACTIVITY_LED
if (setup->wValue & 0x100) {
gpio = setup->wValue >> 9u;
}
active_low = setup->wValue & 0x200;
#endif
rom_reset_usb_boot_extra(gpio, (setup->wValue & 0x7f) | PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK, active_low);
// does not return, otherwise we'd return true
}
#endif
#if PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT
if (setup->bRequest == RESET_REQUEST_FLASH) {
watchdog_reboot(0, 0, PICO_STDIO_CHERRYUSB_RESET_RESET_TO_FLASH_DELAY_MS);
return 0;
}
#endif
} else {
return -1;
}
}
#endif
#ifdef CONFIG_USBDEV_ADVANCE_DESC
static const uint8_t device_descriptor[] = {
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
USB_DEVICE_DESCRIPTOR_INIT(USB_2_1, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
#else
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
#endif
};
static const uint8_t config_descriptor[] = {
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, USBD_ITF_MAX, 0x01, USBD_CONFIGURATION_DESCRIPTOR_ATTRIBUTE, USBD_MAX_POWER_MA),
CDC_ACM_DESCRIPTOR_INIT(USBD_ITF_CDC, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, USBD_STR_CDC),
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE
USB_INTERFACE_DESCRIPTOR_INIT(USBD_ITF_RPI_RESET, 0x00, 0x00, 0xFF, RESET_INTERFACE_SUBCLASS, RESET_INTERFACE_PROTOCOL, USBD_STR_RPI_RESET),
#endif
};
static const uint8_t device_quality_descriptor[] = {
///////////////////////////////////////
/// device qualifier descriptor
///////////////////////////////////////
0x0a,
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x00,
0x00,
};
static char usbd_serial_str[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
static const char *string_descriptors[] = {
[USBD_STR_0] = (const char[]){ 0x09, 0x04 },
[USBD_STR_MANUF] = USBD_MANUFACTURER,
[USBD_STR_PRODUCT] = USBD_PRODUCT,
[USBD_STR_SERIAL] = usbd_serial_str,
[USBD_STR_CDC] = "Board CDC",
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE
[USBD_STR_RPI_RESET] = "Reset",
#endif
};
static const uint8_t *device_descriptor_callback(uint8_t speed) {
return device_descriptor;
}
static const uint8_t *config_descriptor_callback(uint8_t speed) {
return config_descriptor;
}
static const uint8_t *device_quality_descriptor_callback(uint8_t speed) {
return device_quality_descriptor;
}
static const char *string_descriptor_callback(uint8_t speed, uint8_t index) {
if (index > 5) {
return NULL;
}
// Assign the SN using the unique flash id
if (!usbd_serial_str[0]) {
pico_get_unique_board_id_string(usbd_serial_str, sizeof(usbd_serial_str));
}
return string_descriptors[index];
}
const struct usb_descriptor cdc_descriptor = {
.device_descriptor_callback = device_descriptor_callback,
.config_descriptor_callback = config_descriptor_callback,
.device_quality_descriptor_callback = device_quality_descriptor_callback,
.string_descriptor_callback = string_descriptor_callback,
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
.msosv2_descriptor = &msosv2_desc,
.bos_descriptor = &bos_desc
#endif
};
#else
/*!< global descriptor */
static const uint8_t cdc_descriptor[] = {
USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01),
USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
CDC_ACM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, 0x02),
///////////////////////////////////////
/// string0 descriptor
///////////////////////////////////////
USB_LANGID_INIT(USBD_LANGID_STRING),
///////////////////////////////////////
/// string1 descriptor
///////////////////////////////////////
0x14, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
///////////////////////////////////////
/// string2 descriptor
///////////////////////////////////////
0x26, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'C', 0x00, /* wcChar0 */
'h', 0x00, /* wcChar1 */
'e', 0x00, /* wcChar2 */
'r', 0x00, /* wcChar3 */
'r', 0x00, /* wcChar4 */
'y', 0x00, /* wcChar5 */
'U', 0x00, /* wcChar6 */
'S', 0x00, /* wcChar7 */
'B', 0x00, /* wcChar8 */
' ', 0x00, /* wcChar9 */
'C', 0x00, /* wcChar10 */
'D', 0x00, /* wcChar11 */
'C', 0x00, /* wcChar12 */
' ', 0x00, /* wcChar13 */
'D', 0x00, /* wcChar14 */
'E', 0x00, /* wcChar15 */
'M', 0x00, /* wcChar16 */
'O', 0x00, /* wcChar17 */
///////////////////////////////////////
/// string3 descriptor
///////////////////////////////////////
0x16, /* bLength */
USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */
'2', 0x00, /* wcChar0 */
'0', 0x00, /* wcChar1 */
'2', 0x00, /* wcChar2 */
'2', 0x00, /* wcChar3 */
'1', 0x00, /* wcChar4 */
'2', 0x00, /* wcChar5 */
'3', 0x00, /* wcChar6 */
'4', 0x00, /* wcChar7 */
'5', 0x00, /* wcChar8 */
'6', 0x00, /* wcChar9 */
#ifdef CONFIG_USB_HS
///////////////////////////////////////
/// device qualifier descriptor
///////////////////////////////////////
0x0a,
USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x00,
0x00,
#endif
0x00
};
#endif
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_usb_read_buffer[CDC_MAX_MPS];
volatile bool g_usb_tx_busy_flag = false;
volatile uint32_t g_usb_rx_count = 0;
volatile uint32_t g_usb_rx_offset = 0;
static void usbd_event_handler(uint8_t busid, uint8_t event) {
switch (event) {
case USBD_EVENT_RESET:
g_usb_tx_busy_flag = false;
g_usb_rx_offset = 0;
g_usb_rx_count = 0;
break;
case USBD_EVENT_CONNECTED:
break;
case USBD_EVENT_DISCONNECTED:
break;
case USBD_EVENT_RESUME:
break;
case USBD_EVENT_SUSPEND:
break;
case USBD_EVENT_CONFIGURED:
g_usb_tx_busy_flag = false;
/* setup first out ep read transfer */
usbd_ep_start_read(busid, CDC_OUT_EP, g_usb_read_buffer, CDC_MAX_MPS);
break;
case USBD_EVENT_SET_REMOTE_WAKEUP:
break;
case USBD_EVENT_CLR_REMOTE_WAKEUP:
break;
default:
break;
}
}
void usbd_cdc_acm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) {
g_usb_rx_count = nbytes;
g_usb_rx_offset = 0;
}
void usbd_cdc_acm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) {
if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
/* send zlp */
usbd_ep_start_write(busid, CDC_IN_EP, NULL, 0);
} else {
g_usb_tx_busy_flag = false;
}
}
/*!< endpoint call back */
struct usbd_endpoint cdc_out_ep = {
.ep_addr = CDC_OUT_EP,
.ep_cb = usbd_cdc_acm_bulk_out
};
struct usbd_endpoint cdc_in_ep = {
.ep_addr = CDC_IN_EP,
.ep_cb = usbd_cdc_acm_bulk_in
};
static struct usbd_interface intf0;
static struct usbd_interface intf1;
static struct usbd_interface intf2;
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_BAUD_RATE
// Support for default BOOTSEL reset by changing baud rate
void usbd_cdc_acm_set_line_coding(uint8_t busid, uint8_t intf, struct cdc_line_coding *line_coding) {
(void)busid;
(void)intf;
if (line_coding->dwDTERate == PICO_STDIO_CHERRYUSB_RESET_MAGIC_BAUD_RATE) {
#ifdef PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED
int gpio = PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED;
bool active_low = PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_ACTIVITY_LED_ACTIVE_LOW;
#else
int gpio = -1;
bool active_low = false;
#endif
rom_reset_usb_boot_extra(gpio, PICO_STDIO_CHERRYUSB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK, active_low);
}
}
#endif
static void cdc_acm_init(uint8_t busid, uintptr_t reg_base) {
#ifdef CONFIG_USBDEV_ADVANCE_DESC
usbd_desc_register(busid, &cdc_descriptor);
#else
usbd_desc_register(busid, cdc_descriptor);
#endif
#ifndef CONFIG_USBDEV_ADVANCE_DESC
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
usbd_bos_desc_register(busid, &bos_desc);
usbd_msosv2_desc_register(busid, &msosv2_desc);
#endif
#endif
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf0));
usbd_add_interface(busid, usbd_cdc_acm_init_intf(busid, &intf1));
#if PICO_STDIO_CHERRYUSB_ENABLE_RESET_VIA_VENDOR_INTERFACE && PICO_STDIO_CHERRYUSB_RESET_INTERFACE_SUPPORT_MS_OS_20_DESCRIPTOR
intf2.vendor_handler = rp_vendor_request_handler;
usbd_add_interface(busid, &intf2);
#endif
usbd_add_endpoint(busid, &cdc_out_ep);
usbd_add_endpoint(busid, &cdc_in_ep);
usbd_initialize(busid, reg_base, usbd_event_handler);
}
#if PICO_STDIO_CHERRYUSB_SUPPORT_CHARS_AVAILABLE_CALLBACK
static void (*chars_available_callback)(void *);
static void *chars_available_param;
#endif
static mutex_t stdio_usb_mutex;
static void stdio_usb_out_chars(const char *buf, int length) {
uint64_t last_avail_time;
if (!mutex_try_enter_block_until(&stdio_usb_mutex, make_timeout_time_ms(PICO_STDIO_DEADLOCK_TIMEOUT_MS))) {
return;
}
last_avail_time = time_us_64();
if (usb_device_is_configured(0)) {
g_usb_tx_busy_flag = true;
usbd_ep_start_write(0, CDC_IN_EP, buf, length);
while (g_usb_tx_busy_flag) {
if ((time_us_64() - last_avail_time) > PICO_STDIO_CHERRYUSB_STDOUT_TIMEOUT_US) {
break;
}
}
} else {
}
mutex_exit(&stdio_usb_mutex);
}
static void stdio_usb_out_flush(void) {
}
static int stdio_usb_in_chars(char *buf, int length) {
int rc = PICO_ERROR_NO_DATA;
uint32_t len;
if (g_usb_rx_count > 0) {
len = MIN(g_usb_rx_count - g_usb_rx_offset, length);
memcpy(buf, &g_usb_read_buffer[g_usb_rx_offset], len);
g_usb_rx_offset += len;
if (len > 0) {
return len;
} else {
g_usb_rx_count = 0;
/* setup first out ep read transfer */
usbd_ep_start_read(0, CDC_OUT_EP, g_usb_read_buffer, CDC_MAX_MPS);
return rc;
}
} else {
return rc;
}
}
#if PICO_STDIO_CHERRYUSB_SUPPORT_CHARS_AVAILABLE_CALLBACK
void stdio_usb_set_chars_available_callback(void (*fn)(void *), void *param) {
chars_available_callback = fn;
chars_available_param = param;
}
#endif
stdio_driver_t stdio_usb = {
.out_chars = stdio_usb_out_chars,
.out_flush = stdio_usb_out_flush,
.in_chars = stdio_usb_in_chars,
#if PICO_STDIO_CHERRYUSB_SUPPORT_CHARS_AVAILABLE_CALLBACK
.set_chars_available_callback = stdio_usb_set_chars_available_callback,
#endif
#if PICO_STDIO_ENABLE_CRLF_SUPPORT
.crlf_enabled = PICO_STDIO_CHERRYUSB_DEFAULT_CRLF
#endif
};
bool stdio_usb_init(void) {
if (get_core_num() != alarm_pool_core_num(alarm_pool_get_default())) {
// included an assertion here rather than just returning false, as this is likely
// a coding bug, rather than anything else.
assert(false);
return false;
}
#if !PICO_NO_BI_STDIO_USB
bi_decl_if_func_used(bi_program_feature("USB stdin / stdout"));
#endif
cdc_acm_init(0, 0);
if (!mutex_is_initialized(&stdio_usb_mutex))
mutex_init(&stdio_usb_mutex);
bool rc = true;
if (rc) {
stdio_set_driver_enabled(&stdio_usb, true);
#if PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS
#if PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS > 0
absolute_time_t until = make_timeout_time_ms(PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS);
#else
absolute_time_t until = at_the_end_of_time;
#endif
do {
if (usb_device_is_configured(0)) {
#if PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS != 0
sleep_ms(PICO_STDIO_CHERRYUSB_CONNECT_WAIT_TIMEOUT_MS);
#endif
break;
}
sleep_ms(10);
} while (!time_reached(until));
#endif
}
return rc;
}
bool stdio_usb_deinit(void) {
if (get_core_num() != alarm_pool_core_num(alarm_pool_get_default())) {
// included an assertion here rather than just returning false, as this is likely
// a coding bug, rather than anything else.
assert(false);
return false;
}
usbd_deinitialize(0);
bool rc = true;
stdio_set_driver_enabled(&stdio_usb, false);
#if PICO_STDIO_CHERRYUSB_DEINIT_DELAY_MS != 0
sleep_ms(PICO_STDIO_CHERRYUSB_DEINIT_DELAY_MS);
#endif
return rc;
}
#endif