From ff91b05cfa8154d1a4d098423dfa95d14ade4271 Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Thu, 30 May 2019 17:16:15 +1000
Subject: [PATCH] stm32/usb: Support up to 3 VCP interfaces on USB device
 peripheral.

To enable define MICROPY_HW_USB_CDC_NUM to 3.
---
 ports/stm32/usb.c                             | 15 ++++++
 ports/stm32/usb.h                             |  2 +
 ports/stm32/usbd_conf.c                       | 12 +++++
 ports/stm32/usbd_conf.h                       |  2 +-
 .../stm32/usbdev/class/inc/usbd_cdc_msc_hid.h |  5 +-
 .../usbdev/class/inc/usbd_cdc_msc_hid0.h      |  2 +
 .../stm32/usbdev/class/src/usbd_cdc_msc_hid.c | 49 +++++++++++++++++++
 7 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index c9c22d5d2..ace090f80 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -309,6 +309,18 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
         }
         mode = USBD_MODE_CDC2_MSC;
     #endif
+    #if MICROPY_HW_USB_CDC_NUM >= 3
+    } else if (strcmp(mode_str, "3xVCP") == 0) {
+        if (args[2].u_int == -1) {
+            pid = USBD_PID_CDC3;
+        }
+        mode = USBD_MODE_CDC3;
+    } else if (strcmp(mode_str, "3xVCP+MSC") == 0) {
+        if (args[2].u_int == -1) {
+            pid = USBD_PID_CDC3_MSC;
+        }
+        mode = USBD_MODE_CDC3_MSC;
+    #endif
     } else if (strcmp(mode_str, "CDC+HID") == 0 || strcmp(mode_str, "VCP+HID") == 0) {
         if (args[2].u_int == -1) {
             pid = USBD_PID_CDC_HID;
@@ -386,6 +398,9 @@ const pyb_usb_vcp_obj_t pyb_usb_vcp_obj[MICROPY_HW_USB_CDC_NUM] = {
     #if MICROPY_HW_USB_CDC_NUM >= 2
     {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf[1]},
     #endif
+    #if MICROPY_HW_USB_CDC_NUM >= 3
+    {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf[2]},
+    #endif
 };
 
 STATIC void pyb_usb_vcp_init0(void) {
diff --git a/ports/stm32/usb.h b/ports/stm32/usb.h
index 6678e1e17..0aa50f9e7 100644
--- a/ports/stm32/usb.h
+++ b/ports/stm32/usb.h
@@ -38,6 +38,8 @@
 #define USBD_PID_MSC     (0x9803)
 #define USBD_PID_CDC2_MSC (0x9804)
 #define USBD_PID_CDC2    (0x9805)
+#define USBD_PID_CDC3    (0x9806)
+#define USBD_PID_CDC3_MSC (0x9807)
 
 typedef enum {
     PYB_USB_STORAGE_MEDIUM_NONE = 0,
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
index c2e86ccb5..ed99700e9 100644
--- a/ports/stm32/usbd_conf.c
+++ b/ports/stm32/usbd_conf.c
@@ -385,7 +385,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
     if (pdev->id == USB_PHY_HS_ID) {
         // Set LL Driver parameters
         pcd_hs_handle.Instance = USB_OTG_HS;
+        #if MICROPY_HW_USB_CDC_NUM == 3
+        pcd_hs_handle.Init.dev_endpoints = 8;
+        #else
         pcd_hs_handle.Init.dev_endpoints = 6;
+        #endif
         pcd_hs_handle.Init.use_dedicated_ep1 = 0;
         pcd_hs_handle.Init.ep0_mps = 0x40;
         pcd_hs_handle.Init.dma_enable = 0;
@@ -431,13 +435,21 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
         HAL_PCD_Init(&pcd_hs_handle);
 
         // We have 1024 32-bit words in total to use here
+        #if MICROPY_HW_USB_CDC_NUM == 3
+        HAL_PCD_SetRxFiFo(&pcd_hs_handle, 328);
+        #else
         HAL_PCD_SetRxFiFo(&pcd_hs_handle, 464);
+        #endif
         HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 32); // EP0
         HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 256); // MSC / HID
         HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 8); // CDC CMD
         HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 128); // CDC DATA
         HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 8); // CDC2 CMD
         HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 128); // CDC2 DATA
+        #if MICROPY_HW_USB_CDC_NUM == 3
+        HAL_PCD_SetTxFiFo(&pcd_hs_handle, 6, 8); // CDC3 CMD
+        HAL_PCD_SetTxFiFo(&pcd_hs_handle, 7, 128); // CDC3 DATA
+        #endif
     }
     #endif  // MICROPY_HW_USB_HS
 
diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h
index c5faf6c8c..639b54d9f 100644
--- a/ports/stm32/usbd_conf.h
+++ b/ports/stm32/usbd_conf.h
@@ -39,7 +39,7 @@
 
 #include "py/mpconfig.h"
 
-#define USBD_MAX_NUM_INTERFACES               4
+#define USBD_MAX_NUM_INTERFACES               5
 #define USBD_MAX_NUM_CONFIGURATION            1
 #define USBD_MAX_STR_DESC_SIZ                 0x100
 #if MICROPY_HW_USB_SELF_POWERED
diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
index f20485a7c..d4a218a4a 100644
--- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid.h
@@ -19,7 +19,10 @@
 #endif
 
 // Should be maximum of possible config descriptors that might be configured
-#if MICROPY_HW_USB_CDC_NUM == 2
+#if MICROPY_HW_USB_CDC_NUM == 3
+// Maximum is MSC+CDC+CDC+CDC
+#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58) + (8 + 58))
+#elif MICROPY_HW_USB_CDC_NUM == 2
 // Maximum is MSC+CDC+CDC
 #define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58))
 #else
diff --git a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
index 1cb879180..63fe8ecef 100644
--- a/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
+++ b/ports/stm32/usbdev/class/inc/usbd_cdc_msc_hid0.h
@@ -39,9 +39,11 @@
 // Convenience macros for supported mode combinations
 #define USBD_MODE_CDC       (USBD_MODE_IFACE_CDC(0))
 #define USBD_MODE_CDC2      (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1))
+#define USBD_MODE_CDC3      (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_CDC(2))
 #define USBD_MODE_CDC_HID   (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_HID)
 #define USBD_MODE_CDC_MSC   (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_MSC)
 #define USBD_MODE_CDC2_MSC  (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_MSC)
+#define USBD_MODE_CDC3_MSC  (USBD_MODE_IFACE_CDC(0) | USBD_MODE_IFACE_CDC(1) | USBD_MODE_IFACE_CDC(2) | USBD_MODE_IFACE_MSC)
 #define USBD_MODE_HID       (USBD_MODE_IFACE_HID)
 #define USBD_MODE_MSC       (USBD_MODE_IFACE_MSC)
 #define USBD_MODE_MSC_HID   (USBD_MODE_IFACE_MSC | USBD_MODE_IFACE_HID)
diff --git a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
index bfb5d3058..d982fe8e6 100644
--- a/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
+++ b/ports/stm32/usbdev/class/src/usbd_cdc_msc_hid.c
@@ -43,6 +43,13 @@
 #define CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET (9)
 #define CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8)
 #define CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8)
+#define CDC3_TEMPLATE_CDC_DESC_OFFSET (9 + 8)
+#define CDC3_TEMPLATE_CDC2_DESC_OFFSET (9 + (8 + 58) + 8)
+#define CDC3_TEMPLATE_CDC3_DESC_OFFSET (9 + (8 + 58) + (8 + 58) + 8)
+#define CDC3_MSC_TEMPLATE_MSC_DESC_OFFSET (9)
+#define CDC3_MSC_TEMPLATE_CDC_DESC_OFFSET (9 + 23 + 8)
+#define CDC3_MSC_TEMPLATE_CDC2_DESC_OFFSET (9 + 23 + (8 + 58) + 8)
+#define CDC3_MSC_TEMPLATE_CDC3_DESC_OFFSET (9 + 23 + (8 + 58) + (8 + 58) + 8)
 #define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49)
 #define CDC_TEMPLATE_CDC_DESC_OFFSET (9)
 #define CDC_DESC_OFFSET_INTR_INTERVAL (34)
@@ -65,7 +72,9 @@
 #define CDC_IFACE_NUM_ALONE (0)
 #define CDC_IFACE_NUM_WITH_MSC (1)
 #define CDC2_IFACE_NUM_WITH_CDC (2)
+#define CDC3_IFACE_NUM_WITH_CDC (4)
 #define CDC2_IFACE_NUM_WITH_MSC (3)
+#define CDC3_IFACE_NUM_WITH_MSC (5)
 #define CDC_IFACE_NUM_WITH_HID (1)
 #define MSC_IFACE_NUM_WITH_CDC (0)
 #define HID_IFACE_NUM_WITH_CDC (0)
@@ -493,6 +502,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
         }
         #endif
 
+        #if MICROPY_HW_USB_CDC_NUM >= 3
+        case USBD_MODE_CDC3: {
+            n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_ALONE);
+            n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_CDC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1));
+            n += make_cdc_desc_ep(d + n, 1, CDC3_IFACE_NUM_WITH_CDC, CDC_CMD_EP(2), CDC_OUT_EP(2), CDC_IN_EP(2));
+            usbd->cdc[0]->iface_num = CDC_IFACE_NUM_ALONE;
+            usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_CDC;
+            usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_CDC;
+            num_itf = 6;
+            break;
+        }
+
+        case USBD_MODE_CDC3_MSC: {
+            n += make_msc_desc(d + n);
+            n += make_cdc_desc(d + n, 1, CDC_IFACE_NUM_WITH_MSC);
+            n += make_cdc_desc_ep(d + n, 1, CDC2_IFACE_NUM_WITH_MSC, CDC_CMD_EP(1), CDC_OUT_EP(1), CDC_IN_EP(1));
+            n += make_cdc_desc_ep(d + n, 1, CDC3_IFACE_NUM_WITH_MSC, CDC_CMD_EP(2), CDC_OUT_EP(2), CDC_IN_EP(2));
+            usbd->cdc[0]->iface_num = CDC_IFACE_NUM_WITH_MSC;
+            usbd->cdc[1]->iface_num = CDC2_IFACE_NUM_WITH_MSC;
+            usbd->cdc[2]->iface_num = CDC3_IFACE_NUM_WITH_MSC;
+            num_itf = 7;
+            break;
+        }
+        #endif
+
         case USBD_MODE_CDC_HID:
             usbd->hid->desc = d + n;
             n += make_hid_desc(d + n, hid_info);
@@ -973,6 +1007,21 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *
             break;
         #endif
 
+        #if MICROPY_HW_USB_CDC_NUM >= 3
+        case USBD_MODE_CDC3:
+            cdc_desc[0] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC_DESC_OFFSET;
+            cdc_desc[1] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC2_DESC_OFFSET;
+            cdc_desc[2] = usbd->usbd_config_desc + CDC3_TEMPLATE_CDC3_DESC_OFFSET;
+            break;
+
+        case USBD_MODE_CDC3_MSC:
+            cdc_desc[0] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC_DESC_OFFSET;
+            cdc_desc[1] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC2_DESC_OFFSET;
+            cdc_desc[2] = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_CDC3_DESC_OFFSET;
+            msc_desc = usbd->usbd_config_desc + CDC3_MSC_TEMPLATE_MSC_DESC_OFFSET;
+            break;
+        #endif
+
         case USBD_MODE_CDC_HID:
             cdc_desc[0] = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET;
             break;
-- 
GitLab