summaryrefslogtreecommitdiff
path: root/fw/src/usbd_hid.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw/src/usbd_hid.c')
-rw-r--r--fw/src/usbd_hid.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/fw/src/usbd_hid.c b/fw/src/usbd_hid.c
new file mode 100644
index 0000000..4d313b4
--- /dev/null
+++ b/fw/src/usbd_hid.c
@@ -0,0 +1,373 @@
+#include "usbd_hid.h"
+#include "usbd_desc.h"
+#include "usbd_ctlreq.h"
+
+
+static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev, uint8_t cfgidx);
+static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
+static uint8_t *USBD_HID_GetCfgDesc (uint16_t *length);
+static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length);
+static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum);
+static uint8_t USBD_HID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum);
+
+USBD_ClassTypeDef USBD_HID =
+{
+ USBD_HID_Init,
+ USBD_HID_DeInit,
+ USBD_HID_Setup,
+ NULL, /* EP0_TxSent */
+ NULL, /* EP0_RxReady */
+ USBD_HID_DataIn,
+ USBD_HID_DataOut,
+ NULL, /* SOF */
+ NULL,
+ NULL,
+ USBD_HID_GetCfgDesc,
+ USBD_HID_GetCfgDesc,
+ USBD_HID_GetCfgDesc,
+ USBD_HID_GetDeviceQualifierDesc,
+};
+
+/* USB HID device configuration descriptor */
+__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+ 0x09, /* bLength: Configuration Descriptor size */
+ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
+ USB_HID_CONFIG_DESC_SIZ,
+ /* wTotalLength: Bytes returned */
+ 0x00,
+ 0x01, /*bNumInterfaces: 1 interface*/
+ 0x01, /*bConfigurationValue: Configuration value*/
+ 0x00, /*iConfiguration: Index of string descriptor describing
+ the configuration*/
+ 0xE0, /*bmAttributes: bus powered and Support Remote Wake-up */
+ 0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
+
+ /* Interface descriptor */
+ /* 09 */
+ 0x09, /*bLength: Interface Descriptor size*/
+ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
+ 0x00, /*bInterfaceNumber: Number of Interface*/
+ 0x00, /*bAlternateSetting: Alternate setting*/
+ HID_NUM_EP,
+
+ 0x03, /*bInterfaceClass: HID*/
+
+ 0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
+ 0x01, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
+ 0, /*iInterface: Index of string descriptor*/
+ /* HID descriptor */
+ /* 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_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
+ 0x00,
+ /* HID endpoint descriptor */
+ /* 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: 4 Byte max */
+ 0x00,
+ HID_FS_BINTERVAL, /*bInterval: Polling Interval (10 ms)*/
+ /* 34 */
+#if HID_LED_SUPPORT
+ 0x07, /*bLength: Endpoint Descriptor size*/
+ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
+
+ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
+ 0x03, /*bmAttributes: Interrupt endpoint*/
+ HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */
+ 0x00,
+ HID_FS_BINTERVAL, /*bInterval: Polling Interval (10 ms)*/
+#endif
+ /* 41 */
+
+} ;
+
+/* USB HID device Configuration Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_HID_Desc[USB_HID_DESC_SIZ] __ALIGN_END =
+{
+ /* 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_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
+ 0x00,
+};
+
+/* USB Standard Device Descriptor */
+__ALIGN_BEGIN static uint8_t USBD_HID_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
+{
+ USB_LEN_DEV_QUALIFIER_DESC,
+ USB_DESC_TYPE_DEVICE_QUALIFIER,
+ 0x00,
+ 0x02,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x40,
+ 0x01,
+ 0x00,
+};
+
+__ALIGN_BEGIN static uint8_t HID_ReportDesc[HID_REPORT_DESC_SIZE] __ALIGN_END =
+{
+ 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+ 0x09, 0x06, // USAGE (Keyboard)
+ 0xa1, 0x01, // COLLECTION (Application)
+ 0x85, 0x01, /* Report ID */
+ 0x05, 0x07, // USAGE_PAGE (Keyboard)
+ 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
+ 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x95, 0x08, // REPORT_COUNT (8)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x81, 0x03, // INPUT (Cnst,Var,Abs)
+ 0x95, 0x05, // REPORT_COUNT (5)
+ 0x75, 0x01, // REPORT_SIZE (1)
+ 0x05, 0x08, // USAGE_PAGE (LEDs)
+ 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
+ 0x29, 0x05, // USAGE_MAXIMUM (Kana)
+ 0x91, 0x02, // OUTPUT (Data,Var,Abs)
+ 0x95, 0x01, // REPORT_COUNT (1)
+ 0x75, 0x03, // REPORT_SIZE (3)
+ 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
+ 0x95, 0x06, // REPORT_COUNT (6)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x25, 0x65, // LOGICAL_MAXIMUM (101)
+ 0x05, 0x07, // USAGE_PAGE (Keyboard)
+ 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
+ 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
+ 0x81, 0x00, // INPUT (Data,Ary,Abs)
+ 0xc0, // End Collection
+ //
+ 0x05, 0x0C, /* Usage Page (Consumer Devices) */
+ 0x09, 0x01, /* Usage (Consumer Control) */
+ 0xA1, 0x01, /* Collection (Application) */
+ 0x85, 0x02, /* Report ID=2 */
+ 0x05, 0x0C, /* Usage Page (Consumer Devices) */
+ 0x15, 0x00, /* Logical Minimum (0) */
+ 0x25, 0x01, /* Logical Maximum (1) */
+ 0x75, 0x01, /* Report Size (1) */
+ 0x95, 0x07, /* Report Count (7) */
+ 0x09, 0xB5, /* Usage (Scan Next Track) */
+ 0x09, 0xB6, /* Usage (Scan Previous Track) */
+ 0x09, 0xB7, /* Usage (Stop) */
+ 0x09, 0xCD, /* Usage (Play / Pause) */
+ 0x09, 0xE2, /* Usage (Mute) */
+ 0x09, 0xE9, /* Usage (Volume Up) */
+ 0x09, 0xEA, /* Usage (Volume Down) */
+ 0x81, 0x02, /* Input (Data, Variable, Absolute) */
+ 0x95, 0x01, /* Report Count (1) */
+ 0x81, 0x01, /* Input (Constant) */
+ 0xC0, // End Collection
+
+ // how to format the 3 byte report
+ // byte 0 report ID = 0x02 (VOLUME_REPORT)
+ // byte 1 media code for ex VOL_UP 0xE9 , VOL_DONW 0xEA ... etc
+ // byte 2 0x00
+ // a second report with 0 code shal be send to avoid "key repaeat"
+};
+
+uint32_t nOutData;
+uint8_t OutDataBuffer[HID_EPOUT_SIZE]; // local copy for user (usb fly at same time)
+uint8_t OutData[HID_EPOUT_SIZE]; // live usb buffer
+
+
+static uint8_t USBD_HID_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx)
+{
+ USBD_LL_OpenEP(pdev, HID_EPIN_ADDR, USBD_EP_TYPE_INTR, HID_EPIN_SIZE);
+#if HID_LED_SUPPORT
+ USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE);
+#endif
+
+ pdev->pClassData = USBD_malloc(sizeof (USBD_HID_HandleTypeDef));
+
+ if(pdev->pClassData == NULL)
+ return 1;
+
+#if HID_LED_SUPPORT
+ USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR, OutData, HID_EPOUT_SIZE);
+#endif
+ ((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
+ return 0;
+}
+
+static uint8_t USBD_HID_DeInit (USBD_HandleTypeDef *pdev,
+ uint8_t cfgidx)
+{
+ USBD_LL_CloseEP(pdev, HID_EPIN_ADDR);
+ USBD_LL_CloseEP(pdev, HID_EPOUT_ADDR);
+
+ if(pdev->pClassData != NULL) {
+ USBD_free(pdev->pClassData);
+ pdev->pClassData = NULL;
+ }
+
+ return USBD_OK;
+}
+
+static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
+{
+ uint16_t len = 0;
+ uint8_t *pbuf = NULL;
+ USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*) pdev->pClassData;
+
+ 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;
+
+ 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_REPORT_DESC_SIZE , req->wLength);
+ pbuf = HID_ReportDesc;
+ }
+ else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE)
+ {
+ pbuf = USBD_HID_Desc;
+ len = MIN(USB_HID_DESC_SIZ , req->wLength);
+ }
+
+ USBD_CtlSendData (pdev,
+ pbuf,
+ len);
+
+ break;
+
+ case USB_REQ_GET_INTERFACE :
+ USBD_CtlSendData (pdev,
+ (uint8_t *)&hhid->AltSetting,
+ 1);
+ break;
+
+ case USB_REQ_SET_INTERFACE :
+ hhid->AltSetting = (uint8_t)(req->wValue);
+ break;
+ }
+ }
+ return USBD_OK;
+}
+
+uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len)
+{
+ USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;
+
+ if (pdev->dev_state != USBD_STATE_CONFIGURED )
+ return USBD_OK;
+
+ if(hhid->state == HID_IDLE)
+ return USBD_OK;
+
+ hhid->state = HID_BUSY;
+ USBD_LL_Transmit(pdev, HID_EPIN_ADDR, report, len);
+ return USBD_OK;
+}
+
+uint32_t USBD_HID_GetPollingInterval (USBD_HandleTypeDef *pdev)
+{
+ uint32_t polling_interval = 0;
+
+ /* HIGH-speed endpoints */
+ if(pdev->dev_speed == USBD_SPEED_HIGH)
+ {
+ /* Sets the data transfer polling interval for high speed transfers.
+ Values between 1..16 are allowed. Values correspond to interval
+ of 2 ^ (bInterval-1). This option (8 ms, corresponds to HID_HS_BINTERVAL */
+ polling_interval = (((1 <<(HID_HS_BINTERVAL - 1)))/8);
+ }
+ else /* LOW and FULL-speed endpoints */
+ {
+ /* Sets the data transfer polling interval for low and full
+ speed transfers */
+ polling_interval = HID_FS_BINTERVAL;
+ }
+
+ return ((uint32_t)(polling_interval));
+}
+
+static uint8_t *USBD_HID_GetCfgDesc (uint16_t *length)
+{
+ *length = sizeof (USBD_HID_CfgDesc);
+ return USBD_HID_CfgDesc;
+}
+
+
+static uint8_t USBD_HID_DataIn (USBD_HandleTypeDef *pdev,
+ uint8_t epnum)
+{
+ /* 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 */
+ ((USBD_HID_HandleTypeDef *)pdev->pClassData)->state = HID_IDLE;
+ return USBD_OK;
+}
+
+
+__weak void USBD_HID_GetReport(uint8_t *buf, int len){
+}
+
+static uint8_t USBD_HID_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum)
+{
+ int len;
+
+ nOutData++;
+ // data cpy so we can be ready for next usb out and used received data safely
+ len = USBD_LL_GetRxDataSize (pdev, epnum);
+ memcpy(OutDataBuffer, OutData, len);
+ USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR, OutData, HID_EPOUT_SIZE);
+ USBD_HID_GetReport(OutDataBuffer, len);
+ return USBD_OK;
+}
+
+static uint8_t *USBD_HID_GetDeviceQualifierDesc (uint16_t *length)
+{
+ *length = sizeof (USBD_HID_DeviceQualifierDesc);
+ return USBD_HID_DeviceQualifierDesc;
+}
+