@@ -57,9 +57,11 @@ typedef struct {
5757 TUH_EPBUF_DEF (ctrl_buf , CFG_TUH_HUB_BUFSIZE );
5858} hub_epbuf_t ;
5959
60+ static tuh_xfer_cb_t user_complete_cb = NULL ;
6061static hub_interface_t hub_itfs [CFG_TUH_HUB ];
6162CFG_TUH_MEM_SECTION static hub_epbuf_t hub_epbufs [CFG_TUH_HUB ];
6263
64+
6365TU_ATTR_ALWAYS_INLINE static inline hub_interface_t * get_hub_itf (uint8_t daddr ) {
6466 return & hub_itfs [daddr - 1 - CFG_TUH_DEVICE_MAX ];
6567}
@@ -142,10 +144,23 @@ bool hub_port_set_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature,
142144 };
143145
144146 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 ));
146148 return true;
147149}
148150
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+
149164bool hub_port_get_status (uint8_t hub_addr , uint8_t hub_port , void * resp ,
150165 tuh_xfer_cb_t complete_cb , uintptr_t user_data ) {
151166 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,
169184 .user_data = user_data
170185 };
171186
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+
172197 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 ;
174207 return true;
175208}
176209
@@ -238,10 +271,10 @@ bool hub_edpt_status_xfer(uint8_t daddr) {
238271static void config_set_port_power (tuh_xfer_t * xfer );
239272static void config_port_power_complete (tuh_xfer_t * xfer );
240273
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 );
243276 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 );
245278
246279 // Get Hub Descriptor
247280 tusb_control_request_t const request = {
@@ -257,7 +290,7 @@ bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) {
257290 };
258291
259292 tuh_xfer_t xfer = {
260- .daddr = dev_addr ,
293+ .daddr = daddr ,
261294 .ep_addr = 0 ,
262295 .setup = & request ,
263296 .buffer = p_epbuf -> ctrl_buf ,
@@ -312,11 +345,15 @@ static void config_port_power_complete (tuh_xfer_t* xfer) {
312345//--------------------------------------------------------------------+
313346// Connection Changes
314347//--------------------------------------------------------------------+
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 );
320357
321358// callback as response of interrupt endpoint polling
322359bool 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
337374 processed = false;
338375 } else if (tu_bit_test (status_change , 0 )) {
339376 // 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 );
341378 } else {
342379 // Hub bits 1 to n are hub port events
343380 for (uint8_t port = 1 ; port <= p_hub -> bNbrPorts ; port ++ ) {
344381 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 );
346383 break ; // after completely processed one port, we will re-queue the status poll and handle next one
347384 }
348385 }
@@ -358,117 +395,84 @@ bool hub_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t
358395 return true;
359396}
360397
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 ) {
366399 const uint8_t daddr = xfer -> daddr ;
367400
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 ;
385404 }
386- }
387405
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 ;
390409 bool processed = false; // true if new status is processed
391410
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 ;
413425 }
414- }
415426
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+ }
428465
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 ;
431470
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);
446471 }
447- }
448-
449- static void connection_port_reset_complete (tuh_xfer_t * xfer ) {
450- const uint8_t daddr = xfer -> daddr ;
451472
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 ),);
458475 }
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);
472476}
473477
474478#endif
0 commit comments