Merge pull request #1043 from hathach/more-host-improvement

More host improvement
This commit is contained in:
Ha Thach 2021-08-24 12:28:41 +07:00 committed by GitHub
commit 9c3fdb8135
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 527 additions and 377 deletions

View File

@ -80,6 +80,13 @@ void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_re
hid_info[instance].report_count = tuh_hid_parse_report_descriptor(hid_info[instance].report_info, MAX_REPORT, desc_report, desc_len);
printf("HID has %u reports \r\n", hid_info[instance].report_count);
}
// request to receive report
// tuh_hid_report_received_cb() will be invoked when report is available
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
printf("Error: cannot request to receive report\r\n");
}
}
// Invoked when device with hid interface is un-mounted
@ -110,6 +117,12 @@ void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t cons
process_generic_report(dev_addr, instance, report, len);
break;
}
// continue to request to receive report
if ( !tuh_hid_receive_report(dev_addr, instance) )
{
printf("Error: cannot request to receive report\r\n");
}
}
//--------------------------------------------------------------------+

View File

@ -33,7 +33,6 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
void print_greeting(void);
void led_blinking_task(void);
extern void cdc_task(void);
@ -43,7 +42,8 @@ extern void hid_app_task(void);
int main(void)
{
board_init();
print_greeting();
printf("TinyUSB Host CDC MSC HID Example\r\n");
tusb_init();
@ -126,28 +126,3 @@ void led_blinking_task(void)
board_led_write(led_state);
led_state = 1 - led_state; // toggle
}
//--------------------------------------------------------------------+
// HELPER FUNCTION
//--------------------------------------------------------------------+
void print_greeting(void)
{
char const * const rtos_name[] =
{
[OPT_OS_NONE] = "None",
[OPT_OS_FREERTOS] = "FreeRTOS",
[OPT_OS_MYNEWT] = "Mynewt OS",
[OPT_OS_CUSTOM] = "Custom OS implemnted by application",
[OPT_OS_PICO] = "Raspberry Pi Pico SDK",
[OPT_OS_RTTHREAD] = "RT-Thread"
};
printf("----------------------------------------------------\r\n");
printf("TinyUSB Host Example\r\n");
printf("If you find any bugs or problems, feel free to open\r\n");
printf("an issue at https://github.com/hathach/tinyusb\r\n");
printf("----------------------------------------------------\r\n\r\n");
printf("This Host demo is configured to support:\r\n");
printf(" - RTOS = %s\r\n", rtos_name[CFG_TUSB_OS]);
}

View File

@ -92,7 +92,7 @@ void tuh_msc_umount_cb(uint8_t dev_addr)
//
// if ( phy_disk == f_get_current_drive() )
// { // active drive is unplugged --> change to other drive
// for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX; i++)
// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
// {
// if ( disk_is_ready(i) )
// {

View File

@ -76,15 +76,16 @@
#define CFG_TUH_HUB 1
#define CFG_TUH_CDC 1
#define CFG_TUH_HID 4
#define CFG_TUH_HID 4 // typical keyboard + mouse device can have 3-4 HID interfaces
#define CFG_TUH_MSC 1
#define CFG_TUH_VENDOR 0
#define CFG_TUSB_HOST_DEVICE_MAX (CFG_TUH_HUB ? 5 : 1) // normal hub has 4 ports
// max device support (excluding hub device)
#define CFG_TUH_DEVICE_MAX (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports
//------------- HID -------------//
#define CFG_TUH_HID_EP_BUFSIZE 64
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
#ifdef __cplusplus
}

View File

@ -36,7 +36,7 @@
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// TODO change it to portable init
static DSTATUS disk_state[CFG_TUSB_HOST_DEVICE_MAX];
static DSTATUS disk_state[CFG_TUH_DEVICE_MAX];
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
@ -61,7 +61,7 @@ static DRESULT wait_for_io_complete(uint8_t usb_addr)
void diskio_init(void)
{
memset(disk_state, STA_NOINIT, CFG_TUSB_HOST_DEVICE_MAX);
memset(disk_state, STA_NOINIT, CFG_TUH_DEVICE_MAX);
}
//pdrv Specifies the physical drive number.

View File

@ -83,7 +83,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
static inline bool disk_is_ready(BYTE pdrv);
static inline bool disk_is_ready(BYTE pdrv)
{
return (pdrv < CFG_TUSB_HOST_DEVICE_MAX) &&
return (pdrv < CFG_TUH_DEVICE_MAX) &&
( (disk_status(pdrv) & (STA_NOINIT | STA_NODISK)) == 0 );
}

View File

@ -128,7 +128,7 @@
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES CFG_TUSB_HOST_DEVICE_MAX
#define _VOLUMES CFG_TUH_DEVICE_MAX
/* Number of volumes (logical drives) to be used. */

View File

@ -51,7 +51,7 @@ typedef struct {
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
static cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX];
static cdch_data_t cdch_data[CFG_TUH_DEVICE_MAX];
static inline cdch_data_t* get_itf(uint8_t dev_addr)
{
@ -146,7 +146,7 @@ bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_co
//--------------------------------------------------------------------+
void cdch_init(void)
{
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
tu_memclr(cdch_data, sizeof(cdch_data));
}
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
@ -240,6 +240,8 @@ bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
void cdch_close(uint8_t dev_addr)
{
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
cdch_data_t * p_cdc = get_itf(dev_addr);
tu_memclr(p_cdc, sizeof(cdch_data_t));
}

View File

@ -40,10 +40,10 @@
//--------------------------------------------------------------------+
#define RNDIS_MSG_PAYLOAD_MAX (1024*4)
CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUSB_HOST_DEVICE_MAX][8];
CFG_TUSB_MEM_SECTION static uint8_t msg_notification[CFG_TUH_DEVICE_MAX][8];
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msg_payload[RNDIS_MSG_PAYLOAD_MAX];
static rndish_data_t rndish_data[CFG_TUSB_HOST_DEVICE_MAX];
static rndish_data_t rndish_data[CFG_TUH_DEVICE_MAX];
// TODO Microsoft requires message length for any get command must be at least 4096 bytes
@ -88,7 +88,7 @@ static tusb_error_t rndis_body_subtask(void)
OSAL_SUBTASK_BEGIN
for (relative_addr = 0; relative_addr < CFG_TUSB_HOST_DEVICE_MAX; relative_addr++)
for (relative_addr = 0; relative_addr < CFG_TUH_DEVICE_MAX; relative_addr++)
{
}
@ -103,12 +103,12 @@ static tusb_error_t rndis_body_subtask(void)
//--------------------------------------------------------------------+
void rndish_init(void)
{
tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
tu_memclr(rndish_data, sizeof(rndish_data_t)*CFG_TUH_DEVICE_MAX);
//------------- Task creation -------------//
//------------- semaphore creation for notificaiton pipe -------------//
for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX; i++)
for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
{
rndish_data[i].sem_notification_hdl = osal_semaphore_create( OSAL_SEM_REF(rndish_data[i].semaphore_notification) );
}

View File

@ -52,8 +52,8 @@ typedef struct
uint16_t epin_size;
uint16_t epout_size;
uint8_t epin_buf[CFG_TUH_HID_EP_BUFSIZE];
uint8_t epout_buf[CFG_TUH_HID_EP_BUFSIZE];
uint8_t epin_buf[CFG_TUH_HID_EPIN_BUFSIZE];
uint8_t epout_buf[CFG_TUH_HID_EPOUT_BUFSIZE];
} hidh_interface_t;
typedef struct
@ -62,7 +62,7 @@ typedef struct
hidh_interface_t instances[CFG_TUH_HID];
} hidh_device_t;
static hidh_device_t _hidh_dev[CFG_TUSB_HOST_DEVICE_MAX-1];
static hidh_device_t _hidh_dev[CFG_TUH_DEVICE_MAX];
//------------- Internal prototypes -------------//
@ -72,13 +72,8 @@ TU_ATTR_ALWAYS_INLINE static inline hidh_interface_t* get_instance(uint8_t dev_a
static uint8_t get_instance_id_by_itfnum(uint8_t dev_addr, uint8_t itf);
static uint8_t get_instance_id_by_epaddr(uint8_t dev_addr, uint8_t ep_addr);
TU_ATTR_ALWAYS_INLINE static inline bool hidh_get_report(uint8_t dev_addr, hidh_interface_t* hid_itf)
{
return usbh_edpt_xfer(dev_addr, hid_itf->ep_in, hid_itf->epin_buf, hid_itf->epin_size);
}
//--------------------------------------------------------------------+
// Application API
// Interface API
//--------------------------------------------------------------------+
uint8_t tuh_hid_instance_count(uint8_t dev_addr)
@ -98,6 +93,10 @@ uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance)
return hid_itf->itf_protocol;
}
//--------------------------------------------------------------------+
// Control Endpoint API
//--------------------------------------------------------------------+
uint8_t tuh_hid_get_protocol(uint8_t dev_addr, uint8_t instance)
{
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
@ -186,6 +185,20 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u
return true;
}
//--------------------------------------------------------------------+
// Interrupt Endpoint API
//--------------------------------------------------------------------+
bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance)
{
hidh_interface_t* hid_itf = get_instance(dev_addr, 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);
}
//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance)
//{
// TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance));
@ -217,9 +230,6 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3
TU_LOG2(" Get Report callback (%u, %u)\r\n", dev_addr, instance);
TU_LOG1_MEM(hid_itf->epin_buf, 8, 2);
tuh_hid_report_received_cb(dev_addr, instance, hid_itf->epin_buf, xferred_bytes);
// queue next report
hidh_get_report(dev_addr, hid_itf);
}else
{
if (tuh_hid_report_sent_cb) tuh_hid_report_sent_cb(dev_addr, instance, hid_itf->epout_buf, xferred_bytes);
@ -230,10 +240,13 @@ bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint3
void hidh_close(uint8_t dev_addr)
{
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
hidh_device_t* hid_dev = get_dev(dev_addr);
if (tuh_hid_umount_cb)
{
for ( uint8_t inst = 0; inst < hid_dev->inst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst);
for (uint8_t inst = 0; inst < hid_dev->inst_count; inst++ ) tuh_hid_umount_cb(dev_addr, inst);
}
tu_memclr(hid_dev, sizeof(hidh_device_t));
@ -255,6 +268,8 @@ bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *de
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
TU_LOG2("HID opening Interface %u (addr = %u)\r\n", desc_itf->bInterfaceNumber, dev_addr);
// 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);
TU_ASSERT(max_len >= drv_len);
@ -336,7 +351,7 @@ static bool config_set_protocol(uint8_t dev_addr, tusb_control_request_t const *
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\r\n");
TU_LOG2("HID Set Protocol to Boot Mode\r\n");
hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
tusb_control_request_t const new_request =
{
@ -422,9 +437,6 @@ static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uin
// enumeration is complete
tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len);
// queue transfer for IN endpoint
hidh_get_report(dev_addr, hid_itf);
// notify usbh that driver enumeration is complete
usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num);
}

View File

@ -38,10 +38,15 @@
//--------------------------------------------------------------------+
// TODO Highspeed interrupt can be up to 512 bytes
#ifndef CFG_TUH_HID_EP_BUFSIZE
#define CFG_TUH_HID_EP_BUFSIZE 64
#ifndef CFG_TUH_HID_EPIN_BUFSIZE
#define CFG_TUH_HID_EPIN_BUFSIZE 64
#endif
#ifndef CFG_TUH_HID_EPOUT_BUFSIZE
#define CFG_TUH_HID_EPOUT_BUFSIZE 64
#endif
typedef struct
{
uint8_t report_id;
@ -54,7 +59,7 @@ typedef struct
} tuh_hid_report_info_t;
//--------------------------------------------------------------------+
// Application API
// Interface API
//--------------------------------------------------------------------+
// Get the number of HID instances
@ -66,6 +71,14 @@ bool tuh_hid_mounted(uint8_t dev_addr, uint8_t instance);
// Get interface supported protocol (bInterfaceProtocol) check out hid_interface_protocol_enum_t for possible values
uint8_t tuh_hid_interface_protocol(uint8_t dev_addr, uint8_t instance);
// Parse report descriptor into array of report_info struct and return number of reports.
// For complicated report, application should write its own parser.
uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED;
//--------------------------------------------------------------------+
// Control Endpoint API
//--------------------------------------------------------------------+
// Get current protocol: HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
// Note: Device will be initialized in Boot protocol for simplicity.
// Application can use set_protocol() to switch back to Report protocol.
@ -79,13 +92,18 @@ bool tuh_hid_set_protocol(uint8_t dev_addr, uint8_t instance, uint8_t protocol);
// report_type is either Intput, Output or Feature, (value from hid_report_type_t)
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);
// Parse report descriptor into array of report_info struct and return number of reports.
// For complicated report, application should write its own parser.
uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr, uint8_t arr_count, uint8_t const* desc_report, uint16_t desc_len) TU_ATTR_UNUSED;
//--------------------------------------------------------------------+
// Interrupt Endpoint API
//--------------------------------------------------------------------+
// Check if the interface is ready to use
//bool tuh_n_hid_n_ready(uint8_t dev_addr, uint8_t instance);
// Try to receive next report on Interrupt Endpoint. Immediately return
// - true If succeeded, tuh_hid_report_received_cb() callback will be invoked when report is available
// - false if failed to queue the transfer e.g endpoint is busy
bool tuh_hid_receive_report(uint8_t dev_addr, uint8_t instance);
// Send report using interrupt endpoint
// If report_id > 0 (composite), it will be sent as 1st byte, then report contents. Otherwise only report content is sent.
//void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len);

View File

@ -69,13 +69,14 @@ typedef struct
msc_csw_t csw;
}msch_interface_t;
CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUSB_HOST_DEVICE_MAX];
CFG_TUSB_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
// buffer used to read scsi information when mounted
// largest response data currently is inquiry TODO Inquiry is not part of enum anymore
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4)
static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
TU_ATTR_ALWAYS_INLINE
static inline msch_interface_t* get_itf(uint8_t dev_addr)
{
return &_msch_itf[dev_addr-1];
@ -291,11 +292,13 @@ bool tuh_msc_reset(uint8_t dev_addr)
//--------------------------------------------------------------------+
void msch_init(void)
{
tu_memclr(_msch_itf, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX);
tu_memclr(_msch_itf, sizeof(_msch_itf));
}
void msch_close(uint8_t dev_addr)
{
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
msch_interface_t* p_msc = get_itf(dev_addr);
// invoke Application Callback

View File

@ -41,7 +41,7 @@
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
custom_interface_info_t custom_interface[CFG_TUSB_HOST_DEVICE_MAX];
custom_interface_info_t custom_interface[CFG_TUH_DEVICE_MAX];
static tusb_error_t cush_validate_paras(uint8_t dev_addr, uint16_t vendor_id, uint16_t product_id, void * p_buffer, uint16_t length)
{
@ -90,7 +90,7 @@ tusb_error_t tusbh_custom_write(uint8_t dev_addr, uint16_t vendor_id, uint16_t p
//--------------------------------------------------------------------+
void cush_init(void)
{
tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUSB_HOST_DEVICE_MAX);
tu_memclr(&custom_interface, sizeof(custom_interface_info_t) * CFG_TUH_DEVICE_MAX);
}
tusb_error_t cush_open_subtask(uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length)

View File

@ -30,6 +30,7 @@
#include "common/tusb_common.h"
#include "osal/osal.h"
#include "common/tusb_fifo.h"
#include "hcd_attr.h"
#ifdef __cplusplus
extern "C" {
@ -62,6 +63,7 @@ typedef struct
struct {
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
} connection;
// XFER_COMPLETE
@ -84,12 +86,20 @@ typedef struct
// Max number of endpoints per device
enum {
// TODO better computation
HCD_MAX_ENDPOINT = CFG_TUSB_HOST_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3),
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;
uint8_t hub_port;
uint8_t speed;
} hcd_devtree_info_t;
#endif
//--------------------------------------------------------------------+
@ -140,9 +150,16 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
//--------------------------------------------------------------------+
// Event API (implemented by stack)
// USBH implemented API
//--------------------------------------------------------------------+
// Get device tree information of a device
// USB device tree can be complicated and manged by USBH, this help HCD to retrieve
// needed topology info to carry out its work
extern void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info);
//------------- Event API -------------//
// Called by HCD to notify stack
extern void hcd_event_handler(hcd_event_t const* event, bool in_isr);

105
src/host/hcd_attr.h Normal file
View File

@ -0,0 +1,105 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021, 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_HCD_ATTR_H_
#define TUSB_HCD_ATTR_H_
#include "tusb_option.h"
// Attribute includes
// - ENDPOINT_MAX: max (logical) number of endpoint
// - PORT_HIGHSPEED: mask to indicate which port support highspeed mode, bit0 for port0 and so on.
//------------- NXP -------------//
#if TU_CHECK_MCU(LPC175X_6X) || TU_CHECK_MCU(LPC177X_8X) || TU_CHECK_MCU(LPC40XX)
#define HCD_ATTR_OHCI
#elif TU_CHECK_MCU(LPC18XX) || TU_CHECK_MCU(LPC43XX)
#define HCD_ATTR_EHCI_TRANSDIMENSION
#elif TU_CHECK_MCU(LPC54XXX)
// #define HCD_ATTR_EHCI_NXP_PTD
#elif TU_CHECK_MCU(LPC55XX)
// #define HCD_ATTR_EHCI_NXP_PTD
#elif TU_CHECK_MCU(MIMXRT10XX)
#define HCD_ATTR_EHCI_TRANSDIMENSION
#elif TU_CHECK_MCU(MKL25ZXX)
//------------- Microchip -------------//
#elif TU_CHECK_MCU(SAMD21) || TU_CHECK_MCU(SAMD51) || TU_CHECK_MCU(SAME5X) || \
TU_CHECK_MCU(SAMD11) || TU_CHECK_MCU(SAML21) || TU_CHECK_MCU(SAML22)
#elif TU_CHECK_MCU(SAMG)
#elif TU_CHECK_MCU(SAMX7X)
//------------- ST -------------//
#elif TU_CHECK_MCU(STM32F0) || TU_CHECK_MCU(STM32F1) || TU_CHECK_MCU(STM32F3) || \
TU_CHECK_MCU(STM32L0) || TU_CHECK_MCU(STM32L1) || TU_CHECK_MCU(STM32L4)
#elif TU_CHECK_MCU(STM32F2) || TU_CHECK_MCU(STM32F4) || TU_CHECK_MCU(STM32F3)
#elif TU_CHECK_MCU(STM32F7)
#elif TU_CHECK_MCU(STM32H7)
//------------- Sony -------------//
#elif TU_CHECK_MCU(CXD56)
//------------- Nuvoton -------------//
#elif TU_CHECK_MCU(NUC505)
//------------- Espressif -------------//
#elif TU_CHECK_MCU(ESP32S2) || TU_CHECK_MCU(ESP32S3)
//------------- Raspberry Pi -------------//
#elif TU_CHECK_MCU(RP2040)
//------------- Silabs -------------//
#elif TU_CHECK_MCU(EFM32GG) || TU_CHECK_MCU(EFM32GG11) || TU_CHECK_MCU(EFM32GG12)
//------------- Renesas -------------//
#elif TU_CHECK_MCU(RX63X) || TU_CHECK_MCU(RX65X) || TU_CHECK_MCU(RX72N)
//#elif TU_CHECK_MCU(MM32F327X)
// #define DCD_ATTR_ENDPOINT_MAX not known yet
//------------- GigaDevice -------------//
#elif TU_CHECK_MCU(GD32VF103)
#else
// #warning "DCD_ATTR_ENDPOINT_MAX is not defined for this MCU, default to 8"
#endif
// Default to fullspeed if not defined
//#ifndef PORT_HIGHSPEED
// #define DCD_ATTR_PORT_HIGHSPEED 0x00
//#endif
#endif

View File

@ -45,8 +45,14 @@ typedef struct
hub_port_status_response_t port_status;
} hub_interface_t;
CFG_TUSB_MEM_SECTION static hub_interface_t hub_data[CFG_TUSB_HOST_DEVICE_MAX];
TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)];
CFG_TUSB_MEM_SECTION static hub_interface_t hub_data[CFG_TUH_HUB];
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)];
TU_ATTR_ALWAYS_INLINE
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
static char const* const _hub_feature_str[] =
@ -144,7 +150,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con
//--------------------------------------------------------------------+
void hub_init(void)
{
tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(hub_interface_t));
tu_memclr(hub_data, sizeof(hub_data));
}
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
@ -167,21 +173,26 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
hub_data[dev_addr-1].ep_in = desc_ep->bEndpointAddress;
hub_interface_t* p_hub = get_itf(dev_addr);
p_hub->itf_num = itf_desc->bInterfaceNumber;
p_hub->ep_in = desc_ep->bEndpointAddress;
return true;
}
void hub_close(uint8_t dev_addr)
{
tu_memclr(&hub_data[dev_addr-1], sizeof( hub_interface_t));
TU_VERIFY(dev_addr > CFG_TUH_DEVICE_MAX, );
hub_interface_t* p_hub = get_itf(dev_addr);
if (p_hub->ep_in) tu_memclr(p_hub, sizeof( hub_interface_t));
}
bool hub_status_pipe_queue(uint8_t dev_addr)
{
hub_interface_t * p_hub = &hub_data[dev_addr-1];
return usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1);
hub_interface_t* hub_itf = get_itf(dev_addr);
return usbh_edpt_xfer(dev_addr, hub_itf->ep_in, &hub_itf->status_change, 1);
}
@ -194,7 +205,7 @@ static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t
bool hub_set_config(uint8_t dev_addr, uint8_t itf_num)
{
hub_interface_t* p_hub = &hub_data[dev_addr-1];
hub_interface_t* p_hub = get_itf(dev_addr);
TU_ASSERT(itf_num == p_hub->itf_num);
// Get Hub Descriptor
@ -222,7 +233,7 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons
(void) request;
TU_ASSERT(XFER_RESULT_SUCCESS == result);
hub_interface_t* p_hub = &hub_data[dev_addr-1];
hub_interface_t* p_hub = get_itf(dev_addr);
// only use number of ports in hub descriptor
descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer;
@ -238,7 +249,7 @@ static bool config_set_port_power (uint8_t dev_addr, tusb_control_request_t cons
static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
TU_ASSERT(XFER_RESULT_SUCCESS == result);
hub_interface_t* p_hub = &hub_data[dev_addr-1];
hub_interface_t* p_hub = get_itf(dev_addr);
if (request->wIndex == p_hub->port_count)
{
@ -272,7 +283,7 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
(void) ep_addr;
TU_ASSERT(result == XFER_RESULT_SUCCESS);
hub_interface_t * p_hub = &hub_data[dev_addr-1];
hub_interface_t* p_hub = get_itf(dev_addr);
TU_LOG2(" Port Status Change = 0x%02X\r\n", p_hub->status_change);
@ -294,7 +305,8 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32
static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
TU_ASSERT(result == XFER_RESULT_SUCCESS);
hub_interface_t * p_hub = &hub_data[dev_addr-1];
hub_interface_t* p_hub = get_itf(dev_addr);
uint8_t const port_num = (uint8_t) request->wIndex;
// Connection change
@ -322,7 +334,7 @@ static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_contro
{
TU_ASSERT(result == XFER_RESULT_SUCCESS);
hub_interface_t * p_hub = &hub_data[dev_addr-1];
hub_interface_t* p_hub = get_itf(dev_addr);
uint8_t const port_num = (uint8_t) request->wIndex;
if ( p_hub->port_status.status.connection )
@ -353,7 +365,7 @@ static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_reque
{
TU_ASSERT(result == XFER_RESULT_SUCCESS);
// usbh_hub_t * p_hub = &hub_data[dev_addr-1];
// hub_interface_t* p_hub = get_itf(dev_addr);
uint8_t const port_num = (uint8_t) request->wIndex;
// submit attach event

View File

@ -32,12 +32,16 @@
#include "host/usbh.h"
#include "host/usbh_classdriver.h"
#include "hub.h"
#include "usbh_hcd.h"
//--------------------------------------------------------------------+
// 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
@ -45,12 +49,72 @@
// Debug level of USBD
#define USBH_DBG_LVL 2
//--------------------------------------------------------------------+
// USBH-HCD common data structure
//--------------------------------------------------------------------+
typedef struct {
//------------- port -------------//
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
//------------- device descriptor -------------//
uint16_t vendor_id;
uint16_t product_id;
uint8_t ep0_packet_size;
//------------- configuration descriptor -------------//
// uint8_t interface_count; // bNumInterfaces alias
//------------- device -------------//
struct TU_ATTR_PACKED
{
uint8_t connected : 1;
uint8_t addressed : 1;
uint8_t configured : 1;
uint8_t suspended : 1;
};
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 )
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_TUH_EP_MAX][2];
// Mutex for claiming endpoint, only needed when using with preempted RTOS
#if CFG_TUSB_OS != OPT_OS_NONE
osal_mutex_def_t mutexdef;
osal_mutex_t mutex;
#endif
} usbh_device_t;
typedef struct
{
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
} usbh_dev0_t;
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// Invalid driver ID in itf2drv[] ep2drv[][] mapping
enum { DRVID_INVALID = 0xFFu };
enum { ADDR_INVALID = 0xFFu };
#if CFG_TUSB_DEBUG >= 2
#define DRIVER_NAME(_name) .name = _name,
@ -128,8 +192,12 @@ enum { CONFIG_NUM = 1 }; // default to use configuration 1
static bool _usbh_initialized = false;
// including zero-address
CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1];
// Device with address = 0 for enumeration
static usbh_dev0_t _dev0;
// all devices excluding zero-address
// hub address start from CFG_TUH_DEVICE_MAX+1
CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUH_DEVICE_MAX + CFG_TUH_HUB];
// Event queue
// role device/host is used by OS NONE for mutex (disable usb isr)
@ -138,7 +206,15 @@ static osal_queue_t _usbh_q;
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
//------------- Helper Function Prototypes -------------//
//------------- Helper Function -------------//
TU_ATTR_ALWAYS_INLINE
static inline usbh_device_t* get_device(uint8_t dev_addr)
{
TU_ASSERT(dev_addr, NULL);
return &_usbh_devices[dev_addr-1];
}
static bool enum_new_device(hcd_event_t* event);
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
@ -151,13 +227,13 @@ extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
//--------------------------------------------------------------------+
bool tuh_device_configured(uint8_t dev_addr)
{
return _usbh_devices[dev_addr].configured;
return get_device(dev_addr)->configured;
}
tusb_speed_t tuh_device_get_speed (uint8_t const dev_addr)
{
TU_ASSERT( dev_addr <= CFG_TUSB_HOST_DEVICE_MAX, TUSB_SPEED_INVALID);
return (tusb_speed_t) _usbh_devices[dev_addr].speed;
TU_ASSERT( dev_addr <= CFG_TUH_DEVICE_MAX + CFG_TUH_HUB, TUSB_SPEED_INVALID);
return (tusb_speed_t) get_device(dev_addr)->speed;
}
#if CFG_TUSB_OS == OPT_OS_NONE
@ -186,16 +262,17 @@ bool tuh_init(uint8_t rhport)
TU_LOG2("USBH init\r\n");
tu_memclr(_usbh_devices, sizeof(usbh_device_t)*(CFG_TUSB_HOST_DEVICE_MAX+1));
tu_memclr(_usbh_devices, sizeof(_usbh_devices));
tu_memclr(&_dev0, sizeof(_dev0));
//------------- Enumeration & Reporter Task init -------------//
_usbh_q = osal_queue_create( &_usbh_qdef );
TU_ASSERT(_usbh_q != NULL);
//------------- Semaphore, Mutex for Control Pipe -------------//
for(uint8_t i=0; i<CFG_TUSB_HOST_DEVICE_MAX+1; i++) // including address zero
for(uint8_t i=0; i<TU_ARRAY_SIZE(_usbh_devices); i++)
{
usbh_device_t * const dev = &_usbh_devices[i];
usbh_device_t * dev = &_usbh_devices[i];
#if CFG_TUSB_OS != OPT_OS_NONE
dev->mutex = osal_mutex_create(&dev->mutexdef);
@ -274,26 +351,35 @@ void tuh_task(void)
case HCD_EVENT_XFER_COMPLETE:
{
usbh_device_t* dev = &_usbh_devices[event.dev_addr];
uint8_t const ep_addr = event.xfer_complete.ep_addr;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const ep_dir = tu_edpt_dir(ep_addr);
TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
dev->ep_status[epnum][ep_dir].busy = false;
dev->ep_status[epnum][ep_dir].claimed = 0;
if ( 0 == epnum )
if (event.dev_addr == 0)
{
// device 0 only has control endpoint
TU_ASSERT(epnum == 0, );
usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
}else
}
else
{
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, );
usbh_device_t* dev = get_device(event.dev_addr);
dev->ep_status[epnum][ep_dir].busy = false;
dev->ep_status[epnum][ep_dir].claimed = 0;
TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
if ( 0 == epnum )
{
usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
}else
{
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, );
TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
}
}
}
break;
@ -313,7 +399,7 @@ void tuh_task(void)
uint8_t usbh_get_rhport(uint8_t dev_addr)
{
return _usbh_devices[dev_addr].rhport;
return (dev_addr == 0) ? _dev0.rhport : get_device(dev_addr)->rhport;
}
uint8_t* usbh_get_enum_buf(void)
@ -325,6 +411,25 @@ uint8_t* usbh_get_enum_buf(void)
// HCD Event Handler
//--------------------------------------------------------------------+
void hcd_devtree_get_info(uint8_t dev_addr, hcd_devtree_info_t* devtree_info)
{
if (dev_addr)
{
usbh_device_t const* dev = get_device(dev_addr);
devtree_info->rhport = dev->rhport;
devtree_info->hub_addr = dev->hub_addr;
devtree_info->hub_port = dev->hub_port;
devtree_info->speed = dev->speed;
}else
{
devtree_info->rhport = _dev0.rhport;
devtree_info->hub_addr = _dev0.hub_addr;
devtree_info->hub_port = _dev0.hub_port;
devtree_info->speed = _dev0.speed;
}
}
void hcd_event_handler(hcd_event_t const* event, bool in_isr)
{
switch (event->event_id)
@ -387,9 +492,11 @@ void hcd_event_device_remove(uint8_t hostid, bool in_isr)
void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port)
{
//------------- find the all devices (star-network) under port that is unplugged -------------//
for (uint8_t dev_addr = 0; dev_addr <= CFG_TUSB_HOST_DEVICE_MAX; dev_addr ++)
// TODO mark as disconnected in ISR, also handle dev0
for ( uint8_t dev_id = 0; dev_id < TU_ARRAY_SIZE(_usbh_devices); dev_id++ )
{
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = &_usbh_devices[dev_id];
uint8_t const dev_addr = dev_id+1;
// TODO Hub multiple level
if (dev->rhport == rhport &&
@ -420,22 +527,27 @@ void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port
//--------------------------------------------------------------------+
// INTERNAL HELPER
//--------------------------------------------------------------------+
static uint8_t get_new_address(void)
static uint8_t get_new_address(bool is_hub)
{
for (uint8_t addr=1; addr <= CFG_TUSB_HOST_DEVICE_MAX; addr++)
uint8_t const start = (is_hub ? CFG_TUH_DEVICE_MAX : 0) + 1;
uint8_t const count = (is_hub ? CFG_TUH_HUB : CFG_TUH_DEVICE_MAX);
for (uint8_t i=0; i < count; i++)
{
if (_usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG) return addr;
uint8_t const addr = start + i;
if (get_device(addr)->state == TUSB_DEVICE_STATE_UNPLUG) return addr;
}
return CFG_TUSB_HOST_DEVICE_MAX+1;
return ADDR_INVALID;
}
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
{
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
for(itf_num++; itf_num < sizeof(dev->itf2drv); itf_num++)
{
// continue with next valid interface
// TODO skip IAD binding interface such as CDCs
uint8_t const drv_id = dev->itf2drv[itf_num];
if (drv_id != DRVID_INVALID)
{
@ -474,6 +586,7 @@ static bool enum_get_config_desc_complete (uint8_t dev_addr, tusb_control_
static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg);
#if CFG_TUH_HUB
static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result)
{
(void) dev_addr; (void) request;
@ -486,12 +599,11 @@ static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_reques
{
(void) dev_addr; (void) request;
TU_ASSERT(XFER_RESULT_SUCCESS == result);
usbh_device_t* dev0 = &_usbh_devices[0];
enum_request_set_addr();
// done with hub, waiting for next data on status pipe
(void) hub_status_pipe_queue( dev0->hub_addr );
(void) hub_status_pipe_queue( _dev0.hub_addr );
return true;
}
@ -500,7 +612,6 @@ static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request
{
(void) dev_addr; (void) request;
TU_ASSERT(XFER_RESULT_SUCCESS == result);
usbh_device_t* dev0 = &_usbh_devices[0];
hub_port_status_response_t port_status;
memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
@ -508,7 +619,7 @@ static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request
// Acknowledge Port Reset Change if Reset Successful
if (port_status.change.reset)
{
TU_ASSERT( hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) );
TU_ASSERT( hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) );
}
return true;
@ -518,7 +629,6 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request
{
(void) dev_addr; (void) request;
TU_ASSERT(XFER_RESULT_SUCCESS == result);
usbh_device_t* dev0 = &_usbh_devices[0];
hub_port_status_response_t port_status;
memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t));
@ -529,36 +639,38 @@ static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request
return hub_status_pipe_queue(dev_addr);
}
dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
_dev0.speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH :
(port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
// Acknowledge Port Reset Change
if (port_status.change.reset)
{
hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete);
hub_port_clear_feature(_dev0.hub_addr, _dev0.hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete);
}
return true;
}
#endif
static bool enum_request_set_addr(void)
{
// Set Address
uint8_t const new_addr = get_new_address();
TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices
uint8_t const addr0 = 0;
tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
// Get new address
uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
TU_ASSERT(new_addr != ADDR_INVALID);
TU_LOG2("Set Address = %d\r\n", new_addr);
usbh_device_t* dev0 = &_usbh_devices[0];
usbh_device_t* new_dev = &_usbh_devices[new_addr];
usbh_device_t* new_dev = get_device(new_addr);
new_dev->rhport = dev0->rhport;
new_dev->hub_addr = dev0->hub_addr;
new_dev->hub_port = dev0->hub_port;
new_dev->speed = dev0->speed;
new_dev->rhport = _dev0.rhport;
new_dev->hub_addr = _dev0.hub_addr;
new_dev->hub_port = _dev0.hub_port;
new_dev->speed = _dev0.speed;
new_dev->connected = 1;
new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0;
new_dev->ep0_packet_size = desc_device->bMaxPacketSize0;
tusb_control_request_t const new_request =
{
@ -574,29 +686,27 @@ static bool enum_request_set_addr(void)
.wLength = 0
};
TU_ASSERT( tuh_control_xfer(0, &new_request, NULL, enum_set_address_complete) );
TU_ASSERT( tuh_control_xfer(addr0, &new_request, NULL, enum_set_address_complete) );
return true;
}
static bool enum_new_device(hcd_event_t* event)
{
usbh_device_t* dev0 = &_usbh_devices[0];
dev0->rhport = event->rhport; // TODO refractor integrate to device_pool
dev0->hub_addr = event->connection.hub_addr;
dev0->hub_port = event->connection.hub_port;
dev0->state = TUSB_DEVICE_STATE_UNPLUG;
_dev0.rhport = event->rhport; // TODO refractor integrate to device_pool
_dev0.hub_addr = event->connection.hub_addr;
_dev0.hub_port = event->connection.hub_port;
//------------- connected/disconnected directly with roothub -------------//
if (dev0->hub_addr == 0)
if (_dev0.hub_addr == 0)
{
// wait until device is stable TODO non blocking
osal_task_delay(RESET_DELAY);
// device unplugged while delaying
if ( !hcd_port_connect_status(dev0->rhport) ) return true;
if ( !hcd_port_connect_status(_dev0.rhport) ) return true;
dev0->speed = hcd_port_speed_get( dev0->rhport );
_dev0.speed = hcd_port_speed_get(_dev0.rhport );
enum_request_addr0_device_desc();
}
@ -606,7 +716,7 @@ static bool enum_new_device(hcd_event_t* event)
{
// wait until device is stable
osal_task_delay(RESET_DELAY);
TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) );
TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) );
}
#endif // CFG_TUH_HUB
@ -616,7 +726,8 @@ static bool enum_new_device(hcd_event_t* event)
static bool enum_request_addr0_device_desc(void)
{
// TODO probably doesn't need to open/close each enumeration
TU_ASSERT( usbh_edpt_control_open(0, 8) );
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 -------------//
TU_LOG2("Get 8 byte of Device Descriptor\r\n");
@ -633,7 +744,7 @@ static bool enum_request_addr0_device_desc(void)
.wIndex = 0,
.wLength = 8
};
TU_ASSERT( tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) );
TU_ASSERT( tuh_control_xfer(addr0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) );
return true;
}
@ -644,27 +755,26 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
(void) request;
TU_ASSERT(0 == dev_addr);
usbh_device_t* dev0 = &_usbh_devices[0];
if (XFER_RESULT_SUCCESS != result)
{
#if CFG_TUH_HUB
// TODO remove, waiting for next data on status pipe
if (dev0->hub_addr != 0) hub_status_pipe_queue(dev0->hub_addr);
if (_dev0.hub_addr != 0) hub_status_pipe_queue(_dev0.hub_addr);
#endif
return false;
}
TU_ASSERT(tu_desc_type(_usbh_ctrl_buf) == TUSB_DESC_DEVICE);
tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
TU_ASSERT( tu_desc_type(desc_device) == TUSB_DESC_DEVICE );
// Reset device again before Set Address
TU_LOG2("Port reset \r\n");
if (dev0->hub_addr == 0)
if (_dev0.hub_addr == 0)
{
// connected directly to roothub
hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor
hcd_port_reset( _dev0.rhport ); // reset port after 8 byte descriptor
osal_task_delay(RESET_DELAY);
enum_request_set_addr();
@ -673,12 +783,12 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r
else
{
// after RESET_DELAY the hub_port_reset() already complete
TU_ASSERT( hub_port_reset(dev0->hub_addr, dev0->hub_port, NULL) );
TU_ASSERT( hub_port_reset(_dev0.hub_addr, _dev0.hub_port, NULL) );
osal_task_delay(RESET_DELAY);
tuh_task(); // FIXME temporarily to clean up port_reset control transfer
TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) );
TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) );
}
#endif
@ -693,13 +803,11 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
uint8_t const new_addr = (uint8_t const) request->wValue;
usbh_device_t* new_dev = &_usbh_devices[new_addr];
usbh_device_t* new_dev = get_device(new_addr);
new_dev->addressed = 1;
// TODO close device 0, may not be needed
usbh_device_t* dev0 = &_usbh_devices[0];
hcd_device_close(dev0->rhport, 0);
dev0->state = TUSB_DEVICE_STATE_UNPLUG;
hcd_device_close(_dev0.rhport, 0);
// open control pipe for new address
TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) );
@ -731,7 +839,7 @@ static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request
TU_ASSERT(XFER_RESULT_SUCCESS == result);
tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf;
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
dev->vendor_id = desc_device->idVendor;
dev->product_id = desc_device->idProduct;
@ -829,7 +937,7 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
TU_ASSERT(XFER_RESULT_SUCCESS == result);
TU_LOG2("Device configured\r\n");
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
dev->configured = 1;
dev->state = TUSB_DEVICE_STATE_CONFIGURED;
@ -844,7 +952,7 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg)
{
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
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);
@ -889,7 +997,7 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
{
// open successfully
TU_LOG2("%s opened\r\n", driver->name);
TU_LOG2(" Opened successfully\r\n");
// bind interface to found driver
dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
@ -938,7 +1046,7 @@ bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
#if CFG_TUSB_OS != OPT_OS_NONE
// pre-check to help reducing mutex lock
@ -966,7 +1074,7 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
#if CFG_TUSB_OS != OPT_OS_NONE
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
@ -992,7 +1100,7 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
@ -1020,7 +1128,7 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
{
TU_LOG2("Open EP Control with Size = %u\r\n", max_packet_size);
TU_LOG2("Open EP0 with Size = %u (addr = %u)\r\n", max_packet_size, dev_addr);
tusb_desc_endpoint_t ep0_desc =
{
@ -1032,12 +1140,12 @@ static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
.bInterval = 0
};
return hcd_edpt_open(_usbh_devices[dev_addr].rhport, dev_addr, &ep0_desc);
return hcd_edpt_open(usbh_get_rhport(dev_addr), dev_addr, &ep0_desc);
}
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
{
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) dev->speed));
return hcd_edpt_open(rhport, dev_addr, desc_ep);
@ -1048,7 +1156,7 @@ bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
usbh_device_t* dev = &_usbh_devices[dev_addr];
usbh_device_t* dev = get_device(dev_addr);
return dev->ep_status[epnum][dir].busy;
}

View File

@ -29,7 +29,7 @@
#if TUSB_OPT_HOST_ENABLED
#include "tusb.h"
#include "usbh_hcd.h"
#include "usbh_classdriver.h"
enum
{
@ -59,9 +59,7 @@ static usbh_control_xfer_t _ctrl_xfer;
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
usbh_device_t* dev = &_usbh_devices[dev_addr];
const uint8_t rhport = dev->rhport;
const uint8_t rhport = usbh_get_rhport(dev_addr);
_ctrl_xfer.request = (*request);
_ctrl_xfer.buffer = buffer;
@ -89,8 +87,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu
(void) ep_addr;
(void) xferred_bytes;
usbh_device_t* dev = &_usbh_devices[dev_addr];
const uint8_t rhport = dev->rhport;
const uint8_t rhport = usbh_get_rhport(dev_addr);
tusb_control_request_t const * request = &_ctrl_xfer.request;

View File

@ -1,106 +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_HCD
* @{ */
#ifndef _TUSB_USBH_HCD_H_
#define _TUSB_USBH_HCD_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
#include "common/tusb_common.h"
#include "osal/osal.h"
#ifndef CFG_TUH_EP_MAX
#define CFG_TUH_EP_MAX 9
#endif
//--------------------------------------------------------------------+
// USBH-HCD common data structure
//--------------------------------------------------------------------+
// TODO move to usbh.c
typedef struct {
//------------- port -------------//
uint8_t rhport;
uint8_t hub_addr;
uint8_t hub_port;
uint8_t speed;
//------------- device descriptor -------------//
uint16_t vendor_id;
uint16_t product_id;
uint8_t ep0_packet_size;
//------------- configuration descriptor -------------//
// uint8_t interface_count; // bNumInterfaces alias
//------------- device -------------//
struct TU_ATTR_PACKED
{
uint8_t connected : 1;
uint8_t addressed : 1;
uint8_t configured : 1;
uint8_t suspended : 1;
};
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 )
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_TUH_EP_MAX][2];
// Mutex for claiming endpoint, only needed when using with preempted RTOS
#if CFG_TUSB_OS != OPT_OS_NONE
osal_mutex_def_t mutexdef;
osal_mutex_t mutex;
#endif
} usbh_device_t;
extern usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // including zero-address
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_USBH_HCD_H_ */
/** @} */

View File

@ -24,11 +24,9 @@
* This file is part of the TinyUSB stack.
*/
#include "common/tusb_common.h"
#include "host/hcd_attr.h"
#if TUSB_OPT_HOST_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX )
#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_EHCI_TRANSDIMENSION)
//--------------------------------------------------------------------+
// INCLUDE
@ -36,27 +34,44 @@
#include "osal/osal.h"
#include "host/hcd.h"
#include "host/usbh_hcd.h"
#include "hcd_ehci.h"
#include "ehci_api.h"
#include "ehci.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
// Debug level of EHCI
#define EHCI_DBG 2
// Framelist size as small as possible to save SRAM
#ifdef HCD_ATTR_EHCI_TRANSDIMENSION
// NXP Transdimension: 8 elements
#define FRAMELIST_SIZE_BIT_VALUE 7u
#define FRAMELIST_SIZE_USBCMD_VALUE (((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE) | \
((FRAMELIST_SIZE_BIT_VALUE >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB))
#else
// STD EHCI: 256 elements
#define FRAMELIST_SIZE_BIT_VALUE 2u
#define FRAMELIST_SIZE_USBCMD_VALUE ((FRAMELIST_SIZE_BIT_VALUE & 3) << EHCI_USBCMD_POS_FRAMELIST_SIZE)
#endif
#define FRAMELIST_SIZE (1024 >> FRAMELIST_SIZE_BIT_VALUE)
typedef struct
{
ehci_link_t period_framelist[EHCI_FRAMELIST_SIZE];
ehci_link_t period_framelist[FRAMELIST_SIZE];
// for NXP ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
// TODO only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
// [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms
// TODO better implementation without dummy head to save SRAM
ehci_qhd_t period_head_arr[4];
// Note control qhd of dev0 is used as head of async list
struct {
ehci_qhd_t qhd;
ehci_qtd_t qtd;
}control[CFG_TUSB_HOST_DEVICE_MAX+1];
}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);
@ -65,19 +80,17 @@ typedef struct
volatile uint32_t uframe_number;
}ehci_data_t;
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
// Periodic frame list must be 4K alignment
CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4096) static ehci_data_t ehci_data;
//--------------------------------------------------------------------+
// PROTOTYPE
//--------------------------------------------------------------------+
static inline ehci_link_t* get_period_head(uint8_t rhport, uint8_t interval_ms)
static inline ehci_link_t* get_period_head(uint8_t rhport, uint32_t interval_ms)
{
(void) rhport;
return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min8(EHCI_FRAMELIST_SIZE, interval_ms) ) ];
return (ehci_link_t*) &ehci_data.period_head_arr[ tu_log2( tu_min32(FRAMELIST_SIZE, interval_ms) ) ];
}
static inline ehci_qhd_t* qhd_control(uint8_t dev_addr)
@ -109,7 +122,7 @@ static inline bool qhd_has_xact_error (ehci_qhd_t * p_qhd)
//p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error
}
static void qhd_init (ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
static inline ehci_qtd_t* qtd_find_free (void);
static inline ehci_qtd_t* qtd_next (ehci_qtd_t const * p_qtd);
@ -218,12 +231,13 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
ehci_data.regs->command_bm.async_adv_doorbell = 1;
}
// EHCI controller init
bool hcd_ehci_init(uint8_t rhport)
bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg)
{
(void) capability_reg; // not used yet
tu_memclr(&ehci_data, sizeof(ehci_data_t));
ehci_data.regs = (ehci_registers_t* ) hcd_ehci_register_addr(rhport);
ehci_data.regs = (ehci_registers_t* ) operatial_reg;
ehci_registers_t* regs = ehci_data.regs;
@ -249,37 +263,38 @@ bool hcd_ehci_init(uint8_t rhport)
//------------- Periodic List -------------//
// Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only
for(uint32_t i=0; i<4; i++)
for ( uint32_t i = 0; i < TU_ARRAY_SIZE(ehci_data.period_head_arr); i++ )
{
ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
ehci_data.period_head_arr[i].int_smask = 1; // queue head in period list must have smask non-zero
ehci_data.period_head_arr[i].qtd_overlay.halted = 1; // dummy node, always inactive
}
ehci_link_t * const framelist = ehci_data.period_framelist;
ehci_link_t * const period_1ms = get_period_head(rhport, 1);
ehci_link_t * const period_1ms = get_period_head(rhport, 1u);
// all links --> period_head_arr[0] (1ms)
// 0, 2, 4, 6 etc --> period_head_arr[1] (2ms)
// 1, 5 --> period_head_arr[2] (4ms)
// 3 --> period_head_arr[3] (8ms)
// TODO EHCI_FRAMELIST_SIZE with other size than 8
for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i++)
for(uint32_t i=0; i<FRAMELIST_SIZE; i++)
{
framelist[i].address = (uint32_t) period_1ms;
framelist[i].type = EHCI_QTYPE_QHD;
}
for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i+=2)
for(uint32_t i=0; i<FRAMELIST_SIZE; i+=2)
{
list_insert(framelist + i, get_period_head(rhport, 2), EHCI_QTYPE_QHD);
list_insert(framelist + i, get_period_head(rhport, 2u), EHCI_QTYPE_QHD);
}
for(uint32_t i=1; i<EHCI_FRAMELIST_SIZE; i+=4)
for(uint32_t i=1; i<FRAMELIST_SIZE; i+=4)
{
list_insert(framelist + i, get_period_head(rhport, 4), EHCI_QTYPE_QHD);
list_insert(framelist + i, get_period_head(rhport, 4u), EHCI_QTYPE_QHD);
}
list_insert(framelist+3, get_period_head(rhport, 8), EHCI_QTYPE_QHD);
list_insert(framelist+3, get_period_head(rhport, 8u), EHCI_QTYPE_QHD);
period_1ms->terminate = 1;
@ -289,10 +304,9 @@ bool hcd_ehci_init(uint8_t rhport)
regs->nxp_tt_control = 0;
//------------- USB CMD Register -------------//
regs->command |= TU_BIT(EHCI_USBCMD_POS_RUN_STOP) | TU_BIT(EHCI_USBCMD_POS_ASYNC_ENABLE)
| TU_BIT(EHCI_USBCMD_POS_PERIOD_ENABLE) // TODO enable period list only there is int/iso endpoint
| ((EHCI_CFG_FRAMELIST_SIZE_BITS & TU_BIN8(011)) << EHCI_USBCMD_POS_FRAMELIST_SZIE)
| ((EHCI_CFG_FRAMELIST_SIZE_BITS >> 2) << EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB);
regs->command |= TU_BIT(EHCI_USBCMD_POS_RUN_STOP) | TU_BIT(EHCI_USBCMD_POS_ASYNC_ENABLE) |
TU_BIT(EHCI_USBCMD_POS_PERIOD_ENABLE) | // TODO enable period list only there is int/iso endpoint
FRAMELIST_SIZE_USBCMD_VALUE;
//------------- ConfigFlag Register (skip) -------------//
regs->portsc_bm.port_power = 1; // enable port power
@ -470,16 +484,16 @@ static void async_advance_isr(uint8_t rhport)
}
}
static void port_connect_status_change_isr(uint8_t hostid)
static void port_connect_status_change_isr(uint8_t rhport)
{
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
if (ehci_data.regs->portsc_bm.current_connect_status)
{
hcd_port_reset(hostid);
hcd_event_device_attach(hostid, true);
hcd_port_reset(rhport);
hcd_event_device_attach(rhport, true);
}else // device unplugged
{
hcd_event_device_remove(hostid, true);
hcd_event_device_remove(rhport, true);
}
}
@ -519,16 +533,16 @@ static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head)
}while(p_qhd != async_head); // async list traversal, stop if loop around
}
static void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms)
static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
{
uint16_t max_loop = 0;
uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1);
uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1u);
ehci_link_t next_item = * get_period_head(hostid, 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_TUSB_HOST_DEVICE_MAX)
max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
{
switch ( next_item.type )
{
@ -605,8 +619,8 @@ static void xfer_error_isr(uint8_t hostid)
}while(p_qhd != async_head); // async list traversal, stop if loop around
//------------- TODO refractor period list -------------//
uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1);
for (uint8_t interval_ms=1; interval_ms <= EHCI_FRAMELIST_SIZE; interval_ms *= 2)
uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1u);
for (uint32_t interval_ms=1; interval_ms <= FRAMELIST_SIZE; interval_ms *= 2)
{
ehci_link_t next_item = * get_period_head(hostid, interval_ms);
@ -649,13 +663,15 @@ void hcd_int_handler(uint8_t rhport)
if (int_status & EHCI_INT_MASK_FRAMELIST_ROLLOVER)
{
ehci_data.uframe_number += (EHCI_FRAMELIST_SIZE << 3);
ehci_data.uframe_number += (FRAMELIST_SIZE << 3);
}
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);
if (regs->portsc_bm.connect_status_change)
{
port_connect_status_change_isr(rhport);
@ -677,7 +693,7 @@ void hcd_int_handler(uint8_t rhport)
if (int_status & EHCI_INT_MASK_NXP_PERIODIC)
{
for (uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2)
for (uint32_t i=1; i <= FRAMELIST_SIZE; i *= 2)
{
period_list_xfer_complete_isr( rhport, i );
}
@ -774,13 +790,16 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
tu_memclr(p_qhd, sizeof(ehci_qhd_t));
}
hcd_devtree_info_t devtree_info;
hcd_devtree_get_info(dev_addr, &devtree_info);
uint8_t const xfer_type = ep_desc->bmAttributes.xfer;
uint8_t const interval = ep_desc->bInterval;
p_qhd->dev_addr = dev_addr;
p_qhd->fl_inactive_next_xact = 0;
p_qhd->ep_number = tu_edpt_number(ep_desc->bEndpointAddress);
p_qhd->ep_speed = _usbh_devices[dev_addr].speed;
p_qhd->ep_speed = devtree_info.speed;
p_qhd->data_toggle_control= (xfer_type == TUSB_XFER_CONTROL) ? 1 : 0;
p_qhd->head_list_flag = (dev_addr == 0) ? 1 : 0; // addr0's endpoint is the static asyn list head
p_qhd->max_packet_size = ep_desc->wMaxPacketSize.size;
@ -817,8 +836,8 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c
p_qhd->int_smask = p_qhd->fl_int_cmask = 0;
}
p_qhd->fl_hub_addr = _usbh_devices[dev_addr].hub_addr;
p_qhd->fl_hub_port = _usbh_devices[dev_addr].hub_port;
p_qhd->fl_hub_addr = devtree_info.hub_addr;
p_qhd->fl_hub_port = devtree_info.hub_port;
p_qhd->mult = 1; // TODO not use high bandwidth/park mode yet
//------------- HCD Management Data -------------//

View File

@ -46,8 +46,6 @@
//--------------------------------------------------------------------+
// EHCI CONFIGURATION & CONSTANTS
//--------------------------------------------------------------------+
#define EHCI_CFG_FRAMELIST_SIZE_BITS 7 /// Framelist Size (NXP specific) (0:1024) - (1:512) - (2:256) - (3:128) - (4:64) - (5:32) - (6:16) - (7:8)
#define EHCI_FRAMELIST_SIZE (1024 >> EHCI_CFG_FRAMELIST_SIZE_BITS)
// TODO merge OHCI with EHCI
enum {
@ -55,9 +53,6 @@ enum {
EHCI_MAX_SITD = 16
};
//------------- Validation -------------//
TU_VERIFY_STATIC(EHCI_CFG_FRAMELIST_SIZE_BITS <= 7, "incorrect value");
//--------------------------------------------------------------------+
// EHCI Data Structure
//--------------------------------------------------------------------+
@ -294,7 +289,7 @@ enum ehci_interrupt_mask_{
enum ehci_usbcmd_pos_ {
EHCI_USBCMD_POS_RUN_STOP = 0,
EHCI_USBCMD_POS_FRAMELIST_SZIE = 2,
EHCI_USBCMD_POS_FRAMELIST_SIZE = 2,
EHCI_USBCMD_POS_PERIOD_ENABLE = 4,
EHCI_USBCMD_POS_ASYNC_ENABLE = 5,
EHCI_USBCMD_POS_NXP_FRAMELIST_SIZE_MSB = 15,
@ -411,7 +406,7 @@ typedef volatile struct
uint32_t wake_on_over_current_enable : 1; ///< Enables over-current conditions as wake-up events
uint32_t nxp_phy_clock_disable : 1; ///< NXP customized: the PHY can be put into Low Power Suspend Clock Disable when the downstream device has been put into suspend mode or when no downstream device is connected. Low power suspend is completely under the control of software. 0: enable PHY clock, 1: disable PHY clock
uint32_t nxp_port_force_fullspeed : 1; ///< NXP customized: Writing this bit to a 1 will force the port to only connect at Full Speed. It disables the chirp sequence that allowsthe port to identify itself as High Speed. This is useful for testing FS configurations with a HS host, hub or device.
uint32_t : 1;
uint32_t TU_RESERVED : 1;
uint32_t nxp_port_speed : 2; ///< NXP customized: This register field indicates the speed atwhich the port is operating. For HS mode operation in the host controllerand HS/FS operation in the device controller the port routing steers data to the Protocol engine. For FS and LS mode operation in the host controller, the port routing steers data to the Protocol Engine w/ Embedded Transaction Translator. 0x0: Fullspeed, 0x1: Lowspeed, 0x2: Highspeed
uint32_t TU_RESERVED : 4;
}portsc_bm;

View File

@ -24,27 +24,19 @@
* This file is part of the TinyUSB stack.
*/
#ifndef _TUSB_HCD_EHCI_H_
#define _TUSB_HCD_EHCI_H_
#ifndef _TUSB_EHCI_API_H_
#define _TUSB_EHCI_API_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// API Implemented by HCD
//--------------------------------------------------------------------+
// Get operational address i.e EHCI Command register
uint32_t hcd_ehci_register_addr(uint8_t rhport);
//--------------------------------------------------------------------+
// API Implemented by EHCI
//--------------------------------------------------------------------+
// Initialize EHCI driver
extern bool hcd_ehci_init (uint8_t rhport);
bool ehci_init(uint8_t rhport, uint32_t capability_reg, uint32_t operatial_reg);
#ifdef __cplusplus
}

View File

@ -127,7 +127,7 @@ typedef struct
__I uint32_t ENDPTSTAT; ///< Endpoint Status
__IO uint32_t ENDPTCOMPLETE; ///< Endpoint Complete
__IO uint32_t ENDPTCTRL[8]; ///< Endpoint Control 0 - 7
} dcd_registers_t;
} dcd_registers_t, hcd_registers_t;
#ifdef __cplusplus
}

View File

@ -43,7 +43,7 @@
#include "common/tusb_common.h"
#include "common_transdimension.h"
#include "portable/ehci/hcd_ehci.h"
#include "portable/ehci/ehci_api.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@ -82,26 +82,26 @@ typedef struct
bool hcd_init(uint8_t rhport)
{
dcd_registers_t* dcd_reg = (dcd_registers_t*) _hcd_controller[rhport].regs_base;
hcd_registers_t* hcd_reg = (hcd_registers_t*) _hcd_controller[rhport].regs_base;
// Reset controller
dcd_reg->USBCMD |= USBCMD_RESET;
while( dcd_reg->USBCMD & USBCMD_RESET ) {}
hcd_reg->USBCMD |= USBCMD_RESET;
while( hcd_reg->USBCMD & USBCMD_RESET ) {}
// Set mode to device, must be set immediately after reset
#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
// LPC18XX/43XX need to set VBUS Power Select to HIGH
// RHPORT1 is fullspeed only (need external PHY for Highspeed)
dcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
if (rhport == 1) dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
if (rhport == 1) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
#else
dcd_reg->USBMODE = USBMODE_CM_HOST;
hcd_reg->USBMODE = USBMODE_CM_HOST;
#endif
// FIXME force full speed, still have issue with Highspeed enumeration
dcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
return hcd_ehci_init(rhport);
return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
}
void hcd_int_enable(uint8_t rhport)
@ -114,12 +114,4 @@ void hcd_int_disable(uint8_t rhport)
NVIC_DisableIRQ(_hcd_controller[rhport].irqnum);
}
uint32_t hcd_ehci_register_addr(uint8_t rhport)
{
dcd_registers_t* hcd_reg = (dcd_registers_t*) _hcd_controller[rhport].regs_base;
// EHCI USBCMD has same address within dcd_register_t
return (uint32_t) &hcd_reg->USBCMD;
}
#endif

View File

@ -24,10 +24,9 @@
* This file is part of the TinyUSB stack.
*/
#include <common/tusb_common.h>
#include "host/hcd_attr.h"
#if TUSB_OPT_HOST_ENABLED && \
(CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX)
#if TUSB_OPT_HOST_ENABLED && defined(HCD_ATTR_OHCI)
//--------------------------------------------------------------------+
// INCLUDE
@ -35,7 +34,6 @@
#include "osal/osal.h"
#include "host/hcd.h"
#include "host/usbh_hcd.h"
#include "ohci.h"
// TODO remove
@ -280,10 +278,13 @@ static void ed_init(ohci_ed_t *p_ed, uint8_t dev_addr, uint16_t ep_size, uint8_t
tu_memclr(p_ed, sizeof(ohci_ed_t));
}
hcd_devtree_info_t devtree_info;
hcd_devtree_get_info(dev_addr, &devtree_info);
p_ed->dev_addr = dev_addr;
p_ed->ep_number = ep_addr & 0x0F;
p_ed->pid = (xfer_type == TUSB_XFER_CONTROL) ? PID_FROM_TD : (tu_edpt_dir(ep_addr) ? PID_IN : PID_OUT);
p_ed->speed = _usbh_devices[dev_addr].speed;
p_ed->speed = devtree_info.speed;
p_ed->is_iso = (xfer_type == TUSB_XFER_ISOCHRONOUS) ? 1 : 0;
p_ed->max_packet_size = ep_size;

View File

@ -159,7 +159,7 @@ typedef struct TU_ATTR_ALIGNED(256)
struct {
ohci_ed_t ed;
ohci_gtd_t gtd;
}control[CFG_TUSB_HOST_DEVICE_MAX+1];
}control[CFG_TUH_DEVICE_MAX+1];
// ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];

View File

@ -39,7 +39,6 @@
#include "host/hcd.h"
#include "host/usbh.h"
#include "host/usbh_hcd.h"
#define ROOT_PORT 0

View File

@ -117,10 +117,11 @@ void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_
{
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
TU_LOG(2, " Bind EP %02x to driver id %u\r\n", ep_addr, driver_id);
ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
}
len = (uint16_t)(len + tu_desc_len(p_desc));
len = (uint16_t)(len + tu_desc_len(p_desc));
p_desc = tu_desc_next(p_desc);
}
}

View File

@ -267,14 +267,8 @@
// HOST OPTIONS
//--------------------------------------------------------------------
#if TUSB_OPT_HOST_ENABLED
#ifndef CFG_TUSB_HOST_DEVICE_MAX
#define CFG_TUSB_HOST_DEVICE_MAX 1
#warning CFG_TUSB_HOST_DEVICE_MAX is not defined, default value is 1
#endif
//------------- HUB CLASS -------------//
#if CFG_TUH_HUB && (CFG_TUSB_HOST_DEVICE_MAX == 1)
#error There is no benefit enable hub with max device is 1. Please disable hub or increase CFG_TUSB_HOST_DEVICE_MAX
#ifndef CFG_TUH_DEVICE_MAX
#define CFG_TUH_DEVICE_MAX 1
#endif
#ifndef CFG_TUH_ENUMERATION_BUFSIZE