|
|
|
//
|
|
|
|
// Created by MightyPork on 2017/11/07.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "platform.h"
|
|
|
|
#include "framework/system_settings.h"
|
|
|
|
#include "usbd_desc.h"
|
|
|
|
#include "tasks/task_main.h"
|
|
|
|
#include "usbd_msc.h"
|
|
|
|
#include "usbd_cdc.h"
|
|
|
|
#include "usbd_msc_cdc.h"
|
|
|
|
|
|
|
|
#define USBD_MSC_CDC_CONFIG_DESC_SIZ 98
|
|
|
|
/* USB Mass storage device Configuration Descriptor */
|
|
|
|
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
|
|
|
|
|
|
|
|
// NOTE: This must NOT be in flash, otherwise the driver / peripheral crashes
|
|
|
|
__ALIGN_BEGIN uint8_t USBD_MSC_CDC_CfgFSDesc[USBD_MSC_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
|
|
|
|
{
|
|
|
|
/*0*/ 0x09, /* bLength: Configuation Descriptor size */
|
|
|
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
|
|
LOBYTE(USBD_MSC_CDC_CONFIG_DESC_SIZ), // TODO
|
|
|
|
HIBYTE(USBD_MSC_CDC_CONFIG_DESC_SIZ),
|
|
|
|
3, /* bNumInterfaces - 1 MSC + 2 composite CDC ACM */
|
|
|
|
0x01, /* bConfigurationValue: */
|
|
|
|
0, /* iConfiguration: - string descriptor */
|
|
|
|
0xC0, /* bmAttributes: - self powered */
|
|
|
|
150, /* MaxPower 300 mA */
|
|
|
|
|
|
|
|
/******************** Mass Storage interface ********************/
|
|
|
|
/*9*/ 0x09, /* bLength: Interface Descriptor size */
|
|
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
|
|
|
0x00, /* bInterfaceNumber: Number of Interface */
|
|
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
|
|
0x02, /* bNumEndpoints*/
|
|
|
|
0x08, /* bInterfaceClass: MSC Class */ // #14
|
|
|
|
0x06, /* bInterfaceSubClass : SCSI transparent*/
|
|
|
|
0x50, /* nInterfaceProtocol */
|
|
|
|
0x04, /* iInterface: String descriptor */
|
|
|
|
|
|
|
|
/******************** Mass Storage Endpoints ********************/
|
|
|
|
/*18*/ 0x07, /*Endpoint descriptor length = 7*/
|
|
|
|
0x05, /*Endpoint descriptor type */
|
|
|
|
MSC_EPIN_ADDR, /*Endpoint address (IN, address 1) */
|
|
|
|
0x02, /*Bulk endpoint type */
|
|
|
|
LOBYTE(MSC_MAX_FS_PACKET),
|
|
|
|
HIBYTE(MSC_MAX_FS_PACKET),
|
|
|
|
0x00, /*Polling interval in milliseconds */
|
|
|
|
|
|
|
|
/*25*/ 0x07, /*Endpoint descriptor length = 7 */
|
|
|
|
0x05, /*Endpoint descriptor type */
|
|
|
|
MSC_EPOUT_ADDR, /*Endpoint address (OUT, address 1) */
|
|
|
|
0x02, /*Bulk endpoint type */
|
|
|
|
LOBYTE(MSC_MAX_FS_PACKET),
|
|
|
|
HIBYTE(MSC_MAX_FS_PACKET),
|
|
|
|
0x00, /*Polling interval in milliseconds*/
|
|
|
|
|
|
|
|
/********************** IFACE ASSOC *************************/
|
|
|
|
/*32*/ 0x08, /* bLength */
|
|
|
|
USB_DESC_TYPE_IFACE_ASSOCIATION, /* bDescriptorType */
|
|
|
|
0x01, /* bFirstInterface */
|
|
|
|
0x02, /* bInterfaceCount */
|
|
|
|
0x02, /* bFunctionClass */ // #36
|
|
|
|
0x02, /* bFunctionSubClass (ACM) */
|
|
|
|
0x01, /* bFunctionProtocol (AT-COMMANDS) */
|
|
|
|
0x05, /* iFunction: string descriptor */
|
|
|
|
|
|
|
|
/********************** ACM interface **********************/
|
|
|
|
/*40*/ 0x09, /* bLength: Interface Descriptor size */
|
|
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
|
|
0x01, /* bInterfaceNumber: Number of Interface */
|
|
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
|
|
0x01, /* bNumEndpoints: One endpoints used */
|
|
|
|
0x02, /* bInterfaceClass: Communication Interface Class */ // #45
|
|
|
|
0x02, /* bInterfaceSubClass: Abstract Control Model */
|
|
|
|
0x01, /* bInterfaceProtocol: Common AT commands */
|
|
|
|
0x05, /* iInterface: string descriptor */
|
|
|
|
|
|
|
|
/**************** Header Functional Descriptor ***************/
|
|
|
|
/*49*/ 0x05, /* bLength: Endpoint Descriptor size */
|
|
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
|
|
0x00, /* bDescriptorSubtype: Header Func Desc */
|
|
|
|
0x10, /* bcdCDC: spec release number */
|
|
|
|
0x01,
|
|
|
|
|
|
|
|
/*********** Call Management Functional Descriptor **********/
|
|
|
|
/*54*/ 0x05, /* bFunctionLength */
|
|
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
|
|
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
|
|
|
0x00, /* bmCapabilities: D0+D1 */
|
|
|
|
0x02, /* bDataInterface: 2 */
|
|
|
|
|
|
|
|
/*************** ACM Functional Descriptor ***************/
|
|
|
|
/*59*/ 0x04, /* bFunctionLength */
|
|
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
|
|
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
|
|
|
|
0x06, /* bmCapabilities XXX was:0x02? */
|
|
|
|
|
|
|
|
/************* Union Functional Descriptor **************/
|
|
|
|
/*63*/ 0x05, /* bFunctionLength */
|
|
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
|
|
0x06, /* bDescriptorSubtype: Union func desc */
|
|
|
|
0x01, /* bMasterInterface: Communication class interface */
|
|
|
|
0x02, /* bSlaveInterface0: Data Class Interface */
|
|
|
|
|
|
|
|
/******************** CDC Endpoints ********************/
|
|
|
|
|
|
|
|
/// Command endpoint
|
|
|
|
/*68*/ 0x07, /* bLength: Endpoint Descriptor size */
|
|
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
|
|
CDC_CMD_EP, /* bEndpointAddress */
|
|
|
|
0x03, /* bmAttributes: Interrupt */
|
|
|
|
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: TODO: 2?*/
|
|
|
|
HIBYTE(CDC_CMD_PACKET_SIZE),
|
|
|
|
0xFF, /* bInterval: TODO was 0x10?*/
|
|
|
|
|
|
|
|
/********** CDC Data Class Interface Descriptor ***********/
|
|
|
|
/*75*/ 0x09, /* bLength: Endpoint Descriptor size */
|
|
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
|
|
|
0x02, /* bInterfaceNumber: Number of Interface */
|
|
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
|
|
0x02, /* bNumEndpoints: Two endpoints used */
|
|
|
|
0x0A, /* bInterfaceClass: CDC */ // #80
|
|
|
|
0x00, /* bInterfaceSubClass: */
|
|
|
|
0x00, /* bInterfaceProtocol: */
|
|
|
|
0x06, /* iInterface: TODO: string descriptor */
|
|
|
|
|
|
|
|
/// Endpoint OUT Descriptor
|
|
|
|
/*84*/ 0x07, /* bLength: Endpoint Descriptor size */
|
|
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
|
|
CDC_OUT_EP, /* bEndpointAddress */
|
|
|
|
0x02, /* bmAttributes: Bulk */
|
|
|
|
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: TODO 8? */
|
|
|
|
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
|
|
|
0x00, /* bInterval: ignore for Bulk transfer */
|
|
|
|
|
|
|
|
/// Endpoint IN Descriptor
|
|
|
|
/*91*/ 0x07, /* bLength: Endpoint Descriptor size */
|
|
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
|
|
CDC_IN_EP, /* bEndpointAddress */
|
|
|
|
0x02, /* bmAttributes: Bulk */
|
|
|
|
LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: TODO 16? */
|
|
|
|
HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
|
|
|
|
0x00 /* bInterval: ignore for Bulk transfer */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* USB Standard Device Descriptor */
|
|
|
|
__ALIGN_BEGIN uint8_t USBD_MSC_CDC_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
|
|
{
|
|
|
|
USB_LEN_DEV_QUALIFIER_DESC,
|
|
|
|
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
|
|
|
0x00,
|
|
|
|
0x02,
|
|
|
|
0x00,
|
|
|
|
0x00,
|
|
|
|
0x00,
|
|
|
|
MSC_MAX_FS_PACKET,
|
|
|
|
0x01,
|
|
|
|
0x00,
|
|
|
|
};
|
|
|
|
|
|
|
|
static uint8_t USBD_MSC_CDC_Init(struct _USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
|
|
{
|
|
|
|
// this is not correct, but will work if neither returns BUSY (which they don't)
|
|
|
|
uint8_t ret = 0;
|
|
|
|
ret |= USBD_MSC_Init(pdev, cfgidx);
|
|
|
|
ret |= USBD_CDC_Init(pdev, cfgidx);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t USBD_MSC_CDC_DeInit(struct _USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
|
|
{
|
|
|
|
uint8_t ret = 0;
|
|
|
|
ret |= USBD_MSC_DeInit(pdev, cfgidx);
|
|
|
|
ret |= USBD_CDC_DeInit(pdev, cfgidx);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Control Endpoints*/
|
|
|
|
static uint8_t USBD_MSC_CDC_Setup(struct _USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
|
|
|
|
{
|
|
|
|
static uint8_t interface_bit;
|
|
|
|
|
|
|
|
// handle common
|
|
|
|
switch (req->bmRequest & USB_REQ_TYPE_MASK) {
|
|
|
|
case USB_REQ_TYPE_STANDARD:
|
|
|
|
switch (req->bRequest) {
|
|
|
|
// those don't really do anything useful, but each class implements
|
|
|
|
// them and it would send the data twice.
|
|
|
|
case USB_REQ_GET_INTERFACE :
|
|
|
|
USBD_CtlSendData(pdev, &interface_bit, 1);
|
|
|
|
return USBD_OK;
|
|
|
|
|
|
|
|
case USB_REQ_SET_INTERFACE :
|
|
|
|
interface_bit = (uint8_t) (req->wValue);
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// class specific, or Interface -> Clear Feature
|
|
|
|
USBD_MSC_Setup(pdev, req);
|
|
|
|
USBD_CDC_Setup(pdev, req);
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static uint8_t USBD_MSC_CDC_EP0_TxSent(struct _USBD_HandleTypeDef *pdev)
|
|
|
|
{
|
|
|
|
// not handled by either
|
|
|
|
xTaskNotify(tskUsbEventHandle, USBEVT_FLAG_EP0_TX_SENT, eSetBits);
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static uint8_t USBD_MSC_CDC_EP0_RxReady(struct _USBD_HandleTypeDef *pdev)
|
|
|
|
{
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
xTaskNotifyFromISR(tskMainHandle, USBEVT_FLAG_EP0_RX_RDY, eSetBits, &xHigherPriorityTaskWoken);
|
|
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
|
|
//USBD_CDC_EP0_RxReady(pdev);
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Class Specific Endpoints*/
|
|
|
|
static uint8_t USBD_MSC_CDC_DataIn(struct _USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
|
|
{
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
xTaskNotifyFromISR(tskMainHandle, USBEVT_FLAG_EPx_IN(epnum), eSetBits, &xHigherPriorityTaskWoken);
|
|
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
|
|
// if (epnum == MSC_EPIN_ADDR||epnum==MSC_EPOUT_ADDR) USBD_MSC_DataIn(pdev, epnum);
|
|
|
|
// else if (epnum == CDC_IN_EP||epnum == CDC_CMD_EP) USBD_CDC_DataIn(pdev, epnum);
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t USBD_MSC_CDC_DataOut(struct _USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
|
|
{
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
xTaskNotifyFromISR(tskMainHandle, USBEVT_FLAG_EPx_OUT(epnum), eSetBits, &xHigherPriorityTaskWoken);
|
|
|
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
|
|
// if (epnum == MSC_EPIN_ADDR||epnum == MSC_EPOUT_ADDR) USBD_MSC_DataOut(pdev, epnum);
|
|
|
|
// else if (epnum == CDC_OUT_EP||epnum == CDC_CMD_EP) USBD_CDC_DataOut(pdev, epnum);
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static uint8_t USBD_MSC_CDC_SOF(struct _USBD_HandleTypeDef *pdev)
|
|
|
|
{
|
|
|
|
// not handled by either
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t USBD_MSC_CDC_IsoINIncomplete(struct _USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
|
|
{
|
|
|
|
// not handled by either
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t USBD_MSC_CDC_IsoOUTIncomplete(struct _USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
|
|
{
|
|
|
|
// not handled by either
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t *USBD_MSC_CDC_GetUsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
|
|
|
|
{
|
|
|
|
// not handled by either
|
|
|
|
return USBD_OK;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
uint8_t *USBD_MSC_CDC_GetHSCfgDesc (uint16_t *length)
|
|
|
|
{
|
|
|
|
// *length = sizeof (USBD_MSC_CDC_CfgHSDesc);
|
|
|
|
// return USBD_MSC_CDC_CfgHSDesc;
|
|
|
|
*length = sizeof (USBD_MSC_CDC_CfgFSDesc);
|
|
|
|
return USBD_MSC_CDC_CfgFSDesc;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t *USBD_MSC_CDC_GetFSCfgDesc (uint16_t *length)
|
|
|
|
{
|
|
|
|
*length = sizeof (USBD_MSC_CDC_CfgFSDesc);
|
|
|
|
|
|
|
|
// Optionally hide CDC-ACM by setting its class to Vendor Specific
|
|
|
|
bool cdc_visible = SystemSettings.visible_vcom;
|
|
|
|
USBD_MSC_CDC_CfgFSDesc[36] = (uint8_t) (cdc_visible ? 0x02 : 0xFF);
|
|
|
|
USBD_MSC_CDC_CfgFSDesc[45] = (uint8_t) (cdc_visible ? 0x02 : 0xFF);
|
|
|
|
USBD_MSC_CDC_CfgFSDesc[80] = (uint8_t) (cdc_visible ? 0x0A : 0xFF);
|
|
|
|
|
|
|
|
// Optionally hide settings (if lock jumper is installed)
|
|
|
|
bool msc_visible = SystemSettings.editable;
|
|
|
|
USBD_MSC_CDC_CfgFSDesc[14] = (uint8_t) (msc_visible ? 0x08 : 0xFF);
|
|
|
|
|
|
|
|
return USBD_MSC_CDC_CfgFSDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
uint8_t *USBD_MSC_CDC_GetOtherSpeedCfgDesc (uint16_t *length)
|
|
|
|
{
|
|
|
|
// *length = sizeof (USBD_MSC_CDC_OtherSpeedCfgDesc);
|
|
|
|
// return USBD_MSC_CDC_OtherSpeedCfgDesc;
|
|
|
|
*length = sizeof (USBD_MSC_CDC_CfgFSDesc);
|
|
|
|
return USBD_MSC_CDC_CfgFSDesc;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint8_t *USBD_MSC_CDC_GetDeviceQualifierDescriptor (uint16_t *length)
|
|
|
|
{
|
|
|
|
*length = sizeof (USBD_MSC_CDC_DeviceQualifierDesc);
|
|
|
|
return USBD_MSC_CDC_DeviceQualifierDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *USBD_MSC_CDC_GetUsrStrDescriptor(struct _USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
|
|
|
|
{
|
|
|
|
const char *str;
|
|
|
|
switch (index) {
|
|
|
|
case 0x04: str = "Settings Virtual Mass Storage"; break;
|
|
|
|
case 0x05: str = "Virtual Comport ACM"; break;
|
|
|
|
case 0x06: str = "Virtual Comport CDC"; break;
|
|
|
|
default: str = "No Descriptor";
|
|
|
|
}
|
|
|
|
USBD_GetString ((uint8_t *) str, USBD_StrDesc, length);
|
|
|
|
return USBD_StrDesc;
|
|
|
|
}
|
|
|
|
|
|
|
|
USBD_ClassTypeDef USBD_MSC_CDC =
|
|
|
|
{
|
|
|
|
USBD_MSC_CDC_Init,
|
|
|
|
USBD_MSC_CDC_DeInit,
|
|
|
|
USBD_MSC_CDC_Setup,
|
|
|
|
|
|
|
|
NULL, // USBD_MSC_CDC_EP0_TxSent,
|
|
|
|
USBD_MSC_CDC_EP0_RxReady,
|
|
|
|
|
|
|
|
USBD_MSC_CDC_DataIn,
|
|
|
|
USBD_MSC_CDC_DataOut,
|
|
|
|
|
|
|
|
NULL, // USBD_MSC_CDC_SOF,
|
|
|
|
NULL, // USBD_MSC_CDC_IsoINIncomplete,
|
|
|
|
NULL, // USBD_MSC_CDC_IsoOUTIncomplete,
|
|
|
|
|
|
|
|
// we return only the FS one, others are useless
|
|
|
|
USBD_MSC_CDC_GetFSCfgDesc, //USBD_MSC_CDC_GetHSCfgDesc,
|
|
|
|
USBD_MSC_CDC_GetFSCfgDesc,
|
|
|
|
USBD_MSC_CDC_GetFSCfgDesc, //USBD_MSC_CDC_GetOtherSpeedCfgDesc,
|
|
|
|
|
|
|
|
USBD_MSC_CDC_GetDeviceQualifierDescriptor,
|
|
|
|
USBD_MSC_CDC_GetUsrStrDescriptor
|
|
|
|
};
|