summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorhathach <[email protected]>2018-12-12 16:49:38 +0700
committerhathach <[email protected]>2018-12-12 16:49:38 +0700
commitaa17ec60d3abdc3179d4d496bc072ed633bb67ce (patch)
treecda3b554b289ab50f650aa0e7b30adb79e33be22 /src/common
parentc4a37237171855c0147699c263673c88f2fa6d5d (diff)
parent908931320e206e6ae6610cfc56b2a0950f252172 (diff)
Merge branch 'develop'
Diffstat (limited to 'src/common')
-rw-r--r--src/common/binary.h132
-rw-r--r--src/common/compiler/tusb_compiler_gcc.h135
-rw-r--r--src/common/compiler/tusb_compiler_iar.h89
-rw-r--r--src/common/sys_queue.h871
-rw-r--r--src/common/tusb_common.h220
-rw-r--r--src/common/tusb_compiler.h83
-rw-r--r--src/common/tusb_error.h117
-rw-r--r--src/common/tusb_fifo.c280
-rw-r--r--src/common/tusb_fifo.h143
-rw-r--r--src/common/tusb_timeout.h98
-rw-r--r--src/common/tusb_types.h428
-rw-r--r--src/common/tusb_verify.h186
12 files changed, 2782 insertions, 0 deletions
diff --git a/src/common/binary.h b/src/common/binary.h
new file mode 100644
index 000000000..3ab87e3f8
--- /dev/null
+++ b/src/common/binary.h
@@ -0,0 +1,132 @@
+/**************************************************************************/
+/*!
+ @file binary.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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Common
+ * \defgroup Group_Binary Binary
+ * @{ */
+
+#ifndef _TUSB_BINARY_H_
+#define _TUSB_BINARY_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "tusb_compiler.h"
+
+//------------- Bit manipulation -------------//
+#define BIT_(n) (1U << (n)) ///< n-th Bit
+#define BIT_SET_(x, n) ( (x) | BIT_(n) ) ///< set n-th bit of x to 1
+#define BIT_CLR_(x, n) ( (x) & (~BIT_(n)) ) ///< clear n-th bit of x
+#define BIT_TEST_(x, n) ( ((x) & BIT_(n)) ? true : false ) ///< check if n-th bit of x is 1
+
+static inline uint32_t bit_set(uint32_t value, uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline uint32_t bit_set(uint32_t value, uint8_t n)
+{
+ return value | BIT_(n);
+}
+
+static inline uint32_t bit_clear(uint32_t value, uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline uint32_t bit_clear(uint32_t value, uint8_t n)
+{
+ return value & (~BIT_(n));
+}
+
+static inline bool bit_test(uint32_t value, uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline bool bit_test(uint32_t value, uint8_t n)
+{
+ return (value & BIT_(n)) ? true : false;
+}
+
+///< create a mask with n-bit lsb set to 1
+static inline uint32_t bit_mask(uint8_t n) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline uint32_t bit_mask(uint8_t n)
+{
+ return (n < 32) ? ( BIT_(n) - 1 ) : UINT32_MAX;
+}
+
+static inline uint32_t bit_mask_range(uint8_t start, uint32_t end) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline uint32_t bit_mask_range(uint8_t start, uint32_t end)
+{
+ return bit_mask(end+1) & ~ bit_mask(start);
+}
+
+static inline uint32_t bit_set_range(uint32_t value, uint8_t start, uint8_t end, uint32_t pattern) ATTR_CONST ATTR_ALWAYS_INLINE;
+static inline uint32_t bit_set_range(uint32_t value, uint8_t start, uint8_t end, uint32_t pattern)
+{
+ return ( value & ~bit_mask_range(start, end) ) | (pattern << start);
+}
+
+
+//------------- Binary Constant -------------//
+#if defined(__GNUC__) && !defined(__CC_ARM)
+
+#define BIN8(x) ((uint8_t) (0b##x))
+#define BIN16(b1, b2) ((uint16_t) (0b##b1##b2))
+#define BIN32(b1, b2, b3, b4) ((uint32_t) (0b##b1##b2##b3##b4))
+
+#else
+
+// internal macro of B8, B16, B32
+#define _B8__(x) (((x&0x0000000FUL)?1:0) \
+ +((x&0x000000F0UL)?2:0) \
+ +((x&0x00000F00UL)?4:0) \
+ +((x&0x0000F000UL)?8:0) \
+ +((x&0x000F0000UL)?16:0) \
+ +((x&0x00F00000UL)?32:0) \
+ +((x&0x0F000000UL)?64:0) \
+ +((x&0xF0000000UL)?128:0))
+
+#define BIN8(d) ((uint8_t) _B8__(0x##d##UL))
+#define BIN16(dmsb,dlsb) (((uint16_t)BIN8(dmsb)<<8) + BIN8(dlsb))
+#define BIN32(dmsb,db2,db3,dlsb) \
+ (((uint32_t)BIN8(dmsb)<<24) \
+ + ((uint32_t)BIN8(db2)<<16) \
+ + ((uint32_t)BIN8(db3)<<8) \
+ + BIN8(dlsb))
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_BINARY_H_ */
+
+/** @} */
diff --git a/src/common/compiler/tusb_compiler_gcc.h b/src/common/compiler/tusb_compiler_gcc.h
new file mode 100644
index 000000000..e40ad9c41
--- /dev/null
+++ b/src/common/compiler/tusb_compiler_gcc.h
@@ -0,0 +1,135 @@
+/**************************************************************************/
+/*!
+ @file compiler_gcc.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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Compiler
+ * \defgroup Group_GCC GNU GCC
+ * @{ */
+
+#ifndef _TUSB_COMPILER_GCC_H_
+#define _TUSB_COMPILER_GCC_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define ALIGN_OF(x) __alignof__(x)
+
+/// Normally, the compiler places the objects it generates in sections like data or bss & function in text. Sometimes, however, you need additional sections, or you need certain particular variables to appear in special sections, for example to map to special hardware. The section attribute specifies that a variable (or function) lives in a particular section
+#define ATTR_SECTION(sec_name) __attribute__ (( section(#sec_name) ))
+
+/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, an error that includes message is diagnosed. This is useful for compile-time checking
+#define ATTR_ERROR(Message) __attribute__ ((error(Message)))
+
+/// If this attribute is used on a function declaration and a call to such a function is not eliminated through dead code elimination or other optimizations, a warning that includes message is diagnosed. This is useful for compile-time checking
+#define ATTR_WARNING(Message) __attribute__ ((warning(Message)))
+
+/** \defgroup Group_VariableAttr Variable Attributes
+ * @{ */
+
+/// This attribute specifies a minimum alignment for the variable or structure field, measured in bytes
+#define ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
+
+/// The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable, and one bit for a field, unless you specify a larger value with the aligned attribute
+#define ATTR_PACKED __attribute__ ((packed))
+#define ATTR_PREPACKED
+
+/** @} */
+
+/** \defgroup Group_FuncAttr Function Attributes
+ * @{ */
+
+/// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified
+#define ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
+
+/// The nonnull attribute specifies that some function parameters should be non-null pointers. f the compiler determines that a null pointer is passed in an argument slot marked as non-null, and the -Wnonnull option is enabled, a warning is issued. All pointer arguments are marked as non-null
+#define ATTR_NON_NULL __attribute__ ((nonull))
+
+/// Many functions have no effects except the return value and their return value depends only on the parameters and/or global variables. Such a function can be subject to common subexpression elimination and loop optimization just as an arithmetic operator would be. These functions should be declared with the attribute pure
+#define ATTR_PURE __attribute__ ((pure))
+
+/// \brief Many functions do not examine any values except their arguments, and have no effects except the return value. Basically this is just slightly more strict class than the pure attribute below, since function is not allowed to read global memory.
+/// Note that a function that has pointer arguments and examines the data pointed to must not be declared const. Likewise, a function that calls a non-const function usually must not be const. It does not make sense for a const function to return void
+#define ATTR_CONST __attribute__ ((const))
+
+/// The deprecated attribute results in a warning if the function is used anywhere in the source file. This is useful when identifying functions that are expected to be removed in a future version of a program. The warning also includes the location of the declaration of the deprecated function, to enable users to easily find further information about why the function is deprecated, or what they should do instead. Note that the warnings only occurs for uses
+#define ATTR_DEPRECATED __attribute__ ((deprecated))
+
+/// Same as the deprecated attribute with optional message in the warning
+#define ATTR_DEPRECATED_MESS(mess) __attribute__ ((deprecated(mess)))
+
+/// The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions that can be overridden in user code
+#define ATTR_WEAK __attribute__ ((weak))
+
+/// The alias attribute causes the declaration to be emitted as an alias for another symbol, which must be specified
+#define ATTR_ALIAS(func) __attribute__ ((alias(#func)))
+
+/// The weakref attribute marks a declaration as a weak reference. It is equivalent with weak + alias attribute, but require function is static
+#define ATTR_WEAKREF(func) __attribute__ ((weakref(#func)))
+
+/// The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this attribute does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug
+#define ATTR_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+
+/// This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced. This is useful, for example, when the function is referenced only in inline assembly.
+#define ATTR_USED __attribute__ ((used))
+
+/// This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function.
+#define ATTR_UNUSED __attribute__ ((unused))
+
+/** @} */
+
+/** \defgroup Group_BuiltinFunc Built-in Functions
+* @{ */
+
+// TODO mcu specific
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define __n2be(x) __builtin_bswap32(x) ///< built-in function to convert 32-bit from native to Big Endian
+#define __be2n(x) __n2be(x) ///< built-in function to convert 32-bit from Big Endian to native
+
+#define __n2be_16(u16) __builtin_bswap16(u16)
+#define __be2n_16(u16) __n2be_16(u16)
+#endif
+
+/** @} */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_COMPILER_GCC_H_ */
+
+/// @}
diff --git a/src/common/compiler/tusb_compiler_iar.h b/src/common/compiler/tusb_compiler_iar.h
new file mode 100644
index 000000000..1f8936859
--- /dev/null
+++ b/src/common/compiler/tusb_compiler_iar.h
@@ -0,0 +1,89 @@
+/**************************************************************************/
+/*!
+ @file compiler_iar.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.
+*/
+/**************************************************************************/
+
+/** \file
+ * \brief IAR Compiler
+ */
+
+/** \ingroup Group_Compiler
+ * \defgroup Group_IAR IAR ARM
+ * @{
+ */
+
+#ifndef _TUSB_COMPILER_IAR_H_
+#define _TUSB_COMPILER_IAR_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define ALIGN_OF(x) __ALIGNOF__(x)
+#define ATTR_PREPACKED __packed
+#define ATTR_PACKED
+//#define ATTR_SECTION(section) _Pragma((#section))
+
+#define ATTR_ALIGNED(bytes) _Pragma(XSTRING_(data_alignment=##bytes))
+
+#ifndef ATTR_ALWAYS_INLINE
+/// Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified
+#define ATTR_ALWAYS_INLINE error
+#endif
+
+#define ATTR_PURE // TODO IAR pure function attribute
+#define ATTR_CONST // TODO IAR const function attribute
+#define ATTR_WEAK __weak
+
+#define ATTR_WARN_UNUSED_RESULT
+#define ATTR_USED
+#define ATTR_UNUSED
+
+// built-in function to convert 32-bit Big-Endian to Little-Endian
+//#if __LITTLE_ENDIAN__
+#define __be2n __REV
+#define __n2be __be2n
+
+#define __n2be_16(u16) ((uint16_t) __REV16(u16))
+#define __be2n_16(u16) __n2be_16(u16)
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_COMPILER_IAR_H_ */
+
+/** @} */
diff --git a/src/common/sys_queue.h b/src/common/sys_queue.h
new file mode 100644
index 000000000..443f01b22
--- /dev/null
+++ b/src/common/sys_queue.h
@@ -0,0 +1,871 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. 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 University 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 REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ * $FreeBSD$
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may be traversed in either direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ * Below is a summary of implemented functions where:
+ * + means the macro is available
+ * - means the macro is not available
+ * s means the macro is available but is slow (runs in O(n) time)
+ *
+ * SLIST LIST STAILQ TAILQ
+ * _HEAD + + + +
+ * _CLASS_HEAD + + + +
+ * _HEAD_INITIALIZER + + + +
+ * _ENTRY + + + +
+ * _CLASS_ENTRY + + + +
+ * _INIT + + + +
+ * _EMPTY + + + +
+ * _FIRST + + + +
+ * _NEXT + + + +
+ * _PREV - + - +
+ * _LAST - - + +
+ * _LAST_FAST - - - +
+ * _FOREACH + + + +
+ * _FOREACH_FROM + + + +
+ * _FOREACH_SAFE + + + +
+ * _FOREACH_FROM_SAFE + + + +
+ * _FOREACH_REVERSE - - - +
+ * _FOREACH_REVERSE_FROM - - - +
+ * _FOREACH_REVERSE_SAFE - - - +
+ * _FOREACH_REVERSE_FROM_SAFE - - - +
+ * _INSERT_HEAD + + + +
+ * _INSERT_BEFORE - + - +
+ * _INSERT_AFTER + + + +
+ * _INSERT_TAIL - - + +
+ * _CONCAT s s + +
+ * _REMOVE_AFTER + - + -
+ * _REMOVE_HEAD + - + -
+ * _REMOVE s + s +
+ * _SWAP + + + +
+ *
+ */
+#ifdef QUEUE_MACRO_DEBUG
+#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
+#define QUEUE_MACRO_DEBUG_TRACE
+#define QUEUE_MACRO_DEBUG_TRASH
+#endif
+
+#ifdef QUEUE_MACRO_DEBUG_TRACE
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+ unsigned long lastline;
+ unsigned long prevline;
+ const char *lastfile;
+ const char *prevfile;
+};
+
+#define TRACEBUF struct qm_trace trace;
+#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
+
+#define QMD_TRACE_HEAD(head) do { \
+ (head)->trace.prevline = (head)->trace.lastline; \
+ (head)->trace.prevfile = (head)->trace.lastfile; \
+ (head)->trace.lastline = __LINE__; \
+ (head)->trace.lastfile = __FILE__; \
+} while (0)
+
+#define QMD_TRACE_ELEM(elem) do { \
+ (elem)->trace.prevline = (elem)->trace.lastline; \
+ (elem)->trace.prevfile = (elem)->trace.lastfile; \
+ (elem)->trace.lastline = __LINE__; \
+ (elem)->trace.lastfile = __FILE__; \
+} while (0)
+
+#else /* !QUEUE_MACRO_DEBUG_TRACE */
+#define QMD_TRACE_ELEM(elem)
+#define QMD_TRACE_HEAD(head)
+#define TRACEBUF
+#define TRACEBUF_INITIALIZER
+#endif /* QUEUE_MACRO_DEBUG_TRACE */
+
+#ifdef QUEUE_MACRO_DEBUG_TRASH
+#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
+#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1)
+#else /* !QUEUE_MACRO_DEBUG_TRASH */
+#define TRASHIT(x)
+#define QMD_IS_TRASHED(x) 0
+#endif /* QUEUE_MACRO_DEBUG_TRASH */
+
+#if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH)
+#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
+#else /* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */
+#define QMD_SAVELINK(name, link)
+#endif /* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */
+
+#ifdef __cplusplus
+/*
+ * In C++ there can be structure lists and class lists:
+ */
+#define QUEUE_TYPEOF(type) type
+#else
+#define QUEUE_TYPEOF(type) struct type
+#endif
+
+/*
+ * Singly-linked List declarations.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_CLASS_HEAD(name, type) \
+struct name { \
+ class type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+#define SLIST_CLASS_ENTRY(type) \
+struct { \
+ class type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \
+ if (*(prevp) != (elm)) \
+ panic("Bad prevptr *(%p) == %p != %p", \
+ (prevp), *(prevp), (elm)); \
+} while (0)
+#else
+#define QMD_SLIST_CHECK_PREVPTR(prevp, elm)
+#endif
+
+#define SLIST_CONCAT(head1, head2, type, field) do { \
+ QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
+ if (curelm == NULL) { \
+ if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
+ SLIST_INIT(head2); \
+ } else if (SLIST_FIRST(head2) != NULL) { \
+ while (SLIST_NEXT(curelm, field) != NULL) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \
+ SLIST_INIT(head2); \
+ } \
+} while (0)
+
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+
+#define SLIST_FIRST(head) ((head)->slh_first)
+
+#define SLIST_FOREACH(var, head, field) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
+ (var); \
+ (var) = SLIST_NEXT((var), field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
+ (var) && ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
+ for ((varp) = &SLIST_FIRST((head)); \
+ ((var) = *(varp)) != NULL; \
+ (varp) = &SLIST_NEXT((var), field))
+
+#define SLIST_INIT(head) do { \
+ SLIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
+ SLIST_NEXT((slistelm), field) = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
+ SLIST_FIRST((head)) = (elm); \
+} while (0)
+
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
+ if (SLIST_FIRST((head)) == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \
+ while (SLIST_NEXT(curelm, field) != (elm)) \
+ curelm = SLIST_NEXT(curelm, field); \
+ SLIST_REMOVE_AFTER(curelm, field); \
+ } \
+ TRASHIT(*oldnext); \
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do { \
+ SLIST_NEXT(elm, field) = \
+ SLIST_NEXT(SLIST_NEXT(elm, field), field); \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
+} while (0)
+
+#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \
+ QMD_SLIST_CHECK_PREVPTR(prevp, elm); \
+ *(prevp) = SLIST_NEXT(elm, field); \
+ TRASHIT((elm)->field.sle_next); \
+} while (0)
+
+#define SLIST_SWAP(head1, head2, type) do { \
+ QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
+ SLIST_FIRST(head1) = SLIST_FIRST(head2); \
+ SLIST_FIRST(head2) = swap_first; \
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first;/* first element */ \
+ struct type **stqh_last;/* addr of last next element */ \
+}
+
+#define STAILQ_CLASS_HEAD(name, type) \
+struct name { \
+ class type *stqh_first; /* first element */ \
+ class type **stqh_last; /* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+#define STAILQ_CLASS_ENTRY(type) \
+struct { \
+ class type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_CONCAT(head1, head2) do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+} while (0)
+
+#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
+
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for((var) = STAILQ_FIRST((head)); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+#define STAILQ_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
+ (var); \
+ (var) = STAILQ_NEXT((var), field))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_INIT(head) do { \
+ STAILQ_FIRST((head)) = NULL; \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_NEXT((tqelm), field) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+ STAILQ_FIRST((head)) = (elm); \
+} while (0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ STAILQ_NEXT((elm), field) = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? NULL : \
+ __containerof((head)->stqh_last, \
+ QUEUE_TYPEOF(type), field.stqe_next))
+
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
+ if (STAILQ_FIRST((head)) == (elm)) { \
+ STAILQ_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \
+ while (STAILQ_NEXT(curelm, field) != (elm)) \
+ curelm = STAILQ_NEXT(curelm, field); \
+ STAILQ_REMOVE_AFTER(head, curelm, field); \
+ } \
+ TRASHIT(*oldnext); \
+} while (0)
+
+#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
+ if ((STAILQ_NEXT(elm, field) = \
+ STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_NEXT((elm), field); \
+} while (0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if ((STAILQ_FIRST((head)) = \
+ STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
+ (head)->stqh_last = &STAILQ_FIRST((head)); \
+} while (0)
+
+#define STAILQ_SWAP(head1, head2, type) do { \
+ QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \
+ QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \
+ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_FIRST(head2) = swap_first; \
+ (head2)->stqh_last = swap_last; \
+ if (STAILQ_EMPTY(head1)) \
+ (head1)->stqh_last = &STAILQ_FIRST(head1); \
+ if (STAILQ_EMPTY(head2)) \
+ (head2)->stqh_last = &STAILQ_FIRST(head2); \
+} while (0)
+
+
+/*
+ * List declarations.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_CLASS_HEAD(name, type) \
+struct name { \
+ class type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+#define LIST_CLASS_ENTRY(type) \
+struct { \
+ class type *le_next; /* next element */ \
+ class type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List functions.
+ */
+
+#if (defined(_KERNEL) && defined(INVARIANTS))
+/*
+ * QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME)
+ *
+ * If the list is non-empty, validates that the first element of the list
+ * points back at 'head.'
+ */
+#define QMD_LIST_CHECK_HEAD(head, field) do { \
+ if (LIST_FIRST((head)) != NULL && \
+ LIST_FIRST((head))->field.le_prev != \
+ &LIST_FIRST((head))) \
+ panic("Bad list head %p first->prev != head", (head)); \
+} while (0)
+
+/*
+ * QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME)
+ *
+ * If an element follows 'elm' in the list, validates that the next element
+ * points back at 'elm.'
+ */
+#define QMD_LIST_CHECK_NEXT(elm, field) do { \
+ if (LIST_NEXT((elm), field) != NULL && \
+ LIST_NEXT((elm), field)->field.le_prev != \
+ &((elm)->field.le_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+/*
+ * QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME)
+ *
+ * Validates that the previous element (or head of the list) points to 'elm.'
+ */
+#define QMD_LIST_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.le_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_LIST_CHECK_HEAD(head, field)
+#define QMD_LIST_CHECK_NEXT(elm, field)
+#define QMD_LIST_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define LIST_CONCAT(head1, head2, type, field) do { \
+ QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \
+ if (curelm == NULL) { \
+ if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \
+ LIST_FIRST(head2)->field.le_prev = \
+ &LIST_FIRST((head1)); \
+ LIST_INIT(head2); \
+ } \
+ } else if (LIST_FIRST(head2) != NULL) { \
+ while (LIST_NEXT(curelm, field) != NULL) \
+ curelm = LIST_NEXT(curelm, field); \
+ LIST_NEXT(curelm, field) = LIST_FIRST(head2); \
+ LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \
+ LIST_INIT(head2); \
+ } \
+} while (0)
+
+#define LIST_EMPTY(head) ((head)->lh_first == NULL)
+
+#define LIST_FIRST(head) ((head)->lh_first)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
+ (var); \
+ (var) = LIST_NEXT((var), field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
+ (var) && ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_INIT(head) do { \
+ LIST_FIRST((head)) = NULL; \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ QMD_LIST_CHECK_NEXT(listelm, field); \
+ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+ LIST_NEXT((listelm), field)->field.le_prev = \
+ &LIST_NEXT((elm), field); \
+ LIST_NEXT((listelm), field) = (elm); \
+ (elm)->field.le_prev = &LIST_NEXT((listelm), field); \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ QMD_LIST_CHECK_PREV(listelm, field); \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ LIST_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &LIST_NEXT((elm), field); \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ QMD_LIST_CHECK_HEAD((head), field); \
+ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->field.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_PREV(elm, head, type, field) \
+ ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
+ __containerof((elm)->field.le_prev, \
+ QUEUE_TYPEOF(type), field.le_next))
+
+#define LIST_REMOVE(elm, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.le_next); \
+ QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
+ QMD_LIST_CHECK_NEXT(elm, field); \
+ QMD_LIST_CHECK_PREV(elm, field); \
+ if (LIST_NEXT((elm), field) != NULL) \
+ LIST_NEXT((elm), field)->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
+ TRASHIT(*oldnext); \
+ TRASHIT(*oldprev); \
+} while (0)
+
+#define LIST_SWAP(head1, head2, type, field) do { \
+ QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \
+ LIST_FIRST((head1)) = LIST_FIRST((head2)); \
+ LIST_FIRST((head2)) = swap_tmp; \
+ if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
+ swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
+ if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
+ swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+ TRACEBUF \
+}
+
+#define TAILQ_CLASS_HEAD(name, type) \
+struct name { \
+ class type *tqh_first; /* first element */ \
+ class type **tqh_last; /* addr of last next element */ \
+ TRACEBUF \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+ TRACEBUF \
+}
+
+#define TAILQ_CLASS_ENTRY(type) \
+struct { \
+ class type *tqe_next; /* next element */ \
+ class type **tqe_prev; /* address of previous next element */ \
+ TRACEBUF \
+}
+
+/*
+ * Tail queue functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+/*
+ * QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
+ *
+ * If the tailq is non-empty, validates that the first element of the tailq
+ * points back at 'head.'
+ */
+#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
+ if (!TAILQ_EMPTY(head) && \
+ TAILQ_FIRST((head))->field.tqe_prev != \
+ &TAILQ_FIRST((head))) \
+ panic("Bad tailq head %p first->prev != head", (head)); \
+} while (0)
+
+/*
+ * QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
+ *
+ * Validates that the tail of the tailq is a pointer to pointer to NULL.
+ */
+#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
+ if (*(head)->tqh_last != NULL) \
+ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
+} while (0)
+
+/*
+ * QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME)
+ *
+ * If an element follows 'elm' in the tailq, validates that the next element
+ * points back at 'elm.'
+ */
+#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
+ if (TAILQ_NEXT((elm), field) != NULL && \
+ TAILQ_NEXT((elm), field)->field.tqe_prev != \
+ &((elm)->field.tqe_next)) \
+ panic("Bad link elm %p next->prev != elm", (elm)); \
+} while (0)
+
+/*
+ * QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME)
+ *
+ * Validates that the previous element (or head of the tailq) points to 'elm.'
+ */
+#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
+ if (*(elm)->field.tqe_prev != (elm)) \
+ panic("Bad link elm %p prev->next != elm", (elm)); \
+} while (0)
+#else
+#define QMD_TAILQ_CHECK_HEAD(head, field)
+#define QMD_TAILQ_CHECK_TAIL(head, headname)
+#define QMD_TAILQ_CHECK_NEXT(elm, field)
+#define QMD_TAILQ_CHECK_PREV(elm, field)
+#endif /* (_KERNEL && INVARIANTS) */
+
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ QMD_TRACE_HEAD(head1); \
+ QMD_TRACE_HEAD(head2); \
+ } \
+} while (0)
+
+#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_FROM(var, head, field) \
+ for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
+ (var); \
+ (var) = TAILQ_NEXT((var), field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST((head)); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
+ for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
+ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
+ for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
+ (var); \
+ (var) = TAILQ_PREV((var), headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
+ for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
+ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
+ (var) = (tvar))
+
+#define TAILQ_INIT(head) do { \
+ TAILQ_FIRST((head)) = NULL; \
+ (head)->tqh_last = &TAILQ_FIRST((head)); \
+ QMD_TRACE_HEAD(head); \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ QMD_TAILQ_CHECK_NEXT(listelm, field); \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else { \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ QMD_TRACE_HEAD(head); \
+ } \
+ TAILQ_NEXT((listelm), field) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+ QMD_TRACE_ELEM(&(listelm)->field); \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ QMD_TAILQ_CHECK_PREV(listelm, field); \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ TAILQ_NEXT((elm), field) = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+ QMD_TRACE_ELEM(&(listelm)->field); \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ QMD_TAILQ_CHECK_HEAD(head, field); \
+ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
+ TAILQ_FIRST((head))->field.tqe_prev = \
+ &TAILQ_NEXT((elm), field); \
+ else \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ TAILQ_FIRST((head)) = (elm); \
+ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
+ QMD_TRACE_HEAD(head); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ QMD_TAILQ_CHECK_TAIL(head, field); \
+ TAILQ_NEXT((elm), field) = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &TAILQ_NEXT((elm), field); \
+ QMD_TRACE_HEAD(head); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+} while (0)
+
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+/*
+ * The FAST function is fast in that it causes no data access other
+ * then the access to the head. The standard LAST function above
+ * will cause a data access of both the element you want and
+ * the previous element. FAST is very useful for instances when
+ * you may want to prefetch the last data element.
+ */
+#define TAILQ_LAST_FAST(head, type, field) \
+ (TAILQ_EMPTY(head) ? NULL : __containerof((head)->tqh_last, QUEUE_TYPEOF(type), field.tqe_next))
+
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
+ QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
+ QMD_TAILQ_CHECK_NEXT(elm, field); \
+ QMD_TAILQ_CHECK_PREV(elm, field); \
+ if ((TAILQ_NEXT((elm), field)) != NULL) \
+ TAILQ_NEXT((elm), field)->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else { \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ QMD_TRACE_HEAD(head); \
+ } \
+ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
+ TRASHIT(*oldnext); \
+ TRASHIT(*oldprev); \
+ QMD_TRACE_ELEM(&(elm)->field); \
+} while (0)
+
+#define TAILQ_SWAP(head1, head2, type, field) do { \
+ QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \
+ QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \
+ (head1)->tqh_first = (head2)->tqh_first; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ (head2)->tqh_first = swap_first; \
+ (head2)->tqh_last = swap_last; \
+ if ((swap_first = (head1)->tqh_first) != NULL) \
+ swap_first->field.tqe_prev = &(head1)->tqh_first; \
+ else \
+ (head1)->tqh_last = &(head1)->tqh_first; \
+ if ((swap_first = (head2)->tqh_first) != NULL) \
+ swap_first->field.tqe_prev = &(head2)->tqh_first; \
+ else \
+ (head2)->tqh_last = &(head2)->tqh_first; \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
new file mode 100644
index 000000000..f4fac96b8
--- /dev/null
+++ b/src/common/tusb_common.h
@@ -0,0 +1,220 @@
+/**************************************************************************/
+/*!
+ @file tusb_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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Common
+ * \defgroup Group_CommonH common.h
+ * @{ */
+
+#ifndef _TUSB_COMMON_H_
+#define _TUSB_COMMON_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// INCLUDES
+//--------------------------------------------------------------------+
+
+//------------- Standard Header -------------//
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+//------------- TUSB Option Header -------------//
+#include "tusb_option.h"
+
+//------------- Common Header -------------//
+#include "tusb_compiler.h"
+#include "tusb_verify.h"
+#include "binary.h"
+#include "tusb_error.h"
+#include "tusb_timeout.h"
+#include "tusb_types.h"
+
+//--------------------------------------------------------------------+
+// MACROS
+//--------------------------------------------------------------------+
+#define TU_ARRAY_SZIE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
+#define TU_MIN(_x, _y) ( (_x) < (_y) ) ? (_x) : (_y) )
+#define TU_MAX(_x, _y) ( (_x) > (_y) ) ? (_x) : (_y) )
+
+#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
+
+
+// for declaration of reserved field, make use of _TU_COUNTER_
+#define TU_RESERVED XSTRING_CONCAT_(reserved, _TU_COUNTER_)
+
+/*------------------------------------------------------------------*/
+/* Count number of arguments of __VA_ARGS__
+ * - reference https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s
+ * - _GET_NTH_ARG() takes args >= N (64) but only expand to Nth one (64th)
+ * - _RSEQ_N() is reverse sequential to N to add padding to have
+ * Nth position is the same as the number of arguments
+ * - ##__VA_ARGS__ is used to deal with 0 paramerter (swallows comma)
+ *------------------------------------------------------------------*/
+#ifndef VA_ARGS_NUM_
+
+#define VA_ARGS_NUM_(...) NARG_(_0, ##__VA_ARGS__,_RSEQ_N())
+#define NARG_(...) _GET_NTH_ARG(__VA_ARGS__)
+#define _GET_NTH_ARG( \
+ _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
+ _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
+ _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
+ _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
+ _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
+ _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
+ _61,_62,_63,N,...) N
+#define _RSEQ_N() \
+ 62,61,60, \
+ 59,58,57,56,55,54,53,52,51,50, \
+ 49,48,47,46,45,44,43,42,41,40, \
+ 39,38,37,36,35,34,33,32,31,30, \
+ 29,28,27,26,25,24,23,22,21,20, \
+ 19,18,17,16,15,14,13,12,11,10, \
+ 9,8,7,6,5,4,3,2,1,0
+#endif
+
+//--------------------------------------------------------------------+
+// INLINE FUNCTION
+//--------------------------------------------------------------------+
+#define tu_memclr(buffer, size) memset((buffer), 0, (size))
+#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
+
+static inline bool tu_mem_test_zero (void const* buffer, uint32_t size)
+{
+ uint8_t const* p_mem = (uint8_t const*) buffer;
+ for(uint32_t i=0; i<size; i++) if (p_mem[i] != 0) return false;
+ return true;
+}
+
+
+//------------- Conversion -------------//
+static inline uint32_t tu_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 tu_u16_high(uint16_t u16)
+{
+ return (uint8_t) ( ((uint16_t) (u16 >> 8)) & 0x00ff);
+}
+
+static inline uint8_t tu_u16_low(uint16_t u16)
+{
+ return (uint8_t) (u16 & 0x00ff);
+}
+
+static inline uint16_t tu_u16_le2be(uint16_t u16)
+{
+ return ((uint16_t)(tu_u16_low(u16) << 8)) | tu_u16_high(u16);
+}
+
+// Min
+static inline uint8_t tu_min8(uint8_t x, uint8_t y) { return (x < y) ? x : y; }
+static inline uint16_t tu_min16(uint16_t x, uint16_t y) { return (x < y) ? x : y; }
+static inline uint32_t tu_min32(uint32_t x, uint32_t y) { return (x < y) ? x : y; }
+
+// Max
+static inline uint8_t tu_max8(uint8_t x, uint8_t y) { return (x > y) ? x : y; }
+static inline uint16_t tu_max16(uint16_t x, uint16_t y) { return (x > y) ? x : y; }
+static inline uint32_t tu_max32(uint32_t x, uint32_t y) { return (x > y) ? x : y; }
+
+// Align
+static inline uint32_t tu_align32 (uint32_t value) { return (value & 0xFFFFFFE0UL); }
+static inline uint32_t tu_align16 (uint32_t value) { return (value & 0xFFFFFFF0UL); }
+static inline uint32_t tu_align_n (uint32_t alignment, uint32_t value) { return value & ((uint32_t) ~(alignment-1)); }
+static inline uint32_t tu_align4k (uint32_t value) { return (value & 0xFFFFF000UL); }
+
+static inline uint32_t tu_offset4k(uint32_t value) { return (value & 0xFFFUL); }
+
+//------------- Mathematics -------------//
+static inline uint32_t tu_abs(int32_t value)
+{
+ return (value < 0) ? (-value) : value;
+}
+
+/// inclusive range checking
+static inline bool tu_within(uint32_t lower, uint32_t value, uint32_t upper)
+{
+ return (lower <= value) && (value <= upper);
+}
+
+// TODO use clz
+static inline uint8_t tu_log2(uint32_t value)
+{
+ uint8_t result = 0; // log2 of a value is its MSB's position
+
+ while (value >>= 1)
+ {
+ result++;
+ }
+ return result;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_COMMON_H_ */
+
+/** @} */
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
new file mode 100644
index 000000000..933d76043
--- /dev/null
+++ b/src/common/tusb_compiler.h
@@ -0,0 +1,83 @@
+/**************************************************************************/
+/*!
+ @file compiler.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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Common
+ * \defgroup Group_Compiler Compiler
+ * \brief Group_Compiler brief
+ * @{ */
+
+#ifndef _TUSB_COMPILER_H_
+#define _TUSB_COMPILER_H_
+
+#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
+
+#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
+ #define _TU_COUNTER_ __COUNTER__
+#else
+ #define _TU_COUNTER_ __LINE__
+#endif
+
+//--------------------------------------------------------------------+
+// Compile-time Assert (use TU_VERIFY_STATIC to avoid name conflict)
+//--------------------------------------------------------------------+
+#if __STDC_VERSION__ >= 201112L
+ #define TU_VERIFY_STATIC _Static_assert
+#else
+ #define TU_VERIFY_STATIC(const_expr, _mess) enum { XSTRING_CONCAT_(_verify_static_, _TU_COUNTER_) = 1/(!!(const_expr)) }
+#endif
+
+// allow debugger to watch any module-wide variables anywhere
+#if CFG_TUSB_DEBUG
+#define STATIC_VAR
+#else
+#define STATIC_VAR static
+#endif
+
+
+#if defined(__GNUC__)
+ #include "compiler/tusb_compiler_gcc.h"
+#elif defined __ICCARM__
+ #include "compiler/tusb_compiler_iar.h"
+#endif
+
+#endif /* _TUSB_COMPILER_H_ */
+
+/// @}
diff --git a/src/common/tusb_error.h b/src/common/tusb_error.h
new file mode 100644
index 000000000..677fc44e4
--- /dev/null
+++ b/src/common/tusb_error.h
@@ -0,0 +1,117 @@
+/**************************************************************************/
+/*!
+ @file tusb_error.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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Common
+ * \defgroup Group_Error Error Codes
+ * @{ */
+
+#ifndef _TUSB_ERRORS_H_
+#define _TUSB_ERRORS_H_
+
+#include "tusb_option.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define ERROR_ENUM(x) x,
+#define ERROR_STRING(x) #x,
+
+#define ERROR_TABLE(ENTRY) \
+ ENTRY(TUSB_ERROR_NONE )\
+ ENTRY(TUSB_ERROR_INVALID_PARA )\
+ ENTRY(TUSB_ERROR_DEVICE_NOT_READY )\
+ ENTRY(TUSB_ERROR_INTERFACE_IS_BUSY )\
+ ENTRY(TUSB_ERROR_HCD_FAILED )\
+ ENTRY(TUSB_ERROR_HCD_OPEN_PIPE_FAILED )\
+ ENTRY(TUSB_ERROR_USBH_MOUNT_DEVICE_NOT_RESPOND )\
+ ENTRY(TUSB_ERROR_USBH_MOUNT_CONFIG_DESC_TOO_LONG )\
+ ENTRY(TUSB_ERROR_USBH_DESCRIPTOR_CORRUPTED )\
+ ENTRY(TUSB_ERROR_USBH_XFER_STALLED )\
+ ENTRY(TUSB_ERROR_USBH_XFER_FAILED )\
+ ENTRY(TUSB_ERROR_OSAL_TIMEOUT )\
+ ENTRY(TUSB_ERROR_OSAL_WAITING ) /* only used by OSAL_NONE in the subtask */ \
+ ENTRY(TUSB_ERROR_OSAL_TASK_FAILED )\
+ ENTRY(TUSB_ERROR_OSAL_QUEUE_FAILED )\
+ ENTRY(TUSB_ERROR_OSAL_SEMAPHORE_FAILED )\
+ ENTRY(TUSB_ERROR_OSAL_MUTEX_FAILED )\
+ ENTRY(TUSB_ERROR_EHCI_NOT_ENOUGH_QTD )\
+ ENTRY(TUSB_ERROR_HIDD_DESCRIPTOR_INTERFACE )\
+ ENTRY(TUSB_ERROR_HIDH_NOT_SUPPORTED_PROTOCOL )\
+ ENTRY(TUSB_ERROR_HIDH_NOT_SUPPORTED_SUBCLASS )\
+ ENTRY(TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS )\
+ ENTRY(TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL )\
+ ENTRY(TUSB_ERROR_CDCH_DEVICE_NOT_MOUNTED )\
+ ENTRY(TUSB_ERROR_MSC_UNSUPPORTED_PROTOCOL )\
+ ENTRY(TUSB_ERROR_MSCH_UNKNOWN_SCSI_COMMAND )\
+ ENTRY(TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED )\
+ ENTRY(TUSB_ERROR_HUB_FEATURE_NOT_SUPPORTED )\
+ ENTRY(TUSB_ERROR_DESCRIPTOR_CORRUPTED )\
+ ENTRY(TUSB_ERROR_DCD_FAILED )\
+ ENTRY(TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT )\
+ ENTRY(TUSB_ERROR_DCD_NOT_ENOUGH_QTD )\
+ ENTRY(TUSB_ERROR_DCD_OPEN_PIPE_FAILED )\
+ ENTRY(TUSB_ERROR_DCD_EDPT_XFER )\
+ ENTRY(TUSB_ERROR_NOT_SUPPORTED_YET )\
+ ENTRY(TUSB_ERROR_USBD_DEVICE_NOT_CONFIGURED )\
+ ENTRY(TUSB_ERROR_NOT_ENOUGH_MEMORY )\
+ ENTRY(TUSB_ERROR_FAILED )\
+ \
+ ENTRY(ERR_TUD_INVALID_DESCRIPTOR) \
+ ENTRY(ERR_TUD_EDPT_OPEN_FAILED) \
+
+
+/// \brief Error Code returned
+typedef enum
+{
+ ERROR_TABLE(ERROR_ENUM)
+ TUSB_ERROR_COUNT
+}tusb_error_t;
+
+#if CFG_TUSB_DEBUG
+/// Enum to String for debugging purposes. Only available if \ref CFG_TUSB_DEBUG > 0
+extern char const* const tusb_strerr[TUSB_ERROR_COUNT];
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_ERRORS_H_ */
+
+/** @} */
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
new file mode 100644
index 000000000..2acd4b696
--- /dev/null
+++ b/src/common/tusb_fifo.c
@@ -0,0 +1,280 @@
+/**************************************************************************/
+/*!
+ @file tusb_fifo.c
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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 <string.h>
+
+#include "osal/osal.h"
+#include "tusb_fifo.h"
+
+// implement mutex lock and unlock
+#if CFG_FIFO_MUTEX
+
+static void tu_fifo_lock(tu_fifo_t *f)
+{
+ if (f->mutex)
+ {
+ uint32_t err;
+ (void) err;
+ osal_mutex_lock(f->mutex, OSAL_TIMEOUT_WAIT_FOREVER, &err);
+ }
+}
+
+static void tu_fifo_unlock(tu_fifo_t *f)
+{
+ if (f->mutex)
+ {
+ osal_mutex_unlock(f->mutex);
+ }
+}
+
+#else
+
+#define tu_fifo_lock(_ff)
+#define tu_fifo_unlock(_ff)
+
+#endif
+
+bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
+{
+ tu_fifo_lock(f);
+
+ f->buffer = (uint8_t*) buffer;
+ f->depth = depth;
+ f->item_size = item_size;
+ f->overwritable = overwritable;
+
+ f->rd_idx = f->wr_idx = f->count = 0;
+
+ tu_fifo_unlock(f);
+
+ return true;
+}
+
+
+/******************************************************************************/
+/*!
+ @brief Read one byte out of the RX buffer.
+
+ This function will return the byte located at the array index of the
+ read pointer, and then increment the read pointer index. If the read
+ pointer exceeds the maximum buffer size, it will roll over to zero.
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] p_buffer
+ Pointer to the place holder for data read from the buffer
+
+ @returns TRUE if the queue is not empty
+*/
+/******************************************************************************/
+bool tu_fifo_read(tu_fifo_t* f, void * p_buffer)
+{
+ if( tu_fifo_empty(f) ) return false;
+
+ tu_fifo_lock(f);
+
+ memcpy(p_buffer,
+ f->buffer + (f->rd_idx * f->item_size),
+ f->item_size);
+ f->rd_idx = (f->rd_idx + 1) % f->depth;
+ f->count--;
+
+ tu_fifo_unlock(f);
+
+ return true;
+}
+
+/******************************************************************************/
+/*!
+ @brief This function will read n elements into the array index specified by
+ the write pointer and increment the write index. If the write index
+ exceeds the max buffer size, then it will roll over to zero.
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] p_data
+ The pointer to data location
+ @param[in] count
+ Number of element that buffer can afford
+
+ @returns number of items read from the FIFO
+*/
+/******************************************************************************/
+uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t count)
+{
+ if( tu_fifo_empty(f) ) return 0;
+
+ /* Limit up to fifo's count */
+ if ( count > f->count ) count = f->count;
+
+ /* Could copy up to 2 portions marked as 'x' if queue is wrapped around
+ * case 1: ....RxxxxW.......
+ * case 2: xxxxxW....Rxxxxxx
+ */
+// uint16_t index2upper = tu_min16(count, f->count-f->rd_idx);
+
+ uint8_t* p_buf = (uint8_t*) p_buffer;
+ uint16_t len = 0;
+ while( (len < count) && tu_fifo_read(f, p_buf) )
+ {
+ len++;
+ p_buf += f->item_size;
+ }
+
+ return len;
+}
+
+/******************************************************************************/
+/*!
+ @brief Reads one item without removing it from the FIFO
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] pos
+ Position to read from in the FIFO buffer
+ @param[in] p_buffer
+ Pointer to the place holder for data read from the buffer
+
+ @returns TRUE if the queue is not empty
+*/
+/******************************************************************************/
+bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t pos, void * p_buffer)
+{
+ if ( pos >= f->count ) return false;
+
+ // rd_idx is pos=0
+ uint16_t index = (f->rd_idx + pos) % f->depth;
+ memcpy(p_buffer,
+ f->buffer + (index * f->item_size),
+ f->item_size);
+
+ return true;
+}
+
+/******************************************************************************/
+/*!
+ @brief Write one element into the RX buffer.
+
+ This function will write one element into the array index specified by
+ the write pointer and increment the write index. If the write index
+ exceeds the max buffer size, then it will roll over to zero.
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] p_data
+ The byte to add to the FIFO
+
+ @returns TRUE if the data was written to the FIFO (overwrittable
+ FIFO will always return TRUE)
+*/
+/******************************************************************************/
+bool tu_fifo_write (tu_fifo_t* f, const void * p_data)
+{
+ if ( tu_fifo_full(f) && !f->overwritable ) return false;
+
+ tu_fifo_lock(f);
+
+ memcpy( f->buffer + (f->wr_idx * f->item_size),
+ p_data,
+ f->item_size);
+
+ f->wr_idx = (f->wr_idx + 1) % f->depth;
+
+ if (tu_fifo_full(f))
+ {
+ f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size)
+ }
+ else
+ {
+ f->count++;
+ }
+
+ tu_fifo_unlock(f);
+
+ return true;
+}
+
+/******************************************************************************/
+/*!
+ @brief This function will write n elements into the array index specified by
+ the write pointer and increment the write index. If the write index
+ exceeds the max buffer size, then it will roll over to zero.
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] p_data
+ The pointer to data to add to the FIFO
+ @param[in] count
+ Number of element
+ @return Number of written elements
+*/
+/******************************************************************************/
+uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * p_data, uint16_t count)
+{
+ if ( count == 0 ) return 0;
+
+ uint8_t const* p_buf = (uint8_t const*) p_data;
+
+ uint16_t len = 0;
+ while( (len < count) && tu_fifo_write(f, p_buf) )
+ {
+ len++;
+ p_buf += f->item_size;
+ }
+
+ return len;
+}
+
+/******************************************************************************/
+/*!
+ @brief Clear the fifo read and write pointers and set length to zero
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+*/
+/******************************************************************************/
+bool tu_fifo_clear(tu_fifo_t *f)
+{
+ tu_fifo_lock(f);
+
+ f->rd_idx = f->wr_idx = f->count = 0;
+
+ tu_fifo_unlock(f);
+
+ return true;
+}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
new file mode 100644
index 000000000..e88c2ac6d
--- /dev/null
+++ b/src/common/tusb_fifo.h
@@ -0,0 +1,143 @@
+/**************************************************************************/
+/*!
+ @file tusb_fifo.h
+ @author hathach (tinyusb.org)
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Common
+ * \defgroup group_fifo fifo
+ * @{ */
+
+#ifndef _TUSB_FIFO_H_
+#define _TUSB_FIFO_H_
+
+// mutex is only needed for RTOS
+// for OS None, we don't get preempted
+#define CFG_FIFO_MUTEX (CFG_TUSB_OS != OPT_OS_NONE)
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#if CFG_FIFO_MUTEX
+#define tu_fifo_mutex_t osal_mutex_t
+#endif
+
+
+/** \struct tu_fifo_t
+ * \brief Simple Circular FIFO
+ */
+typedef struct
+{
+ uint8_t* buffer ; ///< buffer pointer
+ uint16_t depth ; ///< max items
+ uint16_t item_size ; ///< size of each item
+ bool overwritable ;
+
+ volatile uint16_t count ; ///< number of items in queue
+ volatile uint16_t wr_idx ; ///< write pointer
+ volatile uint16_t rd_idx ; ///< read pointer
+
+#if CFG_FIFO_MUTEX
+ tu_fifo_mutex_t mutex;
+#endif
+
+} tu_fifo_t;
+
+#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
+ uint8_t _name##_buf[_depth*sizeof(_type)]; \
+ tu_fifo_t _name = { \
+ .buffer = _name##_buf, \
+ .depth = _depth, \
+ .item_size = sizeof(_type), \
+ .overwritable = _overwritable, \
+ }
+
+bool tu_fifo_clear(tu_fifo_t *f);
+bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
+
+#if CFG_FIFO_MUTEX
+static inline void tu_fifo_config_mutex(tu_fifo_t *f, tu_fifo_mutex_t mutex_hdl)
+{
+ f->mutex = mutex_hdl;
+}
+#endif
+
+bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
+uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t count);
+
+bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
+uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t count);
+
+bool tu_fifo_peek_at (tu_fifo_t* f, uint16_t pos, void * p_buffer);
+
+static inline bool tu_fifo_peek(tu_fifo_t* f, void * p_buffer)
+{
+ return tu_fifo_peek_at(f, 0, p_buffer);
+}
+
+static inline bool tu_fifo_empty(tu_fifo_t* f)
+{
+ return (f->count == 0);
+}
+
+static inline bool tu_fifo_full(tu_fifo_t* f)
+{
+ return (f->count == f->depth);
+}
+
+static inline uint16_t tu_fifo_count(tu_fifo_t* f)
+{
+ return f->count;
+}
+
+static inline uint16_t tu_fifo_remaining(tu_fifo_t* f)
+{
+ return f->depth - f->count;
+}
+
+static inline uint16_t tu_fifo_depth(tu_fifo_t* f)
+{
+ return f->depth;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_FIFO_H_ */
diff --git a/src/common/tusb_timeout.h b/src/common/tusb_timeout.h
new file mode 100644
index 000000000..9d80f5fe7
--- /dev/null
+++ b/src/common/tusb_timeout.h
@@ -0,0 +1,98 @@
+/**************************************************************************/
+/*!
+ @file tusb_timeout.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.
+*/
+/**************************************************************************/
+
+/** \ingroup Group_Common Common Files
+ * \defgroup Group_TimeoutTimer timeout timer
+ * @{ */
+
+
+#ifndef _TUSB_TIMEOUT_H_
+#define _TUSB_TIMEOUT_H_
+
+#include "tusb_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ uint32_t start;
+ uint32_t interval;
+}tu_timeout_t;
+
+extern uint32_t tusb_hal_millis(void);
+
+static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec)
+{
+ tt->interval = msec;
+ tt->start = tusb_hal_millis();
+}
+
+static inline bool tu_timeout_expired(tu_timeout_t* tt)
+{
+ return ( tusb_hal_millis() - tt->start ) >= tt->interval;
+}
+
+// For used with periodic event to prevent drift
+static inline void tu_timeout_reset(tu_timeout_t* tt)
+{
+ tt->start += tt->interval;
+}
+
+static inline void tu_timeout_restart(tu_timeout_t* tt)
+{
+ tt->start = tusb_hal_millis();
+}
+
+
+static inline void tu_timeout_wait(uint32_t msec)
+{
+ tu_timeout_t tt;
+ tu_timeout_set(&tt, msec);
+
+ // blocking delay
+ while ( !tu_timeout_expired(&tt) ) { }
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_TIMEOUT_H_ */
+
+/** @} */
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
new file mode 100644
index 000000000..6f0167898
--- /dev/null
+++ b/src/common/tusb_types.h
@@ -0,0 +1,428 @@
+/**************************************************************************/
+/*!
+ @file tusb_types.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.
+*/
+/**************************************************************************/
+
+/** \ingroup group_usb_definitions
+ * \defgroup USBDef_Type USB Types
+ * @{ */
+
+#ifndef _TUSB_TYPES_H_
+#define _TUSB_TYPES_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "tusb_compiler.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*------------------------------------------------------------------*/
+/* CONSTANTS
+ *------------------------------------------------------------------*/
+
+/// defined base on EHCI specs value for Endpoint Speed
+typedef enum
+{
+ TUSB_SPEED_FULL = 0,
+ TUSB_SPEED_LOW ,
+ TUSB_SPEED_HIGH
+}tusb_speed_t;
+
+/// defined base on USB Specs Endpoint's bmAttributes
+typedef enum
+{
+ TUSB_XFER_CONTROL = 0 ,
+ TUSB_XFER_ISOCHRONOUS ,
+ TUSB_XFER_BULK ,
+ TUSB_XFER_INTERRUPT
+}tusb_xfer_type_t;
+
+typedef enum
+{
+ TUSB_DIR_OUT = 0,
+ TUSB_DIR_IN = 1,
+
+ TUSB_DIR_IN_MASK = 0x80
+}tusb_dir_t;
+
+
+/// USB Descriptor Types (section 9.4 table 9-5)
+typedef enum
+{
+ TUSB_DESC_DEVICE = 0x01 ,
+ TUSB_DESC_CONFIGURATION = 0x02 ,
+ TUSB_DESC_STRING = 0x03 ,
+ TUSB_DESC_INTERFACE = 0x04 ,
+ TUSB_DESC_ENDPOINT = 0x05 ,
+ TUSB_DESC_DEVICE_QUALIFIER = 0x06 ,
+ TUSB_DESC_OTHER_SPEED_CONFIG = 0x07 ,
+ TUSB_DESC_INTERFACE_POWER = 0x08 ,
+ TUSB_DESC_OTG = 0x09 ,
+ TUSB_DESC_DEBUG = 0x0A ,
+ TUSB_DESC_INTERFACE_ASSOCIATION = 0x0B ,
+ TUSB_DESC_CLASS_SPECIFIC = 0x24
+}tusb_desc_type_t;
+
+typedef enum
+{
+ TUSB_REQ_GET_STATUS =0 , ///< 0
+ TUSB_REQ_CLEAR_FEATURE , ///< 1
+ TUSB_REQ_RESERVED , ///< 2
+ TUSB_REQ_SET_FEATURE , ///< 3
+ TUSB_REQ_RESERVED2 , ///< 4
+ TUSB_REQ_SET_ADDRESS , ///< 5
+ TUSB_REQ_GET_DESCRIPTOR , ///< 6
+ TUSB_REQ_SET_DESCRIPTOR , ///< 7
+ TUSB_REQ_GET_CONFIGURATION , ///< 8
+ TUSB_REQ_SET_CONFIGURATION , ///< 9
+ TUSB_REQ_GET_INTERFACE , ///< 10
+ TUSB_REQ_SET_INTERFACE , ///< 11
+ TUSB_REQ_SYNCH_FRAME ///< 12
+}tusb_request_code_t;
+
+typedef enum
+{
+ TUSB_REQ_TYPE_STANDARD = 0,
+ TUSB_REQ_TYPE_CLASS,
+ TUSB_REQ_TYPE_VENDOR
+} tusb_request_type_t;
+
+typedef enum
+{
+ TUSB_REQ_RCPT_DEVICE =0,
+ TUSB_REQ_RCPT_INTERFACE,
+ TUSB_REQ_RCPT_ENDPOINT,
+ TUSB_REQ_RCPT_OTHER
+} tusb_request_recipient_t;
+
+typedef enum
+{
+ TUSB_CLASS_UNSPECIFIED = 0 , ///< 0
+ TUSB_CLASS_AUDIO = 1 , ///< 1
+ TUSB_CLASS_CDC = 2 , ///< 2
+ TUSB_CLASS_HID = 3 , ///< 3
+ TUSB_CLASS_RESERVED_4 = 4 , ///< 4
+ TUSB_CLASS_PHYSICAL = 5 , ///< 5
+ TUSB_CLASS_IMAGE = 6 , ///< 6
+ TUSB_CLASS_PRINTER = 7 , ///< 7
+ TUSB_CLASS_MSC = 8 , ///< 8
+ TUSB_CLASS_HUB = 9 , ///< 9
+ TUSB_CLASS_CDC_DATA = 10 , ///< 10
+ TUSB_CLASS_SMART_CARD = 11 , ///< 11
+ TUSB_CLASS_RESERVED_12 = 12 , ///< 12
+ TUSB_CLASS_CONTENT_SECURITY = 13 , ///< 13
+ TUSB_CLASS_VIDEO = 14 , ///< 14
+ TUSB_CLASS_PERSONAL_HEALTHCARE = 15 , ///< 15
+ TUSB_CLASS_AUDIO_VIDEO = 16 , ///< 16
+
+ TUSB_CLASS_MAPPED_INDEX_START = 17 , // TODO Map DIAGNOSTIC, WIRELESS_CONTROLLER, MISC, VENDOR_SPECIFIC to this to minimize the array
+
+ TUSB_CLASS_DIAGNOSTIC = 0xDC ,
+ TUSB_CLASS_WIRELESS_CONTROLLER = 0xE0 ,
+ TUSB_CLASS_MISC = 0xEF ,
+ TUSB_CLASS_APPLICATION_SPECIFIC = 0xFE ,
+ TUSB_CLASS_VENDOR_SPECIFIC = 0xFF
+}tusb_class_code_t;
+
+typedef enum
+{
+ MISC_SUBCLASS_COMMON = 2
+}misc_subclass_type_t;
+
+typedef enum
+{
+ MISC_PROTOCOL_IAD = 1
+}misc_protocol_type_t;
+
+enum {
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = BIT_(5),
+ TUSB_DESC_CONFIG_ATT_SELF_POWER = BIT_(6),
+ TUSB_DESC_CONFIG_ATT_BUS_POWER = BIT_(7)
+};
+
+#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
+
+/// Device State
+typedef enum
+{
+ TUSB_DEVICE_STATE_UNPLUG = 0 ,
+ TUSB_DEVICE_STATE_CONFIGURED ,
+ TUSB_DEVICE_STATE_SUSPENDED ,
+}tusb_device_state_t;
+
+typedef enum
+{
+ XFER_RESULT_SUCCESS,
+ XFER_RESULT_FAILED,
+ XFER_RESULT_STALLED,
+}xfer_result_t;
+
+enum
+{
+ DESC_OFFSET_LEN = 0,
+ DESC_OFFSET_TYPE = 1
+};
+
+enum
+{
+ INTERFACE_INVALID_NUMBER = 0xff
+};
+
+//--------------------------------------------------------------------+
+// STANDARD DESCRIPTORS
+//--------------------------------------------------------------------+
+
+/// USB Standard Device Descriptor (section 9.6.1, table 9-8)
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of this descriptor in bytes.
+ uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
+ uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
+
+ uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
+ uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
+ uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
+ uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
+
+ uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
+ uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
+ uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
+ uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
+ uint8_t iProduct ; ///< Index of string descriptor describing product.
+ uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
+
+ uint8_t bNumConfigurations ; ///< Number of possible configurations.
+} tusb_desc_device_t;
+
+/// USB Standard Configuration Descriptor (section 9.6.1 table 9-10) */
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of this descriptor in bytes
+ uint8_t bDescriptorType ; ///< CONFIGURATION Descriptor Type
+ uint16_t wTotalLength ; ///< Total length of data returned for this configuration. Includes the combined length of all descriptors (configuration, interface, endpoint, and class- or vendor-specific) returned for this configuration.
+
+ uint8_t bNumInterfaces ; ///< Number of interfaces supported by this configuration
+ uint8_t bConfigurationValue ; ///< Value to use as an argument to the SetConfiguration() request to select this configuration.
+ uint8_t iConfiguration ; ///< Index of string descriptor describing this configuration
+ uint8_t bmAttributes ; ///< Configuration characteristics \n D7: Reserved (set to one)\n D6: Self-powered \n D5: Remote Wakeup \n D4...0: Reserved (reset to zero) \n D7 is reserved and must be set to one for historical reasons. \n A device configuration that uses power from the bus and a local source reports a non-zero value in bMaxPower to indicate the amount of bus power required and sets D6. The actual power source at runtime may be determined using the GetStatus(DEVICE) request (see USB 2.0 spec Section 9.4.5). \n If a device configuration supports remote wakeup, D5 is set to one.
+ uint8_t bMaxPower ; ///< Maximum power consumption of the USB device from the bus in this specific configuration when the device is fully operational. Expressed in 2 mA units (i.e., 50 = 100 mA).
+} tusb_desc_configuration_t;
+
+/// USB Standard Interface Descriptor (section 9.6.1 table 9-12)
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of this descriptor in bytes
+ uint8_t bDescriptorType ; ///< INTERFACE Descriptor Type
+
+ uint8_t bInterfaceNumber ; ///< Number of this interface. Zero-based value identifying the index in the array of concurrent interfaces supported by this configuration.
+ uint8_t bAlternateSetting ; ///< Value used to select this alternate setting for the interface identified in the prior field
+ uint8_t bNumEndpoints ; ///< Number of endpoints used by this interface (excluding endpoint zero). If this value is zero, this interface only uses the Default Control Pipe.
+ uint8_t bInterfaceClass ; ///< Class code (assigned by the USB-IF). \li A value of zero is reserved for future standardization. \li If this field is set to FFH, the interface class is vendor-specific. \li All other values are reserved for assignment by the USB-IF.
+ uint8_t bInterfaceSubClass ; ///< Subclass code (assigned by the USB-IF). \n These codes are qualified by the value of the bInterfaceClass field. \li If the bInterfaceClass field is reset to zero, this field must also be reset to zero. \li If the bInterfaceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
+ uint8_t bInterfaceProtocol ; ///< Protocol code (assigned by the USB). \n These codes are qualified by the value of the bInterfaceClass and the bInterfaceSubClass fields. If an interface supports class-specific requests, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use a class-specific protocol on this interface. \li If this field is set to FFH, the device uses a vendor-specific protocol for this interface.
+ uint8_t iInterface ; ///< Index of string descriptor describing this interface
+} tusb_desc_interface_t;
+
+/// USB Standard Endpoint Descriptor (section 9.6.1 table 9-13)
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of this descriptor in bytes
+ uint8_t bDescriptorType ; ///< ENDPOINT Descriptor Type
+
+ uint8_t bEndpointAddress ; ///< The address of the endpoint on the USB device described by this descriptor. The address is encoded as follows: \n Bit 3...0: The endpoint number \n Bit 6...4: Reserved, reset to zero \n Bit 7: Direction, ignored for control endpoints 0 = OUT endpoint 1 = IN endpoint.
+
+ struct ATTR_PACKED {
+ uint8_t xfer : 2;
+ uint8_t sync : 2;
+ uint8_t usage : 2;
+ uint8_t : 2;
+ } bmAttributes ; ///< This field describes the endpoint's attributes when it is configured using the bConfigurationValue. \n Bits 1..0: Transfer Type \n- 00 = Control \n- 01 = Isochronous \n- 10 = Bulk \n- 11 = Interrupt \n If not an isochronous endpoint, bits 5..2 are reserved and must be set to zero. If isochronous, they are defined as follows: \n Bits 3..2: Synchronization Type \n- 00 = No Synchronization \n- 01 = Asynchronous \n- 10 = Adaptive \n- 11 = Synchronous \n Bits 5..4: Usage Type \n- 00 = Data endpoint \n- 01 = Feedback endpoint \n- 10 = Implicit feedback Data endpoint \n- 11 = Reserved \n Refer to Chapter 5 of USB 2.0 specification for more information. \n All other bits are reserved and must be reset to zero. Reserved bits must be ignored by the host.
+
+ struct ATTR_PACKED {
+ uint16_t size : 11; ///< Maximum packet size this endpoint is capable of sending or receiving when this configuration is selected. \n For isochronous endpoints, this value is used to reserve the bus time in the schedule, required for the per-(micro)frame data payloads. The pipe may, on an ongoing basis, actually use less bandwidth than that reserved. The device reports, if necessary, the actual bandwidth used via its normal, non-USB defined mechanisms. \n For all endpoints, bits 10..0 specify the maximum packet size (in bytes). \n For high-speed isochronous and interrupt endpoints: \n Bits 12..11 specify the number of additional transaction opportunities per microframe: \n- 00 = None (1 transaction per microframe) \n- 01 = 1 additional (2 per microframe) \n- 10 = 2 additional (3 per microframe) \n- 11 = Reserved \n Bits 15..13 are reserved and must be set to zero.
+ uint16_t hs_period_mult : 2;
+ uint16_t : 0;
+ }wMaxPacketSize;
+
+ uint8_t bInterval ; ///< Interval for polling endpoint for data transfers. Expressed in frames or microframes depending on the device operating speed (i.e., either 1 millisecond or 125 us units). \n- For full-/high-speed isochronous endpoints, this value must be in the range from 1 to 16. The bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$). \n- For full-/low-speed interrupt endpoints, the value of this field may be from 1 to 255. \n- For high-speed interrupt endpoints, the bInterval value is used as the exponent for a \f$ 2^(bInterval-1) \f$ value; e.g., a bInterval of 4 means a period of 8 (\f$ 2^(4-1) \f$) . This value must be from 1 to 16. \n- For high-speed bulk/control OUT endpoints, the bInterval must specify the maximum NAK rate of the endpoint. A value of 0 indicates the endpoint never NAKs. Other values indicate at most 1 NAK each bInterval number of microframes. This value must be in the range from 0 to 255. \n Refer to Chapter 5 of USB 2.0 specification for more information.
+} tusb_desc_endpoint_t;
+
+/// USB Other Speed Configuration Descriptor (section 9.6.1 table 9-11)
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of descriptor
+ uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
+ uint16_t wTotalLength ; ///< Total length of data returned
+
+ uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration
+ uint8_t bConfigurationValue ; ///< Value to use to select configuration
+ uint8_t IConfiguration ; ///< Index of string descriptor
+ uint8_t bmAttributes ; ///< Same as Configuration descriptor
+ uint8_t bMaxPower ; ///< Same as Configuration descriptor
+} tusb_desc_other_speed_t;
+
+/// USB Device Qualifier Descriptor (section 9.6.1 table 9-9)
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of descriptor
+ uint8_t bDescriptorType ; ///< Device Qualifier Type
+ uint16_t bcdUSB ; ///< USB specification version number (e.g., 0200H for V2.00)
+
+ uint8_t bDeviceClass ; ///< Class Code
+ uint8_t bDeviceSubClass ; ///< SubClass Code
+ uint8_t bDeviceProtocol ; ///< Protocol Code
+ uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed
+ uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations
+ uint8_t bReserved ; ///< Reserved for future use, must be zero
+} tusb_desc_device_qualifier_t;
+
+/// USB Interface Association Descriptor (IAD ECN)
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of descriptor
+ uint8_t bDescriptorType ; ///< Other_speed_Configuration Type
+
+ uint8_t bFirstInterface ; ///< Index of the first associated interface.
+ uint8_t bInterfaceCount ; ///< Total number of associated interfaces.
+
+ uint8_t bFunctionClass ; ///< Interface class ID.
+ uint8_t bFunctionSubClass ; ///< Interface subclass ID.
+ uint8_t bFunctionProtocol ; ///< Interface protocol ID.
+
+ uint8_t iFunction ; ///< Index of the string descriptor describing the interface association.
+} tusb_desc_interface_assoc_t;
+
+/// USB Header Descriptor
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of this descriptor in bytes
+ uint8_t bDescriptorType ; ///< Descriptor Type
+} tusb_desc_header_t;
+
+typedef struct ATTR_PACKED
+{
+ uint8_t bLength ; ///< Size of this descriptor in bytes
+ uint8_t bDescriptorType ; ///< Descriptor Type
+ uint16_t unicode_string[];
+} tusb_desc_string_t;
+
+
+/*------------------------------------------------------------------*/
+/* Types
+ *------------------------------------------------------------------*/
+typedef struct ATTR_PACKED{
+ union {
+ struct ATTR_PACKED {
+ uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t.
+ uint8_t type : 2; ///< Request type tusb_request_type_t.
+ uint8_t direction : 1; ///< Direction type. tusb_dir_t
+ } bmRequestType_bit;
+
+ uint8_t bmRequestType;
+ };
+
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+} tusb_control_request_t;
+
+TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "mostly compiler option issue");
+
+// TODO move to somewhere suitable
+static inline uint8_t bm_request_type(uint8_t direction, uint8_t type, uint8_t recipient)
+{
+ return ((uint8_t) (direction << 7)) | ((uint8_t) (type << 5)) | (recipient);
+}
+
+//--------------------------------------------------------------------+
+// Endpoint helper
+//--------------------------------------------------------------------+
+
+// Get direction from Endpoint address
+static inline tusb_dir_t tu_edpt_dir(uint8_t addr)
+{
+ return (addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+}
+
+// Get Endpoint number from address
+static inline uint8_t tu_edpt_number(uint8_t addr)
+{
+ return addr & (~TUSB_DIR_IN_MASK);
+}
+
+static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir)
+{
+ return num | (dir ? TUSB_DIR_IN_MASK : 0);
+}
+
+//--------------------------------------------------------------------+
+// Descriptor helper
+//--------------------------------------------------------------------+
+static inline uint8_t const * tu_desc_next(void const* desc)
+{
+ uint8_t const* desc8 = (uint8_t const*) desc;
+ return desc8 + desc8[DESC_OFFSET_LEN];
+}
+
+static inline uint8_t tu_desc_type(void const* desc)
+{
+ return ((uint8_t const*) desc)[DESC_OFFSET_TYPE];
+}
+
+static inline uint8_t tu_desc_len(void const* desc)
+{
+ return ((uint8_t const*) desc)[DESC_OFFSET_LEN];
+}
+
+// Length of the string descriptors in bytes with slen characters
+#define TUD_DESC_STRLEN(_slen) (2*(_slen) + 2)
+
+// Header of string descriptors with len + string type
+#define TUD_DESC_STR_HEADER(_slen) ( (uint16_t) ( (TUSB_DESC_STRING << 8 ) | TUD_DESC_STRLEN(_slen)) )
+
+// Convert comma-separated string to descriptor unicode format
+#define TUD_DESC_STRCONV( ... ) (const uint16_t[]) { TUD_DESC_STR_HEADER(VA_ARGS_NUM_(__VA_ARGS__)), __VA_ARGS__ }
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_TYPES_H_ */
+
+/** @} */
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
new file mode 100644
index 000000000..1cb8443bc
--- /dev/null
+++ b/src/common/tusb_verify.h
@@ -0,0 +1,186 @@
+/**************************************************************************/
+/*!
+ @file verify.h
+ @author hathach
+
+ @section LICENSE
+
+ Software License Agreement (BSD License)
+
+ Copyright (c) 2018, 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.
+*/
+/**************************************************************************/
+#ifndef TUSB_VERIFY_H_
+#define TUSB_VERIFY_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "tusb_option.h"
+#include "tusb_compiler.h"
+
+/*------------------------------------------------------------------*/
+/* This file use an advanced macro technique to mimic the default parameter
+ * as C++ for the sake of code simplicity. Beware of a headache macro
+ * manipulation that you are told to stay away.
+ *
+ * e.g
+ *
+ * - TU_VERIFY( cond ) will return false if cond is false
+ * - TU_VERIFY( cond, err) will return err instead if cond is false
+ *------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+//--------------------------------------------------------------------+
+// TU_VERIFY Helper
+//--------------------------------------------------------------------+
+#if CFG_TUSB_DEBUG >= 1
+ #include <stdio.h>
+ #define _MESS_ERR(_err) printf("%s: %d: failed, error = %s\n", __func__, __LINE__, tusb_strerr[_err])
+ #define _MESS_FAILED() printf("%s: %d: failed\n", __func__, __LINE__)
+#else
+ #define _MESS_ERR(_err)
+ #define _MESS_FAILED()
+#endif
+
+// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7
+#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__)
+
+#define TU_BREAKPOINT() \
+ do {\
+ volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
+ if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */\
+ } while(0)
+
+#else
+#define TU_BREAKPOINT()
+#endif
+
+/*------------------------------------------------------------------*/
+/* Macro Generator
+ *------------------------------------------------------------------*/
+
+// Helper to implement optional parameter for TU_VERIFY Macro family
+#define GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
+#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
+
+/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
+#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do { if ( !(_cond) ) { _handler; return _ret; } } while(0)
+
+/*------------- Generator for TU_VERIFY_ERR and TU_VERIFY_ERR_HDLR -------------*/
+#define TU_VERIFY_ERR_DEF2(_error, _handler) \
+ do { \
+ uint32_t _err = (uint32_t)(_error); \
+ if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _err; }\
+ } while(0)
+
+#define TU_VERIFY_ERR_DEF3(_error, _handler, _ret) \
+ do { \
+ uint32_t _err = (uint32_t)(_error); \
+ if ( 0 != _err ) { _MESS_ERR(_err); _handler; return _ret; }\
+ } while(0)
+
+
+
+
+/*------------------------------------------------------------------*/
+/* TU_VERIFY
+ * - TU_VERIFY_1ARGS : return false if failed
+ * - TU_VERIFY_2ARGS : return provided value if failed
+ *------------------------------------------------------------------*/
+#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false)
+#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret)
+
+#define TU_VERIFY(...) GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS)(__VA_ARGS__)
+
+
+/*------------------------------------------------------------------*/
+/* TU_VERIFY WITH HANDLER
+ * - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed
+ * - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed
+ *------------------------------------------------------------------*/
+#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false)
+#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret)
+
+#define TU_VERIFY_HDLR(...) GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS)(__VA_ARGS__)
+
+
+/*------------------------------------------------------------------*/
+/* TU_VERIFY STATUS
+ * - TU_VERIFY_ERR_1ARGS : return status of condition if failed
+ * - TU_VERIFY_ERR_2ARGS : return provided status code if failed
+ *------------------------------------------------------------------*/
+#define TU_VERIFY_ERR_1ARGS(_error) TU_VERIFY_ERR_DEF2(_error, )
+#define TU_VERIFY_ERR_2ARGS(_error, _ret) TU_VERIFY_ERR_DEF3(_error, ,_ret)
+
+#define TU_VERIFY_ERR(...) GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_ERR_2ARGS, TU_VERIFY_ERR_1ARGS)(__VA_ARGS__)
+
+/*------------------------------------------------------------------*/
+/* TU_VERIFY STATUS WITH HANDLER
+ * - TU_VERIFY_ERR_HDLR_2ARGS : execute handler, return status if failed
+ * - TU_VERIFY_ERR_HDLR_3ARGS : execute handler, return provided error if failed
+ *------------------------------------------------------------------*/
+#define TU_VERIFY_ERR_HDLR_2ARGS(_error, _handler) TU_VERIFY_ERR_DEF2(_error, _handler)
+#define TU_VERIFY_ERR_HDLR_3ARGS(_error, _handler, _ret) TU_VERIFY_ERR_DEF3(_error, _handler, _ret)
+
+#define TU_VERIFY_ERR_HDLR(...) GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_ERR_HDLR_3ARGS, TU_VERIFY_ERR_HDLR_2ARGS)(__VA_ARGS__)
+
+
+
+/*------------------------------------------------------------------*/
+/* ASSERT
+ * basically TU_VERIFY with TU_BREAKPOINT() as handler
+ * - 1 arg : return false if failed
+ * - 2 arg : return error if failed
+ *------------------------------------------------------------------*/
+#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false)
+#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret)
+
+#define TU_ASSERT(...) GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS)(__VA_ARGS__)
+
+/*------------------------------------------------------------------*/
+/* ASSERT Error
+ * basically TU_VERIFY Error with TU_BREAKPOINT() as handler
+ *------------------------------------------------------------------*/
+#define ASERT_ERR_1ARGS(_error) TU_VERIFY_ERR_DEF2(_error, TU_BREAKPOINT())
+#define ASERT_ERR_2ARGS(_error, _ret) TU_VERIFY_ERR_DEF3(_error, TU_BREAKPOINT(), _ret)
+
+#define TU_ASSERT_ERR(...) GET_3RD_ARG(__VA_ARGS__, ASERT_ERR_2ARGS, ASERT_ERR_1ARGS)(__VA_ARGS__)
+
+/*------------------------------------------------------------------*/
+/* ASSERT HDLR
+ *------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* TUSB_VERIFY_H_ */