diff --git a/tests/test/host/ehci/test_ehci_pipe.c b/tests/test/host/ehci/test_ehci_pipe.c index a6ce8cb0..0d59bbd8 100644 --- a/tests/test/host/ehci/test_ehci_pipe.c +++ b/tests/test/host/ehci/test_ehci_pipe.c @@ -114,6 +114,7 @@ void verify_open_qhd(ehci_qhd_t *p_qhd, uint8_t endpoint_addr, uint16_t max_pack //------------- HCD -------------// TEST_ASSERT(p_qhd->used); TEST_ASSERT_NULL(p_qhd->p_qtd_list_head); + TEST_ASSERT_NULL(p_qhd->p_qtd_list_tail); } //--------------------------------------------------------------------+ 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 6a7bdf50..5ee4a04e 100644 --- a/tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c +++ b/tests/test/host/ehci/test_ehci_pipe_bulk_xfer.c @@ -59,6 +59,7 @@ uint8_t const hub_port = 2; uint8_t dev_addr; uint8_t hostid; uint8_t xfer_data [18000]; // 18K to test buffer pointer list +uint8_t data2[100]; ehci_qhd_t *async_head; ehci_qhd_t *p_qhd_bulk; @@ -128,9 +129,11 @@ void verify_qtd(ehci_qtd_t *p_qtd, uint8_t p_data[], uint16_t length) TEST_ASSERT_FALSE(p_qtd->halted); TEST_ASSERT_TRUE(p_qtd->active); + TEST_ASSERT_FALSE(p_qtd->data_toggle); TEST_ASSERT_EQUAL(3, p_qtd->cerr); TEST_ASSERT_EQUAL(0, p_qtd->current_page); TEST_ASSERT_EQUAL(length, p_qtd->total_bytes); + TEST_ASSERT_TRUE(p_qtd->used); TEST_ASSERT_EQUAL_HEX( p_data, p_qtd->buffer[0] ); for(uint8_t i=1; i<5; i++) @@ -149,24 +152,29 @@ void test_bulk_xfer(void) TEST_ASSERT_NOT_NULL(p_qtd); verify_qtd( p_qtd, xfer_data, sizeof(xfer_data)); - TEST_ASSERT_TRUE(p_qtd->used); + TEST_ASSERT_EQUAL_HEX(p_qhd_bulk->qtd_overlay.next.address, p_qtd); TEST_ASSERT_TRUE(p_qtd->next.terminate); TEST_ASSERT_EQUAL(EHCI_PID_IN, p_qtd->pid); TEST_ASSERT_TRUE(p_qtd->int_on_complete); - TEST_ASSERT_FALSE(p_qtd->data_toggle); } void test_bulk_xfer_double(void) { - uint8_t data2[100]; //------------- Code Under Test -------------// hcd_pipe_xfer(pipe_hdl_bulk, xfer_data, sizeof(xfer_data)); hcd_pipe_xfer(pipe_hdl_bulk, data2, sizeof(data2)); - ehci_qtd_t* p_qtd = p_qhd_bulk->p_qtd_list_head; - TEST_ASSERT_NOT_NULL(p_qtd); + ehci_qtd_t* p_head = p_qhd_bulk->p_qtd_list_head; + ehci_qtd_t* p_tail = p_qhd_bulk->p_qtd_list_head; - TEST_ASSERT_FALSE(p_qtd->next.terminate); + //------------- list head -------------// + TEST_ASSERT_NOT_NULL(p_head); + verify_qtd(p_head, xfer_data, sizeof(xfer_data)); + TEST_ASSERT_EQUAL_HEX(p_qhd_bulk->qtd_overlay.next.address, p_head); + TEST_ASSERT_EQUAL(EHCI_PID_IN, p_head->pid); + TEST_ASSERT_FALSE(p_head->next.terminate); + TEST_ASSERT_FALSE(p_head->int_on_complete); + //------------- list tail -------------// } diff --git a/tests/test/host/ehci/test_ehci_pipe_xfer.c b/tests/test/host/ehci/test_ehci_pipe_xfer.c index 586b8a1d..08d1d15a 100644 --- a/tests/test/host/ehci/test_ehci_pipe_xfer.c +++ b/tests/test/host/ehci/test_ehci_pipe_xfer.c @@ -162,7 +162,7 @@ void test_control_addr0_xfer_get_check_qhd_qtd_mapping(void) TEST_ASSERT_EQUAL_HEX( p_status , p_data->next.address ); TEST_ASSERT_TRUE( p_status->next.terminate ); - verify_qtd(p_setup, &ehci_data.control_request[0], 8); + verify_qtd(p_setup, &usbh_device_info_pool[0].control_request, 8); } @@ -181,7 +181,7 @@ void test_control_xfer_get(void) TEST_ASSERT_TRUE( p_status->next.terminate ); //------------- SETUP -------------// - uint8_t* p_request = (uint8_t *) &ehci_data.control_request[dev_addr]; + uint8_t* p_request = (uint8_t *) &usbh_device_info_pool[dev_addr].control_request; verify_qtd(p_setup, p_request, 8); TEST_ASSERT_EQUAL_MEMORY(&request_get_dev_desc, p_request, sizeof(tusb_std_request_t)); diff --git a/tinyusb/class/hid_host.c b/tinyusb/class/hid_host.c index 2f3107a3..5d7218ac 100644 --- a/tinyusb/class/hid_host.c +++ b/tinyusb/class/hid_host.c @@ -90,6 +90,13 @@ uint8_t tusbh_hid_keyboard_no_instances(tusb_handle_device_t const device_hdl) //--------------------------------------------------------------------+ // CLASS-USBD API (don't require to verify parameters) //--------------------------------------------------------------------+ +void hidh_init(void) +{ +#if TUSB_CFG_HOST_HID_KEYBOARD + hidh_keyboard_init(); +#endif +} + void hidh_keyboard_init(void) { memclr_(&keyboard_info_pool, sizeof(class_hid_keyboard_info_t)*TUSB_CFG_HOST_DEVICE_MAX); diff --git a/tinyusb/class/hid_host.h b/tinyusb/class/hid_host.h index 96f73cdd..6ca025fa 100644 --- a/tinyusb/class/hid_host.h +++ b/tinyusb/class/hid_host.h @@ -84,19 +84,11 @@ typedef struct { void hidh_keyboard_init(void); tusb_error_t hidh_keyboard_install(uint8_t dev_addr, uint8_t const *descriptor) ATTR_WARN_UNUSED_RESULT; -#ifndef _TEST_ -static inline void hidh_init(void) ATTR_ALWAYS_INLINE; -static inline void hidh_init(void) -{ -#if TUSB_CFG_HOST_HID_KEYBOARD - hidh_keyboard_init(); -#endif -} -#else -void hidh_init(void); -#endif - -tusb_error_t hidh_install_subtask(uint8_t dev_addr, uint8_t const *descriptor, uint16_t *p_length) ATTR_WARN_UNUSED_RESULT; +//--------------------------------------------------------------------+ +// CLASS DRIVER FUNCTION (all declared with WEAK) +//--------------------------------------------------------------------+ +void hidh_init(void) ATTR_WEAK; +tusb_error_t hidh_install_subtask(uint8_t dev_addr, uint8_t const *descriptor, uint16_t *p_length) ATTR_WEAK ATTR_WARN_UNUSED_RESULT; #endif diff --git a/tinyusb/core/tusb_types.h b/tinyusb/core/tusb_types.h index d35c3f64..4df7292c 100644 --- a/tinyusb/core/tusb_types.h +++ b/tinyusb/core/tusb_types.h @@ -136,6 +136,8 @@ typedef enum { TUSB_CLASS_PERSONAL_HEALTHCARE = 15 , ///< 15 TUSB_CLASS_AUDIO_VIDEO = 16 , ///< 16 + TUSB_CLASS_MAX_CONSEC_NUMBER = 17 , // TODO compact & minimize this number + TUSB_CLASS_DIAGNOSTIC = 0xDC , TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 , TUSB_CLASS_MISC = 0xEF , diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c index d3cf5b6a..bb12c117 100644 --- a/tinyusb/host/ehci/ehci.c +++ b/tinyusb/host/ehci/ehci.c @@ -273,10 +273,10 @@ tusb_error_t hcd_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) queue_head_init(p_qhd, dev_addr, max_packet_size, 0, TUSB_XFER_CONTROL); - //------------- insert to async list -------------// - // TODO might need to to disable async list first if (dev_addr != 0) { + //------------- insert to async list -------------// + // TODO might need to to disable async list first list_insert( (ehci_link_t*) get_async_head(usbh_device_info_pool[dev_addr].core_id), (ehci_link_t*) p_qhd, EHCI_QUEUE_ELEMENT_QHD); } @@ -351,6 +351,7 @@ tusb_error_t hcd_pipe_control_xfer(uint8_t dev_addr, tusb_std_request_t const * tusb_error_t hcd_pipe_control_close(uint8_t dev_addr) { + //------------- TODO pipe handle validate -------------// ehci_qhd_t * const p_qhd = get_control_qhd(dev_addr); p_qhd->qtd_overlay.halted = 1; @@ -400,9 +401,24 @@ 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) { - //------------- pipe handle validate -------------// + //------------- TODO pipe handle validate -------------// //------------- find a free qtd -------------// uint8_t index=0; @@ -413,16 +429,15 @@ tusb_error_t hcd_pipe_xfer(pipe_handle_t pipe_hdl, uint8_t buffer[], uint16_t t ASSERT( index < EHCI_MAX_QTD, TUSB_ERROR_EHCI_NOT_ENOUGH_QTD); //------------- set up QTD -------------// - ehci_qhd_t *p_qhd = &ehci_data.device[pipe_hdl.dev_addr].qhd[index]; - + ehci_qhd_t *p_qhd = &ehci_data.device[pipe_hdl.dev_addr].qhd[pipe_hdl.index]; ehci_qtd_t *p_qtd = &ehci_data.device[pipe_hdl.dev_addr].qtd[index]; + queue_td_init(p_qtd, (uint32_t) buffer, total_bytes); p_qtd->pid = p_qhd->pid_non_control; p_qtd->int_on_complete = 1; - - p_qhd->p_qtd_list_head = p_qtd; - p_qhd->qtd_overlay.next.address = (uint32_t) p_qtd; + //------------- insert TD to TD list -------------// + insert_qtd_to_qhd(p_qhd, p_qtd); return TUSB_ERROR_NONE; } @@ -445,7 +460,7 @@ static inline ehci_qtd_t* get_control_qtds(uint8_t dev_addr) static inline tusb_std_request_t* const get_control_request_ptr(uint8_t dev_addr) { - return &ehci_data.control_request[dev_addr]; + return &usbh_device_info_pool[dev_addr].control_request; } // TODO subject to pure function @@ -483,7 +498,8 @@ static void queue_head_init(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_pa //------------- HCD Management Data -------------// p_qhd->used = 1; - p_qhd->p_qtd_list_head = NULL; + p_qhd->p_qtd_list_head = NULL; + p_qhd->p_qtd_list_tail = NULL; p_qhd->pid_non_control = (endpoint_addr & 0x80) ? EHCI_PID_IN : EHCI_PID_OUT; // PID for TD under this endpoint } diff --git a/tinyusb/host/ehci/ehci.h b/tinyusb/host/ehci/ehci.h index cfd37c49..290d5f08 100644 --- a/tinyusb/host/ehci/ehci.h +++ b/tinyusb/host/ehci/ehci.h @@ -201,10 +201,10 @@ typedef struct { uint8_t list_index; uint8_t reserved; - ehci_qtd_t *p_qtd_list_head; // head of the TD list scheduled + ehci_qtd_t *p_qtd_list_head; // head of the scheduled TD list + ehci_qtd_t *p_qtd_list_tail; // tail of the scheduled TD list + uint32_t reserved_2; - volatile uint32_t status; // TODO will remove volatile after remove all HcdQHD function - uint16_t *pActualTransferCount; /* total transferred bytes of a usb request */ }ATTR_ALIGNED(32) ehci_qhd_t; /// Highspeed Isochronous Transfer Descriptor (section 3.3) @@ -440,8 +440,7 @@ typedef struct { ehci_qhd_t async_head[CONTROLLER_HOST_NUMBER]; /// head qhd of async list, also is used as control endpoint for address 0 ehci_qhd_t period_head[CONTROLLER_HOST_NUMBER]; - //------------- Data for Address 0 -------------// - // qhd: addr0 use async head (dummy) as Queue Head + //------------- Data for Address 0 (use async head as its queue head) -------------// ehci_qtd_t addr0_qtd[3]; struct { @@ -450,13 +449,11 @@ typedef struct { ehci_qtd_t qtd[3]; }control; - ehci_qhd_t qhd[EHCI_MAX_QHD] ; ///< Queue Head Pool - ehci_qtd_t qtd[EHCI_MAX_QTD] ; ///< Queue Element Transfer Pool -// ehci_itd_t itd[EHCI_MAX_ITD] ; ///< Iso Transfer Pool -// ehci_sitd_t sitd[EHCI_MAX_SITD] ; ///< Split (FS) Isochronous Transfer Pool + ehci_qhd_t qhd[EHCI_MAX_QHD] ; ///< Queue Head Pool + ehci_qtd_t qtd[EHCI_MAX_QTD] ATTR_ALIGNED(32) ; ///< Queue Element Transfer Pool +// ehci_itd_t itd[EHCI_MAX_ITD] ; ///< Iso Transfer Pool +// ehci_sitd_t sitd[EHCI_MAX_SITD] ; ///< Split (FS) Isochronous Transfer Pool }device[TUSB_CFG_HOST_DEVICE_MAX]; - - tusb_std_request_t control_request[TUSB_CFG_HOST_DEVICE_MAX+1]; // including address zero, 32-byte alignment breaker }ehci_data_t; #ifdef __cplusplus diff --git a/tinyusb/host/usbh.c b/tinyusb/host/usbh.c index 3c2010c0..1bef861b 100644 --- a/tinyusb/host/usbh.c +++ b/tinyusb/host/usbh.c @@ -52,11 +52,24 @@ //--------------------------------------------------------------------+ #define ENUM_QUEUE_DEPTH 5 +// TODO fix number of class driver +class_driver_t const class_host_drivers[TUSB_CLASS_MAX_CONSEC_NUMBER] = +{ + [TUSB_CLASS_HID] = { + .init = hidh_init, + .install_subtask = hidh_install_subtask + }, + + [TUSB_CLASS_MSC] = { + .init = msch_init, + .install_subtask = msch_install_subtask + } +}; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ -usbh_device_info_t usbh_device_info_pool[TUSB_CFG_HOST_DEVICE_MAX+1]; // including zero-address +usbh_device_info_t usbh_device_info_pool[TUSB_CFG_HOST_DEVICE_MAX+1] TUSB_CFG_ATTR_USBRAM; // including zero-address //------------- Enumeration Task Data -------------// OSAL_TASK_DEF(enum_task, usbh_enumeration_task, 128, OSAL_PRIO_HIGH); @@ -94,9 +107,11 @@ tusb_error_t usbh_init(void) ASSERT_PTR(enum_queue_hdl, TUSB_ERROR_OSAL_QUEUE_FAILED); //------------- class init -------------// -#if HOST_CLASS_HID - hidh_init(); -#endif + for (uint8_t class_code = 1; class_code < TUSB_CLASS_MAX_CONSEC_NUMBER; class_code++) + { + if (class_host_drivers[class_code].init) + class_host_drivers[class_code].init(); + } return TUSB_ERROR_NONE; } @@ -108,7 +123,9 @@ tusb_error_t usbh_control_xfer_subtask(uint8_t dev_addr, tusb_std_request_t cons OSAL_SUBTASK_BEGIN + usbh_device_info_pool[dev_addr].control_request = *p_request; (void) hcd_pipe_control_xfer(dev_addr, p_request, data); + osal_semaphore_wait(usbh_device_info_pool[dev_addr].sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); @@ -242,7 +259,7 @@ OSAL_TASK_DECLARE(usbh_enumeration_task) // update configuration info usbh_device_info_pool[new_addr].interface_count = ((tusb_descriptor_configuration_t*) enum_data_buffer)->bNumInterfaces; - //------------- parse configuration -------------// + //------------- parse configuration & install drivers -------------// p_desc = enum_data_buffer + sizeof(tusb_descriptor_configuration_t); // parse each interfaces @@ -250,21 +267,20 @@ OSAL_TASK_DECLARE(usbh_enumeration_task) { TASK_ASSERT( TUSB_DESC_INTERFACE == ((tusb_descriptor_interface_t*) p_desc)->bDescriptorType ); // TODO should we skip this descriptor and advance - // NOTE: cannot use switch (conflicted with OSAL_NONE task) - if (TUSB_CLASS_UNSPECIFIED == ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass) + uint8_t class_code = ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass; + if (class_code == 0) { - TASK_ASSERT( false ); // corrupted data - } -#if HOST_CLASS_HID - else if ( TUSB_CLASS_HID == ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass) + TASK_ASSERT( false ); // corrupted data, abort enumeration + } else if ( class_code < TUSB_CLASS_MAX_CONSEC_NUMBER) { - uint16_t length; - OSAL_SUBTASK_INVOKED_AND_WAIT ( hidh_install_subtask(new_addr, p_desc, &length) ); - p_desc += length; - } -#endif - // unsupported class - else + if ( class_host_drivers[class_code].install_subtask ) + { + uint16_t length; + OSAL_SUBTASK_INVOKED_AND_WAIT ( // parameters in task/sub_task must be static storage (static or global) + class_host_drivers[ ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass ].install_subtask(new_addr, p_desc, &length) ); + p_desc += length; + } + } else // unsupported class (not enable or yet implemented) { do { diff --git a/tinyusb/host/usbh.h b/tinyusb/host/usbh.h index 1f7e492c..feb13b7e 100644 --- a/tinyusb/host/usbh.h +++ b/tinyusb/host/usbh.h @@ -63,6 +63,36 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ +#define CLASS_TABLE(ENTRY_EXPANDER) \ + ENTRY_EXPANDER(TUSB_CLASS_AUDIO)\ + ENTRY_EXPANDER(TUSB_CLASS_CDC)\ + ENTRY_EXPANDER(TUSB_CLASS_HID)\ + ENTRY_EXPANDER(TUSB_CLASS_PHYSICAL)\ + ENTRY_EXPANDER(TUSB_CLASS_IMAGE)\ + ENTRY_EXPANDER(TUSB_CLASS_PRINTER)\ + ENTRY_EXPANDER(TUSB_CLASS_MSC)\ + ENTRY_EXPANDER(TUSB_CLASS_HUB)\ + ENTRY_EXPANDER(TUSB_CLASS_CDC_DATA)\ + ENTRY_EXPANDER(TUSB_CLASS_SMART_CARD)\ + ENTRY_EXPANDER(TUSB_CLASS_CONTENT_SECURITY)\ + ENTRY_EXPANDER(TUSB_CLASS_VIDEO)\ + ENTRY_EXPANDER(TUSB_CLASS_PERSONAL_HEALTHCARE)\ + ENTRY_EXPANDER(TUSB_CLASS_AUDIO_VIDEO)\ + +#define CLASS_LOOKUP_EXPAND(class_code) + +#define CLASS_LOOKUP_INIT_FUNCTION(class_code)\ + +#define CLASS_EXPANDER_INIT(class_code)\ + + + +// TUSB_CLASS_DIAGNOSTIC = 0xDC , +// TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 , +// TUSB_CLASS_MISC = 0xEF , +// TUSB_CLASS_APPLICATION_SPECIFIC = 0xEF , +// TUSB_CLASS_VENDOR_SPECIFIC = 0xFF + enum { TUSB_FLAGS_CLASS_UNSPECIFIED = BIT_(0) , ///< 0 TUSB_FLAGS_CLASS_AUDIO = BIT_(1) , ///< 1 @@ -119,6 +149,10 @@ typedef uint32_t tusbh_flag_class_t; typedef uint32_t tusb_handle_device_t; typedef uint8_t tusbh_device_status_t; +typedef struct { + void (* const init) (void); + tusb_error_t (* const install_subtask)(uint8_t, uint8_t const *, uint16_t*); +} class_driver_t; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ diff --git a/tinyusb/host/usbh_hcd.h b/tinyusb/host/usbh_hcd.h index f36586db..e8a1d4c6 100644 --- a/tinyusb/host/usbh_hcd.h +++ b/tinyusb/host/usbh_hcd.h @@ -80,7 +80,7 @@ typedef struct { // TODO internal structure, re-order members //------------- device descriptor info -------------// uint16_t vendor_id; uint16_t product_id; - uint8_t configure_count; // bNumConfigurations alias + uint8_t configure_count; // bNumConfigurations alias //------------- configuration descriptor info -------------// uint8_t interface_count; // bNumInterfaces alias @@ -88,7 +88,7 @@ typedef struct { // TODO internal structure, re-order members uint8_t status; // value from enum tusbh_device_status_ // pipe_handle_t pipe_control; NOTE: use device address/handle instead - tusb_std_request_t request_control; + tusb_std_request_t control_request; OSAL_SEM_DEF(semaphore); osal_semaphore_handle_t sem_hdl; diff --git a/tinyusb/tusb.h b/tinyusb/tusb.h index 8bc4d7af..f972f825 100644 --- a/tinyusb/tusb.h +++ b/tinyusb/tusb.h @@ -58,6 +58,12 @@ #ifdef HOST_CLASS_HID #include "class/hid_host.h" #endif + + #define HOST_CLASS_MSC + #ifdef HOST_CLASS_MSC + #include "class/msc_host.h" + #endif + #endif #if MODE_DEVICE_SUPPORTED