diff options
| author | hathach <[email protected]> | 2014-03-10 14:20:38 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2014-03-10 14:20:38 +0700 |
| commit | b586fe632acb45dc0577a9ab447fe02ab6cb457d (patch) | |
| tree | 6befaafae699e40ac96e32233336ef0e251a2cea /tinyusb | |
| parent | ad72db5aeacf7d969f5c091c59a2f279eaf1c19c (diff) | |
change desc_str_table to array of pointer of uint8_t* to be compatible with IAR (lack of support for VLA initialization)
IAR device os none works with ea4357
Diffstat (limited to 'tinyusb')
| -rw-r--r-- | tinyusb/common/common.h | 582 | ||||
| -rw-r--r-- | tinyusb/device/dcd_lpc43xx.c | 8 | ||||
| -rw-r--r-- | tinyusb/device/usbd.c | 2 | ||||
| -rw-r--r-- | tinyusb/host/usbh.c | 1266 |
4 files changed, 929 insertions, 929 deletions
diff --git a/tinyusb/common/common.h b/tinyusb/common/common.h index 4933634d2..db4d72661 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 <stddef.h> -#include <string.h> -#include <stdio.h> - -//------------- 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 <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+//------------- 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 05e47fd11..036c65a64 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 38d139f1f..0b9044db9 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 f15cdfebb..be7c3f42d 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; i<TUSB_CFG_HOST_DEVICE_MAX+1; i++) // including address zero - { - usbh_device_info_t * const p_device = &usbh_devices[i]; - - p_device->control.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; i<TUSB_CFG_HOST_DEVICE_MAX+1; i++) // including address zero
+ {
+ usbh_device_info_t * const p_device = &usbh_devices[i];
+
+ p_device->control.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
|
