@@ -57,9 +57,11 @@ typedef struct {
57
57
TUH_EPBUF_DEF (ctrl_buf , CFG_TUH_HUB_BUFSIZE );
58
58
} hub_epbuf_t ;
59
59
60
+ static tuh_xfer_cb_t user_complete_cb = NULL ;
60
61
static hub_interface_t hub_itfs [CFG_TUH_HUB ];
61
62
CFG_TUH_MEM_SECTION static hub_epbuf_t hub_epbufs [CFG_TUH_HUB ];
62
63
64
+
63
65
TU_ATTR_ALWAYS_INLINE static inline hub_interface_t * get_hub_itf (uint8_t daddr ) {
64
66
return & hub_itfs [daddr - 1 - CFG_TUH_DEVICE_MAX ];
65
67
}
@@ -142,10 +144,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
142
144
};
143
145
144
146
TU_LOG_DRV ("HUB Set Feature: %s, addr = %u port = %u\r\n" , _hub_feature_str [feature ], hub_addr , hub_port );
145
- TU_ASSERT ( tuh_control_xfer (& xfer ) );
147
+ TU_ASSERT (tuh_control_xfer (& xfer ));
146
148
return true;
147
149
}
148
150
151
+ static void port_get_status_complete (tuh_xfer_t * xfer ) {
152
+ if (xfer -> result == XFER_RESULT_SUCCESS ) {
153
+ hub_interface_t * p_hub = get_hub_itf (xfer -> daddr );
154
+ p_hub -> port_status = * ((const hub_port_status_response_t * ) (uintptr_t ) xfer -> buffer );
155
+ }
156
+
157
+ xfer -> complete_cb = user_complete_cb ;
158
+ user_complete_cb = NULL ;
159
+ if (xfer -> complete_cb ) {
160
+ xfer -> complete_cb (xfer );
161
+ }
162
+ }
163
+
149
164
bool hub_port_get_status (uint8_t hub_addr , uint8_t hub_port , void * resp ,
150
165
tuh_xfer_cb_t complete_cb , uintptr_t user_data ) {
151
166
tusb_control_request_t const request = {
@@ -169,8 +184,26 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp,
169
184
.user_data = user_data
170
185
};
171
186
187
+ if (hub_port != 0 ) {
188
+ // intercept complete callback to save port status, ignore resp
189
+ hub_epbuf_t * p_epbuf = get_hub_epbuf (hub_addr );
190
+ xfer .complete_cb = port_get_status_complete ;
191
+ xfer .buffer = p_epbuf -> ctrl_buf ;
192
+ user_complete_cb = complete_cb ;
193
+ } else {
194
+ user_complete_cb = NULL ;
195
+ }
196
+
172
197
TU_LOG_DRV ("HUB Get Port Status: addr = %u port = %u\r\n" , hub_addr , hub_port );
173
- TU_VERIFY ( tuh_control_xfer (& xfer ) );
198
+ TU_VERIFY (tuh_control_xfer (& xfer ));
199
+ return true;
200
+ }
201
+
202
+ bool hub_port_get_status_local (uint8_t hub_addr , uint8_t hub_port , hub_port_status_response_t * resp ) {
203
+ (void ) hub_port ;
204
+ TU_VERIFY (hub_addr > CFG_TUH_DEVICE_MAX );
205
+ hub_interface_t * p_hub = get_hub_itf (hub_addr );
206
+ * resp = p_hub -> port_status ;
174
207
return true;
175
208
}
176
209
@@ -238,10 +271,10 @@ bool hub_edpt_status_xfer(uint8_t daddr) {
238
271
static void config_set_port_power (tuh_xfer_t * xfer );
239
272
static void config_port_power_complete (tuh_xfer_t * xfer );
240
273
241
- bool hub_set_config (uint8_t dev_addr , uint8_t itf_num ) {
242
- hub_interface_t * p_hub = get_hub_itf (dev_addr );
274
+ bool hub_set_config (uint8_t daddr , uint8_t itf_num ) {
275
+ hub_interface_t * p_hub = get_hub_itf (daddr );
243
276
TU_ASSERT (itf_num == p_hub -> itf_num );
244
- hub_epbuf_t * p_epbuf = get_hub_epbuf (dev_addr );
277
+ hub_epbuf_t * p_epbuf = get_hub_epbuf (daddr );
245
278
246
279
// Get Hub Descriptor
247
280
tusb_control_request_t const request = {
@@ -257,7 +290,7 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
257
290
};
258
291
259
292
tuh_xfer_t xfer = {
260
- .daddr = dev_addr ,
293
+ .daddr = daddr ,
261
294
.ep_addr = 0 ,
262
295
.setup = & request ,
263
296
.buffer = p_epbuf -> ctrl_buf ,
@@ -312,11 +345,15 @@ static void config_port_power_complete (tuh_xfer_t* xfer) {
312
345
//--------------------------------------------------------------------+
313
346
// Connection Changes
314
347
//--------------------------------------------------------------------+
315
- static void get_status_complete (tuh_xfer_t * xfer );
316
- static void port_get_status_complete (tuh_xfer_t * xfer );
317
- static void port_clear_feature_complete_stub (tuh_xfer_t * xfer );
318
- static void connection_clear_conn_change_complete (tuh_xfer_t * xfer );
319
- static void connection_port_reset_complete (tuh_xfer_t * xfer );
348
+ enum {
349
+ STATE_IDLE = 0 ,
350
+ STATE_HUB_STATUS ,
351
+ STATE_CLEAR_CHANGE ,
352
+ STATE_CHECK_CONN ,
353
+ STATE_COMPLETE
354
+ };
355
+
356
+ static void process_new_status (tuh_xfer_t * xfer );
320
357
321
358
// callback as response of interrupt endpoint polling
322
359
bool hub_xfer_cb (uint8_t daddr , uint8_t ep_addr , xfer_result_t result , uint32_t xferred_bytes ) {
@@ -337,12 +374,12 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
337
374
processed = false;
338
375
} else if (tu_bit_test (status_change , 0 )) {
339
376
// Hub bit 0 is for the hub device events
340
- processed = hub_get_status (daddr , p_epbuf -> ctrl_buf , get_status_complete , 0 );
377
+ processed = hub_get_status (daddr , p_epbuf -> ctrl_buf , process_new_status , STATE_HUB_STATUS );
341
378
} else {
342
379
// Hub bits 1 to n are hub port events
343
380
for (uint8_t port = 1 ; port <= p_hub -> bNbrPorts ; port ++ ) {
344
381
if (tu_bit_test (status_change , port )) {
345
- processed = hub_port_get_status (daddr , port , p_epbuf -> ctrl_buf , port_get_status_complete , 0 );
382
+ processed = hub_port_get_status (daddr , port , NULL , process_new_status , STATE_CLEAR_CHANGE );
346
383
break ; // after completely processed one port, we will re-queue the status poll and handle next one
347
384
}
348
385
}
@@ -358,117 +395,84 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
358
395
return true;
359
396
}
360
397
361
- static void port_clear_feature_complete_stub (tuh_xfer_t * xfer ) {
362
- hub_edpt_status_xfer (xfer -> daddr );
363
- }
364
-
365
- static void get_status_complete (tuh_xfer_t * xfer ) {
398
+ static void process_new_status (tuh_xfer_t * xfer ) {
366
399
const uint8_t daddr = xfer -> daddr ;
367
400
368
- bool processed = false; // true if new status is processed
369
- if (xfer -> result == XFER_RESULT_SUCCESS ) {
370
- hub_status_response_t hub_status = * ((const hub_status_response_t * ) (uintptr_t ) xfer -> buffer );
371
-
372
- TU_LOG_DRV ("HUB Got hub status, addr = %u, status = %04x\r\n" , daddr , hub_status .change .value );
373
-
374
- if (hub_status .change .local_power_source ) {
375
- TU_LOG_DRV (" Local Power Change\r\n" );
376
- processed = hub_clear_feature (daddr , HUB_FEATURE_HUB_LOCAL_POWER_CHANGE , port_clear_feature_complete_stub , 0 );
377
- } else if (hub_status .change .over_current ) {
378
- TU_LOG_DRV (" Over Current\r\n" );
379
- processed = hub_clear_feature (daddr , HUB_FEATURE_HUB_OVER_CURRENT_CHANGE , port_clear_feature_complete_stub , 0 );
380
- }
381
- }
382
-
383
- if (!processed ) {
384
- TU_ASSERT (hub_edpt_status_xfer (daddr ), );
401
+ if (xfer -> result != XFER_RESULT_SUCCESS ) {
402
+ TU_ASSERT (hub_edpt_status_xfer (daddr ),);
403
+ return ;
385
404
}
386
- }
387
405
388
- static void port_get_status_complete (tuh_xfer_t * xfer ) {
389
- const uint8_t daddr = xfer -> daddr ;
406
+ const uint8_t port_num = (uint8_t ) tu_le16toh (xfer -> setup -> wIndex );
407
+ hub_interface_t * p_hub = get_hub_itf (daddr );
408
+ const uintptr_t state = xfer -> user_data ;
390
409
bool processed = false; // true if new status is processed
391
410
392
- if (xfer -> result == XFER_RESULT_SUCCESS ) {
393
- const uint8_t port_num = (uint8_t ) tu_le16toh (xfer -> setup -> wIndex );
394
- hub_interface_t * p_hub = get_hub_itf (daddr );
395
- p_hub -> port_status = * ((const hub_port_status_response_t * ) (uintptr_t ) xfer -> buffer );
396
-
397
- // Clear port status change interrupts
398
- if (p_hub -> port_status .change .connection ) {
399
- // Connection change
400
- // Port is powered and enabled
401
- //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
402
-
403
- // Acknowledge Port Connection Change
404
- processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_CONNECTION_CHANGE , connection_clear_conn_change_complete , 0 );
405
- } else if (p_hub -> port_status .change .port_enable ) {
406
- processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_ENABLE_CHANGE , port_clear_feature_complete_stub , 0 );
407
- } else if (p_hub -> port_status .change .suspend ) {
408
- processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_SUSPEND_CHANGE , port_clear_feature_complete_stub , 0 );
409
- } else if (p_hub -> port_status .change .over_current ) {
410
- processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_OVER_CURRENT_CHANGE , port_clear_feature_complete_stub , 0 );
411
- } else if (p_hub -> port_status .change .reset ) {
412
- processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_RESET_CHANGE , port_clear_feature_complete_stub , 0 );
411
+ switch (state ) {
412
+ case STATE_HUB_STATUS : {
413
+ hub_status_response_t hub_status = * ((const hub_status_response_t * ) (uintptr_t ) xfer -> buffer );
414
+ TU_LOG_DRV ("HUB Got hub status, addr = %u, status = %04x\r\n" , daddr , hub_status .change .value );
415
+ if (hub_status .change .local_power_source ) {
416
+ TU_LOG_DRV (" Local Power Change\r\n" );
417
+ processed = hub_clear_feature (daddr , HUB_FEATURE_HUB_LOCAL_POWER_CHANGE ,
418
+ process_new_status , STATE_COMPLETE );
419
+ } else if (hub_status .change .over_current ) {
420
+ TU_LOG_DRV (" Over Current\r\n" );
421
+ processed = hub_clear_feature (daddr , HUB_FEATURE_HUB_OVER_CURRENT_CHANGE ,
422
+ process_new_status , STATE_COMPLETE );
423
+ }
424
+ break ;
413
425
}
414
- }
415
426
416
- if (!processed ) {
417
- TU_ASSERT (hub_edpt_status_xfer (daddr ), );
418
- }
419
- }
420
-
421
- static void connection_clear_conn_change_complete (tuh_xfer_t * xfer ) {
422
- const uint8_t daddr = xfer -> daddr ;
423
-
424
- if (xfer -> result != XFER_RESULT_SUCCESS ) {
425
- TU_ASSERT (hub_edpt_status_xfer (daddr ), );
426
- return ;
427
- }
427
+ case STATE_CLEAR_CHANGE :
428
+ // Get port status complete --> clear change
429
+ if (p_hub -> port_status .change .connection ) {
430
+ // Connection change
431
+ // Port is powered and enabled
432
+ //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, );
433
+
434
+ // Acknowledge Port Connection Change
435
+ processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_CONNECTION_CHANGE ,
436
+ process_new_status , STATE_CHECK_CONN );
437
+ } else if (p_hub -> port_status .change .port_enable ) {
438
+ processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_ENABLE_CHANGE ,
439
+ process_new_status , STATE_COMPLETE );
440
+ } else if (p_hub -> port_status .change .suspend ) {
441
+ processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_SUSPEND_CHANGE ,
442
+ process_new_status , STATE_COMPLETE );
443
+ } else if (p_hub -> port_status .change .over_current ) {
444
+ processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_OVER_CURRENT_CHANGE ,
445
+ process_new_status , STATE_COMPLETE );
446
+ } else if (p_hub -> port_status .change .reset ) {
447
+ processed = hub_port_clear_feature (daddr , port_num , HUB_FEATURE_PORT_RESET_CHANGE ,
448
+ process_new_status , STATE_COMPLETE );
449
+ }
450
+ break ;
451
+
452
+ case STATE_CHECK_CONN : {
453
+ const hcd_event_t event = {
454
+ .rhport = usbh_get_rhport (daddr ),
455
+ .event_id = p_hub -> port_status .status .connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE ,
456
+ .connection = {
457
+ .hub_addr = daddr ,
458
+ .hub_port = port_num
459
+ }
460
+ };
461
+ hcd_event_handler (& event , false);
462
+ processed = true; // usbh queue status after handled this in (de)enumeration
463
+ break ;
464
+ }
428
465
429
- hub_interface_t * p_hub = get_hub_itf (daddr );
430
- const uint8_t port_num = (uint8_t ) tu_le16toh (xfer -> setup -> wIndex );
466
+ case STATE_COMPLETE :
467
+ default :
468
+ processed = false; // complete this status, queue next status
469
+ break ;
431
470
432
- if (p_hub -> port_status .status .connection ) {
433
- // Reset port if attach event
434
- hub_port_reset (daddr , port_num , connection_port_reset_complete , 0 );
435
- } else {
436
- // submit detach event
437
- const hcd_event_t event = {
438
- .rhport = usbh_get_rhport (daddr ),
439
- .event_id = HCD_EVENT_DEVICE_REMOVE ,
440
- .connection = {
441
- .hub_addr = daddr ,
442
- .hub_port = port_num
443
- }
444
- };
445
- hcd_event_handler (& event , false);
446
471
}
447
- }
448
-
449
- static void connection_port_reset_complete (tuh_xfer_t * xfer ) {
450
- const uint8_t daddr = xfer -> daddr ;
451
472
452
- if (xfer -> result != XFER_RESULT_SUCCESS ) {
453
- // retry port reset if failed
454
- if (!tuh_control_xfer (xfer )) {
455
- TU_ASSERT (hub_edpt_status_xfer (daddr ), ); // back to status poll if failed to queue request
456
- }
457
- return ;
473
+ if (!processed ) {
474
+ TU_ASSERT (hub_edpt_status_xfer (daddr ),);
458
475
}
459
-
460
- const uint8_t port_num = (uint8_t ) tu_le16toh (xfer -> setup -> wIndex );
461
-
462
- // submit attach event
463
- hcd_event_t event = {
464
- .rhport = usbh_get_rhport (daddr ),
465
- .event_id = HCD_EVENT_DEVICE_ATTACH ,
466
- .connection = {
467
- .hub_addr = daddr ,
468
- .hub_port = port_num
469
- }
470
- };
471
- hcd_event_handler (& event , false);
472
476
}
473
477
474
478
#endif
0 commit comments