stm32/usb: Add ability to have 2x VCP interfaces on the one USB device.

This patch adds the configuration MICROPY_HW_USB_ENABLE_CDC2 which enables
a new USB device configuration at runtime: VCP+VCP+MSC.  It will give two
independent VCP interfaces available via pyb.USB_VCP(0) and pyb.USB_VCP(1).
The first one is the usual one and has the REPL on it.  The second one is
available for general use.

This configuration is disabled by default because if the mode is not used
then it takes up about 2200 bytes of RAM.  Also, F4 MCUs can't support this
mode on their USB FS peripheral (eg PYBv1.x) because they don't have enough
endpoints.  The USB HS peripheral of an F4 supports it, as well as both the
USB FS and USB HS peripherals of F7 MCUs.
pull/3784/head
Damien George 2018-05-14 23:44:45 +10:00
rodzic 2e565cc0d4
commit 47ecbbbecb
9 zmienionych plików z 257 dodań i 75 usunięć

Wyświetl plik

@ -63,6 +63,9 @@ typedef struct _usb_device_t {
USBD_HandleTypeDef hUSBDDevice;
usbd_cdc_msc_hid_state_t usbd_cdc_msc_hid_state;
usbd_cdc_itf_t usbd_cdc_itf;
#if MICROPY_HW_USB_ENABLE_CDC2
usbd_cdc_itf_t usbd_cdc2_itf;
#endif
usbd_hid_itf_t usbd_hid_itf;
} usb_device_t;
@ -127,6 +130,9 @@ bool pyb_usb_dev_init(uint16_t vid, uint16_t pid, usb_device_mode_t mode, USBD_H
usbd->pClass = &USBD_CDC_MSC_HID;
usb_dev->usbd_cdc_msc_hid_state.pdev = usbd;
usb_dev->usbd_cdc_msc_hid_state.cdc = &usb_dev->usbd_cdc_itf.base;
#if MICROPY_HW_USB_ENABLE_CDC2
usb_dev->usbd_cdc_msc_hid_state.cdc2 = &usb_dev->usbd_cdc2_itf.base;
#endif
usb_dev->usbd_cdc_msc_hid_state.hid = &usb_dev->usbd_hid_itf.base;
usbd->pClassData = &usb_dev->usbd_cdc_msc_hid_state;
@ -178,6 +184,15 @@ void usb_vcp_send_strn(const char *str, int len) {
}
}
usbd_cdc_itf_t *usb_vcp_get(int idx) {
#if MICROPY_HW_USB_ENABLE_CDC2
if (idx == 1) {
return &usb_device.usbd_cdc2_itf;
}
#endif
return &usb_device.usbd_cdc_itf;
}
/******************************************************************************/
// MicroPython bindings for USB
@ -285,6 +300,13 @@ STATIC mp_obj_t pyb_usb_mode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
pid = USBD_PID_CDC_MSC;
}
mode = USBD_MODE_CDC_MSC;
#if MICROPY_HW_USB_ENABLE_CDC2
} else if (strcmp(mode_str, "VCP+VCP+MSC") == 0) {
if (args[2].u_int == -1) {
pid = USBD_PID_CDC2_MSC;
}
mode = USBD_MODE_CDC2_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;
@ -358,21 +380,33 @@ typedef struct _pyb_usb_vcp_obj_t {
} pyb_usb_vcp_obj_t;
STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc_itf};
#if MICROPY_HW_USB_ENABLE_CDC2
STATIC const pyb_usb_vcp_obj_t pyb_usb_vcp2_obj = {{&pyb_usb_vcp_type}, &usb_device.usbd_cdc2_itf};
#endif
STATIC void pyb_usb_vcp_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
mp_print_str(print, "USB_VCP()");
int id = ((pyb_usb_vcp_obj_t*)self_in)->cdc_itf - &usb_device.usbd_cdc_itf;
mp_printf(print, "USB_VCP(%u)", id);
}
/// \classmethod \constructor()
/// Create a new USB_VCP object.
STATIC mp_obj_t pyb_usb_vcp_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
// check arguments
mp_arg_check_num(n_args, n_kw, 0, 0, false);
mp_arg_check_num(n_args, n_kw, 0, 1, false);
// TODO raise exception if USB is not configured for VCP
// return the USB VCP object
return (mp_obj_t)&pyb_usb_vcp_obj;
int id = (n_args == 0) ? 0 : mp_obj_get_int(args[0]);
if (id == 0) {
return MP_OBJ_FROM_PTR(&pyb_usb_vcp_obj);
#if MICROPY_HW_USB_ENABLE_CDC2
} else if (id == 1) {
return MP_OBJ_FROM_PTR(&pyb_usb_vcp2_obj);
#endif
} else {
mp_raise_ValueError(NULL);
}
}
STATIC mp_obj_t pyb_usb_vcp_setinterrupt(mp_obj_t self_in, mp_obj_t int_chr_in) {

Wyświetl plik

@ -36,6 +36,7 @@
#define USBD_PID_CDC_HID (0x9801)
#define USBD_PID_CDC (0x9802)
#define USBD_PID_MSC (0x9803)
#define USBD_PID_CDC2_MSC (0x9804)
typedef enum {
PYB_USB_STORAGE_MEDIUM_NONE = 0,

Wyświetl plik

@ -69,6 +69,11 @@ uint8_t *usbd_cdc_init(usbd_cdc_state_t *cdc_in) {
cdc->tx_buf_ptr_wait_count = 0;
cdc->tx_need_empty_packet = 0;
cdc->dev_is_connected = 0;
#if MICROPY_HW_USB_ENABLE_CDC2
cdc->attached_to_repl = &cdc->base == cdc->base.usbd->cdc;
#else
cdc->attached_to_repl = 1;
#endif
// Return the buffer to place the first USB OUT packet
return cdc->rx_packet_buf;
@ -143,10 +148,7 @@ int8_t usbd_cdc_control(usbd_cdc_state_t *cdc_in, uint8_t cmd, uint8_t* pbuf, ui
// This function is called to process outgoing data. We hook directly into the
// SOF (start of frame) callback so that it is called exactly at the time it is
// needed (reducing latency), and often enough (increasing bandwidth).
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData;
usbd_cdc_itf_t *cdc = (usbd_cdc_itf_t*)usbd->cdc;
static void usbd_cdc_sof(PCD_HandleTypeDef *hpcd, usbd_cdc_itf_t *cdc) {
if (cdc == NULL || !cdc->dev_is_connected) {
// CDC device is not connected to a host, so we are unable to send any data
return;
@ -199,11 +201,19 @@ void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
// the host waits for all data to arrive (ie, waits for a packet < max packet size).
// To flush a packet of exactly max packet size, we need to send a zero-size packet.
// See eg http://www.cypress.com/?id=4&rID=92719
cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in);
cdc->tx_need_empty_packet = (buffsize > 0 && buffsize % usbd_cdc_max_packet(cdc->base.usbd->pdev) == 0 && cdc->tx_buf_ptr_out_shadow == cdc->tx_buf_ptr_in);
}
}
}
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd) {
usbd_cdc_msc_hid_state_t *usbd = ((USBD_HandleTypeDef*)hpcd->pData)->pClassData;
usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc);
#if MICROPY_HW_USB_ENABLE_CDC2
usbd_cdc_sof(hpcd, (usbd_cdc_itf_t*)usbd->cdc2);
#endif
}
// Data received over USB OUT endpoint is processed here.
// len: number of bytes received into the buffer we passed to USBD_CDC_ReceivePacket
// Returns USBD_OK if all operations are OK else USBD_FAIL
@ -212,7 +222,7 @@ int8_t usbd_cdc_receive(usbd_cdc_state_t *cdc_in, size_t len) {
// copy the incoming data into the circular buffer
for (const uint8_t *src = cdc->rx_packet_buf, *top = cdc->rx_packet_buf + len; src < top; ++src) {
if (mp_interrupt_char != -1 && *src == mp_interrupt_char) {
if (cdc->attached_to_repl && mp_interrupt_char != -1 && *src == mp_interrupt_char) {
pendsv_kbd_intr();
} else {
uint16_t next_put = (cdc->rx_buf_put + 1) & (USBD_CDC_RX_DATA_SIZE - 1);

Wyświetl plik

@ -50,8 +50,12 @@ typedef struct _usbd_cdc_itf_t {
uint8_t tx_need_empty_packet; // used to flush the USB IN endpoint if the last packet was exactly the endpoint packet size
volatile uint8_t dev_is_connected; // indicates if we are connected
uint8_t attached_to_repl; // indicates if interface is connected to REPL
} usbd_cdc_itf_t;
// This is implemented in usb.c
usbd_cdc_itf_t *usb_vcp_get(int idx);
static inline int usbd_cdc_is_connected(usbd_cdc_itf_t *cdc) {
return cdc->dev_is_connected;
}

Wyświetl plik

@ -368,7 +368,11 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
if (pdev->id == USB_PHY_FS_ID) {
// Set LL Driver parameters
pcd_fs_handle.Instance = USB_OTG_FS;
#if MICROPY_HW_USB_ENABLE_CDC2
pcd_fs_handle.Init.dev_endpoints = 6;
#else
pcd_fs_handle.Init.dev_endpoints = 4;
#endif
pcd_fs_handle.Init.use_dedicated_ep1 = 0;
pcd_fs_handle.Init.ep0_mps = 0x40;
pcd_fs_handle.Init.dma_enable = 0;
@ -393,11 +397,22 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
// Initialize LL Driver
HAL_PCD_Init(&pcd_fs_handle);
HAL_PCD_SetRxFiFo(&pcd_fs_handle, 0x80);
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 0x20);
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 0x40);
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 0x20);
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 0x40);
// We have 320 32-bit words in total to use here
#if MICROPY_HW_USB_ENABLE_CDC2
HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128);
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 16); // CDC CMD
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 32); // CDC DATA
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 4, 16); // CDC2 CMD
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 5, 32); // CDC2 DATA
#else
HAL_PCD_SetRxFiFo(&pcd_fs_handle, 128);
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 0, 32); // EP0
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 1, 64); // MSC / HID
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 2, 32); // CDC CMD
HAL_PCD_SetTxFiFo(&pcd_fs_handle, 3, 64); // CDC DATA
#endif
}
#endif
#if MICROPY_HW_USB_HS
@ -406,11 +421,13 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
// Set LL Driver parameters
pcd_hs_handle.Instance = USB_OTG_HS;
pcd_hs_handle.Init.dev_endpoints = 4;
pcd_hs_handle.Init.dev_endpoints = 6;
pcd_hs_handle.Init.use_dedicated_ep1 = 0;
pcd_hs_handle.Init.ep0_mps = 0x40;
pcd_hs_handle.Init.dma_enable = 0;
pcd_hs_handle.Init.low_power_enable = 0;
pcd_hs_handle.Init.lpm_enable = DISABLE;
pcd_hs_handle.Init.battery_charging_enable = DISABLE;
#if defined(STM32F723xx) || defined(STM32F733xx)
pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY;
#else
@ -436,11 +453,14 @@ USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev, int high_speed) {
// Initialize LL Driver
HAL_PCD_Init(&pcd_hs_handle);
HAL_PCD_SetRxFiFo(&pcd_hs_handle, 0x200);
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 0, 0x20);
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 1, 0x100);
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 2, 0x20);
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 0xc0);
// We have 1024 32-bit words in total to use here
HAL_PCD_SetRxFiFo(&pcd_hs_handle, 512);
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, 32); // CDC CMD
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 3, 64); // CDC DATA
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 4, 32); // CDC2 CMD
HAL_PCD_SetTxFiFo(&pcd_hs_handle, 5, 64); // CDC2 DATA
#else // !MICROPY_HW_USB_HS_IN_FS

Wyświetl plik

@ -37,7 +37,7 @@
#include <stdlib.h>
#include <string.h>
#define USBD_MAX_NUM_INTERFACES 1
#define USBD_MAX_NUM_INTERFACES 4
#define USBD_MAX_NUM_CONFIGURATION 1
#define USBD_MAX_STR_DESC_SIZ 0x100
#define USBD_SELF_POWERED 0

Wyświetl plik

@ -20,7 +20,11 @@
// Needed for the CDC+MSC+HID state and should be maximum of all template
// config descriptors defined in usbd_cdc_msc_hid.c
#if MICROPY_HW_USB_ENABLE_CDC2
#define MAX_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58))
#else
#define MAX_TEMPLATE_CONFIG_DESC_SIZE (107)
#endif
// CDC, MSC and HID packet sizes
#define MSC_FS_MAX_PACKET (64)
@ -46,6 +50,7 @@ typedef struct {
uint32_t ctl_packet_buf[CDC_DATA_MAX_PACKET_SIZE / 4]; // Force 32-bit alignment
uint8_t iface_num;
uint8_t in_ep;
uint8_t out_ep;
uint8_t cur_request;
uint8_t cur_length;
volatile uint8_t tx_in_progress;
@ -120,6 +125,9 @@ typedef struct _usbd_cdc_msc_hid_state_t {
__ALIGN_BEGIN uint8_t usbd_config_desc[MAX_TEMPLATE_CONFIG_DESC_SIZE] __ALIGN_END;
usbd_cdc_state_t *cdc;
#if MICROPY_HW_USB_ENABLE_CDC2
usbd_cdc_state_t *cdc2;
#endif
usbd_hid_state_t *hid;
} usbd_cdc_msc_hid_state_t;

Wyświetl plik

@ -34,9 +34,11 @@ typedef enum {
USBD_MODE_CDC = 0x01,
USBD_MODE_MSC = 0x02,
USBD_MODE_HID = 0x04,
USBD_MODE_CDC_MSC = 0x03,
USBD_MODE_CDC_HID = 0x05,
USBD_MODE_MSC_HID = 0x06,
USBD_MODE_CDC2 = 0x08,
USBD_MODE_CDC_MSC = USBD_MODE_CDC | USBD_MODE_MSC,
USBD_MODE_CDC_HID = USBD_MODE_CDC | USBD_MODE_HID,
USBD_MODE_MSC_HID = USBD_MODE_MSC | USBD_MODE_HID,
USBD_MODE_CDC2_MSC = USBD_MODE_CDC | USBD_MODE_MSC | USBD_MODE_CDC2,
USBD_MODE_HIGH_SPEED = 0x80, // or with one of the above
} usb_device_mode_t;

Wyświetl plik

@ -34,6 +34,10 @@
#define CDC_MSC_TEMPLATE_CONFIG_DESC_SIZE (98)
#define CDC_MSC_TEMPLATE_MSC_DESC_OFFSET (9)
#define CDC_MSC_TEMPLATE_CDC_DESC_OFFSET (40)
#define CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE (9 + 23 + (8 + 58) + (8 + 58))
#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 CDC_HID_TEMPLATE_CONFIG_DESC_SIZE (107)
#define CDC_HID_TEMPLATE_HID_DESC_OFFSET (9)
#define CDC_HID_TEMPLATE_CDC_DESC_OFFSET (49)
@ -57,6 +61,7 @@
#define CDC_IFACE_NUM_ALONE (0)
#define CDC_IFACE_NUM_WITH_MSC (1)
#define CDC2_IFACE_NUM_WITH_MSC (3)
#define CDC_IFACE_NUM_WITH_HID (1)
#define MSC_IFACE_NUM_WITH_CDC (0)
#define HID_IFACE_NUM_WITH_CDC (0)
@ -66,6 +71,10 @@
#define CDC_OUT_EP (0x03)
#define CDC_CMD_EP (0x82)
#define CDC2_IN_EP (0x85)
#define CDC2_OUT_EP (0x05)
#define CDC2_CMD_EP (0x84)
#define HID_IN_EP_WITH_CDC (0x81)
#define HID_OUT_EP_WITH_CDC (0x01)
#define HID_IN_EP_WITH_MSC (0x83)
@ -625,6 +634,31 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC;
break;
#if MICROPY_HW_USB_ENABLE_CDC2
case USBD_MODE_CDC2_MSC: {
usbd->usbd_config_desc_size = CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE;
uint8_t *d = usbd->usbd_config_desc;
memcpy(d, cdc_msc_template_config_desc, sizeof(cdc_msc_template_config_desc));
d[2] = LOBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE); // wTotalLength
d[3] = HIBYTE(CDC2_MSC_TEMPLATE_CONFIG_DESC_SIZE);
d[4] = 5; // bNumInterfaces
memcpy(d + 9 + 23 + (8 + 58), d + 9 + 23, 8 + 58);
d += 9 + 23 + (8 + 58);
d[2] = CDC2_IFACE_NUM_WITH_MSC; // bFirstInterface
d[10] = CDC2_IFACE_NUM_WITH_MSC; // bInterfaceNumber
d[26] = CDC2_IFACE_NUM_WITH_MSC + 1; // bDataInterface
d[34] = CDC2_IFACE_NUM_WITH_MSC + 0; // bMasterInterface
d[35] = CDC2_IFACE_NUM_WITH_MSC + 1; // bSlaveInterface
d[38] = CDC2_CMD_EP; // bEndpointAddress
d[45] = CDC2_IFACE_NUM_WITH_MSC + 1; // bInterfaceNumber
d[54] = CDC2_OUT_EP; // bEndpointAddress
d[61] = CDC2_IN_EP; // bEndpointAddress
usbd->cdc->iface_num = CDC_IFACE_NUM_WITH_MSC;
usbd->cdc2->iface_num = CDC2_IFACE_NUM_WITH_MSC;
break;
}
#endif
case USBD_MODE_CDC_HID:
usbd->usbd_config_desc_size = sizeof(cdc_hid_template_config_desc);
memcpy(usbd->usbd_config_desc, cdc_hid_template_config_desc, sizeof(cdc_hid_template_config_desc));
@ -657,8 +691,16 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
if (usbd->usbd_mode & USBD_MODE_CDC) {
usbd->cdc->in_ep = CDC_IN_EP;
usbd->cdc->out_ep = CDC_OUT_EP;
}
#if MICROPY_HW_USB_ENABLE_CDC2
if (usbd->usbd_mode & USBD_MODE_CDC2) {
usbd->cdc2->in_ep = CDC2_IN_EP;
usbd->cdc2->out_ep = CDC2_OUT_EP;
}
#endif
// configure the HID descriptor, if needed
if (usbd->usbd_mode & USBD_MODE_HID) {
uint8_t *hid_desc = usbd->hid->desc;
@ -677,6 +719,26 @@ int USBD_SelectMode(usbd_cdc_msc_hid_state_t *usbd, uint32_t mode, USBD_HID_Mode
return 0;
}
static void usbd_cdc_state_init(USBD_HandleTypeDef *pdev, usbd_cdc_msc_hid_state_t *usbd, usbd_cdc_state_t *cdc, uint8_t cmd_ep) {
int mp = usbd_cdc_max_packet(pdev);
// Open endpoints
USBD_LL_OpenEP(pdev, cdc->in_ep, USBD_EP_TYPE_BULK, mp);
USBD_LL_OpenEP(pdev, cdc->out_ep, USBD_EP_TYPE_BULK, mp);
USBD_LL_OpenEP(pdev, cmd_ep, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
// Init state
cdc->usbd = usbd;
cdc->cur_request = 0xff;
cdc->tx_in_progress = 0;
// Init interface
uint8_t *buf = usbd_cdc_init(cdc);
// Prepare Out endpoint to receive next packet
USBD_LL_PrepareReceive(pdev, cdc->out_ep, buf, mp);
}
static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
#if !USBD_SUPPORT_HS_MODE
if (pdev->dev_speed == USBD_SPEED_HIGH) {
@ -689,39 +751,16 @@ static uint8_t USBD_CDC_MSC_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) {
if (usbd->usbd_mode & USBD_MODE_CDC) {
// CDC VCP component
int mp = usbd_cdc_max_packet(pdev);
// Open EP IN
USBD_LL_OpenEP(pdev,
CDC_IN_EP,
USBD_EP_TYPE_BULK,
mp);
// Open EP OUT
USBD_LL_OpenEP(pdev,
CDC_OUT_EP,
USBD_EP_TYPE_BULK,
mp);
// Open Command IN EP
USBD_LL_OpenEP(pdev,
CDC_CMD_EP,
USBD_EP_TYPE_INTR,
CDC_CMD_PACKET_SIZE);
// Init Xfer states
usbd->cdc->usbd = usbd;
usbd->cdc->cur_request = 0xff;
usbd->cdc->tx_in_progress = 0;
// Init physical Interface components
uint8_t *buf = usbd_cdc_init(usbd->cdc);
// Prepare Out endpoint to receive next packet
USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, buf, mp);
usbd_cdc_state_init(pdev, usbd, usbd->cdc, CDC_CMD_EP);
}
#if MICROPY_HW_USB_ENABLE_CDC2
if (usbd->usbd_mode & USBD_MODE_CDC2) {
// CDC VCP #2 component
usbd_cdc_state_init(pdev, usbd, usbd->cdc2, CDC2_CMD_EP);
}
#endif
if (usbd->usbd_mode & USBD_MODE_MSC) {
// MSC component
@ -785,6 +824,17 @@ static uint8_t USBD_CDC_MSC_HID_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
USBD_LL_CloseEP(pdev, CDC_CMD_EP);
}
#if MICROPY_HW_USB_ENABLE_CDC2
if ((usbd->usbd_mode & USBD_MODE_CDC2) && usbd->cdc2) {
// CDC VCP #2 component
// close endpoints
USBD_LL_CloseEP(pdev, CDC2_IN_EP);
USBD_LL_CloseEP(pdev, CDC2_OUT_EP);
USBD_LL_CloseEP(pdev, CDC2_CMD_EP);
}
#endif
if (usbd->usbd_mode & USBD_MODE_MSC) {
// MSC component
@ -830,11 +880,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
// Work out the recipient of the setup request
uint8_t mode = usbd->usbd_mode;
uint8_t recipient = 0;
usbd_cdc_state_t *cdc;
switch (req->bmRequest & USB_REQ_RECIPIENT_MASK) {
case USB_REQ_RECIPIENT_INTERFACE: {
uint16_t iface = req->wIndex;
if ((mode & USBD_MODE_CDC) && iface == usbd->cdc->iface_num) {
recipient = USBD_MODE_CDC;
cdc = usbd->cdc;
#if MICROPY_HW_USB_ENABLE_CDC2
} else if ((mode & USBD_MODE_CDC2) && iface == usbd->cdc2->iface_num) {
recipient = USBD_MODE_CDC;
cdc = usbd->cdc2;
#endif
} else if ((mode & USBD_MODE_MSC) && iface == MSC_IFACE_NUM_WITH_CDC) {
recipient = USBD_MODE_MSC;
} else if ((mode & USBD_MODE_HID) && iface == usbd->hid->iface_num) {
@ -846,6 +903,12 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
uint8_t ep = req->wIndex & 0x7f;
if ((mode & USBD_MODE_CDC) && (ep == CDC_OUT_EP || ep == (CDC_CMD_EP & 0x7f))) {
recipient = USBD_MODE_CDC;
cdc = usbd->cdc;
#if MICROPY_HW_USB_ENABLE_CDC2
} else if ((mode & USBD_MODE_CDC2) && (ep == CDC2_OUT_EP || ep == (CDC2_CMD_EP & 0x7f))) {
recipient = USBD_MODE_CDC;
cdc = usbd->cdc2;
#endif
} else if ((mode & USBD_MODE_MSC) && ep == MSC_OUT_EP) {
recipient = USBD_MODE_MSC;
} else if ((mode & USBD_MODE_HID) && ep == usbd->hid->out_ep) {
@ -869,18 +932,18 @@ static uint8_t USBD_CDC_MSC_HID_Setup(USBD_HandleTypeDef *pdev, USBD_SetupReqTyp
if (req->wLength) {
if (req->bmRequest & 0x80) {
// device-to-host request
usbd_cdc_control(usbd->cdc, req->bRequest, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength);
USBD_CtlSendData(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength);
usbd_cdc_control(cdc, req->bRequest, (uint8_t*)cdc->ctl_packet_buf, req->wLength);
USBD_CtlSendData(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength);
} else {
// host-to-device request
usbd->cdc->cur_request = req->bRequest;
usbd->cdc->cur_length = req->wLength;
USBD_CtlPrepareRx(pdev, (uint8_t*)usbd->cdc->ctl_packet_buf, req->wLength);
cdc->cur_request = req->bRequest;
cdc->cur_length = req->wLength;
USBD_CtlPrepareRx(pdev, (uint8_t*)cdc->ctl_packet_buf, req->wLength);
}
} else {
// Not a Data request
// Transfer the command to the interface layer
return usbd_cdc_control(usbd->cdc, req->bRequest, NULL, req->wValue);
return usbd_cdc_control(cdc, req->bRequest, NULL, req->wValue);
}
} else if (recipient == USBD_MODE_MSC) {
switch (req->bRequest) {
@ -1002,6 +1065,12 @@ static uint8_t USBD_CDC_MSC_HID_EP0_RxReady(USBD_HandleTypeDef *pdev) {
usbd_cdc_control(usbd->cdc, usbd->cdc->cur_request, (uint8_t*)usbd->cdc->ctl_packet_buf, usbd->cdc->cur_length);
usbd->cdc->cur_request = 0xff;
}
#if MICROPY_HW_USB_ENABLE_CDC2
if (usbd->cdc2 != NULL && usbd->cdc2->cur_request != 0xff) {
usbd_cdc_control(usbd->cdc2, usbd->cdc2->cur_request, (uint8_t*)usbd->cdc2->ctl_packet_buf, usbd->cdc2->cur_length);
usbd->cdc2->cur_request = 0xff;
}
#endif
return USBD_OK;
}
@ -1011,6 +1080,11 @@ static uint8_t USBD_CDC_MSC_HID_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
if ((usbd->usbd_mode & USBD_MODE_CDC) && (epnum == (CDC_IN_EP & 0x7f) || epnum == (CDC_CMD_EP & 0x7f))) {
usbd->cdc->tx_in_progress = 0;
return USBD_OK;
#if MICROPY_HW_USB_ENABLE_CDC2
} else if ((usbd->usbd_mode & USBD_MODE_CDC2) && (epnum == (CDC2_IN_EP & 0x7f) || epnum == (CDC2_CMD_EP & 0x7f))) {
usbd->cdc2->tx_in_progress = 0;
return USBD_OK;
#endif
} else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_IN_EP & 0x7f)) {
MSC_BOT_DataIn(pdev, epnum);
return USBD_OK;
@ -1035,6 +1109,12 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
usbd_cdc_receive(usbd->cdc, len);
return USBD_OK;
#if MICROPY_HW_USB_ENABLE_CDC2
} else if ((usbd->usbd_mode & USBD_MODE_CDC2) && epnum == (CDC2_OUT_EP & 0x7f)) {
size_t len = USBD_LL_GetRxDataSize(pdev, epnum);
usbd_cdc_receive(usbd->cdc2, len);
return USBD_OK;
#endif
} else if ((usbd->usbd_mode & USBD_MODE_MSC) && epnum == (MSC_OUT_EP & 0x7f)) {
MSC_BOT_DataOut(pdev, epnum);
return USBD_OK;
@ -1046,11 +1126,31 @@ static uint8_t USBD_CDC_MSC_HID_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
return USBD_OK;
}
#if USBD_SUPPORT_HS_MODE
static void usbd_cdc_desc_config_max_packet(USBD_HandleTypeDef *pdev, uint8_t *cdc_desc) {
uint32_t mp = usbd_cdc_max_packet(pdev);
cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp);
cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp);
cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp);
cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp);
uint8_t interval; // polling interval in frames of 1ms
if (pdev->dev_speed == USBD_SPEED_HIGH) {
interval = 0x09;
} else {
interval = 0x20;
}
cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval;
}
#endif
static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *length) {
usbd_cdc_msc_hid_state_t *usbd = pdev->pClassData;
#if USBD_SUPPORT_HS_MODE
uint8_t *cdc_desc = NULL;
#if MICROPY_HW_USB_ENABLE_CDC2
uint8_t *cdc2_desc = NULL;
#endif
uint8_t *msc_desc = NULL;
switch (usbd->usbd_mode) {
case USBD_MODE_MSC:
@ -1062,6 +1162,14 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *
msc_desc = usbd->usbd_config_desc + CDC_MSC_TEMPLATE_MSC_DESC_OFFSET;
break;
#if MICROPY_HW_USB_ENABLE_CDC2
case USBD_MODE_CDC2_MSC:
cdc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC_DESC_OFFSET;
cdc2_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_CDC2_DESC_OFFSET;
msc_desc = usbd->usbd_config_desc + CDC2_MSC_TEMPLATE_MSC_DESC_OFFSET;
break;
#endif
case USBD_MODE_CDC_HID:
cdc_desc = usbd->usbd_config_desc + CDC_HID_TEMPLATE_CDC_DESC_OFFSET;
break;
@ -1073,20 +1181,15 @@ static uint8_t *USBD_CDC_MSC_HID_GetCfgDesc(USBD_HandleTypeDef *pdev, uint16_t *
// configure CDC descriptors, if needed
if (cdc_desc != NULL) {
uint32_t mp = usbd_cdc_max_packet(pdev);
cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_LO] = LOBYTE(mp);
cdc_desc[CDC_DESC_OFFSET_OUT_MAX_PACKET_HI] = HIBYTE(mp);
cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_LO] = LOBYTE(mp);
cdc_desc[CDC_DESC_OFFSET_IN_MAX_PACKET_HI] = HIBYTE(mp);
uint8_t interval; // polling interval in frames of 1ms
if (pdev->dev_speed == USBD_SPEED_HIGH) {
interval = 0x09;
} else {
interval = 0x20;
}
cdc_desc[CDC_DESC_OFFSET_INTR_INTERVAL] = interval;
usbd_cdc_desc_config_max_packet(pdev, cdc_desc);
}
#if MICROPY_HW_USB_ENABLE_CDC2
if (cdc2_desc != NULL) {
usbd_cdc_desc_config_max_packet(pdev, cdc2_desc);
}
#endif
if (msc_desc != NULL) {
uint32_t mp = usbd_msc_max_packet(pdev);
msc_desc[13] = LOBYTE(mp);
@ -1135,7 +1238,7 @@ uint8_t USBD_CDC_ReceivePacket(usbd_cdc_state_t *cdc, uint8_t *buf) {
#endif
// Prepare Out endpoint to receive next packet
USBD_LL_PrepareReceive(cdc->usbd->pdev, CDC_OUT_EP, buf, usbd_cdc_max_packet(cdc->usbd->pdev));
USBD_LL_PrepareReceive(cdc->usbd->pdev, cdc->out_ep, buf, usbd_cdc_max_packet(cdc->usbd->pdev));
return USBD_OK;
}