2 ******************************************************************************
3 * @file usbh_hid_core.c
4 * @author MCD Application Team
7 * @brief This file is the HID Layer Handlers for USB Host HID class.
11 * ===================================================================
12 * HID Class Description
13 * ===================================================================
14 * This module manages the MSC class V1.11 following the "Device Class Definition
15 * for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
16 * This driver implements the following aspects of the specification:
17 * - The Boot Interface Subclass
18 * - The Mouse and Keyboard protocols
22 ******************************************************************************
25 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
26 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
27 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
28 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
29 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
30 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
32 * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
33 ******************************************************************************
36 /* Includes ------------------------------------------------------------------*/
37 #include "usbh_hid_core.h"
38 #include "usbh_hid_mouse.h"
39 #include "usbh_hid_keybd.h"
41 /** @addtogroup USBH_LIB
45 /** @addtogroup USBH_CLASS
49 /** @addtogroup USBH_HID_CLASS
53 /** @defgroup USBH_HID_CORE
54 * @brief This file includes HID Layer Handlers for USB Host HID class.
58 /** @defgroup USBH_HID_CORE_Private_TypesDefinitions
66 /** @defgroup USBH_HID_CORE_Private_Defines
74 /** @defgroup USBH_HID_CORE_Private_Macros
82 /** @defgroup USBH_HID_CORE_Private_Variables
85 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
86 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
87 #pragma data_alignment=4
89 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
90 __ALIGN_BEGIN HID_Machine_TypeDef HID_Machine __ALIGN_END ;
92 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
93 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
94 #pragma data_alignment=4
96 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
97 __ALIGN_BEGIN HID_Report_TypeDef HID_Report __ALIGN_END ;
99 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
100 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
101 #pragma data_alignment=4
103 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
104 __ALIGN_BEGIN USB_Setup_TypeDef HID_Setup __ALIGN_END ;
106 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
107 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
108 #pragma data_alignment=4
110 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
111 __ALIGN_BEGIN USBH_HIDDesc_TypeDef HID_Desc __ALIGN_END ;
113 __IO uint8_t flag = 0;
119 /** @defgroup USBH_HID_CORE_Private_FunctionPrototypes
123 static USBH_Status USBH_HID_InterfaceInit (USB_OTG_CORE_HANDLE *pdev ,
126 static void USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf);
128 static void USBH_HID_InterfaceDeInit (USB_OTG_CORE_HANDLE *pdev ,
131 static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev ,
134 static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
137 static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
141 static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,\
145 static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
150 static USBH_Status USBH_Set_Protocol (USB_OTG_CORE_HANDLE *pdev,
155 USBH_Class_cb_TypeDef HID_cb =
157 USBH_HID_InterfaceInit,
158 USBH_HID_InterfaceDeInit,
159 USBH_HID_ClassRequest,
167 /** @defgroup USBH_HID_CORE_Private_Functions
172 * @brief USBH_HID_InterfaceInit
173 * The function init the HID class.
174 * @param pdev: Selected device
175 * @param hdev: Selected device property
176 * @retval USBH_Status :Response for USB HID driver intialization
178 static USBH_Status USBH_HID_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev,
182 USBH_HOST *pphost = phost;
185 USBH_Status status = USBH_BUSY ;
186 HID_Machine.state = HID_ERROR;
189 if(pphost->device_prop.Itf_Desc[0].bInterfaceSubClass == HID_BOOT_CODE)
191 /*Decode Bootclass Protocl: Mouse or Keyboard*/
192 if(pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE)
194 HID_Machine.cb = &HID_KEYBRD_cb;
196 else if(pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == HID_MOUSE_BOOT_CODE)
198 HID_Machine.cb = &HID_MOUSE_cb;
201 HID_Machine.state = HID_IDLE;
202 HID_Machine.ctl_state = HID_REQ_IDLE;
203 HID_Machine.ep_addr = pphost->device_prop.Ep_Desc[0][0].bEndpointAddress;
204 HID_Machine.length = pphost->device_prop.Ep_Desc[0][0].wMaxPacketSize;
205 HID_Machine.poll = pphost->device_prop.Ep_Desc[0][0].bInterval ;
207 /* Check fo available number of endpoints */
208 /* Find the number of EPs in the Interface Descriptor */
209 /* Choose the lower number in order not to overrun the buffer allocated */
210 maxEP = ( (pphost->device_prop.Itf_Desc[0].bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) ?
211 pphost->device_prop.Itf_Desc[0].bNumEndpoints :
212 USBH_MAX_NUM_ENDPOINTS);
215 /* Decode endpoint IN and OUT address from interface descriptor */
216 for (num=0; num < maxEP; num++)
218 if(pphost->device_prop.Ep_Desc[0][num].bEndpointAddress & 0x80)
220 HID_Machine.HIDIntInEp = (pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
221 HID_Machine.hc_num_in =\
222 USBH_Alloc_Channel(pdev,
223 pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
225 /* Open channel for IN endpoint */
226 USBH_Open_Channel (pdev,
227 HID_Machine.hc_num_in,
228 pphost->device_prop.address,
229 pphost->device_prop.speed,
235 HID_Machine.HIDIntOutEp = (pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
236 HID_Machine.hc_num_out =\
237 USBH_Alloc_Channel(pdev,
238 pphost->device_prop.Ep_Desc[0][num].bEndpointAddress);
240 /* Open channel for OUT endpoint */
241 USBH_Open_Channel (pdev,
242 HID_Machine.hc_num_out,
243 pphost->device_prop.address,
244 pphost->device_prop.speed,
256 pphost->usr_cb->USBH_USR_DeviceNotSupported();
266 * @brief USBH_HID_InterfaceDeInit
267 * The function DeInit the Host Channels used for the HID class.
268 * @param pdev: Selected device
269 * @param hdev: Selected device property
272 void USBH_HID_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
275 //USBH_HOST *pphost = phost;
277 if(HID_Machine.hc_num_in != 0x00)
279 USB_OTG_HC_Halt(pdev, HID_Machine.hc_num_in);
280 USBH_Free_Channel (pdev, HID_Machine.hc_num_in);
281 HID_Machine.hc_num_in = 0; /* Reset the Channel as Free */
284 if(HID_Machine.hc_num_out != 0x00)
286 USB_OTG_HC_Halt(pdev, HID_Machine.hc_num_out);
287 USBH_Free_Channel (pdev, HID_Machine.hc_num_out);
288 HID_Machine.hc_num_out = 0; /* Reset the Channel as Free */
295 * @brief USBH_HID_ClassRequest
296 * The function is responsible for handling HID Class requests
298 * @param pdev: Selected device
299 * @param hdev: Selected device property
300 * @retval USBH_Status :Response for USB Set Protocol request
302 static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev ,
305 USBH_HOST *pphost = phost;
307 USBH_Status status = USBH_BUSY;
308 USBH_Status classReqStatus = USBH_BUSY;
311 /* Switch HID state machine */
312 switch (HID_Machine.ctl_state)
315 case HID_REQ_GET_HID_DESC:
318 if (USBH_Get_HID_Descriptor (pdev, pphost, USB_HID_DESC_SIZE)== USBH_OK)
321 USBH_ParseHIDDesc(&HID_Desc, pdev->host.Rx_Buffer);
322 HID_Machine.ctl_state = HID_REQ_GET_REPORT_DESC;
326 case HID_REQ_GET_REPORT_DESC:
329 /* Get Report Desc */
330 if (USBH_Get_HID_ReportDescriptor(pdev , pphost, HID_Desc.wItemLength) == USBH_OK)
332 HID_Machine.ctl_state = HID_REQ_SET_IDLE;
337 case HID_REQ_SET_IDLE:
339 classReqStatus = USBH_Set_Idle (pdev, pphost, 0, 0);
342 if (classReqStatus == USBH_OK)
344 HID_Machine.ctl_state = HID_REQ_SET_PROTOCOL;
346 else if(classReqStatus == USBH_NOT_SUPPORTED)
348 HID_Machine.ctl_state = HID_REQ_SET_PROTOCOL;
352 case HID_REQ_SET_PROTOCOL:
354 if (USBH_Set_Protocol (pdev ,pphost, 0) == USBH_OK)
356 HID_Machine.ctl_state = HID_REQ_IDLE;
358 /* all requests performed*/
372 * @brief USBH_HID_Handle
373 * The function is for managing state machine for HID data transfers
374 * @param pdev: Selected device
375 * @param hdev: Selected device property
376 * @retval USBH_Status
378 static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev ,
381 USBH_HOST *pphost = phost;
382 USBH_Status status = USBH_OK;
384 switch (HID_Machine.state)
388 HID_Machine.cb->Init();
389 HID_Machine.state = HID_GET_DATA;
394 /* Sync with start of Even Frame */
395 while(USB_OTG_IsEvenFrame(pdev) == FALSE);
397 USBH_InterruptReceiveData(pdev,
400 HID_Machine.hc_num_in);
403 HID_Machine.state = HID_POLL;
404 HID_Machine.timer = HCD_GetCurrentFrame(pdev);
408 if(( HCD_GetCurrentFrame(pdev) - HID_Machine.timer) >= HID_Machine.poll)
410 HID_Machine.state = HID_GET_DATA;
412 else if(HCD_GetURB_State(pdev , HID_Machine.hc_num_in) == URB_DONE)
414 if(flag == 1) /* handle data once */
417 HID_Machine.cb->Decode(HID_Machine.buff);
420 else if(HCD_GetURB_State(pdev, HID_Machine.hc_num_in) == URB_STALL) /* IN Endpoint Stalled */
423 /* Issue Clear Feature on interrupt IN endpoint */
424 if( (USBH_ClrFeature(pdev,
427 HID_Machine.hc_num_in)) == USBH_OK)
429 /* Change state to issue next IN token */
430 HID_Machine.state = HID_GET_DATA;
445 * @brief USBH_Get_HID_ReportDescriptor
446 * Issue report Descriptor command to the device. Once the response
447 * received, parse the report descriptor and update the status.
448 * @param pdev : Selected device
449 * @param Length : HID Report Descriptor Length
450 * @retval USBH_Status : Response for USB HID Get Report Descriptor Request
452 static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
459 status = USBH_GetDescriptor(pdev,
461 USB_REQ_RECIPIENT_INTERFACE
462 | USB_REQ_TYPE_STANDARD,
464 pdev->host.Rx_Buffer,
467 /* HID report descriptor is available in pdev->host.Rx_Buffer.
468 In case of USB Boot Mode devices for In report handling ,
469 HID report descriptor parsing is not required.
470 In case, for supporting Non-Boot Protocol devices and output reports,
471 user may parse the report descriptor*/
478 * @brief USBH_Get_HID_Descriptor
479 * Issue HID Descriptor command to the device. Once the response
480 * received, parse the report descriptor and update the status.
481 * @param pdev : Selected device
482 * @param Length : HID Descriptor Length
483 * @retval USBH_Status : Response for USB HID Get Report Descriptor Request
485 static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,
492 status = USBH_GetDescriptor(pdev,
494 USB_REQ_RECIPIENT_INTERFACE
495 | USB_REQ_TYPE_STANDARD,
497 pdev->host.Rx_Buffer,
504 * @brief USBH_Set_Idle
506 * @param pdev: Selected device
507 * @param duration: Duration for HID Idle request
508 * @param reportID : Targetted report ID for Set Idle request
509 * @retval USBH_Status : Response for USB Set Idle request
511 static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
517 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
521 phost->Control.setup.b.bRequest = USB_HID_SET_IDLE;
522 phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId;
524 phost->Control.setup.b.wIndex.w = 0;
525 phost->Control.setup.b.wLength.w = 0;
527 return USBH_CtlReq(pdev, phost, 0 , 0 );
532 * @brief USBH_Set_Report
534 * @param pdev: Selected device
535 * @param reportType : Report type to be sent
536 * @param reportID : Targetted report ID for Set Report request
537 * @param reportLen : Length of data report to be send
538 * @param reportBuff : Report Buffer
539 * @retval USBH_Status : Response for USB Set Idle request
541 USBH_Status USBH_Set_Report (USB_OTG_CORE_HANDLE *pdev,
549 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
553 phost->Control.setup.b.bRequest = USB_HID_SET_REPORT;
554 phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;
556 phost->Control.setup.b.wIndex.w = 0;
557 phost->Control.setup.b.wLength.w = reportLen;
559 return USBH_CtlReq(pdev, phost, reportBuff , reportLen );
564 * @brief USBH_Set_Protocol
565 * Set protocol State.
566 * @param pdev: Selected device
567 * @param protocol : Set Protocol for HID : boot/report protocol
568 * @retval USBH_Status : Response for USB Set Protocol request
570 static USBH_Status USBH_Set_Protocol(USB_OTG_CORE_HANDLE *pdev,
576 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
580 phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL;
585 phost->Control.setup.b.wValue.w = 0;
590 phost->Control.setup.b.wValue.w = 1;
593 phost->Control.setup.b.wIndex.w = 0;
594 phost->Control.setup.b.wLength.w = 0;
596 return USBH_CtlReq(pdev, phost, 0 , 0 );
601 * @brief USBH_ParseHIDDesc
602 * This function Parse the HID descriptor
603 * @param buf: Buffer where the source descriptor is available
606 static void USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf)
609 desc->bLength = *(uint8_t *) (buf + 0);
610 desc->bDescriptorType = *(uint8_t *) (buf + 1);
611 desc->bcdHID = LE16 (buf + 2);
612 desc->bCountryCode = *(uint8_t *) (buf + 4);
613 desc->bNumDescriptors = *(uint8_t *) (buf + 5);
614 desc->bReportDescriptorType = *(uint8_t *) (buf + 6);
615 desc->wItemLength = LE16 (buf + 7);
640 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/