From 3cc169f2fd3159ecad494eb6223bbed6cc8135d6 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 30 Sep 2013 15:16:23 +0700 Subject: [PATCH] able to mount one device on the hub --- .../boards/embedded_artists/board_ea4357.h | 4 +- demos/host/host_os_none/host_os_none.uvopt | 104 ++++++------ demos/host/src/msc_app.c | 23 ++- demos/host/src/tusb_config.h | 4 +- readme.md | 4 +- tinyusb/class/msc_host.c | 12 +- tinyusb/common/errors.h | 1 + tinyusb/host/ehci/ehci.c | 2 +- tinyusb/host/hub.c | 89 ++++++++++- tinyusb/host/hub.h | 127 ++++++++++++++- tinyusb/host/usbh.c | 150 ++++++++++++++++-- tinyusb/host/usbh_hcd.h | 2 +- vendor/fatfs/diskio.c | 7 +- vendor/fatfs/diskio.h | 2 +- 14 files changed, 439 insertions(+), 92 deletions(-) diff --git a/demos/bsp/boards/embedded_artists/board_ea4357.h b/demos/bsp/boards/embedded_artists/board_ea4357.h index 5858b0496..cb9a7136a 100644 --- a/demos/bsp/boards/embedded_artists/board_ea4357.h +++ b/demos/bsp/boards/embedded_artists/board_ea4357.h @@ -67,8 +67,8 @@ #include "oem_base_board/pca9532.h" // LEDs -//#define CFG_PRINTF_TARGET PRINTF_TARGET_SWO -#define CFG_PRINTF_TARGET PRINTF_TARGET_UART // FIXME keil's cmsis rtx does not work with UART (work with SWO) +#define CFG_PRINTF_TARGET PRINTF_TARGET_SWO +//#define CFG_PRINTF_TARGET PRINTF_TARGET_UART // FIXME keil's cmsis rtx does not work with UART (work with SWO) /*========================================================================= HARDWARE MAC ADDRESS diff --git a/demos/host/host_os_none/host_os_none.uvopt b/demos/host/host_os_none/host_os_none.uvopt index f7043fdc4..6a9661362 100644 --- a/demos/host/host_os_none/host_os_none.uvopt +++ b/demos/host/host_os_none/host_os_none.uvopt @@ -135,7 +135,7 @@ 0 DLGUARM - (106=-1,-1,-1,-1,0)(107=-1,-1,-1,-1,0) + 0 @@ -168,27 +168,27 @@ 1 1 - msch_data + ehci_data 2 1 - mouse_data + ehci_data.device[1] 3 1 - keyboard_data + ehci_data.device[0] 4 1 - ehci_data + hub_data 5 1 - msch_semaphore + disk_state @@ -424,10 +424,10 @@ 1 0 0 - 0 + 25 0 - 147 - 159 + 151 + 160 0 ..\src\main.c main.c @@ -442,8 +442,8 @@ 0 0 0 - 59 - 75 + 126 + 149 0 ..\src\cdc_serial_app.c cdc_serial_app.c @@ -458,7 +458,7 @@ 0 0 0 - 112 + 127 135 0 ..\src\keyboard_app.c @@ -474,8 +474,8 @@ 0 44 0 - 118 - 127 + 0 + 0 0 ..\src\mouse_app.c mouse_app.c @@ -490,8 +490,8 @@ 0 1 0 - 47 - 65 + 53 + 86 0 ..\src\rndis_app.c rndis_app.c @@ -520,10 +520,10 @@ 1 0 0 - 18 + 33 0 - 8 - 11 + 73 + 77 0 ..\src\cli.c cli.c @@ -562,8 +562,8 @@ 0 78 0 - 27 - 31 + 0 + 0 0 ..\..\bsp\boards\embedded_artists\board_ea4357.c board_ea4357.c @@ -578,7 +578,7 @@ 0 44 0 - 64 + 82 106 0 ..\..\bsp\boards\printf_retarget.c @@ -714,8 +714,8 @@ 0 64 0 - 23 - 33 + 0 + 0 0 ..\..\..\tinyusb\tusb.c tusb.c @@ -760,10 +760,10 @@ 1 0 0 - 0 + 1 0 - 0 - 0 + 114 + 123 0 ..\..\..\tinyusb\host\hub.c hub.c @@ -776,10 +776,10 @@ 1 0 0 - 61 + 0 0 - 430 - 518 + 337 + 338 0 ..\..\..\tinyusb\host\usbh.c usbh.c @@ -794,8 +794,8 @@ 0 0 0 - 2 - 5 + 411 + 419 0 ..\..\..\tinyusb\host\ehci\ehci.c ehci.c @@ -938,8 +938,8 @@ 0 0 0 - 1 - 12 + 0 + 0 0 ..\..\..\tinyusb\class\hid_host.c hid_host.c @@ -952,10 +952,10 @@ 1 0 0 - 79 + 0 0 - 1 - 14 + 240 + 249 0 ..\..\..\tinyusb\class\msc_host.c msc_host.c @@ -978,8 +978,8 @@ 0 0 0 - 552 - 553 + 0 + 0 0 ..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_uart.c lpc43xx_uart.c @@ -1024,10 +1024,10 @@ 1 0 0 - 64 + 3 0 - 553 - 579 + 572 + 580 0 ..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_cgu.c lpc43xx_cgu.c @@ -1058,8 +1058,8 @@ 0 7 0 - 777 - 782 + 0 + 0 0 ..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_i2c.c lpc43xx_i2c.c @@ -1080,10 +1080,10 @@ 2 0 0 - 0 + 26 0 - 139 - 151 + 145 + 154 0 ..\..\bsp\lpc43xx\startup_keil\startup_LPC43xx.s startup_LPC43xx.s @@ -1104,10 +1104,10 @@ 1 0 0 - 20 + 51 0 - 50 - 62 + 111 + 108 0 ..\..\..\vendor\fatfs\diskio.c diskio.c @@ -1122,8 +1122,8 @@ 0 0 0 - 1 - 1 + 0 + 0 0 ..\..\..\vendor\fatfs\ff.c ff.c diff --git a/demos/host/src/msc_app.c b/demos/host/src/msc_app.c index 5c3881826..e5101cafa 100644 --- a/demos/host/src/msc_app.c +++ b/demos/host/src/msc_app.c @@ -85,11 +85,12 @@ void tusbh_msc_mounted_cb(uint8_t dev_addr) //------------- file system (only 1 LUN support) -------------// // DSTATUS stat = disk_initialize(0); - disk_state = 0; + uint8_t phy_disk = dev_addr-1; + disk_state[phy_disk] = 0; - if ( disk_is_ready(0) ) + if ( disk_is_ready(phy_disk) ) { - if ( f_mount(0, &fatfs[dev_addr-1]) != FR_OK ) // TODO multiple volume + if ( f_mount(phy_disk, &fatfs[phy_disk]) != FR_OK ) // TODO multiple volume { puts("mount failed"); return; @@ -102,7 +103,7 @@ void tusbh_msc_mounted_cb(uint8_t dev_addr) puts("- THE AUTHOR HAS NO RESPONSIBILITY WITH YOUR DEVICE NOR ITS DATA -"); puts("---------------------------------------------------------------------"); - f_chdrive(dev_addr-1); // change to newly mounted drive + f_chdrive(phy_disk); // change to newly mounted drive f_chdir("/"); // root as current dir cli_init(); @@ -112,7 +113,7 @@ void tusbh_msc_mounted_cb(uint8_t dev_addr) void tusbh_msc_unmounted_isr(uint8_t dev_addr) { // unmount disk - disk_state = STA_NOINIT; + disk_state[dev_addr-1] = STA_NOINIT; puts("--"); } @@ -136,7 +137,17 @@ OSAL_TASK_FUNCTION( msc_app_task ) (void* p_task_para) osal_task_delay(10); - if ( disk_is_ready(0) ) + bool is_any_disk_mounted = false; + for(uint8_t phy_disk=0; phy_disk < TUSB_CFG_HOST_DEVICE_MAX; phy_disk++) + { + if ( disk_is_ready(phy_disk) ) + { + is_any_disk_mounted = true; + break; + } + } + + if ( is_any_disk_mounted ) { int ch = getchar(); if ( ch > 0 ) diff --git a/demos/host/src/tusb_config.h b/demos/host/src/tusb_config.h index 711802fab..3b69dffad 100644 --- a/demos/host/src/tusb_config.h +++ b/demos/host/src/tusb_config.h @@ -65,14 +65,14 @@ //--------------------------------------------------------------------+ // HOST CONFIGURATION //--------------------------------------------------------------------+ -#define TUSB_CFG_HOST_DEVICE_MAX 1 +#define TUSB_CFG_HOST_DEVICE_MAX 3 #define TUSB_CFG_CONFIGURATION_MAX 1 //------------- USBD -------------// #define TUSB_CFG_HOST_ENUM_BUFFER_SIZE 255 //------------- CLASS -------------// -#define TUSB_CFG_HOST_HUB 0 +#define TUSB_CFG_HOST_HUB 1 #define TUSB_CFG_HOST_HID_KEYBOARD 1 #define TUSB_CFG_HOST_HID_MOUSE 1 #define TUSB_CFG_HOST_HID_GENERIC 0 diff --git a/readme.md b/readme.md index 2eaa0b360..3b6a86bd9 100644 --- a/readme.md +++ b/readme.md @@ -15,13 +15,13 @@ designed to be simple and run out-of-the-box provided the configuration is corre - HID Mouse - HID Keyboard - Communication Class (CDC) -- Mass-Storage (MSC) coming soon... +- Mass-Storage (MSC) - Hub coming soon... - Multiple host controllers ### Device ### -coming soon ... +coming not so soon ... ### RTOS ### 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 diff --git a/vendor/fatfs/diskio.c b/vendor/fatfs/diskio.c index a3c1d8fee..55a1e5f24 100644 --- a/vendor/fatfs/diskio.c +++ b/vendor/fatfs/diskio.c @@ -47,7 +47,8 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ - volatile DSTATUS disk_state = STA_NOINIT; +// TODO change it to portable init +volatile DSTATUS disk_state[TUSB_CFG_HOST_DEVICE_MAX] = { [0 ... TUSB_CFG_HOST_DEVICE_MAX-1] = STA_NOINIT }; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION @@ -73,12 +74,12 @@ static DRESULT wait_for_io_complete(uint8_t usb_addr) //pdrv Specifies the physical drive number. DSTATUS disk_initialize ( BYTE pdrv ) { - return disk_state; + return disk_state[pdrv]; } DSTATUS disk_status (BYTE pdrv) { - return disk_state; + return disk_state[pdrv]; } //pdrv diff --git a/vendor/fatfs/diskio.h b/vendor/fatfs/diskio.h index 9b1f9a28f..bd3688580 100644 --- a/vendor/fatfs/diskio.h +++ b/vendor/fatfs/diskio.h @@ -18,7 +18,7 @@ extern "C" { /* Status of Disk Functions */ typedef BYTE DSTATUS; -extern volatile DSTATUS disk_state; +extern volatile DSTATUS disk_state[TUSB_CFG_HOST_DEVICE_MAX]; /* Results of Disk Functions */ typedef enum {