/** ****************************************************************************** * @attention * *

© COPYRIGHT 2015 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 "usbd_composite.h" #include "usbd_hid.h" #include "usbd_msc.h" #include "usbd_desc.h" #include "usbd_ctlreq.h" #define MSC_MAX_FS_PACKET 64 #define MSC_MAX_HS_PACKET 512 // Support 2 USB devices. #ifdef S2S_USB_FS __ALIGN_BEGIN static USBD_CompositeClassData fsClassData __ALIGN_END; #endif #ifdef S2S_USB_HS __ALIGN_BEGIN static USBD_CompositeClassData hsClassData __ALIGN_END; #endif static uint8_t USBD_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx); static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx); static uint8_t USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); static uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length); static uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length); static uint8_t *USBD_Composite_GetDeviceQualifierDesc (uint16_t *length); static uint8_t USBD_Composite_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum); static uint8_t USBD_Composite_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum); USBD_ClassTypeDef USBD_Composite = { USBD_Composite_Init, USBD_Composite_DeInit, USBD_Composite_Setup, NULL, /*EP0_TxSent*/ NULL, /*EP0_RxReady*/ USBD_Composite_DataIn, /*DataIn*/ USBD_Composite_DataOut, /*DataOut*/ NULL, /*SOF */ NULL, NULL, USBD_Composite_GetHSCfgDesc, USBD_Composite_GetFSCfgDesc, USBD_Composite_GetFSCfgDesc, // "Other" speed USBD_Composite_GetDeviceQualifierDesc, }; __ALIGN_BEGIN static uint8_t USBD_Composite_CfgHSDesc[USB_COMPOSITE_CONFIG_DESC_SIZ] __ALIGN_END = { 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_COMPOSITE_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */ 0x00, 0x02, /*bNumInterfaces: 1 interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x00, /*iConfiguration: Index of string descriptor describing the configuration*/ 0x80, /*bmAttributes: bus powered */ 0xFA, /*MaxPower 500 mA: this current is used for detecting Vbus*/ /************** Descriptor of GENERIC interface ****************/ /* 09 */ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x00, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass: HID*/ 0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ 0, /*iInterface: Index of string descriptor*/ /******************** Descriptor of GENERIC HID ********************/ /* 18 */ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID Class Spec release number*/ 0x01, 0x00, /*bCountryCode: Hardware target country*/ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_GENERIC_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/ 0x00, /******************** Descriptor of Generic HID endpoint ********************/ /* 27 */ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ HID_EPIN_SIZE, /*wMaxPacketSize: 64 Byte max */ 0x00, HID_HS_BINTERVAL, /*bInterval*/ /* 34 */ /******************** Descriptor of GENERIC HID endpoint ********************/ /* 34 */ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ HID_EPOUT_SIZE, /*wMaxPacketSize */ 0x00, HID_HS_BINTERVAL, /*bInterval*/ /* 41 */ /******************** Mass Storage interface ********************/ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ 0x01, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints*/ 0x08, /* bInterfaceClass: MSC Class */ 0x06, /* bInterfaceSubClass : SCSI transparent*/ 0x50, /* nInterfaceProtocol */ 0x00, /* iInterface: */ /******************** Mass Storage Endpoints ********************/ 0x07, /*Endpoint descriptor length = 7*/ 0x05, /*Endpoint descriptor type */ MSC_EPIN_ADDR, /*Endpoint address */ 0x02, /*Bulk endpoint type */ LOBYTE(MSC_MAX_HS_PACKET), HIBYTE(MSC_MAX_HS_PACKET), 0x00, /*Polling interval in milliseconds */ 0x07, /*Endpoint descriptor length = 7 */ 0x05, /*Endpoint descriptor type */ MSC_EPOUT_ADDR, /*Endpoint address */ 0x02, /*Bulk endpoint type */ LOBYTE(MSC_MAX_HS_PACKET), HIBYTE(MSC_MAX_HS_PACKET), 0x00 /*Polling interval in milliseconds*/ }; __ALIGN_BEGIN static uint8_t USBD_Composite_CfgFSDesc[USB_COMPOSITE_CONFIG_DESC_SIZ] __ALIGN_END = { 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_COMPOSITE_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */ 0x00, 0x02, /*bNumInterfaces: 1 interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x00, /*iConfiguration: Index of string descriptor describing the configuration*/ 0x80, /*bmAttributes: bus powered */ 0xFA, /*MaxPower 500 mA: this current is used for detecting Vbus*/ /************** Descriptor of GENERIC interface ****************/ /* 09 */ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x00, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass: HID*/ 0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ 0, /*iInterface: Index of string descriptor*/ /******************** Descriptor of GENERIC HID ********************/ /* 18 */ 0x09, /*bLength: HID Descriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID Class Spec release number*/ 0x01, 0x00, /*bCountryCode: Hardware target country*/ 0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_GENERIC_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/ 0x00, /******************** Descriptor of Generic HID endpoint ********************/ /* 27 */ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ HID_EPIN_SIZE, /*wMaxPacketSize: 64 Byte max */ 0x00, HID_FS_BINTERVAL, /*bInterval*/ /* 34 */ /******************** Descriptor of GENERIC HID endpoint ********************/ /* 34 */ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (OUT)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ HID_EPOUT_SIZE, /*wMaxPacketSize */ 0x00, HID_FS_BINTERVAL, /*bInterval*/ /* 41 */ /******************** Mass Storage interface ********************/ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ 0x01, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints*/ 0x08, /* bInterfaceClass: MSC Class */ 0x06, /* bInterfaceSubClass : SCSI transparent*/ 0x50, /* nInterfaceProtocol */ 0x00, /* iInterface: */ /******************** Mass Storage Endpoints ********************/ 0x07, /*Endpoint descriptor length = 7*/ 0x05, /*Endpoint descriptor type */ MSC_EPIN_ADDR, /*Endpoint address */ 0x02, /*Bulk endpoint type */ LOBYTE(MSC_MAX_FS_PACKET), HIBYTE(MSC_MAX_FS_PACKET), 0x00, /*Polling interval in milliseconds */ 0x07, /*Endpoint descriptor length = 7 */ 0x05, /*Endpoint descriptor type */ MSC_EPOUT_ADDR, /*Endpoint address */ 0x02, /*Bulk endpoint type */ LOBYTE(MSC_MAX_FS_PACKET), HIBYTE(MSC_MAX_FS_PACKET), 0x00 /*Polling interval in milliseconds*/ } ; /* USB Standard Device Descriptor */ __ALIGN_BEGIN static uint8_t USBD_Composite_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_Composite_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) { uint8_t ret = 0; // HID Endpoints USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE); USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE); USBD_CompositeClassData* classData; #ifdef S2S_USB_HS if(pdev->dev_speed == USBD_SPEED_HIGH) { classData = &hsClassData; // MSC Endpoints USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_HS_PACKET); USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_HS_PACKET); } #endif #ifdef S2S_USB_FS if(pdev->dev_speed != USBD_SPEED_HIGH) { classData = &fsClassData; // MSC Endpoints USBD_LL_OpenEP(pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET); USBD_LL_OpenEP(pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, MSC_MAX_FS_PACKET); } #endif classData->hid.state = HID_IDLE; classData->hid.reportReady = 0; classData->DataInReady = 0; classData->DataOutReady = 0; pdev->pClassData = classData; MSC_BOT_Init(pdev); // Prepare Out endpoint to receive next HID packet USBD_LL_PrepareReceive( pdev, HID_EPOUT_ADDR, classData->hid.rxBuffer, sizeof(classData->hid.rxBuffer)); return ret; } static uint8_t USBD_Composite_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { USBD_LL_CloseEP(pdev, HID_EPIN_ADDR); USBD_LL_CloseEP(pdev, HID_EPOUT_ADDR); USBD_LL_CloseEP(pdev, MSC_EPOUT_ADDR); USBD_LL_CloseEP(pdev, MSC_EPIN_ADDR); MSC_BOT_DeInit(pdev); pdev->pClassData = NULL; return USBD_OK; } static uint8_t USBD_Composite_Setup( USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) { uint16_t len = 0; uint8_t *pbuf = NULL; USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData; USBD_HID_HandleTypeDef *hhid = &(classData->hid); USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc); switch (req->bmRequest & USB_REQ_TYPE_MASK) { case USB_REQ_TYPE_CLASS : switch (req->bRequest) { case HID_REQ_SET_PROTOCOL: hhid->Protocol = (uint8_t)(req->wValue); break; case HID_REQ_GET_PROTOCOL: USBD_CtlSendData (pdev, (uint8_t *)&hhid->Protocol, 1); break; case HID_REQ_SET_IDLE: hhid->IdleState = (uint8_t)(req->wValue >> 8); break; case HID_REQ_GET_IDLE: USBD_CtlSendData (pdev, (uint8_t *)&hhid->IdleState, 1); break; case BOT_GET_MAX_LUN : if((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { hmsc->max_lun = ((USBD_StorageTypeDef *)pdev->pUserData)->GetMaxLun(); USBD_CtlSendData (pdev, (uint8_t *)&hmsc->max_lun, 1); } else { USBD_CtlError(pdev , req); return USBD_FAIL; } break; case BOT_RESET : if((req->wValue == 0) && (req->wLength == 0) && ((req->bmRequest & 0x80) != 0x80)) { MSC_BOT_Reset(pdev); } else { USBD_CtlError(pdev , req); return USBD_FAIL; } break; default: USBD_CtlError (pdev, req); return USBD_FAIL; } break; case USB_REQ_TYPE_STANDARD: switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: if( req->wValue >> 8 == HID_REPORT_DESC) { len = MIN(HID_GENERIC_REPORT_DESC_SIZE , req->wLength); pbuf = (uint8_t*) USBD_HID_GetReportDesc(); } else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE) { pbuf = (uint8_t*) USBD_HID_GetDesc(); len = MIN(USB_HID_DESC_SIZ , req->wLength); } USBD_CtlSendData (pdev, pbuf, len); break; case USB_REQ_GET_INTERFACE : if (req->wIndex == 0) { USBD_CtlSendData (pdev, (uint8_t *)&hhid->AltSetting, 1); } else { USBD_CtlSendData (pdev, (uint8_t *)&hmsc->interface, 1); } break; case USB_REQ_SET_INTERFACE : if (req->wIndex == 0) { hhid->AltSetting = (uint8_t)(req->wValue); } else { hmsc->interface = (uint8_t)(req->wValue); } break; case USB_REQ_CLEAR_FEATURE: /* Flush the FIFO and Clear the stall status */ USBD_LL_FlushEP(pdev, (uint8_t)req->wIndex); /* Reactivate the EP */ USBD_LL_CloseEP (pdev , (uint8_t)req->wIndex); switch ((uint8_t)req->wIndex) { case MSC_EPIN_ADDR: USBD_LL_OpenEP( pdev, MSC_EPIN_ADDR, USBD_EP_TYPE_BULK, pdev->dev_speed == USBD_SPEED_HIGH ? MSC_MAX_HS_PACKET : MSC_MAX_FS_PACKET); break; case MSC_EPOUT_ADDR: USBD_LL_OpenEP( pdev, MSC_EPOUT_ADDR, USBD_EP_TYPE_BULK, pdev->dev_speed == USBD_SPEED_HIGH ? MSC_MAX_HS_PACKET : MSC_MAX_FS_PACKET); break; case HID_EPIN_ADDR: USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE); break; case HID_EPOUT_ADDR: USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE); break; } /* Handle BOT error */ MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); break; } break; } return USBD_OK; } static uint8_t USBD_Composite_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData; if (epnum == (HID_EPIN_ADDR & 0x7F)) { USBD_HID_HandleTypeDef *hhid = &(classData->hid); /* 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 */ hhid->state = HID_IDLE; } else if (epnum == (MSC_EPIN_ADDR & 0x7F)) { classData->DataInReady = epnum; } return USBD_OK; } static uint8_t USBD_Composite_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData; if (epnum == (HID_EPOUT_ADDR & 0x7F)) { USBD_HID_HandleTypeDef *hhid = &(classData->hid); hhid->reportReady = 1; } else if (epnum == (MSC_EPOUT_ADDR & 0x7F)) { classData->DataOutReady = epnum; } return USBD_OK; } void s2s_usbDevicePoll(USBD_HandleTypeDef *pdev) { USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData; if (classData->DataInReady) { classData->DataInReady = 0; MSC_BOT_DataIn(pdev); } if (classData->DataOutReady) { classData->DataOutReady = 0; MSC_BOT_DataOut(pdev); } } static uint8_t *USBD_Composite_GetDeviceQualifierDesc (uint16_t *length) { *length = sizeof (USBD_Composite_DeviceQualifierDesc); return USBD_Composite_DeviceQualifierDesc; } uint8_t *USBD_Composite_GetHSCfgDesc (uint16_t *length) { *length = sizeof (USBD_Composite_CfgHSDesc); return USBD_Composite_CfgHSDesc; } uint8_t *USBD_Composite_GetFSCfgDesc (uint16_t *length) { *length = sizeof (USBD_Composite_CfgFSDesc); return USBD_Composite_CfgFSDesc; }