summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Conrad <[email protected]>2019-09-19 09:16:48 -0400
committerNathan Conrad <[email protected]>2019-09-19 09:16:48 -0400
commit5fcc1468eb0b4e406bc882a3e752559376593983 (patch)
tree3867823f4b55ff06cb1f1f45f27f983b418cc1ee /src
parent89ffe78f84fe9771f23b51e60e539cec236a1704 (diff)
parent77cc5b1b0c9f2ddacaddce5bbd9fce9093f4e797 (diff)
Merge branch 'master' into fsdev_smallPacket
Diffstat (limited to 'src')
-rw-r--r--src/common/tusb_common.h2
-rw-r--r--src/common/tusb_compiler.h71
-rw-r--r--src/common/tusb_types.h3
-rw-r--r--src/common/tusb_verify.h30
-rw-r--r--src/device/usbd.c118
-rw-r--r--src/portable/nxp/lpc17_40/dcd_lpc17_40.c2
6 files changed, 171 insertions, 55 deletions
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index 4f0105d13..57c6e2fcf 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -38,7 +38,7 @@
//--------------------------------------------------------------------+
// Macros Helper
//--------------------------------------------------------------------+
-#define TU_ARRAY_SZIE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
+#define TU_ARRAY_SIZE(_arr) ( sizeof(_arr) / sizeof(_arr[0]) )
#define TU_MIN(_x, _y) ( (_x) < (_y) ) ? (_x) : (_y) )
#define TU_MAX(_x, _y) ( (_x) > (_y) ) ? (_x) : (_y) )
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 09768ef88..58732b871 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -53,6 +53,9 @@
// for declaration of reserved field, make use of _TU_COUNTER_
#define TU_RESERVED TU_XSTRCAT(reserved, _TU_COUNTER_)
+#define TU_LITTLE_ENDIAN (0x12u)
+#define TU_BIG_ENDIAN (0x21u)
+
//--------------------------------------------------------------------+
// Compiler porting with Attribute and Endian
//--------------------------------------------------------------------+
@@ -67,20 +70,68 @@
// Endian conversion use well-known host to network (big endian) naming
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- #define tu_htonl(u32) __builtin_bswap32(u32)
- #define tu_ntohl(u32) __builtin_bswap32(u32)
-
- #define tu_htons(u16) __builtin_bswap16(u16)
- #define tu_ntohs(u16) __builtin_bswap16(u16)
+ #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
#else
- #define tu_htonl(u32) (u32)
- #define tu_ntohl(u32) (u32)
+ #define TU_BYTE_ORDER TU_BIG_ENDIAN
+ #endif
+
+#define TU_BSWAP16(u16) (__builtin_bswap16(u16))
+#define TU_BSWAP32(u32) (__builtin_bswap32(u32))
- #define tu_htons(u16) (u16)
- #define tu_ntohs(u16) (u16)
+#elif defined(__TI_COMPILER_VERSION__)
+ #define TU_ATTR_ALIGNED(Bytes) __attribute__ ((aligned(Bytes)))
+ #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
+ #define TU_ATTR_PACKED __attribute__ ((packed))
+ #define TU_ATTR_PREPACKED
+ #define TU_ATTR_WEAK __attribute__ ((weak))
+ #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
+ #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
+
+ // __BYTE_ORDER is defined in the TI ARM compiler, but not MSP430 (which is little endian)
+ #if ((__BYTE_ORDER__) == (__ORDER_LITTLE_ENDIAN__)) || defined(__MSP430__)
+ #define TU_BYTE_ORDER TU_LITTLE_ENDIAN
+ #else
+ #define TU_BYTE_ORDER TU_BIG_ENDIAN
#endif
+
+ #define TU_BSWAP16(u16) (__builtin_bswap16(u16))
+ #define TU_BSWAP32(u32) (__builtin_bswap32(u32))
+
+#else
+ #error "Compiler attribute porting is required"
+#endif
+
+#if (TU_BYTE_ORDER == TU_LITTLE_ENDIAN)
+
+ #define tu_htons(u16) (TU_BSWAP16(u16))
+ #define tu_ntohs(u16) (TU_BSWAP16(u16))
+
+ #define tu_htonl(u32) (TU_BSWAP32(u32))
+ #define tu_ntohl(u32) (TU_BSWAP32(u32))
+
+ #define tu_htole16(u16) (u16)
+ #define tu_le16toh(u16) (u16)
+
+ #define tu_htole32(u32) (u32)
+ #define tu_le32toh(u32) (u32)
+
+#elif (TU_BYTE_ORDER == TU_BIG_ENDIAN)
+
+ #define tu_htons(u16) (u16)
+ #define tu_ntohs(u16) (u16)
+
+ #define tu_htonl(u32) (u32)
+ #define tu_ntohl(u32) (u32)
+
+
+ #define tu_htole16(u16) (tu_bswap16(u16))
+ #define tu_le16toh(u16) (tu_bswap16(u16))
+
+ #define tu_htole32(u32) (tu_bswap32(u32))
+ #define tu_le32toh(u32) (tu_bswap32(u32))
+
#else
- #error "Compiler attribute porting are required"
+ #error Byte order is undefined
#endif
#endif /* _TUSB_COMPILER_H_ */
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index a50e89934..ad42baad7 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -125,7 +125,8 @@ typedef enum
{
TUSB_REQ_TYPE_STANDARD = 0,
TUSB_REQ_TYPE_CLASS,
- TUSB_REQ_TYPE_VENDOR
+ TUSB_REQ_TYPE_VENDOR,
+ TUSB_REQ_TYPE_INVALID
} tusb_request_type_t;
typedef enum
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 2727ce043..fae0c88ae 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -36,10 +36,34 @@
* 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
+ * This contains macros for both VERIFY and ASSERT:
+ *
+ * VERIFY: Used when there is an error condition which is not the
+ * fault of the MCU. For example, bounds checking on data
+ * sent to the micro over USB should use this function.
+ * Another example is checking for buffer overflows, where
+ * returning from the active function causes a NAK.
+ *
+ * ASSERT: Used for error conditions that are caused by MCU firmware
+ * bugs. This is used to discover bugs in the code more
+ * quickly. One example would be adding assertions in library
+ * function calls to confirm a function's (untainted)
+ * parameters are valid.
+ *
+ *
+ * The difference in behaviour is that ASSERT triggers a breakpoint while
+ * verify does not.
+ *
+ * #define TU_VERIFY(cond) if(cond) return false;
+ * #define TU_VERIFY(cond,ret) if(cond) return ret;
+ *
+ * #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;}
+ * #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;}
+ *
+ * #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;}
+ * #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
+ *
*------------------------------------------------------------------*/
#ifdef __cplusplus
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 184702f1a..0366d1ece 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -61,6 +61,9 @@ typedef struct {
static usbd_device_t _usbd_dev = { 0 };
+// Invalid driver ID in itf2drv[] ep2drv[][] mapping
+enum { DRVID_INVALID = 0xFFu };
+
//--------------------------------------------------------------------+
// Class Driver
//--------------------------------------------------------------------+
@@ -144,7 +147,7 @@ static usbd_class_driver_t const usbd_class_drivers[] =
#endif
};
-enum { USBD_CLASS_DRIVER_COUNT = TU_ARRAY_SZIE(usbd_class_drivers) };
+enum { USBD_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbd_class_drivers) };
//--------------------------------------------------------------------+
// DCD Event
@@ -213,8 +216,8 @@ static void usbd_reset(uint8_t rhport)
{
tu_varclr(&_usbd_dev);
- memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping
- memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping
+ memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
+ memset(_usbd_dev.ep2drv , DRVID_INVALID, sizeof(_usbd_dev.ep2drv )); // invalid mapping
usbd_control_reset(rhport);
@@ -287,19 +290,19 @@ void tud_task (void)
{
// Invoke the class callback associated with the endpoint address
uint8_t const ep_addr = event.xfer_complete.ep_addr;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const ep_dir = tu_edpt_dir(ep_addr);
- _usbd_dev.ep_busy_map[dir] = (uint8_t) tu_bit_clear(_usbd_dev.ep_busy_map[dir], epnum);
+ _usbd_dev.ep_busy_map[ep_dir] = (uint8_t) tu_bit_clear(_usbd_dev.ep_busy_map[ep_dir], epnum);
- if ( 0 == tu_edpt_number(ep_addr) )
+ if ( 0 == epnum )
{
// control transfer DATA stage callback
usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
}
else
{
- uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)];
+ uint8_t const drv_id = _usbd_dev.ep2drv[epnum][ep_dir];
TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,);
usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
@@ -346,6 +349,8 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
{
usbd_control_set_complete_callback(NULL);
+ TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID);
+
// Vendor request
if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR )
{
@@ -435,7 +440,7 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
case TUSB_REQ_RCPT_INTERFACE:
{
uint8_t const itf = tu_u16_low(p_request->wIndex);
- TU_VERIFY(itf < TU_ARRAY_SZIE(_usbd_dev.itf2drv));
+ TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
uint8_t const drvid = _usbd_dev.itf2drv[itf];
TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT);
@@ -465,56 +470,91 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
default:
// forward to class driver: "STD request to Interface"
// GET HID REPORT DESCRIPTOR falls into this case
- usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_complete);
-
// stall control endpoint if driver return false
- TU_ASSERT(usbd_class_drivers[drvid].control_request(rhport, p_request));
+ usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_complete);
+ TU_ASSERT(usbd_class_drivers[drvid].control_request != NULL &&
+ usbd_class_drivers[drvid].control_request(rhport, p_request));
break;
}
}else
{
// forward to class driver: "non-STD request to Interface"
- usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_complete);
-
// stall control endpoint if driver return false
- TU_ASSERT(usbd_class_drivers[drvid].control_request(rhport, p_request));
+ usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_complete);
+ TU_ASSERT(usbd_class_drivers[drvid].control_request != NULL &&
+ usbd_class_drivers[drvid].control_request(rhport, p_request));
}
}
break;
//------------- Endpoint Request -------------//
case TUSB_REQ_RCPT_ENDPOINT:
- // Non standard request is not supported
- TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type );
+ {
+ uint8_t const ep_addr = tu_u16_low(p_request->wIndex);
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ uint8_t const ep_dir = tu_edpt_dir(ep_addr);
- switch ( p_request->bRequest )
+ TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
+
+ uint8_t const drv_id = _usbd_dev.ep2drv[ep_num][ep_dir];
+ TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT);
+
+ // Some classes such as TMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request
+ // We will forward all request targeted endpoint to its class driver
+ // - For non-standard request: driver can ACK or Stall the request by return true/false
+ // - For standard request: usbd decide the ACK stage regardless of driver return value
+ bool ret = false;
+
+ if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
{
- case TUSB_REQ_GET_STATUS:
- {
- uint16_t status = usbd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
- tud_control_xfer(rhport, p_request, &status, 2);
- }
- break;
+ // complete callback is also capable of stalling/acking the request
+ usbd_control_set_complete_callback(usbd_class_drivers[drv_id].control_complete);
+ }
- case TUSB_REQ_CLEAR_FEATURE:
- if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
- {
- usbd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
- }
- tud_control_status(rhport, p_request);
- break;
+ // Invoke class driver first if available
+ if ( usbd_class_drivers[drv_id].control_request )
+ {
+ ret = usbd_class_drivers[drv_id].control_request(rhport, p_request);
+ }
- case TUSB_REQ_SET_FEATURE:
- if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
+ // Then handle if it is standard request
+ if ( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
+ {
+ // force return true for standard request
+ ret = true;
+
+ switch ( p_request->bRequest )
+ {
+ case TUSB_REQ_GET_STATUS:
{
- usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
+ uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000;
+ tud_control_xfer(rhport, p_request, &status, 2);
}
- tud_control_status(rhport, p_request);
- break;
+ break;
- // Unknown/Unsupported request
- default: TU_BREAKPOINT(); return false;
+ case TUSB_REQ_CLEAR_FEATURE:
+ if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
+ {
+ usbd_edpt_clear_stall(rhport, ep_addr);
+ }
+ tud_control_status(rhport, p_request);
+ break;
+
+ case TUSB_REQ_SET_FEATURE:
+ if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
+ {
+ usbd_edpt_stall(rhport, ep_addr);
+ }
+ tud_control_status(rhport, p_request);
+ break;
+
+ // Unknown/Unsupported request
+ default: TU_BREAKPOINT(); return false;
+ }
}
+
+ return ret;
+ }
break;
// Unknown recipient
@@ -560,7 +600,7 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT );
// Interface number must not be used already TODO alternate interface
- TU_ASSERT( 0xff == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] );
+ TU_ASSERT( DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] );
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id;
uint16_t itf_len=0;
diff --git a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
index 2b49f52e9..d5f90d2a7 100644
--- a/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
+++ b/src/portable/nxp/lpc17_40/dcd_lpc17_40.c
@@ -293,7 +293,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
break;
case TUSB_XFER_ISOCHRONOUS:
- TU_ASSERT((epnum % 3) == 3 && (epnum != 15));
+ TU_ASSERT((epnum % 3) == 0 && (epnum != 0) && (epnum != 15));
break;
default: