/** ****************************************************************************** * @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 * *

© COPYRIGHT 2012 STMicroelectronics

* * 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 #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" // CDC VCP is the first interface // the option below is supposed to select between MSC (1) and HID (0) for the // second USB interface, but it does not work (only VCP+MSC works) // to use HID on its own (ie no VCP), the functions in usbd_pyb_core2.c can be // used, and selected in the call to pyb_usb_dev_init(). #define USB_PYB_USE_MSC (1) #if USB_PYB_USE_MSC //#define USB_PYB_CONFIG_DESC_SIZ (67) // for only CDC VCP interfaces #define USB_PYB_CONFIG_DESC_SIZ (98) // for both CDC VCP and MSC interfaces #else // USE_HID #define USB_PYB_CONFIG_DESC_SIZ (100) // for both CDC VCP and HID interfaces #endif #define MSC_EPIN_SIZE MSC_MAX_PACKET #define MSC_EPOUT_SIZE MSC_MAX_PACKET #define HID_MOUSE_REPORT_DESC_SIZE (74) #define HID_DESCRIPTOR_TYPE 0x21 #define HID_REPORT_DESC 0x22 // HID parameters #define HID_IN_EP (0x83) #define HID_IN_PACKET (4) /* maximum, and actual, packet size */ /********************************************* 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 VCP_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; #if USB_PYB_USE_MSC __ALIGN_BEGIN static uint8_t USBD_MSC_MaxLun __ALIGN_END = 0; __ALIGN_BEGIN static uint8_t USBD_MSC_AltSet __ALIGN_END = 0; #else __ALIGN_BEGIN static uint8_t USBD_HID_AltSet __ALIGN_END = 0; __ALIGN_BEGIN static uint8_t USBD_HID_Protocol __ALIGN_END = 0; __ALIGN_BEGIN static uint8_t USBD_HID_IdleState __ALIGN_END = 0; #endif 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 0x04, // 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: ? 0x04, // 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 #if USB_PYB_USE_MSC //========================================================================== // 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 #else //========================================================================== // HID 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 0x01, // bNumEndpoints 0x03, // bInterfaceClass: HID Class 0x01, // bInterfaceSubClass: 0=no boot, 1=BOOT 0x02, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse 0x00, // iInterface: // Descriptor of Joystick Mouse HID 0x09, // bLength: HID Descriptor size HID_DESCRIPTOR_TYPE, // bDescriptorType: HID 0x11, // bcdHID: HID Class Spec release number, low byte 0x01, // bcdHID: high byte 0x00, // bCountryCode: Hardware target country (0=unsupported) 0x01, // bNumDescriptors: Number of HID class descriptors to follow HID_REPORT_DESC, // bDescriptorType: report HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor 0x00, // Endpoint IN descriptor 0x07, // bLength: Endpoint descriptor length USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint descriptor type HID_IN_EP, // bEndpointAddress: IN, address of HID 0x03, // bmAttributes: Interrupt endpoint type LOBYTE(HID_IN_PACKET), // wMaxPacketSize HIBYTE(HID_IN_PACKET), 0x0a, // bInterval: polling interval, units of 1ms #endif }; #if !USB_PYB_USE_MSC __ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END = { 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 0xC0, 0x09, 0x3c, 0x05, 0xff, 0x09, 0x01, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x02, 0xb1, 0x22, 0x75, 0x06, 0x95, 0x01, 0xb1, 0x01, 0xc0 }; #endif /** @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 VCP_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); #if USB_PYB_USE_MSC //---------------------------------- // 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); #else //---------------------------------- // HID component // Open EP IN DCD_EP_Open(pdev, HID_IN_EP, HID_IN_PACKET, USB_OTG_EP_INT); #endif 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 VCP_fops.pIf_DeInit(); #if USB_PYB_USE_MSC //---------------------------------- // 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); #else //---------------------------------- // HID component // Close HID EP DCD_EP_Close(pdev, HID_IN_EP); #endif return USBD_OK; } #define BOT_GET_MAX_LUN 0xFE #define BOT_RESET 0xFF #define HID_REQ_SET_PROTOCOL (0x0B) #define HID_REQ_GET_PROTOCOL (0x03) #define HID_REQ_SET_IDLE (0x0A) #define HID_REQ_GET_IDLE (0x02) #define HID_REQ_SET_REPORT (0x09) // used? #define HID_REQ_GET_REPORT (0x01) // used? /** * @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); // TODO stuff here for HID, using HID_MOUSE_ReportDesc } } */ break; // Standard Interface Request ------------------------------------------ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE): switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: // needed for HID; SU 0x81 0x06 0x2200 0x00 request // wIndex & 0xff is the interface if ((req->wIndex & 0xff) <= 1) { // CDC VCP } else { #if USB_PYB_USE_MSC #else uint16_t len = 0; uint8_t *pbuf = NULL; if (req->wValue >> 8 == HID_REPORT_DESC) { len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength); pbuf = HID_MOUSE_ReportDesc; return USBD_CtlSendData(pdev, pbuf, len); } else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE) { pbuf = usbd_pyb_CfgDesc + /* skip VCP */ 0x09 + 0x08 + 0x09 + 0x05 + 0x05 + 0x04 + 0x05 + 0x07 + 0x09 + 0x07 + 0x07 + /* skip iface descr */ 0x09; len = MIN(0x09, req->wLength); return USBD_CtlSendData(pdev, pbuf, len); } #endif } break; case USB_REQ_GET_INTERFACE: // wIndex & 0xff is the interface if ((req->wIndex & 0xff) <= 1) { return USBD_CtlSendData(pdev, &usbd_cdc_AltSet, 1); } else { #if USB_PYB_USE_MSC return USBD_CtlSendData(pdev, &USBD_MSC_AltSet, 1); #else return USBD_CtlSendData(pdev, &USBD_HID_AltSet, 1); #endif } 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 { #if USB_PYB_USE_MSC USBD_MSC_AltSet = req->wValue; #else USBD_HID_AltSet = req->wValue; #endif } 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 USB_PYB_USE_MSC 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; } } #endif 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 VCP_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 VCP_fops.pIf_Ctrl(req->bRequest, NULL, req->wValue); } } else if (req->wIndex == 2) { #if USB_PYB_USE_MSC // 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; } #else // HID component switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: USBD_HID_Protocol = req->wValue; return USBD_OK; case HID_REQ_GET_PROTOCOL: return USBD_CtlSendData(pdev, &USBD_HID_Protocol, 1); case HID_REQ_SET_IDLE: USBD_HID_IdleState = (req->wValue >> 8); return USBD_OK; case HID_REQ_GET_IDLE: return USBD_CtlSendData(pdev, &USBD_HID_IdleState, 1); } #endif } 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 VCP_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); } } return USBD_OK; #if USB_PYB_USE_MSC case (MSC_IN_EP & 0x7f): // TODO? MSC_BOT_DataIn(pdev, epnum); return USBD_OK; #else case (HID_IN_EP & 0x7f): /* Ensure that the FIFO is empty before a new transfer, this condition could be caused by a new transfer before the end of the previous transfer */ DCD_EP_Flush(pdev, HID_IN_EP); return USBD_OK; #endif } printf("DI %x\n", epnum); 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 */ VCP_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); return USBD_OK; #if USB_PYB_USE_MSC case (MSC_OUT_EP & 0x7f): // TODO is this correct? MSC_BOT_DataOut(pdev, epnum); return USBD_OK; #endif } printf("DO %x\n", epnum); 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; } /** * @brief USBD_HID_SendReport * Send HID Report * @param pdev: device instance * @param buff: pointer to report (4 bytes: ?, x, y, ?) * @retval status */ /* uint8_t USBD_HID_SendReport(USB_OTG_CORE_HANDLE *pdev, uint8_t *report, uint16_t len) { if (pdev->dev.device_status == USB_OTG_CONFIGURED) { DCD_EP_Tx(pdev, HID_IN_EP, report, len); } return USBD_OK; } */