Normalize line endings
This commit is contained in:
		
							
								
								
									
										1712
									
								
								src/host/ehci/ehci.c
									
									
									
									
									
								
							
							
						
						
									
										1712
									
								
								src/host/ehci/ehci.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										294
									
								
								src/host/hcd.h
									
									
									
									
									
								
							
							
						
						
									
										294
									
								
								src/host/hcd.h
									
									
									
									
									
								
							| @@ -1,147 +1,147 @@ | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| /** \ingroup group_usbh | ||||
|  * \defgroup Group_HCD Host Controller Driver (HCD) | ||||
|  *  @{ */ | ||||
|  | ||||
| #ifndef _TUSB_HCD_H_ | ||||
| #define _TUSB_HCD_H_ | ||||
|  | ||||
| #include <common/tusb_common.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
|  //--------------------------------------------------------------------+ | ||||
| // MACRO CONSTANT TYPEDEF | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef enum | ||||
| { | ||||
|   HCD_EVENT_DEVICE_ATTACH, | ||||
|   HCD_EVENT_DEVICE_REMOVE, | ||||
|   HCD_EVENT_XFER_COMPLETE, | ||||
| } hcd_eventid_t; | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   uint8_t rhport; | ||||
|   uint8_t event_id; | ||||
|  | ||||
|   union | ||||
|   { | ||||
|     struct | ||||
|     { | ||||
|       uint8_t hub_addr; | ||||
|       uint8_t hub_port; | ||||
|     } attach, remove; | ||||
|  | ||||
|     struct | ||||
|     { | ||||
|       uint8_t ep_addr; | ||||
|       uint8_t result; | ||||
|       uint32_t len; | ||||
|     } xfer_complete; | ||||
|   }; | ||||
|  | ||||
| } hcd_event_t; | ||||
|  | ||||
| #if TUSB_OPT_HOST_ENABLED | ||||
| // Max number of endpoints per device | ||||
| enum { | ||||
|   HCD_MAX_ENDPOINT = CFG_TUSB_HOST_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID_KEYBOARD + CFG_TUH_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC + | ||||
|                      CFG_TUH_MSC*2 + CFG_TUH_CDC*3), | ||||
|  | ||||
|   HCD_MAX_XFER     = HCD_MAX_ENDPOINT*2, | ||||
| }; | ||||
|  | ||||
| //#define HCD_MAX_ENDPOINT 16 | ||||
| //#define HCD_MAX_XFER 16 | ||||
| #endif | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // HCD API | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hcd_init(void); | ||||
| void hcd_isr(uint8_t hostid); | ||||
| void hcd_int_enable (uint8_t rhport); | ||||
| void hcd_int_disable(uint8_t rhport); | ||||
|  | ||||
| // PORT API | ||||
| /// return the current connect status of roothub port | ||||
| bool hcd_port_connect_status(uint8_t hostid); | ||||
| void hcd_port_reset(uint8_t hostid); | ||||
| tusb_speed_t hcd_port_speed_get(uint8_t hostid); | ||||
|  | ||||
| // HCD closes all opened endpoints belong to this device | ||||
| void hcd_device_close(uint8_t rhport, uint8_t dev_addr); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // Event function | ||||
| //--------------------------------------------------------------------+ | ||||
| void hcd_event_handler(hcd_event_t const* event, bool in_isr); | ||||
|  | ||||
| // Helper to send device attach event | ||||
| void hcd_event_device_attach(uint8_t rhport); | ||||
|  | ||||
| // Helper to send device removal event | ||||
| void hcd_event_device_remove(uint8_t rhport); | ||||
|  | ||||
| // Helper to send USB transfer event | ||||
| void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // Endpoints API | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]); | ||||
| bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); | ||||
|  | ||||
| bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr); | ||||
| bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr); | ||||
| bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr); | ||||
|  | ||||
| // TODO merge with pipe_xfer | ||||
| bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // PIPE API | ||||
| //--------------------------------------------------------------------+ | ||||
| // TODO control xfer should be used via usbh layer | ||||
| bool hcd_pipe_queue_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes); // only queue, not transferring yet | ||||
| bool hcd_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete); | ||||
|  | ||||
| #if 0 | ||||
| tusb_error_t hcd_pipe_cancel(); | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|  | ||||
| #endif /* _TUSB_HCD_H_ */ | ||||
|  | ||||
| /// @} | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| /** \ingroup group_usbh | ||||
|  * \defgroup Group_HCD Host Controller Driver (HCD) | ||||
|  *  @{ */ | ||||
|  | ||||
| #ifndef _TUSB_HCD_H_ | ||||
| #define _TUSB_HCD_H_ | ||||
|  | ||||
| #include <common/tusb_common.h> | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
|  //--------------------------------------------------------------------+ | ||||
| // MACRO CONSTANT TYPEDEF | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef enum | ||||
| { | ||||
|   HCD_EVENT_DEVICE_ATTACH, | ||||
|   HCD_EVENT_DEVICE_REMOVE, | ||||
|   HCD_EVENT_XFER_COMPLETE, | ||||
| } hcd_eventid_t; | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   uint8_t rhport; | ||||
|   uint8_t event_id; | ||||
|  | ||||
|   union | ||||
|   { | ||||
|     struct | ||||
|     { | ||||
|       uint8_t hub_addr; | ||||
|       uint8_t hub_port; | ||||
|     } attach, remove; | ||||
|  | ||||
|     struct | ||||
|     { | ||||
|       uint8_t ep_addr; | ||||
|       uint8_t result; | ||||
|       uint32_t len; | ||||
|     } xfer_complete; | ||||
|   }; | ||||
|  | ||||
| } hcd_event_t; | ||||
|  | ||||
| #if TUSB_OPT_HOST_ENABLED | ||||
| // Max number of endpoints per device | ||||
| enum { | ||||
|   HCD_MAX_ENDPOINT = CFG_TUSB_HOST_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID_KEYBOARD + CFG_TUH_HID_MOUSE + CFG_TUSB_HOST_HID_GENERIC + | ||||
|                      CFG_TUH_MSC*2 + CFG_TUH_CDC*3), | ||||
|  | ||||
|   HCD_MAX_XFER     = HCD_MAX_ENDPOINT*2, | ||||
| }; | ||||
|  | ||||
| //#define HCD_MAX_ENDPOINT 16 | ||||
| //#define HCD_MAX_XFER 16 | ||||
| #endif | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // HCD API | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hcd_init(void); | ||||
| void hcd_isr(uint8_t hostid); | ||||
| void hcd_int_enable (uint8_t rhport); | ||||
| void hcd_int_disable(uint8_t rhport); | ||||
|  | ||||
| // PORT API | ||||
| /// return the current connect status of roothub port | ||||
| bool hcd_port_connect_status(uint8_t hostid); | ||||
| void hcd_port_reset(uint8_t hostid); | ||||
| tusb_speed_t hcd_port_speed_get(uint8_t hostid); | ||||
|  | ||||
| // HCD closes all opened endpoints belong to this device | ||||
| void hcd_device_close(uint8_t rhport, uint8_t dev_addr); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // Event function | ||||
| //--------------------------------------------------------------------+ | ||||
| void hcd_event_handler(hcd_event_t const* event, bool in_isr); | ||||
|  | ||||
| // Helper to send device attach event | ||||
| void hcd_event_device_attach(uint8_t rhport); | ||||
|  | ||||
| // Helper to send device removal event | ||||
| void hcd_event_device_remove(uint8_t rhport); | ||||
|  | ||||
| // Helper to send USB transfer event | ||||
| void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // Endpoints API | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]); | ||||
| bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); | ||||
|  | ||||
| bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr); | ||||
| bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr); | ||||
| bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr); | ||||
|  | ||||
| // TODO merge with pipe_xfer | ||||
| bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // PIPE API | ||||
| //--------------------------------------------------------------------+ | ||||
| // TODO control xfer should be used via usbh layer | ||||
| bool hcd_pipe_queue_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes); // only queue, not transferring yet | ||||
| bool hcd_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete); | ||||
|  | ||||
| #if 0 | ||||
| tusb_error_t hcd_pipe_cancel(); | ||||
| #endif | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|  | ||||
| #endif /* _TUSB_HCD_H_ */ | ||||
|  | ||||
| /// @} | ||||
|   | ||||
							
								
								
									
										500
									
								
								src/host/hub.c
									
									
									
									
									
								
							
							
						
						
									
										500
									
								
								src/host/hub.c
									
									
									
									
									
								
							| @@ -1,250 +1,250 @@ | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| #include "tusb_option.h" | ||||
|  | ||||
| #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB) | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // INCLUDE | ||||
| //--------------------------------------------------------------------+ | ||||
| #include "hub.h" | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // MACRO CONSTANT TYPEDEF | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef struct | ||||
| { | ||||
|   uint8_t itf_num; | ||||
|   uint8_t ep_status; | ||||
|   uint8_t port_number; | ||||
|   uint8_t status_change; // data from status change interrupt endpoint | ||||
| }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)]; | ||||
|  | ||||
| //OSAL_SEM_DEF(hub_enum_semaphore); | ||||
| //static osal_semaphore_handle_t hub_enum_sem_hdl; | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // HUB | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature) | ||||
| { | ||||
|   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 | ||||
|   }; | ||||
|  | ||||
|   //------------- Clear Port Feature request -------------// | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); | ||||
|  | ||||
|   //------------- Get Port Status to check if feature is cleared -------------// | ||||
|   request = (tusb_control_request_t ) { | ||||
|         .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .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 ) ); | ||||
|  | ||||
|   //------------- Check if feature is cleared -------------// | ||||
|   hub_port_status_response_t * p_port_status; | ||||
|   p_port_status = (hub_port_status_response_t *) hub_enum_buffer; | ||||
|  | ||||
|   TU_ASSERT( !tu_bit_test(p_port_status->status_change.value, feature-16)  ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port) | ||||
| { | ||||
|   enum { RESET_DELAY = 200 }; // USB specs say only 50ms but many devices require much longer | ||||
|  | ||||
|   //------------- 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 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); | ||||
|  | ||||
|   osal_task_delay(RESET_DELAY); // TODO Hub wait for Status Endpoint on Reset Change | ||||
|  | ||||
|   //------------- Get Port Status to check if port is enabled, powered and reset_change -------------// | ||||
|   request = (tusb_control_request_t ) { | ||||
|         .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .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 ) ); | ||||
|  | ||||
|   hub_port_status_response_t * p_port_status; | ||||
|   p_port_status = (hub_port_status_response_t *) hub_enum_buffer; | ||||
|  | ||||
|   TU_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status && | ||||
|               p_port_status->status_current.port_power && p_port_status->status_current.port_enable); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| // can only get the speed RIGHT AFTER hub_port_reset_subtask call | ||||
| tusb_speed_t hub_port_get_speed(void) | ||||
| { | ||||
|   hub_port_status_response_t * p_port_status = (hub_port_status_response_t *) hub_enum_buffer; | ||||
|   return (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH : | ||||
|          (p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW  : TUSB_SPEED_FULL; | ||||
| } | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // CLASS-USBH API (don't require to verify parameters) | ||||
| //--------------------------------------------------------------------+ | ||||
| void hub_init(void) | ||||
| { | ||||
|   tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(usbh_hub_t)); | ||||
| //  hub_enum_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(hub_enum_semaphore) ); | ||||
| } | ||||
|  | ||||
| bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length) | ||||
| { | ||||
|   // not support multiple TT yet | ||||
|   if ( itf_desc->bInterfaceProtocol > 1 ) return false; | ||||
|  | ||||
|   //------------- Open Interrupt Status Pipe -------------// | ||||
|   tusb_desc_endpoint_t const *ep_desc; | ||||
|   ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); | ||||
|  | ||||
|   TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType); | ||||
|   TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer); | ||||
|    | ||||
|   TU_ASSERT(hcd_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; | ||||
|  | ||||
|   (*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) | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( dev_addr, &request, hub_enum_buffer ) ); | ||||
|  | ||||
|   // only care about this field in hub descriptor | ||||
|   hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts; | ||||
|  | ||||
|   //------------- 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 | ||||
|   }; | ||||
|  | ||||
|   for(uint8_t i=1; i <= hub_data[dev_addr-1].port_number; i++) | ||||
|   { | ||||
|     request.wIndex = i; | ||||
|     TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); | ||||
|   } | ||||
|  | ||||
|   //------------- Queue the initial Status endpoint transfer -------------// | ||||
|   TU_ASSERT( hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true) ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| // is the response of interrupt endpoint polling | ||||
| #include "usbh_hcd.h" // FIXME remove | ||||
| void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) | ||||
| { | ||||
|   (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports | ||||
|   (void) ep_addr; | ||||
|  | ||||
|   usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|  | ||||
|   if ( event == XFER_RESULT_SUCCESS ) | ||||
|   { | ||||
|     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) ) | ||||
|       { | ||||
|         hcd_event_t event = | ||||
|         { | ||||
|           .rhport = _usbh_devices[dev_addr].rhport, | ||||
|           .event_id = HCD_EVENT_DEVICE_ATTACH | ||||
|         }; | ||||
|  | ||||
|         event.attach.hub_addr = dev_addr; | ||||
|         event.attach.hub_port = port; | ||||
|  | ||||
|         hcd_event_handler(&event, true); | ||||
|         break; // handle one port at a time, next port if any will be handled in the next cycle | ||||
|       } | ||||
|     } | ||||
|     // 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) ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void hub_close(uint8_t dev_addr) | ||||
| { | ||||
|   tu_memclr(&hub_data[dev_addr-1], sizeof(usbh_hub_t)); | ||||
| //  osal_semaphore_reset(hub_enum_sem_hdl); | ||||
| } | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| #include "tusb_option.h" | ||||
|  | ||||
| #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB) | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // INCLUDE | ||||
| //--------------------------------------------------------------------+ | ||||
| #include "hub.h" | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // MACRO CONSTANT TYPEDEF | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef struct | ||||
| { | ||||
|   uint8_t itf_num; | ||||
|   uint8_t ep_status; | ||||
|   uint8_t port_number; | ||||
|   uint8_t status_change; // data from status change interrupt endpoint | ||||
| }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)]; | ||||
|  | ||||
| //OSAL_SEM_DEF(hub_enum_semaphore); | ||||
| //static osal_semaphore_handle_t hub_enum_sem_hdl; | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // HUB | ||||
| //--------------------------------------------------------------------+ | ||||
| bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature) | ||||
| { | ||||
|   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 | ||||
|   }; | ||||
|  | ||||
|   //------------- Clear Port Feature request -------------// | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); | ||||
|  | ||||
|   //------------- Get Port Status to check if feature is cleared -------------// | ||||
|   request = (tusb_control_request_t ) { | ||||
|         .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .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 ) ); | ||||
|  | ||||
|   //------------- Check if feature is cleared -------------// | ||||
|   hub_port_status_response_t * p_port_status; | ||||
|   p_port_status = (hub_port_status_response_t *) hub_enum_buffer; | ||||
|  | ||||
|   TU_ASSERT( !tu_bit_test(p_port_status->status_change.value, feature-16)  ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port) | ||||
| { | ||||
|   enum { RESET_DELAY = 200 }; // USB specs say only 50ms but many devices require much longer | ||||
|  | ||||
|   //------------- 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 | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); | ||||
|  | ||||
|   osal_task_delay(RESET_DELAY); // TODO Hub wait for Status Endpoint on Reset Change | ||||
|  | ||||
|   //------------- Get Port Status to check if port is enabled, powered and reset_change -------------// | ||||
|   request = (tusb_control_request_t ) { | ||||
|         .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .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 ) ); | ||||
|  | ||||
|   hub_port_status_response_t * p_port_status; | ||||
|   p_port_status = (hub_port_status_response_t *) hub_enum_buffer; | ||||
|  | ||||
|   TU_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status && | ||||
|               p_port_status->status_current.port_power && p_port_status->status_current.port_enable); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| // can only get the speed RIGHT AFTER hub_port_reset_subtask call | ||||
| tusb_speed_t hub_port_get_speed(void) | ||||
| { | ||||
|   hub_port_status_response_t * p_port_status = (hub_port_status_response_t *) hub_enum_buffer; | ||||
|   return (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH : | ||||
|          (p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW  : TUSB_SPEED_FULL; | ||||
| } | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // CLASS-USBH API (don't require to verify parameters) | ||||
| //--------------------------------------------------------------------+ | ||||
| void hub_init(void) | ||||
| { | ||||
|   tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(usbh_hub_t)); | ||||
| //  hub_enum_sem_hdl = osal_semaphore_create( OSAL_SEM_REF(hub_enum_semaphore) ); | ||||
| } | ||||
|  | ||||
| bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length) | ||||
| { | ||||
|   // not support multiple TT yet | ||||
|   if ( itf_desc->bInterfaceProtocol > 1 ) return false; | ||||
|  | ||||
|   //------------- Open Interrupt Status Pipe -------------// | ||||
|   tusb_desc_endpoint_t const *ep_desc; | ||||
|   ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); | ||||
|  | ||||
|   TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType); | ||||
|   TU_ASSERT(TUSB_XFER_INTERRUPT == ep_desc->bmAttributes.xfer); | ||||
|    | ||||
|   TU_ASSERT(hcd_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; | ||||
|  | ||||
|   (*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) | ||||
|   }; | ||||
|  | ||||
|   TU_ASSERT( usbh_control_xfer( dev_addr, &request, hub_enum_buffer ) ); | ||||
|  | ||||
|   // only care about this field in hub descriptor | ||||
|   hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts; | ||||
|  | ||||
|   //------------- 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 | ||||
|   }; | ||||
|  | ||||
|   for(uint8_t i=1; i <= hub_data[dev_addr-1].port_number; i++) | ||||
|   { | ||||
|     request.wIndex = i; | ||||
|     TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); | ||||
|   } | ||||
|  | ||||
|   //------------- Queue the initial Status endpoint transfer -------------// | ||||
|   TU_ASSERT( hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true) ); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| // is the response of interrupt endpoint polling | ||||
| #include "usbh_hcd.h" // FIXME remove | ||||
| void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) | ||||
| { | ||||
|   (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports | ||||
|   (void) ep_addr; | ||||
|  | ||||
|   usbh_hub_t * p_hub = &hub_data[dev_addr-1]; | ||||
|  | ||||
|   if ( event == XFER_RESULT_SUCCESS ) | ||||
|   { | ||||
|     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) ) | ||||
|       { | ||||
|         hcd_event_t event = | ||||
|         { | ||||
|           .rhport = _usbh_devices[dev_addr].rhport, | ||||
|           .event_id = HCD_EVENT_DEVICE_ATTACH | ||||
|         }; | ||||
|  | ||||
|         event.attach.hub_addr = dev_addr; | ||||
|         event.attach.hub_port = port; | ||||
|  | ||||
|         hcd_event_handler(&event, true); | ||||
|         break; // handle one port at a time, next port if any will be handled in the next cycle | ||||
|       } | ||||
|     } | ||||
|     // 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) ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void hub_close(uint8_t dev_addr) | ||||
| { | ||||
|   tu_memclr(&hub_data[dev_addr-1], sizeof(usbh_hub_t)); | ||||
| //  osal_semaphore_reset(hub_enum_sem_hdl); | ||||
| } | ||||
|  | ||||
| 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); | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										388
									
								
								src/host/hub.h
									
									
									
									
									
								
							
							
						
						
									
										388
									
								
								src/host/hub.h
									
									
									
									
									
								
							| @@ -1,194 +1,194 @@ | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| /** \ingroup group_class | ||||
|  *  \defgroup ClassDriver_Hub Hub (Host only) | ||||
|  *  \details  Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether | ||||
|  *            a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed | ||||
|  *            by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application. | ||||
|  *  \note     Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub. | ||||
|  *  @{ | ||||
|  */ | ||||
|  | ||||
| #ifndef _TUSB_HUB_H_ | ||||
| #define _TUSB_HUB_H_ | ||||
|  | ||||
| #include <common/tusb_common.h> | ||||
| #include "usbh.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
| //D1...D0: Logical Power Switching Mode | ||||
| //00:  Ganged power switching (all ports’power at | ||||
| //once) | ||||
| //01:  Individual port power switching | ||||
| //1X:  Reserved. Used only on 1.0 compliant hubs | ||||
| //that implement no power switching | ||||
| //D2:  Identifies a Compound Device | ||||
| //0: Hub is not part of a compound device. | ||||
| //1: Hub is part of a compound device. | ||||
| //D4...D3: Over-current Protection Mode | ||||
| //00: Global Over-current Protection. The hub | ||||
| //reports over-current as a summation of all | ||||
| //ports’current draw, without a breakdown of | ||||
| //individual port over-current status. | ||||
| //01: Individual Port Over-current Protection. The | ||||
| //hub reports over-current on a per-port basis. | ||||
| //Each port has an over-current status. | ||||
| //1X: No Over-current Protection. This option is | ||||
| //allowed only for bus-powered hubs that do not | ||||
| //implement over-current protection. | ||||
| // | ||||
| //D6...D5: TT Think TIme | ||||
| //00:  TT requires at most 8 FS bit times of inter | ||||
| //transaction gap on a full-/low-speed | ||||
| //downstream bus. | ||||
| //01:  TT requires at most 16 FS bit times. | ||||
| //10:  TT requires at most 24 FS bit times. | ||||
| //11:  TT requires at most 32 FS bit times. | ||||
| //D7: Port Indicators Supported | ||||
| //0:  Port Indicators are not supported on its | ||||
| //downstream facing ports and the | ||||
| //PORT_INDICATOR request has no effect. | ||||
| //1:  Port Indicators are supported on its | ||||
| //downstream facing ports and the | ||||
| //PORT_INDICATOR request controls the | ||||
| //indicators. See Section 11.5.3. | ||||
| //D15...D8: Reserved | ||||
|  | ||||
| typedef struct TU_ATTR_PACKED{ | ||||
|   uint8_t  bLength           ; ///< Size of descriptor | ||||
|   uint8_t  bDescriptorType   ; ///< Other_speed_Configuration Type | ||||
|   uint8_t  bNbrPorts; | ||||
|   uint16_t wHubCharacteristics; | ||||
|   uint8_t  bPwrOn2PwrGood; | ||||
|   uint8_t  bHubContrCurrent; | ||||
|   uint8_t  DeviceRemovable; // bitmap each bit for a port (from bit1) | ||||
|   uint8_t  PortPwrCtrlMask; // just for compatibility, should be 0xff | ||||
| } descriptor_hub_desc_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct"); | ||||
|  | ||||
| enum { | ||||
|   HUB_REQUEST_GET_STATUS      = 0  , | ||||
|   HUB_REQUEST_CLEAR_FEATURE   = 1  , | ||||
|  | ||||
|   HUB_REQUEST_SET_FEATURE     = 3  , | ||||
|  | ||||
|   HUB_REQUEST_GET_DESCRIPTOR  = 6  , | ||||
|   HUB_REQUEST_SET_DESCRIPTOR  = 7  , | ||||
|   HUB_REQUEST_CLEAR_TT_BUFFER = 8  , | ||||
|   HUB_REQUEST_RESET_TT        = 9  , | ||||
|   HUB_REQUEST_GET_TT_STATE    = 10 , | ||||
|   HUB_REQUEST_STOP_TT         = 11 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0, | ||||
|   HUB_FEATURE_HUB_OVER_CURRENT_CHANGE | ||||
| }; | ||||
|  | ||||
| enum{ | ||||
|   HUB_FEATURE_PORT_CONNECTION          = 0, | ||||
|   HUB_FEATURE_PORT_ENABLE              = 1, | ||||
|   HUB_FEATURE_PORT_SUSPEND             = 2, | ||||
|   HUB_FEATURE_PORT_OVER_CURRENT        = 3, | ||||
|   HUB_FEATURE_PORT_RESET               = 4, | ||||
|  | ||||
|   HUB_FEATURE_PORT_POWER               = 8, | ||||
|   HUB_FEATURE_PORT_LOW_SPEED           = 9, | ||||
|  | ||||
|   HUB_FEATURE_PORT_CONNECTION_CHANGE   = 16, | ||||
|   HUB_FEATURE_PORT_ENABLE_CHANGE       = 17, | ||||
|   HUB_FEATURE_PORT_SUSPEND_CHANGE      = 18, | ||||
|   HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19, | ||||
|   HUB_FEATURE_PORT_RESET_CHANGE        = 20, | ||||
|   HUB_FEATURE_PORT_TEST                = 21, | ||||
|   HUB_FEATURE_PORT_INDICATOR           = 22 | ||||
| }; | ||||
|  | ||||
| // data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub) | ||||
| typedef struct { | ||||
|   union{ | ||||
|     struct TU_ATTR_PACKED { | ||||
|       uint16_t local_power_source : 1; | ||||
|       uint16_t over_current       : 1; | ||||
|       uint16_t : 14; | ||||
|     }; | ||||
|  | ||||
|     uint16_t value; | ||||
|   } status, status_change; | ||||
| } hub_status_response_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct"); | ||||
|  | ||||
| // data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num | ||||
| typedef struct { | ||||
|   union { | ||||
|     struct TU_ATTR_PACKED { | ||||
|       uint16_t connect_status             : 1; | ||||
|       uint16_t port_enable                : 1; | ||||
|       uint16_t suspend                    : 1; | ||||
|       uint16_t over_current               : 1; | ||||
|       uint16_t reset                      : 1; | ||||
|  | ||||
|       uint16_t                            : 3; | ||||
|       uint16_t port_power                 : 1; | ||||
|       uint16_t low_speed_device_attached  : 1; | ||||
|       uint16_t high_speed_device_attached : 1; | ||||
|       uint16_t port_test_mode             : 1; | ||||
|       uint16_t port_indicator_control     : 1; | ||||
|       uint16_t : 0; | ||||
|     }; | ||||
|  | ||||
|     uint16_t value; | ||||
|   } status_current, status_change; | ||||
| } hub_port_status_response_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"); | ||||
|  | ||||
| bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port); | ||||
| bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature); | ||||
| tusb_speed_t hub_port_get_speed(void); | ||||
| bool hub_status_pipe_queue(uint8_t dev_addr); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // Internal Class Driver API | ||||
| //--------------------------------------------------------------------+ | ||||
| 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); | ||||
| void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); | ||||
| void hub_close(uint8_t dev_addr); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|  | ||||
| #endif /* _TUSB_HUB_H_ */ | ||||
|  | ||||
| /** @} */ | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| /** \ingroup group_class | ||||
|  *  \defgroup ClassDriver_Hub Hub (Host only) | ||||
|  *  \details  Like most PC's OS, Hub support is completely hidden from Application. In fact, application cannot determine whether | ||||
|  *            a device is mounted directly via roothub or via a hub's port. All Hub-related procedures are performed and managed | ||||
|  *            by tinyusb stack. Unless you are trying to develop the stack itself, there are nothing else can be used by Application. | ||||
|  *  \note     Due to my laziness, only 1-level of Hub is supported. In other way, the stack cannot mount a hub via another hub. | ||||
|  *  @{ | ||||
|  */ | ||||
|  | ||||
| #ifndef _TUSB_HUB_H_ | ||||
| #define _TUSB_HUB_H_ | ||||
|  | ||||
| #include <common/tusb_common.h> | ||||
| #include "usbh.h" | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
| //D1...D0: Logical Power Switching Mode | ||||
| //00:  Ganged power switching (all ports’power at | ||||
| //once) | ||||
| //01:  Individual port power switching | ||||
| //1X:  Reserved. Used only on 1.0 compliant hubs | ||||
| //that implement no power switching | ||||
| //D2:  Identifies a Compound Device | ||||
| //0: Hub is not part of a compound device. | ||||
| //1: Hub is part of a compound device. | ||||
| //D4...D3: Over-current Protection Mode | ||||
| //00: Global Over-current Protection. The hub | ||||
| //reports over-current as a summation of all | ||||
| //ports’current draw, without a breakdown of | ||||
| //individual port over-current status. | ||||
| //01: Individual Port Over-current Protection. The | ||||
| //hub reports over-current on a per-port basis. | ||||
| //Each port has an over-current status. | ||||
| //1X: No Over-current Protection. This option is | ||||
| //allowed only for bus-powered hubs that do not | ||||
| //implement over-current protection. | ||||
| // | ||||
| //D6...D5: TT Think TIme | ||||
| //00:  TT requires at most 8 FS bit times of inter | ||||
| //transaction gap on a full-/low-speed | ||||
| //downstream bus. | ||||
| //01:  TT requires at most 16 FS bit times. | ||||
| //10:  TT requires at most 24 FS bit times. | ||||
| //11:  TT requires at most 32 FS bit times. | ||||
| //D7: Port Indicators Supported | ||||
| //0:  Port Indicators are not supported on its | ||||
| //downstream facing ports and the | ||||
| //PORT_INDICATOR request has no effect. | ||||
| //1:  Port Indicators are supported on its | ||||
| //downstream facing ports and the | ||||
| //PORT_INDICATOR request controls the | ||||
| //indicators. See Section 11.5.3. | ||||
| //D15...D8: Reserved | ||||
|  | ||||
| typedef struct TU_ATTR_PACKED{ | ||||
|   uint8_t  bLength           ; ///< Size of descriptor | ||||
|   uint8_t  bDescriptorType   ; ///< Other_speed_Configuration Type | ||||
|   uint8_t  bNbrPorts; | ||||
|   uint16_t wHubCharacteristics; | ||||
|   uint8_t  bPwrOn2PwrGood; | ||||
|   uint8_t  bHubContrCurrent; | ||||
|   uint8_t  DeviceRemovable; // bitmap each bit for a port (from bit1) | ||||
|   uint8_t  PortPwrCtrlMask; // just for compatibility, should be 0xff | ||||
| } descriptor_hub_desc_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(descriptor_hub_desc_t) == 9, "size is not correct"); | ||||
|  | ||||
| enum { | ||||
|   HUB_REQUEST_GET_STATUS      = 0  , | ||||
|   HUB_REQUEST_CLEAR_FEATURE   = 1  , | ||||
|  | ||||
|   HUB_REQUEST_SET_FEATURE     = 3  , | ||||
|  | ||||
|   HUB_REQUEST_GET_DESCRIPTOR  = 6  , | ||||
|   HUB_REQUEST_SET_DESCRIPTOR  = 7  , | ||||
|   HUB_REQUEST_CLEAR_TT_BUFFER = 8  , | ||||
|   HUB_REQUEST_RESET_TT        = 9  , | ||||
|   HUB_REQUEST_GET_TT_STATE    = 10 , | ||||
|   HUB_REQUEST_STOP_TT         = 11 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   HUB_FEATURE_HUB_LOCAL_POWER_CHANGE = 0, | ||||
|   HUB_FEATURE_HUB_OVER_CURRENT_CHANGE | ||||
| }; | ||||
|  | ||||
| enum{ | ||||
|   HUB_FEATURE_PORT_CONNECTION          = 0, | ||||
|   HUB_FEATURE_PORT_ENABLE              = 1, | ||||
|   HUB_FEATURE_PORT_SUSPEND             = 2, | ||||
|   HUB_FEATURE_PORT_OVER_CURRENT        = 3, | ||||
|   HUB_FEATURE_PORT_RESET               = 4, | ||||
|  | ||||
|   HUB_FEATURE_PORT_POWER               = 8, | ||||
|   HUB_FEATURE_PORT_LOW_SPEED           = 9, | ||||
|  | ||||
|   HUB_FEATURE_PORT_CONNECTION_CHANGE   = 16, | ||||
|   HUB_FEATURE_PORT_ENABLE_CHANGE       = 17, | ||||
|   HUB_FEATURE_PORT_SUSPEND_CHANGE      = 18, | ||||
|   HUB_FEATURE_PORT_OVER_CURRENT_CHANGE = 19, | ||||
|   HUB_FEATURE_PORT_RESET_CHANGE        = 20, | ||||
|   HUB_FEATURE_PORT_TEST                = 21, | ||||
|   HUB_FEATURE_PORT_INDICATOR           = 22 | ||||
| }; | ||||
|  | ||||
| // data in response of HUB_REQUEST_GET_STATUS, wIndex = 0 (hub) | ||||
| typedef struct { | ||||
|   union{ | ||||
|     struct TU_ATTR_PACKED { | ||||
|       uint16_t local_power_source : 1; | ||||
|       uint16_t over_current       : 1; | ||||
|       uint16_t : 14; | ||||
|     }; | ||||
|  | ||||
|     uint16_t value; | ||||
|   } status, status_change; | ||||
| } hub_status_response_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct"); | ||||
|  | ||||
| // data in response of HUB_REQUEST_GET_STATUS, wIndex = Port num | ||||
| typedef struct { | ||||
|   union { | ||||
|     struct TU_ATTR_PACKED { | ||||
|       uint16_t connect_status             : 1; | ||||
|       uint16_t port_enable                : 1; | ||||
|       uint16_t suspend                    : 1; | ||||
|       uint16_t over_current               : 1; | ||||
|       uint16_t reset                      : 1; | ||||
|  | ||||
|       uint16_t                            : 3; | ||||
|       uint16_t port_power                 : 1; | ||||
|       uint16_t low_speed_device_attached  : 1; | ||||
|       uint16_t high_speed_device_attached : 1; | ||||
|       uint16_t port_test_mode             : 1; | ||||
|       uint16_t port_indicator_control     : 1; | ||||
|       uint16_t : 0; | ||||
|     }; | ||||
|  | ||||
|     uint16_t value; | ||||
|   } status_current, status_change; | ||||
| } hub_port_status_response_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"); | ||||
|  | ||||
| bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port); | ||||
| bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature); | ||||
| tusb_speed_t hub_port_get_speed(void); | ||||
| bool hub_status_pipe_queue(uint8_t dev_addr); | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // Internal Class Driver API | ||||
| //--------------------------------------------------------------------+ | ||||
| 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); | ||||
| void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); | ||||
| void hub_close(uint8_t dev_addr); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|  | ||||
| #endif /* _TUSB_HUB_H_ */ | ||||
|  | ||||
| /** @} */ | ||||
|   | ||||
							
								
								
									
										1302
									
								
								src/host/ohci/ohci.c
									
									
									
									
									
								
							
							
						
						
									
										1302
									
								
								src/host/ohci/ohci.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,291 +1,291 @@ | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| /** \ingroup Group_HCD | ||||
|  * @{ | ||||
|  *  \defgroup OHCI | ||||
|  *  \brief OHCI driver. All documents sources mentioned here (eg section 3.5) is referring to OHCI Specs unless state otherwise | ||||
|  *  @{ */ | ||||
|  | ||||
| #ifndef _TUSB_OHCI_H_ | ||||
| #define _TUSB_OHCI_H_ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "common/tusb_common.h" | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI CONFIGURATION & CONSTANTS | ||||
| //--------------------------------------------------------------------+ | ||||
| #define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed | ||||
| #define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS) | ||||
|  | ||||
| // TODO merge OHCI with EHCI | ||||
| enum { | ||||
|   OHCI_MAX_ITD = 4 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   OHCI_PID_SETUP = 0, | ||||
|   OHCI_PID_OUT, | ||||
|   OHCI_PID_IN, | ||||
| }; | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI Data Structure | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef struct { | ||||
|   uint32_t interrupt_table[32]; | ||||
|   volatile uint16_t frame_number; | ||||
|   volatile uint16_t frame_pad; | ||||
|   volatile uint32_t done_head; | ||||
|   uint8_t reserved[116+4];  // TODO try to make use of this area if possible, extra 4 byte to make the whole struct size = 256 | ||||
| }ohci_hcca_t; // TU_ATTR_ALIGNED(256) | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" ); | ||||
|  | ||||
| typedef struct { | ||||
|   uint32_t reserved[2]; | ||||
|   volatile uint32_t next; | ||||
|   uint32_t reserved2; | ||||
| }ohci_td_item_t; | ||||
|  | ||||
|  | ||||
| typedef struct TU_ATTR_ALIGNED(16) | ||||
| { | ||||
| 	// Word 0 | ||||
| 	uint32_t used                    : 1; | ||||
| 	uint32_t index                   : 4;  // endpoint index the td belongs to, or device address in case of control xfer | ||||
|   uint32_t expected_bytes          : 13; // TODO available for hcd | ||||
|  | ||||
|   uint32_t buffer_rounding         : 1; | ||||
|   uint32_t pid                     : 2; | ||||
|   uint32_t delay_interrupt         : 3; | ||||
|   volatile uint32_t data_toggle    : 2; | ||||
|   volatile uint32_t error_count    : 2; | ||||
|   volatile uint32_t condition_code : 4; | ||||
|  | ||||
| 	// Word 1 | ||||
| 	volatile uint8_t* current_buffer_pointer; | ||||
|  | ||||
| 	// Word 2 : next TD | ||||
| 	volatile uint32_t next; | ||||
|  | ||||
| 	// Word 3 | ||||
| 	uint8_t* buffer_end; | ||||
| } ohci_gtd_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" ); | ||||
|  | ||||
| typedef struct TU_ATTR_ALIGNED(16) | ||||
| { | ||||
|   // Word 0 | ||||
| 	uint32_t dev_addr          : 7; | ||||
| 	uint32_t ep_number         : 4; | ||||
| 	uint32_t pid               : 2; // 00b from TD, 01b Out, 10b In | ||||
| 	uint32_t speed             : 1; | ||||
| 	uint32_t skip              : 1; | ||||
| 	uint32_t is_iso            : 1; | ||||
| 	uint32_t max_packet_size   : 11; | ||||
| 	      // HCD: make use of 5 reserved bits | ||||
| 	uint32_t used              : 1; | ||||
| 	uint32_t is_interrupt_xfer : 1; | ||||
| 	uint32_t is_stalled        : 1; | ||||
| 	uint32_t                   : 2; | ||||
|  | ||||
| 	// Word 1 | ||||
| 	uint32_t td_tail; | ||||
|  | ||||
| 	// Word 2 | ||||
| 	volatile union { | ||||
| 		uint32_t address; | ||||
| 		struct { | ||||
| 			uint32_t halted : 1; | ||||
| 			uint32_t toggle : 1; | ||||
| 			uint32_t : 30; | ||||
| 		}; | ||||
| 	}td_head; | ||||
|  | ||||
| 	// Word 3: next ED | ||||
| 	uint32_t next; | ||||
| } ohci_ed_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" ); | ||||
|  | ||||
| typedef struct TU_ATTR_ALIGNED(32) | ||||
| { | ||||
| 	/*---------- Word 1 ----------*/ | ||||
|   uint32_t starting_frame          : 16; | ||||
|   uint32_t                         : 5; // can be used | ||||
|   uint32_t delay_interrupt         : 3; | ||||
|   uint32_t frame_count             : 3; | ||||
|   uint32_t                         : 1; // can be used | ||||
|   volatile uint32_t condition_code : 4; | ||||
|  | ||||
| 	/*---------- Word 2 ----------*/ | ||||
| 	uint32_t buffer_page0;	// 12 lsb bits can be used | ||||
|  | ||||
| 	/*---------- Word 3 ----------*/ | ||||
| 	volatile uint32_t next; | ||||
|  | ||||
| 	/*---------- Word 4 ----------*/ | ||||
| 	uint32_t buffer_end; | ||||
|  | ||||
| 	/*---------- Word 5-8 ----------*/ | ||||
| 	volatile uint16_t offset_packetstatus[8]; | ||||
| } ochi_itd_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" ); | ||||
|  | ||||
| // structure with member alignment required from large to small | ||||
| typedef struct TU_ATTR_ALIGNED(256) | ||||
| { | ||||
|   ohci_hcca_t hcca; | ||||
|  | ||||
|   ohci_ed_t bulk_head_ed; // static bulk head (dummy) | ||||
|   ohci_ed_t period_head_ed; // static periodic list head (dummy) | ||||
|  | ||||
|   // control endpoints has reserved resources | ||||
|   struct { | ||||
|     ohci_ed_t ed; | ||||
|     ohci_gtd_t gtd; | ||||
|   }control[CFG_TUSB_HOST_DEVICE_MAX+1]; | ||||
|  | ||||
|   //  ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32 | ||||
|   ohci_ed_t ed_pool[HCD_MAX_ENDPOINT]; | ||||
|   ohci_gtd_t gtd_pool[HCD_MAX_XFER]; | ||||
|  | ||||
| } ohci_data_t; | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI Operational Register | ||||
| //--------------------------------------------------------------------+ | ||||
|  | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI Data Organization | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef volatile struct | ||||
| { | ||||
|   uint32_t revision; | ||||
|  | ||||
|   union { | ||||
|     uint32_t control; | ||||
|     struct { | ||||
|       uint32_t control_bulk_service_ratio : 2; | ||||
|       uint32_t periodic_list_enable       : 1; | ||||
|       uint32_t isochronous_enable         : 1; | ||||
|       uint32_t control_list_enable        : 1; | ||||
|       uint32_t bulk_list_enable           : 1; | ||||
|       uint32_t hc_functional_state        : 2; | ||||
|       uint32_t interrupt_routing          : 1; | ||||
|       uint32_t remote_wakeup_connected    : 1; | ||||
|       uint32_t remote_wakeup_enale        : 1; | ||||
|       uint32_t : 0; | ||||
|     }control_bit; | ||||
|   }; | ||||
|  | ||||
|   union { | ||||
|     uint32_t command_status; | ||||
|     struct { | ||||
|       uint32_t controller_reset         : 1; | ||||
|       uint32_t control_list_filled      : 1; | ||||
|       uint32_t bulk_list_filled         : 1; | ||||
|       uint32_t ownership_change_request : 1; | ||||
|       uint32_t                          : 12; | ||||
|       uint32_t scheduling_overrun_count : 2; | ||||
|     }command_status_bit; | ||||
|   }; | ||||
|  | ||||
|   uint32_t interrupt_status; | ||||
|   uint32_t interrupt_enable; | ||||
|   uint32_t interrupt_disable; | ||||
|  | ||||
|   uint32_t hcca; | ||||
|   uint32_t period_current_ed; | ||||
|   uint32_t control_head_ed; | ||||
|   uint32_t control_current_ed; | ||||
|   uint32_t bulk_head_ed; | ||||
|   uint32_t bulk_current_ed; | ||||
|   uint32_t done_head; | ||||
|  | ||||
|   uint32_t frame_interval; | ||||
|   uint32_t frame_remaining; | ||||
|   uint32_t frame_number; | ||||
|   uint32_t periodic_start; | ||||
|   uint32_t lowspeed_threshold; | ||||
|  | ||||
|   uint32_t rh_descriptorA; | ||||
|   uint32_t rh_descriptorB; | ||||
|  | ||||
|   union { | ||||
|     uint32_t rh_status; | ||||
|     struct { | ||||
|       uint32_t local_power_status            : 1; // read Local Power Status; write: Clear Global Power | ||||
|       uint32_t over_current_indicator        : 1; | ||||
|       uint32_t                               : 13; | ||||
|       uint32_t device_remote_wakeup_enable   : 1; | ||||
|       uint32_t local_power_status_change     : 1; | ||||
|       uint32_t over_current_indicator_change : 1; | ||||
|       uint32_t                               : 13; | ||||
|       uint32_t clear_remote_wakeup_enable    : 1; | ||||
|     }rh_status_bit; | ||||
|   }; | ||||
|  | ||||
|   union { | ||||
|     uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports | ||||
|     struct { | ||||
|       uint32_t current_connect_status             : 1; | ||||
|       uint32_t port_enable_status                 : 1; | ||||
|       uint32_t port_suspend_status                : 1; | ||||
|       uint32_t port_over_current_indicator        : 1; | ||||
|       uint32_t port_reset_status                  : 1; | ||||
|       uint32_t                                    : 3; | ||||
|       uint32_t port_power_status                  : 1; | ||||
|       uint32_t low_speed_device_attached          : 1; | ||||
|       uint32_t                                    : 6; | ||||
|       uint32_t connect_status_change              : 1; | ||||
|       uint32_t port_enable_status_change          : 1; | ||||
|       uint32_t port_suspend_status_change         : 1; | ||||
|       uint32_t port_over_current_indicator_change : 1; | ||||
|       uint32_t port_reset_status_change           : 1; | ||||
|       uint32_t                                    : 0; | ||||
|     }rhport_status_bit[2]; | ||||
|   }; | ||||
| }ohci_registers_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct"); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|  | ||||
| #endif /* _TUSB_OHCI_H_ */ | ||||
|  | ||||
| /** @} */ | ||||
| /** @} */ | ||||
| /*  | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2019 Ha Thach (tinyusb.org) | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  * | ||||
|  * This file is part of the TinyUSB stack. | ||||
|  */ | ||||
|  | ||||
| /** \ingroup Group_HCD | ||||
|  * @{ | ||||
|  *  \defgroup OHCI | ||||
|  *  \brief OHCI driver. All documents sources mentioned here (eg section 3.5) is referring to OHCI Specs unless state otherwise | ||||
|  *  @{ */ | ||||
|  | ||||
| #ifndef _TUSB_OHCI_H_ | ||||
| #define _TUSB_OHCI_H_ | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  extern "C" { | ||||
| #endif | ||||
|  | ||||
| #include "common/tusb_common.h" | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI CONFIGURATION & CONSTANTS | ||||
| //--------------------------------------------------------------------+ | ||||
| #define HOST_HCD_XFER_INTERRUPT // TODO interrupt is used widely, should always be enalbed | ||||
| #define OHCI_PERIODIC_LIST (defined HOST_HCD_XFER_INTERRUPT || defined HOST_HCD_XFER_ISOCHRONOUS) | ||||
|  | ||||
| // TODO merge OHCI with EHCI | ||||
| enum { | ||||
|   OHCI_MAX_ITD = 4 | ||||
| }; | ||||
|  | ||||
| enum { | ||||
|   OHCI_PID_SETUP = 0, | ||||
|   OHCI_PID_OUT, | ||||
|   OHCI_PID_IN, | ||||
| }; | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI Data Structure | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef struct { | ||||
|   uint32_t interrupt_table[32]; | ||||
|   volatile uint16_t frame_number; | ||||
|   volatile uint16_t frame_pad; | ||||
|   volatile uint32_t done_head; | ||||
|   uint8_t reserved[116+4];  // TODO try to make use of this area if possible, extra 4 byte to make the whole struct size = 256 | ||||
| }ohci_hcca_t; // TU_ATTR_ALIGNED(256) | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_hcca_t) == 256, "size is not correct" ); | ||||
|  | ||||
| typedef struct { | ||||
|   uint32_t reserved[2]; | ||||
|   volatile uint32_t next; | ||||
|   uint32_t reserved2; | ||||
| }ohci_td_item_t; | ||||
|  | ||||
|  | ||||
| typedef struct TU_ATTR_ALIGNED(16) | ||||
| { | ||||
| 	// Word 0 | ||||
| 	uint32_t used                    : 1; | ||||
| 	uint32_t index                   : 4;  // endpoint index the td belongs to, or device address in case of control xfer | ||||
|   uint32_t expected_bytes          : 13; // TODO available for hcd | ||||
|  | ||||
|   uint32_t buffer_rounding         : 1; | ||||
|   uint32_t pid                     : 2; | ||||
|   uint32_t delay_interrupt         : 3; | ||||
|   volatile uint32_t data_toggle    : 2; | ||||
|   volatile uint32_t error_count    : 2; | ||||
|   volatile uint32_t condition_code : 4; | ||||
|  | ||||
| 	// Word 1 | ||||
| 	volatile uint8_t* current_buffer_pointer; | ||||
|  | ||||
| 	// Word 2 : next TD | ||||
| 	volatile uint32_t next; | ||||
|  | ||||
| 	// Word 3 | ||||
| 	uint8_t* buffer_end; | ||||
| } ohci_gtd_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_gtd_t) == 16, "size is not correct" ); | ||||
|  | ||||
| typedef struct TU_ATTR_ALIGNED(16) | ||||
| { | ||||
|   // Word 0 | ||||
| 	uint32_t dev_addr          : 7; | ||||
| 	uint32_t ep_number         : 4; | ||||
| 	uint32_t pid               : 2; // 00b from TD, 01b Out, 10b In | ||||
| 	uint32_t speed             : 1; | ||||
| 	uint32_t skip              : 1; | ||||
| 	uint32_t is_iso            : 1; | ||||
| 	uint32_t max_packet_size   : 11; | ||||
| 	      // HCD: make use of 5 reserved bits | ||||
| 	uint32_t used              : 1; | ||||
| 	uint32_t is_interrupt_xfer : 1; | ||||
| 	uint32_t is_stalled        : 1; | ||||
| 	uint32_t                   : 2; | ||||
|  | ||||
| 	// Word 1 | ||||
| 	uint32_t td_tail; | ||||
|  | ||||
| 	// Word 2 | ||||
| 	volatile union { | ||||
| 		uint32_t address; | ||||
| 		struct { | ||||
| 			uint32_t halted : 1; | ||||
| 			uint32_t toggle : 1; | ||||
| 			uint32_t : 30; | ||||
| 		}; | ||||
| 	}td_head; | ||||
|  | ||||
| 	// Word 3: next ED | ||||
| 	uint32_t next; | ||||
| } ohci_ed_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_ed_t) == 16, "size is not correct" ); | ||||
|  | ||||
| typedef struct TU_ATTR_ALIGNED(32) | ||||
| { | ||||
| 	/*---------- Word 1 ----------*/ | ||||
|   uint32_t starting_frame          : 16; | ||||
|   uint32_t                         : 5; // can be used | ||||
|   uint32_t delay_interrupt         : 3; | ||||
|   uint32_t frame_count             : 3; | ||||
|   uint32_t                         : 1; // can be used | ||||
|   volatile uint32_t condition_code : 4; | ||||
|  | ||||
| 	/*---------- Word 2 ----------*/ | ||||
| 	uint32_t buffer_page0;	// 12 lsb bits can be used | ||||
|  | ||||
| 	/*---------- Word 3 ----------*/ | ||||
| 	volatile uint32_t next; | ||||
|  | ||||
| 	/*---------- Word 4 ----------*/ | ||||
| 	uint32_t buffer_end; | ||||
|  | ||||
| 	/*---------- Word 5-8 ----------*/ | ||||
| 	volatile uint16_t offset_packetstatus[8]; | ||||
| } ochi_itd_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ochi_itd_t) == 32, "size is not correct" ); | ||||
|  | ||||
| // structure with member alignment required from large to small | ||||
| typedef struct TU_ATTR_ALIGNED(256) | ||||
| { | ||||
|   ohci_hcca_t hcca; | ||||
|  | ||||
|   ohci_ed_t bulk_head_ed; // static bulk head (dummy) | ||||
|   ohci_ed_t period_head_ed; // static periodic list head (dummy) | ||||
|  | ||||
|   // control endpoints has reserved resources | ||||
|   struct { | ||||
|     ohci_ed_t ed; | ||||
|     ohci_gtd_t gtd; | ||||
|   }control[CFG_TUSB_HOST_DEVICE_MAX+1]; | ||||
|  | ||||
|   //  ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32 | ||||
|   ohci_ed_t ed_pool[HCD_MAX_ENDPOINT]; | ||||
|   ohci_gtd_t gtd_pool[HCD_MAX_XFER]; | ||||
|  | ||||
| } ohci_data_t; | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI Operational Register | ||||
| //--------------------------------------------------------------------+ | ||||
|  | ||||
|  | ||||
| //--------------------------------------------------------------------+ | ||||
| // OHCI Data Organization | ||||
| //--------------------------------------------------------------------+ | ||||
| typedef volatile struct | ||||
| { | ||||
|   uint32_t revision; | ||||
|  | ||||
|   union { | ||||
|     uint32_t control; | ||||
|     struct { | ||||
|       uint32_t control_bulk_service_ratio : 2; | ||||
|       uint32_t periodic_list_enable       : 1; | ||||
|       uint32_t isochronous_enable         : 1; | ||||
|       uint32_t control_list_enable        : 1; | ||||
|       uint32_t bulk_list_enable           : 1; | ||||
|       uint32_t hc_functional_state        : 2; | ||||
|       uint32_t interrupt_routing          : 1; | ||||
|       uint32_t remote_wakeup_connected    : 1; | ||||
|       uint32_t remote_wakeup_enale        : 1; | ||||
|       uint32_t : 0; | ||||
|     }control_bit; | ||||
|   }; | ||||
|  | ||||
|   union { | ||||
|     uint32_t command_status; | ||||
|     struct { | ||||
|       uint32_t controller_reset         : 1; | ||||
|       uint32_t control_list_filled      : 1; | ||||
|       uint32_t bulk_list_filled         : 1; | ||||
|       uint32_t ownership_change_request : 1; | ||||
|       uint32_t                          : 12; | ||||
|       uint32_t scheduling_overrun_count : 2; | ||||
|     }command_status_bit; | ||||
|   }; | ||||
|  | ||||
|   uint32_t interrupt_status; | ||||
|   uint32_t interrupt_enable; | ||||
|   uint32_t interrupt_disable; | ||||
|  | ||||
|   uint32_t hcca; | ||||
|   uint32_t period_current_ed; | ||||
|   uint32_t control_head_ed; | ||||
|   uint32_t control_current_ed; | ||||
|   uint32_t bulk_head_ed; | ||||
|   uint32_t bulk_current_ed; | ||||
|   uint32_t done_head; | ||||
|  | ||||
|   uint32_t frame_interval; | ||||
|   uint32_t frame_remaining; | ||||
|   uint32_t frame_number; | ||||
|   uint32_t periodic_start; | ||||
|   uint32_t lowspeed_threshold; | ||||
|  | ||||
|   uint32_t rh_descriptorA; | ||||
|   uint32_t rh_descriptorB; | ||||
|  | ||||
|   union { | ||||
|     uint32_t rh_status; | ||||
|     struct { | ||||
|       uint32_t local_power_status            : 1; // read Local Power Status; write: Clear Global Power | ||||
|       uint32_t over_current_indicator        : 1; | ||||
|       uint32_t                               : 13; | ||||
|       uint32_t device_remote_wakeup_enable   : 1; | ||||
|       uint32_t local_power_status_change     : 1; | ||||
|       uint32_t over_current_indicator_change : 1; | ||||
|       uint32_t                               : 13; | ||||
|       uint32_t clear_remote_wakeup_enable    : 1; | ||||
|     }rh_status_bit; | ||||
|   }; | ||||
|  | ||||
|   union { | ||||
|     uint32_t rhport_status[2]; // TODO NXP OHCI controller only has 2 ports | ||||
|     struct { | ||||
|       uint32_t current_connect_status             : 1; | ||||
|       uint32_t port_enable_status                 : 1; | ||||
|       uint32_t port_suspend_status                : 1; | ||||
|       uint32_t port_over_current_indicator        : 1; | ||||
|       uint32_t port_reset_status                  : 1; | ||||
|       uint32_t                                    : 3; | ||||
|       uint32_t port_power_status                  : 1; | ||||
|       uint32_t low_speed_device_attached          : 1; | ||||
|       uint32_t                                    : 6; | ||||
|       uint32_t connect_status_change              : 1; | ||||
|       uint32_t port_enable_status_change          : 1; | ||||
|       uint32_t port_suspend_status_change         : 1; | ||||
|       uint32_t port_over_current_indicator_change : 1; | ||||
|       uint32_t port_reset_status_change           : 1; | ||||
|       uint32_t                                    : 0; | ||||
|     }rhport_status_bit[2]; | ||||
|   }; | ||||
| }ohci_registers_t; | ||||
|  | ||||
| TU_VERIFY_STATIC( sizeof(ohci_registers_t) == 0x5c, "size is not correct"); | ||||
|  | ||||
| #ifdef __cplusplus | ||||
|  } | ||||
| #endif | ||||
|  | ||||
| #endif /* _TUSB_OHCI_H_ */ | ||||
|  | ||||
| /** @} */ | ||||
| /** @} */ | ||||
|   | ||||
							
								
								
									
										1352
									
								
								src/host/usbh.c
									
									
									
									
									
								
							
							
						
						
									
										1352
									
								
								src/host/usbh.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user
	 Nathan Conrad
					Nathan Conrad