Skip to content

Commit 1f95a41

Browse files
committed
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
1 parent 1b92108 commit 1f95a41

File tree

6 files changed

+128
-103
lines changed

6 files changed

+128
-103
lines changed

src/host/hcd.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,11 @@ uint32_t hcd_frame_number(uint8_t rhport);
149149
// Get the current connect status of roothub port
150150
bool hcd_port_connect_status(uint8_t rhport);
151151

152-
// Reset USB bus on the port
152+
// Reset USB bus on the port. Return immediately, bus reset sequence may not be complete.
153+
// Some port would require hcd_port_reset_end() to be invoked after 10ms to complete the reset sequence.
153154
void hcd_port_reset(uint8_t rhport);
154155

155-
// TODO implement later
156+
// Complete bus reset sequence, may be required by some controllers
156157
void hcd_port_reset_end(uint8_t rhport);
157158

158159
// Get port link speed

src/host/hub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ static void connection_port_reset_complete (tuh_xfer_t* xfer);
330330
bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
331331
(void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports
332332
(void) ep_addr;
333-
TU_ASSERT(result == XFER_RESULT_SUCCESS);
333+
TU_VERIFY(result == XFER_RESULT_SUCCESS);
334334

335335
hub_interface_t* p_hub = get_itf(dev_addr);
336336

src/host/usbh.c

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
181181
};
182182

183183
enum { USBH_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) };
184-
185-
enum { RESET_DELAY = 500 }; // 200 USB specs say only 50ms but many devices require much longer
186-
187184
enum { CONFIG_NUM = 1 }; // default to use configuration 1
188185

189186

@@ -251,40 +248,27 @@ static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t
251248

252249
#if CFG_TUSB_OS == OPT_OS_NONE
253250
// TODO rework time-related function later
254-
TU_ATTR_WEAK void osal_task_delay(uint32_t msec)
255-
{
251+
// weak and overridable
252+
TU_ATTR_WEAK void osal_task_delay(uint32_t msec) {
256253
const uint32_t start = hcd_frame_number(_usbh_controller);
257254
while ( ( hcd_frame_number(_usbh_controller) - start ) < msec ) {}
258255
}
259256
#endif
260257

261258
//--------------------------------------------------------------------+
262-
// PUBLIC API (Parameter Verification is required)
259+
// Device API
263260
//--------------------------------------------------------------------+
264261

265-
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
266-
{
267-
if (hcd_configure)
268-
{
269-
return hcd_configure(rhport, cfg_id, cfg_param);
270-
}else
271-
{
272-
return false;
273-
}
274-
}
275-
276-
bool tuh_mounted(uint8_t dev_addr)
277-
{
278-
usbh_device_t* dev = get_device(dev_addr);
262+
bool tuh_mounted(uint8_t dev_addr) {
263+
usbh_device_t *dev = get_device(dev_addr);
279264
TU_VERIFY(dev);
280265
return dev->configured;
281266
}
282267

283-
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
284-
{
268+
bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t *vid, uint16_t *pid) {
285269
*vid = *pid = 0;
286270

287-
usbh_device_t const* dev = get_device(dev_addr);
271+
usbh_device_t const *dev = get_device(dev_addr);
288272
TU_VERIFY(dev && dev->addressed && dev->vid != 0);
289273

290274
*vid = dev->vid;
@@ -293,26 +277,48 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
293277
return true;
294278
}
295279

296-
tusb_speed_t tuh_speed_get (uint8_t dev_addr)
297-
{
298-
usbh_device_t* dev = get_device(dev_addr);
280+
tusb_speed_t tuh_speed_get(uint8_t dev_addr) {
281+
usbh_device_t *dev = get_device(dev_addr);
299282
return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed);
300283
}
301284

302-
static void clear_device(usbh_device_t* dev)
303-
{
285+
bool tuh_rhport_is_active(uint8_t rhport) {
286+
return _usbh_controller == rhport;
287+
}
288+
289+
bool tuh_rhport_reset_bus(uint8_t rhport, bool active) {
290+
TU_VERIFY(tuh_rhport_is_active(rhport));
291+
if ( active ) {
292+
hcd_port_reset(rhport);
293+
} else {
294+
hcd_port_reset_end(rhport);
295+
}
296+
return true;
297+
}
298+
299+
//--------------------------------------------------------------------+
300+
// PUBLIC API (Parameter Verification is required)
301+
//--------------------------------------------------------------------+
302+
303+
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void *cfg_param) {
304+
if ( hcd_configure ) {
305+
return hcd_configure(rhport, cfg_id, cfg_param);
306+
} else {
307+
return false;
308+
}
309+
}
310+
311+
static void clear_device(usbh_device_t* dev) {
304312
tu_memclr(dev, sizeof(usbh_device_t));
305313
memset(dev->itf2drv, TUSB_INDEX_INVALID_8, sizeof(dev->itf2drv)); // invalid mapping
306314
memset(dev->ep2drv , TUSB_INDEX_INVALID_8, sizeof(dev->ep2drv )); // invalid mapping
307315
}
308316

309-
bool tuh_inited(void)
310-
{
317+
bool tuh_inited(void) {
311318
return _usbh_controller != TUSB_INDEX_INVALID_8;
312319
}
313320

314-
bool tuh_init(uint8_t controller_id)
315-
{
321+
bool tuh_init(uint8_t controller_id) {
316322
// skip if already initialized
317323
if ( tuh_inited() ) return true;
318324

@@ -359,8 +365,7 @@ bool tuh_init(uint8_t controller_id)
359365
return true;
360366
}
361367

362-
bool tuh_task_event_ready(void)
363-
{
368+
bool tuh_task_event_ready(void) {
364369
// Skip if stack is not initialized
365370
if ( !tuh_inited() ) return false;
366371

@@ -385,8 +390,7 @@ bool tuh_task_event_ready(void)
385390
}
386391
@endcode
387392
*/
388-
void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
389-
{
393+
void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
390394
(void) in_isr; // not implemented yet
391395

392396
// Skip if stack is not initialized
@@ -403,8 +407,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
403407
case HCD_EVENT_DEVICE_ATTACH:
404408
// due to the shared _usbh_ctrl_buf, we must complete enumerating
405409
// one device before enumerating another one.
406-
if ( _dev0.enumerating )
407-
{
410+
if ( _dev0.enumerating ) {
408411
TU_LOG_USBH("[%u:] USBH Defer Attach until current enumeration complete\r\n", event.rhport);
409412

410413
bool is_empty = osal_queue_empty(_usbh_q);
@@ -414,8 +417,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
414417
// Exit if this is the only event in the queue, otherwise we may loop forever
415418
return;
416419
}
417-
}else
418-
{
420+
}else {
419421
TU_LOG_USBH("[%u:] USBH DEVICE ATTACH\r\n", event.rhport);
420422
_dev0.enumerating = 1;
421423
enum_new_device(&event);
@@ -428,8 +430,7 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr)
428430

429431
#if CFG_TUH_HUB
430432
// TODO remove
431-
if ( event.connection.hub_addr != 0)
432-
{
433+
if ( event.connection.hub_addr != 0) {
433434
// done with hub, waiting for next data on status pipe
434435
(void) hub_edpt_status_xfer( event.connection.hub_addr );
435436
}
@@ -1230,6 +1231,12 @@ static void process_removing_device(uint8_t rhport, uint8_t hub_addr, uint8_t hu
12301231
// one device before enumerating another one.
12311232
//--------------------------------------------------------------------+
12321233

1234+
enum {
1235+
ENUM_RESET_DELAY = 50, // USB specs: 10 to 50ms
1236+
ENUM_CONTACT_DEBOUNCING_DELAY = 450, // when plug/unplug a device, physical connection can be bouncing and may
1237+
// generate a series of attach/detach event. This delay wait for stable connection
1238+
};
1239+
12331240
enum {
12341241
ENUM_IDLE,
12351242
ENUM_RESET_1, // 1st reset when attached
@@ -1311,7 +1318,7 @@ static void process_enumeration(tuh_xfer_t* xfer)
13111318
break;
13121319

13131320
case ENUM_HUB_GET_STATUS_2:
1314-
osal_task_delay(RESET_DELAY);
1321+
osal_task_delay(ENUM_RESET_DELAY);
13151322
TU_ASSERT( hub_port_get_status(_dev0.hub_addr, _dev0.hub_port, _usbh_ctrl_buf, process_enumeration, ENUM_HUB_CLEAR_RESET_2), );
13161323
break;
13171324

@@ -1468,12 +1475,14 @@ static bool enum_new_device(hcd_event_t* event)
14681475
if (_dev0.hub_addr == 0)
14691476
{
14701477
// connected/disconnected directly with roothub
1471-
// wait until device is stable TODO non blocking
14721478
hcd_port_reset(_dev0.rhport);
1473-
osal_task_delay(RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
1474-
// sof of controller may not running while resetting
1479+
osal_task_delay(ENUM_RESET_DELAY); // TODO may not work for no-OS on MCU that require reset_end() since
1480+
// sof of controller may not running while resetting
14751481
hcd_port_reset_end( _dev0.rhport);
14761482

1483+
// wait until device connection is stable TODO non blocking
1484+
osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);
1485+
14771486
// device unplugged while delaying
14781487
if ( !hcd_port_connect_status(_dev0.rhport) ) {
14791488
enum_full_complete();
@@ -1489,15 +1498,16 @@ static bool enum_new_device(hcd_event_t* event)
14891498
xfer.result = XFER_RESULT_SUCCESS;
14901499
xfer.user_data = ENUM_ADDR0_DEVICE_DESC;
14911500

1501+
14921502
process_enumeration(&xfer);
14931503

14941504
}
14951505
#if CFG_TUH_HUB
14961506
else
14971507
{
14981508
// connected/disconnected via external hub
1499-
// wait until device is stable
1500-
osal_task_delay(RESET_DELAY);
1509+
// wait until device connection is stable TODO non blocking
1510+
osal_task_delay(ENUM_CONTACT_DEBOUNCING_DELAY);
15011511

15021512
// ENUM_HUB_GET_STATUS
15031513
//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)
15081518
return true;
15091519
}
15101520

1511-
static uint8_t get_new_address(bool is_hub)
1512-
{
1521+
static uint8_t get_new_address(bool is_hub) {
15131522
uint8_t start;
15141523
uint8_t end;
15151524

1516-
if ( is_hub )
1517-
{
1525+
if ( is_hub ) {
15181526
start = CFG_TUH_DEVICE_MAX;
15191527
end = start + CFG_TUH_HUB;
1520-
}else
1521-
{
1528+
}else {
15221529
start = 0;
15231530
end = start + CFG_TUH_DEVICE_MAX;
15241531
}
15251532

1526-
for (uint8_t idx = start; idx < end; idx++)
1527-
{
1533+
for (uint8_t idx = start; idx < end; idx++) {
15281534
if (!_usbh_devices[idx].connected) return (idx+1);
15291535
}
15301536

src/host/usbh.h

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,15 @@ typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
4747
// it is advised to initialize it using member name
4848
// Note2: not all field is available/meaningful in callback,
4949
// some info is not saved by usbh to save SRAM
50-
struct tuh_xfer_s
51-
{
50+
struct tuh_xfer_s {
5251
uint8_t daddr;
5352
uint8_t ep_addr;
5453
uint8_t TU_RESERVED; // reserved
5554
xfer_result_t result;
5655

5756
uint32_t actual_len; // excluding setup packet
5857

59-
union
60-
{
58+
union {
6159
tusb_control_request_t const* setup; // setup packet pointer if control transfer
6260
uint32_t buflen; // expected length if not control transfer (not available in callback)
6361
};
@@ -70,15 +68,13 @@ struct tuh_xfer_s
7068
};
7169

7270
// Subject to change
73-
typedef struct
74-
{
71+
typedef struct {
7572
uint8_t daddr;
7673
tusb_desc_interface_t desc;
7774
} tuh_itf_info_t;
7875

7976
// ConfigID for tuh_config()
80-
enum
81-
{
77+
enum {
8278
TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 << 8 // cfg_param: pio_usb_configuration_t
8379
};
8480

@@ -105,12 +101,12 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
105101
// Should be called before tuh_init()
106102
// - cfg_id : configure ID (TBD)
107103
// - cfg_param: configure data, structure depends on the ID
108-
bool tuh_configure(uint8_t controller_id, uint32_t cfg_id, const void* cfg_param);
104+
bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
109105

110106
// Init host stack
111-
bool tuh_init(uint8_t controller_id);
107+
bool tuh_init(uint8_t rhport);
112108

113-
// Check if host stack is already initialized
109+
// Check if host stack is already initialized with any roothub ports
114110
bool tuh_inited(void);
115111

116112
// 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);
120116

121117
// Task function should be called in main/rtos loop
122118
TU_ATTR_ALWAYS_INLINE static inline
123-
void tuh_task(void)
124-
{
119+
void tuh_task(void) {
125120
tuh_task_ext(UINT32_MAX, false);
126121
}
127122

@@ -135,26 +130,36 @@ extern void hcd_int_handler(uint8_t rhport);
135130
// Interrupt handler, name alias to HCD
136131
#define tuh_int_handler hcd_int_handler
137132

133+
// Check if roothub port is initialized and active as a host
134+
bool tuh_rhport_is_active(uint8_t rhport);
135+
136+
// Assert/de-assert Bus Reset signal to roothub port. USB specs: it should last 10-50ms
137+
bool tuh_rhport_reset_bus(uint8_t rhport, bool active);
138+
139+
//--------------------------------------------------------------------+
140+
// Device API
141+
//--------------------------------------------------------------------+
142+
143+
// Get VID/PID of device
138144
bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
139145

146+
// Get speed of device
140147
tusb_speed_t tuh_speed_get(uint8_t daddr);
141148

142149
// Check if device is connected and configured
143150
bool tuh_mounted(uint8_t daddr);
144151

145152
// Check if device is suspended
146153
TU_ATTR_ALWAYS_INLINE static inline
147-
bool tuh_suspended(uint8_t daddr)
148-
{
154+
bool tuh_suspended(uint8_t daddr) {
149155
// TODO implement suspend & resume on host
150156
(void) daddr;
151157
return false;
152158
}
153159

154160
// Check if device is ready to communicate with
155161
TU_ATTR_ALWAYS_INLINE static inline
156-
bool tuh_ready(uint8_t daddr)
157-
{
162+
bool tuh_ready(uint8_t daddr) {
158163
return tuh_mounted(daddr) && !tuh_suspended(daddr);
159164
}
160165

0 commit comments

Comments
 (0)