--- /dev/null
+/**
+ ******************************************************************************
+ * @file usbh_hid_core.c
+ * @author MCD Application Team
+ * @version V2.0.0
+ * @date 22-July-2011
+ * @brief This file is the HID Layer Handlers for USB Host HID class.
+ *
+ * @verbatim
+ *
+ * ===================================================================
+ * HID Class Description
+ * ===================================================================
+ * This module manages the MSC 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
+ *
+ * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbh_hid_core.h"
+#include "usbh_hid_mouse.h"
+#include "usbh_hid_keybd.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
+* @{
+*/
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+ #pragma data_alignment=4
+ #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+__ALIGN_BEGIN HID_Machine_TypeDef HID_Machine __ALIGN_END ;
+
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+ #pragma data_alignment=4
+ #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+__ALIGN_BEGIN HID_Report_TypeDef HID_Report __ALIGN_END ;
+
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+ #pragma data_alignment=4
+ #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+__ALIGN_BEGIN USB_Setup_TypeDef HID_Setup __ALIGN_END ;
+
+#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
+ #if defined ( __ICCARM__ ) /*!< IAR Compiler */
+ #pragma data_alignment=4
+ #endif
+#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
+__ALIGN_BEGIN USBH_HIDDesc_TypeDef HID_Desc __ALIGN_END ;
+
+__IO uint8_t flag = 0;
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_FunctionPrototypes
+* @{
+*/
+
+static USBH_Status USBH_HID_InterfaceInit (USB_OTG_CORE_HANDLE *pdev ,
+ void *phost);
+
+static void USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf);
+
+static void USBH_HID_InterfaceDeInit (USB_OTG_CORE_HANDLE *pdev ,
+ void *phost);
+
+static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev ,
+ void *phost);
+
+static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
+ void *phost);
+
+static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *phost,
+ uint16_t length);
+
+static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,\
+ USBH_HOST *phost,
+ uint16_t length);
+
+static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *phost,
+ uint8_t duration,
+ uint8_t reportId);
+
+static USBH_Status USBH_Set_Protocol (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *phost,
+ uint8_t protocol);
+
+
+USBH_Class_cb_TypeDef HID_cb =
+{
+ USBH_HID_InterfaceInit,
+ USBH_HID_InterfaceDeInit,
+ USBH_HID_ClassRequest,
+ USBH_HID_Handle
+};
+/**
+* @}
+*/
+
+
+/** @defgroup USBH_HID_CORE_Private_Functions
+* @{
+*/
+
+/**
+* @brief USBH_HID_InterfaceInit
+* The function init the HID class.
+* @param pdev: Selected device
+* @param hdev: Selected device property
+* @retval USBH_Status :Response for USB HID driver intialization
+*/
+static USBH_Status USBH_HID_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev,
+ void *phost)
+{
+ uint8_t maxEP;
+ USBH_HOST *pphost = phost;
+
+ uint8_t num =0;
+ USBH_Status status = USBH_BUSY ;
+ HID_Machine.state = HID_ERROR;
+
+
+ if(pphost->device_prop.Itf_Desc[0].bInterfaceSubClass == HID_BOOT_CODE)
+ {
+ /*Decode Bootclass Protocl: Mouse or Keyboard*/
+ if(pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE)
+ {
+ HID_Machine.cb = &HID_KEYBRD_cb;
+ }
+ else if(pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == HID_MOUSE_BOOT_CODE)
+ {
+ HID_Machine.cb = &HID_MOUSE_cb;
+ }
+
+ HID_Machine.state = HID_IDLE;
+ HID_Machine.ctl_state = HID_REQ_IDLE;
+ HID_Machine.ep_addr = pphost->device_prop.Ep_Desc[0][0].bEndpointAddress;
+ HID_Machine.length = pphost->device_prop.Ep_Desc[0][0].wMaxPacketSize;
+ HID_Machine.poll = pphost->device_prop.Ep_Desc[0][0].bInterval ;
+
+ /* 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 */
+ maxEP = ( (pphost->device_prop.Itf_Desc[0].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
+ pphost->device_prop.Itf_Desc[0].bNumEndpoints :
+ USBH_MAX_NUM_ENDPOINTS);
+
+
+ /* Decode endpoint IN and OUT address from interface descriptor */
+ for (num=0; num < maxEP; num++)
+ {
+ if(pphost->device_prop.Ep_Desc[0][num].bEndpointAddress & 0x80)
+ {
+ HID_Machine.HIDIntInEp = (pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
+ HID_Machine.hc_num_in =\
+ USBH_Alloc_Channel(pdev,
+ pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
+
+ /* Open channel for IN endpoint */
+ USBH_Open_Channel (pdev,
+ HID_Machine.hc_num_in,
+ pphost->device_prop.address,
+ pphost->device_prop.speed,
+ EP_TYPE_INTR,
+ HID_Machine.length);
+ }
+ else
+ {
+ HID_Machine.HIDIntOutEp = (pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
+ HID_Machine.hc_num_out =\
+ USBH_Alloc_Channel(pdev,
+ pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
+
+ /* Open channel for OUT endpoint */
+ USBH_Open_Channel (pdev,
+ HID_Machine.hc_num_out,
+ pphost->device_prop.address,
+ pphost->device_prop.speed,
+ EP_TYPE_INTR,
+ HID_Machine.length);
+ }
+
+ }
+
+ flag =0;
+ status = USBH_OK;
+ }
+ else
+ {
+ pphost->usr_cb->USBH_USR_DeviceNotSupported();
+ }
+
+ return status;
+
+}
+
+
+
+/**
+* @brief USBH_HID_InterfaceDeInit
+* The function DeInit the Host Channels used for the HID class.
+* @param pdev: Selected device
+* @param hdev: Selected device property
+* @retval None
+*/
+void USBH_HID_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
+ void *phost)
+{
+ //USBH_HOST *pphost = phost;
+
+ if(HID_Machine.hc_num_in != 0x00)
+ {
+ USB_OTG_HC_Halt(pdev, HID_Machine.hc_num_in);
+ USBH_Free_Channel (pdev, HID_Machine.hc_num_in);
+ HID_Machine.hc_num_in = 0; /* Reset the Channel as Free */
+ }
+
+ if(HID_Machine.hc_num_out != 0x00)
+ {
+ USB_OTG_HC_Halt(pdev, HID_Machine.hc_num_out);
+ USBH_Free_Channel (pdev, HID_Machine.hc_num_out);
+ HID_Machine.hc_num_out = 0; /* Reset the Channel as Free */
+ }
+
+ flag = 0;
+}
+
+/**
+* @brief USBH_HID_ClassRequest
+* The function is responsible for handling HID Class requests
+* for HID class.
+* @param pdev: Selected device
+* @param hdev: Selected device property
+* @retval USBH_Status :Response for USB Set Protocol request
+*/
+static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
+ void *phost)
+{
+ USBH_HOST *pphost = phost;
+
+ USBH_Status status = USBH_BUSY;
+ USBH_Status classReqStatus = USBH_BUSY;
+
+
+ /* Switch HID state machine */
+ switch (HID_Machine.ctl_state)
+ {
+ case HID_IDLE:
+ case HID_REQ_GET_HID_DESC:
+
+ /* Get HID Desc */
+ if (USBH_Get_HID_Descriptor (pdev, pphost, USB_HID_DESC_SIZE)== USBH_OK)
+ {
+
+ USBH_ParseHIDDesc(&HID_Desc, pdev->host.Rx_Buffer);
+ HID_Machine.ctl_state = HID_REQ_GET_REPORT_DESC;
+ }
+
+ break;
+ case HID_REQ_GET_REPORT_DESC:
+
+
+ /* Get Report Desc */
+ if (USBH_Get_HID_ReportDescriptor(pdev , pphost, HID_Desc.wItemLength) == USBH_OK)
+ {
+ HID_Machine.ctl_state = HID_REQ_SET_IDLE;
+ }
+
+ break;
+
+ case HID_REQ_SET_IDLE:
+
+ classReqStatus = USBH_Set_Idle (pdev, pphost, 0, 0);
+
+ /* set Idle */
+ if (classReqStatus == USBH_OK)
+ {
+ HID_Machine.ctl_state = HID_REQ_SET_PROTOCOL;
+ }
+ else if(classReqStatus == USBH_NOT_SUPPORTED)
+ {
+ HID_Machine.ctl_state = HID_REQ_SET_PROTOCOL;
+ }
+ break;
+
+ case HID_REQ_SET_PROTOCOL:
+ /* set protocol */
+ if (USBH_Set_Protocol (pdev ,pphost, 0) == USBH_OK)
+ {
+ HID_Machine.ctl_state = HID_REQ_IDLE;
+
+ /* all requests performed*/
+ status = USBH_OK;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return status;
+}
+
+
+/**
+* @brief USBH_HID_Handle
+* The function is for managing state machine for HID data transfers
+* @param pdev: Selected device
+* @param hdev: Selected device property
+* @retval USBH_Status
+*/
+static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev ,
+ void *phost)
+{
+ USBH_HOST *pphost = phost;
+ USBH_Status status = USBH_OK;
+
+ switch (HID_Machine.state)
+ {
+
+ case HID_IDLE:
+ HID_Machine.cb->Init();
+ HID_Machine.state = HID_GET_DATA;
+ break;
+
+ case HID_GET_DATA:
+
+ /* Sync with start of Even Frame */
+ while(USB_OTG_IsEvenFrame(pdev) == FALSE);
+
+ USBH_InterruptReceiveData(pdev,
+ HID_Machine.buff,
+ HID_Machine.length,
+ HID_Machine.hc_num_in);
+ flag = 1;
+
+ HID_Machine.state = HID_POLL;
+ HID_Machine.timer = HCD_GetCurrentFrame(pdev);
+ break;
+
+ case HID_POLL:
+ if(( HCD_GetCurrentFrame(pdev) - HID_Machine.timer) >= HID_Machine.poll)
+ {
+ HID_Machine.state = HID_GET_DATA;
+ }
+ else if(HCD_GetURB_State(pdev , HID_Machine.hc_num_in) == URB_DONE)
+ {
+ if(flag == 1) /* handle data once */
+ {
+ flag = 0;
+ HID_Machine.cb->Decode(HID_Machine.buff);
+ }
+ }
+ else if(HCD_GetURB_State(pdev, HID_Machine.hc_num_in) == URB_STALL) /* IN Endpoint Stalled */
+ {
+
+ /* Issue Clear Feature on interrupt IN endpoint */
+ if( (USBH_ClrFeature(pdev,
+ pphost,
+ HID_Machine.ep_addr,
+ HID_Machine.hc_num_in)) == USBH_OK)
+ {
+ /* Change state to issue next IN token */
+ HID_Machine.state = HID_GET_DATA;
+
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }
+ return status;
+}
+
+
+/**
+* @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 pdev : Selected device
+* @param Length : HID Report Descriptor Length
+* @retval USBH_Status : Response for USB HID Get Report Descriptor Request
+*/
+static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *phost,
+ uint16_t length)
+{
+
+ USBH_Status status;
+
+ status = USBH_GetDescriptor(pdev,
+ phost,
+ USB_REQ_RECIPIENT_INTERFACE
+ | USB_REQ_TYPE_STANDARD,
+ USB_DESC_HID_REPORT,
+ pdev->host.Rx_Buffer,
+ length);
+
+ /* HID report descriptor is available in pdev->host.Rx_Buffer.
+ 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 pdev : Selected device
+* @param Length : HID Descriptor Length
+* @retval USBH_Status : Response for USB HID Get Report Descriptor Request
+*/
+static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *phost,
+ uint16_t length)
+{
+
+ USBH_Status status;
+
+ status = USBH_GetDescriptor(pdev,
+ phost,
+ USB_REQ_RECIPIENT_INTERFACE
+ | USB_REQ_TYPE_STANDARD,
+ USB_DESC_HID,
+ pdev->host.Rx_Buffer,
+ length);
+
+ return status;
+}
+
+/**
+* @brief USBH_Set_Idle
+* Set Idle State.
+* @param pdev: Selected device
+* @param duration: Duration for HID Idle request
+* @param reportID : Targetted report ID for Set Idle request
+* @retval USBH_Status : Response for USB Set Idle request
+*/
+static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *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 = (duration << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+
+ return USBH_CtlReq(pdev, phost, 0 , 0 );
+}
+
+
+/**
+* @brief USBH_Set_Report
+* Issues Set Report
+* @param pdev: Selected device
+* @param reportType : Report type to be sent
+* @param reportID : Targetted report ID for Set Report request
+* @param reportLen : Length of data report to be send
+* @param reportBuff : Report Buffer
+* @retval USBH_Status : Response for USB Set Idle request
+*/
+USBH_Status USBH_Set_Report (USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *phost,
+ uint8_t reportType,
+ uint8_t reportId,
+ uint8_t reportLen,
+ uint8_t* reportBuff)
+{
+
+ 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 = (reportType << 8 ) | reportId;
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = reportLen;
+
+ return USBH_CtlReq(pdev, phost, reportBuff , reportLen );
+}
+
+
+/**
+* @brief USBH_Set_Protocol
+* Set protocol State.
+* @param pdev: Selected device
+* @param protocol : Set Protocol for HID : boot/report protocol
+* @retval USBH_Status : Response for USB Set Protocol request
+*/
+static USBH_Status USBH_Set_Protocol(USB_OTG_CORE_HANDLE *pdev,
+ USBH_HOST *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 != 0)
+ {
+ /* Boot Protocol */
+ phost->Control.setup.b.wValue.w = 0;
+ }
+ else
+ {
+ /*Report Protocol*/
+ phost->Control.setup.b.wValue.w = 1;
+ }
+
+ phost->Control.setup.b.wIndex.w = 0;
+ phost->Control.setup.b.wLength.w = 0;
+
+ return USBH_CtlReq(pdev, phost, 0 , 0 );
+
+}
+
+/**
+* @brief USBH_ParseHIDDesc
+* This function Parse the HID descriptor
+* @param buf: Buffer where the source descriptor is available
+* @retval None
+*/
+static void USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf)
+{
+
+ desc->bLength = *(uint8_t *) (buf + 0);
+ desc->bDescriptorType = *(uint8_t *) (buf + 1);
+ desc->bcdHID = LE16 (buf + 2);
+ desc->bCountryCode = *(uint8_t *) (buf + 4);
+ desc->bNumDescriptors = *(uint8_t *) (buf + 5);
+ desc->bReportDescriptorType = *(uint8_t *) (buf + 6);
+ desc->wItemLength = LE16 (buf + 7);
+
+}
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+
+/**
+* @}
+*/
+
+/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/