/** ****************************************************************************** * @file usbh_hid.c * @author MCD Application Team * @brief This file is the HID Layer Handlers for USB Host HID class. * * @verbatim * * =================================================================== * HID Class Description * =================================================================== * This module manages the HID class V1.11 following the "Device Class Definition * for Human Interface Devices (HID) Version 1.11 Jun 27, 2001". * This driver implements the following aspects of the specification: * - The Boot Interface Subclass * - The Mouse and Keyboard protocols * * @endverbatim * ****************************************************************************** * @attention * *

© Copyright (c) 2015 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* BSPDependencies - "stm32xxxxx_{eval}{discovery}{nucleo_144}.c" - "stm32xxxxx_{eval}{discovery}_io.c" - "stm32xxxxx_{eval}{discovery}{adafruit}_lcd.c" - "stm32xxxxx_{eval}{discovery}_sdram.c" EndBSPDependencies */ /* Includes ------------------------------------------------------------------*/ #include "usbh_hid.h" #include "usbh_hid_parser.h" /** @addtogroup USBH_LIB * @{ */ /** @addtogroup USBH_CLASS * @{ */ /** @addtogroup USBH_HID_CLASS * @{ */ /** @defgroup USBH_HID_CORE * @brief This file includes HID Layer Handlers for USB Host HID class. * @{ */ /** @defgroup USBH_HID_CORE_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup USBH_HID_CORE_Private_Defines * @{ */ /** * @} */ /** @defgroup USBH_HID_CORE_Private_Macros * @{ */ /** * @} */ /** @defgroup USBH_HID_CORE_Private_Variables * @{ */ /** * @} */ /** @defgroup USBH_HID_CORE_Private_FunctionPrototypes * @{ */ static USBH_StatusTypeDef USBH_HID_InterfaceInit(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_HID_InterfaceDeInit(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost); static void USBH_HID_ParseHIDDesc(HID_DescTypeDef *desc, uint8_t *buf); extern USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost); extern USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost); USBH_ClassTypeDef HID_Class = { "HID", USB_HID_CLASS, USBH_HID_InterfaceInit, USBH_HID_InterfaceDeInit, USBH_HID_ClassRequest, USBH_HID_Process, USBH_HID_SOFProcess, NULL, }; /** * @} */ /** @defgroup USBH_HID_CORE_Private_Functions * @{ */ /** * @brief USBH_HID_InterfaceInit * The function init the HID class. * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HID_InterfaceInit(USBH_HandleTypeDef *phost) { USBH_StatusTypeDef status; HID_HandleTypeDef *HID_Handle; uint8_t max_ep; uint8_t num = 0U; uint8_t interface; interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, HID_BOOT_CODE, 0xFFU); if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES)) /* No Valid Interface */ { USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name); return USBH_FAIL; } status = USBH_SelectInterface(phost, interface); if (status != USBH_OK) { return USBH_FAIL; } phost->pActiveClass->pData = (HID_HandleTypeDef *)USBH_malloc(sizeof(HID_HandleTypeDef)); HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; if (HID_Handle == NULL) { USBH_DbgLog("Cannot allocate memory for HID Handle"); return USBH_FAIL; } /* Initialize hid handler */ USBH_memset(HID_Handle, 0, sizeof(HID_HandleTypeDef)); HID_Handle->state = HID_ERROR; /*Decode Bootclass Protocol: Mouse or Keyboard*/ if (phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE) { USBH_UsrLog("KeyBoard device found!"); HID_Handle->Init = USBH_HID_KeybdInit; } else if (phost->device.CfgDesc.Itf_Desc[interface].bInterfaceProtocol == HID_MOUSE_BOOT_CODE) { USBH_UsrLog("Mouse device found!"); HID_Handle->Init = USBH_HID_MouseInit; } else { USBH_UsrLog("Protocol not supported."); return USBH_FAIL; } HID_Handle->state = HID_INIT; HID_Handle->ctl_state = HID_REQ_INIT; HID_Handle->ep_addr = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress; HID_Handle->length = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; HID_Handle->poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval; if (HID_Handle->poll < HID_MIN_POLL) { HID_Handle->poll = HID_MIN_POLL; } /* Check fo available number of endpoints */ /* Find the number of EPs in the Interface Descriptor */ /* Choose the lower number in order not to overrun the buffer allocated */ max_ep = ((phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ? phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints : USBH_MAX_NUM_ENDPOINTS); /* Decode endpoint IN and OUT address from interface descriptor */ for (num = 0U; num < max_ep; num++) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[num].bEndpointAddress & 0x80U) { HID_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[num].bEndpointAddress); HID_Handle->InPipe = USBH_AllocPipe(phost, HID_Handle->InEp); /* Open pipe for IN endpoint */ USBH_OpenPipe(phost, HID_Handle->InPipe, HID_Handle->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_INTR, HID_Handle->length); USBH_LL_SetToggle(phost, HID_Handle->InPipe, 0U); } else { HID_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[num].bEndpointAddress); HID_Handle->OutPipe = USBH_AllocPipe(phost, HID_Handle->OutEp); /* Open pipe for OUT endpoint */ USBH_OpenPipe(phost, HID_Handle->OutPipe, HID_Handle->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_INTR, HID_Handle->length); USBH_LL_SetToggle(phost, HID_Handle->OutPipe, 0U); } } return USBH_OK; } /** * @brief USBH_HID_InterfaceDeInit * The function DeInit the Pipes used for the HID class. * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HID_InterfaceDeInit(USBH_HandleTypeDef *phost) { HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; if (HID_Handle->InPipe != 0x00U) { USBH_ClosePipe(phost, HID_Handle->InPipe); USBH_FreePipe(phost, HID_Handle->InPipe); HID_Handle->InPipe = 0U; /* Reset the pipe as Free */ } if (HID_Handle->OutPipe != 0x00U) { USBH_ClosePipe(phost, HID_Handle->OutPipe); USBH_FreePipe(phost, HID_Handle->OutPipe); HID_Handle->OutPipe = 0U; /* Reset the pipe as Free */ } if (phost->pActiveClass->pData) { USBH_free(phost->pActiveClass->pData); phost->pActiveClass->pData = 0U; } return USBH_OK; } /** * @brief USBH_HID_ClassRequest * The function is responsible for handling Standard requests * for HID class. * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HID_ClassRequest(USBH_HandleTypeDef *phost) { USBH_StatusTypeDef status = USBH_BUSY; USBH_StatusTypeDef classReqStatus = USBH_BUSY; HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; /* Switch HID state machine */ switch (HID_Handle->ctl_state) { case HID_REQ_INIT: case HID_REQ_GET_HID_DESC: USBH_HID_ParseHIDDesc(&HID_Handle->HID_Desc, phost->device.CfgDesc_Raw); HID_Handle->ctl_state = HID_REQ_GET_REPORT_DESC; break; case HID_REQ_GET_REPORT_DESC: /* Get Report Desc */ classReqStatus = USBH_HID_GetHIDReportDescriptor(phost, HID_Handle->HID_Desc.wItemLength); if (classReqStatus == USBH_OK) { /* The descriptor is available in phost->device.Data */ HID_Handle->ctl_state = HID_REQ_SET_IDLE; } else if (classReqStatus == USBH_NOT_SUPPORTED) { USBH_ErrLog("Control error: HID: Device Get Report Descriptor request failed"); status = USBH_FAIL; } else { /* .. */ } break; case HID_REQ_SET_IDLE: classReqStatus = USBH_HID_SetIdle(phost, 0U, 0U); /* set Idle */ if (classReqStatus == USBH_OK) { HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL; } else { if (classReqStatus == USBH_NOT_SUPPORTED) { HID_Handle->ctl_state = HID_REQ_SET_PROTOCOL; } } break; case HID_REQ_SET_PROTOCOL: /* set protocol */ classReqStatus = USBH_HID_SetProtocol(phost, 0U); if (classReqStatus == USBH_OK) { HID_Handle->ctl_state = HID_REQ_IDLE; /* all requests performed*/ phost->pUser(phost, HOST_USER_CLASS_ACTIVE); status = USBH_OK; } else if (classReqStatus == USBH_NOT_SUPPORTED) { USBH_ErrLog("Control error: HID: Device Set protocol request failed"); status = USBH_FAIL; } else { /* .. */ } break; case HID_REQ_IDLE: default: break; } return status; } /** * @brief USBH_HID_Process * The function is for managing state machine for HID data transfers * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HID_Process(USBH_HandleTypeDef *phost) { USBH_StatusTypeDef status = USBH_OK; HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; uint32_t XferSize; switch (HID_Handle->state) { case HID_INIT: HID_Handle->Init(phost); HID_Handle->state = HID_IDLE; #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_URB_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HID_IDLE: status = USBH_HID_GetReport(phost, 0x01U, 0U, HID_Handle->pData, (uint8_t)HID_Handle->length); if (status == USBH_OK) { HID_Handle->state = HID_SYNC; } else if (status == USBH_BUSY) { HID_Handle->state = HID_IDLE; status = USBH_OK; } else if (status == USBH_NOT_SUPPORTED) { HID_Handle->state = HID_SYNC; status = USBH_OK; } else { HID_Handle->state = HID_ERROR; status = USBH_FAIL; } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_URB_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HID_SYNC: /* Sync with start of Even Frame */ if (phost->Timer & 1U) { HID_Handle->state = HID_GET_DATA; } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_URB_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case HID_GET_DATA: USBH_InterruptReceiveData(phost, HID_Handle->pData, (uint8_t)HID_Handle->length, HID_Handle->InPipe); HID_Handle->state = HID_POLL; HID_Handle->timer = phost->Timer; HID_Handle->DataReady = 0U; break; case HID_POLL: if (USBH_LL_GetURBState(phost, HID_Handle->InPipe) == USBH_URB_DONE) { XferSize = USBH_LL_GetLastXferSize(phost, HID_Handle->InPipe); if ((HID_Handle->DataReady == 0U) && (XferSize != 0U)) { USBH_HID_FifoWrite(&HID_Handle->fifo, HID_Handle->pData, HID_Handle->length); HID_Handle->DataReady = 1U; USBH_HID_EventCallback(phost); #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_URB_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif } } else { /* IN Endpoint Stalled */ if (USBH_LL_GetURBState(phost, HID_Handle->InPipe) == USBH_URB_STALL) { /* Issue Clear Feature on interrupt IN endpoint */ if (USBH_ClrFeature(phost, HID_Handle->ep_addr) == USBH_OK) { /* Change state to issue next IN token */ HID_Handle->state = HID_GET_DATA; } } } break; default: break; } return status; } /** * @brief USBH_HID_SOFProcess * The function is for managing the SOF Process * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_HID_SOFProcess(USBH_HandleTypeDef *phost) { HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; if (HID_Handle->state == HID_POLL) { if ((phost->Timer - HID_Handle->timer) >= HID_Handle->poll) { HID_Handle->state = HID_GET_DATA; #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_URB_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif } } return USBH_OK; } /** * @brief USBH_Get_HID_ReportDescriptor * Issue report Descriptor command to the device. Once the response * received, parse the report descriptor and update the status. * @param phost: Host handle * @param Length : HID Report Descriptor Length * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_GetHIDReportDescriptor(USBH_HandleTypeDef *phost, uint16_t length) { USBH_StatusTypeDef status; status = USBH_GetDescriptor(phost, USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD, USB_DESC_HID_REPORT, phost->device.Data, length); /* HID report descriptor is available in phost->device.Data. In case of USB Boot Mode devices for In report handling , HID report descriptor parsing is not required. In case, for supporting Non-Boot Protocol devices and output reports, user may parse the report descriptor*/ return status; } /** * @brief USBH_Get_HID_Descriptor * Issue HID Descriptor command to the device. Once the response * received, parse the report descriptor and update the status. * @param phost: Host handle * @param Length : HID Descriptor Length * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_GetHIDDescriptor(USBH_HandleTypeDef *phost, uint16_t length) { USBH_StatusTypeDef status; status = USBH_GetDescriptor(phost, USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_STANDARD, USB_DESC_HID, phost->device.Data, length); return status; } /** * @brief USBH_Set_Idle * Set Idle State. * @param phost: Host handle * @param duration: Duration for HID Idle request * @param reportId : Targeted report ID for Set Idle request * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_SetIdle(USBH_HandleTypeDef *phost, uint8_t duration, uint8_t reportId) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_IDLE; phost->Control.setup.b.wValue.w = (uint16_t)(((uint32_t)duration << 8U) | (uint32_t)reportId); phost->Control.setup.b.wIndex.w = 0U; phost->Control.setup.b.wLength.w = 0U; return USBH_CtlReq(phost, 0U, 0U); } /** * @brief USBH_HID_Set_Report * Issues Set Report * @param phost: Host handle * @param reportType : Report type to be sent * @param reportId : Targeted report ID for Set Report request * @param reportBuff : Report Buffer * @param reportLen : Length of data report to be send * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_SetReport(USBH_HandleTypeDef *phost, uint8_t reportType, uint8_t reportId, uint8_t *reportBuff, uint8_t reportLen) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_REPORT; phost->Control.setup.b.wValue.w = (uint16_t)(((uint32_t)reportType << 8U) | (uint32_t)reportId); phost->Control.setup.b.wIndex.w = 0U; phost->Control.setup.b.wLength.w = reportLen; return USBH_CtlReq(phost, reportBuff, (uint16_t)reportLen); } /** * @brief USBH_HID_GetReport * retreive Set Report * @param phost: Host handle * @param reportType : Report type to be sent * @param reportId : Targeted report ID for Set Report request * @param reportBuff : Report Buffer * @param reportLen : Length of data report to be send * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_GetReport(USBH_HandleTypeDef *phost, uint8_t reportType, uint8_t reportId, uint8_t *reportBuff, uint8_t reportLen) { phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \ USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_GET_REPORT; phost->Control.setup.b.wValue.w = (uint16_t)(((uint32_t)reportType << 8U) | (uint32_t)reportId); phost->Control.setup.b.wIndex.w = 0U; phost->Control.setup.b.wLength.w = reportLen; return USBH_CtlReq(phost, reportBuff, (uint16_t)reportLen); } /** * @brief USBH_Set_Protocol * Set protocol State. * @param phost: Host handle * @param protocol : Set Protocol for HID : boot/report protocol * @retval USBH Status */ USBH_StatusTypeDef USBH_HID_SetProtocol(USBH_HandleTypeDef *phost, uint8_t protocol) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_CLASS; phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL; if (protocol) { phost->Control.setup.b.wValue.w = 0U; } else { phost->Control.setup.b.wValue.w = 1U; } phost->Control.setup.b.wIndex.w = 0U; phost->Control.setup.b.wLength.w = 0U; return USBH_CtlReq(phost, 0U, 0U); } /** * @brief USBH_ParseHIDDesc * This function Parse the HID descriptor * @param desc: HID Descriptor * @param buf: Buffer where the source descriptor is available * @retval None */ static void USBH_HID_ParseHIDDesc(HID_DescTypeDef *desc, uint8_t *buf) { USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)buf; uint16_t CfgDescLen; uint16_t ptr; CfgDescLen = LE16(buf + 2U); if (CfgDescLen > USB_CONFIGURATION_DESC_SIZE) { ptr = USB_LEN_CFG_DESC; while (ptr < CfgDescLen) { pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr); if (pdesc->bDescriptorType == USB_DESC_TYPE_HID) { desc->bLength = *(uint8_t *)((uint8_t *)pdesc + 0U); desc->bDescriptorType = *(uint8_t *)((uint8_t *)pdesc + 1U); desc->bcdHID = LE16((uint8_t *)pdesc + 2U); desc->bCountryCode = *(uint8_t *)((uint8_t *)pdesc + 4U); desc->bNumDescriptors = *(uint8_t *)((uint8_t *)pdesc + 5U); desc->bReportDescriptorType = *(uint8_t *)((uint8_t *)pdesc + 6U); desc->wItemLength = LE16((uint8_t *)pdesc + 7U); break; } } } } /** * @brief USBH_HID_GetDeviceType * Return Device function. * @param phost: Host handle * @retval HID function: HID_MOUSE / HID_KEYBOARD */ HID_TypeTypeDef USBH_HID_GetDeviceType(USBH_HandleTypeDef *phost) { HID_TypeTypeDef type = HID_UNKNOWN; uint8_t InterfaceProtocol; if (phost->gState == HOST_CLASS) { InterfaceProtocol = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].bInterfaceProtocol; if (InterfaceProtocol == HID_KEYBRD_BOOT_CODE) { type = HID_KEYBOARD; } else { if (InterfaceProtocol == HID_MOUSE_BOOT_CODE) { type = HID_MOUSE; } } } return type; } /** * @brief USBH_HID_GetPollInterval * Return HID device poll time * @param phost: Host handle * @retval poll time (ms) */ uint8_t USBH_HID_GetPollInterval(USBH_HandleTypeDef *phost) { HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData; if ((phost->gState == HOST_CLASS_REQUEST) || (phost->gState == HOST_INPUT) || (phost->gState == HOST_SET_CONFIGURATION) || (phost->gState == HOST_CHECK_CLASS) || ((phost->gState == HOST_CLASS))) { return (uint8_t)(HID_Handle->poll); } else { return 0U; } } /** * @brief USBH_HID_FifoInit * Initialize FIFO. * @param f: Fifo address * @param buf: Fifo buffer * @param size: Fifo Size * @retval none */ void USBH_HID_FifoInit(FIFO_TypeDef *f, uint8_t *buf, uint16_t size) { f->head = 0U; f->tail = 0U; f->lock = 0U; f->size = size; f->buf = buf; } /** * @brief USBH_HID_FifoRead * Read from FIFO. * @param f: Fifo address * @param buf: read buffer * @param nbytes: number of item to read * @retval number of read items */ uint16_t USBH_HID_FifoRead(FIFO_TypeDef *f, void *buf, uint16_t nbytes) { uint16_t i; uint8_t *p; p = (uint8_t *) buf; if (f->lock == 0U) { f->lock = 1U; for (i = 0U; i < nbytes; i++) { if (f->tail != f->head) { *p++ = f->buf[f->tail]; f->tail++; if (f->tail == f->size) { f->tail = 0U; } } else { f->lock = 0U; return i; } } } f->lock = 0U; return nbytes; } /** * @brief USBH_HID_FifoWrite * Write To FIFO. * @param f: Fifo address * @param buf: read buffer * @param nbytes: number of item to write * @retval number of written items */ uint16_t USBH_HID_FifoWrite(FIFO_TypeDef *f, void *buf, uint16_t nbytes) { uint16_t i; uint8_t *p; p = (uint8_t *) buf; if (f->lock == 0U) { f->lock = 1U; for (i = 0U; i < nbytes; i++) { if ((f->head + 1U == f->tail) || ((f->head + 1U == f->size) && (f->tail == 0U))) { f->lock = 0U; return i; } else { f->buf[f->head] = *p++; f->head++; if (f->head == f->size) { f->head = 0U; } } } } f->lock = 0U; return nbytes; } /** * @brief The function is a callback about HID Data events * @param phost: Selected device * @retval None */ __weak void USBH_HID_EventCallback(USBH_HandleTypeDef *phost) { /* Prevent unused argument(s) compilation warning */ UNUSED(phost); } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/