Merge pull request #1369 from tannewt/host_string_desc

Add host string descriptor functions
This commit is contained in:
Ha Thach 2022-03-04 22:59:16 +07:00 committed by GitHub
commit 8e0b8c15ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 483 additions and 144 deletions

View File

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

View File

@ -0,0 +1,28 @@
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/host/usbh_control.c \
src/portable/ohci/ohci.c \
src/portable/nxp/lpc17_40/hcd_lpc17_40.c
include ../../rules.mk

View File

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

View File

@ -0,0 +1,102 @@
/*
* 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"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
void led_blinking_task(void);
/*------------- MAIN -------------*/
int main(void)
{
board_init();
printf("TinyUSB Host HID Controller Example\r\n");
printf("Note: Events only displayed for explictly supported controllers\r\n");
tusb_init();
while (1)
{
// tinyusb host task
tuh_task();
led_blinking_task();
}
return 0;
}
//--------------------------------------------------------------------+
// TinyUSB Callbacks
//--------------------------------------------------------------------+
void print_device_descriptor(uint8_t dev_addr)
{
(void) dev_addr;
printf("Device Descriptor:\r\n");
}
// Invoked when device is mounted (configured)
void tuh_mount_cb (uint8_t dev_addr)
{
printf("Device attached, address = %d\r\n", dev_addr);
print_device_descriptor(dev_addr);
}
/// Invoked when device is unmounted (bus reset/unplugged)
void tuh_umount_cb(uint8_t dev_addr)
{
printf("Device removed, address = %d\r\n", dev_addr);
}
//--------------------------------------------------------------------+
// 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
}

View File

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

View File

@ -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)
@ -349,7 +350,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
}
// not found return the key value in hex
sprintf(not_found, "0x%08lX", (unsigned long) key);
snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
return not_found;
}

View File

@ -407,6 +407,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);

View File

@ -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,17 +94,6 @@ 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 {
uint8_t rhport;
uint8_t hub_addr;
@ -99,8 +101,6 @@ typedef struct {
uint8_t speed;
} hcd_devtree_info_t;
#endif
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+

View File

@ -54,7 +54,7 @@ static inline hub_interface_t* get_itf(uint8_t dev_addr)
return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX];
}
#if CFG_TUSB_DEBUG
#if CFG_TUSB_DEBUG >= 2
static char const* const _hub_feature_str[] =
{
[HUB_FEATURE_PORT_CONNECTION ] = "PORT_CONNECTION",

View File

@ -37,15 +37,14 @@
// USBH Configuration
//--------------------------------------------------------------------+
// TODO remove,update
#ifndef CFG_TUH_EP_MAX
#define CFG_TUH_EP_MAX 9
#endif
#ifndef CFG_TUH_TASK_QUEUE_SZ
#define CFG_TUH_TASK_QUEUE_SZ 16
#endif
#ifndef CFG_TUH_INTERFACE_MAX
#define CFG_TUH_INTERFACE_MAX 8
#endif
// Debug level of USBD
#define USBH_DBG_LVL 2
@ -72,7 +71,7 @@ typedef struct
} usbh_dev0_t;
typedef struct {
// port
// port, must be same layout as usbh_dev0_t
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
@ -87,10 +86,11 @@ typedef struct {
};
//------------- device descriptor -------------//
uint8_t ep0_size;
uint16_t vid;
uint16_t pid;
uint8_t ep0_size;
uint8_t i_manufacturer;
uint8_t i_product;
uint8_t i_serial;
@ -101,8 +101,8 @@ typedef struct {
//------------- device -------------//
volatile uint8_t state; // device state, value from enum tusbh_device_state_t
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUH_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
uint8_t itf2drv[CFG_TUH_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid )
struct TU_ATTR_PACKED
{
@ -111,7 +111,7 @@ typedef struct {
volatile bool claimed : 1;
// TODO merge ep2drv here, 4-bit should be sufficient
}ep_status[CFG_TUH_EP_MAX][2];
}ep_status[CFG_TUH_ENDPOINT_MAX][2];
// Mutex for claiming endpoint, only needed when using with preempted RTOS
#if CFG_TUSB_OS != OPT_OS_NONE
@ -249,7 +249,6 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
*vid = *pid = 0;
TU_VERIFY(tuh_mounted(dev_addr));
usbh_device_t const* dev = get_device(dev_addr);
*vid = dev->vid;
@ -273,6 +272,107 @@ void osal_task_delay(uint32_t msec)
}
#endif
//--------------------------------------------------------------------+
// Descriptors
//--------------------------------------------------------------------+
bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = tu_htole16( TU_U16(type, index) ),
.wIndex = 0,
.wLength = tu_htole16(len)
};
TU_ASSERT( tuh_control_xfer(daddr, &request, buffer, complete_cb) );
return true;
}
bool tuh_descriptor_device_get(uint8_t daddr, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb);
}
bool tuh_descriptor_configuration_get(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb);
}
bool tuh_descriptor_string_get(uint8_t daddr, uint16_t language_id, uint8_t index,
void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = tu_htole16( TU_U16(TUSB_DESC_STRING, index) ),
.wIndex = tu_htole16(language_id),
.wLength = tu_htole16(len)
};
TU_ASSERT( tuh_control_xfer(daddr, &request, buffer, complete_cb) );
return true;
}
// Get manufacturer string descriptor
bool tuh_descriptor_string_manufacturer_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
TU_VERIFY(tuh_mounted(daddr));
usbh_device_t const* dev = get_device(daddr);
return tuh_descriptor_string_get(daddr, language_id, dev->i_manufacturer, buffer, len, complete_cb);
}
// Get product string descriptor
bool tuh_descriptor_string_product_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
TU_VERIFY(tuh_mounted(daddr));
usbh_device_t const* dev = get_device(daddr);
return tuh_descriptor_string_get(daddr, language_id, dev->i_product, buffer, len, complete_cb);
}
// Get serial string descriptor
bool tuh_descriptor_string_serial_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
{
TU_VERIFY(tuh_mounted(daddr));
usbh_device_t const* dev = get_device(daddr);
return tuh_descriptor_string_get(daddr, language_id, dev->i_serial, buffer, len, complete_cb);
}
bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_control_complete_cb_t complete_cb)
{
TU_LOG2("Set Configuration = %d\r\n", config_num);
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_OUT
},
.bRequest = TUSB_REQ_SET_CONFIGURATION,
.wValue = tu_htole16(config_num),
.wIndex = 0,
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(daddr, &request, NULL, complete_cb) );
return true;
}
//--------------------------------------------------------------------+
// CLASS-USBD API (don't require to verify parameters)
//--------------------------------------------------------------------+
@ -288,6 +388,7 @@ bool tuh_init(uint8_t rhport)
if (_usbh_initialized) return _usbh_initialized;
TU_LOG2("USBH init\r\n");
TU_LOG2_INT(sizeof(usbh_device_t));
tu_memclr(_usbh_devices, sizeof(_usbh_devices));
tu_memclr(&_dev0, sizeof(_dev0));
@ -561,6 +662,7 @@ void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port
tu_memclr(dev->ep_status, sizeof(dev->ep_status));
dev->state = TUSB_DEVICE_STATE_UNPLUG;
dev->configured = false;
}
}
}
@ -585,7 +687,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
{
usbh_device_t* dev = get_device(dev_addr);
for(itf_num++; itf_num < sizeof(dev->itf2drv); itf_num++)
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
{
// continue with next valid interface
// TODO skip IAD binding interface such as CDCs
@ -600,7 +702,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
}
// all interface are configured
if (itf_num == sizeof(dev->itf2drv))
if (itf_num == CFG_TUH_INTERFACE_MAX)
{
// Invoke callback if available
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
@ -609,7 +711,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
//--------------------------------------------------------------------+
// Enumeration Process
// is a lengthy process with a seires of control transfer to configure
// is a lengthy process with a series of control transfer to configure
// newly attached device. Each step is handled by a function in this
// section
// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
@ -732,23 +834,10 @@ static bool enum_request_addr0_device_desc(void)
uint8_t const addr0 = 0;
TU_ASSERT( usbh_edpt_control_open(addr0, 8) );
//------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------//
// Get first 8 bytes of device descriptor for Control Endpoint size
TU_LOG2("Get 8 byte of Device Descriptor\r\n");
tusb_control_request_t const request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = TUSB_DESC_DEVICE << 8,
.wIndex = 0,
.wLength = 8
};
TU_ASSERT( tuh_control_xfer(addr0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) );
TU_ASSERT(tuh_descriptor_device_get(addr0, _usbh_ctrl_buf, 8, enum_get_addr0_device_desc_complete));
return true;
}
@ -827,7 +916,7 @@ static bool enum_request_set_addr(void)
.direction = TUSB_DIR_OUT
},
.bRequest = TUSB_REQ_SET_ADDRESS,
.wValue = new_addr,
.wValue = tu_htole16(new_addr),
.wIndex = 0,
.wLength = 0
};
@ -856,22 +945,8 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
// Get full device descriptor
TU_LOG2("Get Device Descriptor\r\n");
tusb_control_request_t const new_request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = TUSB_DESC_DEVICE << 8,
.wIndex = 0,
.wLength = sizeof(tusb_desc_device_t)
};
TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete));
TU_ASSERT(tuh_descriptor_device_get(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), enum_get_device_desc_complete));
return true;
}
@ -885,29 +960,16 @@ static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request
dev->vid = desc_device->idVendor;
dev->pid = desc_device->idProduct;
dev->i_manufacturer = desc_device->iManufacturer;
dev->i_product = desc_device->iProduct;
dev->i_serial = desc_device->iSerialNumber;
// dev->i_manufacturer = desc_device->iManufacturer;
// dev->i_product = desc_device->iProduct;
// dev->i_serial = desc_device->iSerialNumber;
// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf);
TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n");
tusb_control_request_t const new_request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1),
.wIndex = 0,
.wLength = 9
};
TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) );
// Get 9-byte for total length
uint8_t const config_idx = CONFIG_NUM - 1;
TU_LOG2("Get Configuration[0] Descriptor (9 bytes)\r\n");
TU_ASSERT( tuh_descriptor_configuration_get(dev_addr, config_idx, _usbh_ctrl_buf, 9, enum_get_9byte_config_desc_complete) );
return true;
}
@ -925,24 +987,9 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r
TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
// Get full configuration descriptor
TU_LOG2("Get Configuration Descriptor\r\n");
tusb_control_request_t const new_request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_IN
},
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
.wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1),
.wIndex = 0,
.wLength = total_len
};
TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_config_desc_complete) );
uint8_t const config_idx = CONFIG_NUM - 1;
TU_LOG2("Get Configuration[0] Descriptor\r\n");
TU_ASSERT( tuh_descriptor_configuration_get(dev_addr, config_idx, _usbh_ctrl_buf, total_len, enum_get_config_desc_complete) );
return true;
}
@ -955,23 +1002,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request
// Driver open aren't allowed to make any usb transfer yet
TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
tusb_control_request_t const new_request =
{
.bmRequestType_bit =
{
.recipient = TUSB_REQ_RCPT_DEVICE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_OUT
},
.bRequest = TUSB_REQ_SET_CONFIGURATION,
.wValue = CONFIG_NUM,
.wIndex = 0,
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, enum_set_config_complete) );
TU_ASSERT( tuh_configuration_set(dev_addr, CONFIG_NUM, enum_set_config_complete) );
return true;
}

View File

@ -38,7 +38,7 @@
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
typedef bool (*tuh_control_complete_cb_t)(uint8_t daddr, tusb_control_request_t const * request, xfer_result_t result);
//--------------------------------------------------------------------+
// APPLICATION API
@ -57,29 +57,60 @@ 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);
bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
// Set Configuration
// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_control_complete_cb_t complete_cb);
//------------- descriptors -------------//
// Get an descriptor
bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index,
void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
// Get device descriptor
bool tuh_descriptor_device_get(uint8_t daddr, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
// Get configuration descriptor
bool tuh_descriptor_configuration_get(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
// Get string descriptor
bool tuh_descriptor_string_get(uint8_t daddr, uint16_t language_id, uint8_t index,
void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
// Get manufacturer string descriptor
bool tuh_descriptor_string_manufacturer_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
// Get product string descriptor
bool tuh_descriptor_string_product_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
// Get serial string descriptor
bool tuh_descriptor_string_serial_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
//--------------------------------------------------------------------+
// APPLICATION CALLBACK
@ -87,10 +118,10 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request,
//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);
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 dev_addr);
TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
#ifdef __cplusplus
}

View File

@ -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"

View File

@ -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 )
{
@ -714,7 +721,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 +738,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 +753,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];
}

View File

@ -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

View File

@ -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) ;

View File

@ -313,7 +313,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) )
@ -329,7 +329,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];
}
@ -368,7 +368,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];
}

View File

@ -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;

View File

@ -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;