Merge branch 'master' into portability
This commit is contained in:
245
src/host/usbh.c
245
src/host/usbh.c
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "host/hcd.h"
|
||||
#include "tusb.h"
|
||||
#include "common/tusb_private.h"
|
||||
#include "host/usbh_classdriver.h"
|
||||
#include "hub.h"
|
||||
|
||||
@@ -46,15 +45,15 @@
|
||||
#define CFG_TUH_INTERFACE_MAX 8
|
||||
#endif
|
||||
|
||||
// Debug level of USBD
|
||||
#define USBH_DBG_LVL 2
|
||||
// Debug level, TUSB_CFG_DEBUG must be at least this level for debug message
|
||||
#define USBH_DEBUG 2
|
||||
|
||||
#define TU_LOG_USBH(...) TU_LOG(USBH_DEBUG, __VA_ARGS__)
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH-HCD common data structure
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// device0 struct must be strictly a subset of normal device struct
|
||||
// TODO refactor later
|
||||
typedef struct
|
||||
{
|
||||
// port
|
||||
@@ -62,15 +61,13 @@ typedef struct
|
||||
uint8_t hub_addr;
|
||||
uint8_t hub_port;
|
||||
uint8_t speed;
|
||||
volatile uint8_t enumerating;
|
||||
|
||||
struct TU_ATTR_PACKED
|
||||
{
|
||||
volatile uint8_t connected : 1;
|
||||
volatile uint8_t addressed : 1;
|
||||
volatile uint8_t configured : 1;
|
||||
volatile uint8_t suspended : 1;
|
||||
};
|
||||
|
||||
// struct TU_ATTR_PACKED {
|
||||
// uint8_t speed : 4; // packed speed to save footprint
|
||||
// volatile uint8_t enumerating : 1;
|
||||
// uint8_t TU_RESERVED : 3;
|
||||
// };
|
||||
} usbh_dev0_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -121,10 +118,6 @@ typedef struct {
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invalid driver ID in itf2drv[] ep2drv[][] mapping
|
||||
enum { DRVID_INVALID = 0xFFu };
|
||||
enum { CONTROLLER_INVALID = 0xFFu };
|
||||
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
#define DRIVER_NAME(_name) .name = _name,
|
||||
#else
|
||||
@@ -202,7 +195,7 @@ enum { CONFIG_NUM = 1 }; // default to use configuration 1
|
||||
// sum of end device + hub
|
||||
#define TOTAL_DEVICES (CFG_TUH_DEVICE_MAX + CFG_TUH_HUB)
|
||||
|
||||
static uint8_t _usbh_controller = CONTROLLER_INVALID;
|
||||
static uint8_t _usbh_controller = TU_INDEX_INVALID_8;
|
||||
|
||||
// Device with address = 0 for enumeration
|
||||
static usbh_dev0_t _dev0;
|
||||
@@ -212,28 +205,12 @@ static usbh_dev0_t _dev0;
|
||||
// TODO: hub can has its own simpler struct to save memory
|
||||
CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[TOTAL_DEVICES];
|
||||
|
||||
// Mutex for claiming endpoint, only needed when using with preempted RTOS
|
||||
#if TUSB_OPT_MUTEX
|
||||
static osal_mutex_def_t _usbh_mutexdef;
|
||||
static osal_mutex_t _usbh_mutex;
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void usbh_lock(void)
|
||||
{
|
||||
osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void usbh_unlock(void)
|
||||
{
|
||||
osal_mutex_unlock(_usbh_mutex);
|
||||
}
|
||||
|
||||
// Mutex for claiming endpoint
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
static osal_mutex_def_t _usbh_mutexdef;
|
||||
static osal_mutex_t _usbh_mutex;
|
||||
#else
|
||||
|
||||
#define _usbh_mutex NULL
|
||||
|
||||
#define usbh_lock()
|
||||
#define usbh_unlock()
|
||||
|
||||
#define _usbh_mutex NULL
|
||||
#endif
|
||||
|
||||
// Event queue
|
||||
@@ -244,10 +221,10 @@ static osal_queue_t _usbh_q;
|
||||
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN
|
||||
static uint8_t _usbh_ctrl_buf[CFG_TUH_ENUMERATION_BUFSIZE];
|
||||
|
||||
// Control transfer: since most controller does not support multiple control transfer
|
||||
// on multiple devices concurrently. And control transfer is not used much except enumeration
|
||||
// We will only execute control transfer one at a time.
|
||||
struct
|
||||
// Control transfers: since most controllers do not support multiple control transfers
|
||||
// on multiple devices concurrently and control transfers are not used much except for
|
||||
// enumeration, we will only execute control transfers one at a time.
|
||||
CFG_TUSB_MEM_SECTION struct
|
||||
{
|
||||
tusb_control_request_t request TU_ATTR_ALIGNED(4);
|
||||
uint8_t* buffer;
|
||||
@@ -277,8 +254,6 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
|
||||
// TODO rework time-related function later
|
||||
void osal_task_delay(uint32_t msec)
|
||||
{
|
||||
(void) msec;
|
||||
|
||||
const uint32_t start = hcd_frame_number(_usbh_controller);
|
||||
while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {}
|
||||
}
|
||||
@@ -328,13 +303,13 @@ tusb_speed_t tuh_speed_get (uint8_t dev_addr)
|
||||
static void clear_device(usbh_device_t* dev)
|
||||
{
|
||||
tu_memclr(dev, sizeof(usbh_device_t));
|
||||
memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
|
||||
memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
|
||||
memset(dev->itf2drv, TU_INDEX_INVALID_8, sizeof(dev->itf2drv)); // invalid mapping
|
||||
memset(dev->ep2drv , TU_INDEX_INVALID_8, sizeof(dev->ep2drv )); // invalid mapping
|
||||
}
|
||||
|
||||
bool tuh_inited(void)
|
||||
{
|
||||
return _usbh_controller != CONTROLLER_INVALID;
|
||||
return _usbh_controller != TU_INDEX_INVALID_8;
|
||||
}
|
||||
|
||||
bool tuh_init(uint8_t controller_id)
|
||||
@@ -342,18 +317,20 @@ bool tuh_init(uint8_t controller_id)
|
||||
// skip if already initialized
|
||||
if ( tuh_inited() ) return true;
|
||||
|
||||
TU_LOG2("USBH init on controller %u\r\n", controller_id);
|
||||
TU_LOG2_INT(sizeof(usbh_device_t));
|
||||
TU_LOG2_INT(sizeof(hcd_event_t));
|
||||
TU_LOG2_INT(sizeof(_ctrl_xfer));
|
||||
TU_LOG2_INT(sizeof(tuh_xfer_t));
|
||||
TU_LOG_USBH("USBH init on controller %u\r\n", controller_id);
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(usbh_device_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(hcd_event_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(_ctrl_xfer));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(tuh_xfer_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(tu_fifo_t));
|
||||
TU_LOG_INT(USBH_DEBUG, sizeof(tu_edpt_stream_t));
|
||||
|
||||
// Event queue
|
||||
_usbh_q = osal_queue_create( &_usbh_qdef );
|
||||
TU_ASSERT(_usbh_q != NULL);
|
||||
|
||||
#if TUSB_OPT_MUTEX
|
||||
// Mutex
|
||||
#if OSAL_MUTEX_REQUIRED
|
||||
// Init mutex
|
||||
_usbh_mutex = osal_mutex_create(&_usbh_mutexdef);
|
||||
TU_ASSERT(_usbh_mutex);
|
||||
#endif
|
||||
@@ -371,7 +348,7 @@ bool tuh_init(uint8_t controller_id)
|
||||
// Class drivers
|
||||
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
TU_LOG2("%s init\r\n", usbh_class_drivers[drv_id].name);
|
||||
TU_LOG_USBH("%s init\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].init();
|
||||
}
|
||||
|
||||
@@ -417,14 +394,22 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
switch (event.event_id)
|
||||
{
|
||||
case HCD_EVENT_DEVICE_ATTACH:
|
||||
// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
|
||||
// due to the shared _usbh_ctrl_buf, we must complete enumerating
|
||||
// one device before enumerating another one.
|
||||
TU_LOG2("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
|
||||
enum_new_device(&event);
|
||||
if ( _dev0.enumerating )
|
||||
{
|
||||
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
|
||||
osal_queue_send(_usbh_q, &event, in_isr);
|
||||
}else
|
||||
{
|
||||
TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
|
||||
_dev0.enumerating = 1;
|
||||
enum_new_device(&event);
|
||||
}
|
||||
break;
|
||||
|
||||
case HCD_EVENT_DEVICE_REMOVE:
|
||||
TU_LOG2("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||
TU_LOG_USBH("[%u:%u:%u] USBH DEVICE REMOVED\r\n", event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||
process_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port);
|
||||
|
||||
#if CFG_TUH_HUB
|
||||
@@ -443,7 +428,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
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);
|
||||
TU_LOG_USBH("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
|
||||
|
||||
if (event.dev_addr == 0)
|
||||
{
|
||||
@@ -467,7 +452,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
|
||||
uint8_t drv_id = dev->ep2drv[epnum][ep_dir];
|
||||
if(drv_id < USBH_CLASS_DRIVER_COUNT)
|
||||
{
|
||||
TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
|
||||
TU_LOG_USBH("%s xfer callback\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
else
|
||||
@@ -537,8 +522,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
|
||||
// TODO probably better to use semaphore as resource management than mutex
|
||||
usbh_lock();
|
||||
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
|
||||
bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
|
||||
if (is_idle)
|
||||
@@ -553,14 +537,16 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
_ctrl_xfer.user_data = xfer->user_data;
|
||||
}
|
||||
|
||||
usbh_unlock();
|
||||
(void) osal_mutex_unlock(_usbh_mutex);
|
||||
|
||||
TU_VERIFY(is_idle);
|
||||
const uint8_t rhport = usbh_get_rhport(daddr);
|
||||
|
||||
TU_LOG2("[%u:%u] %s: ", rhport, daddr, xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME ? tu_str_std_request[xfer->setup->bRequest] : "Unknown Request");
|
||||
TU_LOG2_VAR(xfer->setup);
|
||||
TU_LOG2("\r\n");
|
||||
TU_LOG_USBH("[%u:%u] %s: ", rhport, daddr,
|
||||
(xfer->setup->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && xfer->setup->bRequest <= TUSB_REQ_SYNCH_FRAME) ?
|
||||
tu_str_std_request[xfer->setup->bRequest] : "Class Request");
|
||||
TU_LOG_PTR(USBH_DEBUG, xfer->setup);
|
||||
TU_LOG_USBH("\r\n");
|
||||
|
||||
if (xfer->complete_cb)
|
||||
{
|
||||
@@ -597,14 +583,14 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
|
||||
TU_ATTR_ALWAYS_INLINE static inline void _set_control_xfer_stage(uint8_t stage)
|
||||
{
|
||||
usbh_lock();
|
||||
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
_ctrl_xfer.stage = stage;
|
||||
usbh_unlock();
|
||||
(void) osal_mutex_unlock(_usbh_mutex);
|
||||
}
|
||||
|
||||
static void _xfer_complete(uint8_t daddr, xfer_result_t result)
|
||||
{
|
||||
TU_LOG2("\r\n");
|
||||
TU_LOG_USBH("\r\n");
|
||||
|
||||
// duplicate xfer since user can execute control transfer within callback
|
||||
tusb_control_request_t const request = _ctrl_xfer.request;
|
||||
@@ -620,9 +606,7 @@ static void _xfer_complete(uint8_t daddr, xfer_result_t result)
|
||||
.user_data = _ctrl_xfer.user_data
|
||||
};
|
||||
|
||||
usbh_lock();
|
||||
_ctrl_xfer.stage = CONTROL_STAGE_IDLE;
|
||||
usbh_unlock();
|
||||
_set_control_xfer_stage(CONTROL_STAGE_IDLE);
|
||||
|
||||
if (xfer_temp.complete_cb)
|
||||
{
|
||||
@@ -639,7 +623,11 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
||||
|
||||
if (XFER_RESULT_SUCCESS != result)
|
||||
{
|
||||
TU_LOG1("[%u:%u] Control %s\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED");
|
||||
TU_LOG1("[%u:%u] Control %s, xferred_bytes = %lu\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes);
|
||||
#if CFG_TUSB_DEBUG == 1
|
||||
TU_LOG1_PTR(request);
|
||||
TU_LOG1("\r\n");
|
||||
#endif
|
||||
|
||||
// terminate transfer if any stage failed
|
||||
_xfer_complete(dev_addr, result);
|
||||
@@ -660,8 +648,8 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
||||
case CONTROL_STAGE_DATA:
|
||||
if (request->wLength)
|
||||
{
|
||||
TU_LOG2("[%u:%u] Control data:\r\n", rhport, dev_addr);
|
||||
TU_LOG2_MEM(_ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, dev_addr);
|
||||
TU_LOG_MEM(USBH_DEBUG, _ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
}
|
||||
|
||||
_ctrl_xfer.actual_len = (uint16_t) xferred_bytes;
|
||||
@@ -777,7 +765,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
tu_edpt_state_t* ep_state = &dev->ep_status[epnum][dir];
|
||||
|
||||
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||
TU_LOG_USBH(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||
|
||||
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
||||
TU_ASSERT(ep_state->busy == 0);
|
||||
@@ -793,7 +781,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b
|
||||
|
||||
if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
|
||||
{
|
||||
TU_LOG2("OK\r\n");
|
||||
TU_LOG_USBH("OK\r\n");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
@@ -808,7 +796,7 @@ bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * b
|
||||
|
||||
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
||||
{
|
||||
TU_LOG2("[%u:%u] Open EP0 with Size = %u\r\n", usbh_get_rhport(dev_addr), dev_addr, max_packet_size);
|
||||
TU_LOG_USBH("[%u:%u] Open EP0 with Size = %u\r\n", usbh_get_rhport(dev_addr), dev_addr, max_packet_size);
|
||||
|
||||
tusb_desc_endpoint_t ep0_desc =
|
||||
{
|
||||
@@ -977,7 +965,7 @@ bool tuh_descriptor_get_serial_string(uint8_t daddr, uint16_t language_id, void*
|
||||
bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_type, uint8_t index, void* buffer, uint16_t len,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
TU_LOG2("HID Get Report Descriptor\r\n");
|
||||
TU_LOG_USBH("HID Get Report Descriptor\r\n");
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
@@ -1016,7 +1004,7 @@ bool tuh_descriptor_get_hid_report(uint8_t daddr, uint8_t itf_num, uint8_t desc_
|
||||
bool tuh_configuration_set(uint8_t daddr, uint8_t config_num,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
TU_LOG2("Set Configuration = %d\r\n", config_num);
|
||||
TU_LOG_USBH("Set Configuration = %d\r\n", config_num);
|
||||
|
||||
tusb_control_request_t const request =
|
||||
{
|
||||
@@ -1120,11 +1108,11 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
|
||||
(hub_port == 0 || dev->hub_port == hub_port) && // hub_port = 0 means all devices of downstream hub
|
||||
dev->connected)
|
||||
{
|
||||
TU_LOG2(" Address = %u\r\n", dev_addr);
|
||||
TU_LOG_USBH(" Address = %u\r\n", dev_addr);
|
||||
|
||||
if (is_hub_addr(dev_addr))
|
||||
{
|
||||
TU_LOG(USBH_DBG_LVL, "HUB address = %u is unmounted\r\n", dev_addr);
|
||||
TU_LOG(USBH_DEBUG, "HUB address = %u is unmounted\r\n", dev_addr);
|
||||
// If the device itself is a usb hub, unplug downstream devices.
|
||||
// FIXME un-roll recursive calls to prevent potential stack overflow
|
||||
process_device_unplugged(rhport, dev_addr, 0);
|
||||
@@ -1137,7 +1125,7 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
|
||||
// Close class driver
|
||||
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
TU_LOG2("%s close\r\n", usbh_class_drivers[drv_id].name);
|
||||
TU_LOG_USBH("%s close\r\n", usbh_class_drivers[drv_id].name);
|
||||
usbh_class_drivers[drv_id].close(dev_addr);
|
||||
}
|
||||
|
||||
@@ -1182,12 +1170,28 @@ static void enum_full_complete(void);
|
||||
// process device enumeration
|
||||
static void process_enumeration(tuh_xfer_t* xfer)
|
||||
{
|
||||
// Retry a few times with transfers in enumeration since device can be unstable when starting up
|
||||
enum {
|
||||
ATTEMPT_COUNT_MAX = 3,
|
||||
ATTEMPT_DELAY_MS = 100
|
||||
};
|
||||
static uint8_t failed_count = 0;
|
||||
|
||||
if (XFER_RESULT_SUCCESS != xfer->result)
|
||||
{
|
||||
// stop enumeration, maybe we could retry this
|
||||
enum_full_complete();
|
||||
// retry if not reaching max attempt
|
||||
if ( failed_count < ATTEMPT_COUNT_MAX )
|
||||
{
|
||||
failed_count++;
|
||||
osal_task_delay(ATTEMPT_DELAY_MS); // delay a bit
|
||||
TU_ASSERT(tuh_control_xfer(xfer), );
|
||||
}else
|
||||
{
|
||||
enum_full_complete();
|
||||
}
|
||||
return;
|
||||
}
|
||||
failed_count = 0;
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
uintptr_t const state = xfer->user_data;
|
||||
@@ -1246,7 +1250,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
|
||||
TU_ASSERT( usbh_edpt_control_open(addr0, 8), );
|
||||
|
||||
// Get first 8 bytes of device descriptor for Control Endpoint size
|
||||
TU_LOG2("Get 8 byte of Device Descriptor\r\n");
|
||||
TU_LOG_USBH("Get 8 byte of Device Descriptor\r\n");
|
||||
TU_ASSERT(tuh_descriptor_get_device(addr0, _usbh_ctrl_buf, 8, process_enumeration, ENUM_SET_ADDR), );
|
||||
}
|
||||
break;
|
||||
@@ -1255,13 +1259,13 @@ static void process_enumeration(tuh_xfer_t* xfer)
|
||||
case ENUM_RESET_2:
|
||||
// TODO not used by now, but may be needed for some devices !?
|
||||
// Reset device again before Set Address
|
||||
TU_LOG2("Port reset2 \r\n");
|
||||
TU_LOG_USBH("Port reset2 \r\n");
|
||||
if (_dev0.hub_addr == 0)
|
||||
{
|
||||
// connected directly to roothub
|
||||
hcd_port_reset( _dev0.rhport );
|
||||
osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
|
||||
// sof of controller may not running while reseting
|
||||
// sof of controller may not running while resetting
|
||||
hcd_port_reset_end(_dev0.rhport);
|
||||
// TODO: fall through to SET ADDRESS, refactor later
|
||||
}
|
||||
@@ -1295,7 +1299,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
|
||||
TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_size), );
|
||||
|
||||
// Get full device descriptor
|
||||
TU_LOG2("Get Device Descriptor\r\n");
|
||||
TU_LOG_USBH("Get Device Descriptor\r\n");
|
||||
TU_ASSERT(tuh_descriptor_get_device(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), process_enumeration, ENUM_GET_9BYTE_CONFIG_DESC), );
|
||||
}
|
||||
break;
|
||||
@@ -1316,7 +1320,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
|
||||
|
||||
// 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_LOG_USBH("Get Configuration[0] Descriptor (9 bytes)\r\n");
|
||||
TU_ASSERT( tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, 9, process_enumeration, ENUM_GET_FULL_CONFIG_DESC), );
|
||||
}
|
||||
break;
|
||||
@@ -1333,7 +1337,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
|
||||
|
||||
// Get full configuration descriptor
|
||||
uint8_t const config_idx = CONFIG_NUM - 1;
|
||||
TU_LOG2("Get Configuration[0] Descriptor\r\n");
|
||||
TU_LOG_USBH("Get Configuration[0] Descriptor\r\n");
|
||||
TU_ASSERT( tuh_descriptor_get_configuration(daddr, config_idx, _usbh_ctrl_buf, total_len, process_enumeration, ENUM_SET_CONFIG), );
|
||||
}
|
||||
break;
|
||||
@@ -1348,17 +1352,17 @@ static void process_enumeration(tuh_xfer_t* xfer)
|
||||
|
||||
case ENUM_CONFIG_DRIVER:
|
||||
{
|
||||
TU_LOG2("Device configured\r\n");
|
||||
TU_LOG_USBH("Device configured\r\n");
|
||||
usbh_device_t* dev = get_device(daddr);
|
||||
TU_ASSERT(dev, );
|
||||
|
||||
dev->configured = 1;
|
||||
|
||||
// Start the Set Configuration process for interfaces (itf = DRVID_INVALID)
|
||||
// Start the Set Configuration process for interfaces (itf = TU_INDEX_INVALID_8)
|
||||
// Since driver can perform control transfer within its set_config, this is done asynchronously.
|
||||
// The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete()
|
||||
// TODO use separated API instead of using DRVID_INVALID
|
||||
usbh_driver_set_config_complete(daddr, DRVID_INVALID);
|
||||
// TODO use separated API instead of using TU_INDEX_INVALID_8
|
||||
usbh_driver_set_config_complete(daddr, TU_INDEX_INVALID_8);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1381,14 +1385,14 @@ static bool enum_new_device(hcd_event_t* event)
|
||||
// wait until device is stable TODO non blocking
|
||||
hcd_port_reset(_dev0.rhport);
|
||||
osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
|
||||
// sof of controller may not running while reseting
|
||||
// sof of controller may not running while resetting
|
||||
hcd_port_reset_end( _dev0.rhport);
|
||||
|
||||
// device unplugged while delaying
|
||||
if ( !hcd_port_connect_status(_dev0.rhport) ) return true;
|
||||
|
||||
_dev0.speed = hcd_port_speed_get(_dev0.rhport );
|
||||
TU_LOG2("%s Speed\r\n", tu_str_speed[_dev0.speed]);
|
||||
TU_LOG_USBH("%s Speed\r\n", tu_str_speed[_dev0.speed]);
|
||||
|
||||
// fake transfer to kick-off the enumeration process
|
||||
tuh_xfer_t xfer;
|
||||
@@ -1445,7 +1449,7 @@ static bool enum_request_set_addr(void)
|
||||
uint8_t const new_addr = get_new_address(desc_device->bDeviceClass == TUSB_CLASS_HUB);
|
||||
TU_ASSERT(new_addr != 0);
|
||||
|
||||
TU_LOG2("Set Address = %d\r\n", new_addr);
|
||||
TU_LOG_USBH("Set Address = %d\r\n", new_addr);
|
||||
|
||||
usbh_device_t* new_dev = get_device(new_addr);
|
||||
|
||||
@@ -1489,9 +1493,12 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
{
|
||||
usbh_device_t* dev = get_device(dev_addr);
|
||||
|
||||
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
|
||||
uint16_t const total_len = tu_le16toh(desc_cfg->wTotalLength);
|
||||
uint8_t const* desc_end = ((uint8_t const*) desc_cfg) + total_len;
|
||||
uint8_t const* p_desc = tu_desc_next(desc_cfg);
|
||||
|
||||
TU_LOG_USBH("Parsing Configuration descriptor (wTotalLength = %u)\r\n", total_len);
|
||||
|
||||
// parse each interfaces
|
||||
while( p_desc < desc_end )
|
||||
{
|
||||
@@ -1515,7 +1522,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
|
||||
#if CFG_TUH_MIDI
|
||||
// MIDI has 2 interfaces (Audio Control v1 + MIDIStreaming) but does not have IAD
|
||||
// manually increase the associated count
|
||||
// manually force associated count = 2
|
||||
if (1 == assoc_itf_count &&
|
||||
TUSB_CLASS_AUDIO == desc_itf->bInterfaceClass &&
|
||||
AUDIO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass &&
|
||||
@@ -1525,19 +1532,29 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_CDC
|
||||
// Some legacy CDC device does not use IAD but rather use device class as hint to combine 2 interfaces
|
||||
// manually force associated count = 2
|
||||
if (1 == assoc_itf_count &&
|
||||
TUSB_CLASS_CDC == desc_itf->bInterfaceClass &&
|
||||
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == desc_itf->bInterfaceSubClass)
|
||||
{
|
||||
assoc_itf_count = 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, assoc_itf_count, (uint16_t) (desc_end-p_desc));
|
||||
TU_ASSERT(drv_len >= sizeof(tusb_desc_interface_t));
|
||||
|
||||
// Find driver for this interface
|
||||
uint8_t drv_id;
|
||||
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||
for (uint8_t drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
||||
|
||||
if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
|
||||
{
|
||||
// open successfully
|
||||
TU_LOG2(" %s opened\r\n", driver->name);
|
||||
TU_LOG_USBH(" %s opened\r\n", driver->name);
|
||||
|
||||
// bind (associated) interfaces to found driver
|
||||
for(uint8_t i=0; i<assoc_itf_count; i++)
|
||||
@@ -1545,7 +1562,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
uint8_t const itf_num = desc_itf->bInterfaceNumber+i;
|
||||
|
||||
// Interface number must not be used already
|
||||
TU_ASSERT( DRVID_INVALID == dev->itf2drv[itf_num] );
|
||||
TU_ASSERT( TU_INDEX_INVALID_8 == dev->itf2drv[itf_num] );
|
||||
dev->itf2drv[itf_num] = drv_id;
|
||||
}
|
||||
|
||||
@@ -1557,7 +1574,7 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
|
||||
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
||||
{
|
||||
TU_LOG(USBH_DBG_LVL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
||||
TU_LOG(USBH_DEBUG, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
||||
desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
|
||||
}
|
||||
}
|
||||
@@ -1576,12 +1593,13 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t 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
|
||||
// IAD binding interface such as CDCs should return itf_num + 1 when complete
|
||||
// with usbh_driver_set_config_complete()
|
||||
uint8_t const drv_id = dev->itf2drv[itf_num];
|
||||
if (drv_id != DRVID_INVALID)
|
||||
if (drv_id != TU_INDEX_INVALID_8)
|
||||
{
|
||||
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
||||
TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
|
||||
TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num);
|
||||
driver->set_config(dev_addr, itf_num);
|
||||
break;
|
||||
}
|
||||
@@ -1594,7 +1612,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||
|
||||
if (is_hub_addr(dev_addr))
|
||||
{
|
||||
TU_LOG(USBH_DBG_LVL, "HUB address = %u is mounted\r\n", dev_addr);
|
||||
TU_LOG(USBH_DEBUG, "HUB address = %u is mounted\r\n", dev_addr);
|
||||
}else
|
||||
{
|
||||
// Invoke callback if available
|
||||
@@ -1605,6 +1623,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||
|
||||
static void enum_full_complete(void)
|
||||
{
|
||||
// mark enumeration as complete
|
||||
_dev0.enumerating = 0;
|
||||
|
||||
#if CFG_TUH_HUB
|
||||
// get next hub status
|
||||
if (_dev0.hub_addr) hub_edpt_status_xfer(_dev0.hub_addr);
|
||||
|
||||
Reference in New Issue
Block a user