|  |  |  | @@ -99,7 +99,7 @@ static inline ehci_qhd_t*    qhd_next(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLI | 
		
	
		
			
				|  |  |  |  | static inline ehci_qhd_t*    qhd_find_free (uint8_t dev_addr) ATTR_PURE ATTR_ALWAYS_INLINE; | 
		
	
		
			
				|  |  |  |  | static inline tusb_xfer_type_t qhd_get_xfer_type(ehci_qhd_t const * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; | 
		
	
		
			
				|  |  |  |  | static inline ehci_qhd_t*  qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) ATTR_PURE ATTR_ALWAYS_INLINE; | 
		
	
		
			
				|  |  |  |  | static inline pipe_handle_t  qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) ATTR_PURE ATTR_ALWAYS_INLINE; | 
		
	
		
			
				|  |  |  |  | static inline pipe_handle_t  qhd_create_pipe_handle(ehci_qhd_t const * p_qhd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | // determine if a queue head has bus-related error | 
		
	
		
			
				|  |  |  |  | static inline bool qhd_has_xact_error(ehci_qhd_t * p_qhd) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -421,7 +421,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet | 
		
	
		
			
				|  |  |  |  | //--------------------------------------------------------------------+ | 
		
	
		
			
				|  |  |  |  | pipe_handle_t hcd_pipe_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc, uint8_t class_code) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |   pipe_handle_t const null_handle = { .dev_addr = 0, .xfer_type = 0, .index = 0 }; | 
		
	
		
			
				|  |  |  |  |   pipe_handle_t const null_handle = { .dev_addr = 0, .index = 0 }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   // TODO not support ISO yet | 
		
	
		
			
				|  |  |  |  |   if (ep_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) return null_handle; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -470,7 +470,7 @@ pipe_handle_t hcd_pipe_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint | 
		
	
		
			
				|  |  |  |  |   // TODO might need to disable async/period list | 
		
	
		
			
				|  |  |  |  |   list_insert( list_head, (ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   return (pipe_handle_t) { .dev_addr = dev_addr, .xfer_type = ep_desc->bmAttributes.xfer, .index = qhd_get_index(p_qhd) }; | 
		
	
		
			
				|  |  |  |  |   return (pipe_handle_t) { .dev_addr = dev_addr, .index = qhd_get_index(p_qhd) }; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | tusb_error_t  hcd_pipe_queue_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -512,8 +512,6 @@ tusb_error_t  hcd_pipe_close(pipe_handle_t pipe_hdl) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |   TU_ASSERT(pipe_hdl.dev_addr > 0, TUSB_ERROR_INVALID_PARA); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   TU_ASSERT(pipe_hdl.xfer_type != TUSB_XFER_ISOCHRONOUS, TUSB_ERROR_INVALID_PARA); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   ehci_qhd_t *p_qhd = qhd_get_from_pipe_handle( pipe_hdl ); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   // async list needs async advance handshake to make sure host controller has released cached data | 
		
	
	
		
			
				
					
					|  |  |  | @@ -521,7 +519,7 @@ tusb_error_t  hcd_pipe_close(pipe_handle_t pipe_hdl) | 
		
	
		
			
				|  |  |  |  |   // period list queue element is guarantee to be free in the next frame (1 ms) | 
		
	
		
			
				|  |  |  |  |   p_qhd->is_removing = 1; // TODO redundant, only apply to control queue head | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   if ( pipe_hdl.xfer_type == TUSB_XFER_BULK ) | 
		
	
		
			
				|  |  |  |  |   if ( p_qhd->xfer_type == TUSB_XFER_BULK ) | 
		
	
		
			
				|  |  |  |  |   { | 
		
	
		
			
				|  |  |  |  |     TU_ASSERT_ERR( list_remove_qhd( | 
		
	
		
			
				|  |  |  |  |         (ehci_link_t*) get_async_head( _usbh_devices[pipe_hdl.dev_addr].rhport ), | 
		
	
	
		
			
				
					
					|  |  |  | @@ -633,7 +631,6 @@ static void port_connect_status_change_isr(uint8_t hostid) | 
		
	
		
			
				|  |  |  |  | static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |   uint8_t max_loop = 0; | 
		
	
		
			
				|  |  |  |  |   tusb_xfer_type_t const xfer_type = qhd_get_xfer_type(p_qhd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   // free all TDs from the head td to the first active TD | 
		
	
		
			
				|  |  |  |  |   while(p_qhd->p_qtd_list_head != NULL && !p_qhd->p_qtd_list_head->active | 
		
	
	
		
			
				
					
					|  |  |  | @@ -646,10 +643,11 @@ static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd) | 
		
	
		
			
				|  |  |  |  |     p_qhd->p_qtd_list_head->used = 0; // free QTD | 
		
	
		
			
				|  |  |  |  |     qtd_remove_1st_from_qhd(p_qhd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     if (is_ioc) // end of request | 
		
	
		
			
				|  |  |  |  |     { // call USBH callback | 
		
	
		
			
				|  |  |  |  |       usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), XFER_RESULT_SUCCESS, | 
		
	
		
			
				|  |  |  |  |                      p_qhd->total_xferred_bytes - (xfer_type == TUSB_XFER_CONTROL ? 8 : 0) ); // subtract setup packet size if control, | 
		
	
		
			
				|  |  |  |  |     if (is_ioc) | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       // end of request | 
		
	
		
			
				|  |  |  |  |       // call USBH callback | 
		
	
		
			
				|  |  |  |  |       usbh_xfer_isr( qhd_create_pipe_handle(p_qhd), XFER_RESULT_SUCCESS, p_qhd->total_xferred_bytes); | 
		
	
		
			
				|  |  |  |  |       p_qhd->total_xferred_bytes = 0; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -728,10 +726,8 @@ static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd) | 
		
	
		
			
				|  |  |  |  |     p_qhd->p_qtd_list_head->used = 0; // free QTD | 
		
	
		
			
				|  |  |  |  |     qtd_remove_1st_from_qhd(p_qhd); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     if ( TUSB_XFER_CONTROL == xfer_type ) | 
		
	
		
			
				|  |  |  |  |     if ( 0 == p_qhd->endpoint_number ) | 
		
	
		
			
				|  |  |  |  |     { | 
		
	
		
			
				|  |  |  |  |       p_qhd->total_xferred_bytes -= tu_min8(8, p_qhd->total_xferred_bytes); // subtract setup size | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |       // control cannot be halted --> clear all qtd list | 
		
	
		
			
				|  |  |  |  |       p_qhd->p_qtd_list_head = NULL; | 
		
	
		
			
				|  |  |  |  |       p_qhd->p_qtd_list_tail = NULL; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -745,7 +741,7 @@ static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     // call USBH callback | 
		
	
		
			
				|  |  |  |  |     usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), error_event, p_qhd->total_xferred_bytes); | 
		
	
		
			
				|  |  |  |  |     usbh_xfer_isr( qhd_create_pipe_handle(p_qhd), error_event, p_qhd->total_xferred_bytes); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     p_qhd->total_xferred_bytes = 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
	
		
			
				
					
					|  |  |  | @@ -936,15 +932,14 @@ static inline ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl) | 
		
	
		
			
				|  |  |  |  |   return &ehci_data.device[ pipe_hdl.dev_addr-1 ].qhd[ pipe_hdl.index ]; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd, tusb_xfer_type_t xfer_type) | 
		
	
		
			
				|  |  |  |  | static inline pipe_handle_t qhd_create_pipe_handle(ehci_qhd_t const * p_qhd) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  |   pipe_handle_t pipe_hdl = { | 
		
	
		
			
				|  |  |  |  |       .dev_addr  = p_qhd->device_address, | 
		
	
		
			
				|  |  |  |  |       .xfer_type = xfer_type | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   // TODO Isochronous transfer support | 
		
	
		
			
				|  |  |  |  |   if (TUSB_XFER_CONTROL != xfer_type) // qhd index for control is meaningless | 
		
	
		
			
				|  |  |  |  |   if (TUSB_XFER_CONTROL != p_qhd->xfer_type) // qhd index for control is meaningless | 
		
	
		
			
				|  |  |  |  |   { | 
		
	
		
			
				|  |  |  |  |     pipe_hdl.index = qhd_get_index(p_qhd); | 
		
	
		
			
				|  |  |  |  |     pipe_hdl.ep_addr = edpt_addr(p_qhd->endpoint_number, p_qhd->pid_non_control == EHCI_PID_IN ? 1 : 0); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -1054,6 +1049,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, tusb_desc_endpoint_t c | 
		
	
		
			
				|  |  |  |  |   p_qhd->p_qtd_list_head = NULL; | 
		
	
		
			
				|  |  |  |  |   p_qhd->p_qtd_list_tail = NULL; | 
		
	
		
			
				|  |  |  |  |   p_qhd->pid_non_control = edpt_dir(ep_desc->bEndpointAddress) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint | 
		
	
		
			
				|  |  |  |  |   p_qhd->xfer_type       = xfer_type; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |   //------------- active, but no TD list -------------// | 
		
	
		
			
				|  |  |  |  |   p_qhd->qtd_overlay.halted              = 0; | 
		
	
	
		
			
				
					
					|  |  |  |   |