Add tuh_rhport_is_active() and tuh_rhport_reset_bus()

- also improve ehci bus reset
- seperate bus reset delay and contact debouncing delay in enumeration
This commit is contained in:
hathach 2023-08-07 18:22:28 +07:00
parent 1b92108bc3
commit 1f95a417f2
No known key found for this signature in database
GPG Key ID: F5D50C6D51D17CBA
6 changed files with 128 additions and 103 deletions

View File

@ -149,10 +149,11 @@ uint32_t hcd_frame_number(uint8_t rhport);
// Get the current connect status of roothub port // Get the current connect status of roothub port
bool hcd_port_connect_status(uint8_t rhport); bool hcd_port_connect_status(uint8_t rhport);
// Reset USB bus on the port // Reset USB bus on the port. Return immediately, bus reset sequence may not be complete.
// Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence.
void hcd_port_reset(uint8_t rhport); void hcd_port_reset(uint8_t rhport);
// TODO implement later // Complete bus reset sequence, may be required by some controllers
void hcd_port_reset_end(uint8_t rhport); void hcd_port_reset_end(uint8_t rhport);
// Get port link speed // Get port link speed

View File

@ -330,7 +330,7 @@ static void connection_port_reset_complete (tuh_xfer_t* xfer);
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
(void) ep_addr; (void) ep_addr;
TU_ASSERT(result == XFER_RESULT_SUCCESS); TU_VERIFY(result == XFER_RESULT_SUCCESS);
hub_interface_t* p_hub = get_itf(dev_addr); hub_interface_t* p_hub = get_itf(dev_addr);

View File

@ -181,9 +181,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
}; };
enum { USBH_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; enum { USBH_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
enum { RESET_DELAY = 500 }; // 200 USB specs say only 50ms but many devices require much longer
enum { CONFIG_NUM = 1 }; // default to use configuration 1 enum { CONFIG_NUM = 1 }; // default to use configuration 1
@ -251,40 +248,27 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
#if CFG_TUSB_OS == OPT_OS_NONE #if CFG_TUSB_OS == OPT_OS_NONE
// TODO rework time-related function later // TODO rework time-related function later
TU_ATTR_WEAK void osal_task_delay(uint32_t msec) // weak and overridable
{ TU_ATTR_WEAK void osal_task_delay(uint32_t msec) {
const uint32_t start = hcd_frame_number(_usbh_controller); const uint32_t start = hcd_frame_number(_usbh_controller);
while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {} while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {}
} }
#endif #endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// PUBLIC API (Parameter Verification is required) // Device API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) bool tuh_mounted(uint8_t dev_addr) {
{ usbh_device_t *dev = get_device(dev_addr);
if (hcd_configure)
{
return hcd_configure(rhport, cfg_id, cfg_param);
}else
{
return false;
}
}
bool tuh_mounted(uint8_t dev_addr)
{
usbh_device_t* dev = get_device(dev_addr);
TU_VERIFY(dev); TU_VERIFY(dev);
return dev->configured; return dev->configured;
} }
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid) bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) {
{
*vid = *pid = 0; *vid = *pid = 0;
usbh_device_t const* dev = get_device(dev_addr); usbh_device_t const *dev = get_device(dev_addr);
TU_VERIFY(dev && dev->addressed && dev->vid != 0); TU_VERIFY(dev && dev->addressed && dev->vid != 0);
*vid = dev->vid; *vid = dev->vid;
@ -293,26 +277,48 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
return true; return true;
} }
tusb_speed_t tuh_speed_get (uint8_t dev_addr) tusb_speed_t tuh_speed_get(uint8_t dev_addr) {
{ usbh_device_t *dev = get_device(dev_addr);
usbh_device_t* dev = get_device(dev_addr);
return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed); return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed);
} }
static void clear_device(usbh_device_t* dev) bool tuh_rhport_is_active(uint8_t rhport) {
{ return _usbh_controller == rhport;
}
bool tuh_rhport_reset_bus(uint8_t rhport, bool active) {
TU_VERIFY(tuh_rhport_is_active(rhport));
if ( active ) {
hcd_port_reset(rhport);
} else {
hcd_port_reset_end(rhport);
}
return true;
}
//--------------------------------------------------------------------+
// PUBLIC API (Parameter Verification is required)
//--------------------------------------------------------------------+
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
if ( hcd_configure ) {
return hcd_configure(rhport, cfg_id, cfg_param);
} else {
return false;
}
}
static void clear_device(usbh_device_t* dev) {
tu_memclr(dev, sizeof(usbh_device_t)); tu_memclr(dev, sizeof(usbh_device_t));
memset(dev->itf2drv, TUSB_INDEX_INVALID_8, sizeof(dev->itf2drv)); // invalid mapping memset(dev->itf2drv, TUSB_INDEX_INVALID_8, sizeof(dev->itf2drv)); // invalid mapping
memset(dev->ep2drv , TUSB_INDEX_INVALID_8, sizeof(dev->ep2drv )); // invalid mapping memset(dev->ep2drv , TUSB_INDEX_INVALID_8, sizeof(dev->ep2drv )); // invalid mapping
} }
bool tuh_inited(void) bool tuh_inited(void) {
{
return _usbh_controller != TUSB_INDEX_INVALID_8; return _usbh_controller != TUSB_INDEX_INVALID_8;
} }
bool tuh_init(uint8_t controller_id) bool tuh_init(uint8_t controller_id) {
{
// skip if already initialized // skip if already initialized
if ( tuh_inited() ) return true; if ( tuh_inited() ) return true;
@ -359,8 +365,7 @@ bool tuh_init(uint8_t controller_id)
return true; return true;
} }
bool tuh_task_event_ready(void) bool tuh_task_event_ready(void) {
{
// Skip if stack is not initialized // Skip if stack is not initialized
if ( !tuh_inited() ) return false; if ( !tuh_inited() ) return false;
@ -385,8 +390,7 @@ bool tuh_task_event_ready(void)
} }
@endcode @endcode
*/ */
void tuh_task_ext(uint32_t timeout_ms, bool in_isr) void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
{
(void) in_isr; // not implemented yet (void) in_isr; // not implemented yet
// Skip if stack is not initialized // Skip if stack is not initialized
@ -403,8 +407,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
case HCD_EVENT_DEVICE_ATTACH: case HCD_EVENT_DEVICE_ATTACH:
// 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. // one device before enumerating another one.
if ( _dev0.enumerating ) if ( _dev0.enumerating ) {
{
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport); TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
bool is_empty = osal_queue_empty(_usbh_q); bool is_empty = osal_queue_empty(_usbh_q);
@ -414,8 +417,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
// Exit if this is the only event in the queue, otherwise we may loop forever // Exit if this is the only event in the queue, otherwise we may loop forever
return; return;
} }
}else }else {
{
TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport); TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
_dev0.enumerating = 1; _dev0.enumerating = 1;
enum_new_device(&event); enum_new_device(&event);
@ -428,8 +430,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
#if CFG_TUH_HUB #if CFG_TUH_HUB
// TODO remove // TODO remove
if ( event.connection.hub_addr != 0) if ( event.connection.hub_addr != 0) {
{
// done with hub, waiting for next data on status pipe // done with hub, waiting for next data on status pipe
(void) hub_edpt_status_xfer( event.connection.hub_addr ); (void) hub_edpt_status_xfer( event.connection.hub_addr );
} }
@ -1230,6 +1231,12 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
// one device before enumerating another one. // one device before enumerating another one.
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
enum {
ENUM_RESET_DELAY = 50, // USB specs: 10 to 50ms
ENUM_CONTACT_DEBOUNCING_DELAY = 450, // when plug/unplug a device, physical connection can be bouncing and may
// generate a series of attach/detach event. This delay wait for stable connection
};
enum { enum {
ENUM_IDLE, ENUM_IDLE,
ENUM_RESET_1, // 1st reset when attached ENUM_RESET_1, // 1st reset when attached
@ -1311,7 +1318,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
break; break;
case ENUM_HUB_GET_STATUS_2: case ENUM_HUB_GET_STATUS_2:
osal_task_delay(RESET_DELAY); osal_task_delay(ENUM_RESET_DELAY);
TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_2), ); TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_2), );
break; break;
@ -1468,12 +1475,14 @@ static bool enum_new_device(hcd_event_t* event)
if (_dev0.hub_addr == 0) if (_dev0.hub_addr == 0)
{ {
// connected/disconnected directly with roothub // connected/disconnected directly with roothub
// wait until device is stable TODO non blocking
hcd_port_reset(_dev0.rhport); hcd_port_reset(_dev0.rhport);
osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since osal_task_delay(ENUM_RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
// sof of controller may not running while resetting // sof of controller may not running while resetting
hcd_port_reset_end( _dev0.rhport); hcd_port_reset_end( _dev0.rhport);
// wait until device connection is stable TODO non blocking
osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);
// device unplugged while delaying // device unplugged while delaying
if ( !hcd_port_connect_status(_dev0.rhport) ) { if ( !hcd_port_connect_status(_dev0.rhport) ) {
enum_full_complete(); enum_full_complete();
@ -1489,6 +1498,7 @@ static bool enum_new_device(hcd_event_t* event)
xfer.result = XFER_RESULT_SUCCESS; xfer.result = XFER_RESULT_SUCCESS;
xfer.user_data = ENUM_ADDR0_DEVICE_DESC; xfer.user_data = ENUM_ADDR0_DEVICE_DESC;
process_enumeration(&xfer); process_enumeration(&xfer);
} }
@ -1496,8 +1506,8 @@ static bool enum_new_device(hcd_event_t* event)
else else
{ {
// connected/disconnected via external hub // connected/disconnected via external hub
// wait until device is stable // wait until device connection is stable TODO non blocking
osal_task_delay(RESET_DELAY); osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);
// ENUM_HUB_GET_STATUS // ENUM_HUB_GET_STATUS
//TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete, 0) ); //TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete, 0) );
@ -1508,23 +1518,19 @@ static bool enum_new_device(hcd_event_t* event)
return true; return true;
} }
static uint8_t get_new_address(bool is_hub) static uint8_t get_new_address(bool is_hub) {
{
uint8_t start; uint8_t start;
uint8_t end; uint8_t end;
if ( is_hub ) if ( is_hub ) {
{
start = CFG_TUH_DEVICE_MAX; start = CFG_TUH_DEVICE_MAX;
end = start + CFG_TUH_HUB; end = start + CFG_TUH_HUB;
}else }else {
{
start = 0; start = 0;
end = start + CFG_TUH_DEVICE_MAX; end = start + CFG_TUH_DEVICE_MAX;
} }
for (uint8_t idx = start; idx < end; idx++) for (uint8_t idx = start; idx < end; idx++) {
{
if (!_usbh_devices[idx].connected) return (idx+1); if (!_usbh_devices[idx].connected) return (idx+1);
} }

View File

@ -47,8 +47,7 @@ typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
// it is advised to initialize it using member name // it is advised to initialize it using member name
// Note2: not all field is available/meaningful in callback, // Note2: not all field is available/meaningful in callback,
// some info is not saved by usbh to save SRAM // some info is not saved by usbh to save SRAM
struct tuh_xfer_s struct tuh_xfer_s {
{
uint8_t daddr; uint8_t daddr;
uint8_t ep_addr; uint8_t ep_addr;
uint8_t TU_RESERVED; // reserved uint8_t TU_RESERVED; // reserved
@ -56,8 +55,7 @@ struct tuh_xfer_s
uint32_t actual_len; // excluding setup packet uint32_t actual_len; // excluding setup packet
union union {
{
tusb_control_request_t const* setup; // setup packet pointer if control transfer tusb_control_request_t const* setup; // setup packet pointer if control transfer
uint32_t buflen; // expected length if not control transfer (not available in callback) uint32_t buflen; // expected length if not control transfer (not available in callback)
}; };
@ -70,15 +68,13 @@ struct tuh_xfer_s
}; };
// Subject to change // Subject to change
typedef struct typedef struct {
{
uint8_t daddr; uint8_t daddr;
tusb_desc_interface_t desc; tusb_desc_interface_t desc;
} tuh_itf_info_t; } tuh_itf_info_t;
// ConfigID for tuh_config() // ConfigID for tuh_config()
enum enum {
{
TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 << 8 // cfg_param: pio_usb_configuration_t TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 << 8 // cfg_param: pio_usb_configuration_t
}; };
@ -105,12 +101,12 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
// Should be called before tuh_init() // Should be called before tuh_init()
// - cfg_id : configure ID (TBD) // - cfg_id : configure ID (TBD)
// - cfg_param: configure data, structure depends on the ID // - cfg_param: configure data, structure depends on the ID
bool tuh_configure(uint8_t controller_id, uint32_t cfg_id, const void* cfg_param); bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
// Init host stack // Init host stack
bool tuh_init(uint8_t controller_id); bool tuh_init(uint8_t rhport);
// Check if host stack is already initialized // Check if host stack is already initialized with any roothub ports
bool tuh_inited(void); bool tuh_inited(void);
// Task function should be called in main/rtos loop, extended version of tuh_task() // Task function should be called in main/rtos loop, extended version of tuh_task()
@ -120,8 +116,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr);
// Task function should be called in main/rtos loop // Task function should be called in main/rtos loop
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
void tuh_task(void) void tuh_task(void) {
{
tuh_task_ext(UINT32_MAX, false); tuh_task_ext(UINT32_MAX, false);
} }
@ -135,8 +130,20 @@ extern void hcd_int_handler(uint8_t rhport);
// Interrupt handler, name alias to HCD // Interrupt handler, name alias to HCD
#define tuh_int_handler hcd_int_handler #define tuh_int_handler hcd_int_handler
// Check if roothub port is initialized and active as a host
bool tuh_rhport_is_active(uint8_t rhport);
// Assert/de-assert Bus Reset signal to roothub port. USB specs: it should last 10-50ms
bool tuh_rhport_reset_bus(uint8_t rhport, bool active);
//--------------------------------------------------------------------+
// Device API
//--------------------------------------------------------------------+
// Get VID/PID of device
bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid); bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
// Get speed of device
tusb_speed_t tuh_speed_get(uint8_t daddr); tusb_speed_t tuh_speed_get(uint8_t daddr);
// Check if device is connected and configured // Check if device is connected and configured
@ -144,8 +151,7 @@ bool tuh_mounted(uint8_t daddr);
// Check if device is suspended // Check if device is suspended
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
bool tuh_suspended(uint8_t daddr) bool tuh_suspended(uint8_t daddr) {
{
// TODO implement suspend & resume on host // TODO implement suspend & resume on host
(void) daddr; (void) daddr;
return false; return false;
@ -153,8 +159,7 @@ bool tuh_suspended(uint8_t daddr)
// Check if device is ready to communicate with // Check if device is ready to communicate with
TU_ATTR_ALWAYS_INLINE static inline TU_ATTR_ALWAYS_INLINE static inline
bool tuh_ready(uint8_t daddr) bool tuh_ready(uint8_t daddr) {
{
return tuh_mounted(daddr) && !tuh_suspended(daddr); return tuh_mounted(daddr) && !tuh_suspended(daddr);
} }

View File

@ -39,24 +39,27 @@
#include "ci_hs_type.h" #include "ci_hs_type.h"
#if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX #if CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
#include "ci_hs_imxrt.h"
bool hcd_dcache_clean(void const* addr, uint32_t data_size) { #include "ci_hs_imxrt.h"
return imxrt_dcache_clean(addr, data_size);
}
bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) { bool hcd_dcache_clean(void const* addr, uint32_t data_size) {
return imxrt_dcache_invalidate(addr, data_size); return imxrt_dcache_clean(addr, data_size);
} }
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) { bool hcd_dcache_invalidate(void const* addr, uint32_t data_size) {
return imxrt_dcache_clean_invalidate(addr, data_size); return imxrt_dcache_invalidate(addr, data_size);
} }
bool hcd_dcache_clean_invalidate(void const* addr, uint32_t data_size) {
return imxrt_dcache_clean_invalidate(addr, data_size);
}
#elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX) #elif TU_CHECK_MCU(OPT_MCU_LPC18XX, OPT_MCU_LPC43XX)
#include "ci_hs_lpc18_43.h"
#include "ci_hs_lpc18_43.h"
#else #else
#error "Unsupported MCUs" #error "Unsupported MCUs"
#endif #endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
@ -67,25 +70,25 @@
// Controller API // Controller API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool hcd_init(uint8_t rhport) bool hcd_init(uint8_t rhport) {
{ ci_hs_regs_t *hcd_reg = CI_HS_REG(rhport);
ci_hs_regs_t* hcd_reg = CI_HS_REG(rhport);
// Reset controller // Reset controller
hcd_reg->USBCMD |= USBCMD_RESET; hcd_reg->USBCMD |= USBCMD_RESET;
while( hcd_reg->USBCMD & USBCMD_RESET ) {} while ( hcd_reg->USBCMD & USBCMD_RESET ) {}
// Set mode to device, must be set immediately after reset // Set mode to device, must be set immediately after reset
#if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX #if CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX
// LPC18XX/43XX need to set VBUS Power Select to HIGH // LPC18XX/43XX need to set VBUS Power Select to HIGH
// RHPORT1 is fullspeed only (need external PHY for Highspeed) // RHPORT1 is fullspeed only (need external PHY for Highspeed)
hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT; hcd_reg->USBMODE = USBMODE_CM_HOST | USBMODE_VBUS_POWER_SELECT;
if (rhport == 1) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED; if ( rhport == 1 ) hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
#else #else
hcd_reg->USBMODE = USBMODE_CM_HOST; hcd_reg->USBMODE = USBMODE_CM_HOST;
#endif #endif
// FIXME force full speed, still have issue with Highspeed enumeration // FIXME force full speed, still have issue with Highspeed enumeration
// probably due to physical connection bouncing when plug/unplug
// 1. Have issue when plug/unplug devices, maybe the port is not reset properly // 1. Have issue when plug/unplug devices, maybe the port is not reset properly
// 2. Also does not seems to detect disconnection // 2. Also does not seems to detect disconnection
hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED; hcd_reg->PORTSC1 |= PORTSC1_FORCE_FULL_SPEED;
@ -93,13 +96,11 @@ bool hcd_init(uint8_t rhport)
return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD); return ehci_init(rhport, (uint32_t) &hcd_reg->CAPLENGTH, (uint32_t) &hcd_reg->USBCMD);
} }
void hcd_int_enable(uint8_t rhport) void hcd_int_enable(uint8_t rhport) {
{
CI_HCD_INT_ENABLE(rhport); CI_HCD_INT_ENABLE(rhport);
} }
void hcd_int_disable(uint8_t rhport) void hcd_int_disable(uint8_t rhport) {
{
CI_HCD_INT_DISABLE(rhport); CI_HCD_INT_DISABLE(rhport);
} }

View File

@ -188,6 +188,11 @@ void hcd_port_reset(uint8_t rhport)
ehci_registers_t* regs = ehci_data.regs; ehci_registers_t* regs = ehci_data.regs;
// skip if already in reset
if (regs->portsc_bm.port_reset) {
return;
}
// mask out Write-1-to-Clear bits // mask out Write-1-to-Clear bits
uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C; uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
@ -202,16 +207,18 @@ void hcd_port_reset(uint8_t rhport)
void hcd_port_reset_end(uint8_t rhport) void hcd_port_reset_end(uint8_t rhport)
{ {
(void) rhport; (void) rhport;
#if 0 // TODO check if this is necessary
ehci_registers_t* regs = ehci_data.regs; ehci_registers_t* regs = ehci_data.regs;
// skip if reset is already complete
if (!regs->portsc_bm.port_reset) {
return;
}
// mask out all change bits since they are Write 1 to clear // mask out all change bits since they are Write 1 to clear
uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_CHANGE_ALL; uint32_t portsc = regs->portsc & ~EHCI_PORTSC_MASK_W1C;
portsc &= ~(EHCI_PORTSC_MASK_PORT_RESET); portsc &= ~EHCI_PORTSC_MASK_PORT_RESET;
regs->portsc = portsc; regs->portsc = portsc;
#endif
} }
bool hcd_port_connect_status(uint8_t rhport) bool hcd_port_connect_status(uint8_t rhport)
@ -426,6 +433,11 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
hcd_dcache_clean(setup_packet, 8); hcd_dcache_clean(setup_packet, 8);
// Control endpoint never be stalled. Skip reset Data Toggle since it is fixed per stage
if (qhd->qtd_overlay.halted) {
qhd->qtd_overlay.halted = false;
}
// attach TD to QHD -> start transferring // attach TD to QHD -> start transferring
qhd_attach_qtd(qhd, td); qhd_attach_qtd(qhd, td);
@ -662,7 +674,7 @@ void hcd_int_handler(uint8_t rhport)
if (int_status & EHCI_INT_MASK_PORT_CHANGE) { if (int_status & EHCI_INT_MASK_PORT_CHANGE) {
// Including: Force port resume, over-current change, enable/disable change and connect status change. // Including: Force port resume, over-current change, enable/disable change and connect status change.
uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_W1C; uint32_t const port_status = regs->portsc & EHCI_PORTSC_MASK_W1C;
print_portsc(regs); // print_portsc(regs);
if (regs->portsc_bm.connect_status_change) { if (regs->portsc_bm.connect_status_change) {
port_connect_status_change_isr(rhport); port_connect_status_change_isr(rhport);