diff --git a/demos/device/device_os_none/device_os_none.ewp b/demos/device/device_os_none/device_os_none.ewp new file mode 100644 index 00000000..e5710a92 --- /dev/null +++ b/demos/device/device_os_none/device_os_none.ewp @@ -0,0 +1,2975 @@ + + + + 2 + + Board EA4357 + + ARM + + 1 + + General + 3 + + 21 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 28 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 15 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + Board LPCXpresso1769 + + ARM + + 1 + + General + 3 + + 21 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 28 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 15 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + Board NGX4330 + + ARM + + 1 + + General + 3 + + 21 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ICCARM + 2 + + 28 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AARM + 2 + + 8 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + OBJCOPY + 0 + + 1 + 1 + 1 + + + + + + + + + CUSTOM + 3 + + + + + + + BICOMP + 0 + + + + BUILDACTION + 1 + + + + + + + ILINK + 0 + + 15 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IARCHIVE + 0 + + 0 + 1 + 1 + + + + + + + BILINK + 0 + + + + + app + + $PROJ_DIR$\..\src\cdcd_app.c + + + $PROJ_DIR$\..\src\keyboardd_app.c + + + $PROJ_DIR$\..\src\main.c + + + $PROJ_DIR$\..\src\moused_app.c + + + $PROJ_DIR$\..\src\mscd_app.c + + + $PROJ_DIR$\..\src\mscd_app_ramdisk.c + + + $PROJ_DIR$\..\src\mscd_app_romdisk.c + + + $PROJ_DIR$\..\src\tusb_descriptors.c + + + + bsp + + boards + + $PROJ_DIR$\..\..\bsp\boards\board.c + + + $PROJ_DIR$\..\..\bsp\boards\embedded_artists\ea4357\board_ea4357.c + + + $PROJ_DIR$\..\..\bsp\boards\microbuilder\board_lpc4357usb.c + + + $PROJ_DIR$\..\..\bsp\boards\lpcxpresso\board_lpcxpresso1769.c + + + $PROJ_DIR$\..\..\bsp\boards\ngx\board_ngx4330.c + + + $PROJ_DIR$\..\..\bsp\boards\embedded_artists\oem_base_board\pca9532.c + + + $PROJ_DIR$\..\..\bsp\boards\printf_retarget.c + + + + lpc175x_6x + + Board EA4357 + Board NGX4330 + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\CMSISv2p00_LPC17xx\src\core_cm3.c + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\LPC17xx_DriverLib\source\lpc17xx_clkpwr.c + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\LPC17xx_DriverLib\source\lpc17xx_gpio.c + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\LPC17xx_DriverLib\source\lpc17xx_pinsel.c + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\LPC17xx_DriverLib\source\lpc17xx_uart.c + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\startup_iar\startup_LPC17xx.s + + + $PROJ_DIR$\..\..\bsp\lpc175x_6x\CMSISv2p00_LPC17xx\src\system_LPC17xx.c + + + + lpc43xx + + Board LPCXpresso1769 + + + $PROJ_DIR$\..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_cgu.c + + + $PROJ_DIR$\..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_gpio.c + + + $PROJ_DIR$\..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_i2c.c + + + $PROJ_DIR$\..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_scu.c + + + $PROJ_DIR$\..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\lpc43xx_uart.c + + + $PROJ_DIR$\..\..\bsp\lpc43xx\startup_iar\startup_LPC43xx.s + + + $PROJ_DIR$\..\..\bsp\lpc43xx\CMSIS_LPC43xx_DriverLib\src\system_LPC43xx.c + + + + + tinyusb + + class + + $PROJ_DIR$\..\..\..\tinyusb\class\cdc_device.c + + + $PROJ_DIR$\..\..\..\tinyusb\class\cdc_host.c + + + $PROJ_DIR$\..\..\..\tinyusb\class\hid_device.c + + + $PROJ_DIR$\..\..\..\tinyusb\class\hid_host.c + + + $PROJ_DIR$\..\..\..\tinyusb\class\msc_device.c + + + $PROJ_DIR$\..\..\..\tinyusb\class\msc_host.c + + + + common + + $PROJ_DIR$\..\..\..\tinyusb\common\errors.c + + + $PROJ_DIR$\..\..\..\tinyusb\common\fifo.c + + + + device + + $PROJ_DIR$\..\..\..\tinyusb\device\dcd.c + + + $PROJ_DIR$\..\..\..\tinyusb\device\dcd_lpc175x_6x.c + + + $PROJ_DIR$\..\..\..\tinyusb\device\dcd_lpc43xx.c + + + $PROJ_DIR$\..\..\..\tinyusb\device\dcd_lpc_11uxx_13uxx.c + + + $PROJ_DIR$\..\..\..\tinyusb\device\usbd.c + + + + hal + + $PROJ_DIR$\..\..\..\tinyusb\hal\hal_lpc11uxx.c + + + $PROJ_DIR$\..\..\..\tinyusb\hal\hal_lpc13uxx.c + + + $PROJ_DIR$\..\..\..\tinyusb\hal\hal_lpc175x_6x.c + + + $PROJ_DIR$\..\..\..\tinyusb\hal\hal_lpc43xx.c + + + + host + + $PROJ_DIR$\..\..\..\tinyusb\host\ehci\ehci.c + + + $PROJ_DIR$\..\..\..\tinyusb\host\hcd.c + + + $PROJ_DIR$\..\..\..\tinyusb\host\hub.c + + + $PROJ_DIR$\..\..\..\tinyusb\host\ohci\ohci.c + + + $PROJ_DIR$\..\..\..\tinyusb\host\usbh.c + + + + osal + + $PROJ_DIR$\..\..\..\tinyusb\osal\osal_none.c + + + + $PROJ_DIR$\..\..\..\tinyusb\tusb.c + + + + + diff --git a/demos/device/device_os_none/device_os_none.eww b/demos/device/device_os_none/device_os_none.eww new file mode 100644 index 00000000..3821a300 --- /dev/null +++ b/demos/device/device_os_none/device_os_none.eww @@ -0,0 +1,10 @@ + + + + + $WS_DIR$\device_os_none.ewp + + + + + diff --git a/demos/device/src/tusb_descriptors.c b/demos/device/src/tusb_descriptors.c index e31261ae..1eff04c5 100644 --- a/demos/device/src/tusb_descriptors.c +++ b/demos/device/src/tusb_descriptors.c @@ -396,43 +396,40 @@ app_descriptor_configuration_t app_tusb_desc_configuration = // STRING DESCRIPTORS //--------------------------------------------------------------------+ #define STRING_LEN_UNICODE(n) (2 + (2*(n))) // also includes 2 byte header +#define ENDIAN_BE16_FROM( high, low) ENDIAN_BE16(high << 8 | low) ATTR_USB_MIN_ALIGNMENT TUSB_CFG_ATTR_USBRAM -tusb_descriptor_string_t desc_str_language = +uint16_t desc_str_language[] = { - .bLength = STRING_LEN_UNICODE(1), - .bDescriptorType = TUSB_DESC_TYPE_STRING, - .unicode_string = { 0x0409 } + ENDIAN_BE16_FROM( STRING_LEN_UNICODE(1), TUSB_DESC_TYPE_STRING ), + 0x0409 }; ATTR_USB_MIN_ALIGNMENT TUSB_CFG_ATTR_USBRAM -tusb_descriptor_string_t desc_str_manufacturer = +uint16_t desc_str_manufacturer[] = { - .bLength = STRING_LEN_UNICODE(11), - .bDescriptorType = TUSB_DESC_TYPE_STRING, - .unicode_string = { 't', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g' } // len = 11 + ENDIAN_BE16_FROM( STRING_LEN_UNICODE(11), TUSB_DESC_TYPE_STRING), + 't', 'i', 'n', 'y', 'u', 's', 'b', '.', 'o', 'r', 'g' // len = 11 }; ATTR_USB_MIN_ALIGNMENT TUSB_CFG_ATTR_USBRAM -tusb_descriptor_string_t desc_str_product = +uint16_t desc_str_product[] = { - .bLength = STRING_LEN_UNICODE(14), - .bDescriptorType = TUSB_DESC_TYPE_STRING, - .unicode_string = { 't', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'D', 'e', 'v', 'i', 'c', 'e' } // len = 14 + ENDIAN_BE16_FROM( STRING_LEN_UNICODE(14), TUSB_DESC_TYPE_STRING), + 't', 'i', 'n', 'y', 'u', 's', 'b', ' ', 'D', 'e', 'v', 'i', 'c', 'e' // len = 14 }; ATTR_USB_MIN_ALIGNMENT TUSB_CFG_ATTR_USBRAM -tusb_descriptor_string_t desc_str_serial = +uint16_t desc_str_serial[] = { - .bLength = STRING_LEN_UNICODE(4), - .bDescriptorType = TUSB_DESC_TYPE_STRING, - .unicode_string = { '1', '2', '3', '4' } // len = 4 + ENDIAN_BE16_FROM( STRING_LEN_UNICODE(4), TUSB_DESC_TYPE_STRING), + '1', '2', '3', '4' // len = 4 }; -tusb_descriptor_string_t * const desc_str_table [TUSB_CFG_DEVICE_STRING_DESCRIPTOR_COUNT] = +uint8_t* const desc_str_table [TUSB_CFG_DEVICE_STRING_DESCRIPTOR_COUNT] = { - &desc_str_language, - &desc_str_manufacturer, - &desc_str_product, - &desc_str_serial + (uint8_t*) desc_str_language, + (uint8_t*) desc_str_manufacturer, + (uint8_t*) desc_str_product, + (uint8_t*) desc_str_serial }; diff --git a/demos/device/src/tusb_descriptors.h b/demos/device/src/tusb_descriptors.h index a7228479..adb5fce9 100644 --- a/demos/device/src/tusb_descriptors.h +++ b/demos/device/src/tusb_descriptors.h @@ -179,7 +179,7 @@ typedef ATTR_PACKED_STRUCT(struct) //--------------------------------------------------------------------+ // STRINGS DESCRIPTOR //--------------------------------------------------------------------+ -extern tusb_descriptor_string_t * const desc_str_table[TUSB_CFG_DEVICE_STRING_DESCRIPTOR_COUNT]; +extern uint8_t * const desc_str_table[TUSB_CFG_DEVICE_STRING_DESCRIPTOR_COUNT]; //--------------------------------------------------------------------+ // Export descriptors diff --git a/tinyusb/common/common.h b/tinyusb/common/common.h index 4933634d..db4d7266 100644 --- a/tinyusb/common/common.h +++ b/tinyusb/common/common.h @@ -1,291 +1,291 @@ -/**************************************************************************/ -/*! - @file common.h - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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. Neither the name of the copyright holders nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 COPYRIGHT HOLDER 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 tinyusb stack. -*/ -/**************************************************************************/ - -/** \defgroup Group_Common Common Files - * @{ - * - * \defgroup Group_CommonH common.h - * - * @{ - */ - -#ifndef _TUSB_COMMON_H_ -#define _TUSB_COMMON_H_ - -#ifdef __cplusplus - extern "C" { -#endif - -//--------------------------------------------------------------------+ -// MACROS -//--------------------------------------------------------------------+ -#define STRING_(x) #x // stringify without expand -#define XSTRING_(x) STRING_(x) // expand then stringify -#define STRING_CONCAT_(a, b) a##b // concat without expand -#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) // expand then concat - -//--------------------------------------------------------------------+ -// INCLUDES -//--------------------------------------------------------------------+ - -//------------- Standard Header -------------// -#include "primitive_types.h" -#include -#include -#include - -//------------- TUSB Option Header -------------// -#include "tusb_option.h" - -//------------- General Header -------------// -#include "compiler/compiler.h" -#include "assertion.h" -#include "binary.h" -#include "errors.h" - -//------------- TUSB Header -------------// -#include "tusb_types.h" -#include "std_descriptors.h" -#include "std_request.h" - -#include "osal/osal.h" - -//--------------------------------------------------------------------+ -// MACROS -//--------------------------------------------------------------------+ -#define STRING_(x) #x ///< stringify without expand -#define XSTRING_(x) STRING_(x) ///< expand then stringify -#define STRING_CONCAT_(a, b) a##b ///< concat without expand -#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) ///< expand then concat - -#define MAX_OF(a, b) ( (a) > (b) ? (a) : (b) ) -#define MIN_OF(a, b) ( (a) < (b) ? (a) : (b) ) - -#define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff)) -#define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff)) -#define U16_TO_U8S_BE(u16) U16_HIGH_U8(u16), U16_LOW_U8(u16) -#define U16_TO_U8S_LE(u16) U16_LOW_U8(u16), U16_HIGH_U8(u16) - -#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB -#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff)) -#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff)) -#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB - -#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32) -#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32) - -//------------- Endian Conversion -------------// -#define ENDIAN_BE(u32) \ - (uint32_t) ( (((u32) & 0xFF) << 24) | (((u32) & 0xFF00) << 8) | (((u32) >> 8) & 0xFF00) | (((u32) >> 24) & 0xFF) ) - -#define ENDIAN_BE16(le16) ((uint16_t) ((U16_LOW_U8(le16) << 8) | U16_HIGH_U8(le16)) ) - -#ifndef __n2be_16 -#define __n2be_16(u16) ((uint16_t) ((U16_LOW_U8(u16) << 8) | U16_HIGH_U8(u16)) ) -#define __be2n_16(u16) __n2be_16(u16) -#endif - -//--------------------------------------------------------------------+ -// INLINE FUNCTION -//--------------------------------------------------------------------+ -#define memclr_(buffer, size) memset((buffer), 0, (size)) - - -static inline uint8_t const * descriptor_next(uint8_t const p_desc[]) ATTR_ALWAYS_INLINE ATTR_PURE; -static inline uint8_t const * descriptor_next(uint8_t const p_desc[]) -{ - return p_desc + p_desc[DESCRIPTOR_OFFSET_LENGTH]; -} - -static inline uint8_t descriptor_typeof(uint8_t const p_desc[]) ATTR_ALWAYS_INLINE ATTR_PURE; -static inline uint8_t descriptor_typeof(uint8_t const p_desc[]) -{ - return p_desc[DESCRIPTOR_OFFSET_TYPE]; -} - -//------------- Conversion -------------// -/// form an uint32_t from 4 x uint8_t -static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) -{ - return ( ((uint32_t) b1) << 24) + ( ((uint32_t) b2) << 16) + ( ((uint32_t) b3) << 8) + b4; -} - -static inline uint8_t u16_high_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint8_t u16_high_u8(uint16_t u16) -{ - return (uint8_t) ( ((uint16_t) (u16 >> 8)) & 0x00ff); -} - -static inline uint8_t u16_low_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint8_t u16_low_u8(uint16_t u16) -{ - return (uint8_t) (u16 & 0x00ff); -} - -static inline uint16_t u16_le2be(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; -static inline uint16_t u16_le2be(uint16_t u16) -{ - return ((uint16_t)(u16_low_u8(u16) << 8)) | u16_high_u8(u16); -} - -//------------- Min -------------// -static inline uint8_t min8_of(uint8_t x, uint8_t y) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint8_t min8_of(uint8_t x, uint8_t y) -{ - return (x < y) ? x : y; -} - -static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint16_t min16_of(uint16_t x, uint16_t y) -{ - return (x < y) ? x : y; -} - -static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t min32_of(uint32_t x, uint32_t y) -{ - return (x < y) ? x : y; -} - -//------------- Max -------------// -static inline uint32_t max32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t max32_of(uint32_t x, uint32_t y) -{ - return (x > y) ? x : y; -} - -static inline uint16_t max16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint16_t max16_of(uint16_t x, uint16_t y) -{ - return (x > y) ? x : y; -} - -//------------- Align -------------// -static inline uint32_t align32 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t align32 (uint32_t value) -{ - return (value & 0xFFFFFFE0UL); -} - -static inline uint32_t align16 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t align16 (uint32_t value) -{ - return (value & 0xFFFFFFF0UL); -} - -static inline uint32_t align_n (uint32_t alignment, uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t align_n (uint32_t alignment, uint32_t value) -{ - return value & ((uint32_t) ~(alignment-1)); -} - -static inline uint32_t align4k (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t align4k (uint32_t value) -{ - return (value & 0xFFFFF000UL); -} - -static inline uint32_t offset4k(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t offset4k(uint32_t value) -{ - return (value & 0xFFFUL); -} - -//------------- Mathematics -------------// -static inline uint32_t abs_of(int32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint32_t abs_of(int32_t value) -{ - return (value < 0) ? (-value) : value; -} - - -/// inclusive range checking -static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) -{ - return (lower <= value) && (value <= upper); -} - -/// exclusive range checking -static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) -{ - return (lower < value) && (value < upper); -} - -// TODO use clz -static inline uint8_t log2_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint8_t log2_of(uint32_t value) -{ - uint8_t result = 0; // log2 of a value is its MSB's position - - while (value >>= 1) - { - result++; - } - return result; -} - -// return the number of set bits in value -static inline uint8_t cardinality_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; -static inline uint8_t cardinality_of(uint32_t value) -{ - // Brian Kernighan's method goes through as many iterations as there are set bits. So if we have a 32-bit word with only - // the high bit set, then it will only go once through the loop - // Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie) - // mentions this in exercise 2-9. On April 19, 2006 Don Knuth pointed out to me that this method - // "was first published by Peter Wegner in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and - // published in 1964 in a book edited by Beckenbach.)" - uint8_t count; - for (count = 0; value; count++) - { - value &= value - 1; // clear the least significant bit set - } - - return count; -} - -#ifdef __cplusplus - } -#endif - -#endif /* _TUSB_COMMON_H_ */ - -/** @} */ -/** @} */ +/**************************************************************************/ +/*! + @file common.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 COPYRIGHT HOLDER 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 tinyusb stack. +*/ +/**************************************************************************/ + +/** \defgroup Group_Common Common Files + * @{ + * + * \defgroup Group_CommonH common.h + * + * @{ + */ + +#ifndef _TUSB_COMMON_H_ +#define _TUSB_COMMON_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +//--------------------------------------------------------------------+ +// MACROS +//--------------------------------------------------------------------+ +#define STRING_(x) #x // stringify without expand +#define XSTRING_(x) STRING_(x) // expand then stringify +#define STRING_CONCAT_(a, b) a##b // concat without expand +#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) // expand then concat + +//--------------------------------------------------------------------+ +// INCLUDES +//--------------------------------------------------------------------+ + +//------------- Standard Header -------------// +#include "primitive_types.h" +#include +#include +#include + +//------------- TUSB Option Header -------------// +#include "tusb_option.h" + +//------------- General Header -------------// +#include "compiler/compiler.h" +#include "assertion.h" +#include "binary.h" +#include "errors.h" + +//------------- TUSB Header -------------// +#include "tusb_types.h" +#include "std_descriptors.h" +#include "std_request.h" + +#include "osal/osal.h" + +//--------------------------------------------------------------------+ +// MACROS +//--------------------------------------------------------------------+ +#define STRING_(x) #x ///< stringify without expand +#define XSTRING_(x) STRING_(x) ///< expand then stringify +#define STRING_CONCAT_(a, b) a##b ///< concat without expand +#define XSTRING_CONCAT_(a, b) STRING_CONCAT_(a, b) ///< expand then concat + +#define MAX_OF(a, b) ( (a) > (b) ? (a) : (b) ) +#define MIN_OF(a, b) ( (a) < (b) ? (a) : (b) ) + +#define U16_HIGH_U8(u16) ((uint8_t) (((u16) >> 8) & 0x00ff)) +#define U16_LOW_U8(u16) ((uint8_t) ((u16) & 0x00ff)) +#define U16_TO_U8S_BE(u16) U16_HIGH_U8(u16), U16_LOW_U8(u16) +#define U16_TO_U8S_LE(u16) U16_LOW_U8(u16), U16_HIGH_U8(u16) + +#define U32_B1_U8(u32) ((uint8_t) (((u32) >> 24) & 0x000000ff)) // MSB +#define U32_B2_U8(u32) ((uint8_t) (((u32) >> 16) & 0x000000ff)) +#define U32_B3_U8(u32) ((uint8_t) (((u32) >> 8) & 0x000000ff)) +#define U32_B4_U8(u32) ((uint8_t) ((u32) & 0x000000ff)) // LSB + +#define U32_TO_U8S_BE(u32) U32_B1_U8(u32), U32_B2_U8(u32), U32_B3_U8(u32), U32_B4_U8(u32) +#define U32_TO_U8S_LE(u32) U32_B4_U8(u32), U32_B3_U8(u32), U32_B2_U8(u32), U32_B1_U8(u32) + +//------------- Endian Conversion -------------// +#define ENDIAN_BE(u32) \ + (uint32_t) ( (((u32) & 0xFF) << 24) | (((u32) & 0xFF00) << 8) | (((u32) >> 8) & 0xFF00) | (((u32) >> 24) & 0xFF) ) + +#define ENDIAN_BE16(le16) ((uint16_t) ((U16_LOW_U8(le16) << 8) | U16_HIGH_U8(le16)) ) + +#ifndef __n2be_16 +#define __n2be_16(u16) ((uint16_t) ((U16_LOW_U8(u16) << 8) | U16_HIGH_U8(u16)) ) +#define __be2n_16(u16) __n2be_16(u16) +#endif + +//--------------------------------------------------------------------+ +// INLINE FUNCTION +//--------------------------------------------------------------------+ +#define memclr_(buffer, size) memset((buffer), 0, (size)) + + +static inline uint8_t const * descriptor_next(uint8_t const p_desc[]) ATTR_ALWAYS_INLINE ATTR_PURE; +static inline uint8_t const * descriptor_next(uint8_t const p_desc[]) +{ + return p_desc + p_desc[DESCRIPTOR_OFFSET_LENGTH]; +} + +static inline uint8_t descriptor_typeof(uint8_t const p_desc[]) ATTR_ALWAYS_INLINE ATTR_PURE; +static inline uint8_t descriptor_typeof(uint8_t const p_desc[]) +{ + return p_desc[DESCRIPTOR_OFFSET_TYPE]; +} + +//------------- Conversion -------------// +/// form an uint32_t from 4 x uint8_t +static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t u32_from_u8(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4) +{ + return ( ((uint32_t) b1) << 24) + ( ((uint32_t) b2) << 16) + ( ((uint32_t) b3) << 8) + b4; +} + +static inline uint8_t u16_high_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t u16_high_u8(uint16_t u16) +{ + return (uint8_t) ( ((uint16_t) (u16 >> 8)) & 0x00ff); +} + +static inline uint8_t u16_low_u8(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint8_t u16_low_u8(uint16_t u16) +{ + return (uint8_t) (u16 & 0x00ff); +} + +static inline uint16_t u16_le2be(uint16_t u16) ATTR_CONST ATTR_ALWAYS_INLINE; +static inline uint16_t u16_le2be(uint16_t u16) +{ + return ((uint16_t)(u16_low_u8(u16) << 8)) | u16_high_u8(u16); +} + +//------------- Min -------------// +static inline uint8_t min8_of(uint8_t x, uint8_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t min8_of(uint8_t x, uint8_t y) +{ + return (x < y) ? x : y; +} + +static inline uint16_t min16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint16_t min16_of(uint16_t x, uint16_t y) +{ + return (x < y) ? x : y; +} + +static inline uint32_t min32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t min32_of(uint32_t x, uint32_t y) +{ + return (x < y) ? x : y; +} + +//------------- Max -------------// +static inline uint32_t max32_of(uint32_t x, uint32_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t max32_of(uint32_t x, uint32_t y) +{ + return (x > y) ? x : y; +} + +static inline uint16_t max16_of(uint16_t x, uint16_t y) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint16_t max16_of(uint16_t x, uint16_t y) +{ + return (x > y) ? x : y; +} + +//------------- Align -------------// +static inline uint32_t align32 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align32 (uint32_t value) +{ + return (value & 0xFFFFFFE0UL); +} + +static inline uint32_t align16 (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align16 (uint32_t value) +{ + return (value & 0xFFFFFFF0UL); +} + +static inline uint32_t align_n (uint32_t alignment, uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align_n (uint32_t alignment, uint32_t value) +{ + return value & ((uint32_t) ~(alignment-1)); +} + +static inline uint32_t align4k (uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t align4k (uint32_t value) +{ + return (value & 0xFFFFF000UL); +} + +static inline uint32_t offset4k(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t offset4k(uint32_t value) +{ + return (value & 0xFFFUL); +} + +//------------- Mathematics -------------// +static inline uint32_t abs_of(int32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint32_t abs_of(int32_t value) +{ + return (value < 0) ? (-value) : value; +} + + +/// inclusive range checking +static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline bool is_in_range(uint32_t lower, uint32_t value, uint32_t upper) +{ + return (lower <= value) && (value <= upper); +} + +/// exclusive range checking +static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline bool is_in_range_exclusive(uint32_t lower, uint32_t value, uint32_t upper) +{ + return (lower < value) && (value < upper); +} + +// TODO use clz +static inline uint8_t log2_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t log2_of(uint32_t value) +{ + uint8_t result = 0; // log2 of a value is its MSB's position + + while (value >>= 1) + { + result++; + } + return result; +} + +// return the number of set bits in value +static inline uint8_t cardinality_of(uint32_t value) ATTR_ALWAYS_INLINE ATTR_CONST; +static inline uint8_t cardinality_of(uint32_t value) +{ + // Brian Kernighan's method goes through as many iterations as there are set bits. So if we have a 32-bit word with only + // the high bit set, then it will only go once through the loop + // Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan and Dennis M. Ritchie) + // mentions this in exercise 2-9. On April 19, 2006 Don Knuth pointed out to me that this method + // "was first published by Peter Wegner in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and + // published in 1964 in a book edited by Beckenbach.)" + uint8_t count; + for (count = 0; value; count++) + { + value &= value - 1; // clear the least significant bit set + } + + return count; +} + +#ifdef __cplusplus + } +#endif + +#endif /* _TUSB_COMMON_H_ */ + +/** @} */ +/** @} */ diff --git a/tinyusb/device/dcd_lpc43xx.c b/tinyusb/device/dcd_lpc43xx.c index 05e47fd1..036c65a6 100644 --- a/tinyusb/device/dcd_lpc43xx.c +++ b/tinyusb/device/dcd_lpc43xx.c @@ -351,7 +351,7 @@ void dcd_pipe_control_stall(uint8_t coreid) } // control transfer does not need to use qtd find function -tusb_error_t dcd_pipe_control_xfer(uint8_t coreid, tusb_direction_t dir, void * p_buffer, uint16_t length, bool int_on_complete) +tusb_error_t dcd_pipe_control_xfer(uint8_t coreid, tusb_direction_t dir, uint8_t * p_buffer, uint16_t length, bool int_on_complete) { LPC_USB0_Type* const lpc_usb = LPC_USB[coreid]; dcd_data_t* const p_dcd = dcd_data_ptr[coreid]; @@ -485,12 +485,12 @@ static tusb_error_t pipe_add_xfer(endpoint_handle_t edpt_hdl, void * buffer, uin return TUSB_ERROR_NONE; } -tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, void * buffer, uint16_t total_bytes) +tusb_error_t dcd_pipe_queue_xfer(endpoint_handle_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes) { return pipe_add_xfer( edpt_hdl, buffer, total_bytes, false); } -tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, void* buffer, uint16_t total_bytes, bool int_on_complete) +tusb_error_t dcd_pipe_xfer(endpoint_handle_t edpt_hdl, uint8_t * buffer, uint16_t total_bytes, bool int_on_complete) { ASSERT_STATUS ( pipe_add_xfer(edpt_hdl, buffer, total_bytes, int_on_complete) ); @@ -602,7 +602,7 @@ void dcd_isr(uint8_t coreid) .class_code = 0 }; - dcd_qtd_t * const p_qtd = &p_dcd->qhd[ (edpt_complete & BIT_(0)) ? 0 : 1 ].qtd_overlay; + dcd_qtd_t volatile * const p_qtd = &p_dcd->qhd[ (edpt_complete & BIT_(0)) ? 0 : 1 ].qtd_overlay; tusb_event_t event = ( p_qtd->xact_err || p_qtd->halted || p_qtd->buffer_err ) ? TUSB_EVENT_XFER_ERROR : TUSB_EVENT_XFER_COMPLETE; usbd_xfer_isr(edpt_hdl, event, 0); // TODO xferred bytes for control xfer is not needed yet !!!! diff --git a/tinyusb/device/usbd.c b/tinyusb/device/usbd.c index 38d139f1..0b9044db 100644 --- a/tinyusb/device/usbd.c +++ b/tinyusb/device/usbd.c @@ -344,7 +344,7 @@ static tusb_error_t get_descriptor(uint8_t coreid, tusb_control_request_t const if ( ! (desc_index < TUSB_CFG_DEVICE_STRING_DESCRIPTOR_COUNT) ) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; (*pp_buffer) = (uint8_t *) desc_str_table[desc_index]; - (*p_length) = desc_str_table[desc_index]->bLength; + (*p_length) = **pp_buffer; }else { return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT; diff --git a/tinyusb/host/usbh.c b/tinyusb/host/usbh.c index f15cdfeb..be7c3f42 100644 --- a/tinyusb/host/usbh.c +++ b/tinyusb/host/usbh.c @@ -1,633 +1,633 @@ -/**************************************************************************/ -/*! - @file usbd_host.c - @author hathach (tinyusb.org) - - @section LICENSE - - Software License Agreement (BSD License) - - Copyright (c) 2013, hathach (tinyusb.org) - 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. Neither the name of the copyright holders nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 COPYRIGHT HOLDER 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 tinyusb stack. -*/ -/**************************************************************************/ - -#include "common/common.h" - -#if MODE_HOST_SUPPORTED - -#define _TINY_USB_SOURCE_FILE_ - -//--------------------------------------------------------------------+ -// INCLUDE -//--------------------------------------------------------------------+ -#include "tusb.h" -#include "hub.h" -#include "usbh_hcd.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF -//--------------------------------------------------------------------+ -#define ENUM_QUEUE_DEPTH 5 - -// TODO fix/compress number of class driver -static host_class_driver_t const usbh_class_drivers[TUSB_CLASS_MAPPED_INDEX_END] = -{ -#if HOST_CLASS_HID - [TUSB_CLASS_HID] = { - .init = hidh_init, - .open_subtask = hidh_open_subtask, - .isr = hidh_isr, - .close = hidh_close - }, -#endif - -#if TUSB_CFG_HOST_CDC - [TUSB_CLASS_CDC] = { - .init = cdch_init, - .open_subtask = cdch_open_subtask, - .isr = cdch_isr, - .close = cdch_close - }, -#endif - -#if TUSB_CFG_HOST_MSC - [TUSB_CLASS_MSC] = { - .init = msch_init, - .open_subtask = msch_open_subtask, - .isr = msch_isr, - .close = msch_close - }, -#endif - -#if TUSB_CFG_HOST_HUB - [TUSB_CLASS_HUB] = { - .init = hub_init, - .open_subtask = hub_open_subtask, - .isr = hub_isr, - .close = hub_close - }, -#endif - -#if TUSB_CFG_HOST_CUSTOM_CLASS - [TUSB_CLASS_MAPPED_INDEX_END-1] = { - .init = cush_init, - .open_subtask = cush_open_subtask, - .isr = cush_isr, - .close = cush_close - } -#endif -}; - -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ -TUSB_CFG_ATTR_USBRAM usbh_device_info_t usbh_devices[TUSB_CFG_HOST_DEVICE_MAX+1]; // including zero-address - -//------------- Enumeration Task Data -------------// -OSAL_TASK_DEF(usbh_enumeration_task, 200, TUSB_CFG_OS_TASK_PRIO); -OSAL_QUEUE_DEF(enum_queue_def, ENUM_QUEUE_DEPTH, uint32_t); - -static osal_queue_handle_t enum_queue_hdl; -TUSB_CFG_ATTR_USBRAM ATTR_ALIGNED(4) STATIC_VAR uint8_t enum_data_buffer[TUSB_CFG_HOST_ENUM_BUFFER_SIZE]; - -//------------- Reporter Task Data -------------// - -//------------- Helper Function Prototypes -------------// -static inline uint8_t get_new_address(void) ATTR_ALWAYS_INLINE; -static inline uint8_t get_configure_number_for_device(tusb_descriptor_device_t* dev_desc) ATTR_ALWAYS_INLINE; - -//--------------------------------------------------------------------+ -// PUBLIC API (Parameter Verification is required) -//--------------------------------------------------------------------+ -tusb_device_state_t tusbh_device_get_state (uint8_t const dev_addr) -{ - ASSERT_INT_WITHIN(1, TUSB_CFG_HOST_DEVICE_MAX, dev_addr, TUSB_DEVICE_STATE_INVALID_PARAMETER); - return (tusb_device_state_t) usbh_devices[dev_addr].state; -} - -uint32_t tusbh_device_get_mounted_class_flag(uint8_t dev_addr) -{ - return tusbh_device_is_configured(dev_addr) ? usbh_devices[dev_addr].flag_supported_class : 0; -} - -//--------------------------------------------------------------------+ -// CLASS-USBD API (don't require to verify parameters) -//--------------------------------------------------------------------+ -tusb_error_t usbh_init(void) -{ - memclr_(usbh_devices, sizeof(usbh_device_info_t)*(TUSB_CFG_HOST_DEVICE_MAX+1)); - - ASSERT_STATUS( hcd_init() ); - - //------------- Enumeration & Reporter Task init -------------// - enum_queue_hdl = osal_queue_create( OSAL_QUEUE_REF(enum_queue_def) ); - ASSERT_PTR(enum_queue_hdl, TUSB_ERROR_OSAL_QUEUE_FAILED); - ASSERT_STATUS( osal_task_create( OSAL_TASK_REF(usbh_enumeration_task) )); - - //------------- Semaphore, Mutex for Control Pipe -------------// - for(uint8_t i=0; icontrol.sem_hdl = osal_semaphore_create( OSAL_SEM_REF(p_device->control.semaphore) ); - ASSERT_PTR(p_device->control.sem_hdl, TUSB_ERROR_OSAL_SEMAPHORE_FAILED); - - p_device->control.mutex_hdl = osal_mutex_create ( OSAL_MUTEX_REF(p_device->control.mutex) ); - ASSERT_PTR(p_device->control.mutex_hdl, TUSB_ERROR_OSAL_MUTEX_FAILED); - } - - //------------- class init -------------// - for (uint8_t class_index = 1; class_index < TUSB_CLASS_MAPPED_INDEX_END; class_index++) - { - if (usbh_class_drivers[class_index].init) - { - usbh_class_drivers[class_index].init(); - } - } - - return TUSB_ERROR_NONE; -} - -//------------- USBH control transfer -------------// -// function called within a task, requesting os blocking services, subtask input parameter must be static/global variables or constant -tusb_error_t usbh_control_xfer_subtask(uint8_t dev_addr, uint8_t bmRequestType, uint8_t bRequest, - uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t* data) -{ - static tusb_error_t error; // FIXME cmsis-rtx use svc for OS API, error value changed after mutex release at the end of function - - OSAL_SUBTASK_BEGIN - - osal_mutex_wait(usbh_devices[dev_addr].control.mutex_hdl, OSAL_TIMEOUT_NORMAL, &error); - SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl)); - - usbh_devices[dev_addr].control.request = (tusb_control_request_t) { - {.bmRequestType = bmRequestType}, - .bRequest = bRequest, - .wValue = wValue, - .wIndex = wIndex, - .wLength = wLength - }; - -#ifndef _TEST_ - usbh_devices[dev_addr].control.pipe_status = 0; -#else - usbh_devices[dev_addr].control.pipe_status = TUSB_EVENT_XFER_COMPLETE; // in Test project, mark as complete immediately -#endif - - SUBTASK_ASSERT_STATUS_WITH_HANDLER( hcd_pipe_control_xfer(dev_addr, &usbh_devices[dev_addr].control.request, data), - osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl) ); - - osal_semaphore_wait(usbh_devices[dev_addr].control.sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static - osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl); - - // TODO make handler for this function general purpose - if (TUSB_ERROR_NONE != error) SUBTASK_EXIT(error); - if (TUSB_EVENT_XFER_STALLED == usbh_devices[dev_addr].control.pipe_status) SUBTASK_EXIT(TUSB_ERROR_USBH_XFER_STALLED); - if (TUSB_EVENT_XFER_ERROR == usbh_devices[dev_addr].control.pipe_status) SUBTASK_EXIT(TUSB_ERROR_USBH_XFER_FAILED); - -// SUBTASK_ASSERT_WITH_HANDLER(TUSB_ERROR_NONE == error && -// TUSB_EVENT_XFER_COMPLETE == usbh_devices[dev_addr].control.pipe_status, -// tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); - - OSAL_SUBTASK_END -} - -tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) ATTR_ALWAYS_INLINE; -tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) -{ - osal_semaphore_reset( usbh_devices[dev_addr].control.sem_hdl ); - osal_mutex_reset( usbh_devices[dev_addr].control.mutex_hdl ); - - ASSERT_STATUS( hcd_pipe_control_open(dev_addr, max_packet_size) ); - - return TUSB_ERROR_NONE; -} - -static inline tusb_error_t usbh_pipe_control_close(uint8_t dev_addr) ATTR_ALWAYS_INLINE; -static inline tusb_error_t usbh_pipe_control_close(uint8_t dev_addr) -{ - ASSERT_STATUS( hcd_pipe_control_close(dev_addr) ); - - return TUSB_ERROR_NONE; -} - -tusb_interface_status_t usbh_pipe_status_get(pipe_handle_t pipe_hdl) -{ - return TUSB_INTERFACE_STATUS_BUSY; -} - -//--------------------------------------------------------------------+ -// USBH-HCD ISR/Callback API -//--------------------------------------------------------------------+ -// interrupt caused by a TD (with IOC=1) in pipe of class class_code -void usbh_xfer_isr(pipe_handle_t pipe_hdl, uint8_t class_code, tusb_event_t event, uint32_t xferred_bytes) -{ - uint8_t class_index = std_class_code_to_index(class_code); - if (TUSB_XFER_CONTROL == pipe_hdl.xfer_type) - { - usbh_devices[ pipe_hdl.dev_addr ].control.pipe_status = event; -// usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary - osal_semaphore_post( usbh_devices[ pipe_hdl.dev_addr ].control.sem_hdl ); - }else if (usbh_class_drivers[class_index].isr) - { - usbh_class_drivers[class_index].isr(pipe_hdl, event, xferred_bytes); - }else - { - ASSERT(false, VOID_RETURN); // something wrong, no one claims the isr's source - } -} - -void usbh_hub_port_plugged_isr(uint8_t hub_addr, uint8_t hub_port) -{ - osal_queue_send(enum_queue_hdl, - &(usbh_enumerate_t){ - .core_id = usbh_devices[hub_addr].core_id, - .hub_addr = hub_addr, - .hub_port = hub_port} - ); -} - -void usbh_hcd_rhport_plugged_isr(uint8_t hostid) -{ - osal_queue_send(enum_queue_hdl, - &(usbh_enumerate_t){ - .core_id = hostid, - .hub_addr = 0, - .hub_port = 0} - ); -} - -// a device unplugged on hostid, hub_addr, hub_port -// return true if found and unmounted device, false if cannot find -static void usbh_device_unplugged(uint8_t hostid, uint8_t hub_addr, uint8_t hub_port) -{ - bool is_found = false; - //------------- find the all devices (star-network) under port that is unplugged -------------// - for (uint8_t dev_addr = 0; dev_addr <= TUSB_CFG_HOST_DEVICE_MAX; dev_addr ++) - { - if (usbh_devices[dev_addr].core_id == hostid && - (hub_addr == 0 || usbh_devices[dev_addr].hub_addr == hub_addr) && // hub_addr == 0 & hub_port == 0 means roothub - (hub_port == 0 || usbh_devices[dev_addr].hub_port == hub_port) && - usbh_devices[dev_addr].state != TUSB_DEVICE_STATE_UNPLUG) - { - // TODO Hub multiple level - for (uint8_t class_index = 1; class_index < TUSB_CLASS_MAPPED_INDEX_END; class_index++) - { - if ((usbh_devices[dev_addr].flag_supported_class & BIT_(class_index)) && - usbh_class_drivers[class_index].close) - { - usbh_class_drivers[class_index].close(dev_addr); - } - } - - // TODO refractor - // set to REMOVING to allow HCD to clean up its cached data for this device - // HCD must set this device's state to TUSB_DEVICE_STATE_UNPLUG when done - usbh_devices[dev_addr].state = TUSB_DEVICE_STATE_REMOVING; - usbh_devices[dev_addr].flag_supported_class = 0; - - usbh_pipe_control_close(dev_addr); - - - is_found = true; - } - } - - if (is_found) hcd_port_unplug(usbh_devices[0].core_id); // TODO hack - -} - -void usbh_hcd_rhport_unplugged_isr(uint8_t hostid) -{ - osal_queue_send(enum_queue_hdl, - &(usbh_enumerate_t) - { - .core_id = hostid, - .hub_addr = 0, - .hub_port = 0 - } ); -} - -//--------------------------------------------------------------------+ -// ENUMERATION TASK -//--------------------------------------------------------------------+ -static tusb_error_t enumeration_body_subtask(void); - -// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper -// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with -// forever loop cannot have any return at all. -OSAL_TASK_FUNCTION(usbh_enumeration_task) (void* p_task_para) -{ - OSAL_TASK_LOOP_BEGIN - - enumeration_body_subtask(); - - OSAL_TASK_LOOP_END -} - -tusb_error_t enumeration_body_subtask(void) -{ - enum { - POWER_STABLE_DELAY = 300, - RESET_DELAY = 100 // NXP's EHCI require more than 50ms to work properly although the USB specs say only 50ms - }; - - tusb_error_t error; - usbh_enumerate_t enum_entry; - - // for OSAL_NONE local variable won't retain value after blocking service sem_wait/queue_recv - static uint8_t new_addr; - static uint8_t configure_selected = 1; // TODO move - static uint8_t *p_desc = NULL; // TODO move - - OSAL_SUBTASK_BEGIN - - osal_queue_receive(enum_queue_hdl, &enum_entry, OSAL_TIMEOUT_WAIT_FOREVER, &error); - SUBTASK_ASSERT_STATUS(error); - - usbh_devices[0].core_id = enum_entry.core_id; // TODO refractor integrate to device_pool - usbh_devices[0].hub_addr = enum_entry.hub_addr; - usbh_devices[0].hub_port = enum_entry.hub_port; - usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG; - - //------------- connected/disconnected directly with roothub -------------// - if ( usbh_devices[0].hub_addr == 0) - { - if( hcd_port_connect_status(usbh_devices[0].core_id) ) - { // connection event - osal_task_delay(POWER_STABLE_DELAY); // wait until device is stable. Increase this if the first 8 bytes is failed to get - - if ( !hcd_port_connect_status(usbh_devices[0].core_id) ) SUBTASK_EXIT(TUSB_ERROR_NONE); // exit if device unplugged while delaying - - hcd_port_reset( usbh_devices[0].core_id ); // port must be reset to have correct speed operation - osal_task_delay(RESET_DELAY); - - usbh_devices[0].speed = hcd_port_speed_get( usbh_devices[0].core_id ); - } - else - { // disconnection event - usbh_device_unplugged(usbh_devices[0].core_id, 0, 0); - SUBTASK_EXIT(TUSB_ERROR_NONE); // restart task - } - } - #if TUSB_CFG_HOST_HUB - //------------- connected/disconnected via hub -------------// - else - { - //------------- Get Port Status -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER), - HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port, - 4, enum_data_buffer ), - error - ); -// SUBTASK_ASSERT_STATUS( error ); - SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor - - // Acknowledge Port Connection Change - OSAL_SUBTASK_INVOKED_AND_WAIT( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_CONNECTION_CHANGE), error ); - - if ( ! ((hub_port_status_response_t *) enum_data_buffer)->status_change.connect_status ) SUBTASK_EXIT(TUSB_ERROR_NONE); // only handle connection change - - if ( ! ((hub_port_status_response_t *) enum_data_buffer)->status_current.connect_status ) - { // Disconnection event - usbh_device_unplugged(usbh_devices[0].core_id, usbh_devices[0].hub_addr, usbh_devices[0].hub_port); - - (void) hub_status_pipe_queue( usbh_devices[0].hub_addr ); // done with hub, waiting for next data on status pipe - SUBTASK_EXIT(TUSB_ERROR_NONE); // restart task - } - else - { // Connection Event - OSAL_SUBTASK_INVOKED_AND_WAIT ( hub_port_reset_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port), error ); -// SUBTASK_ASSERT_STATUS( error ); - SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor - - usbh_devices[0].speed = hub_port_get_speed(); - - // Acknowledge Port Reset Change - OSAL_SUBTASK_INVOKED_AND_WAIT( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_RESET_CHANGE), error ); - } - } - #endif - - SUBTASK_ASSERT_STATUS( usbh_pipe_control_open(0, 8) ); - usbh_devices[0].state = TUSB_DEVICE_STATE_ADDRESSED; - - //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( 0, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), - TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_DEVICE << 8), 0, - 8, enum_data_buffer ), - error - ); - - //------------- Reset device again before Set Address -------------// - if (usbh_devices[0].hub_addr == 0) - { // connected directly to roothub - SUBTASK_ASSERT_STATUS(error); // TODO some slow device is observed to fail the very fist controller xfer, can try more times - hcd_port_reset( usbh_devices[0].core_id ); // reset port after 8 byte descriptor - osal_task_delay(RESET_DELAY); - } - #if TUSB_CFG_HOST_HUB - else - { // connected via a hub - SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor - OSAL_SUBTASK_INVOKED_AND_WAIT ( hub_port_reset_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port), error ); - - if ( TUSB_ERROR_NONE == error ) - { // Acknowledge Port Reset Change if Reset Successful - OSAL_SUBTASK_INVOKED_AND_WAIT( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_RESET_CHANGE), error ); - } - - (void) hub_status_pipe_queue( usbh_devices[0].hub_addr ); // done with hub, waiting for next data on status pipe - } - #endif - - //------------- Set new address -------------// - new_addr = get_new_address(); - SUBTASK_ASSERT(new_addr <= TUSB_CFG_HOST_DEVICE_MAX); // TODO notify application we reach max devices - - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( 0, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), - TUSB_REQUEST_SET_ADDRESS, new_addr, 0, - 0, NULL ), - error - ); - SUBTASK_ASSERT_STATUS(error); - - //------------- update port info & close control pipe of addr0 -------------// - usbh_devices[new_addr].core_id = usbh_devices[0].core_id; - usbh_devices[new_addr].hub_addr = usbh_devices[0].hub_addr; - usbh_devices[new_addr].hub_port = usbh_devices[0].hub_port; - usbh_devices[new_addr].speed = usbh_devices[0].speed; - usbh_devices[new_addr].state = TUSB_DEVICE_STATE_ADDRESSED; - - usbh_pipe_control_close(0); - usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG; - - // open control pipe for new address - SUBTASK_ASSERT_STATUS ( usbh_pipe_control_open(new_addr, ((tusb_descriptor_device_t*) enum_data_buffer)->bMaxPacketSize0 ) ); - - //------------- Get full device descriptor -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), - TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_DEVICE << 8), 0, - 18, enum_data_buffer ), - error - ); - SUBTASK_ASSERT_STATUS(error); - - // update device info TODO alignment issue - usbh_devices[new_addr].vendor_id = ((tusb_descriptor_device_t*) enum_data_buffer)->idVendor; - usbh_devices[new_addr].product_id = ((tusb_descriptor_device_t*) enum_data_buffer)->idProduct; - usbh_devices[new_addr].configure_count = ((tusb_descriptor_device_t*) enum_data_buffer)->bNumConfigurations; - - configure_selected = get_configure_number_for_device((tusb_descriptor_device_t*) enum_data_buffer); - SUBTASK_ASSERT(configure_selected <= usbh_devices[new_addr].configure_count); // TODO notify application when invalid configuration - - //------------- Get 9 bytes of configuration descriptor -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), - TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_CONFIGURATION << 8) | (configure_selected - 1), 0, - 9, enum_data_buffer ), - error - ); - SUBTASK_ASSERT_STATUS(error); - SUBTASK_ASSERT_WITH_HANDLER( TUSB_CFG_HOST_ENUM_BUFFER_SIZE >= ((tusb_descriptor_configuration_t*)enum_data_buffer)->wTotalLength, - tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_CONFIG_DESC_TOO_LONG, NULL) ); - - //------------- Get full configuration descriptor -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), - TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_CONFIGURATION << 8) | (configure_selected - 1), 0, - TUSB_CFG_HOST_ENUM_BUFFER_SIZE, enum_data_buffer ), - error - ); - SUBTASK_ASSERT_STATUS(error); - - // update configuration info - usbh_devices[new_addr].interface_count = ((tusb_descriptor_configuration_t*) enum_data_buffer)->bNumInterfaces; - - //------------- Set Configure -------------// - OSAL_SUBTASK_INVOKED_AND_WAIT( - usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), - TUSB_REQUEST_SET_CONFIGURATION, configure_selected, 0, - 0, NULL ), - error - ); - SUBTASK_ASSERT_STATUS(error); - - usbh_devices[new_addr].state = TUSB_DEVICE_STATE_CONFIGURED; - - //------------- TODO Get String Descriptors -------------// - - //------------- parse configuration & install drivers -------------// - p_desc = enum_data_buffer + sizeof(tusb_descriptor_configuration_t); - - // parse each interfaces - while( p_desc < enum_data_buffer + ((tusb_descriptor_configuration_t*)enum_data_buffer)->wTotalLength ) - { - // skip until we see interface descriptor - if ( TUSB_DESC_TYPE_INTERFACE != p_desc[DESCRIPTOR_OFFSET_TYPE] ) - { - p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip the descriptor, increase by the descriptor's length - }else - { - static uint8_t class_index; // has to be static as it is used to call class's open_subtask - - class_index = std_class_code_to_index( ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass ); - SUBTASK_ASSERT( class_index != 0 ); // class_index == 0 means corrupted data, abort enumeration - - if (usbh_class_drivers[class_index].open_subtask && - !(class_index == TUSB_CLASS_HUB && usbh_devices[new_addr].hub_addr != 0)) - { // supported class, TODO Hub disable multiple level - static uint16_t length; - length = 0; - - OSAL_SUBTASK_INVOKED_AND_WAIT ( // parameters in task/sub_task must be static storage (static or global) - usbh_class_drivers[class_index].open_subtask( new_addr, (tusb_descriptor_interface_t*) p_desc, &length ), - error - ); - - if (error == TUSB_ERROR_NONE) - { - SUBTASK_ASSERT( length >= sizeof(tusb_descriptor_interface_t) ); - usbh_devices[new_addr].flag_supported_class |= BIT_(class_index); - p_desc += length; - }else // Interface open failed, for example a subclass is not supported - { - p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip this interface, the rest will be skipped by the above loop - } - } else // unsupported class (not enable or yet implemented) - { - p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip this interface, the rest will be skipped by the above loop - } - } - } - - tusbh_device_mount_succeed_cb(new_addr); - - OSAL_SUBTASK_END -} - -//--------------------------------------------------------------------+ -// REPORTER TASK & ITS DATA -//--------------------------------------------------------------------+ - - - - - -//--------------------------------------------------------------------+ -// INTERNAL HELPER -//--------------------------------------------------------------------+ -static inline uint8_t get_new_address(void) -{ - uint8_t addr; - for (addr=1; addr <= TUSB_CFG_HOST_DEVICE_MAX; addr++) - { - if (usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG) - break; - } - return addr; -} - -static inline uint8_t get_configure_number_for_device(tusb_descriptor_device_t* dev_desc) -{ - uint8_t config_num = 1; - - // invoke callback to ask user which configuration to select - if (tusbh_device_attached_cb) - { - config_num = min8_of(1, tusbh_device_attached_cb(dev_desc) ); - } - - return config_num; -} - -#endif +/**************************************************************************/ +/*! + @file usbd_host.c + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2013, hathach (tinyusb.org) + 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. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''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 COPYRIGHT HOLDER 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 tinyusb stack. +*/ +/**************************************************************************/ + +#include "common/common.h" + +#if MODE_HOST_SUPPORTED + +#define _TINY_USB_SOURCE_FILE_ + +//--------------------------------------------------------------------+ +// INCLUDE +//--------------------------------------------------------------------+ +#include "tusb.h" +#include "hub.h" +#include "usbh_hcd.h" + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ +#define ENUM_QUEUE_DEPTH 5 + +// TODO fix/compress number of class driver +static host_class_driver_t const usbh_class_drivers[TUSB_CLASS_MAPPED_INDEX_END] = +{ +#if HOST_CLASS_HID + [TUSB_CLASS_HID] = { + .init = hidh_init, + .open_subtask = hidh_open_subtask, + .isr = hidh_isr, + .close = hidh_close + }, +#endif + +#if TUSB_CFG_HOST_CDC + [TUSB_CLASS_CDC] = { + .init = cdch_init, + .open_subtask = cdch_open_subtask, + .isr = cdch_isr, + .close = cdch_close + }, +#endif + +#if TUSB_CFG_HOST_MSC + [TUSB_CLASS_MSC] = { + .init = msch_init, + .open_subtask = msch_open_subtask, + .isr = msch_isr, + .close = msch_close + }, +#endif + +#if TUSB_CFG_HOST_HUB + [TUSB_CLASS_HUB] = { + .init = hub_init, + .open_subtask = hub_open_subtask, + .isr = hub_isr, + .close = hub_close + }, +#endif + +#if TUSB_CFG_HOST_CUSTOM_CLASS + [TUSB_CLASS_MAPPED_INDEX_END-1] = { + .init = cush_init, + .open_subtask = cush_open_subtask, + .isr = cush_isr, + .close = cush_close + } +#endif +}; + +//--------------------------------------------------------------------+ +// INTERNAL OBJECT & FUNCTION DECLARATION +//--------------------------------------------------------------------+ +TUSB_CFG_ATTR_USBRAM usbh_device_info_t usbh_devices[TUSB_CFG_HOST_DEVICE_MAX+1]; // including zero-address + +//------------- Enumeration Task Data -------------// +OSAL_TASK_DEF(usbh_enumeration_task, 200, TUSB_CFG_OS_TASK_PRIO); +OSAL_QUEUE_DEF(enum_queue_def, ENUM_QUEUE_DEPTH, uint32_t); + +static osal_queue_handle_t enum_queue_hdl; +TUSB_CFG_ATTR_USBRAM ATTR_ALIGNED(4) STATIC_VAR uint8_t enum_data_buffer[TUSB_CFG_HOST_ENUM_BUFFER_SIZE]; + +//------------- Reporter Task Data -------------// + +//------------- Helper Function Prototypes -------------// +static inline uint8_t get_new_address(void) ATTR_ALWAYS_INLINE; +static inline uint8_t get_configure_number_for_device(tusb_descriptor_device_t* dev_desc) ATTR_ALWAYS_INLINE; + +//--------------------------------------------------------------------+ +// PUBLIC API (Parameter Verification is required) +//--------------------------------------------------------------------+ +tusb_device_state_t tusbh_device_get_state (uint8_t const dev_addr) +{ + ASSERT_INT_WITHIN(1, TUSB_CFG_HOST_DEVICE_MAX, dev_addr, TUSB_DEVICE_STATE_INVALID_PARAMETER); + return (tusb_device_state_t) usbh_devices[dev_addr].state; +} + +uint32_t tusbh_device_get_mounted_class_flag(uint8_t dev_addr) +{ + return tusbh_device_is_configured(dev_addr) ? usbh_devices[dev_addr].flag_supported_class : 0; +} + +//--------------------------------------------------------------------+ +// CLASS-USBD API (don't require to verify parameters) +//--------------------------------------------------------------------+ +tusb_error_t usbh_init(void) +{ + memclr_(usbh_devices, sizeof(usbh_device_info_t)*(TUSB_CFG_HOST_DEVICE_MAX+1)); + + ASSERT_STATUS( hcd_init() ); + + //------------- Enumeration & Reporter Task init -------------// + enum_queue_hdl = osal_queue_create( OSAL_QUEUE_REF(enum_queue_def) ); + ASSERT_PTR(enum_queue_hdl, TUSB_ERROR_OSAL_QUEUE_FAILED); + ASSERT_STATUS( osal_task_create( OSAL_TASK_REF(usbh_enumeration_task) )); + + //------------- Semaphore, Mutex for Control Pipe -------------// + for(uint8_t i=0; icontrol.sem_hdl = osal_semaphore_create( OSAL_SEM_REF(p_device->control.semaphore) ); + ASSERT_PTR(p_device->control.sem_hdl, TUSB_ERROR_OSAL_SEMAPHORE_FAILED); + + p_device->control.mutex_hdl = osal_mutex_create ( OSAL_MUTEX_REF(p_device->control.mutex) ); + ASSERT_PTR(p_device->control.mutex_hdl, TUSB_ERROR_OSAL_MUTEX_FAILED); + } + + //------------- class init -------------// + for (uint8_t class_index = 1; class_index < TUSB_CLASS_MAPPED_INDEX_END; class_index++) + { + if (usbh_class_drivers[class_index].init) + { + usbh_class_drivers[class_index].init(); + } + } + + return TUSB_ERROR_NONE; +} + +//------------- USBH control transfer -------------// +// function called within a task, requesting os blocking services, subtask input parameter must be static/global variables or constant +tusb_error_t usbh_control_xfer_subtask(uint8_t dev_addr, uint8_t bmRequestType, uint8_t bRequest, + uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t* data) +{ + static tusb_error_t error; // FIXME cmsis-rtx use svc for OS API, error value changed after mutex release at the end of function + + OSAL_SUBTASK_BEGIN + + osal_mutex_wait(usbh_devices[dev_addr].control.mutex_hdl, OSAL_TIMEOUT_NORMAL, &error); + SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl)); + + usbh_devices[dev_addr].control.request = (tusb_control_request_t) { + {.bmRequestType = bmRequestType}, + .bRequest = bRequest, + .wValue = wValue, + .wIndex = wIndex, + .wLength = wLength + }; + +#ifndef _TEST_ + usbh_devices[dev_addr].control.pipe_status = 0; +#else + usbh_devices[dev_addr].control.pipe_status = TUSB_EVENT_XFER_COMPLETE; // in Test project, mark as complete immediately +#endif + + SUBTASK_ASSERT_STATUS_WITH_HANDLER( hcd_pipe_control_xfer(dev_addr, &usbh_devices[dev_addr].control.request, data), + osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl) ); + + osal_semaphore_wait(usbh_devices[dev_addr].control.sem_hdl, OSAL_TIMEOUT_NORMAL, &error); // careful of local variable without static + osal_mutex_release(usbh_devices[dev_addr].control.mutex_hdl); + + // TODO make handler for this function general purpose + if (TUSB_ERROR_NONE != error) SUBTASK_EXIT(error); + if (TUSB_EVENT_XFER_STALLED == usbh_devices[dev_addr].control.pipe_status) SUBTASK_EXIT(TUSB_ERROR_USBH_XFER_STALLED); + if (TUSB_EVENT_XFER_ERROR == usbh_devices[dev_addr].control.pipe_status) SUBTASK_EXIT(TUSB_ERROR_USBH_XFER_FAILED); + +// SUBTASK_ASSERT_WITH_HANDLER(TUSB_ERROR_NONE == error && +// TUSB_EVENT_XFER_COMPLETE == usbh_devices[dev_addr].control.pipe_status, +// tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND, NULL) ); + + OSAL_SUBTASK_END +} + +tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) ATTR_ALWAYS_INLINE; +tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) +{ + osal_semaphore_reset( usbh_devices[dev_addr].control.sem_hdl ); + osal_mutex_reset( usbh_devices[dev_addr].control.mutex_hdl ); + + ASSERT_STATUS( hcd_pipe_control_open(dev_addr, max_packet_size) ); + + return TUSB_ERROR_NONE; +} + +static inline tusb_error_t usbh_pipe_control_close(uint8_t dev_addr) ATTR_ALWAYS_INLINE; +static inline tusb_error_t usbh_pipe_control_close(uint8_t dev_addr) +{ + ASSERT_STATUS( hcd_pipe_control_close(dev_addr) ); + + return TUSB_ERROR_NONE; +} + +tusb_interface_status_t usbh_pipe_status_get(pipe_handle_t pipe_hdl) +{ + return TUSB_INTERFACE_STATUS_BUSY; +} + +//--------------------------------------------------------------------+ +// USBH-HCD ISR/Callback API +//--------------------------------------------------------------------+ +// interrupt caused by a TD (with IOC=1) in pipe of class class_code +void usbh_xfer_isr(pipe_handle_t pipe_hdl, uint8_t class_code, tusb_event_t event, uint32_t xferred_bytes) +{ + uint8_t class_index = std_class_code_to_index(class_code); + if (TUSB_XFER_CONTROL == pipe_hdl.xfer_type) + { + usbh_devices[ pipe_hdl.dev_addr ].control.pipe_status = event; +// usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary + osal_semaphore_post( usbh_devices[ pipe_hdl.dev_addr ].control.sem_hdl ); + }else if (usbh_class_drivers[class_index].isr) + { + usbh_class_drivers[class_index].isr(pipe_hdl, event, xferred_bytes); + }else + { + ASSERT(false, VOID_RETURN); // something wrong, no one claims the isr's source + } +} + +void usbh_hub_port_plugged_isr(uint8_t hub_addr, uint8_t hub_port) +{ + osal_queue_send(enum_queue_hdl, + &(usbh_enumerate_t){ + .core_id = usbh_devices[hub_addr].core_id, + .hub_addr = hub_addr, + .hub_port = hub_port} + ); +} + +void usbh_hcd_rhport_plugged_isr(uint8_t hostid) +{ + osal_queue_send(enum_queue_hdl, + &(usbh_enumerate_t){ + .core_id = hostid, + .hub_addr = 0, + .hub_port = 0} + ); +} + +// a device unplugged on hostid, hub_addr, hub_port +// return true if found and unmounted device, false if cannot find +static void usbh_device_unplugged(uint8_t hostid, uint8_t hub_addr, uint8_t hub_port) +{ + bool is_found = false; + //------------- find the all devices (star-network) under port that is unplugged -------------// + for (uint8_t dev_addr = 0; dev_addr <= TUSB_CFG_HOST_DEVICE_MAX; dev_addr ++) + { + if (usbh_devices[dev_addr].core_id == hostid && + (hub_addr == 0 || usbh_devices[dev_addr].hub_addr == hub_addr) && // hub_addr == 0 & hub_port == 0 means roothub + (hub_port == 0 || usbh_devices[dev_addr].hub_port == hub_port) && + usbh_devices[dev_addr].state != TUSB_DEVICE_STATE_UNPLUG) + { + // TODO Hub multiple level + for (uint8_t class_index = 1; class_index < TUSB_CLASS_MAPPED_INDEX_END; class_index++) + { + if ((usbh_devices[dev_addr].flag_supported_class & BIT_(class_index)) && + usbh_class_drivers[class_index].close) + { + usbh_class_drivers[class_index].close(dev_addr); + } + } + + // TODO refractor + // set to REMOVING to allow HCD to clean up its cached data for this device + // HCD must set this device's state to TUSB_DEVICE_STATE_UNPLUG when done + usbh_devices[dev_addr].state = TUSB_DEVICE_STATE_REMOVING; + usbh_devices[dev_addr].flag_supported_class = 0; + + usbh_pipe_control_close(dev_addr); + + + is_found = true; + } + } + + if (is_found) hcd_port_unplug(usbh_devices[0].core_id); // TODO hack + +} + +void usbh_hcd_rhport_unplugged_isr(uint8_t hostid) +{ + osal_queue_send(enum_queue_hdl, + &(usbh_enumerate_t) + { + .core_id = hostid, + .hub_addr = 0, + .hub_port = 0 + } ); +} + +//--------------------------------------------------------------------+ +// ENUMERATION TASK +//--------------------------------------------------------------------+ +static tusb_error_t enumeration_body_subtask(void); + +// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper +// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with +// forever loop cannot have any return at all. +OSAL_TASK_FUNCTION(usbh_enumeration_task) (void* p_task_para) +{ + OSAL_TASK_LOOP_BEGIN + + enumeration_body_subtask(); + + OSAL_TASK_LOOP_END +} + +tusb_error_t enumeration_body_subtask(void) +{ + enum { + POWER_STABLE_DELAY = 300, + RESET_DELAY = 100 // NXP's EHCI require more than 50ms to work properly although the USB specs say only 50ms + }; + + tusb_error_t error; + usbh_enumerate_t enum_entry; + + // for OSAL_NONE local variable won't retain value after blocking service sem_wait/queue_recv + static uint8_t new_addr; + static uint8_t configure_selected = 1; // TODO move + static uint8_t *p_desc = NULL; // TODO move + + OSAL_SUBTASK_BEGIN + + osal_queue_receive(enum_queue_hdl, &enum_entry, OSAL_TIMEOUT_WAIT_FOREVER, &error); + SUBTASK_ASSERT_STATUS(error); + + usbh_devices[0].core_id = enum_entry.core_id; // TODO refractor integrate to device_pool + usbh_devices[0].hub_addr = enum_entry.hub_addr; + usbh_devices[0].hub_port = enum_entry.hub_port; + usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG; + + //------------- connected/disconnected directly with roothub -------------// + if ( usbh_devices[0].hub_addr == 0) + { + if( hcd_port_connect_status(usbh_devices[0].core_id) ) + { // connection event + osal_task_delay(POWER_STABLE_DELAY); // wait until device is stable. Increase this if the first 8 bytes is failed to get + + if ( !hcd_port_connect_status(usbh_devices[0].core_id) ) SUBTASK_EXIT(TUSB_ERROR_NONE); // exit if device unplugged while delaying + + hcd_port_reset( usbh_devices[0].core_id ); // port must be reset to have correct speed operation + osal_task_delay(RESET_DELAY); + + usbh_devices[0].speed = hcd_port_speed_get( usbh_devices[0].core_id ); + } + else + { // disconnection event + usbh_device_unplugged(usbh_devices[0].core_id, 0, 0); + SUBTASK_EXIT(TUSB_ERROR_NONE); // restart task + } + } + #if TUSB_CFG_HOST_HUB + //------------- connected/disconnected via hub -------------// + else + { + //------------- Get Port Status -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( usbh_devices[0].hub_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_CLASS, TUSB_REQUEST_RECIPIENT_OTHER), + HUB_REQUEST_GET_STATUS, 0, usbh_devices[0].hub_port, + 4, enum_data_buffer ), + error + ); +// SUBTASK_ASSERT_STATUS( error ); + SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor + + // Acknowledge Port Connection Change + OSAL_SUBTASK_INVOKED_AND_WAIT( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_CONNECTION_CHANGE), error ); + + if ( ! ((hub_port_status_response_t *) enum_data_buffer)->status_change.connect_status ) SUBTASK_EXIT(TUSB_ERROR_NONE); // only handle connection change + + if ( ! ((hub_port_status_response_t *) enum_data_buffer)->status_current.connect_status ) + { // Disconnection event + usbh_device_unplugged(usbh_devices[0].core_id, usbh_devices[0].hub_addr, usbh_devices[0].hub_port); + + (void) hub_status_pipe_queue( usbh_devices[0].hub_addr ); // done with hub, waiting for next data on status pipe + SUBTASK_EXIT(TUSB_ERROR_NONE); // restart task + } + else + { // Connection Event + OSAL_SUBTASK_INVOKED_AND_WAIT ( hub_port_reset_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port), error ); +// SUBTASK_ASSERT_STATUS( error ); + SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor + + usbh_devices[0].speed = hub_port_get_speed(); + + // Acknowledge Port Reset Change + OSAL_SUBTASK_INVOKED_AND_WAIT( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_RESET_CHANGE), error ); + } + } + #endif + + SUBTASK_ASSERT_STATUS( usbh_pipe_control_open(0, 8) ); + usbh_devices[0].state = TUSB_DEVICE_STATE_ADDRESSED; + + //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( 0, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), + TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_DEVICE << 8), 0, + 8, enum_data_buffer ), + error + ); + + //------------- Reset device again before Set Address -------------// + if (usbh_devices[0].hub_addr == 0) + { // connected directly to roothub + SUBTASK_ASSERT_STATUS(error); // TODO some slow device is observed to fail the very fist controller xfer, can try more times + hcd_port_reset( usbh_devices[0].core_id ); // reset port after 8 byte descriptor + osal_task_delay(RESET_DELAY); + } + #if TUSB_CFG_HOST_HUB + else + { // connected via a hub + SUBTASK_ASSERT_STATUS_WITH_HANDLER(error, hub_status_pipe_queue( usbh_devices[0].hub_addr) ); // TODO hub refractor + OSAL_SUBTASK_INVOKED_AND_WAIT ( hub_port_reset_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port), error ); + + if ( TUSB_ERROR_NONE == error ) + { // Acknowledge Port Reset Change if Reset Successful + OSAL_SUBTASK_INVOKED_AND_WAIT( hub_port_clear_feature_subtask(usbh_devices[0].hub_addr, usbh_devices[0].hub_port, HUB_FEATURE_PORT_RESET_CHANGE), error ); + } + + (void) hub_status_pipe_queue( usbh_devices[0].hub_addr ); // done with hub, waiting for next data on status pipe + } + #endif + + //------------- Set new address -------------// + new_addr = get_new_address(); + SUBTASK_ASSERT(new_addr <= TUSB_CFG_HOST_DEVICE_MAX); // TODO notify application we reach max devices + + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( 0, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), + TUSB_REQUEST_SET_ADDRESS, new_addr, 0, + 0, NULL ), + error + ); + SUBTASK_ASSERT_STATUS(error); + + //------------- update port info & close control pipe of addr0 -------------// + usbh_devices[new_addr].core_id = usbh_devices[0].core_id; + usbh_devices[new_addr].hub_addr = usbh_devices[0].hub_addr; + usbh_devices[new_addr].hub_port = usbh_devices[0].hub_port; + usbh_devices[new_addr].speed = usbh_devices[0].speed; + usbh_devices[new_addr].state = TUSB_DEVICE_STATE_ADDRESSED; + + usbh_pipe_control_close(0); + usbh_devices[0].state = TUSB_DEVICE_STATE_UNPLUG; + + // open control pipe for new address + SUBTASK_ASSERT_STATUS ( usbh_pipe_control_open(new_addr, ((tusb_descriptor_device_t*) enum_data_buffer)->bMaxPacketSize0 ) ); + + //------------- Get full device descriptor -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), + TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_DEVICE << 8), 0, + 18, enum_data_buffer ), + error + ); + SUBTASK_ASSERT_STATUS(error); + + // update device info TODO alignment issue + usbh_devices[new_addr].vendor_id = ((tusb_descriptor_device_t*) enum_data_buffer)->idVendor; + usbh_devices[new_addr].product_id = ((tusb_descriptor_device_t*) enum_data_buffer)->idProduct; + usbh_devices[new_addr].configure_count = ((tusb_descriptor_device_t*) enum_data_buffer)->bNumConfigurations; + + configure_selected = get_configure_number_for_device((tusb_descriptor_device_t*) enum_data_buffer); + SUBTASK_ASSERT(configure_selected <= usbh_devices[new_addr].configure_count); // TODO notify application when invalid configuration + + //------------- Get 9 bytes of configuration descriptor -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), + TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_CONFIGURATION << 8) | (configure_selected - 1), 0, + 9, enum_data_buffer ), + error + ); + SUBTASK_ASSERT_STATUS(error); + SUBTASK_ASSERT_WITH_HANDLER( TUSB_CFG_HOST_ENUM_BUFFER_SIZE >= ((tusb_descriptor_configuration_t*)enum_data_buffer)->wTotalLength, + tusbh_device_mount_failed_cb(TUSB_ERROR_USBH_MOUNT_CONFIG_DESC_TOO_LONG, NULL) ); + + //------------- Get full configuration descriptor -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_DEV_TO_HOST, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), + TUSB_REQUEST_GET_DESCRIPTOR, (TUSB_DESC_TYPE_CONFIGURATION << 8) | (configure_selected - 1), 0, + TUSB_CFG_HOST_ENUM_BUFFER_SIZE, enum_data_buffer ), + error + ); + SUBTASK_ASSERT_STATUS(error); + + // update configuration info + usbh_devices[new_addr].interface_count = ((tusb_descriptor_configuration_t*) enum_data_buffer)->bNumInterfaces; + + //------------- Set Configure -------------// + OSAL_SUBTASK_INVOKED_AND_WAIT( + usbh_control_xfer_subtask( new_addr, bm_request_type(TUSB_DIR_HOST_TO_DEV, TUSB_REQUEST_TYPE_STANDARD, TUSB_REQUEST_RECIPIENT_DEVICE), + TUSB_REQUEST_SET_CONFIGURATION, configure_selected, 0, + 0, NULL ), + error + ); + SUBTASK_ASSERT_STATUS(error); + + usbh_devices[new_addr].state = TUSB_DEVICE_STATE_CONFIGURED; + + //------------- TODO Get String Descriptors -------------// + + //------------- parse configuration & install drivers -------------// + p_desc = enum_data_buffer + sizeof(tusb_descriptor_configuration_t); + + // parse each interfaces + while( p_desc < enum_data_buffer + ((tusb_descriptor_configuration_t*)enum_data_buffer)->wTotalLength ) + { + // skip until we see interface descriptor + if ( TUSB_DESC_TYPE_INTERFACE != p_desc[DESCRIPTOR_OFFSET_TYPE] ) + { + p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip the descriptor, increase by the descriptor's length + }else + { + static uint8_t class_index; // has to be static as it is used to call class's open_subtask + + class_index = std_class_code_to_index( ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass ); + SUBTASK_ASSERT( class_index != 0 ); // class_index == 0 means corrupted data, abort enumeration + + if (usbh_class_drivers[class_index].open_subtask && + !(class_index == TUSB_CLASS_HUB && usbh_devices[new_addr].hub_addr != 0)) + { // supported class, TODO Hub disable multiple level + static uint16_t length; + length = 0; + + OSAL_SUBTASK_INVOKED_AND_WAIT ( // parameters in task/sub_task must be static storage (static or global) + usbh_class_drivers[class_index].open_subtask( new_addr, (tusb_descriptor_interface_t*) p_desc, &length ), + error + ); + + if (error == TUSB_ERROR_NONE) + { + SUBTASK_ASSERT( length >= sizeof(tusb_descriptor_interface_t) ); + usbh_devices[new_addr].flag_supported_class |= BIT_(class_index); + p_desc += length; + }else // Interface open failed, for example a subclass is not supported + { + p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip this interface, the rest will be skipped by the above loop + } + } else // unsupported class (not enable or yet implemented) + { + p_desc += p_desc[DESCRIPTOR_OFFSET_LENGTH]; // skip this interface, the rest will be skipped by the above loop + } + } + } + + tusbh_device_mount_succeed_cb(new_addr); + + OSAL_SUBTASK_END +} + +//--------------------------------------------------------------------+ +// REPORTER TASK & ITS DATA +//--------------------------------------------------------------------+ + + + + + +//--------------------------------------------------------------------+ +// INTERNAL HELPER +//--------------------------------------------------------------------+ +static inline uint8_t get_new_address(void) +{ + uint8_t addr; + for (addr=1; addr <= TUSB_CFG_HOST_DEVICE_MAX; addr++) + { + if (usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG) + break; + } + return addr; +} + +static inline uint8_t get_configure_number_for_device(tusb_descriptor_device_t* dev_desc) +{ + uint8_t config_num = 1; + + // invoke callback to ask user which configuration to select + if (tusbh_device_attached_cb) + { + config_num = min8_of(1, tusbh_device_attached_cb(dev_desc) ); + } + + return config_num; +} + +#endif