diff options
| author | hathach <[email protected]> | 2013-03-10 17:51:53 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2013-03-10 17:51:53 +0700 |
| commit | c1848b8114c178bd2b80257118c9cb5789b8e810 (patch) | |
| tree | 3dc199402e7c57ec40bd12f4693e70f8bce13bdf | |
| parent | 889f267e12f1f2d218d2d7e1124eefc2cf899774 (diff) | |
add code for ehci interrupt handler
- interrupt source identifying
- for async list process
refractor control_xfer to use insert_qtd_to_qhd
- add test for control xfer interrupt processing
- add code for faking ehci controller async list scheduling & processing
- add prototype for void usbh_isr(pipe_handle_t pipe_hdl, uint8_t class_code);
| -rw-r--r-- | tests/test/host/ehci/test_ehci_init.c | 2 | ||||
| -rw-r--r-- | tests/test/host/ehci/test_ehci_pipe.c | 2 | ||||
| -rw-r--r-- | tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c | 7 | ||||
| -rw-r--r-- | tests/test/host/ehci/test_ehci_pipe_xfer_control.c | 34 | ||||
| -rw-r--r-- | tests/test/host/ehci/test_ehci_structure.c | 2 | ||||
| -rw-r--r-- | tests/test/support/ehci_controller.c | 78 | ||||
| -rw-r--r-- | tests/test/support/ehci_controller.h | 66 | ||||
| -rw-r--r-- | tinyusb/host/ehci/ehci.c | 166 | ||||
| -rw-r--r-- | tinyusb/host/usbh_hcd.h | 7 |
9 files changed, 317 insertions, 47 deletions
diff --git a/tests/test/host/ehci/test_ehci_init.c b/tests/test/host/ehci/test_ehci_init.c index 323e89f15..4a6088cff 100644 --- a/tests/test/host/ehci/test_ehci_init.c +++ b/tests/test/host/ehci/test_ehci_init.c @@ -43,7 +43,7 @@ #include "hal.h" #include "mock_osal.h" #include "hcd.h" -#include "usbh_hcd.h" +#include "mock_usbh_hcd.h" #include "ehci.h" extern ehci_data_t ehci_data; diff --git a/tests/test/host/ehci/test_ehci_pipe.c b/tests/test/host/ehci/test_ehci_pipe.c index 85612f1b1..9e928d9fb 100644 --- a/tests/test/host/ehci/test_ehci_pipe.c +++ b/tests/test/host/ehci/test_ehci_pipe.c @@ -43,7 +43,7 @@ #include "hal.h" #include "mock_osal.h" #include "hcd.h" -#include "usbh_hcd.h" +#include "mock_usbh_hcd.h" #include "ehci.h" #include "test_ehci.h" diff --git a/tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c b/tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c index f6e6036b1..568cf1c44 100644 --- a/tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c +++ b/tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c @@ -43,7 +43,7 @@ #include "hal.h" #include "mock_osal.h" #include "hcd.h" -#include "usbh_hcd.h" +#include "mock_usbh_hcd.h" #include "ehci.h" #include "test_ehci.h" @@ -178,3 +178,8 @@ void test_bulk_xfer_double(void) //------------- list tail -------------// } + +//void test_bulk_xfer_isr(void) +//{ +// +//} diff --git a/tests/test/host/ehci/test_ehci_pipe_xfer_control.c b/tests/test/host/ehci/test_ehci_pipe_xfer_control.c index 7f3d37ead..2c54d95cd 100644 --- a/tests/test/host/ehci/test_ehci_pipe_xfer_control.c +++ b/tests/test/host/ehci/test_ehci_pipe_xfer_control.c @@ -43,9 +43,10 @@ #include "hal.h" #include "mock_osal.h" #include "hcd.h" -#include "usbh_hcd.h" +#include "mock_usbh_hcd.h" #include "ehci.h" #include "test_ehci.h" +#include "ehci_controller.h" extern ehci_data_t ehci_data; usbh_device_info_t usbh_device_info_pool[TUSB_CFG_HOST_DEVICE_MAX+1]; @@ -199,6 +200,9 @@ void test_control_xfer_get(void) TEST_ASSERT_TRUE(p_status->data_toggle); TEST_ASSERT_EQUAL(EHCI_PID_OUT, p_status->pid); TEST_ASSERT_TRUE(p_status->next.terminate); + + TEST_ASSERT_EQUAL_HEX(p_setup, p_qhd->p_qtd_list_head); + TEST_ASSERT_EQUAL_HEX(p_status, p_qhd->p_qtd_list_tail); } void test_control_xfer_set(void) @@ -227,4 +231,32 @@ void test_control_xfer_set(void) TEST_ASSERT_TRUE(p_status->data_toggle); TEST_ASSERT_EQUAL(EHCI_PID_IN, p_status->pid); TEST_ASSERT_TRUE(p_status->next.terminate); + + TEST_ASSERT_EQUAL_HEX(p_setup, p_qhd->p_qtd_list_head); + TEST_ASSERT_EQUAL_HEX(p_status, p_qhd->p_qtd_list_tail); +} + +void test_control_xfer_isr(void) +{ + ehci_qhd_t * const p_qhd = &ehci_data.device[dev_addr].control.qhd; + hcd_pipe_control_open(dev_addr, control_max_packet_size); + + hcd_pipe_control_xfer(dev_addr, &request_get_dev_desc, xfer_data); + ehci_controller_run(hostid); + + TEST_ASSERT_EQUAL_HEX(async_head, get_operational_register(hostid)->async_list_base); + TEST_ASSERT_EQUAL_HEX((uint32_t) p_qhd, align32(async_head->next.address)); + usbh_isr_Expect(((pipe_handle_t){.dev_addr = dev_addr}), 0); + + //------------- Code Under TEST -------------// + printf("control head = %x\n", p_qhd); + hcd_isr(hostid); + + TEST_ASSERT_NULL(p_qhd->p_qtd_list_head); + TEST_ASSERT_NULL(p_qhd->p_qtd_list_tail); + + TEST_ASSERT_FALSE(p_setup->used); + TEST_ASSERT_FALSE(p_data->used); + TEST_ASSERT_FALSE(p_status->used); + } diff --git a/tests/test/host/ehci/test_ehci_structure.c b/tests/test/host/ehci/test_ehci_structure.c index 0dbf2ff98..5b07f2720 100644 --- a/tests/test/host/ehci/test_ehci_structure.c +++ b/tests/test/host/ehci/test_ehci_structure.c @@ -43,7 +43,7 @@ #include "hal.h" #include "mock_osal.h" #include "hcd.h" -#include "usbh_hcd.h" +#include "mock_usbh_hcd.h" #include "ehci.h" extern ehci_data_t ehci_data; diff --git a/tests/test/support/ehci_controller.c b/tests/test/support/ehci_controller.c new file mode 100644 index 000000000..fed3c730e --- /dev/null +++ b/tests/test/support/ehci_controller.c @@ -0,0 +1,78 @@ +/* + * ehci_controller.c + * + * Created on: Mar 9, 2013 + * Author: hathach + */ + +/* + * Software License Agreement (BSD License) + * Copyright (c) 2012, hathach (tinyusb.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the tiny usb stack. + */ + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "unity.h" +#include "tusb_option.h" +#include "errors.h" +#include "binary.h" +#include "hal.h" +#include "ehci.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +extern ehci_data_t ehci_data; + +//--------------------------------------------------------------------+ +// IMPLEMENTATION +//--------------------------------------------------------------------+ +void ehci_controller_run(uint8_t hostid) +{ + //------------- Async List -------------// + ehci_registers_t* const regs = get_operational_register(hostid); + + ehci_qhd_t *p_qhd = (ehci_qhd_t*) regs->async_list_base; + 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; + } + } + p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); + }while(p_qhd != get_async_head(hostid)); // stop if loop around + //------------- Period List -------------// + + regs->usb_sts = EHCI_INT_MASK_NXP_ASYNC; +} diff --git a/tests/test/support/ehci_controller.h b/tests/test/support/ehci_controller.h new file mode 100644 index 000000000..945e8e13f --- /dev/null +++ b/tests/test/support/ehci_controller.h @@ -0,0 +1,66 @@ +/* + * ehci_controller.h + * + * Created on: Mar 10, 2013 + * Author: hathach + */ + +/* + * Software License Agreement (BSD License) + * Copyright (c) 2012, hathach (tinyusb.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the tiny usb stack. + */ + +/** \file + * \brief TBD + * + * \note TBD + */ + +/** \ingroup TBD + * \defgroup TBD + * \brief TBD + * + * @{ + */ + +#ifndef _TUSB_EHCI_CONTROLLER_H_ +#define _TUSB_EHCI_CONTROLLER_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +void ehci_controller_run(uint8_t hostid); + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_EHCI_CONTROLLER_H_ */ + +/** @} */ diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c index b147ab400..46ea67bf1 100644 --- a/tinyusb/host/ehci/ehci.c +++ b/tinyusb/host/ehci/ehci.c @@ -134,9 +134,92 @@ tusb_error_t hcd_init(void) return TUSB_ERROR_NONE; } +//--------------------------------------------------------------------+ +// EHCI Interrupt Handler +//--------------------------------------------------------------------+ +static inline uint8_t get_qhd_index(ehci_qhd_t * p_qhd) ATTR_ALWAYS_INLINE ATTR_PURE; +static inline uint8_t get_qhd_index(ehci_qhd_t * p_qhd) +{ + return p_qhd - ehci_data.device[p_qhd->device_address].qhd; +} + +void async_list_process_isr(ehci_qhd_t * const async_head, ehci_registers_t * const regs) +{ + ehci_qhd_t *p_qhd = async_head; + do + { + if ( p_qhd->qtd_overlay.halted ) + { + // TODO invoke some error callback if not async head + } else + { + // 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) + { + // TODO check halted TD + if (p_qhd->p_qtd_list_head->int_on_complete) // end of request + { + pipe_handle_t pipe_hdl = { .dev_addr = p_qhd->device_address }; + if (p_qhd->endpoint_number) // if not Control, can only be Bulk + { + pipe_hdl.xfer_type = TUSB_XFER_BULK; + pipe_hdl.index = get_qhd_index(p_qhd); + } + usbh_isr( pipe_hdl, p_qhd->class_code); // call USBH call back + } + p_qhd->p_qtd_list_head->used = 0; // free QTD + + if (p_qhd->p_qtd_list_head == p_qhd->p_qtd_list_tail) // last TD --> make it NULL + { + p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = NULL; + }else + { + p_qhd->p_qtd_list_head = (ehci_qtd_t*) align32(p_qhd->p_qtd_list_head->next.address); + } + } + } + p_qhd = (ehci_qhd_t*) align32(p_qhd->next.address); + }while(p_qhd != async_head); // stop if loop around +} + +//------------- Host Controller Driver's Interrupt Handler -------------// +// TODO this isr is not properly go through TDD void hcd_isr(uint8_t hostid) { + ehci_registers_t* const regs = get_operational_register(hostid); + + uint32_t int_status = regs->usb_sts & regs->usb_int_enable; + + if (int_status == 0) + return; + if (int_status & EHCI_INT_MASK_ERROR) + { + // TODO something going wrong + } + + //------------- some QTD/SITD/ITD with IOC set is completed -------------// + if (int_status & EHCI_INT_MASK_NXP_ASYNC) + { + async_list_process_isr(get_async_head(hostid), regs); + } + + if (int_status & EHCI_INT_MASK_NXP_PERIODIC) + { + + } + + if (int_status & EHCI_INT_MASK_PORT_CHANGE) + { + + } + + if (int_status & EHCI_INT_MASK_ASYNC_ADVANCE) + { + + } + + regs->usb_sts |= regs->usb_sts; // Acknowledge interrupt & clear it } //--------------------------------------------------------------------+ @@ -151,9 +234,10 @@ tusb_error_t hcd_controller_init(uint8_t hostid) regs->usb_int_enable = 0; // 1. disable all the interrupt regs->usb_sts = EHCI_INT_MASK_ALL; // 2. clear all status regs->usb_int_enable = - /*EHCI_INT_MASK_USB |*/ EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE | EHCI_INT_MASK_ASYNC_ADVANCE -#if 1 // TODO enable usbint olny - | EHCI_INT_MASK_NXP_ASYNC | EHCI_INT_MASK_NXP_PERIODIC + EHCI_INT_MASK_ERROR | EHCI_INT_MASK_PORT_CHANGE + | EHCI_INT_MASK_ASYNC_ADVANCE | EHCI_INT_MASK_NXP_ASYNC +#if EHCI_PERIODIC_LIST + | EHCI_INT_MASK_NXP_PERIODIC #endif ; @@ -256,7 +340,27 @@ static inline ehci_qtd_t* get_control_qtds(uint8_t dev_addr) ATTR_ALWAYS_INLINE //--------------------------------------------------------------------+ // CONTROL PIPE API //--------------------------------------------------------------------+ +// TODO subject to pure function +static void init_qtd(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes) +{ + memclr_(p_qtd, sizeof(ehci_qtd_t)); + p_qtd->used = 1; + + p_qtd->next.terminate = 1; // init to null + p_qtd->alternate.terminate = 1; // not used, always set to terminated + p_qtd->active = 1; + p_qtd->cerr = 3; // TODO 3 consecutive errors tolerance + p_qtd->data_toggle = 0; + p_qtd->total_bytes = total_bytes; + + p_qtd->buffer[0] = data_ptr; + + for(uint8_t i=1; i<5; i++) + { + p_qtd->buffer[i] |= align4k( p_qtd->buffer[i-1] ) + 4096; + } +} static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) ATTR_ALWAYS_INLINE; static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t new_type) @@ -266,6 +370,20 @@ static inline void list_insert(ehci_link_t *current, ehci_link_t *new, uint8_t n current->type = new_type; } +static inline void insert_qtd_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE; +static inline void insert_qtd_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) +{ + if (p_qhd->p_qtd_list_head == NULL) // empty list + { + p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new; + p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head; + }else + { + p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new; + p_qhd->p_qtd_list_tail = p_qtd_new; + } +} + tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) { ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); @@ -283,28 +401,6 @@ tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) return TUSB_ERROR_NONE; } -// TODO subject to pure function -static void init_qtd(ehci_qtd_t* p_qtd, uint32_t data_ptr, uint16_t total_bytes) -{ - memclr_(p_qtd, sizeof(ehci_qtd_t)); - - p_qtd->used = 1; - - p_qtd->next.terminate = 1; // init to null - p_qtd->alternate.terminate = 1; // not used, always set to terminated - p_qtd->active = 1; - p_qtd->cerr = 3; // TODO 3 consecutive errors tolerance - p_qtd->data_toggle = 0; - p_qtd->total_bytes = total_bytes; - - p_qtd->buffer[0] = data_ptr; - - for(uint8_t i=1; i<5; i++) - { - p_qtd->buffer[i] |= align4k( p_qtd->buffer[i-1] ) + 4096; - } -} - tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_std_request_t const * p_request, uint8_t data[]) { ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); @@ -317,6 +413,7 @@ tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_std_request_t const * init_qtd(p_setup, (uint32_t) p_request, 8); p_setup->pid = EHCI_PID_SETUP; p_setup->next.address = (uint32_t) p_data; + insert_qtd_to_qhd(p_qhd, p_setup); //------------- DATA Phase -------------// if (p_request->wLength > 0) @@ -324,6 +421,7 @@ tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_std_request_t const * init_qtd(p_data, (uint32_t) data, p_request->wLength); p_data->data_toggle = 1; p_data->pid = p_request->bmRequestType.direction ? EHCI_PID_IN : EHCI_PID_OUT; + insert_qtd_to_qhd(p_qhd, p_data); }else { p_data = p_setup; @@ -337,10 +435,7 @@ tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_std_request_t const * p_status->data_toggle = 1; p_status->pid = p_request->bmRequestType.direction ? EHCI_PID_OUT : EHCI_PID_IN; // reverse direction of data phase p_status->next.terminate = 1; - - //------------- hook TD List to Queue Head -------------// - p_qhd->p_qtd_list_head = p_setup; - p_qhd->qtd_overlay.next.address = (uint32_t) p_setup; + insert_qtd_to_qhd(p_qhd, p_status); return TUSB_ERROR_NONE; } @@ -398,19 +493,6 @@ pipe_handle_t hcd_pipe_open(uint8_t dev_addr, tusb_descriptor_endpoint_t const * return (pipe_handle_t) { .dev_addr = dev_addr, .xfer_type = p_endpoint_desc->bmAttributes.xfer, .index = index}; } -static inline void insert_qtd_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) ATTR_ALWAYS_INLINE; -static inline void insert_qtd_to_qhd(ehci_qhd_t *p_qhd, ehci_qtd_t *p_qtd_new) -{ - if (p_qhd->p_qtd_list_head == NULL) // empty list - { - p_qhd->p_qtd_list_head = p_qhd->p_qtd_list_tail = p_qtd_new; - p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head; - }else - { - p_qhd->p_qtd_list_tail->next.address = (uint32_t) p_qtd_new; - p_qhd->p_qtd_list_tail = p_qtd_new; - } -} tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete) diff --git a/tinyusb/host/usbh_hcd.h b/tinyusb/host/usbh_hcd.h index 7681dc560..ab4bef49b 100644 --- a/tinyusb/host/usbh_hcd.h +++ b/tinyusb/host/usbh_hcd.h @@ -60,6 +60,11 @@ //--------------------------------------------------------------------+ #include "common/common.h" +#ifdef _TEST_ +#include "hcd.h" +#include "osal.h" +#endif + //--------------------------------------------------------------------+ // USBH //--------------------------------------------------------------------+ @@ -103,6 +108,8 @@ typedef struct { // TODO internal structure, re-order members extern usbh_device_info_t usbh_device_info_pool[TUSB_CFG_HOST_DEVICE_MAX+1]; // including zero-address +void usbh_isr(pipe_handle_t pipe_hdl, uint8_t class_code); + #ifdef __cplusplus } #endif |
