mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-31 05:52:55 +08:00
Merge branch 'master' into pio-host
This commit is contained in:
commit
45052c625e
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -60,11 +60,12 @@ body:
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Debug Log
|
||||
label: Debug Log as txt file
|
||||
placeholder: |
|
||||
TinyUSB debug log where the issue occurred as attached txt file, 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.
|
||||
Attach your debug log txt file here, where the issue occurred, best with comments to explain the actual events.
|
||||
|
||||
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)
|
||||
validations:
|
||||
required: false
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -97,6 +97,12 @@
|
||||
[submodule "hw/mcu/st/stm32l5xx_hal_driver"]
|
||||
path = hw/mcu/st/stm32l5xx_hal_driver
|
||||
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"]
|
||||
path = lib/sct_neopixel
|
||||
url = https://github.com/gsteiert/sct_neopixel
|
||||
|
@ -42,7 +42,7 @@ Supported MCUs
|
||||
+--------------+---------+-------------+--------+------+-----------+-------------------+--------------+
|
||||
| NXP | iMXRT | RT10xx | ✔ | ✔ | ✔ | ci_hs | |
|
||||
| +---------+-------------+--------+------+-----------+-------------------+--------------+
|
||||
| | Kinetis | KL25 | ✔ | ⚠ | ✖ | | |
|
||||
| | Kinetis | KL25 | ✔ | ⚠ | ✖ | | |
|
||||
| | +-------------+--------+------+-----------+-------------------+--------------+
|
||||
| | | K32L2 | ✔ | | ✖ | | |
|
||||
| +---------+-------------+--------+------+-----------+-------------------+--------------+
|
||||
|
@ -31,5 +31,5 @@ target_sources(${COMPONENT_TARGET} PUBLIC
|
||||
"${TOP}/src/class/net/ncm_device.c"
|
||||
"${TOP}/src/class/usbtmc/usbtmc_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"
|
||||
)
|
||||
|
@ -86,7 +86,7 @@ enum
|
||||
|
||||
#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \
|
||||
/* 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) */\
|
||||
TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\
|
||||
/* Class-Specific AC Interface Header Descriptor(4.7.2) */\
|
||||
|
27
examples/host/bare_api/CMakeLists.txt
Normal file
27
examples/host/bare_api/CMakeLists.txt
Normal 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})
|
27
examples/host/bare_api/Makefile
Normal file
27
examples/host/bare_api/Makefile
Normal 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
|
9
examples/host/bare_api/only.txt
Normal file
9
examples/host/bare_api/only.txt
Normal 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
|
416
examples/host/bare_api/src/main.c
Normal file
416
examples/host/bare_api/src/main.c
Normal 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);
|
||||
}
|
94
examples/host/bare_api/src/tusb_config.h
Normal file
94
examples/host/bare_api/src/tusb_config.h
Normal 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_ */
|
@ -19,7 +19,6 @@ SRC_C += \
|
||||
src/class/msc/msc_host.c \
|
||||
src/host/hub.c \
|
||||
src/host/usbh.c \
|
||||
src/host/usbh_control.c \
|
||||
src/portable/ohci/ohci.c \
|
||||
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
|
||||
|
||||
|
@ -71,20 +71,6 @@ int main(void)
|
||||
#if CFG_TUH_CDC
|
||||
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
|
||||
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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
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
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -22,7 +22,6 @@ SRC_C += \
|
||||
src/class/msc/msc_host.c \
|
||||
src/host/hub.c \
|
||||
src/host/usbh.c \
|
||||
src/host/usbh_control.c \
|
||||
src/portable/ohci/ohci.c \
|
||||
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
|
||||
|
||||
|
@ -14,7 +14,6 @@ CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
|
||||
SRC_C += \
|
||||
src/class/hid/hid_host.c \
|
||||
src/host/hub.c \
|
||||
src/host/usbh.c \
|
||||
src/host/usbh_control.c
|
||||
src/host/usbh.c
|
||||
|
||||
include ../../rules.mk
|
||||
|
@ -83,7 +83,6 @@ if (NOT TARGET _rp2040_family_inclusion_marker)
|
||||
${TOP}/src/portable/raspberrypi/rp2040/hcd_rp2040.c
|
||||
${TOP}/src/portable/raspberrypi/rp2040/rp2040_usb.c
|
||||
${TOP}/src/host/usbh.c
|
||||
${TOP}/src/host/usbh_control.c
|
||||
${TOP}/src/host/hub.c
|
||||
${TOP}/src/class/cdc/cdc_host.c
|
||||
${TOP}/src/class/hid/hid_host.c
|
||||
|
122
hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h
Normal file
122
hw/bsp/stm32wb/boards/stm32wb55nucleo/board.h
Normal 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_ */
|
9
hw/bsp/stm32wb/boards/stm32wb55nucleo/board.mk
Normal file
9
hw/bsp/stm32wb/boards/stm32wb55nucleo/board.mk
Normal 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
|
171
hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld
Normal file
171
hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld
Normal 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
190
hw/bsp/stm32wb/family.c
Normal 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
44
hw/bsp/stm32wb/family.mk
Normal 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
|
349
hw/bsp/stm32wb/stm32wbxx_hal_conf.h
Normal file
349
hw/bsp/stm32wb/stm32wbxx_hal_conf.h
Normal file
@ -0,0 +1,349 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32wbxx_hal_conf.h
|
||||
* @author MCD Application Team
|
||||
* @brief HAL configuration file.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© 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****/
|
1
hw/mcu/st/cmsis_device_wb
Submodule
1
hw/mcu/st/cmsis_device_wb
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 9c5d1920dd9fabbe2548e10561d63db829bb744f
|
1
hw/mcu/st/stm32wbxx_hal_driver
Submodule
1
hw/mcu/st/stm32wbxx_hal_driver
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 2c5f06638be516c1b772f768456ba637f077bac8
|
@ -9,7 +9,9 @@ repo.versions:
|
||||
"0.10.0": "0.10.0"
|
||||
"0.10.1": "0.10.1"
|
||||
"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-latest": "0.11.0" # latest stable release
|
||||
"0-latest": "0.13.0" # latest stable release
|
||||
|
||||
|
@ -100,7 +100,7 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i
|
||||
{
|
||||
(void) is_notify;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.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
|
||||
};
|
||||
|
||||
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, complete_cb) );
|
||||
return true;
|
||||
tuh_xfer_t xfer =
|
||||
{
|
||||
.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)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) max_len;
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
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;
|
||||
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 )
|
||||
{
|
||||
|
@ -42,14 +42,14 @@
|
||||
* \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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ typedef struct {
|
||||
}rndish_data_t;
|
||||
|
||||
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_close(uint8_t dev_addr);
|
||||
|
||||
|
@ -43,7 +43,7 @@
|
||||
/** \defgroup ClassDriver_HID_Common Common Definitions
|
||||
* @{ */
|
||||
|
||||
/// USB HID Descriptor
|
||||
/// USB HID Descriptor
|
||||
typedef struct TU_ATTR_PACKED
|
||||
{
|
||||
uint8_t bLength; /**< Numeric expression that is the total size of the HID descriptor */
|
||||
|
@ -103,27 +103,27 @@ uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
|
||||
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 instance = get_instance_id_by_itfnum(dev_addr, itf_num);
|
||||
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
|
||||
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
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,
|
||||
.wValue = protocol,
|
||||
.wIndex = hid_itf->itf_num,
|
||||
.wIndex = itf_num,
|
||||
.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;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
if (tuh_hid_set_report_complete_cb)
|
||||
{
|
||||
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 itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
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_id = tu_u16_low(request->wValue);
|
||||
uint8_t const report_type = tu_u16_high(xfer->setup->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)
|
||||
@ -181,7 +198,50 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u
|
||||
.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;
|
||||
}
|
||||
|
||||
@ -196,7 +256,13 @@ bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
|
||||
// claim endpoint
|
||||
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)
|
||||
@ -256,14 +322,9 @@ void hidh_close(uint8_t dev_addr)
|
||||
// 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)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) max_len;
|
||||
|
||||
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);
|
||||
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);
|
||||
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
|
||||
// TODO also open endpoint OUT
|
||||
if(tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_OUT)
|
||||
for(int i = 0; i < desc_itf->bNumEndpoints; i++)
|
||||
{
|
||||
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);
|
||||
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_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
|
||||
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;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// 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)
|
||||
{
|
||||
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
|
||||
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
|
||||
tusb_control_request_t request;
|
||||
request.wIndex = tu_htole16((uint16_t) itf_num);
|
||||
|
||||
// Idle rate = 0 mean only report when there is changes
|
||||
uint16_t const idle_rate = 0;
|
||||
tuh_xfer_t xfer;
|
||||
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
|
||||
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
|
||||
};
|
||||
|
||||
TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, (hid_itf->itf_protocol != HID_ITF_PROTOCOL_NONE) ? config_set_protocol : config_get_report_desc) );
|
||||
// fake request to kick-off the set config process
|
||||
process_set_config(&xfer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Force device to work in BOOT protocol
|
||||
static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
|
||||
static void process_set_config(tuh_xfer_t* xfer)
|
||||
{
|
||||
// Stall is a valid response for SET_IDLE, therefore we could ignore its result
|
||||
(void) result;
|
||||
|
||||
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 =
|
||||
if ( xfer->setup->bRequest != HID_REQ_CONTROL_SET_IDLE )
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
.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);
|
||||
TU_ASSERT(xfer->result == XFER_RESULT_SUCCESS, );
|
||||
}
|
||||
|
||||
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);
|
||||
uintptr_t const state = xfer->user_data;
|
||||
uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
|
||||
// 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 )
|
||||
{
|
||||
TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
|
||||
uint8_t const instance = get_instance_id_by_itfnum(daddr, itf_num);
|
||||
hidh_interface_t* hid_itf = get_instance(daddr, instance);
|
||||
|
||||
// Driver is mounted without report descriptor
|
||||
config_driver_mount_complete(dev_addr, instance, NULL, 0);
|
||||
}else
|
||||
switch(state)
|
||||
{
|
||||
TU_LOG2("HID Get Report Descriptor\r\n");
|
||||
tusb_control_request_t const new_request =
|
||||
case CONFG_SET_IDLE:
|
||||
{
|
||||
.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,
|
||||
.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_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", 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)
|
||||
|
@ -358,13 +358,14 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
|
||||
// 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_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);
|
||||
|
||||
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 &&
|
||||
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++)
|
||||
{
|
||||
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 )
|
||||
{
|
||||
@ -405,7 +406,7 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
|
||||
|
||||
//------------- Get Max Lun -------------//
|
||||
TU_LOG2("MSC Get Max Lun\r\n");
|
||||
tusb_control_request_t request =
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
@ -418,27 +419,34 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
|
||||
.wIndex = itf_num,
|
||||
.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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
msch_interface_t* p_msc = get_itf(daddr);
|
||||
|
||||
// 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
|
||||
|
||||
// TODO multiple LUN support
|
||||
TU_LOG2("SCSI Test Unit Ready\r\n");
|
||||
uint8_t const lun = 0;
|
||||
tuh_msc_test_unit_ready(dev_addr, lun, config_test_unit_ready_complete);
|
||||
|
||||
return true;
|
||||
tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete);
|
||||
}
|
||||
|
||||
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
|
||||
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_size = tu_ntohl(resp->block_size);
|
||||
p_msc->capacity[cbw->lun].block_size = tu_ntohl(resp->block_size);
|
||||
|
||||
// Mark enumeration is complete
|
||||
p_msc->mounted = true;
|
||||
|
17
src/class/vendor/vendor_device.c
vendored
17
src/class/vendor/vendor_device.c
vendored
@ -113,7 +113,7 @@ void tud_vendor_n_read_flush (uint8_t itf)
|
||||
//--------------------------------------------------------------------+
|
||||
// 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
|
||||
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) );
|
||||
}
|
||||
return true;
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize)
|
||||
{
|
||||
vendord_interface_t* p_itf = &_vendord_itf[itf];
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 )
|
||||
{
|
||||
if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, xferred_bytes);
|
||||
// Send complete, try to send more if possible
|
||||
maybe_transmit(p_itf);
|
||||
}
|
||||
|
9
src/class/vendor/vendor_device.h
vendored
9
src/class/vendor/vendor_device.h
vendored
@ -52,6 +52,7 @@ uint32_t tud_vendor_n_write_available (uint8_t itf);
|
||||
|
||||
static inline
|
||||
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)
|
||||
@ -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_str (char const* str);
|
||||
static inline uint32_t tud_vendor_write_available (void);
|
||||
static inline uint32_t tud_vendor_flush (void);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Application Callback API (weak is optional)
|
||||
@ -71,6 +73,8 @@ static inline uint32_t tud_vendor_write_available (void);
|
||||
|
||||
// Invoked when received new data
|
||||
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
|
||||
@ -121,6 +125,11 @@ static inline uint32_t tud_vendor_write_available (void)
|
||||
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
|
||||
//--------------------------------------------------------------------+
|
||||
|
12
src/class/vendor/vendor_host.h
vendored
12
src/class/vendor/vendor_host.h
vendored
@ -49,16 +49,16 @@ static inline bool tusbh_custom_is_mounted(uint8_t dev_addr, uint16_t vendor_id,
|
||||
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);
|
||||
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_read(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, 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
|
||||
//--------------------------------------------------------------------+
|
||||
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);
|
||||
void cush_isr(pipe_handle_t pipe_hdl, xfer_result_t event);
|
||||
void cush_close(uint8_t dev_addr);
|
||||
void cush_init(void);
|
||||
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_close(uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define TU_MIN(_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_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff))
|
||||
#define U16_TO_U8S_BE(_u16) TU_U16_HIGH(_u16), TU_U16_LOW(_u16)
|
||||
@ -70,23 +71,10 @@
|
||||
#include "tusb_compiler.h"
|
||||
#include "tusb_verify.h"
|
||||
#include "tusb_types.h"
|
||||
#include "tusb_debug.h"
|
||||
|
||||
#include "tusb_error.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
|
||||
//--------------------------------------------------------------------+
|
||||
@ -267,138 +255,6 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16 (void* mem, ui
|
||||
+ TU_BIN8(dlsb))
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
|
@ -51,10 +51,10 @@
|
||||
#endif
|
||||
|
||||
// Compile-time Assert
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
#define TU_VERIFY_STATIC _Static_assert
|
||||
#elif defined (__cplusplus) && __cplusplus >= 201103L
|
||||
#if defined (__cplusplus) && __cplusplus >= 201103L
|
||||
#define TU_VERIFY_STATIC static_assert
|
||||
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
#define TU_VERIFY_STATIC _Static_assert
|
||||
#elif defined(__CCRX__)
|
||||
#define TU_VERIFY_STATIC(const_expr, _mess) typedef char TU_XSTRCAT(Line, __LINE__)[(const_expr) ? 1 : 0];
|
||||
#else
|
||||
|
174
src/common/tusb_debug.h
Normal file
174
src/common/tusb_debug.h
Normal 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_ */
|
@ -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_ */
|
||||
|
||||
/** @} */
|
@ -184,6 +184,9 @@
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
#endif
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
//------------- Sony -------------//
|
||||
#elif TU_CHECK_MCU(OPT_MCU_CXD56)
|
||||
#define TUP_DCD_ENDPOINT_MAX 7
|
||||
|
65
src/common/tusb_private.h
Normal file
65
src/common/tusb_private.h
Normal 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_ */
|
@ -223,19 +223,13 @@ enum {
|
||||
|
||||
#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
|
||||
{
|
||||
XFER_RESULT_SUCCESS,
|
||||
XFER_RESULT_FAILED,
|
||||
XFER_RESULT_STALLED,
|
||||
XFER_RESULT_TIMEOUT,
|
||||
XFER_RESULT_INVALID
|
||||
}xfer_result_t;
|
||||
|
||||
enum // TODO remove
|
||||
@ -265,6 +259,7 @@ typedef enum
|
||||
|
||||
enum
|
||||
{
|
||||
CONTROL_STAGE_IDLE,
|
||||
CONTROL_STAGE_SETUP,
|
||||
CONTROL_STAGE_DATA,
|
||||
CONTROL_STAGE_ACK
|
||||
|
@ -74,10 +74,8 @@
|
||||
|
||||
#if CFG_TUSB_DEBUG
|
||||
#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__)
|
||||
#else
|
||||
#define _MESS_ERR(_err) do {} while (0)
|
||||
#define _MESS_FAILED() do {} while (0)
|
||||
#endif
|
||||
|
||||
@ -144,32 +142,6 @@
|
||||
#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
|
||||
#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
|
||||
*------------------------------------------------------------------*/
|
||||
|
@ -29,6 +29,8 @@
|
||||
#if CFG_TUD_ENABLED
|
||||
|
||||
#include "tusb.h"
|
||||
#include "common/tusb_private.h"
|
||||
|
||||
#include "device/usbd.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
#include "device/dcd.h"
|
||||
@ -67,17 +69,10 @@ typedef struct
|
||||
volatile uint8_t cfg_num; // current active configuration (0x00 is not configured)
|
||||
uint8_t speed;
|
||||
|
||||
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 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 ), can use only 4-bit each
|
||||
|
||||
struct TU_ATTR_PACKED
|
||||
{
|
||||
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];
|
||||
tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2];
|
||||
|
||||
}usbd_device_t;
|
||||
|
||||
@ -273,7 +268,7 @@ enum { RHPORT_INVALID = 0xFFu };
|
||||
static uint8_t _usbd_rhport = RHPORT_INVALID;
|
||||
|
||||
// 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);
|
||||
static osal_queue_t _usbd_q;
|
||||
|
||||
@ -315,23 +310,6 @@ static char const* const _usbd_event_str[DCD_EVENT_COUNT] =
|
||||
"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
|
||||
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;
|
||||
|
||||
TU_LOG2("USBD init\r\n");
|
||||
TU_LOG2_INT(sizeof(usbd_device_t));
|
||||
|
||||
tu_varclr(&_usbd_dev);
|
||||
|
||||
@ -507,7 +486,7 @@ void tud_task (void)
|
||||
switch ( event.event_id )
|
||||
{
|
||||
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_dev.speed = event.bus_reset.speed;
|
||||
break;
|
||||
@ -649,7 +628,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
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");
|
||||
}
|
||||
#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
|
||||
// TU_VERIFY(tud_ready());
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
uint8_t const epnum = tu_edpt_number(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
|
||||
// pre-check to help reducing mutex lock
|
||||
TU_VERIFY((_usbd_dev.ep_status[epnum][dir].busy == 0) && (_usbd_dev.ep_status[epnum][dir].claimed == 0));
|
||||
osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
#if TUSB_OPT_MUTEX
|
||||
return tu_edpt_claim(ep_state, _usbd_mutex);
|
||||
#else
|
||||
return tu_edpt_claim(ep_state, NULL);
|
||||
#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)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
uint8_t const epnum = tu_edpt_number(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
|
||||
osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
#if TUSB_OPT_MUTEX
|
||||
return tu_edpt_release(ep_state, _usbd_mutex);
|
||||
#else
|
||||
return tu_edpt_release(ep_state, NULL);
|
||||
#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)
|
||||
|
@ -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.
|
||||
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);
|
||||
|
||||
// Check if endpoint is busy transferring
|
||||
|
@ -35,6 +35,19 @@
|
||||
extern "C" {
|
||||
#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
|
||||
//--------------------------------------------------------------------+
|
||||
@ -81,26 +94,14 @@ typedef struct
|
||||
|
||||
} hcd_event_t;
|
||||
|
||||
#if CFG_TUH_ENABLED
|
||||
// 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 {
|
||||
typedef struct
|
||||
{
|
||||
uint8_t rhport;
|
||||
uint8_t hub_addr;
|
||||
uint8_t hub_port;
|
||||
uint8_t speed;
|
||||
} hcd_devtree_info_t;
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
//--------------------------------------------------------------------+
|
||||
|
159
src/host/hub.c
159
src/host/hub.c
@ -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];
|
||||
}
|
||||
|
||||
#if CFG_TUSB_DEBUG
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
static char const* const _hub_feature_str[] =
|
||||
{
|
||||
[HUB_FEATURE_PORT_CONNECTION ] = "PORT_CONNECTION",
|
||||
@ -77,7 +77,8 @@ static char const* const _hub_feature_str[] =
|
||||
//--------------------------------------------------------------------+
|
||||
// HUB
|
||||
//--------------------------------------------------------------------+
|
||||
bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_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 =
|
||||
{
|
||||
@ -93,12 +94,23 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
.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_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) );
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_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 =
|
||||
{
|
||||
@ -114,17 +126,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, t
|
||||
.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_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) );
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb)
|
||||
{
|
||||
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)
|
||||
bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
@ -140,8 +158,18 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
|
||||
.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_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) );
|
||||
TU_ASSERT( tuh_control_xfer(&xfer) );
|
||||
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)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
|
||||
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 &&
|
||||
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);
|
||||
|
||||
@ -189,7 +219,7 @@ void hub_close(uint8_t dev_addr)
|
||||
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);
|
||||
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
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||
static bool config_port_power_complete (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 void config_port_power_complete (tuh_xfer_t* xfer);
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 == result);
|
||||
TU_ASSERT(XFER_RESULT_SUCCESS == xfer->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
|
||||
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
|
||||
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);
|
||||
hub_interface_t* p_hub = get_itf(dev_addr);
|
||||
TU_ASSERT(XFER_RESULT_SUCCESS == xfer->result, );
|
||||
|
||||
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
|
||||
// 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
|
||||
{
|
||||
// power next port
|
||||
uint8_t const hub_port = (uint8_t) (request->wIndex + 1);
|
||||
return hub_port_set_feature(dev_addr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete);
|
||||
uint8_t const hub_port = (uint8_t) (xfer->setup->wIndex + 1);
|
||||
hub_port_set_feature(daddr, hub_port, HUB_FEATURE_PORT_POWER, config_port_power_complete, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Connection Changes
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||
static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||
static bool connection_port_reset_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 void connection_clear_conn_change_complete (tuh_xfer_t* xfer);
|
||||
static void connection_port_reset_complete (tuh_xfer_t* xfer);
|
||||
|
||||
// callback as response of interrupt endpoint polling
|
||||
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
@ -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) )
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -302,12 +342,13 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
|
||||
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 port_num = (uint8_t) request->wIndex;
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
|
||||
// Connection change
|
||||
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, );
|
||||
|
||||
// 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
|
||||
{
|
||||
// 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
|
||||
// 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 port_num = (uint8_t) request->wIndex;
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
|
||||
if ( p_hub->port_status.status.connection )
|
||||
{
|
||||
// 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
|
||||
{
|
||||
// submit detach event
|
||||
hcd_event_t event =
|
||||
{
|
||||
.rhport = usbh_get_rhport(dev_addr),
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = HCD_EVENT_DEVICE_REMOVE,
|
||||
.connection =
|
||||
{
|
||||
.hub_addr = dev_addr,
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
|
||||
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 port_num = (uint8_t) request->wIndex;
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
// hub_interface_t* p_hub = get_itf(daddr);
|
||||
uint8_t const port_num = (uint8_t) tu_le16toh(xfer->setup->wIndex);
|
||||
|
||||
// submit attach event
|
||||
hcd_event_t event =
|
||||
{
|
||||
.rhport = usbh_get_rhport(dev_addr),
|
||||
.rhport = usbh_get_rhport(daddr),
|
||||
.event_id = HCD_EVENT_DEVICE_ATTACH,
|
||||
.connection =
|
||||
{
|
||||
.hub_addr = dev_addr,
|
||||
.hub_addr = daddr,
|
||||
.hub_port = port_num
|
||||
}
|
||||
};
|
||||
|
||||
hcd_event_handler(&event, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -171,12 +171,35 @@ typedef struct {
|
||||
|
||||
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);
|
||||
bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb);
|
||||
// Clear feature
|
||||
bool hub_port_clear_feature (uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data);
|
||||
|
||||
// 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
|
||||
|
1496
src/host/usbh.c
1496
src/host/usbh.c
File diff suppressed because it is too large
Load Diff
165
src/host/usbh.h
165
src/host/usbh.h
@ -38,7 +38,48 @@
|
||||
// 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
|
||||
@ -57,40 +98,132 @@ void tuh_task(void);
|
||||
extern void hcd_int_handler(uint8_t rhport);
|
||||
#define tuh_int_handler hcd_int_handler
|
||||
|
||||
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid);
|
||||
tusb_speed_t tuh_speed_get(uint8_t dev_addr);
|
||||
bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
|
||||
|
||||
tusb_speed_t tuh_speed_get(uint8_t daddr);
|
||||
|
||||
// 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
|
||||
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
|
||||
(void) dev_addr;
|
||||
(void) daddr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if device is ready to communicate with
|
||||
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)
|
||||
TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr);
|
||||
// Get an descriptor (control transfer)
|
||||
// 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)
|
||||
TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr);
|
||||
// Get device descriptor (control transfer)
|
||||
// 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
|
||||
}
|
||||
|
@ -63,16 +63,22 @@ void usbh_int_set(bool enabled);
|
||||
// USBH Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Open an endpoint
|
||||
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
|
||||
// Submit a usb transfer with callback support, require CFG_TUH_API_EDPT_XFER
|
||||
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.
|
||||
// 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);
|
||||
|
||||
// Release claimed endpoint without submitting a transfer
|
||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
// Check if endpoint transferring is complete
|
||||
|
@ -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
|
@ -111,7 +111,7 @@ typedef struct
|
||||
|
||||
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) \
|
||||
uint8_t _name##_buf[_depth*sizeof(_type)]; \
|
||||
osal_queue_def_t _name = { \
|
||||
|
@ -35,6 +35,7 @@
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "host/hcd.h"
|
||||
#include "portable/ehci/ehci_api.h"
|
||||
#include "ci_hs_type.h"
|
||||
|
||||
|
@ -58,6 +58,9 @@
|
||||
|
||||
#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
|
||||
{
|
||||
ehci_link_t period_framelist[FRAMELIST_SIZE];
|
||||
@ -73,8 +76,8 @@ typedef struct
|
||||
ehci_qtd_t qtd;
|
||||
}control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
|
||||
|
||||
ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT];
|
||||
ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32);
|
||||
ehci_qhd_t qhd_pool[QHD_MAX];
|
||||
ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
|
||||
|
||||
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) )
|
||||
{
|
||||
// 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);
|
||||
#pragma GCC diagnostic pop
|
||||
if ( qhd->dev_addr == dev_addr )
|
||||
{
|
||||
// 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;
|
||||
|
||||
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 )
|
||||
{
|
||||
@ -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
|
||||
while( !next_item.terminate &&
|
||||
!(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 )
|
||||
{
|
||||
@ -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 -------------//
|
||||
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)
|
||||
{
|
||||
uint32_t port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
|
||||
|
||||
TU_LOG_HEX(EHCI_DBG, regs->portsc);
|
||||
uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_ALL;
|
||||
print_portsc(regs);
|
||||
|
||||
if (regs->portsc_bm.connect_status_change)
|
||||
{
|
||||
@ -714,7 +740,7 @@ void hcd_int_handler(uint8_t rhport)
|
||||
//------------- queue head helper -------------//
|
||||
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];
|
||||
}
|
||||
@ -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;
|
||||
|
||||
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) &&
|
||||
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 -------------//
|
||||
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];
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ typedef struct
|
||||
|
||||
// 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 non_hs_split_state : 1 ; ///< Used by HC to track the state of slipt transaction
|
||||
volatile uint32_t non_hs_missed_uframe : 1 ; ///< HC misses a complete slip 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 split transaction
|
||||
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 buffer_err : 1 ; ///< Data overrun/underrun error
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/dport_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/usb_periph.h"
|
||||
|
@ -125,7 +125,7 @@ typedef struct
|
||||
uint16_t bda[2*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 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. */
|
||||
@ -142,7 +142,7 @@ int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
/* Find the target pipe */
|
||||
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];
|
||||
if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
|
||||
return num;
|
||||
@ -463,7 +463,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
|
||||
const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
|
||||
NVIC_DisableIRQ(USB0_IRQn);
|
||||
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) {
|
||||
if (p->dev_addr == dev_addr)
|
||||
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);
|
||||
/* Find a free pipe */
|
||||
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) {
|
||||
p += 2;
|
||||
for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;
|
||||
|
@ -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;
|
||||
|
||||
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) &&
|
||||
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;
|
||||
|
||||
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];
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ enum {
|
||||
OHCI_MAX_ITD = 4
|
||||
};
|
||||
|
||||
#define ED_MAX (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
|
||||
#define GTD_MAX ED_MAX
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// OHCI Data Structure
|
||||
//--------------------------------------------------------------------+
|
||||
@ -162,8 +165,8 @@ typedef struct TU_ATTR_ALIGNED(256)
|
||||
}control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
|
||||
|
||||
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
|
||||
ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
|
||||
ohci_gtd_t gtd_pool[HCD_MAX_XFER];
|
||||
ohci_ed_t ed_pool[ED_MAX];
|
||||
ohci_gtd_t gtd_pool[GTD_MAX];
|
||||
|
||||
volatile uint16_t frame_number_hi;
|
||||
|
||||
|
@ -329,9 +329,11 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
|
||||
// endpoint number / direction
|
||||
// preamble
|
||||
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
|
||||
assert(dir == TUSB_DIR_IN);
|
||||
|
||||
if (dir == TUSB_DIR_OUT)
|
||||
{
|
||||
reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
|
||||
}
|
||||
|
||||
if (need_pre(dev_addr))
|
||||
{
|
||||
|
@ -58,8 +58,12 @@ void rp2040_usb_init(void)
|
||||
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
|
||||
|
||||
// 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_dpram, 0, sizeof(*usb_dpram));
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
// Mux the controller to the onboard usb phy
|
||||
usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
|
||||
|
@ -110,7 +110,7 @@
|
||||
#endif
|
||||
|
||||
#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)) \
|
||||
)
|
||||
|
||||
@ -328,6 +328,10 @@ void dcd_int_enable (uint8_t rhport)
|
||||
NVIC_EnableIRQ(USB_LP_IRQn);
|
||||
NVIC_EnableIRQ(USBWakeUp_IRQn);
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
|
||||
NVIC_EnableIRQ(USB_HP_IRQn);
|
||||
NVIC_EnableIRQ(USB_LP_IRQn);
|
||||
|
||||
#else
|
||||
#error Unknown arch in USB driver
|
||||
#endif
|
||||
@ -370,6 +374,10 @@ void dcd_int_disable(uint8_t rhport)
|
||||
NVIC_DisableIRQ(USB_LP_IRQn);
|
||||
NVIC_DisableIRQ(USBWakeUp_IRQn);
|
||||
|
||||
#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
|
||||
NVIC_DisableIRQ(USB_HP_IRQn);
|
||||
NVIC_DisableIRQ(USB_LP_IRQn);
|
||||
|
||||
#else
|
||||
#error Unknown arch in USB driver
|
||||
#endif
|
||||
|
@ -91,6 +91,13 @@
|
||||
#include "stm32g4xx.h"
|
||||
#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
|
||||
#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
|
||||
|
@ -986,16 +986,16 @@ TU_VERIFY_STATIC(offsetof(dwc2_regs_t, fifo ) == 0x1000, "incorrect size");
|
||||
|
||||
/******************** Bit definition for OTG register ********************/
|
||||
#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_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 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_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 */
|
||||
|
||||
/******************** Bit definition for DVBUSPULSE register ********************/
|
||||
|
69
src/tusb.c
69
src/tusb.c
@ -29,6 +29,7 @@
|
||||
#if CFG_TUH_ENABLED || CFG_TUD_ENABLED
|
||||
|
||||
#include "tusb.h"
|
||||
#include "common/tusb_private.h"
|
||||
|
||||
// TODO clean up
|
||||
#if CFG_TUD_ENABLED
|
||||
@ -67,6 +68,52 @@ bool tusb_inited(void)
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
#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)
|
||||
{
|
||||
|
@ -38,6 +38,8 @@
|
||||
#include "osal/osal.h"
|
||||
#include "common/tusb_fifo.h"
|
||||
|
||||
#include "class/hid/hid.h"
|
||||
|
||||
//------------- HOST -------------//
|
||||
#if CFG_TUH_ENABLED
|
||||
#include "host/usbh.h"
|
||||
@ -117,8 +119,6 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
/** \ingroup group_application_api
|
||||
* @{ */
|
||||
|
||||
// Initialize device/host stack
|
||||
// Note: when using with RTOS, this should be called after scheduler/kernel is started.
|
||||
@ -131,8 +131,6 @@ bool tusb_inited(void);
|
||||
// TODO
|
||||
// bool tusb_teardown(void);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -80,6 +80,7 @@
|
||||
#define OPT_MCU_STM32L4 309 ///< ST L4
|
||||
#define OPT_MCU_STM32G0 310 ///< ST G0
|
||||
#define OPT_MCU_STM32G4 311 ///< ST G4
|
||||
#define OPT_MCU_STM32WB 312 ///< ST WB
|
||||
|
||||
// Sony
|
||||
#define OPT_MCU_CXD56 400 ///< SONY CXD56
|
||||
@ -207,18 +208,23 @@
|
||||
//------------- Roothub as Device -------------//
|
||||
|
||||
#if (CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE
|
||||
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
|
||||
#define TUD_OPT_RHPORT 0
|
||||
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
|
||||
#define TUD_OPT_RHPORT 0
|
||||
#elif (CFG_TUSB_RHPORT1_MODE) & OPT_MODE_DEVICE
|
||||
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT1_MODE)
|
||||
#define TUD_OPT_RHPORT 1
|
||||
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT1_MODE)
|
||||
#define TUD_OPT_RHPORT 1
|
||||
#else
|
||||
#define TUD_RHPORT_MODE OPT_MODE_NONE
|
||||
#define TUD_OPT_RHPORT -1
|
||||
#define TUD_RHPORT_MODE OPT_MODE_NONE
|
||||
#define TUD_OPT_RHPORT -1
|
||||
#endif
|
||||
|
||||
#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)) )
|
||||
#define CFG_TUD_ENABLED (TUD_RHPORT_MODE & OPT_MODE_DEVICE)
|
||||
|
||||
#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 -------------//
|
||||
|
||||
@ -383,11 +389,16 @@
|
||||
#define CFG_TUH_VENDOR 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_API_EDPT_XFER
|
||||
#define CFG_TUH_API_EDPT_XFER 0
|
||||
#endif
|
||||
|
||||
// Enable PIO-USB software host controller
|
||||
#ifndef CFG_TUH_RPI_PIO_USB
|
||||
#define CFG_TUH_RPI_PIO_USB 0
|
||||
#endif
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Configuration Validation
|
||||
//------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user