separate fake ehci's run async & period list
refractor list_find_previous_item & list_remove_qhd to act on ehci_link_t* instead of ehci_qhd_t* fully support 1ms, 2ms, 4ms, 8ms for period list (each list has a dummy queue head) - change period list structure limit the maximum polling interval to 256 ms add max_loop static MAX number of iteration for list_find_previous_item add test for close 256ms polling interrupt
This commit is contained in:
		| @@ -53,55 +53,55 @@ static const struct { | ||||
| // MIC2555 1YML = 0101111, 0YML = 0101101 | ||||
| #define MIC255_ADDR BIN8(0101111) | ||||
|  | ||||
| static uint8_t mic255_regs_read(uint8_t regs_addr) | ||||
| { | ||||
|   uint8_t value; | ||||
| //static uint8_t mic255_regs_read(uint8_t regs_addr) | ||||
| //{ | ||||
| //  uint8_t value; | ||||
| // | ||||
| //  ASSERT( SUCCESS == I2C_MasterTransferData( | ||||
| //      LPC_I2C0, | ||||
| //      & (I2C_M_SETUP_Type) | ||||
| //      { | ||||
| //        .sl_addr7bit         = MIC255_ADDR, | ||||
| //        .retransmissions_max = 3, | ||||
| // | ||||
| //        .tx_data             = ®s_addr, | ||||
| //        .tx_length           = 1, | ||||
| // | ||||
| //        .rx_data             = &value, | ||||
| //        .rx_length           = 1 | ||||
| //      }, | ||||
| //      I2C_TRANSFER_POLLING), 0xFF); | ||||
| // | ||||
| //  return value; | ||||
| //} | ||||
|  | ||||
|   ASSERT( SUCCESS == I2C_MasterTransferData( | ||||
|       LPC_I2C0, | ||||
|       & (I2C_M_SETUP_Type) | ||||
|       { | ||||
|         .sl_addr7bit         = MIC255_ADDR, | ||||
|         .retransmissions_max = 3, | ||||
|  | ||||
|         .tx_data             = ®s_addr, | ||||
|         .tx_length           = 1, | ||||
|  | ||||
|         .rx_data             = &value, | ||||
|         .rx_length           = 1 | ||||
|       }, | ||||
|       I2C_TRANSFER_POLLING), 0xFF); | ||||
|  | ||||
|   return value; | ||||
| } | ||||
|  | ||||
| static bool mic255_regs_write(uint8_t regs_addr, uint8_t data) | ||||
| { | ||||
|   uint8_t xfer_data[2] = { regs_addr, data} ; | ||||
|  | ||||
|   ASSERT( SUCCESS == I2C_MasterTransferData( | ||||
|       LPC_I2C0, | ||||
|       & (I2C_M_SETUP_Type) | ||||
|       { | ||||
|         .sl_addr7bit         = MIC255_ADDR, | ||||
|         .retransmissions_max = 3, | ||||
|  | ||||
|         .tx_data             = xfer_data, | ||||
|         .tx_length           = 2, | ||||
|       }, | ||||
|       I2C_TRANSFER_POLLING), false); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
| //static bool mic255_regs_write(uint8_t regs_addr, uint8_t data) | ||||
| //{ | ||||
| //  uint8_t xfer_data[2] = { regs_addr, data} ; | ||||
| // | ||||
| //  ASSERT( SUCCESS == I2C_MasterTransferData( | ||||
| //      LPC_I2C0, | ||||
| //      & (I2C_M_SETUP_Type) | ||||
| //      { | ||||
| //        .sl_addr7bit         = MIC255_ADDR, | ||||
| //        .retransmissions_max = 3, | ||||
| // | ||||
| //        .tx_data             = xfer_data, | ||||
| //        .tx_length           = 2, | ||||
| //      }, | ||||
| //      I2C_TRANSFER_POLLING), false); | ||||
| // | ||||
| //  return true; | ||||
| //} | ||||
|  | ||||
|  | ||||
| static uint16_t mic255_get_vendorid(void) | ||||
| { | ||||
|   uint8_t vendor_low  = mic255_regs_read(0); | ||||
|   uint8_t vendor_high = mic255_regs_read(1); | ||||
|  | ||||
|   return (vendor_high << 8) | vendor_low; | ||||
| } | ||||
| //static uint16_t mic255_get_vendorid(void) | ||||
| //{ | ||||
| //  uint8_t vendor_low  = mic255_regs_read(0); | ||||
| //  uint8_t vendor_high = mic255_regs_read(1); | ||||
| // | ||||
| //  return (vendor_high << 8) | vendor_low; | ||||
| //} | ||||
|  | ||||
| void board_init(void) | ||||
| { | ||||
|   | ||||
| @@ -107,7 +107,7 @@ void test_hcd_init_async_list(void) | ||||
|  | ||||
|     TEST_ASSERT_EQUAL_HEX(async_head, regs->async_list_base); | ||||
|  | ||||
|     TEST_ASSERT_EQUAL_HEX(async_head, align32(async_head) ); | ||||
|     TEST_ASSERT_EQUAL_HEX(async_head, align32( (uint32_t) async_head) ); | ||||
|     TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, async_head->next.type); | ||||
|     TEST_ASSERT_FALSE(async_head->next.terminate); | ||||
|  | ||||
| @@ -136,20 +136,21 @@ void test_hcd_init_period_list(void) | ||||
|  | ||||
|     TEST_ASSERT_EQUAL_HEX( (uint32_t) framelist, regs->periodic_list_base); | ||||
|  | ||||
|     check_qhd_endpoint_link( framelist+1,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+3,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+5,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+7,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+0,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+2,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+4,  period_head_arr+1); | ||||
|     check_qhd_endpoint_link( framelist+6,  period_head_arr+1); | ||||
|  | ||||
|     check_qhd_endpoint_link( framelist+2,  period_head_arr+2); | ||||
|     check_qhd_endpoint_link( framelist+6,  period_head_arr+2); | ||||
|     check_qhd_endpoint_link( framelist+1,  period_head_arr+2); | ||||
|     check_qhd_endpoint_link( framelist+5,  period_head_arr+2); | ||||
|  | ||||
|     check_qhd_endpoint_link( framelist,  period_head_arr); | ||||
|     check_qhd_endpoint_link( framelist+4,  period_head_arr); | ||||
|     check_qhd_endpoint_link( framelist+3,  period_head_arr+3); | ||||
|     check_qhd_endpoint_link( framelist+7,  period_head_arr); | ||||
|     check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+1),  period_head_arr); | ||||
|     check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+2),  period_head_arr); | ||||
|     check_qhd_endpoint_link( (ehci_link_t*) (period_head_arr+3),  period_head_arr); | ||||
|  | ||||
|     for(uint32_t i=0; i<3; i++) | ||||
|     for(uint32_t i=0; i<4; i++) | ||||
|     { | ||||
|       TEST_ASSERT(period_head_arr[i].interrupt_smask); | ||||
|       TEST_ASSERT(period_head_arr[i].qtd_overlay.halted); | ||||
|   | ||||
| @@ -263,7 +263,7 @@ void test_open_interrupt_hs_interval_7(void) | ||||
| void test_open_interrupt_hs_interval_8(void) | ||||
| { | ||||
|   tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out; | ||||
|   int_edp_interval.bInterval = 8; | ||||
|   int_edp_interval.bInterval = 16; | ||||
|  | ||||
|   //------------- Code Under TEST -------------// | ||||
|   pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID); | ||||
| @@ -327,6 +327,23 @@ void test_interrupt_close(void) | ||||
|   TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_int_qhd->next.type); | ||||
| } | ||||
|  | ||||
| void test_interrupt_256ms_close(void) | ||||
| { | ||||
|   tusb_descriptor_endpoint_t int_edp_interval = desc_ept_interrupt_out; | ||||
|   int_edp_interval.bInterval = 9; | ||||
|  | ||||
|   pipe_hdl = hcd_pipe_open(dev_addr, &int_edp_interval, TUSB_CLASS_HID); | ||||
|   p_int_qhd = qhd_get_from_pipe_handle(pipe_hdl); | ||||
|  | ||||
|   //------------- Code Under TEST -------------// | ||||
|   hcd_pipe_close(pipe_hdl); | ||||
|  | ||||
|   TEST_ASSERT(p_int_qhd->is_removing); | ||||
|   TEST_ASSERT( align32(get_period_head(hostid, 8)->address) != (uint32_t) p_int_qhd ); | ||||
|   TEST_ASSERT_EQUAL_HEX( (uint32_t) get_period_head(hostid, 8), align32(p_int_qhd->next.address ) ); | ||||
|   TEST_ASSERT_EQUAL(EHCI_QUEUE_ELEMENT_QHD, p_int_qhd->next.type); | ||||
| } | ||||
|  | ||||
| uint8_t count_set_bits(uint8_t x) | ||||
| { | ||||
|   uint8_t result = 0; | ||||
|   | ||||
| @@ -88,42 +88,58 @@ void ehci_controller_control_xfer_proceed(uint8_t dev_addr, uint8_t p_data[]) | ||||
|   hcd_isr( usbh_devices[dev_addr].core_id ); | ||||
| } | ||||
|  | ||||
| bool complete_all_qtd_in_list(ehci_qhd_t *head) | ||||
| void complete_qtd_in_qhd(ehci_qhd_t *p_qhd) | ||||
| { | ||||
|   if ( !p_qhd->qtd_overlay.halted ) | ||||
|   { | ||||
|     while(!p_qhd->qtd_overlay.next.terminate) | ||||
|     { | ||||
|       ehci_qtd_t* p_qtd = (ehci_qtd_t*) align32(p_qhd->qtd_overlay.next.address); | ||||
|       p_qtd->active = 0; | ||||
|       p_qhd->qtd_overlay = *p_qtd; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| bool complete_all_qtd_in_async(ehci_qhd_t *head) | ||||
| { | ||||
|   ehci_qhd_t *p_qhd = head; | ||||
|  | ||||
|   do | ||||
|   { | ||||
|     if ( !p_qhd->qtd_overlay.halted ) | ||||
|     { | ||||
|       while(!p_qhd->qtd_overlay.next.terminate) | ||||
|       { | ||||
|         ehci_qtd_t* p_qtd = (ehci_qtd_t*) align32(p_qhd->qtd_overlay.next.address); | ||||
|         p_qtd->active = 0; | ||||
|         p_qhd->qtd_overlay = *p_qtd; | ||||
|       } | ||||
|     } | ||||
|     if (!p_qhd->next.terminate) | ||||
|     { | ||||
|       p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|       break; | ||||
|     } | ||||
|     complete_qtd_in_qhd(p_qhd); | ||||
|     p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); | ||||
|   }while(p_qhd != head); // stop if loop around | ||||
|  | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool complete_all_qtd_in_period(ehci_link_t *head) | ||||
| { | ||||
|   while(!head->terminate) | ||||
|   { | ||||
|     uint32_t queue_type = head->type; | ||||
|     head = (ehci_link_t*) align32(head->address); | ||||
|  | ||||
|     if ( queue_type == EHCI_QUEUE_ELEMENT_QHD) | ||||
|     { | ||||
|       complete_qtd_in_qhd( (ehci_qhd_t*) head ); | ||||
|     } | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| void ehci_controller_run(uint8_t hostid) | ||||
| { | ||||
|   //------------- Async List -------------// | ||||
|   ehci_registers_t* const regs = get_operational_register(hostid); | ||||
|   complete_all_qtd_in_list((ehci_qhd_t*) regs->async_list_base); | ||||
|   complete_all_qtd_in_async((ehci_qhd_t*) regs->async_list_base); | ||||
|  | ||||
|   //------------- Period List -------------// | ||||
|   complete_all_qtd_in_list( get_period_head(hostid, 1) ); | ||||
|   for(uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2) | ||||
|   { | ||||
|     complete_all_qtd_in_period( get_period_head(hostid, i) ); | ||||
|   } | ||||
|   regs->usb_sts = EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC; | ||||
|  | ||||
|   hcd_isr(hostid); | ||||
|   | ||||
| @@ -66,7 +66,7 @@ void ehci_controller_device_unplug(uint8_t hostid); | ||||
| ehci_registers_t* get_operational_register(uint8_t hostid); | ||||
| ehci_link_t* get_period_frame_list(uint8_t hostid); | ||||
| ehci_qhd_t* get_async_head(uint8_t hostid); | ||||
| ehci_qhd_t* get_period_head(uint8_t hostid, uint8_t interval_ms); | ||||
| ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms); | ||||
| ehci_qhd_t* get_control_qhd(uint8_t dev_addr); | ||||
| ehci_qtd_t* get_control_qtds(uint8_t dev_addr); | ||||
| ehci_qhd_t* qhd_get_from_pipe_handle(pipe_handle_t pipe_hdl); | ||||
|   | ||||
| @@ -98,8 +98,8 @@ static inline void           qtd_remove_1st_from_qhd(ehci_qhd_t *p_qhd) ATTR_ALW | ||||
| static void qtd_init(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes); | ||||
|  | ||||
| static inline void  list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) ATTR_ALWAYS_INLINE; | ||||
| static ehci_qhd_t*  list_find_previous_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd); | ||||
| static tusb_error_t list_remove_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd_remove); | ||||
| static ehci_link_t*  list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current); | ||||
| static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove); | ||||
|  | ||||
|  | ||||
| static tusb_error_t hcd_controller_init(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; | ||||
| @@ -181,7 +181,7 @@ static tusb_error_t hcd_controller_init(uint8_t hostid) | ||||
|   //------------- Periodic List -------------// | ||||
|   // Build the polling interval tree with 1 ms, 2 ms, 4 ms and 8 ms (framesize) only | ||||
|  | ||||
|   for(uint32_t i=0; i<3; i++) | ||||
|   for(uint32_t i=0; i<4; i++) | ||||
|   { | ||||
|     ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].interrupt_smask    = 1; // queue head in period list must have smask non-zero | ||||
|     ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ][i].qtd_overlay.halted = 1; // dummy node, always inactive | ||||
| @@ -189,12 +189,10 @@ static tusb_error_t hcd_controller_init(uint8_t hostid) | ||||
|  | ||||
|   ehci_link_t * const framelist  = get_period_frame_list(hostid); | ||||
|   ehci_link_t * const period_1ms = get_period_head(hostid, 1); | ||||
|   ehci_link_t * const period_2ms = get_period_head(hostid, 2); | ||||
|   ehci_link_t * const period_4ms = get_period_head(hostid, 4); | ||||
|  | ||||
|   // 1, 3, 5, 7 etc --> period_head_arr[2] (4ms) | ||||
|   // 2, 6 --> period_head_arr[2] | ||||
|   // 0, 4, + period_head_arr[1] + period_head_arr[2] --> period_head_arr[0] | ||||
|   // all links --> period_head_arr[0] (1ms) | ||||
|   // 0, 2, 4, 6 etc --> period_head_arr[1] (2ms) | ||||
|   // 1, 5 --> period_head_arr[2] (4ms) | ||||
|   // 3 --> period_head_arr[3] (8ms) | ||||
|  | ||||
|   // TODO EHCI_FRAMELIST_SIZE with other size than 8 | ||||
|   for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i++) | ||||
| @@ -203,16 +201,18 @@ static tusb_error_t hcd_controller_init(uint8_t hostid) | ||||
|     framelist[i].type    = EHCI_QUEUE_ELEMENT_QHD; | ||||
|   } | ||||
|  | ||||
|   for(uint32_t i=1; i<EHCI_FRAMELIST_SIZE; i+=2) | ||||
|   for(uint32_t i=0; i<EHCI_FRAMELIST_SIZE; i+=2) | ||||
|   { | ||||
|     list_insert(framelist + i, period_2ms, EHCI_QUEUE_ELEMENT_QHD); | ||||
|     list_insert(framelist + i, get_period_head(hostid, 2), EHCI_QUEUE_ELEMENT_QHD); | ||||
|   } | ||||
|  | ||||
|   for(uint32_t i=2; i<EHCI_FRAMELIST_SIZE; i+=4) | ||||
|   for(uint32_t i=1; i<EHCI_FRAMELIST_SIZE; i+=4) | ||||
|   { | ||||
|     list_insert(framelist + i, period_4ms, EHCI_QUEUE_ELEMENT_QHD); | ||||
|     list_insert(framelist + i, get_period_head(hostid, 4), EHCI_QUEUE_ELEMENT_QHD); | ||||
|   } | ||||
|  | ||||
|   list_insert(framelist+3, get_period_head(hostid, 8), EHCI_QUEUE_ELEMENT_QHD); | ||||
|  | ||||
|   period_1ms->terminate    = 1; | ||||
|  | ||||
|   regs->periodic_list_base = (uint32_t) framelist; | ||||
| @@ -336,7 +336,8 @@ tusb_error_t  hcd_pipe_control_close(uint8_t dev_addr) | ||||
|  | ||||
|   if (dev_addr != 0) | ||||
|   { | ||||
|     ASSERT_STATUS( list_remove_qhd(get_async_head( usbh_devices[dev_addr].core_id ), p_qhd) ); | ||||
|     ASSERT_STATUS( list_remove_qhd( (ehci_link_t*) get_async_head( usbh_devices[dev_addr].core_id ), | ||||
|                                     (ehci_link_t*) p_qhd) ); | ||||
|   } | ||||
|  | ||||
|   return TUSB_ERROR_NONE; | ||||
| @@ -419,11 +420,13 @@ tusb_error_t  hcd_pipe_close(pipe_handle_t pipe_hdl) | ||||
|   if ( pipe_hdl.xfer_type == TUSB_XFER_BULK ) | ||||
|   { | ||||
|     ASSERT_STATUS( list_remove_qhd( | ||||
|         get_async_head( usbh_devices[pipe_hdl.dev_addr].core_id ), p_qhd) ); | ||||
|         (ehci_link_t*) get_async_head( usbh_devices[pipe_hdl.dev_addr].core_id ), | ||||
|         (ehci_link_t*) p_qhd) ); | ||||
|   }else | ||||
|   { | ||||
|     ASSERT_STATUS( list_remove_qhd( | ||||
|         get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, 1 ), p_qhd) ); | ||||
|         get_period_head( usbh_devices[pipe_hdl.dev_addr].core_id, p_qhd->interval_ms ), | ||||
|         (ehci_link_t*) p_qhd) ); | ||||
|   } | ||||
|  | ||||
|   return TUSB_ERROR_NONE; | ||||
| @@ -517,7 +520,7 @@ void async_list_process_isr(ehci_qhd_t * const async_head) | ||||
|     } | ||||
|     p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); | ||||
|     max_loop++; | ||||
|   }while(p_qhd != async_head && max_loop <= EHCI_MAX_QHD); // async list traversal, stop if loop around | ||||
|   }while(p_qhd != async_head && max_loop < EHCI_MAX_QHD); // async list traversal, stop if loop around | ||||
|   // TODO abstract max loop guard for async | ||||
| } | ||||
|  | ||||
| @@ -697,15 +700,10 @@ STATIC_ INLINE_ ehci_qhd_t* get_async_head(uint8_t hostid) | ||||
|  | ||||
| STATIC_ INLINE_ ehci_link_t* get_period_head(uint8_t hostid, uint8_t interval_ms) | ||||
| { | ||||
|   if (interval_ms < 8) | ||||
|   { | ||||
|     return (ehci_link_t*) (ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ] + | ||||
|   return (ehci_link_t*) (ehci_data.period_head_arr[ hostid_to_data_idx(hostid) ] + | ||||
|                                 (interval_ms < 2 ? 0 : | ||||
|                                  interval_ms < 4 ? 1 : 2)); | ||||
|   }else | ||||
|   { | ||||
|     return get_period_frame_list(hostid); | ||||
|   } | ||||
|                                  interval_ms < 4 ? 1 : | ||||
|                                  interval_ms < EHCI_FRAMELIST_SIZE ? 2 : 3)); | ||||
| } | ||||
|  | ||||
| STATIC_ INLINE_ ehci_qhd_t* get_control_qhd(uint8_t dev_addr) | ||||
| @@ -811,7 +809,7 @@ static void qhd_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_si | ||||
|                                  (interval == 2) ? BIN8(10101010) : BIN8(01000100); | ||||
|       }else | ||||
|       { | ||||
|         p_qhd->interval_ms     = ( 1 << (interval-4) ); | ||||
|         p_qhd->interval_ms     = (uint8_t) min16_of( 1 << (interval-4), 255 ); | ||||
|         p_qhd->interrupt_smask = BIT_(interval % 8); | ||||
|       } | ||||
|     }else | ||||
| @@ -872,27 +870,31 @@ static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t n | ||||
|   current->address = ((uint32_t) new) | (new_type << 1); | ||||
| } | ||||
|  | ||||
| static ehci_qhd_t* list_find_previous_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd) | ||||
| static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current) | ||||
| { | ||||
|   ehci_qhd_t *p_prev_qhd = p_head; | ||||
|   while( (align32(p_prev_qhd->next.address) != (uint32_t) p_head) && (align32(p_prev_qhd->next.address) != (uint32_t) p_qhd) ) | ||||
|   ehci_link_t *p_prev = p_head; | ||||
|   uint32_t max_loop = 0; | ||||
|   while( (align32(p_prev->address) != (uint32_t) p_head) && | ||||
|          (align32(p_prev->address) != (uint32_t) p_current)  && | ||||
|          !p_prev->terminate && | ||||
|          max_loop < EHCI_MAX_QHD) | ||||
|   { | ||||
|     p_prev_qhd = (ehci_qhd_t*) align32(p_prev_qhd->next.address); | ||||
|     p_prev = (ehci_link_t*) align32(p_prev->address); | ||||
|     max_loop++; | ||||
|   } | ||||
|  | ||||
|   return  align32(p_prev_qhd->next.address) != (uint32_t) p_head ? p_prev_qhd : NULL; | ||||
|   return  (align32(p_prev->address) != (uint32_t) p_head) ? p_prev : NULL; | ||||
| } | ||||
|  | ||||
| static tusb_error_t list_remove_qhd(ehci_qhd_t* p_head, ehci_qhd_t* p_qhd_remove) | ||||
| static tusb_error_t list_remove_qhd(ehci_link_t* p_head, ehci_link_t* p_remove) | ||||
| { | ||||
|   ehci_qhd_t *p_prev_qhd = list_find_previous_qhd(p_head, p_qhd_remove); | ||||
|   ehci_link_t *p_prev = list_find_previous_item(p_head, p_remove); | ||||
|  | ||||
|   ASSERT_PTR(p_prev_qhd, TUSB_ERROR_INVALID_PARA); | ||||
|   ASSERT_PTR(p_prev, TUSB_ERROR_INVALID_PARA); | ||||
|  | ||||
|   p_prev_qhd->next.address   = p_qhd_remove->next.address; | ||||
|   p_prev->address   = p_remove->address; | ||||
|   // EHCI 4.8.2 link the removing queue head to async/period head (which always reachable by Host Controller) | ||||
|   p_qhd_remove->next.address = (uint32_t) p_head; | ||||
|   p_qhd_remove->next.type    = EHCI_QUEUE_ELEMENT_QHD; | ||||
|   p_remove->address = ((uint32_t) p_head) | (EHCI_QUEUE_ELEMENT_QHD << 1); | ||||
|  | ||||
|   return TUSB_ERROR_NONE; | ||||
| } | ||||
|   | ||||
| @@ -449,8 +449,8 @@ typedef struct { | ||||
|  | ||||
| #if EHCI_PERIODIC_LIST | ||||
|   // for NXP ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist) | ||||
|   // [0] : 1ms, [1] : 2ms, [2] : 4ms | ||||
|   ehci_qhd_t period_head_arr[CONTROLLER_HOST_NUMBER][3]; | ||||
|   // [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms | ||||
|   ehci_qhd_t period_head_arr[CONTROLLER_HOST_NUMBER][4]; | ||||
| #endif | ||||
|  | ||||
|   //------------- Data for Address 0 (use async head as its queue head) -------------// | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 hathach
					hathach