| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 | /**  ******************************************************************************  * @attention  *  * <h2><center>© COPYRIGHT 2015 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_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;#endifstatic 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;}
 |