Просмотр исходного кода

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

hathach 13 лет назад
Родитель
Сommit
a493fab753

+ 46 - 46
demos/bsp/boards/board_ea4357.c

@@ -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;
-
-  ASSERT( SUCCESS == I2C_MasterTransferData(
-      LPC_I2C0,
-      & (I2C_M_SETUP_Type)
-      {
-        .sl_addr7bit         = MIC255_ADDR,
-        .retransmissions_max = 3,
-
-        .tx_data             = &regs_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 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             = &regs_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 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)
 {

+ 11 - 10
tests/test/host/ehci/test_ehci_init.c

@@ -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);

+ 18 - 1
tests/test/host/ehci/test_pipe_interrupt_open.c

@@ -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;

+ 36 - 20
tests/test/support/ehci_controller.c

@@ -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);

+ 1 - 1
tests/test/support/ehci_controller.h

@@ -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);

+ 39 - 37
tinyusb/host/ehci/ehci.c

@@ -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;
 }

+ 2 - 2
tinyusb/host/ehci/ehci.h

@@ -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) -------------//