From 8cbc34de11ccaaf0831cda14ad703d8d962ae725 Mon Sep 17 00:00:00 2001
From: hathach <thach@tinyusb.org>
Date: Wed, 8 Jun 2022 01:17:01 +0700
Subject: [PATCH] add tuh_configure() for port/dynamic host behavior config

---
 hw/bsp/rp2040/family.c                        | 16 +++++++-
 src/device/usbd.c                             |  2 +-
 src/host/hcd.h                                |  5 ++-
 src/host/usbh.c                               | 39 ++++++++++++-------
 src/host/usbh.h                               | 16 +++++++-
 .../raspberrypi/pio_usb/hcd_pio_usb.c         | 12 +++++-
 6 files changed, 67 insertions(+), 23 deletions(-)

diff --git a/hw/bsp/rp2040/family.c b/hw/bsp/rp2040/family.c
index 8de1c1aab..68c9e2d52 100644
--- a/hw/bsp/rp2040/family.c
+++ b/hw/bsp/rp2040/family.c
@@ -35,6 +35,13 @@
 #include "bsp/board.h"
 #include "board.h"
 
+#if CFG_TUH_RPI_PIO_USB || CFG_TUD_RPI_PIO_USB
+#include "pio_usb.h"
+#endif
+
+// PIO_USB_DP_PIN_DEFAULT is 0, which conflict with UART, change to 2
+#define PICO_PIO_USB_PIN_DP   2
+
 #ifdef BUTTON_BOOTSEL
 // This example blinks the Picoboard LED when the BOOTSEL button is pressed.
 //
@@ -130,6 +137,12 @@ void board_init(void)
 #if CFG_TUH_RPI_PIO_USB || CFG_TUD_RPI_PIO_USB
   // Set the system clock to a multiple of 120mhz for bitbanging USB with pico-usb
   set_sys_clock_khz(120000, true);
+
+  // rp2040 use pico-pio-usb for host tuh_configure() can be used to passed pio configuration to the host stack
+  // Note: tuh_configure() must be called before tuh_init()
+  pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
+  pio_cfg.pin_dp = PICO_PIO_USB_PIN_DP;
+  tuh_configure(BOARD_TUH_RHPORT, TUH_CFGID_RPI_PIO_USB_CONFIGURATION, &pio_cfg);
 #endif
 
 #if defined(UART_DEV) && defined(LIB_PICO_STDIO_UART)
@@ -142,9 +155,8 @@ void board_init(void)
   stdio_rtt_init();
 #endif
 
-  // todo probably set up device mode?
 #if CFG_TUD_ENABLED
-
+  // TODO probably set up device mode?
 #endif
 
 #if CFG_TUH_ENABLED
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 55e478a4e..697477584 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -392,7 +392,7 @@ bool tud_init (uint8_t rhport)
   // skip if already initialized
   if ( tud_inited() ) return true;
 
-  TU_LOG2("USBD init\r\n");
+  TU_LOG2("USBD init rhport %u\r\n", rhport);
   TU_LOG2_INT(sizeof(usbd_device_t));
 
   tu_varclr(&_usbd_dev);
diff --git a/src/host/hcd.h b/src/host/hcd.h
index 036394c72..2bc85034f 100644
--- a/src/host/hcd.h
+++ b/src/host/hcd.h
@@ -48,7 +48,7 @@
 //  #endif
 #endif
 
- //--------------------------------------------------------------------+
+//--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
 typedef enum
@@ -106,6 +106,9 @@ typedef struct
 // Controller API
 //--------------------------------------------------------------------+
 
+// optional hcd configuration, called by tuh_config()
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_ATTR_WEAK;
+
 // Initialize controller to host mode
 bool hcd_init(uint8_t rhport);
 
diff --git a/src/host/usbh.c b/src/host/usbh.c
index e0e41a8d1..ab2d8770a 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -274,9 +274,32 @@ static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t h
 static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
 static bool usbh_control_xfer_cb (uint8_t daddr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
 
+#if CFG_TUSB_OS == OPT_OS_NONE
+// TODO rework time-related function later
+void osal_task_delay(uint32_t msec)
+{
+  (void) msec;
+
+  const uint32_t start = hcd_frame_number(TUH_OPT_RHPORT);
+  while ( ( hcd_frame_number(TUH_OPT_RHPORT) - start ) < msec ) {}
+}
+#endif
+
 //--------------------------------------------------------------------+
 // PUBLIC API (Parameter Verification is required)
 //--------------------------------------------------------------------+
+
+bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
+{
+  if (hcd_configure)
+  {
+    return hcd_configure(rhport, cfg_id, cfg_param);
+  }else
+  {
+    return false;
+  }
+}
+
 bool tuh_mounted(uint8_t dev_addr)
 {
   usbh_device_t* dev = get_device(dev_addr);
@@ -303,20 +326,6 @@ tusb_speed_t tuh_speed_get (uint8_t dev_addr)
   return (tusb_speed_t) (dev ? get_device(dev_addr)->speed : _dev0.speed);
 }
 
-#if CFG_TUSB_OS == OPT_OS_NONE
-void osal_task_delay(uint32_t msec)
-{
-  (void) msec;
-
-  const uint32_t start = hcd_frame_number(TUH_OPT_RHPORT);
-  while ( ( hcd_frame_number(TUH_OPT_RHPORT) - start ) < msec ) {}
-}
-#endif
-
-//--------------------------------------------------------------------+
-// CLASS-USBD API (don't require to verify parameters)
-//--------------------------------------------------------------------+
-
 static void clear_device(usbh_device_t* dev)
 {
   tu_memclr(dev, sizeof(usbh_device_t));
@@ -334,7 +343,7 @@ bool tuh_init(uint8_t rhport)
   // skip if already initialized
   if (_usbh_initialized) return _usbh_initialized;
 
-  TU_LOG2("USBH init\r\n");
+  TU_LOG2("USBH init rhport %u\r\n", rhport);
   TU_LOG2_INT(sizeof(usbh_device_t));
   TU_LOG2_INT(sizeof(hcd_event_t));
   TU_LOG2_INT(sizeof(_ctrl_xfer));
diff --git a/src/host/usbh.h b/src/host/usbh.h
index c6d36fb7f..4c65da206 100644
--- a/src/host/usbh.h
+++ b/src/host/usbh.h
@@ -46,8 +46,8 @@ typedef void (*tuh_xfer_cb_t)(tuh_xfer_t* xfer);
 
 // Note1: layout and order of this will be changed in near future
 // it is advised to initialize it using member name
-// Note2: not all field is available/meaningful in callback, some info is not saved by
-// usbh to save SRAM
+// Note2: not all field is available/meaningful in callback,
+// some info is not saved by usbh to save SRAM
 struct tuh_xfer_s
 {
   uint8_t daddr;
@@ -69,6 +69,12 @@ struct tuh_xfer_s
   // uint32_t timeout_ms;    // place holder, not supported yet
 };
 
+// ConfigID for tuh_config()
+enum
+{
+  TUH_CFGID_RPI_PIO_USB_CONFIGURATION = OPT_MCU_RP2040 // cfg_param: pio_usb_configuration_t
+};
+
 //--------------------------------------------------------------------+
 // APPLICATION CALLBACK
 //--------------------------------------------------------------------+
@@ -85,6 +91,12 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
 // APPLICATION API
 //--------------------------------------------------------------------+
 
+// Configure host stack behavior with dynamic or port-specific parameters.
+// Should be called before tuh_init()
+// - cfg_id   : configure ID (TBD)
+// - cfg_param: configure data, structure depends on the ID
+bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param);
+
 // Init host stack
 bool tuh_init(uint8_t rhport);
 
diff --git a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
index 1b2d29331..58b153ac3 100644
--- a/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
+++ b/src/portable/raspberrypi/pio_usb/hcd_pio_usb.c
@@ -43,17 +43,25 @@
 #define RHPORT_OFFSET     1
 #define RHPORT_PIO(_x)    ((_x)-RHPORT_OFFSET)
 
-static pio_usb_configuration_t pio_host_config = PIO_USB_DEFAULT_CONFIG;
+static pio_usb_configuration_t pio_host_cfg = PIO_USB_DEFAULT_CONFIG;
 
 //--------------------------------------------------------------------+
 // HCD API
 //--------------------------------------------------------------------+
+bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param)
+{
+  (void) rhport;
+  TU_VERIFY(cfg_id == TUH_CFGID_RPI_PIO_USB_CONFIGURATION);
+  memcpy(&pio_host_cfg, cfg_param, sizeof(pio_usb_configuration_t));
+  return true;
+}
+
 bool hcd_init(uint8_t rhport)
 {
   (void) rhport;
 
   // To run USB SOF interrupt in core1, call this init in core1
-  pio_usb_host_init(&pio_host_config);
+  pio_usb_host_init(&pio_host_cfg);
 
   return true;
 }