Prechádzať zdrojové kódy

Merge pull request #1369 from tannewt/host_string_desc

Add host string descriptor functions
Ha Thach 4 rokov pred
rodič
commit
8e0b8c15ea

+ 27 - 0
examples/host/bare_api/CMakeLists.txt

@@ -0,0 +1,27 @@
+cmake_minimum_required(VERSION 3.5)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
+
+# gets PROJECT name for the example
+family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
+
+project(${PROJECT})
+
+# Checks this example is valid for the family and initializes the project
+family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
+
+add_executable(${PROJECT})
+
+# Example source
+target_sources(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
+        )
+
+# Example include
+target_include_directories(${PROJECT} PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/src
+        )
+
+# Configure compilation flags and libraries for the example... see the corresponding function
+# in hw/bsp/FAMILY/family.cmake for details.
+family_configure_host_example(${PROJECT})

+ 28 - 0
examples/host/bare_api/Makefile

@@ -0,0 +1,28 @@
+include ../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+	src \
+	$(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += \
+	src/main.c
+
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+# TODO: suppress warning caused by host stack
+CFLAGS += -Wno-error=cast-align -Wno-error=null-dereference
+
+# TinyUSB Host Stack source
+SRC_C += \
+	src/class/cdc/cdc_host.c \
+	src/class/hid/hid_host.c \
+	src/class/msc/msc_host.c \
+	src/host/hub.c \
+	src/host/usbh.c \
+	src/host/usbh_control.c \
+	src/portable/ohci/ohci.c \
+	src/portable/nxp/lpc17_40/hcd_lpc17_40.c
+
+include ../../rules.mk

+ 9 - 0
examples/host/bare_api/only.txt

@@ -0,0 +1,9 @@
+mcu:LPC175X_6X
+mcu:LPC177X_8X
+mcu:LPC18XX
+mcu:LPC40XX
+mcu:LPC43XX
+mcu:MIMXRT10XX
+mcu:RP2040
+mcu:MSP432E4
+mcu:RX65X

+ 102 - 0
examples/host/bare_api/src/main.c

@@ -0,0 +1,102 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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 example current worked and tested with following controller
+ * - Sony DualShock 4 [CUH-ZCT2x] VID = 0x054c, PID = 0x09cc
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+void led_blinking_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+  board_init();
+
+  printf("TinyUSB Host HID Controller Example\r\n");
+  printf("Note: Events only displayed for explictly supported controllers\r\n");
+
+  tusb_init();
+
+  while (1)
+  {
+    // tinyusb host task
+    tuh_task();
+    led_blinking_task();
+  }
+
+  return 0;
+}
+
+//--------------------------------------------------------------------+
+// TinyUSB Callbacks
+//--------------------------------------------------------------------+
+
+void print_device_descriptor(uint8_t dev_addr)
+{
+  (void) dev_addr;
+  printf("Device Descriptor:\r\n");
+}
+
+// Invoked when device is mounted (configured)
+void tuh_mount_cb (uint8_t dev_addr)
+{
+  printf("Device attached, address = %d\r\n", dev_addr);
+  print_device_descriptor(dev_addr);
+}
+
+/// Invoked when device is unmounted (bus reset/unplugged)
+void tuh_umount_cb(uint8_t dev_addr)
+{
+  printf("Device removed, address = %d\r\n", dev_addr);
+}
+
+//--------------------------------------------------------------------+
+// Blinking Task
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+  const uint32_t interval_ms = 1000;
+  static uint32_t start_ms = 0;
+
+  static bool led_state = false;
+
+  // Blink every interval ms
+  if ( board_millis() - start_ms < interval_ms) return; // not enough time
+  start_ms += interval_ms;
+
+  board_led_write(led_state);
+  led_state = 1 - led_state; // toggle
+}

+ 94 - 0
examples/host/bare_api/src/tusb_config.h

@@ -0,0 +1,94 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+  #error CFG_TUSB_MCU must be defined
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+  #define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED)
+#else
+  #define CFG_TUSB_RHPORT0_MODE       OPT_MODE_HOST
+#endif
+
+#ifndef CFG_TUSB_OS
+#define CFG_TUSB_OS                 OPT_OS_NONE
+#endif
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG           0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// CONFIGURATION
+//--------------------------------------------------------------------
+
+// Size of buffer to hold descriptors and other data used for enumeration
+#define CFG_TUH_ENUMERATION_BUFSIZE 256
+
+// only hub class is enabled
+#define CFG_TUH_HUB                 1
+
+// max device support (excluding hub device)
+// 1 hub typically has 4 ports
+#define CFG_TUH_DEVICE_MAX          (CFG_TUH_HUB ? 4 : 1)
+
+#define CFG_TUH_ENDPOINT_MAX       8
+
+//------------- HID -------------//
+
+#define CFG_TUH_HID_EP_BUFSIZE      64
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 2 - 1
src/common/tusb_common.h

@@ -38,6 +38,7 @@
 #define TU_MIN(_x, _y)        ( ( (_x) < (_y) ) ? (_x) : (_y) )
 #define TU_MAX(_x, _y)        ( ( (_x) > (_y) ) ? (_x) : (_y) )
 
+#define TU_U16(_high, _low)   ((uint16_t) (((_high) << 8) | (_low)))
 #define TU_U16_HIGH(_u16)     ((uint8_t) (((_u16) >> 8) & 0x00ff))
 #define TU_U16_LOW(_u16)      ((uint8_t) ((_u16)       & 0x00ff))
 #define U16_TO_U8S_BE(_u16)   TU_U16_HIGH(_u16), TU_U16_LOW(_u16)
@@ -349,7 +350,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3
   }
 
   // not found return the key value in hex
-  sprintf(not_found, "0x%08lX", (unsigned long) key);
+  snprintf(not_found, sizeof(not_found), "0x%08lX", (unsigned long) key);
 
   return not_found;
 }

+ 1 - 0
src/device/usbd.c

@@ -407,6 +407,7 @@ bool tud_init (uint8_t rhport)
   if ( tud_inited() ) return true;
 
   TU_LOG2("USBD init\r\n");
+  TU_LOG2_INT(sizeof(usbd_device_t));
 
   tu_varclr(&_usbd_dev);
 

+ 13 - 13
src/host/hcd.h

@@ -35,6 +35,19 @@
  extern "C" {
 #endif
 
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+
+#ifndef CFG_TUH_ENDPOINT_MAX
+  #define CFG_TUH_ENDPOINT_MAX   (CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3)
+//  #ifdef TUP_HCD_ENDPOINT_MAX
+//    #define CFG_TUH_ENDPPOINT_MAX   TUP_HCD_ENDPOINT_MAX
+//  #else
+//    #define
+//  #endif
+#endif
+
  //--------------------------------------------------------------------+
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
@@ -81,17 +94,6 @@ typedef struct
 
 } hcd_event_t;
 
-#if CFG_TUH_ENABLED
-// Max number of endpoints per device
-enum {
-  // TODO better computation
-  HCD_MAX_ENDPOINT = CFG_TUH_DEVICE_MAX*(CFG_TUH_HUB + CFG_TUH_HID*2 + CFG_TUH_MSC*2 + CFG_TUH_CDC*3),
-  HCD_MAX_XFER     = HCD_MAX_ENDPOINT*2,
-};
-
-//#define HCD_MAX_ENDPOINT 16
-//#define HCD_MAX_XFER 16
-
 typedef struct {
   uint8_t rhport;
   uint8_t hub_addr;
@@ -99,8 +101,6 @@ typedef struct {
   uint8_t speed;
 } hcd_devtree_info_t;
 
-#endif
-
 //--------------------------------------------------------------------+
 // Controller API
 //--------------------------------------------------------------------+

+ 1 - 1
src/host/hub.c

@@ -54,7 +54,7 @@ static inline hub_interface_t* get_itf(uint8_t dev_addr)
   return &hub_data[dev_addr-1-CFG_TUH_DEVICE_MAX];
 }
 
-#if CFG_TUSB_DEBUG
+#if CFG_TUSB_DEBUG >= 2
 static char const* const _hub_feature_str[] =
 {
   [HUB_FEATURE_PORT_CONNECTION          ] = "PORT_CONNECTION",

+ 131 - 100
src/host/usbh.c

@@ -37,15 +37,14 @@
 // USBH Configuration
 //--------------------------------------------------------------------+
 
-// TODO remove,update
-#ifndef CFG_TUH_EP_MAX
-#define CFG_TUH_EP_MAX          9
-#endif
-
 #ifndef CFG_TUH_TASK_QUEUE_SZ
 #define CFG_TUH_TASK_QUEUE_SZ   16
 #endif
 
+#ifndef CFG_TUH_INTERFACE_MAX
+#define CFG_TUH_INTERFACE_MAX   8
+#endif
+
 // Debug level of USBD
 #define USBH_DBG_LVL   2
 
@@ -72,7 +71,7 @@ typedef struct
 } usbh_dev0_t;
 
 typedef struct {
-  // port
+  // port, must be same layout as usbh_dev0_t
   uint8_t rhport;
   uint8_t hub_addr;
   uint8_t hub_port;
@@ -87,10 +86,11 @@ typedef struct {
   };
 
   //------------- device descriptor -------------//
+  uint8_t  ep0_size;
+
   uint16_t vid;
   uint16_t pid;
 
-  uint8_t  ep0_size;
   uint8_t  i_manufacturer;
   uint8_t  i_product;
   uint8_t  i_serial;
@@ -101,8 +101,8 @@ typedef struct {
   //------------- device -------------//
   volatile uint8_t state;            // device state, value from enum tusbh_device_state_t
 
-  uint8_t itf2drv[16];               // map interface number to driver (0xff is invalid)
-  uint8_t ep2drv[CFG_TUH_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
+  uint8_t itf2drv[CFG_TUH_INTERFACE_MAX];  // map interface number to driver (0xff is invalid)
+  uint8_t ep2drv[CFG_TUH_ENDPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid )
 
   struct TU_ATTR_PACKED
   {
@@ -111,7 +111,7 @@ typedef struct {
     volatile bool claimed : 1;
 
     // TODO merge ep2drv here, 4-bit should be sufficient
-  }ep_status[CFG_TUH_EP_MAX][2];
+  }ep_status[CFG_TUH_ENDPOINT_MAX][2];
 
   // Mutex for claiming endpoint, only needed when using with preempted RTOS
 #if CFG_TUSB_OS != OPT_OS_NONE
@@ -249,7 +249,6 @@ bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid)
   *vid = *pid = 0;
 
   TU_VERIFY(tuh_mounted(dev_addr));
-
   usbh_device_t const* dev = get_device(dev_addr);
 
   *vid = dev->vid;
@@ -273,6 +272,107 @@ void osal_task_delay(uint32_t msec)
 }
 #endif
 
+//--------------------------------------------------------------------+
+// Descriptors
+//--------------------------------------------------------------------+
+
+bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_STANDARD,
+      .direction = TUSB_DIR_IN
+    },
+    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
+    .wValue   = tu_htole16( TU_U16(type, index) ),
+    .wIndex   = 0,
+    .wLength  = tu_htole16(len)
+  };
+
+  TU_ASSERT( tuh_control_xfer(daddr, &request, buffer, complete_cb) );
+
+  return true;
+}
+
+bool tuh_descriptor_device_get(uint8_t daddr, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  return tuh_descriptor_get(daddr, TUSB_DESC_DEVICE, 0, buffer, len, complete_cb);
+}
+
+bool tuh_descriptor_configuration_get(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  return tuh_descriptor_get(daddr, TUSB_DESC_CONFIGURATION, index, buffer, len, complete_cb);
+}
+
+bool tuh_descriptor_string_get(uint8_t daddr, uint16_t language_id, uint8_t index,
+                               void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_STANDARD,
+      .direction = TUSB_DIR_IN
+    },
+    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
+    .wValue   = tu_htole16( TU_U16(TUSB_DESC_STRING, index) ),
+    .wIndex   = tu_htole16(language_id),
+    .wLength  = tu_htole16(len)
+  };
+
+  TU_ASSERT( tuh_control_xfer(daddr, &request, buffer, complete_cb) );
+  return true;
+}
+
+// Get manufacturer string descriptor
+bool tuh_descriptor_string_manufacturer_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  TU_VERIFY(tuh_mounted(daddr));
+  usbh_device_t const* dev = get_device(daddr);
+  return tuh_descriptor_string_get(daddr, language_id, dev->i_manufacturer, buffer, len, complete_cb);
+}
+
+// Get product string descriptor
+bool tuh_descriptor_string_product_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  TU_VERIFY(tuh_mounted(daddr));
+  usbh_device_t const* dev = get_device(daddr);
+  return tuh_descriptor_string_get(daddr, language_id, dev->i_product, buffer, len, complete_cb);
+}
+
+// Get serial string descriptor
+bool tuh_descriptor_string_serial_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb)
+{
+  TU_VERIFY(tuh_mounted(daddr));
+  usbh_device_t const* dev = get_device(daddr);
+  return tuh_descriptor_string_get(daddr, language_id, dev->i_serial, buffer, len, complete_cb);
+}
+
+bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_control_complete_cb_t complete_cb)
+{
+  TU_LOG2("Set Configuration = %d\r\n", config_num);
+  tusb_control_request_t const request =
+  {
+    .bmRequestType_bit =
+    {
+      .recipient = TUSB_REQ_RCPT_DEVICE,
+      .type      = TUSB_REQ_TYPE_STANDARD,
+      .direction = TUSB_DIR_OUT
+    },
+    .bRequest = TUSB_REQ_SET_CONFIGURATION,
+    .wValue   = tu_htole16(config_num),
+    .wIndex   = 0,
+    .wLength  = 0
+  };
+
+  TU_ASSERT( tuh_control_xfer(daddr, &request, NULL, complete_cb) );
+  return true;
+}
+
 //--------------------------------------------------------------------+
 // CLASS-USBD API (don't require to verify parameters)
 //--------------------------------------------------------------------+
@@ -288,6 +388,7 @@ bool tuh_init(uint8_t rhport)
   if (_usbh_initialized) return _usbh_initialized;
 
   TU_LOG2("USBH init\r\n");
+  TU_LOG2_INT(sizeof(usbh_device_t));
 
   tu_memclr(_usbh_devices, sizeof(_usbh_devices));
   tu_memclr(&_dev0, sizeof(_dev0));
@@ -561,6 +662,7 @@ void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port
       tu_memclr(dev->ep_status, sizeof(dev->ep_status));
 
       dev->state = TUSB_DEVICE_STATE_UNPLUG;
+      dev->configured = false;
     }
   }
 }
@@ -585,7 +687,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
 {
   usbh_device_t* dev = get_device(dev_addr);
 
-  for(itf_num++; itf_num < sizeof(dev->itf2drv); itf_num++)
+  for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
   {
     // continue with next valid interface
     // TODO skip IAD binding interface such as CDCs
@@ -600,7 +702,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
   }
 
   // all interface are configured
-  if (itf_num == sizeof(dev->itf2drv))
+  if (itf_num == CFG_TUH_INTERFACE_MAX)
   {
     // Invoke callback if available
     if (tuh_mount_cb) tuh_mount_cb(dev_addr);
@@ -609,7 +711,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
 
 //--------------------------------------------------------------------+
 // Enumeration Process
-// is a lengthy process with a seires of control transfer to configure
+// is a lengthy process with a series of control transfer to configure
 // newly attached device. Each step is handled by a function in this
 // section
 // TODO due to the shared _usbh_ctrl_buf, we must complete enumerating
@@ -732,23 +834,10 @@ static bool enum_request_addr0_device_desc(void)
   uint8_t const addr0 = 0;
   TU_ASSERT( usbh_edpt_control_open(addr0, 8) );
 
-  //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------//
+  // Get first 8 bytes of device descriptor for Control Endpoint size
   TU_LOG2("Get 8 byte of Device Descriptor\r\n");
-  tusb_control_request_t const request =
-  {
-    .bmRequestType_bit =
-    {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
-    },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = TUSB_DESC_DEVICE << 8,
-    .wIndex   = 0,
-    .wLength  = 8
-  };
-  TU_ASSERT( tuh_control_xfer(addr0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) );
 
+  TU_ASSERT(tuh_descriptor_device_get(addr0, _usbh_ctrl_buf, 8, enum_get_addr0_device_desc_complete));
   return true;
 }
 
@@ -827,7 +916,7 @@ static bool enum_request_set_addr(void)
       .direction = TUSB_DIR_OUT
     },
     .bRequest = TUSB_REQ_SET_ADDRESS,
-    .wValue   = new_addr,
+    .wValue   = tu_htole16(new_addr),
     .wIndex   = 0,
     .wLength  = 0
   };
@@ -856,22 +945,8 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
 
   // Get full device descriptor
   TU_LOG2("Get Device Descriptor\r\n");
-  tusb_control_request_t const new_request =
-  {
-    .bmRequestType_bit =
-    {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
-    },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = TUSB_DESC_DEVICE << 8,
-    .wIndex   = 0,
-    .wLength  = sizeof(tusb_desc_device_t)
-  };
-
-  TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete));
 
+  TU_ASSERT(tuh_descriptor_device_get(new_addr, _usbh_ctrl_buf, sizeof(tusb_desc_device_t), enum_get_device_desc_complete));
   return true;
 }
 
@@ -885,29 +960,16 @@ static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request
 
   dev->vid            = desc_device->idVendor;
   dev->pid            = desc_device->idProduct;
-  dev->i_manufacturer = desc_device->iManufacturer;
-  dev->i_product      = desc_device->iProduct;
-  dev->i_serial       = desc_device->iSerialNumber;
+//  dev->i_manufacturer = desc_device->iManufacturer;
+//  dev->i_product      = desc_device->iProduct;
+//  dev->i_serial       = desc_device->iSerialNumber;
 
 //  if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf);
 
-  TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n");
-  tusb_control_request_t const new_request =
-  {
-    .bmRequestType_bit =
-    {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
-    },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1),
-    .wIndex   = 0,
-    .wLength  = 9
-  };
-
-  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) );
-
+  // Get 9-byte for total length
+  uint8_t const config_idx = CONFIG_NUM - 1;
+  TU_LOG2("Get Configuration[0] Descriptor (9 bytes)\r\n");
+  TU_ASSERT( tuh_descriptor_configuration_get(dev_addr, config_idx, _usbh_ctrl_buf, 9, enum_get_9byte_config_desc_complete) );
   return true;
 }
 
@@ -925,24 +987,9 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r
   TU_ASSERT(total_len <= CFG_TUH_ENUMERATION_BUFSIZE);
 
   // Get full configuration descriptor
-  TU_LOG2("Get Configuration Descriptor\r\n");
-  tusb_control_request_t const new_request =
-  {
-    .bmRequestType_bit =
-    {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_IN
-    },
-    .bRequest = TUSB_REQ_GET_DESCRIPTOR,
-    .wValue   = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1),
-    .wIndex   = 0,
-    .wLength  = total_len
-
-  };
-
-  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_config_desc_complete) );
-
+  uint8_t const config_idx = CONFIG_NUM - 1;
+  TU_LOG2("Get Configuration[0] Descriptor\r\n");
+  TU_ASSERT( tuh_descriptor_configuration_get(dev_addr, config_idx, _usbh_ctrl_buf, total_len, enum_get_config_desc_complete) );
   return true;
 }
 
@@ -955,23 +1002,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request
   // Driver open aren't allowed to make any usb transfer yet
   TU_ASSERT( parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf) );
 
-  TU_LOG2("Set Configuration = %d\r\n", CONFIG_NUM);
-  tusb_control_request_t const new_request =
-  {
-    .bmRequestType_bit =
-    {
-      .recipient = TUSB_REQ_RCPT_DEVICE,
-      .type      = TUSB_REQ_TYPE_STANDARD,
-      .direction = TUSB_DIR_OUT
-    },
-    .bRequest = TUSB_REQ_SET_CONFIGURATION,
-    .wValue   = CONFIG_NUM,
-    .wIndex   = 0,
-    .wLength  = 0
-  };
-
-  TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, enum_set_config_complete) );
-
+  TU_ASSERT( tuh_configuration_set(dev_addr, CONFIG_NUM, enum_set_config_complete) );
   return true;
 }
 

+ 42 - 11
src/host/usbh.h

@@ -38,7 +38,7 @@
 // MACRO CONSTANT TYPEDEF
 //--------------------------------------------------------------------+
 
-typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
+typedef bool (*tuh_control_complete_cb_t)(uint8_t daddr, tusb_control_request_t const * request, xfer_result_t result);
 
 //--------------------------------------------------------------------+
 // APPLICATION API
@@ -57,29 +57,60 @@ void tuh_task(void);
 extern void hcd_int_handler(uint8_t rhport);
 #define tuh_int_handler   hcd_int_handler
 
-bool tuh_vid_pid_get(uint8_t dev_addr, uint16_t* vid, uint16_t* pid);
-tusb_speed_t tuh_speed_get(uint8_t dev_addr);
+bool tuh_vid_pid_get(uint8_t daddr, uint16_t* vid, uint16_t* pid);
+
+tusb_speed_t tuh_speed_get(uint8_t daddr);
 
 // Check if device is connected and configured
-bool tuh_mounted(uint8_t dev_addr);
+bool tuh_mounted(uint8_t daddr);
 
 // Check if device is suspended
-static inline bool tuh_suspended(uint8_t dev_addr)
+TU_ATTR_ALWAYS_INLINE
+static inline bool tuh_suspended(uint8_t daddr)
 {
   // TODO implement suspend & resume on host
-  (void) dev_addr;
+  (void) daddr;
   return false;
 }
 
 // Check if device is ready to communicate with
 TU_ATTR_ALWAYS_INLINE
-static inline bool tuh_ready(uint8_t dev_addr)
+static inline bool tuh_ready(uint8_t daddr)
 {
-  return tuh_mounted(dev_addr) && !tuh_suspended(dev_addr);
+  return tuh_mounted(daddr) && !tuh_suspended(daddr);
 }
 
 // Carry out control transfer
-bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
+bool tuh_control_xfer (uint8_t daddr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb);
+
+// Set Configuration
+// config_num = 0 will un-configure device. Note: config_num = config_descriptor_index + 1
+bool tuh_configuration_set(uint8_t daddr, uint8_t config_num, tuh_control_complete_cb_t complete_cb);
+
+//------------- descriptors -------------//
+
+// Get an descriptor
+bool tuh_descriptor_get(uint8_t daddr, uint8_t type, uint8_t index,
+                        void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+
+// Get device descriptor
+bool tuh_descriptor_device_get(uint8_t daddr, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+
+// Get configuration descriptor
+bool tuh_descriptor_configuration_get(uint8_t daddr, uint8_t index, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+
+// Get string descriptor
+bool tuh_descriptor_string_get(uint8_t daddr, uint16_t language_id, uint8_t index,
+                               void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+
+// Get manufacturer string descriptor
+bool tuh_descriptor_string_manufacturer_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+
+// Get product string descriptor
+bool tuh_descriptor_string_product_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
+
+// Get serial string descriptor
+bool tuh_descriptor_string_serial_get(uint8_t daddr, uint16_t language_id, void* buffer, uint16_t len, tuh_control_complete_cb_t complete_cb);
 
 //--------------------------------------------------------------------+
 // APPLICATION CALLBACK
@@ -87,10 +118,10 @@ 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);
 
 // Invoked when device is mounted (configured)
-TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr);
+TU_ATTR_WEAK void tuh_mount_cb (uint8_t daddr);
 
 /// Invoked when device is unmounted (bus reset/unplugged)
-TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr);
+TU_ATTR_WEAK void tuh_umount_cb(uint8_t daddr);
 
 #ifdef __cplusplus
  }

+ 1 - 0
src/portable/chipidea/ci_hs/hcd_ci_hs.c

@@ -35,6 +35,7 @@
 // INCLUDE
 //--------------------------------------------------------------------+
 #include "common/tusb_common.h"
+#include "host/hcd.h"
 #include "portable/ehci/ehci_api.h"
 #include "ci_hs_type.h"
 

+ 14 - 7
src/portable/ehci/ehci.c

@@ -58,6 +58,9 @@
 
 #define FRAMELIST_SIZE                  (1024 >> FRAMELIST_SIZE_BIT_VALUE)
 
+#define QHD_MAX      (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define QTD_MAX      QHD_MAX
+
 typedef struct
 {
   ehci_link_t period_framelist[FRAMELIST_SIZE];
@@ -73,8 +76,8 @@ typedef struct
     ehci_qtd_t qtd;
   }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
 
-  ehci_qhd_t qhd_pool[HCD_MAX_ENDPOINT];
-  ehci_qtd_t qtd_pool[HCD_MAX_XFER] TU_ATTR_ALIGNED(32);
+  ehci_qhd_t qhd_pool[QHD_MAX];
+  ehci_qtd_t qtd_pool[QTD_MAX] TU_ATTR_ALIGNED(32);
 
   ehci_registers_t* regs;
 
@@ -189,7 +192,11 @@ static void list_remove_qhd_by_addr(ehci_link_t* list_head, uint8_t dev_addr)
       prev = list_next(prev) )
   {
     // TODO check type for ISO iTD and siTD
+    // TODO Suppress cast-align warning
+    #pragma GCC diagnostic push
+    #pragma GCC diagnostic ignored "-Wcast-align"
     ehci_qhd_t* qhd = (ehci_qhd_t*) list_next(prev);
+    #pragma GCC diagnostic pop
     if ( qhd->dev_addr == dev_addr )
     {
       // TODO deactive all TD, wait for QHD to inactive before removal
@@ -474,7 +481,7 @@ static void async_advance_isr(uint8_t rhport)
   (void) rhport;
 
   ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
-  for(uint32_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+  for(uint32_t i = 0; i < QHD_MAX; i++)
   {
     if ( qhd_pool[i].removing )
     {
@@ -542,7 +549,7 @@ static void period_list_xfer_complete_isr(uint8_t hostid, uint32_t interval_ms)
   // TODO abstract max loop guard for period
   while( !next_item.terminate &&
       !(interval_ms > 1 && period_1ms_addr == tu_align32(next_item.address)) &&
-      max_loop < (HCD_MAX_ENDPOINT + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
+      max_loop < (QHD_MAX + EHCI_MAX_ITD + EHCI_MAX_SITD)*CFG_TUH_DEVICE_MAX)
   {
     switch ( next_item.type )
     {
@@ -714,7 +721,7 @@ void hcd_int_handler(uint8_t rhport)
 //------------- queue head helper -------------//
 static inline ehci_qhd_t* qhd_find_free (void)
 {
-  for (uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+  for (uint32_t i=0; i<QHD_MAX; i++)
   {
     if ( !ehci_data.qhd_pool[i].used ) return &ehci_data.qhd_pool[i];
   }
@@ -731,7 +738,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
 {
   ehci_qhd_t* qhd_pool = ehci_data.qhd_pool;
 
-  for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+  for(uint32_t i=0; i<QHD_MAX; i++)
   {
     if ( (qhd_pool[i].dev_addr == dev_addr) &&
           ep_addr == tu_edpt_addr(qhd_pool[i].ep_number, qhd_pool[i].pid) )
@@ -746,7 +753,7 @@ static inline ehci_qhd_t* qhd_get_from_addr(uint8_t dev_addr, uint8_t ep_addr)
 //------------- TD helper -------------//
 static inline ehci_qtd_t* qtd_find_free(void)
 {
-  for (uint32_t i=0; i<HCD_MAX_XFER; i++)
+  for (uint32_t i=0; i<QTD_MAX; i++)
   {
     if ( !ehci_data.qtd_pool[i].used ) return &ehci_data.qtd_pool[i];
   }

+ 2 - 2
src/portable/ehci/ehci.h

@@ -101,8 +101,8 @@ typedef struct
 
 	// Word 2: qTQ Token
 	volatile uint32_t ping_err             : 1  ; ///< For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator
-	volatile uint32_t non_hs_split_state   : 1  ; ///< Used by HC to track the state of slipt transaction
-	volatile uint32_t non_hs_missed_uframe : 1  ; ///< HC misses a complete slip transaction
+	volatile uint32_t non_hs_split_state   : 1  ; ///< Used by HC to track the state of split transaction
+	volatile uint32_t non_hs_missed_uframe : 1  ; ///< HC misses a complete split transaction
 	volatile uint32_t xact_err             : 1  ; ///< Error (Timeout, CRC, Bad PID ... )
 	volatile uint32_t babble_err           : 1  ; ///< Babble detected, also set Halted bit to 1
 	volatile uint32_t buffer_err           : 1  ; ///< Data overrun/underrun error

+ 4 - 4
src/portable/nxp/khci/hcd_khci.c

@@ -125,7 +125,7 @@ typedef struct
     uint16_t            bda[2*2];
   };
   endpoint_state_t endpoint[2];
-  pipe_state_t pipe[HCD_MAX_XFER * 2];
+  pipe_state_t pipe[CFG_TUH_ENDPOINT_MAX * 2];
   uint32_t     in_progress; /* Bitmap. Each bit indicates that a transfer of the corresponding pipe is in progress */
   uint32_t     pending;     /* Bitmap. Each bit indicates that a transfer of the corresponding pipe will be resume the next frame */
   bool         need_reset;  /* The device has not been reset after connection. */
@@ -142,7 +142,7 @@ int find_pipe(uint8_t dev_addr, uint8_t ep_addr)
 {
   /* Find the target pipe */
   int num;
-  for (num = 0; num < HCD_MAX_XFER * 2; ++num) {
+  for (num = 0; num < CFG_TUH_ENDPOINT_MAX * 2; ++num) {
     pipe_state_t *p = &_hcd.pipe[num];
     if ((p->dev_addr == dev_addr) && (p->ep_addr == ep_addr))
       return num;
@@ -463,7 +463,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
   const unsigned ie = NVIC_GetEnableIRQ(USB0_IRQn);
   NVIC_DisableIRQ(USB0_IRQn);
   pipe_state_t *p   = &_hcd.pipe[0];
-  pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER * 2];
+  pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
   for (;p != end; ++p) {
     if (p->dev_addr == dev_addr)
       tu_memclr(p, sizeof(*p));
@@ -511,7 +511,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
   // TU_LOG1("O %u %x\n", dev_addr, ep_addr);
   /* Find a free pipe */
   pipe_state_t *p = &_hcd.pipe[0];
-  pipe_state_t *end = &_hcd.pipe[HCD_MAX_XFER * 2];
+  pipe_state_t *end = &_hcd.pipe[CFG_TUH_ENDPOINT_MAX * 2];
   if (dev_addr || ep_addr) {
     p += 2;
     for (; p < end && (p->dev_addr || p->ep_addr); ++p) ;

+ 3 - 3
src/portable/ohci/ohci.c

@@ -313,7 +313,7 @@ static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr)
 
   ohci_ed_t* ed_pool = ohci_data.ed_pool;
 
-  for(uint32_t i=0; i<HCD_MAX_ENDPOINT; i++)
+  for(uint32_t i=0; i<ED_MAX; i++)
   {
     if ( (ed_pool[i].dev_addr == dev_addr) &&
           ep_addr == tu_edpt_addr(ed_pool[i].ep_number, ed_pool[i].pid == PID_IN) )
@@ -329,7 +329,7 @@ static ohci_ed_t * ed_find_free(void)
 {
   ohci_ed_t* ed_pool = ohci_data.ed_pool;
 
-  for(uint8_t i = 0; i < HCD_MAX_ENDPOINT; i++)
+  for(uint8_t i = 0; i < ED_MAX; i++)
   {
     if ( !ed_pool[i].used ) return &ed_pool[i];
   }
@@ -368,7 +368,7 @@ static void ed_list_remove_by_addr(ohci_ed_t * p_head, uint8_t dev_addr)
 
 static ohci_gtd_t * gtd_find_free(void)
 {
-  for(uint8_t i=0; i < HCD_MAX_XFER; i++)
+  for(uint8_t i=0; i < GTD_MAX; i++)
   {
     if ( !ohci_data.gtd_pool[i].used ) return &ohci_data.gtd_pool[i];
   }

+ 5 - 2
src/portable/ohci/ohci.h

@@ -42,6 +42,9 @@ enum {
   OHCI_MAX_ITD = 4
 };
 
+#define ED_MAX       (CFG_TUH_DEVICE_MAX*CFG_TUH_ENDPOINT_MAX)
+#define GTD_MAX      ED_MAX
+
 //--------------------------------------------------------------------+
 // OHCI Data Structure
 //--------------------------------------------------------------------+
@@ -162,8 +165,8 @@ typedef struct TU_ATTR_ALIGNED(256)
   }control[CFG_TUH_DEVICE_MAX+CFG_TUH_HUB+1];
 
   //  ochi_itd_t itd[OHCI_MAX_ITD]; // itd requires alignment of 32
-  ohci_ed_t ed_pool[HCD_MAX_ENDPOINT];
-  ohci_gtd_t gtd_pool[HCD_MAX_XFER];
+  ohci_ed_t ed_pool[ED_MAX];
+  ohci_gtd_t gtd_pool[GTD_MAX];
 
   volatile uint16_t frame_number_hi;
 

+ 4 - 0
src/portable/raspberrypi/rp2040/rp2040_usb.c

@@ -58,8 +58,12 @@ void rp2040_usb_init(void)
   unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
 
   // Clear any previous state just in case
+  // TODO Suppress warning array-bounds with gcc11
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
   memset(usb_hw, 0, sizeof(*usb_hw));
   memset(usb_dpram, 0, sizeof(*usb_dpram));
+#pragma GCC diagnostic pop
 
   // Mux the controller to the onboard usb phy
   usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;