Wini-Buh %!s(int64=4) %!d(string=hai) anos
pai
achega
60d8ecbfe6

+ 2 - 3
.github/ISSUE_TEMPLATE/bug_report.md

@@ -9,7 +9,7 @@ assignees: ''
 
 **Set Up**
 
-- **PC OS** e.g Ubuntu 20.04 / Windows 10/ macOS 10.15
+- **PC OS** e.g Ubuntu 20.04 / Windows 10 / macOS 10.15
 - **Board** e.g Feather nRF52840 Express (if custom specify your MCUs)
 - **TinyUSB version** relase version or git hash (preferrably running with master for lastest code) 
 - **Firmware** e.g examples/device/cdc_msc
@@ -31,6 +31,5 @@ If applicable, add screenshots, bus capture to help explain your problem.
 
 **Log**
 
-If applicable, provide the stack's log (uart/rtt/swo) where the issue occurred, best with comments to explain the actual events. If the log is too long, attach it as txt file instead.
-
+If applicable, provide the stack's log (uart/rtt/swo) where the issue occurred as attached txt file, best with comments to explain the actual events.
 Note: To enable logging, add `LOG=2` to to the make command if building with stock examples or set `CFG_TUSB_DEBUG=2` in your tusb_config.h. More information can be found at [example's readme](/docs/getting_started.md)

+ 3 - 0
.gitmodules

@@ -121,3 +121,6 @@
 [submodule "hw/mcu/nxp/nxp_sdk"]
 	path = hw/mcu/nxp/nxp_sdk
 	url = https://github.com/hathach/nxp_sdk.git
+[submodule "hw/mcu/mindmotion/mm32sdk"]
+	path = hw/mcu/mindmotion/mm32sdk
+	url = https://github.com/zhangslice/mm32sdk.git

+ 1 - 1
examples/make.mk

@@ -5,7 +5,7 @@
 # Build directory
 BUILD := _build/$(BOARD)
 
-PROJECT := $(BOARD)-$(notdir $(CURDIR))
+PROJECT := $(notdir $(CURDIR))
 BIN := $(TOP)/_bin/$(BOARD)/$(notdir $(CURDIR))
 
 # Handy check parameter function

+ 1 - 0
hw/mcu/mindmotion/mm32sdk

@@ -0,0 +1 @@
+Subproject commit b6b99de3ab26218784ec158488bdd91377288f94

+ 7 - 5
src/class/cdc/cdc_host.c

@@ -29,6 +29,8 @@
 #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_CDC)
 
 #include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+
 #include "cdc_host.h"
 
 //--------------------------------------------------------------------+
@@ -71,13 +73,13 @@ bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid)
   switch (pipeid)
   {
     case CDC_PIPE_NOTIFICATION:
-      return hcd_edpt_busy(dev_addr, p_cdc->ep_notif );
+      return usbh_edpt_busy(dev_addr, p_cdc->ep_notif );
 
     case CDC_PIPE_DATA_IN:
-      return hcd_edpt_busy(dev_addr, p_cdc->ep_in );
+      return usbh_edpt_busy(dev_addr, p_cdc->ep_in );
 
     case CDC_PIPE_DATA_OUT:
-      return hcd_edpt_busy(dev_addr, p_cdc->ep_out );
+      return usbh_edpt_busy(dev_addr, p_cdc->ep_out );
 
     default:
       return false;
@@ -101,7 +103,7 @@ bool tuh_cdc_send(uint8_t dev_addr, void const * p_data, uint32_t length, bool i
   TU_VERIFY( p_data != NULL && length, TUSB_ERROR_INVALID_PARA);
 
   uint8_t const ep_out = cdch_data[dev_addr-1].ep_out;
-  if ( hcd_edpt_busy(dev_addr, ep_out) ) return false;
+  if ( usbh_edpt_busy(dev_addr, ep_out) ) return false;
 
   return usbh_edpt_xfer(dev_addr, ep_out, (void *) p_data, length);
 }
@@ -113,7 +115,7 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is
   TU_VERIFY( p_buffer != NULL && length, TUSB_ERROR_INVALID_PARA);
 
   uint8_t const ep_in = cdch_data[dev_addr-1].ep_in;
-  if ( hcd_edpt_busy(dev_addr, ep_in) ) return false;
+  if ( usbh_edpt_busy(dev_addr, ep_in) ) return false;
 
   return usbh_edpt_xfer(dev_addr, ep_in, p_buffer, length);
 }

+ 61 - 18
src/class/hid/hid.h

@@ -201,30 +201,73 @@ typedef struct TU_ATTR_PACKED
   int8_t  rx;        ///< Delta Rx movement of analog left trigger
   int8_t  ry;        ///< Delta Ry movement of analog right trigger
   uint8_t hat;       ///< Buttons mask for currently pressed buttons in the DPad/hat
-  uint16_t buttons;  ///< Buttons mask for currently pressed buttons
+  uint32_t buttons;  ///< Buttons mask for currently pressed buttons
 }hid_gamepad_report_t;
 
-/// Standard Gamepad Buttons Bitmap (from Linux input event codes)
+/// Standard Gamepad Buttons Bitmap
 typedef enum
 {
-  GAMEPAD_BUTTON_A      = TU_BIT(0),  ///< A/South button
-  GAMEPAD_BUTTON_B      = TU_BIT(1),  ///< B/East button
-  GAMEPAD_BUTTON_C      = TU_BIT(2),  ///< C button
-  GAMEPAD_BUTTON_X      = TU_BIT(3),  ///< X/North button
-  GAMEPAD_BUTTON_Y      = TU_BIT(4),  ///< Y/West button
-  GAMEPAD_BUTTON_Z      = TU_BIT(5),  ///< Z button
-  GAMEPAD_BUTTON_TL     = TU_BIT(6),  ///< L1 button
-  GAMEPAD_BUTTON_TR     = TU_BIT(7),  ///< R1 button
-  GAMEPAD_BUTTON_TL2    = TU_BIT(8),  ///< L2 button
-  GAMEPAD_BUTTON_TR2    = TU_BIT(9),  ///< R2 button
-  GAMEPAD_BUTTON_SELECT = TU_BIT(10), ///< Select button
-  GAMEPAD_BUTTON_START  = TU_BIT(11), ///< Start button
-  GAMEPAD_BUTTON_MODE   = TU_BIT(12), ///< Mode button
-  GAMEPAD_BUTTON_THUMBL = TU_BIT(13), ///< L3 button
-  GAMEPAD_BUTTON_THUMBR = TU_BIT(14), ///< R3 button
-//GAMEPAD_BUTTON_       = TU_BIT(15), ///< Undefined button
+  GAMEPAD_BUTTON_0  = TU_BIT(0),
+  GAMEPAD_BUTTON_1  = TU_BIT(1),
+  GAMEPAD_BUTTON_2  = TU_BIT(2),
+  GAMEPAD_BUTTON_3  = TU_BIT(3),
+  GAMEPAD_BUTTON_4  = TU_BIT(4),
+  GAMEPAD_BUTTON_5  = TU_BIT(5),
+  GAMEPAD_BUTTON_6  = TU_BIT(6),
+  GAMEPAD_BUTTON_7  = TU_BIT(7),
+  GAMEPAD_BUTTON_8  = TU_BIT(8),
+  GAMEPAD_BUTTON_9  = TU_BIT(9),
+  GAMEPAD_BUTTON_10 = TU_BIT(10),
+  GAMEPAD_BUTTON_11 = TU_BIT(11),
+  GAMEPAD_BUTTON_12 = TU_BIT(12),
+  GAMEPAD_BUTTON_13 = TU_BIT(13),
+  GAMEPAD_BUTTON_14 = TU_BIT(14),
+  GAMEPAD_BUTTON_15 = TU_BIT(15),
+  GAMEPAD_BUTTON_16 = TU_BIT(16),
+  GAMEPAD_BUTTON_17 = TU_BIT(17),
+  GAMEPAD_BUTTON_18 = TU_BIT(18),
+  GAMEPAD_BUTTON_19 = TU_BIT(19),
+  GAMEPAD_BUTTON_20 = TU_BIT(20),
+  GAMEPAD_BUTTON_21 = TU_BIT(21),
+  GAMEPAD_BUTTON_22 = TU_BIT(22),
+  GAMEPAD_BUTTON_23 = TU_BIT(23),
+  GAMEPAD_BUTTON_24 = TU_BIT(24),
+  GAMEPAD_BUTTON_25 = TU_BIT(25),
+  GAMEPAD_BUTTON_26 = TU_BIT(26),
+  GAMEPAD_BUTTON_27 = TU_BIT(27),
+  GAMEPAD_BUTTON_28 = TU_BIT(28),
+  GAMEPAD_BUTTON_29 = TU_BIT(29),
+  GAMEPAD_BUTTON_30 = TU_BIT(30),
+  GAMEPAD_BUTTON_31 = TU_BIT(31),
 }hid_gamepad_button_bm_t;
 
+/// Standard Gamepad Buttons Naming from Linux input event codes
+/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
+#define GAMEPAD_BUTTON_A       GAMEPAD_BUTTON_0
+#define GAMEPAD_BUTTON_SOUTH   GAMEPAD_BUTTON_0
+
+#define GAMEPAD_BUTTON_B       GAMEPAD_BUTTON_1
+#define GAMEPAD_BUTTON_EAST    GAMEPAD_BUTTON_1
+
+#define GAMEPAD_BUTTON_C       GAMEPAD_BUTTON_2
+
+#define GAMEPAD_BUTTON_X       GAMEPAD_BUTTON_3
+#define GAMEPAD_BUTTON_NORTH   GAMEPAD_BUTTON_3
+
+#define GAMEPAD_BUTTON_Y       GAMEPAD_BUTTON_4
+#define GAMEPAD_BUTTON_WEST    GAMEPAD_BUTTON_4
+
+#define GAMEPAD_BUTTON_Z       GAMEPAD_BUTTON_5
+#define GAMEPAD_BUTTON_TL      GAMEPAD_BUTTON_6
+#define GAMEPAD_BUTTON_TR      GAMEPAD_BUTTON_7
+#define GAMEPAD_BUTTON_TL2     GAMEPAD_BUTTON_8
+#define GAMEPAD_BUTTON_TR2     GAMEPAD_BUTTON_9
+#define GAMEPAD_BUTTON_SELECT  GAMEPAD_BUTTON_10
+#define GAMEPAD_BUTTON_START   GAMEPAD_BUTTON_11
+#define GAMEPAD_BUTTON_MODE    GAMEPAD_BUTTON_12
+#define GAMEPAD_BUTTON_THUMBL  GAMEPAD_BUTTON_13
+#define GAMEPAD_BUTTON_THUMBR  GAMEPAD_BUTTON_14
+
 /// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes)
 typedef enum
 {

+ 1 - 1
src/class/hid/hid_device.c

@@ -149,7 +149,7 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
 }
 
 bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
-                              int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons)
+                              int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons)
 {
   hid_gamepad_report_t report =
   {

+ 6 - 6
src/class/hid/hid_device.h

@@ -72,9 +72,9 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi
 // use template layout report as defined by hid_mouse_report_t
 bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
 
-// Gamepad: convenient helper to send mouse report if application
+// Gamepad: convenient helper to send gamepad report if application
 // use template layout report TUD_HID_REPORT_DESC_GAMEPAD
-bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons);
+bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
 
 //--------------------------------------------------------------------+
 // Application API (Single Port)
@@ -85,7 +85,7 @@ static inline uint8_t tud_hid_get_protocol(void);
 static inline bool    tud_hid_report(uint8_t report_id, void const* report, uint8_t len);
 static inline bool    tud_hid_keyboard_report(uint8_t report_id, uint8_t modifier, uint8_t keycode[6]);
 static inline bool    tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
-static inline bool    tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons);
+static inline bool    tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
 
 //--------------------------------------------------------------------+
 // Callbacks (Weak is optional)
@@ -152,7 +152,7 @@ static inline bool tud_hid_mouse_report(uint8_t report_id, uint8_t buttons, int8
   return tud_hid_n_mouse_report(0, report_id, buttons, x, y, vertical, horizontal);
 }
 
-static inline bool  tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint16_t buttons)
+static inline bool  tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons)
 {
   return tud_hid_n_gamepad_report(0, report_id, x, y, z, rz, rx, ry, hat, buttons);
 }
@@ -344,10 +344,10 @@ static inline bool  tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
     /* 16 bit Button Map */ \
     HID_USAGE_PAGE   ( HID_USAGE_PAGE_BUTTON                  ) ,\
     HID_USAGE_MIN    ( 1                                      ) ,\
-    HID_USAGE_MAX    ( 16                                     ) ,\
+    HID_USAGE_MAX    ( 32                                     ) ,\
     HID_LOGICAL_MIN  ( 0                                      ) ,\
     HID_LOGICAL_MAX  ( 1                                      ) ,\
-    HID_REPORT_COUNT ( 16                                     ) ,\
+    HID_REPORT_COUNT ( 32                                     ) ,\
     HID_REPORT_SIZE  ( 1                                      ) ,\
     HID_INPUT        ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ) ,\
   HID_COLLECTION_END \

+ 3 - 1
src/class/hid/hid_host.c

@@ -29,6 +29,8 @@
 #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HID)
 
 #include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+
 #include "hid_host.h"
 
 //--------------------------------------------------------------------+
@@ -199,7 +201,7 @@ bool tuh_hid_set_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, u
 //  TU_VERIFY(tuh_n_hid_n_mounted(dev_addr, instance));
 //
 //  hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
-//  return !hcd_edpt_busy(dev_addr, hid_itf->ep_in);
+//  return !usbh_edpt_busy(dev_addr, hid_itf->ep_in);
 //}
 
 //void tuh_hid_send_report(uint8_t dev_addr, uint8_t instance, uint8_t report_id, uint8_t const* report, uint16_t len);

+ 3 - 1
src/class/msc/msc_host.c

@@ -29,6 +29,8 @@
 #if TUSB_OPT_HOST_ENABLED & CFG_TUH_MSC
 
 #include "host/usbh.h"
+#include "host/usbh_classdriver.h"
+
 #include "msc_host.h"
 
 //--------------------------------------------------------------------+
@@ -109,7 +111,7 @@ bool tuh_msc_mounted(uint8_t dev_addr)
 bool tuh_msc_ready(uint8_t dev_addr)
 {
   msch_interface_t* p_msc = get_itf(dev_addr);
-  return p_msc->mounted && !hcd_edpt_busy(dev_addr, p_msc->ep_in);
+  return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in);
 }
 
 //--------------------------------------------------------------------+

+ 1 - 1
src/common/tusb_common.h

@@ -51,7 +51,7 @@
 #define U32_TO_U8S_BE(u32)    TU_U32_BYTE3(u32), TU_U32_BYTE2(u32), TU_U32_BYTE1(u32), TU_U32_BYTE0(u32)
 #define U32_TO_U8S_LE(u32)    TU_U32_BYTE0(u32), TU_U32_BYTE1(u32), TU_U32_BYTE2(u32), TU_U32_BYTE3(u32)
 
-#define TU_BIT(n)             (1U << (n))
+#define TU_BIT(n)             (1UL << (n))
 
 //--------------------------------------------------------------------+
 // Includes

+ 6 - 6
src/device/dcd.h

@@ -121,20 +121,20 @@ void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
 // May help DCD to prepare for next control transfer, this API is optional.
 void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
 
+// Configure endpoint's registers according to descriptor
+bool dcd_edpt_open            (uint8_t rhport, tusb_desc_endpoint_t const * desc_ep);
+
 // Close an endpoint.
 // Since it is weak, caller must TU_ASSERT this function's existence before calling it.
 void dcd_edpt_close           (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
 
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
+bool dcd_edpt_xfer            (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
+
 // Submit an transfer using fifo, When complete dcd_event_xfer_complete() is invoked to notify the stack
 // This API is optional, may be useful for register-based for transferring data.
 bool dcd_edpt_xfer_fifo       (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) TU_ATTR_WEAK;
 
-// Configure endpoint's registers according to descriptor
-bool dcd_edpt_open            (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
-
-// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
-bool dcd_edpt_xfer            (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
-
 // Stall endpoint
 void dcd_edpt_stall           (uint8_t rhport, uint8_t ep_addr);
 

+ 2 - 2
src/device/usbd.c

@@ -1254,8 +1254,8 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
   // Attempt to transfer on a busy endpoint, sound like an race condition !
   TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
 
-  // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return
-  // and usbd task can preempt and clear the busy
+  // Set busy first since the actual transfer can be complete before dcd_edpt_xfer()
+  // could return and USBD task can preempt and clear the busy
   _usbd_dev.ep_status[epnum][dir].busy = true;
 
   if ( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) )

+ 1 - 1
src/device/usbd_pvt.h

@@ -34,7 +34,7 @@
 #endif
 
 //--------------------------------------------------------------------+
-// Class Drivers
+// Class Driver API
 //--------------------------------------------------------------------+
 
 typedef struct

+ 0 - 3
src/host/hcd.h

@@ -137,9 +137,6 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr);
 bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
 bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
 bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen);
-
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr);
 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr);
 
 //--------------------------------------------------------------------+

+ 1 - 0
src/host/hub.c

@@ -29,6 +29,7 @@
 #if (TUSB_OPT_HOST_ENABLED && CFG_TUH_HUB)
 
 #include "usbh.h"
+#include "usbh_classdriver.h"
 #include "hub.h"
 
 //--------------------------------------------------------------------+

+ 46 - 7
src/host/usbh.c

@@ -24,7 +24,7 @@
  * This file is part of the TinyUSB stack.
  */
 
-#include "common/tusb_common.h"
+#include "tusb_option.h"
 
 #if TUSB_OPT_HOST_ENABLED
 
@@ -32,10 +32,9 @@
 #define CFG_TUH_TASK_QUEUE_SZ   16
 #endif
 
-//--------------------------------------------------------------------+
-// INCLUDE
-//--------------------------------------------------------------------+
 #include "tusb.h"
+#include "host/usbh.h"
+#include "host/usbh_classdriver.h"
 #include "hub.h"
 #include "usbh_hcd.h"
 
@@ -315,8 +314,11 @@ uint8_t* usbh_get_enum_buf(void)
   return _usbh_ctrl_buf;
 }
 
-//------------- Endpoint API -------------//
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
 
+// TODO has some duplication code with device, refactor later
 bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
 {
   uint8_t const epnum = tu_edpt_number(ep_addr);
@@ -344,6 +346,7 @@ bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
   return ret;
 }
 
+// TODO has some duplication code with device, refactor later
 bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
 {
   uint8_t const epnum = tu_edpt_number(ep_addr);
@@ -369,11 +372,36 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
   return ret;
 }
 
+// TODO has some duplication code with device, refactor later
 bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 {
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
   usbh_device_t* dev = &_usbh_devices[dev_addr];
-  TU_LOG2("  Queue EP %02X with %u bytes ... OK\r\n", ep_addr, total_bytes);
-  return hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes);
+
+  TU_LOG2("  Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
+
+  // Attempt to transfer on a busy endpoint, sound like an race condition !
+  TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
+
+  // Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
+  // could return and USBH task can preempt and clear the busy
+  dev->ep_status[epnum][dir].busy = true;
+
+  if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
+  {
+    TU_LOG2("OK\r\n");
+    return true;
+  }else
+  {
+    // HCD error, mark endpoint as ready to allow next transfer
+    dev->ep_status[epnum][dir].busy = false;
+    dev->ep_status[epnum][dir].claimed = 0;
+    TU_LOG2("failed\r\n");
+    TU_BREAKPOINT();
+    return false;
+  }
 }
 
 bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
@@ -420,6 +448,17 @@ bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
   return ret;
 }
 
+bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+{
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  usbh_device_t* dev = &_usbh_devices[dev_addr];
+
+  return dev->ep_status[epnum][dir].busy;
+}
+
+
 //--------------------------------------------------------------------+
 // HCD Event Handler
 //--------------------------------------------------------------------+

+ 3 - 47
src/host/usbh.h

@@ -24,9 +24,6 @@
  * This file is part of the TinyUSB stack.
  */
 
-/** \ingroup group_usbh USB Host Core (USBH)
- *  @{ */
-
 #ifndef _TUSB_USBH_H_
 #define _TUSB_USBH_H_
 
@@ -40,27 +37,6 @@
 //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
-typedef enum tusb_interface_status_{
-  TUSB_INTERFACE_STATUS_READY = 0,
-  TUSB_INTERFACE_STATUS_BUSY,
-  TUSB_INTERFACE_STATUS_COMPLETE,
-  TUSB_INTERFACE_STATUS_ERROR,
-  TUSB_INTERFACE_STATUS_INVALID_PARA
-} tusb_interface_status_t;
-
-typedef struct {
-  #if CFG_TUSB_DEBUG >= 2
-  char const* name;
-  #endif
-
-  uint8_t class_code;
-
-  void (* const init       )(void);
-  bool (* const open       )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen);
-  bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
-  bool (* const xfer_cb    )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
-  void (* const close      )(uint8_t dev_addr);
-} usbh_class_driver_t;
 
 typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
 
@@ -101,34 +77,14 @@ bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request,
 //--------------------------------------------------------------------+
 //TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device);
 
-/** Callback invoked when device is mounted (configured) */
+// Invoked when device is mounted (configured)
 TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr);
 
-/** Callback invoked when device is unmounted (bus reset/unplugged) */
+/// Invoked when device is unmounted (bus reset/unplugged)
 TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr);
 
-//--------------------------------------------------------------------+
-// CLASS-USBH & INTERNAL API
-// TODO move to usbh_pvt.h
-//--------------------------------------------------------------------+
-
-bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc);
-bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
-
-// Claim an endpoint before submitting a transfer.
-// If caller does not make any transfer, it must release endpoint for others.
-bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
-
-void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num);
-
-uint8_t usbh_get_rhport(uint8_t dev_addr);
-
-uint8_t* usbh_get_enum_buf(void);
-
 #ifdef __cplusplus
  }
 #endif
 
-#endif /* _TUSB_USBH_H_ */
-
-/** @} */
+#endif

+ 83 - 0
src/host/usbh_classdriver.h

@@ -0,0 +1,83 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef _TUSB_USBH_CLASSDRIVER_H_
+#define _TUSB_USBH_CLASSDRIVER_H_
+
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------+
+// Class Driver API
+//--------------------------------------------------------------------+
+
+typedef struct {
+  #if CFG_TUSB_DEBUG >= 2
+  char const* name;
+  #endif
+
+  uint8_t class_code;
+
+  void (* const init       )(void);
+  bool (* const open       )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen);
+  bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
+  bool (* const xfer_cb    )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
+  void (* const close      )(uint8_t dev_addr);
+} usbh_class_driver_t;
+
+// Call by class driver to tell USBH that it has complete the enumeration
+void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num);
+
+uint8_t usbh_get_rhport(uint8_t dev_addr);
+
+uint8_t* usbh_get_enum_buf(void);
+
+//--------------------------------------------------------------------+
+// USBH Endpoint API
+//--------------------------------------------------------------------+
+
+// Open an endpoint
+bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep);
+
+// Submit a usb transfer
+bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
+
+// Claim an endpoint before submitting a transfer.
+// If caller does not make any transfer, it must release endpoint for others.
+bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
+
+// Check if endpoint transferring is complete
+bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif

+ 0 - 6
src/host/usbh_hcd.h

@@ -97,12 +97,6 @@ typedef struct {
 
 extern usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // including zero-address
 
-//--------------------------------------------------------------------+
-// callback from HCD ISR
-//--------------------------------------------------------------------+
-
-
-
 #ifdef __cplusplus
  }
 #endif

+ 0 - 12
src/portable/ehci/ehci.c

@@ -440,18 +440,6 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
   return true;
 }
 
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-{
-  ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
-  return !p_qhd->qtd_overlay.halted && (p_qhd->p_qtd_list_head != NULL);
-}
-
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
-{
-  ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);
-  return p_qhd->qtd_overlay.halted && !qhd_has_xact_error(p_qhd);
-}
-
 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
 {
   ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr);

+ 471 - 0
src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c

@@ -0,0 +1,471 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 SE TEAM
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if TUSB_OPT_DEVICE_ENABLED && ( CFG_TUSB_MCU == OPT_MCU_MM32F327X )
+
+#include "reg_usb_otg_fs.h"
+#include "mm32_device.h"
+#include "hal_conf.h"
+#include "device/dcd.h"
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM DECLARATION
+//--------------------------------------------------------------------+
+
+enum {
+  TOK_PID_OUT   = 0x1u,
+  TOK_PID_IN    = 0x9u,
+  TOK_PID_SETUP = 0xDu,
+};
+
+typedef struct TU_ATTR_PACKED
+{
+  union {
+    uint32_t head;
+    struct {
+      union {
+        struct {
+          uint16_t          :  2;
+          uint16_t tok_pid  :  4;
+          uint16_t data     :  1;
+          uint16_t own      :  1;
+          uint16_t          :  8;
+        };
+        struct {
+          uint16_t          :  2;
+          uint16_t bdt_stall:  1;
+          uint16_t dts      :  1;
+          uint16_t ninc     :  1;
+          uint16_t keep     :  1;
+          uint16_t          : 10;
+        };
+      };
+      uint16_t bc          : 10;
+      uint16_t             :  6;
+    };
+  };
+  uint8_t *addr;
+}buffer_descriptor_t;
+
+TU_VERIFY_STATIC( sizeof(buffer_descriptor_t) == 8, "size is not correct" );
+
+typedef struct TU_ATTR_PACKED
+{
+  union {
+    uint32_t state;
+    struct {
+      uint32_t max_packet_size :11;
+      uint32_t                 : 5;
+      uint32_t odd             : 1;
+      uint32_t                 :15;
+    };
+  };
+  uint16_t length;
+  uint16_t remaining;
+}endpoint_state_t;
+
+TU_VERIFY_STATIC( sizeof(endpoint_state_t) == 8, "size is not correct" );
+
+typedef struct
+{
+  union {
+    /* [#EP][OUT,IN][EVEN,ODD] */
+    buffer_descriptor_t bdt[16][2][2];
+    uint16_t            bda[512];
+  };
+  TU_ATTR_ALIGNED(4) union {
+    endpoint_state_t endpoint[16][2];
+    endpoint_state_t endpoint_unified[16 * 2];
+  };
+  uint8_t setup_packet[8];
+  uint8_t addr;
+}dcd_data_t;
+
+//--------------------------------------------------------------------+
+// INTERNAL OBJECT & FUNCTION DECLARATION
+//--------------------------------------------------------------------+
+// BDT(Buffer Descriptor Table) must be 256-byte aligned
+CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(512) static dcd_data_t _dcd;
+
+TU_VERIFY_STATIC( sizeof(_dcd.bdt) == 512, "size is not correct" );
+
+static void prepare_next_setup_packet(uint8_t rhport)
+{
+  const unsigned out_odd = _dcd.endpoint[0][0].odd;
+  const unsigned in_odd  = _dcd.endpoint[0][1].odd;
+  if (_dcd.bdt[0][0][out_odd].own) {
+    TU_LOG1("DCD fail to prepare the next SETUP %d %d\r\n", out_odd, in_odd);
+    return;
+  }
+  _dcd.bdt[0][0][out_odd].data     = 0;
+  _dcd.bdt[0][0][out_odd ^ 1].data = 1;
+  _dcd.bdt[0][1][in_odd].data      = 1;
+  _dcd.bdt[0][1][in_odd ^ 1].data  = 0;
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_OUT),
+                _dcd.setup_packet, sizeof(_dcd.setup_packet));
+}
+
+static void process_stall(uint8_t rhport)
+{
+  if (USB_OTG_FS->EP_CTL[0] & USB_ENDPT_EPSTALL_MASK) {
+    /* clear stall condition of the control pipe */
+    prepare_next_setup_packet(rhport);
+    USB_OTG_FS->EP_CTL[0] &= ~USB_ENDPT_EPSTALL_MASK;
+  }
+}
+
+static void process_tokdne(uint8_t rhport)
+{
+  const unsigned s = USB_OTG_FS->STAT;
+  USB_OTG_FS->INT_STAT = USB_ISTAT_TOKDNE_MASK; /* fetch the next token if received */
+  buffer_descriptor_t *bd = (buffer_descriptor_t *)&_dcd.bda[s];
+  endpoint_state_t    *ep = &_dcd.endpoint_unified[s >> 3];
+  unsigned odd = (s & USB_STAT_ODD_MASK) ? 1 : 0;
+
+  /* fetch pid before discarded by the next steps */
+  const unsigned pid = bd->tok_pid;
+  /* reset values for a next transfer */
+  bd->bdt_stall = 0;
+  bd->dts       = 1;
+  bd->ninc      = 0;
+  bd->keep      = 0;
+  /* update the odd variable to prepare for the next transfer */
+  ep->odd       = odd ^ 1;
+  if (pid == TOK_PID_SETUP) {
+    dcd_event_setup_received(rhport, bd->addr, true);
+    USB_OTG_FS->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK;
+    return;
+  }
+  if (s >> 4) {
+    TU_LOG1("TKDNE %x\r\n", s);
+  }
+
+  const unsigned bc = bd->bc;
+  const unsigned remaining = ep->remaining - bc;
+  if (remaining && bc == ep->max_packet_size) {
+    /* continue the transferring consecutive data */
+    ep->remaining = remaining;
+    const int next_remaining = remaining - ep->max_packet_size;
+    if (next_remaining > 0) {
+      /* prepare to the after next transfer */
+      bd->addr += ep->max_packet_size * 2;
+      bd->bc    = next_remaining > ep->max_packet_size ? ep->max_packet_size: next_remaining;
+      __DSB();
+      bd->own   = 1; /* the own bit must set after addr */
+    }
+    return;
+  }
+  const unsigned length = ep->length;
+  dcd_event_xfer_complete(rhport,
+                          ((s & USB_STAT_TX_MASK) << 4) | (s >> USB_STAT_ENDP_SHIFT),
+                          length - remaining, XFER_RESULT_SUCCESS, true);
+  if (0 == (s & USB_STAT_ENDP_MASK) && 0 == length) {
+    /* After completion a ZLP of control transfer,
+     * it prepares for the next steup transfer. */
+    if (_dcd.addr) {
+      /* When the transfer was the SetAddress,
+       * the device address should be updated here. */
+      USB_OTG_FS->ADDR = _dcd.addr;
+      _dcd.addr  = 0;
+    }
+    prepare_next_setup_packet(rhport);
+  }
+}
+
+static void process_bus_reset(uint8_t rhport)
+{
+  USB_OTG_FS->CTL     |= USB_CTL_ODDRST_MASK;
+  USB_OTG_FS->ADDR     = 0;
+  USB_OTG_FS->INT_ENB    = (USB_OTG_FS->INT_ENB & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+
+  USB_OTG_FS->EP_CTL[0] = USB_ENDPT_EPHSHK_MASK | USB_ENDPT_EPRXEN_MASK | USB_ENDPT_EPTXEN_MASK;
+  for (unsigned i = 1; i < 16; ++i) {
+    USB_OTG_FS->EP_CTL[i] = 0;
+  }
+  buffer_descriptor_t *bd = _dcd.bdt[0][0];
+  for (unsigned i = 0; i < sizeof(_dcd.bdt)/sizeof(*bd); ++i, ++bd) {
+    bd->head = 0;
+  }
+  const endpoint_state_t ep0 = {
+    .max_packet_size = CFG_TUD_ENDPOINT0_SIZE,
+    .odd             = 0,
+    .length          = 0,
+    .remaining       = 0,
+  };
+  _dcd.endpoint[0][0] = ep0;
+  _dcd.endpoint[0][1] = ep0;
+  tu_memclr(_dcd.endpoint[1], sizeof(_dcd.endpoint) - sizeof(_dcd.endpoint[0]));
+  _dcd.addr = 0;
+  prepare_next_setup_packet(rhport);
+  USB_OTG_FS->CTL &= ~USB_CTL_ODDRST_MASK;
+  dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+}
+
+static void process_bus_inactive(uint8_t rhport)
+{
+  (void) rhport;
+  const unsigned inten = USB_OTG_FS->INT_ENB;
+  USB_OTG_FS->INT_ENB    = (inten & ~USB_INTEN_SLEEPEN_MASK) | USB_INTEN_RESUMEEN_MASK;
+  dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
+}
+
+static void process_bus_active(uint8_t rhport)
+{
+  (void) rhport;
+  const unsigned inten = USB_OTG_FS->INT_ENB;
+  USB_OTG_FS->INT_ENB    = (inten & ~USB_INTEN_RESUMEEN_MASK) | USB_INTEN_SLEEPEN_MASK;
+  dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
+}
+
+/*------------------------------------------------------------------*/
+/* Device API
+ *------------------------------------------------------------------*/
+void dcd_init(uint8_t rhport)
+{
+  (void) rhport;
+
+  tu_memclr(&_dcd, sizeof(_dcd));
+  USB_OTG_FS->BDT_PAGE_01 = (uint8_t)((uintptr_t)_dcd.bdt >>  8);
+  USB_OTG_FS->BDT_PAGE_02 = (uint8_t)((uintptr_t)_dcd.bdt >> 16);
+  USB_OTG_FS->BDT_PAGE_03 = (uint8_t)((uintptr_t)_dcd.bdt >> 24);
+
+  dcd_connect(rhport);
+  NVIC_ClearPendingIRQ(USB_FS_IRQn);
+}
+#define USB_DEVICE_INTERRUPT_PRIORITY (3U)
+void dcd_int_enable(uint8_t rhport)
+{
+  uint8_t irqNumber;
+  irqNumber = USB_FS_IRQn;
+  (void) rhport;
+  USB_OTG_FS->INT_ENB = USB_INTEN_USBRSTEN_MASK | USB_INTEN_TOKDNEEN_MASK |
+    USB_INTEN_SLEEPEN_MASK | USB_INTEN_ERROREN_MASK | USB_INTEN_STALLEN_MASK;
+  NVIC_SetPriority((IRQn_Type)irqNumber, USB_DEVICE_INTERRUPT_PRIORITY);
+  NVIC_EnableIRQ(USB_FS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_FS_IRQn);
+  USB_OTG_FS->INT_ENB = 0;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
+{
+  (void) rhport;
+  _dcd.addr = dev_addr & 0x7F;
+  /* Response with status first before changing device address */
+  dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
+}
+extern u32 SystemCoreClock ;
+void dcd_remote_wakeup(uint8_t rhport)
+{
+  (void) rhport;
+  unsigned cnt = SystemCoreClock / 100;
+  USB_OTG_FS->CTL |= USB_CTL_RESUME_MASK;
+  while (cnt--) __NOP();
+  USB_OTG_FS->CTL &= ~USB_CTL_RESUME_MASK;
+}
+
+void dcd_connect(uint8_t rhport)
+{
+  (void) rhport;
+  USB_OTG_FS->CTL     |= USB_CTL_USBENSOFEN_MASK;
+}
+
+void dcd_disconnect(uint8_t rhport)
+{
+  (void) rhport;
+  USB_OTG_FS->CTL      = 0;
+}
+
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc)
+{
+  (void) rhport;
+
+  const unsigned ep_addr  = ep_desc->bEndpointAddress;
+  const unsigned epn      = ep_addr & 0xFu;
+  const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  const unsigned xfer     = ep_desc->bmAttributes.xfer;
+  endpoint_state_t *ep    = &_dcd.endpoint[epn][dir];
+  const unsigned odd      = ep->odd;
+  buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+
+  /* No support for control transfer */
+  TU_ASSERT(epn && (xfer != TUSB_XFER_CONTROL));
+
+  ep->max_packet_size = ep_desc->wMaxPacketSize.size;
+  unsigned val = USB_ENDPT_EPCTLDIS_MASK;
+  val |= (xfer != TUSB_XFER_ISOCHRONOUS) ? USB_ENDPT_EPHSHK_MASK: 0;
+  val |= dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+  USB_OTG_FS->EP_CTL[epn] |= val;
+
+  if (xfer != TUSB_XFER_ISOCHRONOUS) {
+    bd[odd].dts      = 1;
+    bd[odd].data     = 0;
+    bd[odd ^ 1].dts  = 1;
+    bd[odd ^ 1].data = 1;
+  }
+
+  return true;
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  const unsigned epn      = ep_addr & 0xFu;
+  const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  endpoint_state_t *ep    = &_dcd.endpoint[epn][dir];
+  buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][0];
+  const unsigned msk      = dir ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK;
+  USB_OTG_FS->EP_CTL[epn] &= ~msk;
+  ep->max_packet_size = 0;
+  ep->length          = 0;
+  ep->remaining       = 0;
+  bd->head            = 0;
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes)
+{
+  (void) rhport;
+  NVIC_DisableIRQ(USB_FS_IRQn);
+  const unsigned epn = ep_addr & 0xFu;
+  const unsigned dir = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  endpoint_state_t    *ep = &_dcd.endpoint[epn][dir];
+  buffer_descriptor_t *bd = &_dcd.bdt[epn][dir][ep->odd];
+
+  if (bd->own) {
+    TU_LOG1("DCD XFER fail %x %d %lx %lx\r\n", ep_addr, total_bytes, ep->state, bd->head);
+    return false; /* The last transfer has not completed */
+  }
+  ep->length    = total_bytes;
+  ep->remaining = total_bytes;
+
+  const unsigned mps = ep->max_packet_size;
+  if (total_bytes > mps) {
+    buffer_descriptor_t *next = ep->odd ? bd - 1: bd + 1;
+    /* When total_bytes is greater than the max packet size,
+     * it prepares to the next transfer to avoid NAK in advance. */
+    next->bc   = total_bytes >= 2 * mps ? mps: total_bytes - mps;
+    next->addr = buffer + mps;
+    next->own  = 1;
+  }
+  bd->bc        = total_bytes >= mps ? mps: total_bytes;
+  bd->addr      = buffer;
+  __DSB();
+  bd->own  = 1; /* the own bit must set after addr */
+  NVIC_EnableIRQ(USB_FS_IRQn);
+  return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  const unsigned epn = ep_addr & 0xFu;
+  if (0 == epn) {
+    USB_OTG_FS->EP_CTL[epn] |=  USB_ENDPT_EPSTALL_MASK;
+  } else {
+    const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+    buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+    bd[0].bdt_stall = 1;
+    bd[1].bdt_stall = 1;
+  }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+  const unsigned epn      = ep_addr & 0xFu;
+  const unsigned dir      = (ep_addr & TUSB_DIR_IN_MASK) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+  const unsigned odd      = _dcd.endpoint[epn][dir].odd;
+  buffer_descriptor_t *bd = _dcd.bdt[epn][dir];
+
+  bd[odd ^ 1].own       = 0;
+  bd[odd ^ 1].data      = 1;
+  bd[odd ^ 1].bdt_stall = 0;
+  bd[odd].own           = 0;
+  bd[odd].data          = 0;
+  bd[odd].bdt_stall     = 0;
+}
+
+//--------------------------------------------------------------------+
+// ISR
+//--------------------------------------------------------------------+
+void dcd_int_handler(uint8_t rhport)
+{
+  (void) rhport;
+
+  uint32_t is  = USB_OTG_FS->INT_STAT;
+  uint32_t msk = USB_OTG_FS->INT_ENB;
+  USB_OTG_FS->INT_STAT = is & ~msk;
+  is &= msk;
+  if (is & USB_ISTAT_ERROR_MASK) {
+    /* TODO: */
+    uint32_t es = USB_OTG_FS->ERR_STAT;
+    USB_OTG_FS->ERR_STAT = es;
+    USB_OTG_FS->INT_STAT   = is; /* discard any pending events */
+    return;
+  }
+
+  if (is & USB_ISTAT_USBRST_MASK) {
+    USB_OTG_FS->INT_STAT = is; /* discard any pending events */
+    process_bus_reset(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_SLEEP_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_SLEEP_MASK;
+    process_bus_inactive(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_RESUME_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_RESUME_MASK;
+    process_bus_active(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_SOFTOK_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_SOFTOK_MASK;
+    dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+    return;
+  }
+  if (is & USB_ISTAT_STALL_MASK) {
+    USB_OTG_FS->INT_STAT = USB_ISTAT_STALL_MASK;
+    process_stall(rhport);
+    return;
+  }
+  if (is & USB_ISTAT_TOKDNE_MASK) {
+    process_tokdne(rhport);
+    return;
+  }
+}
+
+#endif

+ 0 - 12
src/portable/ohci/ohci.c

@@ -489,18 +489,6 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
   return true;
 }
 
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-{
-  ohci_ed_t const * const p_ed = ed_from_addr(dev_addr, ep_addr);
-  return tu_align16(p_ed->td_head.address) != tu_align16(p_ed->td_tail);
-}
-
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
-{
-  ohci_ed_t const * const p_ed = ed_from_addr(dev_addr, ep_addr);
-  return p_ed->td_head.halted && p_ed->is_stalled;
-}
-
 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
 {
   ohci_ed_t * const p_ed = ed_from_addr(dev_addr, ep_addr);

+ 13 - 19
src/portable/raspberrypi/rp2040/hcd_rp2040.c

@@ -515,25 +515,19 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
     return true;
 }
 
-bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
-{
-    // EPX is shared, so multiple device addresses and endpoint addresses share that
-    // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
-    // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
-    // on that device
-    pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
-    struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
-    assert(ep);
-    bool busy = ep->active;
-    pico_trace("busy == %d\n", busy);
-    return busy;
-}
-
-bool hcd_edpt_stalled(uint8_t dev_addr, uint8_t ep_addr)
-{
-    panic("hcd_pipe_stalled");
-    return false;
-}
+//bool hcd_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
+//{
+//    // EPX is shared, so multiple device addresses and endpoint addresses share that
+//    // so if any transfer is active on epx, we are busy. Interrupt endpoints have their own
+//    // EPX so ep->active will only be busy if there is a pending transfer on that interrupt endpoint
+//    // on that device
+//    pico_trace("hcd_edpt_busy dev addr %d ep_addr 0x%x\n", dev_addr, ep_addr);
+//    struct hw_endpoint *ep = get_dev_ep(dev_addr, ep_addr);
+//    assert(ep);
+//    bool busy = ep->active;
+//    pico_trace("busy == %d\n", busy);
+//    return busy;
+//}
 
 bool hcd_edpt_clear_stall(uint8_t dev_addr, uint8_t ep_addr)
 {

+ 5 - 6
src/portable/raspberrypi/rp2040/rp2040_usb.c

@@ -205,10 +205,7 @@ void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
     // Update hw endpoint struct with info from hardware
     // after a buff status interrupt
 
-    // Get the buffer state and amount of bytes we have
-    // transferred
     uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
-    uint16_t transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
 
 #if TUSB_OPT_HOST_ENABLED
     // RP2040-E4
@@ -227,6 +224,9 @@ void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
     // end::host_buf_sel_fix[]
 #endif
 
+    // Get tranferred bytes after adjusted buf sel
+    uint16_t const transferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+
     // We are continuing a transfer here. If we are TX, we have successfullly
     // sent some data can increase the length we have sent
     if (!ep->rx)
@@ -249,7 +249,7 @@ void _hw_endpoint_xfer_sync(struct hw_endpoint *ep)
     // Sometimes the host will send less data than we expect...
     // If this is a short out transfer update the total length of the transfer
     // to be the current length
-    if ((ep->rx) && (transferred_bytes < ep->transfer_size))
+    if ((ep->rx) && (transferred_bytes < ep->wMaxPacketSize))
     {
         pico_trace("Short rx transfer\n");
         // Reduce total length as this is last packet
@@ -289,8 +289,7 @@ bool _hw_endpoint_xfer_continue(struct hw_endpoint *ep)
     {
         pico_trace("Completed transfer of %d bytes on ep %d %s\n",
                    ep->len, tu_edpt_number(ep->ep_addr), ep_dir_string[tu_edpt_dir(ep->ep_addr)]);
-        // Notify caller we are done so it can notify the tinyusb
-        // stack
+        // Notify caller we are done so it can notify the tinyusb stack
         _hw_endpoint_lock_update(ep, -1);
         return true;
     }

+ 3 - 0
src/tusb_option.h

@@ -114,6 +114,9 @@
 #define OPT_MCU_RX63X            1400 ///< Renesas RX63N/631
 #define OPT_MCU_RX72N            1401 ///< Renesas RX72N
 
+// Mind Motion
+#define OPT_MCU_MM32F327X        1500 ///< Mind Motion MM32F327
+
 /** @} */
 
 /** \defgroup group_supported_os Supported RTOS