summaryrefslogtreecommitdiffstatshomepage
path: root/stm/lib/usbd_pyb_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm/lib/usbd_pyb_core.c')
-rw-r--r--stm/lib/usbd_pyb_core.c726
1 files changed, 726 insertions, 0 deletions
diff --git a/stm/lib/usbd_pyb_core.c b/stm/lib/usbd_pyb_core.c
new file mode 100644
index 0000000000..e2e8c65ca0
--- /dev/null
+++ b/stm/lib/usbd_pyb_core.c
@@ -0,0 +1,726 @@
+/**
+ ******************************************************************************
+ * @file usbd_cdc_core.c
+ * @author MCD Application Team
+ * @version V1.1.0
+ * @date 19-March-2012
+ * @brief This file provides the high layer firmware functions to manage the
+ * following functionalities of the USB CDC Class:
+ * - Initialization and Configuration of high and low layer
+ * - Enumeration as CDC Device (and enumeration for each implemented memory interface)
+ * - OUT/IN data transfer
+ * - Command IN transfer (class requests management)
+ * - Error management
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * CDC Class Driver Description
+ * ===================================================================
+ * This driver manages the "Universal Serial Bus Class Definitions for Communications Devices
+ * Revision 1.2 November 16, 2007" and the sub-protocol specification of "Universal Serial Bus
+ * Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007"
+ * This driver implements the following aspects of the specification:
+ * - Device descriptor management
+ * - Configuration descriptor management
+ * - Enumeration as CDC device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN)
+ * - Requests management (as described in section 6.2 in specification)
+ * - Abstract Control Model compliant
+ * - Union Functional collection (using 1 IN endpoint for control)
+ * - Data interface class
+
+ * @note
+ * For the Abstract Control Model, this core allows only transmitting the requests to
+ * lower layer dispatcher (ie. usbd_cdc_vcp.c/.h) which should manage each request and
+ * perform relative actions.
+ *
+ * These aspects may be enriched or modified for a specific user application.
+ *
+ * This driver doesn't implement the following aspects of the specification
+ * (but it is possible to manage these features with some modifications on this driver):
+ * - Any class-specific aspect relative to communication classes should be managed by user application.
+ * - All communication classes other than PSTN are not managed
+ *
+ * @endverbatim
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_cdc_core.h"
+#include "usbd_desc.h"
+#include "usbd_req.h"
+#include "usbd_conf.h"
+#include "usbd_msc_bot.h"
+#include "usbd_msc_mem.h"
+
+#define USB_PYB_CONFIG_DESC_SIZ 98
+
+#define MSC_EPIN_SIZE MSC_MAX_PACKET
+#define MSC_EPOUT_SIZE MSC_MAX_PACKET
+
+/*********************************************
+ PYB Device library callbacks
+ *********************************************/
+static uint8_t usbd_pyb_Init (void *pdev, uint8_t cfgidx);
+static uint8_t usbd_pyb_DeInit (void *pdev, uint8_t cfgidx);
+static uint8_t usbd_pyb_Setup (void *pdev, USB_SETUP_REQ *req);
+static uint8_t usbd_pyb_EP0_RxReady (void *pdev);
+static uint8_t usbd_pyb_DataIn (void *pdev, uint8_t epnum);
+static uint8_t usbd_pyb_DataOut (void *pdev, uint8_t epnum);
+static uint8_t usbd_pyb_SOF (void *pdev);
+
+/*********************************************
+ PYB specific management functions
+ *********************************************/
+static void Handle_USBAsynchXfer (void *pdev);
+static uint8_t *usbd_pyb_GetCfgDesc (uint8_t speed, uint16_t *length);
+
+/** @defgroup usbd_cdc_Private_Variables
+ * @{
+ */
+extern CDC_IF_Prop_TypeDef APP_FOPS;
+extern uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC];
+
+__ALIGN_BEGIN static uint8_t usbd_cdc_AltSet __ALIGN_END = 0;
+__ALIGN_BEGIN static uint8_t USB_Rx_Buffer[CDC_DATA_MAX_PACKET_SIZE] __ALIGN_END;
+__ALIGN_BEGIN uint8_t APP_Rx_Buffer[APP_RX_DATA_SIZE] __ALIGN_END;
+
+__ALIGN_BEGIN static uint8_t CmdBuff[CDC_CMD_PACKET_SZE] __ALIGN_END;
+
+__ALIGN_BEGIN static uint8_t USBD_MSC_MaxLun __ALIGN_END = 0;
+__ALIGN_BEGIN static uint8_t USBD_MSC_AltSet __ALIGN_END = 0;
+
+uint32_t APP_Rx_ptr_in = 0;
+uint32_t APP_Rx_ptr_out = 0;
+uint32_t APP_Rx_length = 0;
+
+uint8_t USB_Tx_State = 0;
+
+static uint32_t cdcCmd = 0xFF;
+static uint32_t cdcLen = 0;
+
+/* PYB interface class callbacks structure */
+USBD_Class_cb_TypeDef USBD_PYB_cb =
+{
+ usbd_pyb_Init,
+ usbd_pyb_DeInit,
+ usbd_pyb_Setup,
+ NULL, // EP0_TxSent
+ usbd_pyb_EP0_RxReady,
+ usbd_pyb_DataIn,
+ usbd_pyb_DataOut,
+ usbd_pyb_SOF,
+ NULL, // IsoINIncomplete
+ NULL, // IsoOUTIncomplete
+ usbd_pyb_GetCfgDesc,
+ // for OTG_HS support need to add other cfg desc here
+};
+
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+ #pragma data_alignment=4
+ #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+/* USB PYB device Configuration Descriptor */
+__ALIGN_BEGIN static uint8_t usbd_pyb_CfgDesc[USB_PYB_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+ //--------------------------------------------------------------------------
+ // Configuration Descriptor
+ 0x09, // bLength: Configuration Descriptor size
+ USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType: Configuration
+ LOBYTE(USB_PYB_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes
+ HIBYTE(USB_PYB_CONFIG_DESC_SIZ),
+ 0x03, // bNumInterfaces: 3 interfaces
+ 0x01, // bConfigurationValue: Configuration value
+ 0x00, // iConfiguration: Index of string descriptor describing the configuration
+ 0x80, // bmAttributes: bus powered; 0xc0 for self powered
+ 0xfa, // bMaxPower: in units of 2mA
+
+ //==========================================================================
+ // Interface Association for CDC VCP
+ 0x08, // bLength: 8 bytes
+ USB_INTERFACE_ASSOCIATION_TYPE, // bDescriptorType: IAD
+ 0x00, // bFirstInterface: first interface for this association
+ 0x02, // bInterfaceCount: nummber of interfaces for this association
+ 0x00, // bFunctionClass: ?
+ 0x00, // bFunctionSubClass: ?
+ 0x00, // bFunctionProtocol: ?
+ 0x00, // iFunction: index of string for this function
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: Interface
+ 0x00, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x01, // bNumEndpoints: One endpoints used
+ 0x02, // bInterfaceClass: Communication Interface Class
+ 0x02, // bInterfaceSubClass: Abstract Control Model
+ 0x01, // bInterfaceProtocol: Common AT commands
+ 0x00, // iInterface:
+
+ // Header Functional Descriptor
+ 0x05, // bLength: Endpoint Descriptor size
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x00, // bDescriptorSubtype: Header Func Desc
+ 0x10, // bcdCDC: spec release number
+ 0x01, // ?
+
+ // Call Management Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x01, // bDescriptorSubtype: Call Management Func Desc
+ 0x00, // bmCapabilities: D0+D1
+ 0x01, // bDataInterface: 1
+
+ // ACM Functional Descriptor
+ 0x04, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x02, // bDescriptorSubtype: Abstract Control Management desc
+ 0x02, // bmCapabilities
+
+ // Union Functional Descriptor
+ 0x05, // bFunctionLength
+ 0x24, // bDescriptorType: CS_INTERFACE
+ 0x06, // bDescriptorSubtype: Union func desc
+ 0x00, // bMasterInterface: Communication class interface
+ 0x01, // bSlaveInterface0: Data Class Interface
+
+ // Endpoint 2 Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint
+ CDC_CMD_EP, // bEndpointAddress
+ 0x03, // bmAttributes: Interrupt
+ LOBYTE(CDC_CMD_PACKET_SZE), // wMaxPacketSize:
+ HIBYTE(CDC_CMD_PACKET_SZE),
+ 0x80, // bInterval: polling interval in frames of 1ms
+
+ //--------------------------------------------------------------------------
+ // Data class interface descriptor
+ 0x09, // bLength: Endpoint Descriptor size
+ USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: interface
+ 0x01, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints: Two endpoints used
+ 0x0A, // bInterfaceClass: CDC
+ 0x00, // bInterfaceSubClass: ?
+ 0x00, // bInterfaceProtocol: ?
+ 0x00, // iInterface:
+
+ // Endpoint OUT Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint
+ CDC_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_MAX_PACKET_SIZE), // wMaxPacketSize:
+ HIBYTE(CDC_DATA_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ // Endpoint IN Descriptor
+ 0x07, // bLength: Endpoint Descriptor size
+ USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint
+ CDC_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes: Bulk
+ LOBYTE(CDC_DATA_MAX_PACKET_SIZE), // wMaxPacketSize:
+ HIBYTE(CDC_DATA_MAX_PACKET_SIZE),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ //==========================================================================
+ // MSC only has 1 interface so doesn't need an IAD
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: interface descriptor
+ 0x02, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x02, // bNumEndpoints*/
+ 0x08, // bInterfaceClass: MSC Class
+ 0x06, // bInterfaceSubClass : SCSI transparent*/
+ 0x50, // nInterfaceProtocol
+ 0x00, // iInterface:
+
+ // Endpoint IN descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint descriptor type
+ MSC_IN_EP, // bEndpointAddress: IN, address 3
+ 0x02, // bmAttributes: Bulk endpoint type
+ LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_MAX_PACKET),
+ 0x00, // bInterval: ignore for Bulk transfer
+
+ // Endpoint OUT descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint descriptor type
+ MSC_OUT_EP, // bEndpointAddress: OUT, address 3
+ 0x02, // bmAttributes: Bulk endpoint type
+ LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize
+ HIBYTE(MSC_MAX_PACKET),
+ 0x00, // bInterval: ignore for Bulk transfer
+};
+
+
+/** @defgroup usbd_pyb_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief usbd_pyb_Init
+ * Initilaize the PYB interface
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t usbd_pyb_Init(void *pdev, uint8_t cfgidx) {
+ // deinit first to reset
+ usbd_pyb_DeInit(pdev, cfgidx);
+
+ //----------------------------------
+ // CDC VCP component
+
+ // Open EP IN
+ DCD_EP_Open(pdev,
+ CDC_IN_EP,
+ CDC_DATA_IN_PACKET_SIZE,
+ USB_OTG_EP_BULK);
+
+ // Open EP OUT
+ DCD_EP_Open(pdev,
+ CDC_OUT_EP,
+ CDC_DATA_OUT_PACKET_SIZE,
+ USB_OTG_EP_BULK);
+
+ // Open Command IN EP
+ DCD_EP_Open(pdev,
+ CDC_CMD_EP,
+ CDC_CMD_PACKET_SZE,
+ USB_OTG_EP_INT);
+
+ /*
+ // can use this to dynamically set the device class
+ uint8_t *pbuf = USBD_DeviceDesc;
+ pbuf[4] = DEVICE_CLASS_CDC;
+ pbuf[5] = DEVICE_SUBCLASS_CDC;
+ */
+
+ // Initialize the Interface physical components
+ APP_FOPS.pIf_Init();
+
+ // Prepare Out endpoint to receive next packet */
+ DCD_EP_PrepareRx(pdev,
+ CDC_OUT_EP,
+ (uint8_t*)(USB_Rx_Buffer),
+ CDC_DATA_OUT_PACKET_SIZE);
+
+ //----------------------------------
+ // MSC component
+
+ // Open EP IN
+ DCD_EP_Open(pdev,
+ MSC_IN_EP,
+ MSC_EPIN_SIZE,
+ USB_OTG_EP_BULK);
+
+ // Open EP OUT
+ DCD_EP_Open(pdev,
+ MSC_OUT_EP,
+ MSC_EPOUT_SIZE,
+ USB_OTG_EP_BULK);
+
+ // Init the BOT layer
+ MSC_BOT_Init(pdev);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief usbd_pyb_Init
+ * DeInitialize the CDC layer
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t usbd_pyb_DeInit(void *pdev, uint8_t cfgidx) {
+ //----------------------------------
+ // CDC VCP component
+ // close CDC EPs
+ DCD_EP_Close(pdev, CDC_IN_EP);
+ DCD_EP_Close(pdev, CDC_OUT_EP);
+ DCD_EP_Close(pdev, CDC_CMD_EP);
+
+ // Restore default state of the Interface physical components
+ APP_FOPS.pIf_DeInit();
+
+ //----------------------------------
+ // MSC component
+
+ // Close MSC EPs
+ DCD_EP_Close(pdev, MSC_IN_EP);
+ DCD_EP_Close(pdev, MSC_OUT_EP);
+
+ // Un Init the BOT layer
+ MSC_BOT_DeInit(pdev);
+
+ return USBD_OK;
+}
+
+#define BOT_GET_MAX_LUN 0xFE
+#define BOT_RESET 0xFF
+
+/**
+ * @brief usbd_pyb_Setup
+ * Handle the CDC specific requests
+ * @param pdev: instance
+ * @param req: usb requests
+ * @retval status
+ */
+static uint8_t usbd_pyb_Setup(void *pdev, USB_SETUP_REQ *req) {
+ switch (req->bmRequest & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) {
+
+ // Standard Device Request ---------------------------------------------
+ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_DEVICE):
+ switch (req->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ {
+ uint16_t len = USB_CDC_DESC_SIZ; // XXX WRONG!
+ uint8_t *pbuf = usbd_pyb_CfgDesc + 9;
+ if ((req->wValue >> 8) == CDC_DESCRIPTOR_TYPE) {
+ pbuf = usbd_pyb_CfgDesc + 9 + (9 * USBD_ITF_MAX_NUM); // TODO
+ len = MIN(USB_CDC_DESC_SIZ, req->wLength); // TODO
+ }
+ return USBD_CtlSendData(pdev, pbuf, len);
+ }
+ }
+ break;
+
+ // Standard Interface Request ------------------------------------------
+ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE):
+ switch (req->bRequest) {
+ case USB_REQ_GET_INTERFACE:
+ // wIndex & 0xff is the interface
+ if ((req->wIndex & 0xff) <= 1) {
+ return USBD_CtlSendData(pdev, &usbd_cdc_AltSet, 1);
+ } else {
+ return USBD_CtlSendData(pdev, &USBD_MSC_AltSet, 1);
+ }
+
+ case USB_REQ_SET_INTERFACE:
+ if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM) { // TODO
+ if ((req->wIndex & 0xff) <= 1) {
+ usbd_cdc_AltSet = req->wValue;
+ } else {
+ USBD_MSC_AltSet = req->wValue;
+ }
+ return USBD_OK;
+ }
+ }
+ break;
+
+ // Standard Endpoint Request -------------------------------------------
+ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_ENDPOINT):
+ // req->wIndex is the endpoint number, including direction
+ if (req->wIndex == MSC_IN_EP || req->wIndex == MSC_OUT_EP) {
+ // MSC component
+ switch (req->bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+
+ // Flush the FIFO and Clear the stall status
+ DCD_EP_Flush(pdev, (uint8_t)req->wIndex);
+
+ // Re-activate the EP
+ DCD_EP_Close(pdev, (uint8_t)req->wIndex);
+
+ if ((((uint8_t)req->wIndex) & 0x80) == 0x80) {
+ DCD_EP_Open(pdev, ((uint8_t)req->wIndex), MSC_EPIN_SIZE, USB_OTG_EP_BULK);
+ } else {
+ DCD_EP_Open(pdev, ((uint8_t)req->wIndex), MSC_EPOUT_SIZE, USB_OTG_EP_BULK);
+ }
+
+ // Handle BOT error
+ MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
+ return USBD_OK;
+ }
+ }
+ break;
+
+ // CDC Class Requests ------------------------------
+ case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE):
+ // req->wIndex is the recipient interface number
+ if (req->wIndex == 0) {
+ // CDC component, communications interface (TODO do we need to handle if#1?)
+
+ // Check if the request is a data setup packet
+ if (req->wLength) {
+ if (req->bmRequest & 0x80) {
+ // Device-to-Host request
+
+ // Get the data to be sent to Host from interface layer
+ APP_FOPS.pIf_Ctrl(req->bRequest, CmdBuff, req->wLength);
+
+ // Send the data to the host
+ return USBD_CtlSendData(pdev, CmdBuff, req->wLength);
+
+ } else {
+ // Host-to-Device requeset
+
+ // Set the value of the current command to be processed */
+ cdcCmd = req->bRequest;
+ cdcLen = req->wLength;
+
+ // Prepare the reception of the buffer over EP0
+ // Next step: the received data will be managed in usbd_cdc_EP0_TxSent() function.
+ return USBD_CtlPrepareRx(pdev, CmdBuff, req->wLength);
+ }
+ } else {
+ // Not a Data request
+
+ // Transfer the command to the interface layer */
+ return APP_FOPS.pIf_Ctrl(req->bRequest, NULL, 0);
+ }
+
+ } else if (req->wIndex == 2) {
+ // MSC component
+ switch (req->bRequest) {
+ case BOT_GET_MAX_LUN:
+ if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) {
+ USBD_MSC_MaxLun = USBD_STORAGE_fops->GetMaxLun();
+ if (USBD_MSC_MaxLun > 0) {
+ return USBD_CtlSendData(pdev, &USBD_MSC_MaxLun, 1);
+ }
+ }
+ break;
+
+ case BOT_RESET:
+ if ((req->wValue == 0) && (req->wLength == 0) && ((req->bmRequest & 0x80) != 0x80)) {
+ MSC_BOT_Reset(pdev);
+ return USBD_OK;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ printf("SU %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex);
+
+ // invalid command
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+}
+
+/**
+ * @brief usbd_pyb_EP0_RxReady
+ * Data received on control endpoint
+ * @param pdev: device device instance
+ * @retval status
+ */
+static uint8_t usbd_pyb_EP0_RxReady(void *pdev) {
+ if (cdcCmd != NO_CMD) {
+ // Process the data
+ APP_FOPS.pIf_Ctrl(cdcCmd, CmdBuff, cdcLen);
+
+ // Reset the command variable to default value
+ cdcCmd = NO_CMD;
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief usbd_pyb_DataIn
+ * Data sent on non-control IN endpoint
+ * @param pdev: device instance
+ * @param epnum: endpoint number
+ * @retval status
+ */
+static uint8_t usbd_pyb_DataIn(void *pdev, uint8_t epnum) {
+ uint16_t USB_Tx_ptr;
+ uint16_t USB_Tx_length;
+
+ switch (epnum) {
+ case (CDC_IN_EP & 0x7f): // TODO is this correct?
+ case (CDC_CMD_EP & 0x7f): // TODO is this correct?
+ if (USB_Tx_State == 1) {
+ if (APP_Rx_length == 0) {
+ USB_Tx_State = 0;
+ } else {
+ if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE) {
+ USB_Tx_ptr = APP_Rx_ptr_out;
+ USB_Tx_length = CDC_DATA_IN_PACKET_SIZE;
+
+ APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE;
+ APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE;
+ } else {
+ USB_Tx_ptr = APP_Rx_ptr_out;
+ USB_Tx_length = APP_Rx_length;
+
+ APP_Rx_ptr_out += APP_Rx_length;
+ APP_Rx_length = 0;
+ }
+
+ // Prepare the available data buffer to be sent on IN endpoint
+ DCD_EP_Tx(pdev,
+ CDC_IN_EP,
+ (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr],
+ USB_Tx_length);
+ }
+ }
+ break;
+
+ case (MSC_IN_EP & 0x7f): // TODO?
+ MSC_BOT_DataIn(pdev, epnum);
+ break;
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief usbd_pyb_DataOut
+ * Data received on non-control Out endpoint
+ * @param pdev: device instance
+ * @param epnum: endpoint number
+ * @retval status
+ */
+static uint8_t usbd_pyb_DataOut(void *pdev, uint8_t epnum) {
+ uint16_t USB_Rx_Cnt;
+
+ switch (epnum) {
+ case (CDC_OUT_EP & 0x7f): // TODO is this correct?
+ // Get the received data buffer and update the counter */
+ USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count;
+
+ /* USB data will be immediately processed, this allow next USB traffic being
+ NAKed till the end of the application Xfer */
+ APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt);
+
+ // Prepare Out endpoint to receive next packet */
+ DCD_EP_PrepareRx(pdev,
+ CDC_OUT_EP,
+ (uint8_t*)(USB_Rx_Buffer),
+ CDC_DATA_OUT_PACKET_SIZE);
+ break;
+
+ case (MSC_OUT_EP & 0x7f): // TODO is this correct?
+ MSC_BOT_DataOut(pdev, epnum);
+ break;
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief usbd_pyb_SOF
+ * Start Of Frame event management
+ * @param pdev: instance
+ * @retval status
+ */
+static uint8_t usbd_pyb_SOF(void *pdev) {
+ static uint32_t FrameCount = 0;
+
+ // TODO do we need to check that this is for CDC/VCP? can we even do that?
+
+ if (FrameCount++ == CDC_IN_FRAME_INTERVAL) {
+ // Reset the frame counter */
+ FrameCount = 0;
+
+ // Check the data to be sent through IN pipe */
+ Handle_USBAsynchXfer(pdev);
+ }
+
+ return USBD_OK;
+}
+
+/**
+ * @brief Handle_USBAsynchXfer
+ * Send data to USB
+ * @param pdev: instance
+ * @retval None
+ */
+static void Handle_USBAsynchXfer (void *pdev)
+{
+ uint16_t USB_Tx_ptr;
+ uint16_t USB_Tx_length;
+
+ if(USB_Tx_State != 1)
+ {
+ if (APP_Rx_ptr_out == APP_RX_DATA_SIZE)
+ {
+ APP_Rx_ptr_out = 0;
+ }
+
+ if(APP_Rx_ptr_out == APP_Rx_ptr_in)
+ {
+ USB_Tx_State = 0;
+ return;
+ }
+
+ if(APP_Rx_ptr_out > APP_Rx_ptr_in) // rollback */
+ {
+ APP_Rx_length = APP_RX_DATA_SIZE - APP_Rx_ptr_out;
+
+ }
+ else
+ {
+ APP_Rx_length = APP_Rx_ptr_in - APP_Rx_ptr_out;
+
+ }
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ APP_Rx_length &= ~0x03;
+#endif // USB_OTG_HS_INTERNAL_DMA_ENABLED */
+
+ if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE)
+ {
+ USB_Tx_ptr = APP_Rx_ptr_out;
+ USB_Tx_length = CDC_DATA_IN_PACKET_SIZE;
+
+ APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE;
+ APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE;
+ }
+ else
+ {
+ USB_Tx_ptr = APP_Rx_ptr_out;
+ USB_Tx_length = APP_Rx_length;
+
+ APP_Rx_ptr_out += APP_Rx_length;
+ APP_Rx_length = 0;
+ }
+ USB_Tx_State = 1;
+
+ DCD_EP_Tx (pdev,
+ CDC_IN_EP,
+ (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr],
+ USB_Tx_length);
+ }
+
+}
+
+/**
+ * @brief usbd_pyb_GetCfgDesc
+ * Return configuration descriptor
+ * @param speed : current device speed
+ * @param length : pointer data length
+ * @retval pointer to descriptor buffer
+ */
+static uint8_t *usbd_pyb_GetCfgDesc(uint8_t speed, uint16_t *length) {
+ *length = sizeof(usbd_pyb_CfgDesc);
+ return usbd_pyb_CfgDesc;
+}