update usbh with hub to use async control transfer
work ok with msc + hub, but definitely need more testing.
This commit is contained in:
		
							
								
								
									
										311
									
								
								src/host/hub.c
									
									
									
									
									
								
							
							
						
						
									
										311
									
								
								src/host/hub.c
									
									
									
									
									
								
							| @@ -33,21 +33,21 @@ | ||||
| //--------------------------------------------------------------------+ | ||||
| #include "hub.h" | ||||
|  | ||||
| extern void osal_task_delay(uint32_t msec); // TODO remove | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // MACRO CONSTANT TYPEDEF | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef struct | ||||
| { | ||||
|   uint8_t itf_num; | ||||
|   uint8_t ep_status; | ||||
|   uint8_t port_number; | ||||
|   uint8_t ep_in; | ||||
|   uint8_t port_count; | ||||
|   uint8_t status_change; // data from status change interrupt endpoint | ||||
|  | ||||
|   hub_port_status_response_t port_status; | ||||
| }usbh_hub_t; | ||||
|  | ||||
| CFG_TUSB_MEM_SECTION static usbh_hub_t hub_data[CFG_TUSB_HOST_DEVICE_MAX]; | ||||
| TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(descriptor_hub_desc_t)]; | ||||
| TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)]; | ||||
|  | ||||
| //OSAL_SEM_DEF(hub_enum_semaphore); | ||||
| //static osal_semaphore_handle_t hub_enum_sem_hdl; | ||||
| @@ -55,25 +55,30 @@ TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(de | ||||
| //--------------------------------------------------------------------+ | ||||
| // HUB | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature) | ||||
| bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb) | ||||
| { | ||||
|   TU_ASSERT(HUB_FEATURE_PORT_CONNECTION_CHANGE <= feature && feature <= HUB_FEATURE_PORT_RESET_CHANGE); | ||||
|  | ||||
|   tusb_control_request_t request = { | ||||
|           .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, | ||||
|           .bRequest = HUB_REQUEST_CLEAR_FEATURE, | ||||
|           .wValue = feature, | ||||
|           .wIndex = hub_port, | ||||
|           .wLength = 0 | ||||
|   tusb_control_request_t const request = | ||||
|   { | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
|       .recipient = TUSB_REQ_RCPT_OTHER, | ||||
|       .type      = TUSB_REQ_TYPE_CLASS, | ||||
|       .direction = TUSB_DIR_OUT | ||||
|     }, | ||||
|     .bRequest = HUB_REQUEST_CLEAR_FEATURE, | ||||
|     .wValue   = feature, | ||||
|     .wIndex   = hub_port, | ||||
|     .wLength  = 0 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); | ||||
|   TU_LOG2("HUB Clear Port Feature: addr = 0x%02X, port = %u, feature = %u\r\n", hub_addr, hub_port, feature); | ||||
|   TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) | ||||
| bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb) | ||||
| { | ||||
|   tusb_control_request_t request = | ||||
|   tusb_control_request_t const request = | ||||
|   { | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
| @@ -81,31 +86,35 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_res | ||||
|       .type      = TUSB_REQ_TYPE_CLASS, | ||||
|       .direction = TUSB_DIR_IN | ||||
|     }, | ||||
|  | ||||
|     .bRequest = HUB_REQUEST_GET_STATUS, | ||||
|     .wValue   = 0, | ||||
|     .wIndex   = hub_port, | ||||
|     .wLength  = 4 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) ); | ||||
|  | ||||
|   memcpy(resp, hub_enum_buffer, sizeof(hub_port_status_response_t)); | ||||
|   TU_LOG2("HUB Get Port Status: addr = 0x%02X, port = %u\r\n", hub_addr, hub_port); | ||||
|   TU_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) ); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port) | ||||
| bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb) | ||||
| { | ||||
|   //------------- Set Port Reset -------------// | ||||
|   tusb_control_request_t request = { | ||||
|           .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, | ||||
|           .bRequest = HUB_REQUEST_SET_FEATURE, | ||||
|           .wValue = HUB_FEATURE_PORT_RESET, | ||||
|           .wIndex = hub_port, | ||||
|           .wLength = 0 | ||||
|   tusb_control_request_t const request = | ||||
|   { | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
|       .recipient = TUSB_REQ_RCPT_OTHER, | ||||
|       .type      = TUSB_REQ_TYPE_CLASS, | ||||
|       .direction = TUSB_DIR_OUT | ||||
|     }, | ||||
|     .bRequest = HUB_REQUEST_SET_FEATURE, | ||||
|     .wValue   = HUB_FEATURE_PORT_RESET, | ||||
|     .wIndex   = hub_port, | ||||
|     .wLength  = 0 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); | ||||
|   TU_LOG2("HUB Reset Port: addr = 0x%02X, port = %u\r\n", hub_addr, hub_port); | ||||
|   TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| @@ -133,42 +142,179 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf | ||||
|   TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc)); | ||||
|  | ||||
|   hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber; | ||||
|   hub_data[dev_addr-1].ep_status = ep_desc->bEndpointAddress; | ||||
|   hub_data[dev_addr-1].ep_in   = ep_desc->bEndpointAddress; | ||||
|  | ||||
|   (*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t); | ||||
|  | ||||
|   //------------- Get Hub Descriptor -------------// | ||||
|   tusb_control_request_t request = { | ||||
|           .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, | ||||
|           .bRequest = HUB_REQUEST_GET_DESCRIPTOR, | ||||
|           .wValue = 0, | ||||
|           .wIndex = 0, | ||||
|           .wLength = sizeof(descriptor_hub_desc_t) | ||||
|   }; | ||||
|   return true; | ||||
| } | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( dev_addr, &request, hub_enum_buffer ) ); | ||||
| static bool config_get_hub_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
|  | ||||
|   // only care about this field in hub descriptor | ||||
|   hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts; | ||||
| static bool config_get_hub_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   (void) request; | ||||
|   TU_ASSERT(XFER_RESULT_SUCCESS == result); | ||||
|  | ||||
|   //------------- Set Port_Power on all ports -------------// | ||||
|   // TODO may only power port with attached | ||||
|   request = (tusb_control_request_t ) { | ||||
|           .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, | ||||
|           .bRequest = HUB_REQUEST_SET_FEATURE, | ||||
|           .wValue = HUB_FEATURE_PORT_POWER, | ||||
|           .wIndex = 0, | ||||
|           .wLength = 0 | ||||
|   }; | ||||
|   usbh_hub_t* p_hub = &hub_data[dev_addr-1]; | ||||
|  | ||||
|   for(uint8_t i=1; i <= hub_data[dev_addr-1].port_number; i++) | ||||
|   // only use number of ports in hub descriptor | ||||
|   descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer; | ||||
|   p_hub->port_count = desc_hub->bNbrPorts; | ||||
|  | ||||
|   // May need to GET_STATUS | ||||
|  | ||||
|   // Ports must be powered on to be able to detect connection | ||||
|   tusb_control_request_t const new_request = | ||||
|   { | ||||
|     request.wIndex = i; | ||||
|     TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
|       .recipient = TUSB_REQ_RCPT_OTHER, | ||||
|       .type      = TUSB_REQ_TYPE_CLASS, | ||||
|       .direction = TUSB_DIR_OUT | ||||
|     }, | ||||
|     .bRequest = HUB_REQUEST_SET_FEATURE, | ||||
|     .wValue   = HUB_FEATURE_PORT_POWER, | ||||
|     .wIndex   = 1, // starting with port 1 | ||||
|     .wLength  = 0 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_port_power_complete) ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   TU_ASSERT(XFER_RESULT_SUCCESS == result); | ||||
|   usbh_hub_t* p_hub = &hub_data[dev_addr-1]; | ||||
|  | ||||
|   if (request->wIndex == p_hub->port_count) | ||||
|   { | ||||
|     // All ports are power -> queue notification status endpoint and | ||||
|     // complete the SET CONFIGURATION | ||||
|     TU_ASSERT( usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1) ); | ||||
|  | ||||
|     usbh_driver_set_config_complete(dev_addr, p_hub->itf_num); | ||||
|   }else | ||||
|   { | ||||
|     tusb_control_request_t new_request = *request; | ||||
|     new_request.wIndex++; // power next port | ||||
|  | ||||
|     TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_port_power_complete) ); | ||||
|   } | ||||
|  | ||||
|   // Queue notification status endpoint | ||||
|   TU_ASSERT( usbh_edpt_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1) ); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) | ||||
| { | ||||
|   usbh_hub_t* p_hub = &hub_data[dev_addr-1]; | ||||
|   TU_ASSERT(itf_num == p_hub->itf_num); | ||||
|  | ||||
|   //------------- Get Hub Descriptor -------------// | ||||
|   tusb_control_request_t request = | ||||
|   { | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
|       .recipient = TUSB_REQ_RCPT_DEVICE, | ||||
|       .type      = TUSB_REQ_TYPE_CLASS, | ||||
|       .direction = TUSB_DIR_IN | ||||
|     }, | ||||
|     .bRequest = HUB_REQUEST_GET_DESCRIPTOR, | ||||
|     .wValue   = 0, | ||||
|     .wIndex   = 0, | ||||
|     .wLength  = sizeof(descriptor_hub_desc_t) | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( tuh_control_xfer(dev_addr, &request, _hub_buffer, config_get_hub_desc_complete) ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
|  | ||||
| static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   TU_ASSERT(result == XFER_RESULT_SUCCESS); | ||||
|  | ||||
|   // usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|   uint8_t const port_num = (uint8_t) request->wIndex; | ||||
|  | ||||
|   // submit attach event | ||||
|   hcd_event_t event = | ||||
|   { | ||||
|     .rhport     = usbh_get_rhport(dev_addr), | ||||
|     .event_id   = HCD_EVENT_DEVICE_ATTACH, | ||||
|     .connection = | ||||
|     { | ||||
|       .hub_addr = dev_addr, | ||||
|       .hub_port = port_num | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   hcd_event_handler(&event, false); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   TU_ASSERT(result == XFER_RESULT_SUCCESS); | ||||
|  | ||||
|   usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|   uint8_t const port_num = (uint8_t) request->wIndex; | ||||
|  | ||||
|   if ( p_hub->port_status.status.connection ) | ||||
|   { | ||||
|     // Reset port if attach event | ||||
|     hub_port_reset(dev_addr, port_num, connection_port_reset_complete); | ||||
|   }else | ||||
|   { | ||||
|     // submit detach event | ||||
|     hcd_event_t event = | ||||
|     { | ||||
|       .rhport     = usbh_get_rhport(dev_addr), | ||||
|       .event_id   = HCD_EVENT_DEVICE_REMOVE, | ||||
|       .connection = | ||||
|        { | ||||
|          .hub_addr = dev_addr, | ||||
|          .hub_port = port_num | ||||
|        } | ||||
|     }; | ||||
|  | ||||
|     hcd_event_handler(&event, false); | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   TU_ASSERT(result == XFER_RESULT_SUCCESS); | ||||
|   usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|   uint8_t const port_num = (uint8_t) request->wIndex; | ||||
|  | ||||
|   // Connection change | ||||
|   if (p_hub->port_status.change.connection) | ||||
|   { | ||||
|     // Port is powered and enabled | ||||
|     //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); | ||||
|  | ||||
|     // Acknowledge Port Connection Change | ||||
|     hub_port_clear_feature(dev_addr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete); | ||||
|   }else | ||||
|   { | ||||
|     // Other changes are: Enable, Suspend, Over Current, Reset, L1 state | ||||
|     // TODO clear change | ||||
|  | ||||
|     // prepare for next hub status | ||||
|     // TODO continue with status_change, or maybe we can do it again with status | ||||
|     hub_status_pipe_queue(dev_addr); | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
| @@ -179,55 +325,23 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 | ||||
| { | ||||
|   (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports | ||||
|   (void) ep_addr; | ||||
|   TU_ASSERT( result == XFER_RESULT_SUCCESS); | ||||
|  | ||||
|   usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|  | ||||
|   if ( result == XFER_RESULT_SUCCESS ) | ||||
|   TU_LOG2("Port Status Change = 0x%02X\r\n", p_hub->status_change); | ||||
|   for (uint8_t port=1; port <= p_hub->port_count; port++) | ||||
|   { | ||||
|     TU_LOG2("Port Status Change = 0x%02X\r\n", p_hub->status_change); | ||||
|     for (uint8_t port=1; port <= p_hub->port_number; port++) | ||||
|     // TODO HUB ignore bit0 hub_status_change | ||||
|     if ( tu_bit_test(p_hub->status_change, port) ) | ||||
|     { | ||||
|       // TODO HUB ignore bit0 hub_status_change | ||||
|       if ( tu_bit_test(p_hub->status_change, port) ) | ||||
|       { | ||||
|         hub_port_status_response_t port_status; | ||||
|         hub_port_get_status(dev_addr, port, &port_status); | ||||
|  | ||||
|         // Connection change | ||||
|         if (port_status.change.connection) | ||||
|         { | ||||
|           // Port is powered and enabled | ||||
|           //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); | ||||
|  | ||||
|           // Acknowledge Port Connection Change | ||||
|           hub_port_clear_feature(dev_addr, port, HUB_FEATURE_PORT_CONNECTION_CHANGE); | ||||
|  | ||||
|           // Reset port if attach event | ||||
|           if ( port_status.status.connection ) hub_port_reset(dev_addr, port); | ||||
|  | ||||
|           hcd_event_t event = | ||||
|           { | ||||
|             .rhport     = _usbh_devices[dev_addr].rhport, | ||||
|             .event_id   = port_status.status.connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE, | ||||
|             .connection = | ||||
|             { | ||||
|               .hub_addr = dev_addr, | ||||
|               .hub_port = port | ||||
|             } | ||||
|           }; | ||||
|  | ||||
|           hcd_event_handler(&event, true); | ||||
|         } | ||||
|       } | ||||
|       hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete); | ||||
|       break; | ||||
|     } | ||||
|     // NOTE: next status transfer is queued by usbh.c after handling this request | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     // TODO [HUB] check if hub is still plugged before polling status endpoint since failed usually mean hub unplugged | ||||
| //    TU_ASSERT ( hub_status_pipe_queue(dev_addr) ); | ||||
|   } | ||||
|  | ||||
|   // NOTE: next status transfer is queued by usbh.c after handling this request | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| @@ -239,7 +353,8 @@ void hub_close(uint8_t dev_addr) | ||||
|  | ||||
| bool hub_status_pipe_queue(uint8_t dev_addr) | ||||
| { | ||||
|   return hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true); | ||||
|   usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|   return hcd_pipe_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1, true); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -36,7 +36,7 @@ | ||||
| #ifndef _TUSB_HUB_H_ | ||||
| #define _TUSB_HUB_H_ | ||||
|  | ||||
| #include <common/tusb_common.h> | ||||
| #include "common/tusb_common.h" | ||||
| #include "usbh.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| @@ -172,9 +172,9 @@ typedef struct { | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"); | ||||
|  | ||||
| bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port); | ||||
| bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp); | ||||
| bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature); | ||||
| bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb); | ||||
| bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb); | ||||
| bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb); | ||||
| bool hub_status_pipe_queue(uint8_t dev_addr); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| @@ -182,6 +182,7 @@ bool hub_status_pipe_queue(uint8_t dev_addr); | ||||
| //--------------------------------------------------------------------+ | ||||
| void hub_init(void); | ||||
| bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length); | ||||
| bool hub_set_config(uint8_t dev_addr, uint8_t itf_num); | ||||
| bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); | ||||
| void hub_close(uint8_t dev_addr); | ||||
|  | ||||
|   | ||||
							
								
								
									
										169
									
								
								src/host/usbh.c
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								src/host/usbh.c
									
									
									
									
									
								
							| @@ -91,6 +91,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = | ||||
|       .class_code = TUSB_CLASS_HUB, | ||||
|       .init       = hub_init, | ||||
|       .open       = hub_open, | ||||
|       .set_config = hub_set_config, | ||||
|       .xfer_cb    = hub_xfer_cb, | ||||
|       .close      = hub_close | ||||
|     }, | ||||
| @@ -135,6 +136,11 @@ static bool enum_new_device(hcd_event_t* event); | ||||
| // from usbh_control.c | ||||
| extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes); | ||||
|  | ||||
| uint8_t usbh_get_rhport(uint8_t dev_addr) | ||||
| { | ||||
|   return _usbh_devices[dev_addr].rhport; | ||||
| } | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // PUBLIC API (Parameter Verification is required) | ||||
| //--------------------------------------------------------------------+ | ||||
| @@ -562,6 +568,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) | ||||
| // one device before enumerating another one. | ||||
| //--------------------------------------------------------------------+ | ||||
|  | ||||
| static bool enum_request_addr0_device_desc(void); | ||||
| static bool enum_request_set_addr(void); | ||||
|  | ||||
| static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| static bool enum_set_address_complete           (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| static bool enum_get_device_desc_complete       (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| @@ -570,6 +579,92 @@ static bool enum_get_config_desc_complete       (uint8_t dev_addr, tusb_control_ | ||||
| static bool enum_set_config_complete            (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); | ||||
| static bool parse_configuration_descriptor      (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); | ||||
|  | ||||
| static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   (void) dev_addr; (void) request; | ||||
|   TU_ASSERT(XFER_RESULT_SUCCESS == result); | ||||
|   enum_request_addr0_device_desc(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   (void) dev_addr; (void) request; | ||||
|   TU_ASSERT(XFER_RESULT_SUCCESS == result); | ||||
|   usbh_device_t* dev0 = &_usbh_devices[0]; | ||||
|  | ||||
|   enum_request_set_addr(); | ||||
|  | ||||
|   // done with hub, waiting for next data on status pipe | ||||
|   (void) hub_status_pipe_queue( dev0->hub_addr ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool enum_hub_get_status_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) | ||||
| { | ||||
|   (void) dev_addr; (void) request; | ||||
|   TU_ASSERT(XFER_RESULT_SUCCESS == result); | ||||
|   usbh_device_t* dev0 = &_usbh_devices[0]; | ||||
|  | ||||
|   hub_port_status_response_t port_status; | ||||
|   memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); | ||||
|  | ||||
|   if ( !port_status.status.connection ) | ||||
|   { | ||||
|     // device unplugged while delaying, nothing else to do, queue hub status | ||||
|     return hub_status_pipe_queue(dev_addr); | ||||
|   } | ||||
|  | ||||
|   dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : | ||||
|                 (port_status.status.low_speed ) ? TUSB_SPEED_LOW  : TUSB_SPEED_FULL; | ||||
|  | ||||
|   // Acknowledge Port Reset Change | ||||
|   if (port_status.change.reset) | ||||
|   { | ||||
|     hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete); | ||||
|   } | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
|  | ||||
| static bool enum_request_set_addr(void) | ||||
| { | ||||
|   // Set Address | ||||
|   TU_LOG2("Set Address \r\n"); | ||||
|   uint8_t const new_addr = get_new_address(); | ||||
|   TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices | ||||
|  | ||||
|   usbh_device_t* dev0    = &_usbh_devices[0]; | ||||
|   usbh_device_t* new_dev = &_usbh_devices[new_addr]; | ||||
|  | ||||
|   new_dev->rhport          = dev0->rhport; | ||||
|   new_dev->hub_addr        = dev0->hub_addr; | ||||
|   new_dev->hub_port        = dev0->hub_port; | ||||
|   new_dev->speed           = dev0->speed; | ||||
|   new_dev->connected       = 1; | ||||
|   new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; | ||||
|  | ||||
|   tusb_control_request_t const new_request = | ||||
|   { | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
|       .recipient = TUSB_REQ_RCPT_DEVICE, | ||||
|       .type      = TUSB_REQ_TYPE_STANDARD, | ||||
|       .direction = TUSB_DIR_OUT | ||||
|     }, | ||||
|     .bRequest = TUSB_REQ_SET_ADDRESS, | ||||
|     .wValue   = new_addr, | ||||
|     .wIndex   = 0, | ||||
|     .wLength  = 0 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( tuh_control_xfer(0, &new_request, NULL, enum_set_address_complete) ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool enum_new_device(hcd_event_t* event) | ||||
| { | ||||
|   usbh_device_t* dev0 = &_usbh_devices[0]; | ||||
| @@ -581,39 +676,31 @@ static bool enum_new_device(hcd_event_t* event) | ||||
|   //------------- connected/disconnected directly with roothub -------------// | ||||
|   if (dev0->hub_addr == 0) | ||||
|   { | ||||
|     // wait until device is stable. Increase this if the first 8 bytes is failed to get | ||||
|     // wait until device is stable | ||||
|     osal_task_delay(RESET_DELAY); | ||||
|  | ||||
|     // device unplugged while delaying | ||||
|     if ( !hcd_port_connect_status(dev0->rhport) ) return true; | ||||
|  | ||||
|     dev0->speed = hcd_port_speed_get( dev0->rhport ); | ||||
|  | ||||
|     enum_request_addr0_device_desc(); | ||||
|   } | ||||
| #if CFG_TUH_HUB | ||||
|   //------------- connected/disconnected via hub -------------// | ||||
|   else | ||||
|   { | ||||
|     // TODO wait for PORT reset change instead | ||||
|     // wait until device is stable | ||||
|     osal_task_delay(RESET_DELAY); | ||||
|  | ||||
|     // FIXME hub API use usbh_control_xfer | ||||
|     hub_port_status_response_t port_status; | ||||
|     TU_VERIFY_HDLR( hub_port_get_status(dev0->hub_addr, dev0->hub_port, &port_status), hub_status_pipe_queue( dev0->hub_addr) ); | ||||
|  | ||||
|     // device unplugged while delaying | ||||
|     if ( !port_status.status.connection ) return true; | ||||
|  | ||||
|     dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : | ||||
|                   (port_status.status.low_speed ) ? TUSB_SPEED_LOW  : TUSB_SPEED_FULL; | ||||
|  | ||||
|     // Acknowledge Port Reset Change | ||||
|     if (port_status.change.reset) | ||||
|     { | ||||
|       hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); | ||||
|     } | ||||
|     TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status_complete) ); | ||||
|   } | ||||
| #endif // CFG_TUH_HUB | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| static bool enum_request_addr0_device_desc(void) | ||||
| { | ||||
|   // TODO probably doesn't need to open/close each enumeration | ||||
|   TU_ASSERT( usbh_pipe_control_open(0, 8) ); | ||||
|  | ||||
| @@ -632,7 +719,7 @@ static bool enum_new_device(hcd_event_t* event) | ||||
|     .wIndex   = 0, | ||||
|     .wLength  = 8 | ||||
|   }; | ||||
|   TU_ASSERT(tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete)); | ||||
|   TU_ASSERT( tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
| @@ -663,52 +750,22 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r | ||||
|     // connected directly to roothub | ||||
|     hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor | ||||
|     osal_task_delay(RESET_DELAY); | ||||
|  | ||||
|     enum_request_set_addr(); | ||||
|   } | ||||
| #if CFG_TUH_HUB | ||||
|   else | ||||
|   { | ||||
|     // FIXME hub_port_reset use usbh_control_xfer | ||||
|     if ( hub_port_reset(dev0->hub_addr, dev0->hub_port) ) | ||||
|     { | ||||
|       osal_task_delay(RESET_DELAY); | ||||
|     // after RESET_DELAY the hub_port_reset() already complete | ||||
|     TU_ASSERT( hub_port_reset(dev0->hub_addr, dev0->hub_port, NULL) ); | ||||
|  | ||||
|       // Acknowledge Port Reset Change if Reset Successful | ||||
|       hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); | ||||
|     } | ||||
|     osal_task_delay(RESET_DELAY); | ||||
|  | ||||
|     (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe | ||||
|     // Acknowledge Port Reset Change if Reset Successful | ||||
|     TU_ASSERT( hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); | ||||
|   } | ||||
| #endif // CFG_TUH_HUB | ||||
|  | ||||
|   // Set Address | ||||
|   TU_LOG2("Set Address \r\n"); | ||||
|   uint8_t const new_addr = get_new_address(); | ||||
|   TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices | ||||
|  | ||||
|   usbh_device_t* new_dev = &_usbh_devices[new_addr]; | ||||
|   new_dev->rhport  = dev0->rhport; | ||||
|   new_dev->hub_addr = dev0->hub_addr; | ||||
|   new_dev->hub_port = dev0->hub_port; | ||||
|   new_dev->speed    = dev0->speed; | ||||
|   new_dev->connected = 1; | ||||
|   new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; | ||||
|  | ||||
|   tusb_control_request_t const new_request = | ||||
|   { | ||||
|     .bmRequestType_bit = | ||||
|     { | ||||
|       .recipient = TUSB_REQ_RCPT_DEVICE, | ||||
|       .type      = TUSB_REQ_TYPE_STANDARD, | ||||
|       .direction = TUSB_DIR_OUT | ||||
|     }, | ||||
|     .bRequest = TUSB_REQ_SET_ADDRESS, | ||||
|     .wValue   = new_addr, | ||||
|     .wIndex   = 0, | ||||
|     .wLength  = 0 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT(tuh_control_xfer(0, &new_request, NULL, enum_set_address_complete)); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -120,6 +120,8 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 | ||||
|  | ||||
| void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); | ||||
|  | ||||
| uint8_t usbh_get_rhport(uint8_t dev_addr); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|   | ||||
| @@ -97,7 +97,7 @@ typedef struct { | ||||
|     // TODO merge ep2drv here, 4-bit should be sufficient | ||||
|   }ep_status[CFG_TUH_EP_MAX][2]; | ||||
|  | ||||
| // Mutex for claiming endpoint, only needed when using with preempted RTOS | ||||
|   // Mutex for claiming endpoint, only needed when using with preempted RTOS | ||||
| #if CFG_TUSB_OS != OPT_OS_NONE | ||||
|   osal_mutex_def_t mutexdef; | ||||
|   osal_mutex_t mutex; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach