mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
844 lines
27 KiB
C
844 lines
27 KiB
C
#include "usbd_cdc_hid.h"
|
|
#include "usbd_desc.h"
|
|
#include "usbd_ctlreq.h"
|
|
|
|
#include "jshardware.h"
|
|
#include "jsinteractive.h"
|
|
|
|
#ifdef STM32F1
|
|
// don't know why :( probably setup in usdb_conf
|
|
#define CDC_IN_EP 0x81 /* EP1 for data IN */
|
|
#define CDC_OUT_EP 0x01 /* EP1 for data OUT */
|
|
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */
|
|
#else
|
|
#define CDC_IN_EP 0x83 /* EP1 for data IN */
|
|
#define CDC_OUT_EP 0x03 /* EP1 for data OUT */
|
|
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */
|
|
|
|
#define HID_IN_EP 0x81
|
|
#define HID_INTERFACE_NUMBER 0
|
|
#endif
|
|
|
|
extern USBD_HandleTypeDef hUsbDeviceFS;
|
|
//-------------------------------------------------
|
|
static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length);
|
|
//-------------------------------------------------
|
|
|
|
static uint8_t USBD_CDC_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
|
static uint8_t USBD_CDC_HID_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
|
static uint8_t USBD_CDC_HID_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
|
|
static uint8_t USBD_CDC_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
static uint8_t USBD_CDC_HID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
static uint8_t USBD_CDC_HID_SOF (struct _USBD_HandleTypeDef *pdev);
|
|
static uint8_t USBD_CDC_HID_EP0_RxReady (USBD_HandleTypeDef *pdev);
|
|
static uint8_t *USBD_CDC_HID_GetCfgDesc (uint16_t *length);
|
|
uint8_t *USBD_CDC_HID_GetDeviceQualifierDescriptor (uint16_t *length);
|
|
|
|
/* CDC interface class callbacks structure */
|
|
const USBD_ClassTypeDef USBD_CDC_HID =
|
|
{
|
|
USBD_CDC_HID_Init,
|
|
USBD_CDC_HID_DeInit,
|
|
USBD_CDC_HID_Setup,
|
|
NULL, /* EP0_TxSent, */
|
|
USBD_CDC_HID_EP0_RxReady,
|
|
USBD_CDC_HID_DataIn,
|
|
USBD_CDC_HID_DataOut,
|
|
USBD_CDC_HID_SOF,
|
|
NULL,
|
|
NULL,
|
|
USBD_CDC_HID_GetCfgDesc,
|
|
USBD_CDC_HID_GetCfgDesc,
|
|
USBD_CDC_HID_GetCfgDesc,
|
|
USBD_CDC_HID_GetDeviceQualifierDescriptor,
|
|
};
|
|
|
|
/* USB Standard Device Descriptor */
|
|
__ALIGN_BEGIN static const uint8_t USBD_CDC_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
{
|
|
USB_LEN_DEV_QUALIFIER_DESC, // bLength
|
|
USB_DESC_TYPE_DEVICE_QUALIFIER,// bDescriptorType
|
|
0x00, // bcdUSB lo
|
|
0x02, // bcdUSB hi
|
|
0x00, // bDeviceClass
|
|
0x00, // bDeviceSubClass
|
|
0x00, // bDeviceProtocol
|
|
0x40, // bMaxPacketSize0
|
|
0x01, // bNumConfigurations
|
|
0x00, // bReserved
|
|
};
|
|
|
|
|
|
/* USB CDC device Configuration Descriptor
|
|
* ============================================================================
|
|
*
|
|
* No HID
|
|
* CDC on Interfaces 0 and 1
|
|
*/
|
|
#define USBD_CDC_CFGDESC_SIZE 67
|
|
const __ALIGN_BEGIN uint8_t USBD_CDC_CfgDesc[USBD_CDC_CFGDESC_SIZE] __ALIGN_END =
|
|
{
|
|
/*Configuration Descriptor*/
|
|
0x09, /* bLength: Configuration Descriptor size */
|
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
USBD_CDC_CFGDESC_SIZE, 0x00, /* wTotalLength:no of returned bytes */
|
|
0x02, /* bNumInterfaces: 2 interface */
|
|
0x01, /* bConfigurationValue: Configuration value */
|
|
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
|
0xC0, /* bmAttributes: self powered */
|
|
0x32, /* MaxPower 0 mA */
|
|
|
|
// -----------------------------------------------------------------------
|
|
/*CDC Interface Descriptor */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
/* Interface descriptor type */
|
|
0, /* 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 */
|
|
1, /* bDataInterface */
|
|
|
|
/*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 */
|
|
0, /* bMasterInterface: Communication class interface */
|
|
1, /* bSlaveInterface0: Data Class Interface */
|
|
|
|
/*Endpoint 2 Descriptor*/
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_CMD_EP, /* bEndpointAddress */
|
|
0x03, /* bmAttributes: Interrupt */
|
|
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_CMD_PACKET_SIZE),
|
|
0x10, /* bInterval: */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*Data class interface descriptor*/
|
|
0x09, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
|
1, /* 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_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_OUT_EP, /* bEndpointAddress */
|
|
0x02, /* bmAttributes: Bulk */
|
|
LOBYTE(CDC_DATA_FS_OUT_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_DATA_FS_OUT_PACKET_SIZE),
|
|
0x00, /* bInterval: ignore for Bulk transfer */
|
|
|
|
/*Endpoint IN Descriptor*/
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_IN_EP, /* bEndpointAddress */
|
|
0x02, /* bmAttributes: Bulk */
|
|
LOBYTE(CDC_DATA_FS_IN_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_DATA_FS_IN_PACKET_SIZE),
|
|
0x00, /* bInterval: ignore for Bulk transfer */
|
|
} ;
|
|
|
|
#ifdef USE_USB_HID
|
|
/* USB HID + CDC device Configuration Descriptor
|
|
* ============================================================================
|
|
*
|
|
* HID on Interface 0
|
|
* CDC on Interfaces 1 and 2
|
|
*/
|
|
#define USBD_CDC_HID_CFGDESC_SIZE (67+25)
|
|
#define USBD_CDC_HID_CFGDESC_REPORT_SIZE_IDX 25
|
|
// NOT CONST - descriptor size needs updating as this is sent out
|
|
__ALIGN_BEGIN uint8_t USBD_CDC_HID_CfgDesc[USBD_CDC_HID_CFGDESC_SIZE] __ALIGN_END =
|
|
{
|
|
/*Configuration Descriptor*/
|
|
0x09, /* bLength: Configuration Descriptor size */
|
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
USBD_CDC_HID_CFGDESC_SIZE, 0x00, /* wTotalLength:no of returned bytes */
|
|
0x03, /* bNumInterfaces: 3 interface */
|
|
0x01, /* bConfigurationValue: Configuration value */
|
|
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
|
0xC0, /* bmAttributes: self powered */
|
|
0x32, /* MaxPower 0 mA */
|
|
|
|
/************** Descriptor of Joystick Mouse interface ****************/
|
|
/* 9 */
|
|
0x09, /*bLength: Interface Descriptor size*/
|
|
USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
|
|
HID_INTERFACE_NUMBER, /*bInterfaceNumber: Number of Interface*/
|
|
0x00, /*bAlternateSetting: Alternate setting*/
|
|
0x01, /*bNumEndpoints*/
|
|
0x03, /*bInterfaceClass: HID*/
|
|
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
|
|
0, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
|
|
0, /*iInterface: Index of string descriptor*/
|
|
/******************** Descriptor of Joystick Mouse 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*/
|
|
0/*HID_REPORT_DESC_SIZE*/, 0, /*wItemLength: Total length of Report descriptor*/
|
|
/******************** Descriptor of Mouse endpoint ********************/
|
|
/* 27 */
|
|
0x07, /*bLength: Endpoint Descriptor size*/
|
|
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
|
|
HID_IN_EP, /*bEndpointAddress: Endpoint Address (IN)*/
|
|
0x03, /*bmAttributes: Interrupt endpoint*/
|
|
HID_DATA_IN_PACKET_SIZE,0x00, /*wMaxPacketSize: 4 Byte max */
|
|
HID_FS_BINTERVAL, /*bInterval: Polling Interval (10 ms)*/
|
|
|
|
// -----------------------------------------------------------------------
|
|
/*CDC Interface Descriptor */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
/* Interface descriptor type */
|
|
1, /* 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 */
|
|
2, /* bDataInterface */
|
|
|
|
/*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 */
|
|
1, /* bMasterInterface: Communication class interface */
|
|
2, /* bSlaveInterface0: Data Class Interface */
|
|
|
|
/*Endpoint 2 Descriptor*/
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_CMD_EP, /* bEndpointAddress */
|
|
0x03, /* bmAttributes: Interrupt */
|
|
LOBYTE(CDC_CMD_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_CMD_PACKET_SIZE),
|
|
0x10, /* bInterval: */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*Data class interface descriptor*/
|
|
0x09, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
|
2, /* 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_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_OUT_EP, /* bEndpointAddress */
|
|
0x02, /* bmAttributes: Bulk */
|
|
LOBYTE(CDC_DATA_FS_OUT_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_DATA_FS_OUT_PACKET_SIZE),
|
|
0x00, /* bInterval: ignore for Bulk transfer */
|
|
|
|
/*Endpoint IN Descriptor*/
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_IN_EP, /* bEndpointAddress */
|
|
0x02, /* bmAttributes: Bulk */
|
|
LOBYTE(CDC_DATA_FS_IN_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_DATA_FS_IN_PACKET_SIZE),
|
|
0x00, /* bInterval: ignore for Bulk transfer */
|
|
} ;
|
|
|
|
#define USB_HID_DESC_SIZ 9
|
|
#define USBD_HID_DESC_REPORT_SIZE_IDX 7
|
|
/* USB HID device Configuration Descriptor */
|
|
__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END =
|
|
{
|
|
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*/
|
|
0/*HID_REPORT_DESC_SIZE*/, 0x00, /*wItemLength: Total length of Report descriptor*/
|
|
};
|
|
#endif
|
|
// -------------------------------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
|
|
USBD_CDC_HID_HandleTypeDef cdc_hid;
|
|
|
|
/**
|
|
* @brief USBD_CDC_HID_Init
|
|
* Initialize the CDC interface
|
|
* @param pdev: device instance
|
|
* @param cfgidx: Configuration index
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_HID_Init (USBD_HandleTypeDef *pdev,
|
|
uint8_t cfgidx)
|
|
{
|
|
|
|
pdev->pClassData = &cdc_hid;
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*) pdev->pClassData;
|
|
|
|
NOT_USED(cfgidx);
|
|
uint8_t ret = 0;
|
|
|
|
/* Open EP IN */
|
|
USBD_LL_OpenEP(pdev,
|
|
CDC_IN_EP,
|
|
USBD_EP_TYPE_BULK,
|
|
CDC_DATA_FS_IN_PACKET_SIZE);
|
|
|
|
/* Open EP OUT */
|
|
USBD_LL_OpenEP(pdev,
|
|
CDC_OUT_EP,
|
|
USBD_EP_TYPE_BULK,
|
|
CDC_DATA_FS_OUT_PACKET_SIZE);
|
|
/* Open Command IN EP */
|
|
USBD_LL_OpenEP(pdev,
|
|
CDC_CMD_EP,
|
|
USBD_EP_TYPE_INTR,
|
|
CDC_CMD_PACKET_SIZE);
|
|
|
|
/* Init Xfer states */
|
|
handle->cdcState = CDC_IDLE;
|
|
|
|
/* Prepare Out endpoint to receive next packet */
|
|
USBD_LL_PrepareReceive(pdev,
|
|
CDC_OUT_EP,
|
|
handle->cdcRX,
|
|
CDC_DATA_FS_OUT_PACKET_SIZE);
|
|
|
|
#ifdef USE_USB_HID
|
|
unsigned int reportSize = 0;
|
|
handle->hidReportDesc = USB_GetHIDReportDesc(&reportSize);
|
|
handle->hidReportDescSize = (uint16_t)reportSize;
|
|
|
|
/* Open HID EP IN - even if we're not using it */
|
|
USBD_LL_OpenEP(pdev,
|
|
HID_IN_EP,
|
|
USBD_EP_TYPE_INTR,
|
|
HID_DATA_IN_PACKET_SIZE);
|
|
|
|
handle->hidState = HID_IDLE;
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_HID_Init
|
|
* DeInitialize the CDC layer
|
|
* @param pdev: device instance
|
|
* @param cfgidx: Configuration index
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_HID_DeInit (USBD_HandleTypeDef *pdev,
|
|
uint8_t cfgidx)
|
|
{
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*) pdev->pClassData;
|
|
NOT_USED(cfgidx);
|
|
uint8_t ret = 0;
|
|
|
|
/* Open EP IN */
|
|
USBD_LL_CloseEP(pdev,
|
|
CDC_IN_EP);
|
|
|
|
/* Open EP OUT */
|
|
USBD_LL_CloseEP(pdev,
|
|
CDC_OUT_EP);
|
|
|
|
/* Open Command IN EP */
|
|
USBD_LL_CloseEP(pdev,
|
|
CDC_CMD_EP);
|
|
#ifdef USE_USB_HID
|
|
USBD_LL_CloseEP(pdev,
|
|
HID_IN_EP);
|
|
#endif
|
|
|
|
/* DeInit physical Interface components */
|
|
if(pdev->pClassData != NULL)
|
|
{
|
|
//USBD_free(pdev->pClassData);
|
|
pdev->pClassData = NULL;
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static uint8_t USBD_CDC_Setup (USBD_HandleTypeDef *pdev,
|
|
USBD_SetupReqTypedef *req)
|
|
{
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*) pdev->pClassData;
|
|
static uint8_t ifalt = 0;
|
|
|
|
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
{
|
|
case USB_REQ_TYPE_CLASS :
|
|
if (req->wLength)
|
|
{
|
|
if (req->bmRequest & 0x80)
|
|
{
|
|
CDC_Control_FS(req->bRequest, (uint8_t *)handle->data, req->wLength);
|
|
USBD_CtlSendData (pdev,
|
|
(uint8_t *)handle->data,
|
|
req->wLength);
|
|
}
|
|
else
|
|
{
|
|
handle->CmdOpCode = req->bRequest;
|
|
handle->CmdLength = (uint8_t)req->wLength;
|
|
|
|
USBD_CtlPrepareRx (pdev,
|
|
(uint8_t *)handle->data,
|
|
req->wLength);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
CDC_Control_FS(req->bRequest, (uint8_t*)req, 0);
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_TYPE_STANDARD:
|
|
switch (req->bRequest)
|
|
{
|
|
case USB_REQ_GET_INTERFACE :
|
|
USBD_CtlSendData (pdev,
|
|
&ifalt,
|
|
1);
|
|
break;
|
|
|
|
case USB_REQ_SET_INTERFACE :
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return USBD_OK;
|
|
}
|
|
|
|
#ifdef USE_USB_HID
|
|
static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev,
|
|
USBD_SetupReqTypedef *req)
|
|
{
|
|
int len = 0;
|
|
uint8_t *pbuf = NULL;
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*)pdev->pClassData;
|
|
|
|
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
{
|
|
case USB_REQ_TYPE_CLASS :
|
|
switch (req->bRequest)
|
|
{
|
|
|
|
|
|
case HID_REQ_SET_PROTOCOL:
|
|
handle->hidProtocol = (uint8_t)(req->wValue);
|
|
break;
|
|
|
|
case HID_REQ_GET_PROTOCOL:
|
|
USBD_CtlSendData (pdev,
|
|
(uint8_t *)&handle->hidProtocol,
|
|
1);
|
|
break;
|
|
|
|
case HID_REQ_SET_IDLE:
|
|
handle->hidIdleState = (uint8_t)(req->wValue >> 8);
|
|
break;
|
|
|
|
case HID_REQ_GET_IDLE:
|
|
USBD_CtlSendData (pdev,
|
|
(uint8_t *)&handle->hidIdleState,
|
|
1);
|
|
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)
|
|
{
|
|
pbuf = handle->hidReportDesc;
|
|
len = MIN(handle->hidReportDescSize, req->wLength);
|
|
}
|
|
else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
|
|
{
|
|
USBD_HID_Desc[USBD_HID_DESC_REPORT_SIZE_IDX] = (uint8_t)handle->hidReportDescSize;
|
|
USBD_HID_Desc[USBD_HID_DESC_REPORT_SIZE_IDX+1] = (uint8_t)(handle->hidReportDescSize>>8);
|
|
pbuf = USBD_HID_Desc;
|
|
len = MIN(USB_HID_DESC_SIZ , req->wLength);
|
|
}
|
|
|
|
USBD_CtlSendData (pdev,
|
|
pbuf,
|
|
(uint16_t)len);
|
|
|
|
break;
|
|
|
|
case USB_REQ_GET_INTERFACE :
|
|
USBD_CtlSendData (pdev,
|
|
(uint8_t *)&handle->hidAltSetting,
|
|
1);
|
|
break;
|
|
|
|
case USB_REQ_SET_INTERFACE :
|
|
handle->hidAltSetting = (uint8_t)(req->wValue);
|
|
break;
|
|
}
|
|
}
|
|
return USBD_OK;
|
|
}
|
|
#endif
|
|
|
|
static uint8_t USBD_CDC_HID_Setup (USBD_HandleTypeDef *pdev,
|
|
USBD_SetupReqTypedef *req) {
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*)pdev->pClassData;
|
|
#ifdef USE_USB_HID
|
|
if (handle->hidReportDescSize && req->wIndex == HID_INTERFACE_NUMBER)
|
|
return USBD_HID_Setup(pdev, req);
|
|
else
|
|
#endif
|
|
return USBD_CDC_Setup(pdev, req);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief usbd_audio_DataIn
|
|
* Data sent on non-control IN endpoint
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint number
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
{
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*)pdev->pClassData;
|
|
|
|
#ifdef USE_USB_HID
|
|
if (epnum == (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 */
|
|
handle->hidState = HID_IDLE;
|
|
} else
|
|
#endif
|
|
{
|
|
// USB CDC
|
|
handle->cdcState &= ~CDC_WRITE_TX_WAIT;
|
|
}
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_HID_DataOut
|
|
* Data received on non-control Out endpoint
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint number
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_HID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
{
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*)pdev->pClassData;
|
|
|
|
/* Get the received data length */
|
|
unsigned int rxLength = USBD_LL_GetRxDataSize (pdev, epnum);
|
|
|
|
if (handle) {
|
|
// Process data
|
|
jshPushIOCharEvents(EV_USBSERIAL, (char*)handle->cdcRX, rxLength);
|
|
|
|
// Set CDC_READ_WAIT_EMPTY flag - we'll re-enable USB RX using
|
|
// USBD_LL_PrepareReceive ONLY when we have enough space
|
|
handle->cdcState |= CDC_READ_WAIT_EMPTY;
|
|
|
|
return USBD_OK;
|
|
} else {
|
|
return USBD_FAIL;
|
|
}
|
|
}
|
|
|
|
static uint8_t USBD_CDC_HID_SOF (struct _USBD_HandleTypeDef *pdev) {
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*)pdev->pClassData;
|
|
if (!handle ||
|
|
pdev->dev_state != USBD_STATE_CONFIGURED)
|
|
return USBD_OK;
|
|
|
|
if ((handle->cdcState & CDC_READ_WAIT_EMPTY) &&
|
|
jshGetEventsUsed() < IOBUFFER_XOFF) {
|
|
handle->cdcState &= ~CDC_READ_WAIT_EMPTY;
|
|
USBD_LL_PrepareReceive(pdev,
|
|
CDC_OUT_EP,
|
|
handle->cdcRX,
|
|
CDC_DATA_FS_OUT_PACKET_SIZE);
|
|
}
|
|
|
|
if (!handle->cdcState & CDC_WRITE_TX_WAIT) {
|
|
// try and fill the buffer
|
|
unsigned int len = 0;
|
|
int c;
|
|
while (len<CDC_DATA_FS_IN_PACKET_SIZE-1 && // TODO: send max packet size -1 to ensure data is pushed through
|
|
((c = jshGetCharToTransmit(EV_USBSERIAL)) >= 0) ) { // get byte to transmit
|
|
handle->cdcTX[len++] = (uint8_t)c;
|
|
}
|
|
|
|
// send data if we have any...
|
|
if (len) {
|
|
/* Transmit next packet */
|
|
handle->cdcState |= CDC_WRITE_TX_WAIT;
|
|
USBD_LL_Transmit(pdev,
|
|
CDC_IN_EP,
|
|
handle->cdcTX,
|
|
(uint16_t)len);
|
|
}
|
|
}
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_HID_DataOut
|
|
* Data received on non-control Out endpoint
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint number
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_HID_EP0_RxReady (USBD_HandleTypeDef *pdev)
|
|
{
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*) pdev->pClassData;
|
|
|
|
if(handle->CmdOpCode != 0xFF)
|
|
{
|
|
CDC_Control_FS(handle->CmdOpCode, (uint8_t *)handle->data, handle->CmdLength);
|
|
handle->CmdOpCode = 0xFF;
|
|
}
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_HID_GetFSCfgDesc
|
|
* Return configuration descriptor
|
|
* @param speed : current device speed
|
|
* @param length : pointer data length
|
|
* @retval pointer to descriptor buffer
|
|
*/
|
|
static uint8_t *USBD_CDC_HID_GetCfgDesc (uint16_t *length)
|
|
{
|
|
#ifdef USE_USB_HID
|
|
// Check if we have a HID report here - we do it now so we can actually allow
|
|
// Espruino to be plugged and unplugged WITHOUT A RESET
|
|
unsigned int reportSize = 0;
|
|
USB_GetHIDReportDesc(&reportSize);
|
|
|
|
if (reportSize) {
|
|
USBD_CDC_HID_CfgDesc[USBD_CDC_HID_CFGDESC_REPORT_SIZE_IDX] = (uint8_t)reportSize;
|
|
USBD_CDC_HID_CfgDesc[USBD_CDC_HID_CFGDESC_REPORT_SIZE_IDX+1] = (uint8_t)(reportSize>>8);
|
|
*length = USBD_CDC_HID_CFGDESC_SIZE;
|
|
return USBD_CDC_HID_CfgDesc;
|
|
} else
|
|
#endif
|
|
{
|
|
*length = USBD_CDC_CFGDESC_SIZE;
|
|
return USBD_CDC_CfgDesc;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief DeviceQualifierDescriptor
|
|
* return Device Qualifier descriptor
|
|
* @param length : pointer data length
|
|
* @retval pointer to descriptor buffer
|
|
*/
|
|
uint8_t *USBD_CDC_HID_GetDeviceQualifierDescriptor (uint16_t *length)
|
|
{
|
|
*length = sizeof (USBD_CDC_HID_DeviceQualifierDesc);
|
|
return USBD_CDC_HID_DeviceQualifierDesc;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length)
|
|
{
|
|
NOT_USED(pbuf);
|
|
NOT_USED(length);
|
|
switch (cmd)
|
|
{
|
|
case CDC_SEND_ENCAPSULATED_COMMAND:
|
|
|
|
break;
|
|
|
|
case CDC_GET_ENCAPSULATED_RESPONSE:
|
|
|
|
break;
|
|
|
|
case CDC_SET_COMM_FEATURE:
|
|
|
|
break;
|
|
|
|
case CDC_GET_COMM_FEATURE:
|
|
|
|
break;
|
|
|
|
case CDC_CLEAR_COMM_FEATURE:
|
|
|
|
break;
|
|
|
|
/*******************************************************************************/
|
|
/* Line Coding Structure */
|
|
/*-----------------------------------------------------------------------------*/
|
|
/* Offset | Field | Size | Value | Description */
|
|
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
|
|
/* 4 | bCharFormat | 1 | Number | Stop bits */
|
|
/* 0 - 1 Stop bit */
|
|
/* 1 - 1.5 Stop bits */
|
|
/* 2 - 2 Stop bits */
|
|
/* 5 | bParityType | 1 | Number | Parity */
|
|
/* 0 - None */
|
|
/* 1 - Odd */
|
|
/* 2 - Even */
|
|
/* 3 - Mark */
|
|
/* 4 - Space */
|
|
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
|
|
/*******************************************************************************/
|
|
case CDC_SET_LINE_CODING:
|
|
// called when plugged in and app connects
|
|
break;
|
|
|
|
case CDC_GET_LINE_CODING:
|
|
|
|
break;
|
|
|
|
case CDC_SET_CONTROL_LINE_STATE:
|
|
// called on connect/disconnect by app
|
|
break;
|
|
|
|
case CDC_SEND_BREAK:
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (USBD_OK);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
#ifdef USE_USB_HID
|
|
unsigned char *USB_GetHIDReportDesc(unsigned int *len) {
|
|
if (execInfo.hiddenRoot) {
|
|
JsVar *v = jsvObjectGetChild(execInfo.hiddenRoot, JS_USB_HID_VAR_NAME, 0);
|
|
if (jsvIsFlatString(v)) {
|
|
if (len) *len = jsvGetStringLength(v);
|
|
unsigned char *p = jsvGetFlatStringPointer(v);
|
|
jsvUnLock(v);
|
|
return p;
|
|
}
|
|
}
|
|
|
|
if (len) *len = 0;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// --------------------------------------------------------- PUBLIC Functions
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifdef USE_USB_HID
|
|
uint8_t USBD_HID_SendReport (uint8_t *report, unsigned int len)
|
|
{
|
|
USBD_CDC_HID_HandleTypeDef *handle = (USBD_CDC_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
|
|
|
|
if (USB_IsConnected() &&
|
|
handle->hidReportDescSize && // HID enabled?
|
|
handle->hidState == HID_IDLE) { // busy?
|
|
handle->hidState = HID_BUSY;
|
|
memcpy(handle->hidData, report, len);
|
|
USBD_LL_Transmit (&hUsbDeviceFS,
|
|
HID_IN_EP,
|
|
(uint8_t*)handle->hidData,
|
|
(uint16_t)len);
|
|
return USBD_OK;
|
|
}
|
|
return USBD_FAIL;
|
|
}
|
|
#endif
|
|
|
|
|
|
int USB_IsConnected() {
|
|
return hUsbDeviceFS.dev_state == USBD_STATE_CONFIGURED;
|
|
}
|
|
|
|
|