Merge branch 'master' into pio-host

This commit is contained in:
hathach 2022-03-20 00:51:00 +07:00
commit 45052c625e
No known key found for this signature in database
GPG Key ID: 2FA891220FBFD581
66 changed files with 3443 additions and 1353 deletions

View File

@ -60,11 +60,12 @@ body:
- type: textarea - type: textarea
attributes: attributes:
label: Debug Log label: Debug Log as txt file
placeholder: | placeholder: |
TinyUSB debug log where the issue occurred as attached txt file, best with comments to explain the actual events. Attach your debug log txt file here, where the issue occurred, best with comments to explain the actual events.
Note: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h. Note1: Please DO NOT paste your lengthy log contents here since it hurts the readibility.
Note2: To enable logging, add `LOG=3` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=3` in your tusb_config.h.
More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md) More information can be found at [example's readme](https://github.com/hathach/tinyusb/blob/master/docs/getting_started.md)
validations: validations:
required: false required: false

6
.gitmodules vendored
View File

@ -97,6 +97,12 @@
[submodule "hw/mcu/st/stm32l5xx_hal_driver"] [submodule "hw/mcu/st/stm32l5xx_hal_driver"]
path = hw/mcu/st/stm32l5xx_hal_driver path = hw/mcu/st/stm32l5xx_hal_driver
url = https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git url = https://github.com/STMicroelectronics/stm32l5xx_hal_driver.git
[submodule "hw/mcu/st/cmsis_device_wb"]
path = hw/mcu/st/cmsis_device_wb
url = https://github.com/STMicroelectronics/cmsis_device_wb.git
[submodule "hw/mcu/st/stm32wbxx_hal_driver"]
path = hw/mcu/st/stm32wbxx_hal_driver
url = https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git
[submodule "lib/sct_neopixel"] [submodule "lib/sct_neopixel"]
path = lib/sct_neopixel path = lib/sct_neopixel
url = https://github.com/gsteiert/sct_neopixel url = https://github.com/gsteiert/sct_neopixel

View File

@ -42,7 +42,7 @@ Supported MCUs
+--------------+---------+-------------+--------+------+-----------+-------------------+--------------+ +--------------+---------+-------------+--------+------+-----------+-------------------+--------------+
| NXP | iMXRT | RT10xx | ✔ | ✔ | ✔ | ci_hs | | | NXP | iMXRT | RT10xx | ✔ | ✔ | ✔ | ci_hs | |
| +---------+-------------+--------+------+-----------+-------------------+--------------+ | +---------+-------------+--------+------+-----------+-------------------+--------------+
| | Kinetis | KL25 | ✔ | ⚠ | ✖ | | | | | Kinetis | KL25 | ✔ | ⚠ | ✖ | | |
| | +-------------+--------+------+-----------+-------------------+--------------+ | | +-------------+--------+------+-----------+-------------------+--------------+
| | | K32L2 | ✔ | | ✖ | | | | | | K32L2 | ✔ | | ✖ | | |
| +---------+-------------+--------+------+-----------+-------------------+--------------+ | +---------+-------------+--------+------+-----------+-------------------+--------------+

View File

@ -31,5 +31,5 @@ target_sources(${COMPONENT_TARGET} PUBLIC
"${TOP}/src/class/net/ncm_device.c" "${TOP}/src/class/net/ncm_device.c"
"${TOP}/src/class/usbtmc/usbtmc_device.c" "${TOP}/src/class/usbtmc/usbtmc_device.c"
"${TOP}/src/class/vendor/vendor_device.c" "${TOP}/src/class/vendor/vendor_device.c"
"${TOP}/src/portable/espressif/esp32sx/dcd_esp32sx.c" "${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c"
) )

View File

@ -86,7 +86,7 @@ enum
#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \ #define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
/* Standard Interface Association Descriptor (IAD) */\ /* Standard Interface Association Descriptor (IAD) */\
TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\ TUD_AUDIO_DESC_IAD(/*_firstitfs*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ 3, /*_stridx*/ 0x00),\
/* Standard AC Interface Descriptor(4.7.1) */\ /* Standard AC Interface Descriptor(4.7.1) */\
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\

View File

@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.5)
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
# gets PROJECT name for the example
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
project(${PROJECT})
# Checks this example is valid for the family and initializes the project
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
add_executable(${PROJECT})
# Example source
target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
)
# Example include
target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# Configure compilation flags and libraries for the example... see the corresponding function
# in hw/bsp/FAMILY/family.cmake for details.
family_configure_host_example(${PROJECT})

View File

@ -0,0 +1,27 @@
include ../../../tools/top.mk
include ../../make.mk
INC += \
src \
$(TOP)/hw \
# Example source
EXAMPLE_SOURCE += \
src/main.c
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
# TODO: suppress warning caused by host stack
CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
# TinyUSB Host Stack source
SRC_C += \
src/class/cdc/cdc_host.c \
src/class/hid/hid_host.c \
src/class/msc/msc_host.c \
src/host/hub.c \
src/host/usbh.c \
src/portable/ohci/ohci.c \
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
include ../../rules.mk

View File

@ -0,0 +1,9 @@
mcu:LPC175X_6X
mcu:LPC177X_8X
mcu:LPC18XX
mcu:LPC40XX
mcu:LPC43XX
mcu:MIMXRT10XX
mcu:RP2040
mcu:MSP432E4
mcu:RX65X

View File

@ -0,0 +1,416 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
/* This example current worked and tested with following controller
* - Sony DualShock 4 [CUH-ZCT2x] VID = 0x054c, PID = 0x09cc
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "bsp/board.h"
#include "tusb.h"
// English
#define LANGUAGE_ID 0x0409
#define BUF_COUNT 4
tusb_desc_device_t desc_device;
uint8_t buf_pool[BUF_COUNT][64];
uint8_t buf_owner[BUF_COUNT] = { 0 }; // device address that owns buffer
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
void led_blinking_task(void);
static void print_utf16(uint16_t *temp_buf, size_t buf_len);
void print_device_descriptor(tuh_xfer_t* xfer);
void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
uint8_t* get_hid_buf(uint8_t daddr);
void free_hid_buf(uint8_t daddr);
/*------------- MAIN -------------*/
int main(void)
{
board_init();
printf("TinyUSB Host HID Controller Example\r\n");
tusb_init();
while (1)
{
// tinyusb host task
tuh_task();
led_blinking_task();
}
return 0;
}
/*------------- TinyUSB Callbacks -------------*/
// Invoked when device is mounted (configured)
void tuh_mount_cb (uint8_t daddr)
{
printf("Device attached, address = %d\r\n", daddr);
// Get Device Descriptor sync API
// TODO: invoking control trannsfer now has issue with mounting hub with multiple devices attached, fix later
tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
}
/// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t daddr)
{
printf("Device removed, address = %d\r\n", daddr);
free_hid_buf(daddr);
}
//--------------------------------------------------------------------+
// Device Descriptor
//--------------------------------------------------------------------+
void print_device_descriptor(tuh_xfer_t* xfer)
{
if ( XFER_RESULT_SUCCESS != xfer->result )
{
printf("Failed to get device descriptor\r\n");
return;
}
uint8_t const daddr = xfer->daddr;
printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
printf("Device Descriptor:\r\n");
printf(" bLength %u\r\n" , desc_device.bLength);
printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
// Get String descriptor using Sync API
uint16_t temp_buf[128];
printf(" iManufacturer %u " , desc_device.iManufacturer);
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
{
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
printf("\r\n");
printf(" iProduct %u " , desc_device.iProduct);
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
{
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
printf("\r\n");
printf(" iSerialNumber %u " , desc_device.iSerialNumber);
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
{
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
}
printf("\r\n");
printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
// Get configuration descriptor with sync API
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_configuration_sync(daddr, 0, temp_buf, sizeof(temp_buf)))
{
parse_config_descriptor(daddr, (tusb_desc_configuration_t*) temp_buf);
}
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
// count total length of an interface
uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
// simple configuration parser to open and listen to HID Endpoint IN
void parse_config_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
{
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
uint8_t const* p_desc = tu_desc_next(desc_cfg);
// parse each interfaces
while( p_desc < desc_end )
{
uint8_t assoc_itf_count = 1;
// Class will always starts with Interface Association (if any) and then Interface descriptor
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
{
tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
assoc_itf_count = desc_iad->bInterfaceCount;
p_desc = tu_desc_next(p_desc); // next to Interface
}
// must be interface from now
if( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) return;
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
uint16_t const drv_len = count_interface_total_len(desc_itf, assoc_itf_count, desc_end-p_desc);
// probably corrupted descriptor
if(drv_len < sizeof(tusb_desc_interface_t)) return;
// only open and listen to HID endpoint IN
if (desc_itf->bInterfaceClass == TUSB_CLASS_HID)
{
open_hid_interface(dev_addr, desc_itf, drv_len);
}
// next Interface or IAD descriptor
p_desc += drv_len;
}
}
uint16_t count_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
{
uint8_t const* p_desc = (uint8_t const*) desc_itf;
uint16_t len = 0;
while (itf_count--)
{
// Next on interface desc
len += tu_desc_len(desc_itf);
p_desc = tu_desc_next(p_desc);
while (len < max_len)
{
// return on IAD regardless of itf count
if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
{
break;
}
len += tu_desc_len(p_desc);
p_desc = tu_desc_next(p_desc);
}
}
return len;
}
//--------------------------------------------------------------------+
// HID Interface
//--------------------------------------------------------------------+
void hid_report_received(tuh_xfer_t* xfer);
void open_hid_interface(uint8_t daddr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{
// len = interface + hid + n*endpoints
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
// corrupted descriptor
if (max_len < drv_len) return;
uint8_t const *p_desc = (uint8_t const *) desc_itf;
// HID descriptor
p_desc = tu_desc_next(p_desc);
tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
if(HID_DESC_TYPE_HID != desc_hid->bDescriptorType) return;
// Endpoint descriptor
p_desc = tu_desc_next(p_desc);
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
for(int i = 0; i < desc_itf->bNumEndpoints; i++)
{
if (TUSB_DESC_ENDPOINT != desc_ep->bDescriptorType) return;
if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
{
// skip if failed to open endpoint
if ( ! tuh_edpt_open(daddr, desc_ep) ) return;
uint8_t* buf = get_hid_buf(daddr);
if (!buf) return; // out of memory
tuh_xfer_t xfer =
{
.daddr = daddr,
.ep_addr = desc_ep->bEndpointAddress,
.buflen = 64,
.buffer = buf,
.complete_cb = hid_report_received,
.user_data = (uintptr_t) buf, // since buffer is not available in callback, use user data to store the buffer
};
// submit transfer for this EP
tuh_edpt_xfer(&xfer);
printf("Listen to [dev %u: ep %02x]\r\n", daddr, desc_ep->bEndpointAddress);
}
p_desc = tu_desc_next(p_desc);
desc_ep = (tusb_desc_endpoint_t const *) p_desc;
}
}
void hid_report_received(tuh_xfer_t* xfer)
{
// Note: not all field in xfer is available for use (i.e filled by tinyusb stack) in callback to save sram
// For instance, xfer->buffer is NULL. We have used user_data to store buffer when submitted callback
uint8_t* buf = (uint8_t*) xfer->user_data;
if (xfer->result == XFER_RESULT_SUCCESS)
{
printf("[dev %u: ep %02x] HID Report:", xfer->daddr, xfer->ep_addr);
for(uint32_t i=0; i<xfer->actual_len; i++)
{
if (i%16 == 0) printf("\r\n ");
printf("%02X ", buf[i]);
}
printf("\r\n");
}
// continue to submit transfer, with updated buffer
// other field remain the same
xfer->buflen = 64;
xfer->buffer = buf;
tuh_edpt_xfer(xfer);
}
//--------------------------------------------------------------------+
// Buffer helper
//--------------------------------------------------------------------+
// get an buffer from pool
uint8_t* get_hid_buf(uint8_t daddr)
{
for(size_t i=0; i<BUF_COUNT; i++)
{
if (buf_owner[i] == 0)
{
buf_owner[i] = daddr;
return buf_pool[i];
}
}
// out of memory, increase BUF_COUNT
return NULL;
}
// free all buffer owned by device
void free_hid_buf(uint8_t daddr)
{
for(size_t i=0; i<BUF_COUNT; i++)
{
if (buf_owner[i] == daddr) buf_owner[i] = 0;
}
}
//--------------------------------------------------------------------+
// Blinking Task
//--------------------------------------------------------------------+
void led_blinking_task(void)
{
const uint32_t interval_ms = 1000;
static uint32_t start_ms = 0;
static bool led_state = false;
// Blink every interval ms
if ( board_millis() - start_ms < interval_ms) return; // not enough time
start_ms += interval_ms;
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
//--------------------------------------------------------------------+
// String Descriptor Helper
//--------------------------------------------------------------------+
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
// TODO: Check for runover.
(void)utf8_len;
// Get the UTF-16 length out of the data itself.
for (size_t i = 0; i < utf16_len; i++) {
uint16_t chr = utf16[i];
if (chr < 0x80) {
*utf8++ = chr & 0xff;
} else if (chr < 0x800) {
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
} else {
// TODO: Verify surrogate.
*utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
}
// TODO: Handle UTF-16 code points that take two entries.
}
}
// Count how many bytes a utf-16-le encoded string will take in utf-8.
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
size_t total_bytes = 0;
for (size_t i = 0; i < len; i++) {
uint16_t chr = buf[i];
if (chr < 0x80) {
total_bytes += 1;
} else if (chr < 0x800) {
total_bytes += 2;
} else {
total_bytes += 3;
}
// TODO: Handle UTF-16 code points that take two entries.
}
return total_bytes;
}
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
((uint8_t*) temp_buf)[utf8_len] = '\0';
printf((char*)temp_buf);
}

View File

@ -0,0 +1,94 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#ifndef _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
// defined by compiler flags for flexibility
#ifndef CFG_TUSB_MCU
#error CFG_TUSB_MCU must be defined
#endif
#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
#else
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_HOST
#endif
#ifndef CFG_TUSB_OS
#define CFG_TUSB_OS OPT_OS_NONE
#endif
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
// #define CFG_TUSB_DEBUG 0
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
* Tinyusb use follows macros to declare transferring memory so that they can be put
* into those specific section.
* e.g
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
*/
#ifndef CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_SECTION
#endif
#ifndef CFG_TUSB_MEM_ALIGN
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
#endif
//--------------------------------------------------------------------
// CONFIGURATION
//--------------------------------------------------------------------
// Size of buffer to hold descriptors and other data used for enumeration
#define CFG_TUH_ENUMERATION_BUFSIZE 256
// only hub class is enabled
#define CFG_TUH_HUB 1
// max device support (excluding hub device)
// 1 hub typically has 4 ports
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1)
// Max endpoint per device
#define CFG_TUH_ENDPOINT_MAX 8
// Enable tuh_edpt_xfer() API
#define CFG_TUH_API_EDPT_XFER 1
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

View File

@ -19,7 +19,6 @@ SRC_C += \
src/class/msc/msc_host.c \ src/class/msc/msc_host.c \
src/host/hub.c \ src/host/hub.c \
src/host/usbh.c \ src/host/usbh.c \
src/host/usbh_control.c \
src/portable/ohci/ohci.c \ src/portable/ohci/ohci.c \
src/portable/nxp/lpc17_40/hcd_lpc17_40.c src/portable/nxp/lpc17_40/hcd_lpc17_40.c

View File

@ -71,20 +71,6 @@ int main(void)
#if CFG_TUH_CDC #if CFG_TUH_CDC
CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 }; CFG_TUSB_MEM_SECTION static char serial_in_buffer[64] = { 0 };
void tuh_mount_cb(uint8_t dev_addr)
{
// application set-up
printf("A device with address %d is mounted\r\n", dev_addr);
tuh_cdc_receive(dev_addr, serial_in_buffer, sizeof(serial_in_buffer), true); // schedule first transfer
}
void tuh_umount_cb(uint8_t dev_addr)
{
// application tear-down
printf("A device with address %d is unmounted \r\n", dev_addr);
}
// invoked ISR context // invoked ISR context
void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes) void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_id, uint32_t xferred_bytes)
{ {
@ -109,6 +95,19 @@ void cdc_task(void)
// TinyUSB Callbacks // TinyUSB Callbacks
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void tuh_mount_cb(uint8_t dev_addr)
{
// application set-up
printf("A device with address %d is mounted\r\n", dev_addr);
}
void tuh_umount_cb(uint8_t dev_addr)
{
// application tear-down
printf("A device with address %d is unmounted \r\n", dev_addr);
}
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Blinking Task // Blinking Task
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -22,7 +22,6 @@ SRC_C += \
src/class/msc/msc_host.c \ src/class/msc/msc_host.c \
src/host/hub.c \ src/host/hub.c \
src/host/usbh.c \ src/host/usbh.c \
src/host/usbh_control.c \
src/portable/ohci/ohci.c \ src/portable/ohci/ohci.c \
src/portable/nxp/lpc17_40/hcd_lpc17_40.c src/portable/nxp/lpc17_40/hcd_lpc17_40.c

View File

@ -14,7 +14,6 @@ CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
SRC_C += \ SRC_C += \
src/class/hid/hid_host.c \ src/class/hid/hid_host.c \
src/host/hub.c \ src/host/hub.c \
src/host/usbh.c \ src/host/usbh.c
src/host/usbh_control.c
include ../../rules.mk include ../../rules.mk

View File

@ -83,7 +83,6 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
${TOP}/src/portable/raspberrypi/rp2040/hcd_rp2040.c ${TOP}/src/portable/raspberrypi/rp2040/hcd_rp2040.c
${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c ${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c
${TOP}/src/host/usbh.c ${TOP}/src/host/usbh.c
${TOP}/src/host/usbh_control.c
${TOP}/src/host/hub.c ${TOP}/src/host/hub.c
${TOP}/src/class/cdc/cdc_host.c ${TOP}/src/class/cdc/cdc_host.c
${TOP}/src/class/hid/hid_host.c ${TOP}/src/class/hid/hid_host.c

View File

@ -0,0 +1,122 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022, Jerzy Kasenberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#ifndef BOARD_H_
#define BOARD_H_
#ifdef __cplusplus
extern "C" {
#endif
// LED
#define LED_PORT GPIOB
#define LED_PIN GPIO_PIN_5
#define LED_STATE_ON 1
// Button
#define BUTTON_PORT GPIOC
#define BUTTON_PIN GPIO_PIN_4
#define BUTTON_STATE_ACTIVE 0
// UART Enable for STLink VCOM
#define UART_DEV USART1
#define UART_CLK_EN __HAL_RCC_USART1_CLK_ENABLE
#define UART_GPIO_PORT GPIOB
#define UART_GPIO_AF GPIO_AF7_USART1
#define UART_TX_PIN GPIO_PIN_6
#define UART_RX_PIN GPIO_PIN_7
//--------------------------------------------------------------------+
// RCC Clock
//--------------------------------------------------------------------+
static inline void board_clock_init(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
// Initializes the CPU, AHB and APB busses clocks
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
RCC_OscInitStruct.PLL.PLLN = 24;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV4;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV3;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
// Initializes the CPU, AHB and APB busses clocks
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3);
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) ;
#if 0 // TODO need to check if USB clock is enabled
/* Enable HSI48 */
memset(&RCC_OscInitStruct, 0, sizeof(RCC_OscInitStruct));
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/*Enable CRS Clock*/
RCC_CRSInitTypeDef RCC_CRSInitStruct= {0};
__HAL_RCC_CRS_CLK_ENABLE();
/* Default Synchro Signal division factor (not divided) */
RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;
/* Set the SYNCSRC[1:0] bits according to CRS_Source value */
RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;
/* HSI48 is synchronized with USB SOF at 1KHz rate */
RCC_CRSInitStruct.ReloadValue = __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000, 1000);
RCC_CRSInitStruct.ErrorLimitValue = RCC_CRS_ERRORLIMIT_DEFAULT;
/* Set the TRIM[5:0] to the default value */
RCC_CRSInitStruct.HSI48CalibrationValue = RCC_CRS_HSI48CALIBRATION_DEFAULT;
/* Start automatic synchronization */
HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* BOARD_H_ */

View File

@ -0,0 +1,9 @@
CFLAGS += \
-DSTM32WB55xx
LD_FILE = $(BOARD_PATH)/stm32wb55xx_flash_cm4.ld
SRC_S += $(ST_CMSIS)/Source/Templates/gcc/startup_stm32wb55xx_cm4.s
# For flash-jlink target
JLINK_DEVICE = STM32WB55RG

View File

@ -0,0 +1,171 @@
/**
*****************************************************************************
**
** File : stm32wb55xx_flash_cm4.ld
**
** Abstract : System Workbench Minimal System calls file
**
** For more information about which c-functions
** need which of these lowlevel functions
** please consult the Newlib libc-manual
**
** Environment : System Workbench for MCU
**
** Distribution: The file is distributed “as is,” without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2019 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20030000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x400; /* required amount of heap */
_Min_Stack_Size = 0x1000; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM1 (xrw) : ORIGIN = 0x20000008, LENGTH = 0x2FFF8
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM1 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM1
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
MAPPING_TABLE (NOLOAD) : { *(MAPPING_TABLE) } >RAM_SHARED
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
}

190
hw/bsp/stm32wb/family.c Normal file
View File

@ -0,0 +1,190 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Jerzy Kasenberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "stm32wbxx_hal.h"
#include "bsp/board.h"
#include "board.h"
//--------------------------------------------------------------------+
// Forward USB interrupt events to TinyUSB IRQ Handler
//--------------------------------------------------------------------+
void USB_HP_IRQHandler(void)
{
tud_int_handler(0);
}
void USB_LP_IRQHandler(void)
{
tud_int_handler(0);
}
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+
UART_HandleTypeDef UartHandle;
void board_init(void)
{
board_clock_init();
// Enable All GPIOs clocks
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
UART_CLK_EN();
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
SysTick_Config(SystemCoreClock / 1000);
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
// Explicitly disable systick to prevent its ISR runs before scheduler start
SysTick->CTRL &= ~1U;
// If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
NVIC_SetPriority(OTG_FS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
#endif
GPIO_InitTypeDef GPIO_InitStruct;
// LED
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
#if 0
// MCO configuration for System clock value verification PA8 will have SYSCLK / 2
GPIO_InitStruct.Pin = 8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_2);
#endif
board_led_write(false);
// Button
GPIO_InitStruct.Pin = BUTTON_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = BUTTON_STATE_ACTIVE ? GPIO_PULLDOWN : GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
#ifdef UART_DEV
// UART
GPIO_InitStruct.Pin = UART_TX_PIN | UART_RX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = UART_GPIO_AF;
HAL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct);
UartHandle = (UART_HandleTypeDef){
.Instance = UART_DEV,
.Init.BaudRate = CFG_BOARD_UART_BAUDRATE,
.Init.WordLength = UART_WORDLENGTH_8B,
.Init.StopBits = UART_STOPBITS_1,
.Init.Parity = UART_PARITY_NONE,
.Init.HwFlowCtl = UART_HWCONTROL_NONE,
.Init.Mode = UART_MODE_TX_RX,
.Init.OverSampling = UART_OVERSAMPLING_16
};
HAL_UART_Init(&UartHandle);
#endif
// USB Pins TODO double check USB clock and pin setup
// Configure USB DM and DP pins. This is optional, and maintained only for user guidance.
GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_PWREx_EnableVddUSB();
__HAL_RCC_USB_CLK_ENABLE();
}
//--------------------------------------------------------------------+
// Board porting API
//--------------------------------------------------------------------+
void board_led_write(bool state)
{
HAL_GPIO_WritePin(LED_PORT, LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON));
}
uint32_t board_button_read(void)
{
return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);
}
int board_uart_read(uint8_t* buf, int len)
{
(void) buf; (void) len;
return 0;
}
int board_uart_write(void const * buf, int len)
{
#ifdef UART_DEV
HAL_UART_Transmit(&UartHandle, (uint8_t*)(uintptr_t) buf, len, 0xffff);
return len;
#else
(void) buf; (void) len; (void) UartHandle;
return 0;
#endif
}
#if CFG_TUSB_OS == OPT_OS_NONE
volatile uint32_t system_ticks = 0;
void SysTick_Handler (void)
{
system_ticks++;
}
uint32_t board_millis(void)
{
return system_ticks;
}
#endif
void HardFault_Handler (void)
{
asm("bkpt");
}
// Required by __libc_init_array in startup code if we are compiling using
// -nostdlib/-nostartfiles.
void _init(void)
{
}

44
hw/bsp/stm32wb/family.mk Normal file
View File

@ -0,0 +1,44 @@
UF2_FAMILY_ID = 0x70d16653
ST_FAMILY = wb
DEPS_SUBMODULES += lib/CMSIS_5 hw/mcu/st/cmsis_device_$(ST_FAMILY) hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY)
ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver
include $(TOP)/$(BOARD_PATH)/board.mk
CFLAGS += \
-flto \
-mthumb \
-mabi=aapcs \
-mcpu=cortex-m4 \
-mfloat-abi=hard \
-mfpu=fpv4-sp-d16 \
-nostdlib -nostartfiles \
-DCFG_TUSB_MCU=OPT_MCU_STM32WB
# suppress warning caused by vendor mcu driver
CFLAGS += -Wno-error=cast-align -Wno-unused-parameter
SRC_C += \
src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \
$(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_pwr_ex.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc_ex.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_uart.c \
$(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_gpio.c
INC += \
$(TOP)/$(BOARD_PATH) \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
$(TOP)/$(ST_CMSIS)/Include \
$(TOP)/$(ST_HAL_DRIVER)/Inc
# For freeRTOS port source
FREERTOS_PORT = ARM_CM4F
# flash target using on-board stlink
flash: flash-stlink

View File

@ -0,0 +1,349 @@
/**
******************************************************************************
* @file stm32wbxx_hal_conf.h
* @author MCD Application Team
* @brief HAL configuration file.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32WBxx_HAL_CONF_H
#define __STM32WBxx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
/*#define HAL_ADC_MODULE_ENABLED */
/*#define HAL_COMP_MODULE_ENABLED */
/*#define HAL_CRC_MODULE_ENABLED */
/*#define HAL_HSEM_MODULE_ENABLED */
/*#define HAL_IPCC_MODULE_ENABLED */
/*#define HAL_IRDA_MODULE_ENABLED */
/*#define HAL_LCD_MODULE_ENABLED */
/*#define HAL_LPTIM_MODULE_ENABLED */
/*#define HAL_PCD_MODULE_ENABLED */
/*#define HAL_PKA_MODULE_ENABLED */
/*#define HAL_QSPI_MODULE_ENABLED */
#define HAL_RTC_MODULE_ENABLED
/*#define HAL_SAI_MODULE_ENABLED */
/*#define HAL_SMBUS_MODULE_ENABLED */
/*#define HAL_SMARTCARD_MODULE_ENABLED */
/*#define HAL_TSC_MODULE_ENABLED */
#define HAL_UART_MODULE_ENABLED
/*#define HAL_USART_MODULE_ENABLED */
/*#define HAL_WWDG_MODULE_ENABLED */
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_IWDG_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_RNG_MODULE_ENABLED
/*#define HAL_CRYP_MODULE_ENABLED */
#define USE_HAL_ADC_REGISTER_CALLBACKS 0u
#define USE_HAL_COMP_REGISTER_CALLBACKS 0u
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0u
#define USE_HAL_I2C_REGISTER_CALLBACKS 0u
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0u
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0u
#define USE_HAL_PCD_REGISTER_CALLBACKS 0u
#define USE_HAL_PKA_REGISTER_CALLBACKS 0u
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0u
#define USE_HAL_RNG_REGISTER_CALLBACKS 0u
#define USE_HAL_RTC_REGISTER_CALLBACKS 0u
#define USE_HAL_SAI_REGISTER_CALLBACKS 0u
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0u
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0u
#define USE_HAL_SPI_REGISTER_CALLBACKS 0u
#define USE_HAL_TIM_REGISTER_CALLBACKS 0u
#define USE_HAL_TSC_REGISTER_CALLBACKS 0u
#define USE_HAL_UART_REGISTER_CALLBACKS 0u
#define USE_HAL_USART_REGISTER_CALLBACKS 0u
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0u
/* ########################## Oscillator Values adaptation ####################*/
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE 32000000U /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT ((uint32_t)100) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal Multiple Speed oscillator (MSI) default value.
* This value is the default MSI range value after Reset.
*/
#if !defined (MSI_VALUE)
#define MSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* MSI_VALUE */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE 16000000U /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @brief Internal Low Speed oscillator (LSI1) value.
*/
#if !defined (LSI1_VALUE)
#define LSI1_VALUE ((uint32_t)32000) /*!< LSI1 Typical Value in Hz*/
#endif /* LSI1_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature.*/
/**
* @brief Internal Low Speed oscillator (LSI2) value.
*/
#if !defined (LSI2_VALUE)
#define LSI2_VALUE ((uint32_t)32000) /*!< LSI2 Typical Value in Hz*/
#endif /* LSI2_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature.*/
/**
* @brief External Low Speed oscillator (LSE) value.
* This value is used by the UART, RTC HAL module to compute the system frequency
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE 32768U /*!< Value of the External oscillator in Hz*/
#endif /* LSE_VALUE */
/**
* @brief Internal Multiple Speed oscillator (HSI48) default value.
* This value is the default HSI48 range value after Reset.
*/
#if !defined (HSI48_VALUE)
#define HSI48_VALUE ((uint32_t)48000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI48_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief External clock source for SAI1 peripheral
* This value is used by the RCC HAL module to compute the SAI1 & SAI2 clock source
* frequency.
*/
#if !defined (EXTERNAL_SAI1_CLOCK_VALUE)
#define EXTERNAL_SAI1_CLOCK_VALUE ((uint32_t)2097000) /*!< Value of the SAI1 External clock source in Hz*/
#endif /* EXTERNAL_SAI1_CLOCK_VALUE */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE 3300U /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY 0U /*!< tick interrupt priority */
#define USE_RTOS 0U
#define PREFETCH_ENABLE 1
#define INSTRUCTION_CACHE_ENABLE 1
#define DATA_CACHE_ENABLE 1
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* ################## SPI peripheral configuration ########################## */
/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver
* Activated: CRC code is present inside driver
* Deactivated: CRC code cleaned from driver
*/
#define USE_SPI_CRC 0U
/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32wbxx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32wbxx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_COMP_MODULE_ENABLED
#include "stm32wbxx_hal_comp.h"
#endif /* HAL_COMP_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32wbxx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32wbxx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_CRYP_MODULE_ENABLED
#include "stm32wbxx_hal_cryp.h"
#endif /* HAL_CRYP_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32wbxx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32wbxx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_HSEM_MODULE_ENABLED
#include "stm32wbxx_hal_hsem.h"
#endif /* HAL_HSEM_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32wbxx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_IPCC_MODULE_ENABLED
#include "stm32wbxx_hal_ipcc.h"
#endif /* HAL_IPCC_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32wbxx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32wbxx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_LCD_MODULE_ENABLED
#include "stm32wbxx_hal_lcd.h"
#endif /* HAL_LCD_MODULE_ENABLED */
#ifdef HAL_LPTIM_MODULE_ENABLED
#include "stm32wbxx_hal_lptim.h"
#endif /* HAL_LPTIM_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32wbxx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
#ifdef HAL_PKA_MODULE_ENABLED
#include "stm32wbxx_hal_pka.h"
#endif /* HAL_PKA_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32wbxx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_QSPI_MODULE_ENABLED
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U
#include "stm32wbxx_hal_qspi.h"
#endif /* HAL_QSPI_MODULE_ENABLED */
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32wbxx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_RNG_MODULE_ENABLED
#include "stm32wbxx_hal_rng.h"
#endif /* HAL_RNG_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32wbxx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_SAI_MODULE_ENABLED
#include "stm32wbxx_hal_sai.h"
#endif /* HAL_SAI_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32wbxx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32wbxx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32wbxx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32wbxx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_TSC_MODULE_ENABLED
#include "stm32wbxx_hal_tsc.h"
#endif /* HAL_TSC_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32wbxx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32wbxx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32wbxx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* __STM32WBxx_HAL_CONF_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

@ -0,0 +1 @@
Subproject commit 9c5d1920dd9fabbe2548e10561d63db829bb744f

@ -0,0 +1 @@
Subproject commit 2c5f06638be516c1b772f768456ba637f077bac8

View File

@ -9,7 +9,9 @@ repo.versions:
"0.10.0": "0.10.0" "0.10.0": "0.10.0"
"0.10.1": "0.10.1" "0.10.1": "0.10.1"
"0.11.0": "0.11.0" "0.11.0": "0.11.0"
"0.12.0": "0.12.0"
"0.13.0": "0.13.0"
"0-dev": "0.0.0" # master "0-dev": "0.0.0" # master
"0-latest": "0.11.0" # latest stable release "0-latest": "0.13.0" # latest stable release

View File

@ -100,7 +100,7 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i
{ {
(void) is_notify; (void) is_notify;
TU_VERIFY( tuh_cdc_mounted(dev_addr) ); TU_VERIFY( tuh_cdc_mounted(dev_addr) );
TU_VERIFY( p_data != NULL && length, TUSB_ERROR_INVALID_PARA); TU_VERIFY( p_data != NULL && length);
uint8_t const ep_out = cdch_data[dev_addr-1].ep_out; uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
if ( usbh_edpt_busy(dev_addr, ep_out) ) return false; if ( usbh_edpt_busy(dev_addr, ep_out) ) return false;
@ -112,7 +112,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is
{ {
(void) is_notify; (void) is_notify;
TU_VERIFY( tuh_cdc_mounted(dev_addr) ); TU_VERIFY( tuh_cdc_mounted(dev_addr) );
TU_VERIFY( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA); TU_VERIFY( p_buffer != NULL && length );
uint8_t const ep_in = cdch_data[dev_addr-1].ep_in; uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
if ( usbh_edpt_busy(dev_addr, ep_in) ) return false; if ( usbh_edpt_busy(dev_addr, ep_in) ) return false;
@ -120,9 +120,10 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is
return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, length); return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, length);
} }
bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb) bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb)
{ {
cdch_data_t const * p_cdc = get_itf(dev_addr); cdch_data_t const * p_cdc = get_itf(dev_addr);
tusb_control_request_t const request = tusb_control_request_t const request =
{ {
.bmRequestType_bit = .bmRequestType_bit =
@ -137,8 +138,17 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_co
.wLength = 0 .wLength = 0
}; };
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, complete_cb) ); tuh_xfer_t xfer =
return true; {
.daddr = dev_addr,
.ep_addr = 0,
.setup = &request,
.buffer = NULL,
.complete_cb = complete_cb,
.user_data = 0
};
return tuh_control_xfer(&xfer);
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -151,6 +161,7 @@ void cdch_init(void)
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{ {
(void) rhport;
(void) max_len; (void) max_len;
// Only support ACM subclass // Only support ACM subclass
@ -186,7 +197,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
// notification endpoint // notification endpoint
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) ); TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
p_cdc->ep_notif = desc_ep->bEndpointAddress; p_cdc->ep_notif = desc_ep->bEndpointAddress;
drv_len += tu_desc_len(p_desc); drv_len += tu_desc_len(p_desc);
@ -207,7 +218,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc; tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer); TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep)); TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN ) if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
{ {

View File

@ -42,14 +42,14 @@
* \defgroup CDC_Serial_Host Host * \defgroup CDC_Serial_Host Host
* @{ */ * @{ */
bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb); bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_xfer_cb_t complete_cb);
static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb) static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
{ {
return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb);
} }
static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb) static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_xfer_cb_t complete_cb)
{ {
return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb);
} }

View File

@ -50,7 +50,7 @@ typedef struct {
}rndish_data_t; }rndish_data_t;
void rndish_init(void); void rndish_init(void);
tusb_error_t rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc); bool rndish_open_subtask(uint8_t dev_addr, cdch_data_t *p_cdc);
void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes); void rndish_xfer_isr(cdch_data_t *p_cdc, pipe_handle_t pipe_hdl, xfer_result_t event, uint32_t xferred_bytes);
void rndish_close(uint8_t dev_addr); void rndish_close(uint8_t dev_addr);

View File

@ -43,7 +43,7 @@
/** \defgroup ClassDriver_HID_Common Common Definitions /** \defgroup ClassDriver_HID_Common Common Definitions
* @{ */ * @{ */
/// USB HID Descriptor /// USB HID Descriptor
typedef struct TU_ATTR_PACKED typedef struct TU_ATTR_PACKED
{ {
uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */ uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */

View File

@ -103,27 +103,27 @@ uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
return hid_itf->protocol_mode; return hid_itf->protocol_mode;
} }
static bool set_protocol_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void set_protocol_complete(tuh_xfer_t* xfer)
{ {
uint8_t const itf_num = (uint8_t) request->wIndex; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); uint8_t const daddr = xfer->daddr;
hidh_interface_t* hid_itf = get_instance(dev_addr, instance); uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num);
hidh_interface_t* hid_itf = get_instance(daddr, instance);
if (XFER_RESULT_SUCCESS == result) hid_itf->protocol_mode = (uint8_t) request->wValue; if (XFER_RESULT_SUCCESS == xfer->result)
{
hid_itf->protocol_mode = (uint8_t) tu_le16toh(xfer->setup->wValue);
}
if (tuh_hid_set_protocol_complete_cb) if (tuh_hid_set_protocol_complete_cb)
{ {
tuh_hid_set_protocol_complete_cb(dev_addr, instance, hid_itf->protocol_mode); tuh_hid_set_protocol_complete_cb(daddr, instance, hid_itf->protocol_mode);
} }
return true;
} }
bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
{
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
static bool _hidh_set_protocol(uint8_t dev_addr, uint8_t itf_num, uint8_t protocol, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
TU_LOG2("HID Set Protocol = %d\r\n", protocol); TU_LOG2("HID Set Protocol = %d\r\n", protocol);
tusb_control_request_t const request = tusb_control_request_t const request =
@ -136,30 +136,47 @@ bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
}, },
.bRequest = HID_REQ_CONTROL_SET_PROTOCOL, .bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
.wValue = protocol, .wValue = protocol,
.wIndex = hid_itf->itf_num, .wIndex = itf_num,
.wLength = 0 .wLength = 0
}; };
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, set_protocol_complete) ); tuh_xfer_t xfer =
{
.daddr = dev_addr,
.ep_addr = 0,
.setup = &request,
.buffer = NULL,
.complete_cb = complete_cb,
.user_data = user_data
};
TU_ASSERT( tuh_control_xfer(&xfer) );
return true; return true;
} }
static bool set_report_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol)
{
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
TU_VERIFY(hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE);
return _hidh_set_protocol(dev_addr, hid_itf->itf_num, protocol, set_protocol_complete, 0);
}
static void set_report_complete(tuh_xfer_t* xfer)
{ {
TU_LOG2("HID Set Report complete\r\n"); TU_LOG2("HID Set Report complete\r\n");
if (tuh_hid_set_report_complete_cb) if (tuh_hid_set_report_complete_cb)
{ {
uint8_t const itf_num = (uint8_t) request->wIndex; uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); uint8_t const instance = get_instance_id_by_itfnum(xfer->daddr, itf_num);
uint8_t const report_type = tu_u16_high(request->wValue); uint8_t const report_type = tu_u16_high(xfer->setup->wValue);
uint8_t const report_id = tu_u16_low(request->wValue); uint8_t const report_id = tu_u16_low(xfer->setup->wValue);
tuh_hid_set_report_complete_cb(dev_addr, instance, report_id, report_type, (result == XFER_RESULT_SUCCESS) ? request->wLength : 0); tuh_hid_set_report_complete_cb(xfer->daddr, instance, report_id, report_type,
(xfer->result == XFER_RESULT_SUCCESS) ? xfer->setup->wLength : 0);
} }
return true;
} }
bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len) bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t report_type, void* report, uint16_t len)
@ -181,7 +198,50 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u
.wLength = len .wLength = len
}; };
TU_ASSERT( tuh_control_xfer(dev_addr, &request, report, set_report_complete) ); tuh_xfer_t xfer =
{
.daddr = dev_addr,
.ep_addr = 0,
.setup = &request,
.buffer = report,
.complete_cb = set_report_complete,
.user_data = 0
};
TU_ASSERT( tuh_control_xfer(&xfer) );
return true;
}
static bool _hidh_set_idle(uint8_t dev_addr, uint8_t itf_num, uint16_t idle_rate, tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
// SET IDLE request, device can stall if not support this request
TU_LOG2("HID Set Idle \r\n");
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
},
.bRequest = HID_REQ_CONTROL_SET_IDLE,
.wValue = idle_rate,
.wIndex = itf_num,
.wLength = 0
};
tuh_xfer_t xfer =
{
.daddr = dev_addr,
.ep_addr = 0,
.setup = &request,
.buffer = NULL,
.complete_cb = complete_cb,
.user_data = user_data
};
TU_ASSERT( tuh_control_xfer(&xfer) );
return true; return true;
} }
@ -196,7 +256,13 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
// claim endpoint // claim endpoint
TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) ); TU_VERIFY( usbh_edpt_claim(dev_addr, hid_itf->ep_in) );
return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size); if ( !usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size) )
{
usbh_edpt_claim(dev_addr, hid_itf->ep_in);
return false;
}
return true;
} }
//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance) //bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
@ -256,14 +322,9 @@ void hidh_close(uint8_t dev_addr)
// Enumeration // Enumeration
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static bool config_set_protocol (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{ {
(void) rhport;
(void) max_len; (void) max_len;
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass); TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
@ -286,28 +347,35 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
hidh_device_t* hid_dev = get_dev(dev_addr); hidh_device_t* hid_dev = get_dev(dev_addr);
TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0); TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
//------------- Endpoint Descriptor -------------// hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
//------------- Endpoint Descriptors -------------//
p_desc = tu_desc_next(p_desc); p_desc = tu_desc_next(p_desc);
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc; tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
// first endpoint may be OUT, skip to IN endpoint for(int i = 0; i < desc_itf->bNumEndpoints; i++)
// TODO also open endpoint OUT
if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT)
{ {
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
TU_ASSERT( tuh_edpt_open(dev_addr, desc_ep) );
if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
{
hid_itf->ep_in = desc_ep->bEndpointAddress;
hid_itf->epin_size = tu_edpt_packet_size(desc_ep);
}
else
{
hid_itf->ep_out = desc_ep->bEndpointAddress;
hid_itf->epout_size = tu_edpt_packet_size(desc_ep);
}
p_desc = tu_desc_next(p_desc); p_desc = tu_desc_next(p_desc);
desc_ep = (tusb_desc_endpoint_t const *) p_desc; desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
} }
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
hid_dev->inst_count++; hid_dev->inst_count++;
hid_itf->itf_num = desc_itf->bInterfaceNumber; hid_itf->itf_num = desc_itf->bInterfaceNumber;
hid_itf->ep_in = desc_ep->bEndpointAddress;
hid_itf->epin_size = tu_edpt_packet_size(desc_ep);
// Assume bNumDescriptors = 1 // Assume bNumDescriptors = 1
hid_itf->report_desc_type = desc_hid->bReportType; hid_itf->report_desc_type = desc_hid->bReportType;
@ -320,122 +388,93 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
return true; return true;
} }
//--------------------------------------------------------------------+
// Set Configure
//--------------------------------------------------------------------+
enum {
CONFG_SET_IDLE,
CONFIG_SET_PROTOCOL,
CONFIG_GET_REPORT_DESC,
CONFIG_COMPLETE
};
static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
static void process_set_config(tuh_xfer_t* xfer);
bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
{ {
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); tusb_control_request_t request;
hidh_interface_t* hid_itf = get_instance(dev_addr, instance); request.wIndex = tu_htole16((uint16_t) itf_num);
// Idle rate = 0 mean only report when there is changes tuh_xfer_t xfer;
uint16_t const idle_rate = 0; xfer.daddr = dev_addr;
xfer.result = XFER_RESULT_SUCCESS;
xfer.setup = &request;
xfer.user_data = CONFG_SET_IDLE;
// SET IDLE request, device can stall if not support this request // fake request to kick-off the set config process
TU_LOG2("HID Set Idle \r\n"); process_set_config(&xfer);
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
},
.bRequest = HID_REQ_CONTROL_SET_IDLE,
.wValue = idle_rate,
.wIndex = itf_num,
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
return true; return true;
} }
// Force device to work in BOOT protocol static void process_set_config(tuh_xfer_t* xfer)
static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{ {
// Stall is a valid response for SET_IDLE, therefore we could ignore its result // Stall is a valid response for SET_IDLE, therefore we could ignore its result
(void) result; if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE )
uint8_t const itf_num = (uint8_t) request->wIndex;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
TU_LOG2("HID Set Protocol to Boot Mode\r\n");
hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
tusb_control_request_t const new_request =
{ {
.bmRequestType_bit = TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
{
.recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_CLASS,
.direction = TUSB_DIR_OUT
},
.bRequest = HID_REQ_CONTROL_SET_PROTOCOL,
.wValue = HID_PROTOCOL_BOOT,
.wIndex = hid_itf->itf_num,
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_get_report_desc) );
return true;
}
static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
// We can be here after SET_IDLE or SET_PROTOCOL (boot device)
// Trigger assert if result is not successful with set protocol
if ( request->bRequest != HID_REQ_CONTROL_SET_IDLE )
{
TU_ASSERT(result == XFER_RESULT_SUCCESS);
} }
uint8_t const itf_num = (uint8_t) request->wIndex; uintptr_t const state = xfer->user_data;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num); uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
hidh_interface_t* hid_itf = get_instance(dev_addr, instance); uint8_t const daddr = xfer->daddr;
// Get Report Descriptor if possible uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num);
// using usbh enumeration buffer since report descriptor can be very long hidh_interface_t* hid_itf = get_instance(daddr, instance);
if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
{
TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
// Driver is mounted without report descriptor switch(state)
config_driver_mount_complete(dev_addr, instance, NULL, 0);
}else
{ {
TU_LOG2("HID Get Report Descriptor\r\n"); case CONFG_SET_IDLE:
tusb_control_request_t const new_request =
{ {
.bmRequestType_bit = // Idle rate = 0 mean only report when there is changes
const uint16_t idle_rate = 0;
const uintptr_t next_state = (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? CONFIG_SET_PROTOCOL : CONFIG_GET_REPORT_DESC;
_hidh_set_idle(daddr, itf_num, idle_rate, process_set_config, next_state);
}
break;
case CONFIG_SET_PROTOCOL:
_hidh_set_protocol(daddr, hid_itf->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC);
break;
case CONFIG_GET_REPORT_DESC:
// Get Report Descriptor if possible
// using usbh enumeration buffer since report descriptor can be very long
if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
{ {
.recipient = TUSB_REQ_RCPT_INTERFACE, TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = tu_u16(hid_itf->report_desc_type, 0),
.wIndex = itf_num,
.wLength = hid_itf->report_desc_len
};
TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete)); // Driver is mounted without report descriptor
config_driver_mount_complete(daddr, instance, NULL, 0);
}else
{
tuh_descriptor_get_hid_report(daddr, itf_num, hid_itf->report_desc_type, 0, usbh_get_enum_buf(), hid_itf->report_desc_len, process_set_config, CONFIG_COMPLETE);
}
break;
case CONFIG_COMPLETE:
{
uint8_t const* desc_report = usbh_get_enum_buf();
uint16_t const desc_len = tu_le16toh(xfer->setup->wLength);
config_driver_mount_complete(daddr, instance, desc_report, desc_len);
}
break;
default: break;
} }
return true;
}
static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
TU_ASSERT(XFER_RESULT_SUCCESS == result);
uint8_t const itf_num = (uint8_t) request->wIndex;
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
uint8_t const* desc_report = usbh_get_enum_buf();
uint16_t const desc_len = request->wLength;
config_driver_mount_complete(dev_addr, instance, desc_report, desc_len);
return true;
} }
static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)

View File

@ -358,13 +358,14 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
// MSC Enumeration // MSC Enumeration
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static void config_get_maxlun_complete (tuh_xfer_t* xfer);
static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len) bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
{ {
(void) rhport;
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass && TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol); MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
@ -378,7 +379,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
for(uint32_t i=0; i<2; i++) for(uint32_t i=0; i<2; i++)
{ {
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc)); TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc));
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN ) if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
{ {
@ -405,7 +406,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
//------------- Get Max Lun -------------// //------------- Get Max Lun -------------//
TU_LOG2("MSC Get Max Lun\r\n"); TU_LOG2("MSC Get Max Lun\r\n");
tusb_control_request_t request = tusb_control_request_t const request =
{ {
.bmRequestType_bit = .bmRequestType_bit =
{ {
@ -418,27 +419,34 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
.wIndex = itf_num, .wIndex = itf_num,
.wLength = 1 .wLength = 1
}; };
TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, config_get_maxlun_complete));
tuh_xfer_t xfer =
{
.daddr = dev_addr,
.ep_addr = 0,
.setup = &request,
.buffer = &p_msc->max_lun,
.complete_cb = config_get_maxlun_complete,
.user_data = 0
};
TU_ASSERT(tuh_control_xfer(&xfer));
return true; return true;
} }
static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void config_get_maxlun_complete (tuh_xfer_t* xfer)
{ {
(void) request; uint8_t const daddr = xfer->daddr;
msch_interface_t* p_msc = get_itf(daddr);
msch_interface_t* p_msc = get_itf(dev_addr);
// STALL means zero // STALL means zero
p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? _msch_buffer[0] : 0; p_msc->max_lun = (XFER_RESULT_SUCCESS == xfer->result) ? _msch_buffer[0] : 0;
p_msc->max_lun++; // MAX LUN is minus 1 by specs p_msc->max_lun++; // MAX LUN is minus 1 by specs
// TODO multiple LUN support // TODO multiple LUN support
TU_LOG2("SCSI Test Unit Ready\r\n"); TU_LOG2("SCSI Test Unit Ready\r\n");
uint8_t const lun = 0; uint8_t const lun = 0;
tuh_msc_test_unit_ready(dev_addr, lun, config_test_unit_ready_complete); tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete);
return true;
} }
static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw)
@ -476,7 +484,7 @@ static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw
// Capacity response field: Block size and Last LBA are both Big-Endian // Capacity response field: Block size and Last LBA are both Big-Endian
scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer); scsi_read_capacity10_resp_t* resp = (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer);
p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1; p_msc->capacity[cbw->lun].block_count = tu_ntohl(resp->last_lba) + 1;
p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size); p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
// Mark enumeration is complete // Mark enumeration is complete
p_msc->mounted = true; p_msc->mounted = true;

View File

@ -113,7 +113,7 @@ void tud_vendor_n_read_flush (uint8_t itf)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Write API // Write API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static bool maybe_transmit(vendord_interface_t* p_itf) static uint16_t maybe_transmit(vendord_interface_t* p_itf)
{ {
// skip if previous transfer not complete // skip if previous transfer not complete
TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_in) ); TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_itf->ep_in) );
@ -123,14 +123,24 @@ static bool maybe_transmit(vendord_interface_t* p_itf)
{ {
TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_in, p_itf->epin_buf, count) ); TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_itf->ep_in, p_itf->epin_buf, count) );
} }
return true; return count;
} }
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize)
{ {
vendord_interface_t* p_itf = &_vendord_itf[itf]; vendord_interface_t* p_itf = &_vendord_itf[itf];
uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize); uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, bufsize);
maybe_transmit(p_itf); if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) {
maybe_transmit(p_itf);
}
return ret;
}
uint32_t tud_vendor_n_flush (uint8_t itf)
{
vendord_interface_t* p_itf = &_vendord_itf[itf];
uint32_t ret = maybe_transmit(p_itf);
return ret; return ret;
} }
@ -247,6 +257,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
} }
else if ( ep_addr == p_itf->ep_in ) else if ( ep_addr == p_itf->ep_in )
{ {
if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, xferred_bytes);
// Send complete, try to send more if possible // Send complete, try to send more if possible
maybe_transmit(p_itf); maybe_transmit(p_itf);
} }

View File

@ -52,6 +52,7 @@ uint32_t tud_vendor_n_write_available (uint8_t itf);
static inline static inline
uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str);
uint32_t tud_vendor_n_flush (uint8_t itf);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Application API (Single Port) // Application API (Single Port)
@ -64,6 +65,7 @@ static inline void tud_vendor_read_flush (void);
static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize);
static inline uint32_t tud_vendor_write_str (char const* str); static inline uint32_t tud_vendor_write_str (char const* str);
static inline uint32_t tud_vendor_write_available (void); static inline uint32_t tud_vendor_write_available (void);
static inline uint32_t tud_vendor_flush (void);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Application Callback API (weak is optional) // Application Callback API (weak is optional)
@ -71,6 +73,8 @@ static inline uint32_t tud_vendor_write_available (void);
// Invoked when received new data // Invoked when received new data
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf); TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf);
// Invoked when last rx transfer finished
TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Inline Functions // Inline Functions
@ -121,6 +125,11 @@ static inline uint32_t tud_vendor_write_available (void)
return tud_vendor_n_write_available(0); return tud_vendor_n_write_available(0);
} }
static inline uint32_t tud_vendor_flush (void)
{
return tud_vendor_n_flush(0);
}
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Internal Class Driver API // Internal Class Driver API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -49,16 +49,16 @@ static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id,
return false; return false;
} }
tusb_error_t tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length); bool tusbh_custom_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length);
tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length); bool tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void const * p_data, uint16_t length);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Internal Class Driver API // Internal Class Driver API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void cush_init(void); void cush_init(void);
tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); bool cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length);
void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event); void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event);
void cush_close(uint8_t dev_addr); void cush_close(uint8_t dev_addr);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -38,6 +38,7 @@
#define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) ) #define TU_MIN(_x, _y) ( ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) ) #define TU_MAX(_x, _y) ( ( (_x) > (_y) ) ? (_x) : (_y) )
#define TU_U16(_high, _low) ((uint16_t) (((_high) << 8) | (_low)))
#define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) #define TU_U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff))
#define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff)) #define TU_U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff))
#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16) #define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16)
@ -70,23 +71,10 @@
#include "tusb_compiler.h" #include "tusb_compiler.h"
#include "tusb_verify.h" #include "tusb_verify.h"
#include "tusb_types.h" #include "tusb_types.h"
#include "tusb_debug.h"
#include "tusb_error.h" // TODO remove
#include "tusb_timeout.h" // TODO remove #include "tusb_timeout.h" // TODO remove
//--------------------------------------------------------------------+
// Internal Helper used by Host and Device Stack
//--------------------------------------------------------------------+
// Check if endpoint descriptor is valid per USB specs
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed);
// Bind all endpoint of a interface descriptor to class driver
void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
// Calculate total length of n interfaces (depending on IAD)
uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Internal Inline Functions // Internal Inline Functions
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -267,138 +255,6 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, ui
+ TU_BIN8(dlsb)) + TU_BIN8(dlsb))
#endif #endif
//--------------------------------------------------------------------+
// Debug Function
//--------------------------------------------------------------------+
// CFG_TUSB_DEBUG for debugging
// 0 : no debug
// 1 : print error
// 2 : print warning
// 3 : print info
#if CFG_TUSB_DEBUG
void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
#ifdef CFG_TUSB_DEBUG_PRINTF
extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...);
#define tu_printf CFG_TUSB_DEBUG_PRINTF
#else
#define tu_printf printf
#endif
static inline
void tu_print_var(uint8_t const* buf, uint32_t bufsize)
{
for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
}
// Log with Level
#define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__)
#define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__)
#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__)
#define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__)
#define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__)
#define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__)
#define TU_LOG_FAILED() tu_printf("%s: %d: Failed\r\n", __PRETTY_FUNCTION__, __LINE__)
// Log Level 1: Error
#define TU_LOG1 tu_printf
#define TU_LOG1_MEM tu_print_mem
#define TU_LOG1_VAR(_x) tu_print_var((uint8_t const*)(_x), sizeof(*(_x)))
#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) )
#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) )
// Log Level 2: Warn
#if CFG_TUSB_DEBUG >= 2
#define TU_LOG2 TU_LOG1
#define TU_LOG2_MEM TU_LOG1_MEM
#define TU_LOG2_VAR TU_LOG1_VAR
#define TU_LOG2_INT TU_LOG1_INT
#define TU_LOG2_HEX TU_LOG1_HEX
#endif
// Log Level 3: Info
#if CFG_TUSB_DEBUG >= 3
#define TU_LOG3 TU_LOG1
#define TU_LOG3_MEM TU_LOG1_MEM
#define TU_LOG3_VAR TU_LOG1_VAR
#define TU_LOG3_INT TU_LOG1_INT
#define TU_LOG3_HEX TU_LOG1_HEX
#endif
typedef struct
{
uint32_t key;
const char* data;
} tu_lookup_entry_t;
typedef struct
{
uint16_t count;
tu_lookup_entry_t const* items;
} tu_lookup_table_t;
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key)
{
static char not_found[11];
for(uint16_t i=0; i<p_table->count; i++)
{
if (p_table->items[i].key == key) return p_table->items[i].data;
}
// not found return the key value in hex
sprintf(not_found, "0x%08lX", (unsigned long) key);
return not_found;
}
#endif // CFG_TUSB_DEBUG
#ifndef TU_LOG
#define TU_LOG(n, ...)
#define TU_LOG_MEM(n, ...)
#define TU_LOG_VAR(n, ...)
#define TU_LOG_INT(n, ...)
#define TU_LOG_HEX(n, ...)
#define TU_LOG_LOCATION()
#define TU_LOG_FAILED()
#endif
// TODO replace all TU_LOGn with TU_LOG(n)
#define TU_LOG0(...)
#define TU_LOG0_MEM(...)
#define TU_LOG0_VAR(...)
#define TU_LOG0_INT(...)
#define TU_LOG0_HEX(...)
#ifndef TU_LOG1
#define TU_LOG1(...)
#define TU_LOG1_MEM(...)
#define TU_LOG1_VAR(...)
#define TU_LOG1_INT(...)
#define TU_LOG1_HEX(...)
#endif
#ifndef TU_LOG2
#define TU_LOG2(...)
#define TU_LOG2_MEM(...)
#define TU_LOG2_VAR(...)
#define TU_LOG2_INT(...)
#define TU_LOG2_HEX(...)
#endif
#ifndef TU_LOG3
#define TU_LOG3(...)
#define TU_LOG3_MEM(...)
#define TU_LOG3_VAR(...)
#define TU_LOG3_INT(...)
#define TU_LOG3_HEX(...)
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -51,10 +51,10 @@
#endif #endif
// Compile-time Assert // Compile-time Assert
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #if defined (__cplusplus) && __cplusplus >= 201103L
#define TU_VERIFY_STATIC _Static_assert
#elif defined (__cplusplus) && __cplusplus >= 201103L
#define TU_VERIFY_STATIC static_assert #define TU_VERIFY_STATIC static_assert
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define TU_VERIFY_STATIC _Static_assert
#elif defined(__CCRX__) #elif defined(__CCRX__)
#define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0]; #define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0];
#else #else

174
src/common/tusb_debug.h Normal file
View File

@ -0,0 +1,174 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022, Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_DEBUG_H_
#define _TUSB_DEBUG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Debug
//--------------------------------------------------------------------+
// CFG_TUSB_DEBUG for debugging
// 0 : no debug
// 1 : print error
// 2 : print warning
// 3 : print info
#if CFG_TUSB_DEBUG
// Enum to String for debugging purposes
#if CFG_TUSB_DEBUG >= 2
extern char const* const tu_str_speed[];
extern char const* const tu_str_std_request[];
#endif
void tu_print_mem(void const *buf, uint32_t count, uint8_t indent);
#ifdef CFG_TUSB_DEBUG_PRINTF
extern int CFG_TUSB_DEBUG_PRINTF(const char *format, ...);
#define tu_printf CFG_TUSB_DEBUG_PRINTF
#else
#define tu_printf printf
#endif
static inline void tu_print_var(uint8_t const* buf, uint32_t bufsize)
{
for(uint32_t i=0; i<bufsize; i++) tu_printf("%02X ", buf[i]);
}
// Log with Level
#define TU_LOG(n, ...) TU_XSTRCAT(TU_LOG, n)(__VA_ARGS__)
#define TU_LOG_MEM(n, ...) TU_XSTRCAT3(TU_LOG, n, _MEM)(__VA_ARGS__)
#define TU_LOG_VAR(n, ...) TU_XSTRCAT3(TU_LOG, n, _VAR)(__VA_ARGS__)
#define TU_LOG_INT(n, ...) TU_XSTRCAT3(TU_LOG, n, _INT)(__VA_ARGS__)
#define TU_LOG_HEX(n, ...) TU_XSTRCAT3(TU_LOG, n, _HEX)(__VA_ARGS__)
#define TU_LOG_LOCATION() tu_printf("%s: %d:\r\n", __PRETTY_FUNCTION__, __LINE__)
#define TU_LOG_FAILED() tu_printf("%s: %d: Failed\r\n", __PRETTY_FUNCTION__, __LINE__)
// Log Level 1: Error
#define TU_LOG1 tu_printf
#define TU_LOG1_MEM tu_print_mem
#define TU_LOG1_VAR(_x) tu_print_var((uint8_t const*)(_x), sizeof(*(_x)))
#define TU_LOG1_INT(_x) tu_printf(#_x " = %ld\r\n", (unsigned long) (_x) )
#define TU_LOG1_HEX(_x) tu_printf(#_x " = %lX\r\n", (unsigned long) (_x) )
// Log Level 2: Warn
#if CFG_TUSB_DEBUG >= 2
#define TU_LOG2 TU_LOG1
#define TU_LOG2_MEM TU_LOG1_MEM
#define TU_LOG2_VAR TU_LOG1_VAR
#define TU_LOG2_INT TU_LOG1_INT
#define TU_LOG2_HEX TU_LOG1_HEX
#endif
// Log Level 3: Info
#if CFG_TUSB_DEBUG >= 3
#define TU_LOG3 TU_LOG1
#define TU_LOG3_MEM TU_LOG1_MEM
#define TU_LOG3_VAR TU_LOG1_VAR
#define TU_LOG3_INT TU_LOG1_INT
#define TU_LOG3_HEX TU_LOG1_HEX
#endif
typedef struct
{
uint32_t key;
const char* data;
} tu_lookup_entry_t;
typedef struct
{
uint16_t count;
tu_lookup_entry_t const* items;
} tu_lookup_table_t;
static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key)
{
static char not_found[11];
for(uint16_t i=0; i<p_table->count; i++)
{
if (p_table->items[i].key == key) return p_table->items[i].data;
}
// not found return the key value in hex
snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
return not_found;
}
#endif // CFG_TUSB_DEBUG
#ifndef TU_LOG
#define TU_LOG(n, ...)
#define TU_LOG_MEM(n, ...)
#define TU_LOG_VAR(n, ...)
#define TU_LOG_INT(n, ...)
#define TU_LOG_HEX(n, ...)
#define TU_LOG_LOCATION()
#define TU_LOG_FAILED()
#endif
// TODO replace all TU_LOGn with TU_LOG(n)
#define TU_LOG0(...)
#define TU_LOG0_MEM(...)
#define TU_LOG0_VAR(...)
#define TU_LOG0_INT(...)
#define TU_LOG0_HEX(...)
#ifndef TU_LOG1
#define TU_LOG1(...)
#define TU_LOG1_MEM(...)
#define TU_LOG1_VAR(...)
#define TU_LOG1_INT(...)
#define TU_LOG1_HEX(...)
#endif
#ifndef TU_LOG2
#define TU_LOG2(...)
#define TU_LOG2_MEM(...)
#define TU_LOG2_VAR(...)
#define TU_LOG2_INT(...)
#define TU_LOG2_HEX(...)
#endif
#ifndef TU_LOG3
#define TU_LOG3(...)
#define TU_LOG3_MEM(...)
#define TU_LOG3_VAR(...)
#define TU_LOG3_INT(...)
#define TU_LOG3_HEX(...)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_DEBUG_H_ */

View File

@ -1,77 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
/** \ingroup Group_Common
* \defgroup Group_Error Error Codes
* @{ */
#ifndef _TUSB_ERRORS_H_
#define _TUSB_ERRORS_H_
#include "tusb_option.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ERROR_ENUM(x) x,
#define ERROR_STRING(x) #x,
#define ERROR_TABLE(ENTRY) \
ENTRY(TUSB_ERROR_NONE )\
ENTRY(TUSB_ERROR_INVALID_PARA )\
ENTRY(TUSB_ERROR_DEVICE_NOT_READY )\
ENTRY(TUSB_ERROR_INTERFACE_IS_BUSY )\
ENTRY(TUSB_ERROR_HCD_OPEN_PIPE_FAILED )\
ENTRY(TUSB_ERROR_OSAL_TIMEOUT )\
ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\
ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
ENTRY(TUSB_ERROR_NOT_SUPPORTED )\
ENTRY(TUSB_ERROR_NOT_ENOUGH_MEMORY )\
ENTRY(TUSB_ERROR_FAILED )\
/// \brief Error Code returned
/// TODO obsolete and to be remove
typedef enum
{
ERROR_TABLE(ERROR_ENUM)
TUSB_ERROR_COUNT
}tusb_error_t;
#if CFG_TUSB_DEBUG
/// Enum to String for debugging purposes. Only available if \ref CFG_TUSB_DEBUG > 0
extern char const* const tusb_strerr[TUSB_ERROR_COUNT];
extern char const* const tusb_speed_str[];
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_ERRORS_H_ */
/** @} */

View File

@ -184,6 +184,9 @@
#define TUP_DCD_ENDPOINT_MAX 8 #define TUP_DCD_ENDPOINT_MAX 8
#endif #endif
#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
#define TUP_DCD_ENDPOINT_MAX 8
//------------- Sony -------------// //------------- Sony -------------//
#elif TU_CHECK_MCU(OPT_MCU_CXD56) #elif TU_CHECK_MCU(OPT_MCU_CXD56)
#define TUP_DCD_ENDPOINT_MAX 7 #define TUP_DCD_ENDPOINT_MAX 7

65
src/common/tusb_private.h Normal file
View File

@ -0,0 +1,65 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022, Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_PRIVATE_H_
#define _TUSB_PRIVATE_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct TU_ATTR_PACKED
{
volatile uint8_t busy : 1;
volatile uint8_t stalled : 1;
volatile uint8_t claimed : 1;
}tu_edpt_state_t;
//--------------------------------------------------------------------+
// Internal Helper used by Host and Device Stack
//--------------------------------------------------------------------+
// Check if endpoint descriptor is valid per USB specs
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed);
// Bind all endpoint of a interface descriptor to class driver
void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
// Calculate total length of n interfaces (depending on IAD)
uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
// Claim an endpoint with provided mutex
bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
// Release an endpoint with provided mutex
bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex);
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_PRIVATE_H_ */

View File

@ -223,19 +223,13 @@ enum {
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2) #define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
/// Device State TODO remove
typedef enum
{
TUSB_DEVICE_STATE_UNPLUG = 0 ,
TUSB_DEVICE_STATE_CONFIGURED ,
TUSB_DEVICE_STATE_SUSPENDED ,
}tusb_device_state_t;
typedef enum typedef enum
{ {
XFER_RESULT_SUCCESS, XFER_RESULT_SUCCESS,
XFER_RESULT_FAILED, XFER_RESULT_FAILED,
XFER_RESULT_STALLED, XFER_RESULT_STALLED,
XFER_RESULT_TIMEOUT,
XFER_RESULT_INVALID
}xfer_result_t; }xfer_result_t;
enum // TODO remove enum // TODO remove
@ -265,6 +259,7 @@ typedef enum
enum enum
{ {
CONTROL_STAGE_IDLE,
CONTROL_STAGE_SETUP, CONTROL_STAGE_SETUP,
CONTROL_STAGE_DATA, CONTROL_STAGE_DATA,
CONTROL_STAGE_ACK CONTROL_STAGE_ACK

View File

@ -74,10 +74,8 @@
#if CFG_TUSB_DEBUG #if CFG_TUSB_DEBUG
#include <stdio.h> #include <stdio.h>
#define _MESS_ERR(_err) tu_printf("%s %d: failed, error = %s\r\n", __func__, __LINE__, tusb_strerr[_err])
#define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__) #define _MESS_FAILED() tu_printf("%s %d: ASSERT FAILED\r\n", __func__, __LINE__)
#else #else
#define _MESS_ERR(_err) do {} while (0)
#define _MESS_FAILED() do {} while (0) #define _MESS_FAILED() do {} while (0)
#endif #endif
@ -144,32 +142,6 @@
#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__) #define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
#endif #endif
// TODO remove TU_ASSERT_ERR() later
/*------------- Generator for TU_VERIFY_ERR and TU_VERIFY_ERR_HDLR -------------*/
#define TU_VERIFY_ERR_DEF2(_error, _handler) do \
{ \
uint32_t _err = (uint32_t)(_error); \
if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _err; } \
} while(0)
#define TU_VERIFY_ERR_DEF3(_error, _handler, _ret) do \
{ \
uint32_t _err = (uint32_t)(_error); \
if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _ret; } \
} while(0)
/*------------------------------------------------------------------*/
/* ASSERT Error
* basically TU_VERIFY Error with TU_BREAKPOINT() as handler
*------------------------------------------------------------------*/
#define ASSERT_ERR_1ARGS(_error) TU_VERIFY_ERR_DEF2(_error, TU_BREAKPOINT())
#define ASSERT_ERR_2ARGS(_error, _ret) TU_VERIFY_ERR_DEF3(_error, TU_BREAKPOINT(), _ret)
#ifndef TU_ASSERT_ERR
#define TU_ASSERT_ERR(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_ERR_2ARGS, ASSERT_ERR_1ARGS,UNUSED)(__VA_ARGS__)
#endif
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* ASSERT HDLR /* ASSERT HDLR
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/

View File

@ -29,6 +29,8 @@
#if CFG_TUD_ENABLED #if CFG_TUD_ENABLED
#include "tusb.h" #include "tusb.h"
#include "common/tusb_private.h"
#include "device/usbd.h" #include "device/usbd.h"
#include "device/usbd_pvt.h" #include "device/usbd_pvt.h"
#include "device/dcd.h" #include "device/dcd.h"
@ -67,17 +69,10 @@ typedef struct
volatile uint8_t cfg_num; // current active configuration (0x00 is not configured) volatile uint8_t cfg_num; // current active configuration (0x00 is not configured)
uint8_t speed; uint8_t speed;
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ) uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
struct TU_ATTR_PACKED tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2];
{
volatile bool busy : 1;
volatile bool stalled : 1;
volatile bool claimed : 1;
// TODO merge ep2drv here, 4-bit should be sufficient
}ep_status[CFG_TUD_ENDPPOINT_MAX][2];
}usbd_device_t; }usbd_device_t;
@ -273,7 +268,7 @@ enum { RHPORT_INVALID = 0xFFu };
static uint8_t _usbd_rhport = RHPORT_INVALID; static uint8_t _usbd_rhport = RHPORT_INVALID;
// Event queue // Event queue
// OPT_MODE_DEVICE is used by OS NONE for mutex (disable usb isr) // usbd_int_set() is used as mutex in OS NONE config
OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t); OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
static osal_queue_t _usbd_q; static osal_queue_t _usbd_q;
@ -315,23 +310,6 @@ static char const* const _usbd_event_str[DCD_EVENT_COUNT] =
"Func Call" "Func Call"
}; };
static char const* const _tusb_std_request_str[] =
{
"Get Status" ,
"Clear Feature" ,
"Reserved" ,
"Set Feature" ,
"Reserved" ,
"Set Address" ,
"Get Descriptor" ,
"Set Descriptor" ,
"Get Configuration" ,
"Set Configuration" ,
"Get Interface" ,
"Set Interface" ,
"Synch Frame"
};
// for usbd_control to print the name of control complete driver // for usbd_control to print the name of control complete driver
void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback) void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback)
{ {
@ -407,6 +385,7 @@ bool tud_init (uint8_t rhport)
if ( tud_inited() ) return true; if ( tud_inited() ) return true;
TU_LOG2("USBD init\r\n"); TU_LOG2("USBD init\r\n");
TU_LOG2_INT(sizeof(usbd_device_t));
tu_varclr(&_usbd_dev); tu_varclr(&_usbd_dev);
@ -507,7 +486,7 @@ void tud_task (void)
switch ( event.event_id ) switch ( event.event_id )
{ {
case DCD_EVENT_BUS_RESET: case DCD_EVENT_BUS_RESET:
TU_LOG2(": %s Speed\r\n", tusb_speed_str[event.bus_reset.speed]); TU_LOG2(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
usbd_reset(event.rhport); usbd_reset(event.rhport);
_usbd_dev.speed = event.bus_reset.speed; _usbd_dev.speed = event.bus_reset.speed;
break; break;
@ -649,7 +628,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
#if CFG_TUSB_DEBUG >= 2 #if CFG_TUSB_DEBUG >= 2
if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME)
{ {
TU_LOG2(" %s", _tusb_std_request_str[p_request->bRequest]); TU_LOG2(" %s", tu_str_std_request[p_request->bRequest]);
if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG2("\r\n"); if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG2("\r\n");
} }
#endif #endif
@ -1241,52 +1220,30 @@ bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
// TODO add this check later, also make sure we don't starve an out endpoint while suspending // TODO add this check later, also make sure we don't starve an out endpoint while suspending
// TU_VERIFY(tud_ready()); // TU_VERIFY(tud_ready());
uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr);
tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir];
#if CFG_TUSB_OS != OPT_OS_NONE #if TUSB_OPT_MUTEX
// pre-check to help reducing mutex lock return tu_edpt_claim(ep_state, _usbd_mutex);
TU_VERIFY((_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0)); #else
osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER); return tu_edpt_claim(ep_state, NULL);
#endif #endif
// can only claim the endpoint if it is not busy and not claimed yet.
bool const ret = (_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0);
if (ret)
{
_usbd_dev.ep_status[epnum][dir].claimed = 1;
}
#if CFG_TUSB_OS != OPT_OS_NONE
osal_mutex_unlock(_usbd_mutex);
#endif
return ret;
} }
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr)
{ {
(void) rhport; (void) rhport;
uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr);
tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir];
#if CFG_TUSB_OS != OPT_OS_NONE #if TUSB_OPT_MUTEX
osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER); return tu_edpt_release(ep_state, _usbd_mutex);
#else
return tu_edpt_release(ep_state, NULL);
#endif #endif
// can only release the endpoint if it is claimed and not busy
bool const ret = (_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 1);
if (ret)
{
_usbd_dev.ep_status[epnum][dir].claimed = 0;
}
#if CFG_TUSB_OS != OPT_OS_NONE
osal_mutex_unlock(_usbd_mutex);
#endif
return ret;
} }
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)

View File

@ -80,7 +80,7 @@ bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16
// If caller does not make any transfer, it must release endpoint for others. // If caller does not make any transfer, it must release endpoint for others.
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr); bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr);
// Release an endpoint without submitting a transfer // Release claimed endpoint without submitting a transfer
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr); bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr);
// Check if endpoint is busy transferring // Check if endpoint is busy transferring

View File

@ -35,6 +35,19 @@
extern "C" { extern "C" {
#endif #endif
//--------------------------------------------------------------------+
// Configuration
//--------------------------------------------------------------------+
#ifndef CFG_TUH_ENDPOINT_MAX
#define CFG_TUH_ENDPOINT_MAX (CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3)
// #ifdef TUP_HCD_ENDPOINT_MAX
// #define CFG_TUH_ENDPPOINT_MAX TUP_HCD_ENDPOINT_MAX
// #else
// #define
// #endif
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF // MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -81,26 +94,14 @@ typedef struct
} hcd_event_t; } hcd_event_t;
#if CFG_TUH_ENABLED typedef struct
// Max number of endpoints per device {
enum {
// TODO better computation
HCD_MAX_ENDPOINT = CFG_TUH_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3),
HCD_MAX_XFER = HCD_MAX_ENDPOINT*2,
};
//#define HCD_MAX_ENDPOINT 16
//#define HCD_MAX_XFER 16
typedef struct {
uint8_t rhport; uint8_t rhport;
uint8_t hub_addr; uint8_t hub_addr;
uint8_t hub_port; uint8_t hub_port;
uint8_t speed; uint8_t speed;
} hcd_devtree_info_t; } hcd_devtree_info_t;
#endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Controller API // Controller API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -54,7 +54,7 @@ static inline hub_interface_t* get_itf(uint8_t dev_addr)
return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX]; return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX];
} }
#if CFG_TUSB_DEBUG #if CFG_TUSB_DEBUG >= 2
static char const* const _hub_feature_str[] = static char const* const _hub_feature_str[] =
{ {
[HUB_FEATURE_PORT_CONNECTION ] = "PORT_CONNECTION", [HUB_FEATURE_PORT_CONNECTION ] = "PORT_CONNECTION",
@ -77,7 +77,8 @@ static char const* const _hub_feature_str[] =
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// HUB // HUB
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb) bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{ {
tusb_control_request_t const request = tusb_control_request_t const request =
{ {
@ -93,12 +94,23 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
.wLength = 0 .wLength = 0
}; };
tuh_xfer_t xfer =
{
.daddr = hub_addr,
.ep_addr = 0,
.setup = &request,
.buffer = NULL,
.complete_cb = complete_cb,
.user_data = user_data
};
TU_LOG2("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port); TU_LOG2("HUB Clear Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); TU_ASSERT( tuh_control_xfer(&xfer) );
return true; return true;
} }
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb) bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{ {
tusb_control_request_t const request = tusb_control_request_t const request =
{ {
@ -114,17 +126,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, t
.wLength = 0 .wLength = 0
}; };
tuh_xfer_t xfer =
{
.daddr = hub_addr,
.ep_addr = 0,
.setup = &request,
.buffer = NULL,
.complete_cb = complete_cb,
.user_data = user_data
};
TU_LOG2("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port); TU_LOG2("HUB Set Feature: %s, addr = %u port = %u\r\n", _hub_feature_str[feature], hub_addr, hub_port);
TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); TU_ASSERT( tuh_control_xfer(&xfer) );
return true; return true;
} }
bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb) bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
{ tuh_xfer_cb_t complete_cb, uintptr_t user_data)
return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb);
}
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb)
{ {
tusb_control_request_t const request = tusb_control_request_t const request =
{ {
@ -140,8 +158,18 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
.wLength = 4 .wLength = 4
}; };
tuh_xfer_t xfer =
{
.daddr = hub_addr,
.ep_addr = 0,
.setup = &request,
.buffer = resp,
.complete_cb = complete_cb,
.user_data = user_data
};
TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port); TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port);
TU_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) ); TU_ASSERT( tuh_control_xfer(&xfer) );
return true; return true;
} }
@ -155,6 +183,8 @@ void hub_init(void)
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len) bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
{ {
(void) rhport;
TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass && TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
0 == itf_desc->bInterfaceSubClass); 0 == itf_desc->bInterfaceSubClass);
@ -171,7 +201,7 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType &&
TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0); TUSB_XFER_INTERRUPT == desc_ep->bmAttributes.xfer, 0);
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep)); TU_ASSERT(tuh_edpt_open(dev_addr, desc_ep));
hub_interface_t* p_hub = get_itf(dev_addr); hub_interface_t* p_hub = get_itf(dev_addr);
@ -189,7 +219,7 @@ void hub_close(uint8_t dev_addr)
if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t)); if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
} }
bool hub_status_pipe_queue(uint8_t dev_addr) bool hub_edpt_status_xfer(uint8_t dev_addr)
{ {
hub_interface_t* hub_itf = get_itf(dev_addr); hub_interface_t* hub_itf = get_itf(dev_addr);
return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1); return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1);
@ -200,8 +230,8 @@ bool hub_status_pipe_queue(uint8_t dev_addr)
// Set Configure // Set Configure
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static void config_set_port_power (tuh_xfer_t* xfer);
static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static void config_port_power_complete (tuh_xfer_t* xfer);
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
{ {
@ -223,17 +253,27 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
.wLength = sizeof(descriptor_hub_desc_t) .wLength = sizeof(descriptor_hub_desc_t)
}; };
TU_ASSERT( tuh_control_xfer(dev_addr, &request, _hub_buffer, config_set_port_power) ); tuh_xfer_t xfer =
{
.daddr = dev_addr,
.ep_addr = 0,
.setup = &request,
.buffer = _hub_buffer,
.complete_cb = config_set_port_power,
.user_data = 0
};
TU_ASSERT( tuh_control_xfer(&xfer) );
return true; return true;
} }
static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void config_set_port_power (tuh_xfer_t* xfer)
{ {
(void) request; TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
TU_ASSERT(XFER_RESULT_SUCCESS == result);
hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const daddr = xfer->daddr;
hub_interface_t* p_hub = get_itf(daddr);
// only use number of ports in hub descriptor // only use number of ports in hub descriptor
descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer; descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer;
@ -243,38 +283,38 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons
// Set Port Power to be able to detect connection, starting with port 1 // Set Port Power to be able to detect connection, starting with port 1
uint8_t const hub_port = 1; uint8_t const hub_port = 1;
return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete); hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
} }
static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void config_port_power_complete (tuh_xfer_t* xfer)
{ {
TU_ASSERT(XFER_RESULT_SUCCESS == result); TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
hub_interface_t* p_hub = get_itf(dev_addr);
if (request->wIndex == p_hub->port_count) uint8_t const daddr = xfer->daddr;
hub_interface_t* p_hub = get_itf(daddr);
if (xfer->setup->wIndex == p_hub->port_count)
{ {
// All ports are power -> queue notification status endpoint and // All ports are power -> queue notification status endpoint and
// complete the SET CONFIGURATION // complete the SET CONFIGURATION
TU_ASSERT( usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1) ); TU_ASSERT( usbh_edpt_xfer(daddr, p_hub->ep_in, &p_hub->status_change, 1), );
usbh_driver_set_config_complete(dev_addr, p_hub->itf_num); usbh_driver_set_config_complete(daddr, p_hub->itf_num);
}else }else
{ {
// power next port // power next port
uint8_t const hub_port = (uint8_t) (request->wIndex + 1); uint8_t const hub_port = (uint8_t) (xfer->setup->wIndex + 1);
return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete); hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
} }
return true;
} }
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Connection Changes // Connection Changes
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static void connection_get_status_complete (tuh_xfer_t* xfer);
static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static void connection_port_reset_complete (tuh_xfer_t* xfer);
// callback as response of interrupt endpoint polling // callback as response of interrupt endpoint polling
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
@ -292,7 +332,7 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
{ {
if ( tu_bit_test(p_hub->status_change, port) ) if ( tu_bit_test(p_hub->status_change, port) )
{ {
hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete); hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete, 0);
break; break;
} }
} }
@ -302,12 +342,13 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
return true; return true;
} }
static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void connection_get_status_complete (tuh_xfer_t* xfer)
{ {
TU_ASSERT(result == XFER_RESULT_SUCCESS); TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const daddr = xfer->daddr;
uint8_t const port_num = (uint8_t) request->wIndex; hub_interface_t* p_hub = get_itf(daddr);
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
// Connection change // Connection change
if (p_hub->port_status.change.connection) if (p_hub->port_status.change.connection)
@ -316,7 +357,7 @@ static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_reque
//TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
// Acknowledge Port Connection Change // Acknowledge Port Connection Change
hub_port_clear_feature(dev_addr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete); hub_port_clear_feature(daddr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete, 0);
}else }else
{ {
// Other changes are: Enable, Suspend, Over Current, Reset, L1 state // Other changes are: Enable, Suspend, Over Current, Reset, L1 state
@ -324,65 +365,61 @@ static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_reque
// prepare for next hub status // prepare for next hub status
// TODO continue with status_change, or maybe we can do it again with status // TODO continue with status_change, or maybe we can do it again with status
hub_status_pipe_queue(dev_addr); hub_edpt_status_xfer(daddr);
} }
return true;
} }
static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void connection_clear_conn_change_complete (tuh_xfer_t* xfer)
{ {
TU_ASSERT(result == XFER_RESULT_SUCCESS); TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const daddr = xfer->daddr;
uint8_t const port_num = (uint8_t) request->wIndex; hub_interface_t* p_hub = get_itf(daddr);
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
if ( p_hub->port_status.status.connection ) if ( p_hub->port_status.status.connection )
{ {
// Reset port if attach event // Reset port if attach event
hub_port_reset(dev_addr, port_num, connection_port_reset_complete); hub_port_reset(daddr, port_num, connection_port_reset_complete, 0);
}else }else
{ {
// submit detach event // submit detach event
hcd_event_t event = hcd_event_t event =
{ {
.rhport = usbh_get_rhport(dev_addr), .rhport = usbh_get_rhport(daddr),
.event_id = HCD_EVENT_DEVICE_REMOVE, .event_id = HCD_EVENT_DEVICE_REMOVE,
.connection = .connection =
{ {
.hub_addr = dev_addr, .hub_addr = daddr,
.hub_port = port_num .hub_port = port_num
} }
}; };
hcd_event_handler(&event, false); hcd_event_handler(&event, false);
} }
return true;
} }
static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) static void connection_port_reset_complete (tuh_xfer_t* xfer)
{ {
TU_ASSERT(result == XFER_RESULT_SUCCESS); TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
// hub_interface_t* p_hub = get_itf(dev_addr); uint8_t const daddr = xfer->daddr;
uint8_t const port_num = (uint8_t) request->wIndex; // hub_interface_t* p_hub = get_itf(daddr);
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
// submit attach event // submit attach event
hcd_event_t event = hcd_event_t event =
{ {
.rhport = usbh_get_rhport(dev_addr), .rhport = usbh_get_rhport(daddr),
.event_id = HCD_EVENT_DEVICE_ATTACH, .event_id = HCD_EVENT_DEVICE_ATTACH,
.connection = .connection =
{ {
.hub_addr = dev_addr, .hub_addr = daddr,
.hub_port = port_num .hub_port = port_num
} }
}; };
hcd_event_handler(&event, false); hcd_event_handler(&event, false);
return true;
} }
#endif #endif

View File

@ -171,12 +171,35 @@ typedef struct {
TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"); TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct");
bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb); // Clear feature
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb); bool hub_port_clear_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Set feature
bool hub_port_set_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get port status
bool hub_port_get_status (uint8_t hub_addr, uint8_t hub_port, void* resp,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get status from Interrupt endpoint
bool hub_edpt_status_xfer(uint8_t dev_addr);
// Reset a port
static inline bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
return hub_port_set_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET, complete_cb, user_data);
}
// Clear Reset Change
static inline bool hub_port_clear_reset_change(uint8_t hub_addr, uint8_t hub_port,
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
{
return hub_port_clear_feature(hub_addr, hub_port, HUB_FEATURE_PORT_RESET_CHANGE, complete_cb, user_data);
}
bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb);
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb);
bool hub_status_pipe_queue(uint8_t dev_addr);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Internal Class Driver API // Internal Class Driver API

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,48 @@
// MACRO CONSTANT TYPEDEF // MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); // forward declaration
struct tuh_xfer_s;
typedef struct tuh_xfer_s tuh_xfer_t;
typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
// Note1: layout and order of this will be changed in near future
// it is advised to initialize it using member name
// Note2: not all field is available/meaningful in callback, some info is not saved by
// usbh to save SRAM
struct tuh_xfer_s
{
uint8_t daddr;
uint8_t ep_addr;
xfer_result_t result;
uint32_t actual_len; // excluding setup packet
union
{
tusb_control_request_t const* setup; // setup packet pointer if control transfer
uint32_t buflen; // expected length if not control transfer (not available in callback)
};
uint8_t* buffer; // not available in callback if not control transfer
tuh_xfer_cb_t complete_cb;
uintptr_t user_data;
// uint32_t timeout_ms; // place holder, not supported yet
};
//--------------------------------------------------------------------+
// APPLICATION CALLBACK
//--------------------------------------------------------------------+
//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device);
// Invoked when device is mounted (configured)
TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
/// Invoked when device is unmounted (bus reset/unplugged)
TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// APPLICATION API // APPLICATION API
@ -57,40 +98,132 @@ void tuh_task(void);
extern void hcd_int_handler(uint8_t rhport); extern void hcd_int_handler(uint8_t rhport);
#define tuh_int_handler hcd_int_handler #define tuh_int_handler hcd_int_handler
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid); bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
tusb_speed_t tuh_speed_get(uint8_t dev_addr);
tusb_speed_t tuh_speed_get(uint8_t daddr);
// Check if device is connected and configured // Check if device is connected and configured
bool tuh_mounted(uint8_t dev_addr); bool tuh_mounted(uint8_t daddr);
// Check if device is suspended // Check if device is suspended
static inline bool tuh_suspended(uint8_t dev_addr) TU_ATTR_ALWAYS_INLINE
static inline bool tuh_suspended(uint8_t daddr)
{ {
// TODO implement suspend & resume on host // TODO implement suspend & resume on host
(void) dev_addr; (void) daddr;
return false; return false;
} }
// Check if device is ready to communicate with // Check if device is ready to communicate with
TU_ATTR_ALWAYS_INLINE TU_ATTR_ALWAYS_INLINE
static inline bool tuh_ready(uint8_t dev_addr) static inline bool tuh_ready(uint8_t daddr)
{ {
return tuh_mounted(dev_addr) && !tuh_suspended(dev_addr); return tuh_mounted(daddr) && !tuh_suspended(daddr);
} }
// Carry out control transfer //--------------------------------------------------------------------+
bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb); // Transfer API
//--------------------------------------------------------------------+
// Submit a control transfer
// - async: complete callback invoked when finished.
// - sync : blocking if complete callback is NULL.
bool tuh_control_xfer(tuh_xfer_t* xfer);
// Submit a bulk/interrupt transfer
// - async: complete callback invoked when finished.
// - sync : blocking if complete callback is NULL.
bool tuh_edpt_xfer(tuh_xfer_t* xfer);
// Open an non-control endpoint
bool tuh_edpt_open(uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
// Set Configuration (control transfer)
// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
// true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// APPLICATION CALLBACK // Descriptors Asynchronous (non-blocking)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device);
// Invoked when device is mounted (configured) // Get an descriptor (control transfer)
TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr); // true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
/// Invoked when device is unmounted (bus reset/unplugged) // Get device descriptor (control transfer)
TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr); // true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get_device(uint8_t daddr, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get configuration descriptor (control transfer)
// true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get_configuration(uint8_t daddr, uint8_t index, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get HID report descriptor (control transfer)
// true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get string descriptor (control transfer)
// true on success, false if there is on-going control transfer or incorrect parameters
// Blocking if complete callback is NULL, in this case 'user_data' must contain xfer_result_t variable
bool tuh_descriptor_get_string(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get manufacturer string descriptor (control transfer)
// true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get_manufacturer_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get product string descriptor (control transfer)
// true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get_product_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get serial string descriptor (control transfer)
// true on success, false if there is on-going control transfer or incorrect parameters
bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
//--------------------------------------------------------------------+
// Descriptors Synchronous (blocking)
//--------------------------------------------------------------------+
// Sync (blocking) version of tuh_descriptor_get()
// return transfer result
uint8_t tuh_descriptor_get_sync(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_device()
// return transfer result
uint8_t tuh_descriptor_get_device_sync(uint8_t daddr, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_configuration()
// return transfer result
uint8_t tuh_descriptor_get_configuration_sync(uint8_t daddr, uint8_t index, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_hid_report()
// return transfer result
uint8_t tuh_descriptor_get_hid_report_sync(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_string()
// return transfer result
uint8_t tuh_descriptor_get_string_sync(uint8_t daddr, uint8_t index, uint16_t language_id, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_manufacturer_string()
// return transfer result
uint8_t tuh_descriptor_get_manufacturer_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_product_string()
// return transfer result
uint8_t tuh_descriptor_get_product_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
// Sync (blocking) version of tuh_descriptor_get_serial_string()
// return transfer result
uint8_t tuh_descriptor_get_serial_string_sync(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -63,16 +63,22 @@ void usbh_int_set(bool enabled);
// USBH Endpoint API // USBH Endpoint API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Open an endpoint // Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep); bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
TU_ATTR_ALWAYS_INLINE
static inline bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
{
return usbh_edpt_xfer_with_callback(dev_addr, ep_addr, buffer, total_bytes, NULL, 0);
}
// Submit a usb transfer
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
// Claim an endpoint before submitting a transfer. // Claim an endpoint before submitting a transfer.
// If caller does not make any transfer, it must release endpoint for others. // If caller does not make any transfer, it must release endpoint for others.
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr); bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
// Release claimed endpoint without submitting a transfer
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr); bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr);
// Check if endpoint transferring is complete // Check if endpoint transferring is complete

View File

@ -1,145 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020, Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "tusb_option.h"
#if CFG_TUH_ENABLED
#include "tusb.h"
#include "usbh_classdriver.h"
enum
{
STAGE_SETUP,
STAGE_DATA,
STAGE_ACK
};
typedef struct
{
tusb_control_request_t request TU_ATTR_ALIGNED(4);
uint8_t stage;
uint8_t* buffer;
tuh_control_complete_cb_t complete_cb;
} usbh_control_xfer_t;
static usbh_control_xfer_t _ctrl_xfer;
//CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
//static uint8_t _tuh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb)
{
// TODO need to claim the endpoint first
const uint8_t rhport = usbh_get_rhport(dev_addr);
_ctrl_xfer.request = (*request);
_ctrl_xfer.buffer = buffer;
_ctrl_xfer.stage = STAGE_SETUP;
_ctrl_xfer.complete_cb = complete_cb;
TU_LOG2("Control Setup (addr = %u): ", dev_addr);
TU_LOG2_VAR(request);
TU_LOG2("\r\n");
// Send setup packet
if ( hcd_edpt_control_xfer )
{
_ctrl_xfer.stage = STAGE_ACK;
TU_ASSERT( hcd_edpt_control_xfer(rhport, dev_addr, (uint8_t const*) &_ctrl_xfer.request, buffer) );
}else
{
TU_ASSERT( hcd_setup_send(rhport, dev_addr, (uint8_t const*) &_ctrl_xfer.request) );
}
return true;
}
static void _xfer_complete(uint8_t dev_addr, xfer_result_t result)
{
TU_LOG2("\r\n");
if (_ctrl_xfer.complete_cb) _ctrl_xfer.complete_cb(dev_addr, &_ctrl_xfer.request, result);
}
bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
(void) ep_addr;
(void) xferred_bytes;
const uint8_t rhport = usbh_get_rhport(dev_addr);
tusb_control_request_t const * request = &_ctrl_xfer.request;
if (XFER_RESULT_SUCCESS != result)
{
TU_LOG2("Control failed: result = %d\r\n", result);
// terminate transfer if any stage failed
_xfer_complete(dev_addr, result);
}else
{
switch(_ctrl_xfer.stage)
{
case STAGE_SETUP:
_ctrl_xfer.stage = STAGE_DATA;
if (request->wLength)
{
// DATA stage: initial data toggle is always 1
hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength);
return true;
}
__attribute__((fallthrough));
case STAGE_DATA:
_ctrl_xfer.stage = STAGE_ACK;
if (request->wLength)
{
TU_LOG2("Control data (addr = %u):\r\n", dev_addr);
TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2);
}
// ACK stage: toggle is always 1
hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0);
break;
case STAGE_ACK:
_xfer_complete(dev_addr, result);
break;
default: return false;
}
}
return true;
}
#endif

View File

@ -111,7 +111,7 @@ typedef struct
typedef osal_queue_def_t* osal_queue_t; typedef osal_queue_def_t* osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only // _int_set is used as mutex in OS NONE (disable/enable USB ISR)
#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \ #define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
uint8_t _name##_buf[_depth*sizeof(_type)]; \ uint8_t _name##_buf[_depth*sizeof(_type)]; \
osal_queue_def_t _name = { \ osal_queue_def_t _name = { \

View File

@ -35,6 +35,7 @@
// INCLUDE // INCLUDE
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#include "common/tusb_common.h" #include "common/tusb_common.h"
#include "host/hcd.h"
#include "portable/ehci/ehci_api.h" #include "portable/ehci/ehci_api.h"
#include "ci_hs_type.h" #include "ci_hs_type.h"

View File

@ -58,6 +58,9 @@
#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE) #define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
#define QHD_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
#define QTD_MAX QHD_MAX
typedef struct typedef struct
{ {
ehci_link_t period_framelist[FRAMELIST_SIZE]; ehci_link_t period_framelist[FRAMELIST_SIZE];
@ -73,8 +76,8 @@ typedef struct
ehci_qtd_t qtd; ehci_qtd_t qtd;
}control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1]; }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT]; ehci_qhd_t qhd_pool[QHD_MAX];
ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32); ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
ehci_registers_t* regs; ehci_registers_t* regs;
@ -189,7 +192,11 @@ static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
prev = list_next(prev) ) prev = list_next(prev) )
{ {
// TODO check type for ISO iTD and siTD // TODO check type for ISO iTD and siTD
// TODO Suppress cast-align warning
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev); ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
#pragma GCC diagnostic pop
if ( qhd->dev_addr == dev_addr ) if ( qhd->dev_addr == dev_addr )
{ {
// TODO deactive all TD, wait for QHD to inactive before removal // TODO deactive all TD, wait for QHD to inactive before removal
@ -474,7 +481,7 @@ static void async_advance_isr(uint8_t rhport)
(void) rhport; (void) rhport;
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool; ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
for(uint32_t i = 0; i < HCD_MAX_ENDPOINT; i++) for(uint32_t i = 0; i < QHD_MAX; i++)
{ {
if ( qhd_pool[i].removing ) if ( qhd_pool[i].removing )
{ {
@ -542,7 +549,7 @@ static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
// TODO abstract max loop guard for period // TODO abstract max loop guard for period
while( !next_item.terminate && while( !next_item.terminate &&
!(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) && !(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) &&
max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX) max_loop < (QHD_MAX + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
{ {
switch ( next_item.type ) switch ( next_item.type )
{ {
@ -649,6 +656,26 @@ static void xfer_error_isr(uint8_t hostid)
} }
} }
#if CFG_TUSB_DEBUG >= EHCI_DBG
static inline void print_portsc(ehci_registers_t* regs)
{
TU_LOG_HEX(EHCI_DBG, regs->portsc);
TU_LOG(EHCI_DBG, " Current Connect Status: %u\r\n", regs->portsc_bm.current_connect_status);
TU_LOG(EHCI_DBG, " Connect Status Change : %u\r\n", regs->portsc_bm.connect_status_change);
TU_LOG(EHCI_DBG, " Port Enabled : %u\r\n", regs->portsc_bm.port_enabled);
TU_LOG(EHCI_DBG, " Port Enabled Change : %u\r\n", regs->portsc_bm.port_enable_change);
TU_LOG(EHCI_DBG, " Port Reset : %u\r\n", regs->portsc_bm.port_reset);
TU_LOG(EHCI_DBG, " Port Power : %u\r\n", regs->portsc_bm.port_power);
}
#else
#define print_portsc(_reg)
#endif
//------------- Host Controller Driver's Interrupt Handler -------------// //------------- Host Controller Driver's Interrupt Handler -------------//
void hcd_int_handler(uint8_t rhport) void hcd_int_handler(uint8_t rhport)
{ {
@ -668,9 +695,8 @@ void hcd_int_handler(uint8_t rhport)
if (int_status & EHCI_INT_MASK_PORT_CHANGE) if (int_status & EHCI_INT_MASK_PORT_CHANGE)
{ {
uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL; uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
print_portsc(regs);
TU_LOG_HEX(EHCI_DBG, regs->portsc);
if (regs->portsc_bm.connect_status_change) if (regs->portsc_bm.connect_status_change)
{ {
@ -714,7 +740,7 @@ void hcd_int_handler(uint8_t rhport)
//------------- queue head helper -------------// //------------- queue head helper -------------//
static inline ehci_qhd_t* qhd_find_free (void) static inline ehci_qhd_t* qhd_find_free (void)
{ {
for (uint32_t i=0; i<HCD_MAX_ENDPOINT; i++) for (uint32_t i=0; i<QHD_MAX; i++)
{ {
if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i]; if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
} }
@ -731,7 +757,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
{ {
ehci_qhd_t* qhd_pool = ehci_data.qhd_pool; ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++) for(uint32_t i=0; i<QHD_MAX; i++)
{ {
if ( (qhd_pool[i].dev_addr == dev_addr) && if ( (qhd_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) ) ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
@ -746,7 +772,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
//------------- TD helper -------------// //------------- TD helper -------------//
static inline ehci_qtd_t* qtd_find_free(void) static inline ehci_qtd_t* qtd_find_free(void)
{ {
for (uint32_t i=0; i<HCD_MAX_XFER; i++) for (uint32_t i=0; i<QTD_MAX; i++)
{ {
if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i]; if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
} }

View File

@ -101,8 +101,8 @@ typedef struct
// Word 2: qTQ Token // Word 2: qTQ Token
volatile uint32_t ping_err : 1 ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator volatile uint32_t ping_err : 1 ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of slipt transaction volatile uint32_t non_hs_split_state : 1 ; ///< Used by HC to track the state of split transaction
volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete slip transaction volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete split transaction
volatile uint32_t xact_err : 1 ; ///< Error (Timeout, CRC, Bad PID ... ) volatile uint32_t xact_err : 1 ; ///< Error (Timeout, CRC, Bad PID ... )
volatile uint32_t babble_err : 1 ; ///< Babble detected, also set Halted bit to 1 volatile uint32_t babble_err : 1 ; ///< Babble detected, also set Halted bit to 1
volatile uint32_t buffer_err : 1 ; ///< Data overrun/underrun error volatile uint32_t buffer_err : 1 ; ///< Data overrun/underrun error

View File

@ -34,7 +34,6 @@
#include "freertos/xtensa_api.h" #include "freertos/xtensa_api.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "esp_log.h" #include "esp_log.h"
#include "driver/gpio.h"
#include "soc/dport_reg.h" #include "soc/dport_reg.h"
#include "soc/gpio_sig_map.h" #include "soc/gpio_sig_map.h"
#include "soc/usb_periph.h" #include "soc/usb_periph.h"

View File

@ -125,7 +125,7 @@ typedef struct
uint16_t bda[2*2]; uint16_t bda[2*2];
}; };
endpoint_state_t endpoint[2]; endpoint_state_t endpoint[2];
pipe_state_t pipe[HCD_MAX_XFER * 2]; pipe_state_t pipe[CFG_TUH_ENDPOINT_MAX * 2];
uint32_t in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */ uint32_t in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */
uint32_t pending; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */ uint32_t pending; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */
bool need_reset; /* The device has not been reset after connection. */ bool need_reset; /* The device has not been reset after connection. */
@ -142,7 +142,7 @@ int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
{ {
/* Find the target pipe */ /* Find the target pipe */
int num; int num;
for (num = 0; num < HCD_MAX_XFER * 2; ++num) { for (num = 0; num < CFG_TUH_ENDPOINT_MAX * 2; ++num) {
pipe_state_t *p = &_hcd.pipe[num]; pipe_state_t *p = &_hcd.pipe[num];
if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr)) if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
return num; return num;
@ -463,7 +463,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn); const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
NVIC_DisableIRQ(USB0_IRQn); NVIC_DisableIRQ(USB0_IRQn);
pipe_state_t *p = &_hcd.pipe[0]; pipe_state_t *p = &_hcd.pipe[0];
pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER * 2]; pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
for (;p != end; ++p) { for (;p != end; ++p) {
if (p->dev_addr == dev_addr) if (p->dev_addr == dev_addr)
tu_memclr(p, sizeof(*p)); tu_memclr(p, sizeof(*p));
@ -511,7 +511,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
// TU_LOG1("O %u %x\n", dev_addr, ep_addr); // TU_LOG1("O %u %x\n", dev_addr, ep_addr);
/* Find a free pipe */ /* Find a free pipe */
pipe_state_t *p = &_hcd.pipe[0]; pipe_state_t *p = &_hcd.pipe[0];
pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER * 2]; pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
if (dev_addr || ep_addr) { if (dev_addr || ep_addr) {
p += 2; p += 2;
for (; p < end && (p->dev_addr || p->ep_addr); ++p) ; for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;

View File

@ -318,7 +318,7 @@ static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
ohci_ed_t* ed_pool = ohci_data.ed_pool; ohci_ed_t* ed_pool = ohci_data.ed_pool;
for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++) for(uint32_t i=0; i<ED_MAX; i++)
{ {
if ( (ed_pool[i].dev_addr == dev_addr) && if ( (ed_pool[i].dev_addr == dev_addr) &&
ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) ) ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) )
@ -334,7 +334,7 @@ static ohci_ed_t * ed_find_free(void)
{ {
ohci_ed_t* ed_pool = ohci_data.ed_pool; ohci_ed_t* ed_pool = ohci_data.ed_pool;
for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++) for(uint8_t i = 0; i < ED_MAX; i++)
{ {
if ( !ed_pool[i].used ) return &ed_pool[i]; if ( !ed_pool[i].used ) return &ed_pool[i];
} }
@ -373,7 +373,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
static ohci_gtd_t * gtd_find_free(void) static ohci_gtd_t * gtd_find_free(void)
{ {
for(uint8_t i=0; i < HCD_MAX_XFER; i++) for(uint8_t i=0; i < GTD_MAX; i++)
{ {
if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i]; if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
} }

View File

@ -42,6 +42,9 @@ enum {
OHCI_MAX_ITD = 4 OHCI_MAX_ITD = 4
}; };
#define ED_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
#define GTD_MAX ED_MAX
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// OHCI Data Structure // OHCI Data Structure
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -162,8 +165,8 @@ typedef struct TU_ATTR_ALIGNED(256)
}control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1]; }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32 // ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
ohci_ed_t ed_pool[HCD_MAX_ENDPOINT]; ohci_ed_t ed_pool[ED_MAX];
ohci_gtd_t gtd_pool[HCD_MAX_XFER]; ohci_gtd_t gtd_pool[GTD_MAX];
volatile uint16_t frame_number_hi; volatile uint16_t frame_number_hi;

View File

@ -329,9 +329,11 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// endpoint number / direction // endpoint number / direction
// preamble // preamble
uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB); uint32_t reg = dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB);
// Assert the interrupt endpoint is IN_TO_HOST
// TODO Interrupt can also be OUT if (dir == TUSB_DIR_OUT)
assert(dir == TUSB_DIR_IN); {
reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
}
if (need_pre(dev_addr)) if (need_pre(dev_addr))
{ {

View File

@ -58,8 +58,12 @@ void rp2040_usb_init(void)
unreset_block_wait(RESETS_RESET_USBCTRL_BITS); unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
// Clear any previous state just in case // Clear any previous state just in case
// TODO Suppress warning array-bounds with gcc11
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
memset(usb_hw, 0, sizeof(*usb_hw)); memset(usb_hw, 0, sizeof(*usb_hw));
memset(usb_dpram, 0, sizeof(*usb_dpram)); memset(usb_dpram, 0, sizeof(*usb_dpram));
#pragma GCC diagnostic pop
// Mux the controller to the onboard usb phy // Mux the controller to the onboard usb phy
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS; usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;

View File

@ -110,7 +110,7 @@
#endif #endif
#if CFG_TUD_ENABLED && \ #if CFG_TUD_ENABLED && \
( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4) || \ ( TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32F3, OPT_MCU_STM32L0, OPT_MCU_STM32L1, OPT_MCU_STM32G4, OPT_MCU_STM32WB) || \
(TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \ (TU_CHECK_MCU(OPT_MCU_STM32F1) && defined(STM32F1_FSDEV)) \
) )
@ -328,6 +328,10 @@ void dcd_int_enable (uint8_t rhport)
NVIC_EnableIRQ(USB_LP_IRQn); NVIC_EnableIRQ(USB_LP_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn); NVIC_EnableIRQ(USBWakeUp_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
NVIC_EnableIRQ(USB_HP_IRQn);
NVIC_EnableIRQ(USB_LP_IRQn);
#else #else
#error Unknown arch in USB driver #error Unknown arch in USB driver
#endif #endif
@ -370,6 +374,10 @@ void dcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(USB_LP_IRQn); NVIC_DisableIRQ(USB_LP_IRQn);
NVIC_DisableIRQ(USBWakeUp_IRQn); NVIC_DisableIRQ(USBWakeUp_IRQn);
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
NVIC_DisableIRQ(USB_HP_IRQn);
NVIC_DisableIRQ(USB_LP_IRQn);
#else #else
#error Unknown arch in USB driver #error Unknown arch in USB driver
#endif #endif

View File

@ -91,6 +91,13 @@
#include "stm32g4xx.h" #include "stm32g4xx.h"
#define PMA_LENGTH (1024u) #define PMA_LENGTH (1024u)
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
#include "stm32wbxx.h"
#define PMA_LENGTH (1024u)
/* ST provided header has incorrect value */
#undef USB_PMAADDR
#define USB_PMAADDR USB1_PMAADDR
#else #else
#error You are using an untested or unimplemented STM32 variant. Please update the driver. #error You are using an untested or unimplemented STM32 variant. Please update the driver.
// This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4 // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4

View File

@ -986,16 +986,16 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
/******************** Bit definition for OTG register ********************/ /******************** Bit definition for OTG register ********************/
#define GNPTXFSIZ_NPTXFSA_Pos (0U) #define GNPTXFSIZ_NPTXFSA_Pos (0U)
#define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << NPTXFSA_Pos) // 0x0000FFFF */ #define GNPTXFSIZ_NPTXFSA_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFSA_Pos) // 0x0000FFFF */
#define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */ #define GNPTXFSIZ_NPTXFSA GNPTXFSIZ_NPTXFSA_Msk // Nonperiodic transmit RAM start address */
#define GNPTXFSIZ_NPTXFD_Pos (16U) #define GNPTXFSIZ_NPTXFD_Pos (16U)
#define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << NPTXFD_Pos) // 0xFFFF0000 */ #define GNPTXFSIZ_NPTXFD_Msk (0xFFFFUL << GNPTXFSIZ_NPTXFD_Pos) // 0xFFFF0000 */
#define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */ #define GNPTXFSIZ_NPTXFD GNPTXFSIZ_NPTXFD_Msk // Nonperiodic TxFIFO depth */
#define DIEPTXF0_TX0FSA_Pos (0U) #define DIEPTXF0_TX0FSA_Pos (0U)
#define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << TX0FSA_Pos) // 0x0000FFFF */ #define DIEPTXF0_TX0FSA_Msk (0xFFFFUL << DIEPTXF0_TX0FSA_Pos) // 0x0000FFFF */
#define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */ #define DIEPTXF0_TX0FSA DIEPTXF0_TX0FSA_Msk // Endpoint 0 transmit RAM start address */
#define DIEPTXF0_TX0FD_Pos (16U) #define DIEPTXF0_TX0FD_Pos (16U)
#define DIEPTXF0_TX0FD_Msk (0xFFFFUL << TX0FD_Pos) // 0xFFFF0000 */ #define DIEPTXF0_TX0FD_Msk (0xFFFFUL << DIEPTXF0_TX0FD_Pos) // 0xFFFF0000 */
#define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */ #define DIEPTXF0_TX0FD DIEPTXF0_TX0FD_Msk // Endpoint 0 TxFIFO depth */
/******************** Bit definition for DVBUSPULSE register ********************/ /******************** Bit definition for DVBUSPULSE register ********************/

View File

@ -29,6 +29,7 @@
#if CFG_TUH_ENABLED || CFG_TUD_ENABLED #if CFG_TUH_ENABLED || CFG_TUD_ENABLED
#include "tusb.h" #include "tusb.h"
#include "common/tusb_private.h"
// TODO clean up // TODO clean up
#if CFG_TUD_ENABLED #if CFG_TUD_ENABLED
@ -67,6 +68,52 @@ bool tusb_inited(void)
// Internal Helper for both Host and Device stack // Internal Helper for both Host and Device stack
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool tu_edpt_claim(tu_edpt_state_t* ep_state, osal_mutex_t mutex)
{
(void) mutex;
#if TUSB_OPT_MUTEX
// pre-check to help reducing mutex lock
TU_VERIFY((ep_state->busy == 0) && (ep_state->claimed == 0));
osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
#endif
// can only claim the endpoint if it is not busy and not claimed yet.
bool const available = (ep_state->busy == 0) && (ep_state->claimed == 0);
if (available)
{
ep_state->claimed = 1;
}
#if TUSB_OPT_MUTEX
osal_mutex_unlock(mutex);
#endif
return available;
}
bool tu_edpt_release(tu_edpt_state_t* ep_state, osal_mutex_t mutex)
{
(void) mutex;
#if TUSB_OPT_MUTEX
osal_mutex_lock(mutex, OSAL_TIMEOUT_WAIT_FOREVER);
#endif
// can only release the endpoint if it is claimed and not busy
bool const ret = (ep_state->claimed == 1) && (ep_state->busy == 0);
if (ret)
{
ep_state->claimed = 0;
}
#if TUSB_OPT_MUTEX
osal_mutex_unlock(mutex);
#endif
return ret;
}
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed) bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed)
{ {
uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep); uint16_t const max_packet_size = tu_edpt_packet_size(desc_ep);
@ -161,9 +208,27 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf,
#if CFG_TUSB_DEBUG #if CFG_TUSB_DEBUG
#include <ctype.h> #include <ctype.h>
char const* const tusb_strerr[TUSB_ERROR_COUNT] = { ERROR_TABLE(ERROR_STRING) }; #if CFG_TUSB_DEBUG >= 2
char const* const tusb_speed_str[] = { "Full", "Low", "High" }; char const* const tu_str_speed[] = { "Full", "Low", "High" };
char const* const tu_str_std_request[] =
{
"Get Status" ,
"Clear Feature" ,
"Reserved" ,
"Set Feature" ,
"Reserved" ,
"Set Address" ,
"Get Descriptor" ,
"Set Descriptor" ,
"Get Configuration" ,
"Set Configuration" ,
"Get Interface" ,
"Set Interface" ,
"Synch Frame"
};
#endif
static void dump_str_line(uint8_t const* buf, uint16_t count) static void dump_str_line(uint8_t const* buf, uint16_t count)
{ {

View File

@ -38,6 +38,8 @@
#include "osal/osal.h" #include "osal/osal.h"
#include "common/tusb_fifo.h" #include "common/tusb_fifo.h"
#include "class/hid/hid.h"
//------------- HOST -------------// //------------- HOST -------------//
#if CFG_TUH_ENABLED #if CFG_TUH_ENABLED
#include "host/usbh.h" #include "host/usbh.h"
@ -117,8 +119,6 @@
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// APPLICATION API // APPLICATION API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
/** \ingroup group_application_api
* @{ */
// Initialize device/host stack // Initialize device/host stack
// Note: when using with RTOS, this should be called after scheduler/kernel is started. // Note: when using with RTOS, this should be called after scheduler/kernel is started.
@ -131,8 +131,6 @@ bool tusb_inited(void);
// TODO // TODO
// bool tusb_teardown(void); // bool tusb_teardown(void);
/** @} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -80,6 +80,7 @@
#define OPT_MCU_STM32L4 309 ///< ST L4 #define OPT_MCU_STM32L4 309 ///< ST L4
#define OPT_MCU_STM32G0 310 ///< ST G0 #define OPT_MCU_STM32G0 310 ///< ST G0
#define OPT_MCU_STM32G4 311 ///< ST G4 #define OPT_MCU_STM32G4 311 ///< ST G4
#define OPT_MCU_STM32WB 312 ///< ST WB
// Sony // Sony
#define OPT_MCU_CXD56 400 ///< SONY CXD56 #define OPT_MCU_CXD56 400 ///< SONY CXD56
@ -207,18 +208,23 @@
//------------- Roothub as Device -------------// //------------- Roothub as Device -------------//
#if (CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE #if (CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE) #define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
#define TUD_OPT_RHPORT 0 #define TUD_OPT_RHPORT 0
#elif (CFG_TUSB_RHPORT1_MODE) & OPT_MODE_DEVICE #elif (CFG_TUSB_RHPORT1_MODE) & OPT_MODE_DEVICE
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT1_MODE) #define TUD_RHPORT_MODE (CFG_TUSB_RHPORT1_MODE)
#define TUD_OPT_RHPORT 1 #define TUD_OPT_RHPORT 1
#else #else
#define TUD_RHPORT_MODE OPT_MODE_NONE #define TUD_RHPORT_MODE OPT_MODE_NONE
#define TUD_OPT_RHPORT -1 #define TUD_OPT_RHPORT -1
#endif #endif
#define CFG_TUD_ENABLED ( TUD_RHPORT_MODE & OPT_MODE_DEVICE ) #define CFG_TUD_ENABLED (TUD_RHPORT_MODE & OPT_MODE_DEVICE)
#define TUD_OPT_HIGH_SPEED ( (TUD_RHPORT_MODE & OPT_MODE_SPEED_MASK) ? (TUD_RHPORT_MODE & OPT_MODE_HIGH_SPEED) : (TUP_RHPORT_HIGHSPEED & (1 << TUD_OPT_RHPORT)) )
#if CFG_TUD_ENABLED
#define TUD_OPT_HIGH_SPEED ((TUD_RHPORT_MODE & OPT_MODE_SPEED_MASK) ? (TUD_RHPORT_MODE & OPT_MODE_HIGH_SPEED) : (TUP_RHPORT_HIGHSPEED & (1 << TUD_OPT_RHPORT)))
#else
#define TUD_OPT_HIGH_SPEED 0
#endif
//------------- Roothub as Host -------------// //------------- Roothub as Host -------------//
@ -383,11 +389,16 @@
#define CFG_TUH_VENDOR 0 #define CFG_TUH_VENDOR 0
#endif #endif
#ifndef CFG_TUH_API_EDPT_XFER
#define CFG_TUH_API_EDPT_XFER 0
#endif
// Enable PIO-USB software host controller // Enable PIO-USB software host controller
#ifndef CFG_TUH_RPI_PIO_USB #ifndef CFG_TUH_RPI_PIO_USB
#define CFG_TUH_RPI_PIO_USB 0 #define CFG_TUH_RPI_PIO_USB 0
#endif #endif
//------------------------------------------------------------------ //------------------------------------------------------------------
// Configuration Validation // Configuration Validation
//------------------------------------------------------------------ //------------------------------------------------------------------