summaryrefslogtreecommitdiff
path: root/tinyusb
diff options
context:
space:
mode:
authorhathach <[email protected]>2013-09-30 15:16:23 +0700
committerhathach <[email protected]>2013-09-30 15:16:23 +0700
commit3cc169f2fd3159ecad494eb6223bbed6cc8135d6 (patch)
tree8a29e735e2f450857f6180c442695cad78b3fd7c /tinyusb
parentcb600ed9887224b6e0b4904f66442eef2900fd2d (diff)
able to mount one device on the hub
Diffstat (limited to 'tinyusb')
-rw-r--r--tinyusb/class/msc_host.c12
-rw-r--r--tinyusb/common/errors.h1
-rw-r--r--tinyusb/host/ehci/ehci.c2
-rw-r--r--tinyusb/host/hub.c89
-rw-r--r--tinyusb/host/hub.h127
-rw-r--r--tinyusb/host/usbh.c150
-rw-r--r--tinyusb/host/usbh_hcd.h2
7 files changed, 359 insertions, 24 deletions
diff --git a/tinyusb/class/msc_host.c b/tinyusb/class/msc_host.c
index af85606cf..14c6bb5e4 100644
--- a/tinyusb/class/msc_host.c
+++ b/tinyusb/class/msc_host.c
@@ -109,6 +109,9 @@ tusb_error_t tusbh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint
return TUSB_ERROR_NONE;
}
+//--------------------------------------------------------------------+
+// PUBLIC API: SCSI COMMAND
+//--------------------------------------------------------------------+
static inline void msc_cbw_add_signature(msc_cmd_block_wrapper_t *p_cbw, uint8_t lun) ATTR_ALWAYS_INLINE;
static inline void msc_cbw_add_signature(msc_cmd_block_wrapper_t *p_cbw, uint8_t lun)
{
@@ -138,9 +141,6 @@ static tusb_error_t msch_command_xfer(msch_interface_t * p_msch, void* p_buffer)
return TUSB_ERROR_NONE;
}
-//--------------------------------------------------------------------+
-// PUBLIC API: SCSI COMMAND
-//--------------------------------------------------------------------+
tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data)
{
msch_interface_t* p_msch = &msch_data[dev_addr-1];
@@ -317,14 +317,14 @@ tusb_error_t msch_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t con
tusb_descriptor_endpoint_t const *p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_interface_desc );
for(uint32_t i=0; i<2; i++)
{
- ASSERT_INT(TUSB_DESC_TYPE_ENDPOINT, p_endpoint->bDescriptorType, TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED);
- ASSERT_INT(TUSB_XFER_BULK, p_endpoint->bmAttributes.xfer, TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED);
+ SUBTASK_ASSERT(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->bDescriptorType);
+ SUBTASK_ASSERT(TUSB_XFER_BULK == p_endpoint->bmAttributes.xfer);
pipe_handle_t * p_pipe_hdl = ( p_endpoint->bEndpointAddress & TUSB_DIR_DEV_TO_HOST_MASK ) ?
&msch_data[dev_addr-1].bulk_in : &msch_data[dev_addr-1].bulk_out;
(*p_pipe_hdl) = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_MSC);
- ASSERT ( pipehandle_is_valid(*p_pipe_hdl), TUSB_ERROR_HCD_OPEN_PIPE_FAILED );
+ SUBTASK_ASSERT( pipehandle_is_valid(*p_pipe_hdl) );
p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_endpoint );
}
diff --git a/tinyusb/common/errors.h b/tinyusb/common/errors.h
index 77461f568..8762bf06d 100644
--- a/tinyusb/common/errors.h
+++ b/tinyusb/common/errors.h
@@ -89,6 +89,7 @@
ENTRY(TUSB_ERROR_MSCH_UNSUPPORTED_PROTOCOL )\
ENTRY(TUSB_ERROR_MSCH_UNKNOWN_SCSI_COMMAND )\
ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
+ ENTRY(TUSB_ERROR_HUB_FEATURE_NOT_SUPPORTED )\
ENTRY(TUSB_ERROR_NOT_SUPPORTED_YET )\
ENTRY(TUSB_ERROR_FAILED )\
diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c
index f3fe6614c..8f8ed9afe 100644
--- a/tinyusb/host/ehci/ehci.c
+++ b/tinyusb/host/ehci/ehci.c
@@ -564,7 +564,7 @@ static void port_connect_status_change_isr(uint8_t hostid)
// NOTE There is an sequence plug->unplug->…..-> plug if device is powering with pre-plugged device
if (regs->portsc_bit.current_connect_status)
{
- usbh_device_plugged_isr(hostid);
+ usbh_device_plugged_isr(hostid, 0, 0);
}else // device unplugged
{
usbh_device_unplugged_isr(hostid);
diff --git a/tinyusb/host/hub.c b/tinyusb/host/hub.c
index fc06db0a3..da457a359 100644
--- a/tinyusb/host/hub.c
+++ b/tinyusb/host/hub.c
@@ -46,17 +46,104 @@
// INCLUDE
//--------------------------------------------------------------------+
#include "hub.h"
+#include "usbh_hcd.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+typedef struct {
+ pipe_handle_t pipe_status;
+ uint8_t interface_number;
+ uint8_t port_number;
+ uint8_t status_change; // data from status change interrupt endpoint
+}usbh_hub_t;
+
+usbh_hub_t hub_data[TUSB_CFG_HOST_DEVICE_MAX] TUSB_CFG_ATTR_USBRAM;
+descriptor_hub_desc_t hub_descriptor TUSB_CFG_ATTR_USBRAM;
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
//--------------------------------------------------------------------+
-// IMPLEMENTATION
+// CLASS-USBH API (don't require to verify parameters)
//--------------------------------------------------------------------+
+void hub_init(void)
+{
+ memclr_(hub_data, TUSB_CFG_HOST_DEVICE_MAX*sizeof(usbh_hub_t));
+}
+
+tusb_error_t hub_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length)
+{
+ tusb_error_t error;
+
+ OSAL_SUBTASK_BEGIN
+
+ // not support multiple TT yet
+ if ( p_interface_desc->bInterfaceProtocol > 1 ) return TUSB_ERROR_HUB_FEATURE_NOT_SUPPORTED;
+
+ //------------- Open Interrupt Status Pipe -------------//
+ tusb_descriptor_endpoint_t const *p_endpoint = (tusb_descriptor_endpoint_t const *) descriptor_next( (uint8_t const*) p_interface_desc );
+ SUBTASK_ASSERT(TUSB_DESC_TYPE_ENDPOINT == p_endpoint->bDescriptorType);
+ SUBTASK_ASSERT(TUSB_XFER_INTERRUPT == p_endpoint->bmAttributes.xfer);
+
+ hub_data[dev_addr-1].pipe_status = hcd_pipe_open(dev_addr, p_endpoint, TUSB_CLASS_HUB);
+ SUBTASK_ASSERT( pipehandle_is_valid(hub_data[dev_addr-1].pipe_status) );
+ hub_data[dev_addr-1].interface_number = p_interface_desc->bInterfaceNumber;
+
+ (*p_length) = sizeof(tusb_descriptor_interface_t) + sizeof(tusb_descriptor_endpoint_t);
+
+ //------------- Get Hub Descriptor -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_DEVICE),
+ HUB_REQUEST_GET_DESCRIPTOR, 0, 0,
+ 9, &hub_descriptor ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS(error);
+
+ hub_data[dev_addr-1].port_number = hub_descriptor.bNbrPorts; // only care about this field in hub descriptor
+
+ //------------- Set Port_Power on all ports -------------//
+ static uint8_t i;
+ for(i=1; i <= hub_data[dev_addr-1].port_number; i++)
+ {
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_SET_FEATURE, HUB_FEATURE_PORT_POWER, i,
+ 0, NULL ),
+ error
+ );
+ }
+
+ //------------- Queue the initial Status endpoint transfer -------------//
+ SUBTASK_ASSERT_STATUS ( hcd_pipe_xfer(hub_data[dev_addr-1].pipe_status, &hub_data[dev_addr-1].status_change, 1, true) );
+
+ OSAL_SUBTASK_END
+}
+
+void hub_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes)
+{
+ usbh_hub_t * p_hub = &hub_data[pipe_hdl.dev_addr-1];
+
+ for (uint8_t port=1; port <= p_hub->port_number; port++)
+ { // TODO HUB ignore bit0 hub_status_change
+ if ( BIT_TEST_(p_hub->status_change, port) )
+ {
+ // TODO HUB connection/disconnection will be determined in enum task --> connect change
+ usbh_device_plugged_isr(usbh_devices[pipe_hdl.dev_addr].core_id, pipe_hdl.dev_addr, port);
+ }
+ }
+
+ // TODO queue next transfer
+}
+
+void hub_close(uint8_t dev_addr)
+{
+ (void) hcd_pipe_close(hub_data[dev_addr-1].pipe_status);
+ memclr_(&hub_data[dev_addr-1], sizeof(usbh_hub_t));
+}
+
+
#endif
diff --git a/tinyusb/host/hub.h b/tinyusb/host/hub.h
index 5163693b3..cc36ef0a6 100644
--- a/tinyusb/host/hub.h
+++ b/tinyusb/host/hub.h
@@ -53,17 +53,138 @@
extern "C" {
#endif
-//#ifdef _TINY_USB_SOURCE_FILE_
+//D1...D0: Logical Power Switching Mode
+//00: Ganged power switching (all ports’power at
+//once)
+//01: Individual port power switching
+//1X: Reserved. Used only on 1.0 compliant hubs
+//that implement no power switching
+//D2: Identifies a Compound Device
+//0: Hub is not part of a compound device.
+//1: Hub is part of a compound device.
+//D4...D3: Over-current Protection Mode
+//00: Global Over-current Protection. The hub
+//reports over-current as a summation of all
+//ports’current draw, without a breakdown of
+//individual port over-current status.
+//01: Individual Port Over-current Protection. The
+//hub reports over-current on a per-port basis.
+//Each port has an over-current status.
+//1X: No Over-current Protection. This option is
+//allowed only for bus-powered hubs that do not
+//implement over-current protection.
+//
+//D6...D5: TT Think TIme
+//00: TT requires at most 8 FS bit times of inter
+//transaction gap on a full-/low-speed
+//downstream bus.
+//01: TT requires at most 16 FS bit times.
+//10: TT requires at most 24 FS bit times.
+//11: TT requires at most 32 FS bit times.
+//D7: Port Indicators Supported
+//0: Port Indicators are not supported on its
+//downstream facing ports and the
+//PORT_INDICATOR request has no effect.
+//1: Port Indicators are supported on its
+//downstream facing ports and the
+//PORT_INDICATOR request controls the
+//indicators. See Section 11.5.3.
+//D15...D8: Reserved
+
+typedef ATTR_PACKED_STRUCT(struct){
+ uint8_t bLength ; ///< Size of descriptor
+ uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
+ uint8_t bNbrPorts;
+ uint16_t wHubCharacteristics;
+ uint8_t bPwrOn2PwrGood;
+ uint8_t bHubContrCurrent;
+ uint8_t DeviceRemovable; // bitmap each bit for a port (from bit1)
+ uint8_t PortPwrCtrlMask; // just for compatibility, should be 0xff
+} descriptor_hub_desc_t;
+
+STATIC_ASSERT( sizeof(descriptor_hub_desc_t) == 9, "size is not correct");
+
+enum {
+ HUB_REQUEST_GET_STATUS = 0 ,
+ HUB_REQUEST_CLEAR_FEATURE = 1 ,
+
+ HUB_REQUEST_SET_FEATURE = 3 ,
+
+ HUB_REQUEST_GET_DESCRIPTOR = 6 ,
+ HUB_REQUEST_SET_DESCRIPTOR = 7 ,
+ HUB_REQUEST_CLEAR_TT_BUFFER = 8 ,
+ HUB_REQUEST_RESET_TT = 9 ,
+ HUB_REQUEST_GET_TT_STATE = 10 ,
+ HUB_REQUEST_STOP_TT = 11
+};
+
+enum {
+ HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0,
+ HUB_FEATURE_HUB_OVER_CURRENT_CHANGE
+};
+
+enum{
+ HUB_FEATURE_PORT_CONNECTION = 0,
+ HUB_FEATURE_PORT_ENABLE = 1,
+ HUB_FEATURE_PORT_SUSPEND = 2,
+ HUB_FEATURE_PORT_OVER_CURRENT = 3,
+ HUB_FEATURE_PORT_RESET = 4,
+
+ HUB_FEATURE_PORT_POWER = 8,
+ HUB_FEATURE_PORT_LOW_SPEED = 9,
+
+ HUB_FEATURE_PORT_CONNECTION_CHANGE = 16,
+ HUB_FEATURE_PORT_ENABLE_CHANGE = 17,
+ HUB_FEATURE_PORT_SUSPEND_CHANGE = 18,
+ HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19,
+ HUB_FEATURE_PORT_RESET_CHANGE = 20,
+ HUB_FEATURE_PORT_TEST = 21,
+ HUB_FEATURE_PORT_INDICATOR = 22
+};
+
+// data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub)
+typedef struct {
+ ATTR_PACKED_STRUCT(struct) {
+ uint16_t local_power_source : 1;
+ uint16_t over_current : 1;
+ uint16_t : 14;
+ }status, status_change;
+} hub_status_response_t;
+
+STATIC_ASSERT( sizeof(hub_status_response_t) == 4, "size is not correct");
+
+// data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num
+typedef struct {
+ ATTR_PACKED_STRUCT(struct) {
+ uint16_t connect_status : 1;
+ uint16_t port_enable : 1;
+ uint16_t suspend : 1;
+ uint16_t over_current : 1;
+ uint16_t reset : 1;
+
+ uint16_t : 3;
+ uint16_t port_power : 1;
+ uint16_t low_speed_device_attached : 1;
+ uint16_t high_speed_device_attached : 1;
+ uint16_t port_test_mode : 1;
+ uint16_t port_indicator_control : 1;
+ uint16_t : 0;
+ }status_current, status_change;
+} hub_port_status_response_t;
+
+STATIC_ASSERT( sizeof(hub_port_status_response_t) == 4, "size is not correct");
//--------------------------------------------------------------------+
// USBH-CLASS DRIVER API
//--------------------------------------------------------------------+
+#ifdef _TINY_USB_SOURCE_FILE_
+
void hub_init(void);
tusb_error_t hub_open_subtask(uint8_t dev_addr, tusb_descriptor_interface_t const *p_interface_desc, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT;
-void hub_isr(pipe_handle_t pipe_hdl, tusb_event_t event);
+void hub_isr(pipe_handle_t pipe_hdl, tusb_event_t event, uint32_t xferred_bytes);
void hub_close(uint8_t dev_addr);
-//#endif
+#endif
#ifdef __cplusplus
}
diff --git a/tinyusb/host/usbh.c b/tinyusb/host/usbh.c
index 65efe8768..6115939b7 100644
--- a/tinyusb/host/usbh.c
+++ b/tinyusb/host/usbh.c
@@ -46,6 +46,7 @@
// INCLUDE
//--------------------------------------------------------------------+
#include "tusb.h"
+#include "hub.h"
#include "usbh_hcd.h"
//--------------------------------------------------------------------+
@@ -80,7 +81,7 @@ static host_class_driver_t const usbh_class_drivers[TUSB_CLASS_MAPPED_INDEX_END]
.open_subtask = msch_open_subtask,
.isr = msch_isr,
.close = msch_close
- }
+ },
#endif
#if TUSB_CFG_HOST_HUB
@@ -89,7 +90,7 @@ static host_class_driver_t const usbh_class_drivers[TUSB_CLASS_MAPPED_INDEX_END]
.open_subtask = hub_open_subtask,
.isr = hub_isr,
.close = hub_close
- }
+ },
#endif
#if TUSB_CFG_HOST_CUSTOM_CLASS
@@ -112,7 +113,7 @@ OSAL_TASK_DEF(usbh_enumeration_task, 150, TUSB_CFG_OS_TASK_PRIO);
OSAL_QUEUE_DEF(enum_queue_def, ENUM_QUEUE_DEPTH, uint32_t);
static osal_queue_handle_t enum_queue_hdl;
-STATIC_VAR uint8_t enum_data_buffer[TUSB_CFG_HOST_ENUM_BUFFER_SIZE] TUSB_CFG_ATTR_USBRAM;
+ATTR_ALIGNED(4) STATIC_VAR uint8_t enum_data_buffer[TUSB_CFG_HOST_ENUM_BUFFER_SIZE] TUSB_CFG_ATTR_USBRAM;
//------------- Reporter Task Data -------------//
@@ -272,12 +273,13 @@ void usbh_xfer_isr(pipe_handle_t pipe_hdl, uint8_t class_code, tusb_event_t even
}
}
-void usbh_device_plugged_isr(uint8_t hostid)
+void usbh_device_plugged_isr(uint8_t hostid, uint8_t hub_addr, uint8_t hub_port)
{
osal_queue_send(enum_queue_hdl,
- &(usbh_enumerate_t){ .core_id = hostid} );
+ &(usbh_enumerate_t){ .core_id = hostid, .hub_addr = hub_addr, .hub_port = hub_port} );
}
+
void usbh_device_unplugged_isr(uint8_t hostid)
{
//------------- find the device address that is unplugged -------------//
@@ -346,17 +348,100 @@ tusb_error_t enumeration_body_subtask(void)
osal_queue_receive(enum_queue_hdl, &enum_entry, OSAL_TIMEOUT_WAIT_FOREVER, &error);
- SUBTASK_ASSERT( hcd_port_connect_status(enum_entry.core_id) ); // ensure device is still plugged
-
usbh_devices[0].core_id = enum_entry.core_id; // TODO refractor integrate to device_pool
usbh_devices[0].hub_addr = enum_entry.hub_addr;
usbh_devices[0].hub_port = enum_entry.hub_port;
- osal_task_delay(200); // wait for device is stable
+ if ( usbh_devices[0].hub_addr != 0) // connected/disconnected via hub
+ {
+ hub_port_status_response_t * p_port_status;
- hcd_port_reset( usbh_devices[0].core_id ); // port must be reset to have correct speed operation
-// osal_task_delay(50); // TODO reset is recommended to last 50 ms (NXP EHCI passes this)
- usbh_devices[0].speed = hcd_port_speed_get( usbh_devices[0].core_id );
+ //------------- Get Port Status -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port,
+ 4, enum_data_buffer ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ p_port_status = (hub_port_status_response_t *) enum_data_buffer;
+ if ( !p_port_status->status_change.connect_status ) SUBTASK_EXIT(TUSB_ERROR_NONE); // only handle connection change
+
+ if ( !p_port_status->status_current.connect_status )
+ { // TODO HUB Disconnection
+
+ SUBTASK_EXIT(TUSB_ERROR_NONE);
+ }
+
+ // Hub connection
+ //------------- Clear Hub Port Connect Status Change -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_CLEAR_FEATURE, HUB_FEATURE_PORT_CONNECTION_CHANGE, usbh_devices[0].hub_port,
+ 0, NULL ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ //------------- Get Port Status again to make sure Connect Change is cleared -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port,
+ 4, enum_data_buffer ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ p_port_status = (hub_port_status_response_t *) enum_data_buffer;
+ SUBTASK_ASSERT( !p_port_status->status_change.connect_status); // this has to be cleared
+
+ //--------------------------------------------------------------------+
+ // PORT RESET & WAIT FOR STATUS ENDPOINT & GET STATUS & CLEAR RESET CHANGE
+ //--------------------------------------------------------------------+
+ //------------- Set Port Reset -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_SET_FEATURE, HUB_FEATURE_PORT_RESET, usbh_devices[0].hub_port,
+ 0, NULL ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ osal_task_delay(200); // TODO Hub wait for Status Endpoint on Reset Change
+
+ //------------- Get Port Status to check if port is enabled, powered and reset_change -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port,
+ 4, enum_data_buffer ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ p_port_status = (hub_port_status_response_t *) enum_data_buffer;
+ SUBTASK_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status &&
+ p_port_status->status_current.port_power && p_port_status->status_current.port_enable);
+
+ usbh_devices[0].speed = (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH :
+ (p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL;
+
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_CLEAR_FEATURE, HUB_FEATURE_PORT_RESET_CHANGE, usbh_devices[0].hub_port,
+ 0, NULL ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+ }
+ else
+ {
+ SUBTASK_ASSERT( hcd_port_connect_status(usbh_devices[0].core_id) ); // ensure device is still plugged
+ osal_task_delay(200); // wait for device is stable
+ hcd_port_reset( usbh_devices[0].core_id ); // port must be reset to have correct speed operation
+ // osal_task_delay(50); // TODO reset is recommended to last 50 ms (NXP EHCI passes this)
+ usbh_devices[0].speed = hcd_port_speed_get( usbh_devices[0].core_id );
+ }
SUBTASK_ASSERT_STATUS( usbh_pipe_control_open(0, 8) );
usbh_devices[0].state = TUSB_DEVICE_STATE_ADDRESSED;
@@ -370,8 +455,49 @@ tusb_error_t enumeration_body_subtask(void)
);
SUBTASK_ASSERT_STATUS(error); // TODO some slow device is observed to fail the very fist controller xfer, can try more times
- hcd_port_reset( usbh_devices[0].core_id ); // reset port after 8 byte descriptor
+ if (usbh_devices[0].hub_addr == 0)
+ { // mount direct to root hub
+ hcd_port_reset( usbh_devices[0].core_id ); // reset port after 8 byte descriptor
// osal_task_delay(50); // TODO reset is recommended to last 50 ms (NXP EHCI passes this)
+ }else
+ {
+ hub_port_status_response_t * p_port_status;
+
+ //--------------------------------------------------------------------+
+ // PORT RESET & WAIT FOR STATUS ENDPOINT & GET STATUS & CLEAR RESET CHANGE
+ //--------------------------------------------------------------------+
+ //------------- Set Port Reset -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_SET_FEATURE, HUB_FEATURE_PORT_RESET, usbh_devices[0].hub_port,
+ 0, NULL ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ osal_task_delay(200); // TODO Hub wait for Status Endpoint on Reset Change
+
+ //------------- Get Port Status to check if port is enabled, powered and reset_change -------------//
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port,
+ 4, enum_data_buffer ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+
+ p_port_status = (hub_port_status_response_t *) enum_data_buffer;
+ SUBTASK_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status &&
+ p_port_status->status_current.port_power && p_port_status->status_current.port_enable);
+
+ OSAL_SUBTASK_INVOKED_AND_WAIT(
+ usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER),
+ HUB_REQUEST_CLEAR_FEATURE, HUB_FEATURE_PORT_RESET_CHANGE, usbh_devices[0].hub_port,
+ 0, NULL ),
+ error
+ );
+ SUBTASK_ASSERT_STATUS( error );
+ }
//------------- Set new address -------------//
new_addr = get_new_address();
diff --git a/tinyusb/host/usbh_hcd.h b/tinyusb/host/usbh_hcd.h
index 7d5b03a72..ebc1d9628 100644
--- a/tinyusb/host/usbh_hcd.h
+++ b/tinyusb/host/usbh_hcd.h
@@ -115,7 +115,7 @@ extern usbh_device_info_t usbh_devices[TUSB_CFG_HOST_DEVICE_MAX+1]; // including
// callback from HCD ISR
//--------------------------------------------------------------------+
void usbh_xfer_isr(pipe_handle_t pipe_hdl, uint8_t class_code, tusb_event_t event, uint32_t xferred_bytes);
-void usbh_device_plugged_isr(uint8_t hostid);
+void usbh_device_plugged_isr(uint8_t hostid, uint8_t hub_addr, uint8_t hub_port);
void usbh_device_unplugged_isr(uint8_t hostid);
#ifdef __cplusplus