From 9fea5291bfa272212d74bac0fee67d6db6272296 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 2 Jul 2013 12:01:51 +0700 Subject: [PATCH] refractor extract list_next add support for TUSB_EVENT_XFER_STALL add test for error/stall in periodic list --- .../test/host/ehci/test_pipe_control_xfer.c | 10 ++++ .../test/host/ehci/test_pipe_interrupt_xfer.c | 21 +++++++ tests/support/ehci_controller_fake.c | 55 +++++++++++++++---- tinyusb/host/ehci/ehci.c | 34 +++++++----- 4 files changed, 94 insertions(+), 26 deletions(-) diff --git a/tests/lpc18xx_43xx/test/host/ehci/test_pipe_control_xfer.c b/tests/lpc18xx_43xx/test/host/ehci/test_pipe_control_xfer.c index bb1ca6692..7ed632ad2 100644 --- a/tests/lpc18xx_43xx/test/host/ehci/test_pipe_control_xfer.c +++ b/tests/lpc18xx_43xx/test/host/ehci/test_pipe_control_xfer.c @@ -250,3 +250,13 @@ void test_control_xfer_error_isr(void) //------------- Code Under TEST -------------// ehci_controller_run_error(hostid); } + +void test_control_xfer_error_stall(void) +{ + TEST_ASSERT_STATUS( hcd_pipe_control_xfer(dev_addr, &request_get_dev_desc, xfer_data) ); + + usbh_xfer_isr_Expect(((pipe_handle_t){.dev_addr = dev_addr}), 0, TUSB_EVENT_XFER_STALLED); + + //------------- Code Under TEST -------------// + ehci_controller_run_stall(hostid); +} diff --git a/tests/lpc18xx_43xx/test/host/ehci/test_pipe_interrupt_xfer.c b/tests/lpc18xx_43xx/test/host/ehci/test_pipe_interrupt_xfer.c index d367292a8..a53db9578 100644 --- a/tests/lpc18xx_43xx/test/host/ehci/test_pipe_interrupt_xfer.c +++ b/tests/lpc18xx_43xx/test/host/ehci/test_pipe_interrupt_xfer.c @@ -234,3 +234,24 @@ void test_interrupt_xfer_complete_isr_interval_2ms(void) TEST_ASSERT_FALSE(p_tail->used); } + +void test_interrupt_xfer_error_isr(void) +{ + TEST_ASSERT_STATUS( hcd_pipe_xfer(pipe_hdl_interrupt, xfer_data, sizeof(xfer_data), true) ); + + usbh_xfer_isr_Expect(((pipe_handle_t){.dev_addr = dev_addr}), 0, TUSB_EVENT_XFER_ERROR); + + //------------- Code Under TEST -------------// + ehci_controller_run_error(hostid); +} + +//void test_interrupt_xfer_error_stall(void) +//{ +// TEST_ASSERT_STATUS( hcd_pipe_control_xfer(dev_addr, &request_get_dev_desc, xfer_data) ); +// +// usbh_xfer_isr_Expect(((pipe_handle_t){.dev_addr = dev_addr}), 0, TUSB_EVENT_XFER_STALLED); +// +// //------------- Code Under TEST -------------// +// ehci_controller_run_stall(hostid); +//} + diff --git a/tests/support/ehci_controller_fake.c b/tests/support/ehci_controller_fake.c index d3659e834..d22f8cd09 100644 --- a/tests/support/ehci_controller_fake.c +++ b/tests/support/ehci_controller_fake.c @@ -144,7 +144,23 @@ void ehci_controller_run(uint8_t hostid) hcd_isr(hostid); } -void ehci_controller_run_error(uint8_t hostid) +void complete_1st_qtd_with_error(ehci_qhd_t* p_qhd, bool halted, bool xact_err) +{ + if ( !p_qhd->qtd_overlay.halted ) + { + if(!p_qhd->qtd_overlay.next.terminate) // TODO add active check + { + ehci_qtd_t* p_qtd = (ehci_qtd_t*) align32(p_qhd->qtd_overlay.next.address); + p_qtd->active = 0; + p_qtd->halted = halted ? 1 : 0; + p_qtd->xact_err = xact_err ? 1 : 0; + + p_qhd->qtd_overlay = *p_qtd; + } + } +} + +void complete_list_with_error(uint8_t hostid, bool halted, bool xact_err) { //------------- Async List -------------// ehci_registers_t* const regs = get_operational_register(hostid); @@ -152,25 +168,42 @@ void ehci_controller_run_error(uint8_t hostid) ehci_qhd_t *p_qhd = (ehci_qhd_t*) regs->async_list_base; do { - if ( !p_qhd->qtd_overlay.halted ) - { - if(!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_qtd->babble_err = p_qtd->buffer_err = p_qtd->xact_err = 1; - p_qhd->qtd_overlay = *p_qtd; - } - } + complete_1st_qtd_with_error(p_qhd, halted, xact_err); p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); }while(p_qhd != get_async_head(hostid)); // stop if loop around + //------------- Period List -------------// + for(uint8_t i=1; i <= EHCI_FRAMELIST_SIZE; i *= 2) + { + ehci_link_t *head = get_period_head(hostid, i); + + while(!head->terminate) + { + uint32_t queue_type = head->type; + head = (ehci_link_t*) align32(head->address); + + if ( queue_type == EHCI_QUEUE_ELEMENT_QHD) + { + complete_1st_qtd_with_error((ehci_qhd_t*) head, halted, xact_err); + } + } + } regs->usb_sts = EHCI_INT_MASK_ERROR; hcd_isr(hostid); } +void ehci_controller_run_stall(uint8_t hostid) +{ + complete_list_with_error(hostid, true, false); +} + +void ehci_controller_run_error(uint8_t hostid) +{ + complete_list_with_error(hostid, true, true); +} + void ehci_controller_device_plug(uint8_t hostid, tusb_speed_t speed) { ehci_registers_t* const regs = get_operational_register(hostid); diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c index 5ef8d0250..99dfac709 100644 --- a/tinyusb/host/ehci/ehci.c +++ b/tinyusb/host/ehci/ehci.c @@ -104,10 +104,10 @@ 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 inline ehci_link_t* list_next(ehci_link_t *p_link_pointer) ATTR_PURE ATTR_ALWAYS_INLINE; 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; static tusb_error_t hcd_controller_stop(uint8_t hostid) ATTR_WARN_UNUSED_RESULT; @@ -573,7 +573,6 @@ void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms) { qhd_xfer_complete_isr(p_qhd_int, TUSB_XFER_INTERRUPT); } - next_item = p_qhd_int->next; } break; @@ -584,6 +583,8 @@ void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms) ASSERT (false, (void) 0); // TODO support hs/fs ISO break; } + + next_item = *list_next(&next_item); max_loop++; } } @@ -599,15 +600,14 @@ void xfer_error_isr(uint8_t hostid) { // current qhd has error in transaction if ( (p_qhd->device_address != 0 && p_qhd->qtd_overlay.halted) || // addr0 cannot be protocol STALL - p_qhd->qtd_overlay.buffer_err ||p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err - //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error - ) + p_qhd->qtd_overlay.buffer_err ||p_qhd->qtd_overlay.babble_err || p_qhd->qtd_overlay.xact_err ) + //p_qhd->qtd_overlay.non_hs_period_missed_uframe || p_qhd->qtd_overlay.pingstate_err TODO split transaction error { + tusb_event_t error_event; - if ( !p_qhd->qtd_overlay.buffer_err && !p_qhd->qtd_overlay.babble_err && !p_qhd->qtd_overlay.xact_err) - { // no error bits are set, endpoint is halted due to STALL handshake - - } + // no error bits are set, endpoint is halted due to STALL + error_event = ( !(p_qhd->qtd_overlay.buffer_err || p_qhd->qtd_overlay.babble_err || + p_qhd->qtd_overlay.xact_err) ) ? TUSB_EVENT_XFER_STALLED : TUSB_EVENT_XFER_ERROR; hal_debugger_breakpoint(); @@ -617,7 +617,7 @@ void xfer_error_isr(uint8_t hostid) tusb_xfer_type_t xfer_type = p_qhd->endpoint_number != 0 ? TUSB_XFER_BULK : TUSB_XFER_CONTROL; usbh_xfer_isr( qhd_create_pipe_handle(p_qhd, xfer_type), - p_qhd->class_code, TUSB_EVENT_XFER_ERROR); // call USBH callback + p_qhd->class_code, error_event); // call USBH callback } p_qhd = qhd_next(p_qhd); @@ -652,7 +652,6 @@ void hcd_isr(uint8_t hostid) if (int_status & EHCI_INT_MASK_ERROR) { - // TODO handle Queue Head halted xfer_error_isr(hostid); } @@ -920,16 +919,21 @@ 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 inline ehci_link_t* list_next(ehci_link_t *p_link_pointer) +{ + return (ehci_link_t*) align32(p_link_pointer->address); +} + static ehci_link_t* list_find_previous_item(ehci_link_t* p_head, ehci_link_t* p_current) { 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 && + while( (align32(p_prev->address) != (uint32_t) p_head) && // not loop around + (align32(p_prev->address) != (uint32_t) p_current) && // not found yet + !p_prev->terminate && // not advancable max_loop < EHCI_MAX_QHD) { - p_prev = (ehci_link_t*) align32(p_prev->address); + p_prev = list_next(p_prev); max_loop++; }