Added all the F4 libraries to the project
[fw/stlink] / exampleF4 / STM32_USB_HOST_Library / Class / HID / src / usbh_hid_core.c
1 /**
2   ******************************************************************************
3   * @file    usbh_hid_core.c
4   * @author  MCD Application Team
5   * @version V2.0.0
6   * @date    22-July-2011
7   * @brief   This file is the HID Layer Handlers for USB Host HID class.
8   *
9   * @verbatim
10   *      
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
19   *      
20   *  @endverbatim
21   *
22   ******************************************************************************
23   * @attention
24   *
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. 
31   *
32   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
33   ******************************************************************************
34   */
35
36 /* Includes ------------------------------------------------------------------*/
37 #include "usbh_hid_core.h"
38 #include "usbh_hid_mouse.h"
39 #include "usbh_hid_keybd.h"
40
41 /** @addtogroup USBH_LIB
42 * @{
43 */
44
45 /** @addtogroup USBH_CLASS
46 * @{
47 */
48
49 /** @addtogroup USBH_HID_CLASS
50 * @{
51 */
52
53 /** @defgroup USBH_HID_CORE 
54 * @brief    This file includes HID Layer Handlers for USB Host HID class.
55 * @{
56 */ 
57
58 /** @defgroup USBH_HID_CORE_Private_TypesDefinitions
59 * @{
60 */ 
61 /**
62 * @}
63 */ 
64
65
66 /** @defgroup USBH_HID_CORE_Private_Defines
67 * @{
68 */ 
69 /**
70 * @}
71 */ 
72
73
74 /** @defgroup USBH_HID_CORE_Private_Macros
75 * @{
76 */ 
77 /**
78 * @}
79 */ 
80
81
82 /** @defgroup USBH_HID_CORE_Private_Variables
83 * @{
84 */
85 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
86   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
87     #pragma data_alignment=4   
88   #endif
89 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
90 __ALIGN_BEGIN HID_Machine_TypeDef        HID_Machine __ALIGN_END ;
91
92 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
93   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
94     #pragma data_alignment=4   
95   #endif
96 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
97 __ALIGN_BEGIN HID_Report_TypeDef         HID_Report __ALIGN_END ;
98
99 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
100   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
101     #pragma data_alignment=4   
102   #endif
103 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
104 __ALIGN_BEGIN USB_Setup_TypeDef          HID_Setup __ALIGN_END ;
105
106 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
107   #if defined ( __ICCARM__ ) /*!< IAR Compiler */
108     #pragma data_alignment=4   
109   #endif
110 #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
111 __ALIGN_BEGIN USBH_HIDDesc_TypeDef       HID_Desc __ALIGN_END ; 
112
113 __IO uint8_t flag = 0;
114 /**
115 * @}
116 */ 
117
118
119 /** @defgroup USBH_HID_CORE_Private_FunctionPrototypes
120 * @{
121 */ 
122
123 static USBH_Status USBH_HID_InterfaceInit  (USB_OTG_CORE_HANDLE *pdev , 
124                                             void *phost);
125
126 static void  USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf);
127
128 static void USBH_HID_InterfaceDeInit  (USB_OTG_CORE_HANDLE *pdev , 
129                                        void *phost);
130
131 static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev , 
132                                    void *phost);
133
134 static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev , 
135                                          void *phost);
136
137 static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev, 
138                                                   USBH_HOST *phost,
139                                                   uint16_t length);
140
141 static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,\
142                                             USBH_HOST *phost,  
143                                             uint16_t length);
144
145 static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev, 
146                                   USBH_HOST *phost,
147                                   uint8_t duration,
148                                   uint8_t reportId);
149
150 static USBH_Status USBH_Set_Protocol (USB_OTG_CORE_HANDLE *pdev, 
151                                       USBH_HOST *phost,
152                                       uint8_t protocol);
153
154
155 USBH_Class_cb_TypeDef  HID_cb = 
156 {
157   USBH_HID_InterfaceInit,
158   USBH_HID_InterfaceDeInit,
159   USBH_HID_ClassRequest,
160   USBH_HID_Handle
161 };
162 /**
163 * @}
164 */ 
165
166
167 /** @defgroup USBH_HID_CORE_Private_Functions
168 * @{
169 */ 
170
171 /**
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
177 */
178 static USBH_Status USBH_HID_InterfaceInit ( USB_OTG_CORE_HANDLE *pdev, 
179                                            void *phost)
180 {       
181   uint8_t maxEP;
182   USBH_HOST *pphost = phost;
183     
184   uint8_t num =0;
185   USBH_Status status = USBH_BUSY ;
186   HID_Machine.state = HID_ERROR;
187   
188   
189   if(pphost->device_prop.Itf_Desc[0].bInterfaceSubClass  == HID_BOOT_CODE)
190   {
191     /*Decode Bootclass Protocl: Mouse or Keyboard*/
192     if(pphost->device_prop.Itf_Desc[0].bInterfaceProtocol == HID_KEYBRD_BOOT_CODE)
193     {
194       HID_Machine.cb = &HID_KEYBRD_cb;
195     }
196     else if(pphost->device_prop.Itf_Desc[0].bInterfaceProtocol  == HID_MOUSE_BOOT_CODE)           
197     {
198       HID_Machine.cb = &HID_MOUSE_cb;
199     }
200     
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 ;
206     
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); 
213     
214     
215     /* Decode endpoint IN and OUT address from interface descriptor */
216     for (num=0; num < maxEP; num++)
217     {
218       if(pphost->device_prop.Ep_Desc[0][num].bEndpointAddress & 0x80)
219       {
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);
224         
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,
230                             EP_TYPE_INTR,
231                             HID_Machine.length); 
232       }
233       else
234       {
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);
239         
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,
245                             EP_TYPE_INTR,
246                             HID_Machine.length); 
247       }
248       
249     }   
250     
251      flag =0;
252      status = USBH_OK; 
253   }
254   else
255   {
256     pphost->usr_cb->USBH_USR_DeviceNotSupported();   
257   }
258   
259   return status;
260   
261 }
262
263
264
265 /**
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
270 * @retval None
271 */
272 void USBH_HID_InterfaceDeInit ( USB_OTG_CORE_HANDLE *pdev,
273                                void *phost)
274 {       
275    //USBH_HOST *pphost = phost;
276     
277   if(HID_Machine.hc_num_in != 0x00)
278   {   
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 */  
282   }
283   
284   if(HID_Machine.hc_num_out != 0x00)
285   {   
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 */  
289   }
290  
291   flag = 0;
292 }
293
294 /**
295 * @brief  USBH_HID_ClassRequest 
296 *         The function is responsible for handling HID Class requests
297 *         for HID class.
298 * @param  pdev: Selected device
299 * @param  hdev: Selected device property
300 * @retval  USBH_Status :Response for USB Set Protocol request
301 */
302 static USBH_Status USBH_HID_ClassRequest(USB_OTG_CORE_HANDLE *pdev , 
303                                          void *phost)
304 {   
305     USBH_HOST *pphost = phost;
306     
307   USBH_Status status         = USBH_BUSY;
308   USBH_Status classReqStatus = USBH_BUSY;
309   
310   
311   /* Switch HID state machine */
312   switch (HID_Machine.ctl_state)
313   {
314   case HID_IDLE:  
315   case HID_REQ_GET_HID_DESC:
316     
317     /* Get HID Desc */ 
318     if (USBH_Get_HID_Descriptor (pdev, pphost, USB_HID_DESC_SIZE)== USBH_OK)
319     {
320       
321       USBH_ParseHIDDesc(&HID_Desc, pdev->host.Rx_Buffer);
322       HID_Machine.ctl_state = HID_REQ_GET_REPORT_DESC;
323     }
324     
325     break;     
326   case HID_REQ_GET_REPORT_DESC:
327     
328     
329     /* Get Report Desc */ 
330     if (USBH_Get_HID_ReportDescriptor(pdev , pphost, HID_Desc.wItemLength) == USBH_OK)
331     {
332       HID_Machine.ctl_state = HID_REQ_SET_IDLE;
333     }
334     
335     break;
336     
337   case HID_REQ_SET_IDLE:
338     
339     classReqStatus = USBH_Set_Idle (pdev, pphost, 0, 0);
340     
341     /* set Idle */
342     if (classReqStatus == USBH_OK)
343     {
344       HID_Machine.ctl_state = HID_REQ_SET_PROTOCOL;  
345     }
346     else if(classReqStatus == USBH_NOT_SUPPORTED) 
347     {
348       HID_Machine.ctl_state = HID_REQ_SET_PROTOCOL;        
349     } 
350     break; 
351     
352   case HID_REQ_SET_PROTOCOL:
353     /* set protocol */
354     if (USBH_Set_Protocol (pdev ,pphost, 0) == USBH_OK)
355     {
356       HID_Machine.ctl_state = HID_REQ_IDLE;
357       
358       /* all requests performed*/
359       status = USBH_OK; 
360     } 
361     break;
362     
363   default:
364     break;
365   }
366   
367   return status; 
368 }
369
370
371 /**
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
377 */
378 static USBH_Status USBH_HID_Handle(USB_OTG_CORE_HANDLE *pdev , 
379                                    void   *phost)
380 {
381     USBH_HOST *pphost = phost;
382   USBH_Status status = USBH_OK;
383   
384   switch (HID_Machine.state)
385   {
386     
387   case HID_IDLE:
388     HID_Machine.cb->Init();
389     HID_Machine.state = HID_GET_DATA;
390     break;  
391     
392   case HID_GET_DATA:
393     
394     /* Sync with start of Even Frame */
395     while(USB_OTG_IsEvenFrame(pdev) == FALSE);
396     
397     USBH_InterruptReceiveData(pdev, 
398                               HID_Machine.buff,
399                               HID_Machine.length,
400                               HID_Machine.hc_num_in);
401     flag = 1;
402     
403     HID_Machine.state = HID_POLL;
404     HID_Machine.timer = HCD_GetCurrentFrame(pdev);
405     break;
406     
407   case HID_POLL:
408     if(( HCD_GetCurrentFrame(pdev) - HID_Machine.timer) >= HID_Machine.poll)
409     {
410       HID_Machine.state = HID_GET_DATA;
411     }
412     else if(HCD_GetURB_State(pdev , HID_Machine.hc_num_in) == URB_DONE)
413     {
414       if(flag == 1) /* handle data once */
415       {
416         flag = 0;
417         HID_Machine.cb->Decode(HID_Machine.buff);
418       }
419     }
420     else if(HCD_GetURB_State(pdev, HID_Machine.hc_num_in) == URB_STALL) /* IN Endpoint Stalled */
421     {
422       
423       /* Issue Clear Feature on interrupt IN endpoint */ 
424       if( (USBH_ClrFeature(pdev, 
425                            pphost,
426                            HID_Machine.ep_addr,
427                            HID_Machine.hc_num_in)) == USBH_OK)
428       {
429         /* Change state to issue next IN token */
430         HID_Machine.state = HID_GET_DATA;
431         
432       }
433       
434     }      
435     break;
436     
437   default:
438     break;
439   }
440   return status;
441 }
442
443
444 /**
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
451 */
452 static USBH_Status USBH_Get_HID_ReportDescriptor (USB_OTG_CORE_HANDLE *pdev,
453                                                   USBH_HOST *phost,
454                                                   uint16_t length)
455 {
456   
457   USBH_Status status;
458   
459   status = USBH_GetDescriptor(pdev,
460                               phost,
461                               USB_REQ_RECIPIENT_INTERFACE
462                                 | USB_REQ_TYPE_STANDARD,                                  
463                                 USB_DESC_HID_REPORT, 
464                                 pdev->host.Rx_Buffer,
465                                 length);
466   
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*/
472   
473   
474   return status;
475 }
476
477 /**
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
484 */
485 static USBH_Status USBH_Get_HID_Descriptor (USB_OTG_CORE_HANDLE *pdev,
486                                             USBH_HOST *phost,
487                                             uint16_t length)
488 {
489   
490   USBH_Status status;
491   
492   status = USBH_GetDescriptor(pdev, 
493                               phost,
494                               USB_REQ_RECIPIENT_INTERFACE
495                                 | USB_REQ_TYPE_STANDARD,                                  
496                                 USB_DESC_HID,
497                                 pdev->host.Rx_Buffer,
498                                 length);
499  
500   return status;
501 }
502
503 /**
504 * @brief  USBH_Set_Idle
505 *         Set Idle State. 
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
510 */
511 static USBH_Status USBH_Set_Idle (USB_OTG_CORE_HANDLE *pdev,
512                                   USBH_HOST *phost,
513                                   uint8_t duration,
514                                   uint8_t reportId)
515 {
516   
517   phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
518     USB_REQ_TYPE_CLASS;
519   
520   
521   phost->Control.setup.b.bRequest = USB_HID_SET_IDLE;
522   phost->Control.setup.b.wValue.w = (duration << 8 ) | reportId;
523   
524   phost->Control.setup.b.wIndex.w = 0;
525   phost->Control.setup.b.wLength.w = 0;
526   
527   return USBH_CtlReq(pdev, phost, 0 , 0 );
528 }
529
530
531 /**
532 * @brief  USBH_Set_Report
533 *         Issues 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
540 */
541 USBH_Status USBH_Set_Report (USB_OTG_CORE_HANDLE *pdev, 
542                                  USBH_HOST *phost,
543                                     uint8_t reportType,
544                                     uint8_t reportId,
545                                     uint8_t reportLen,
546                                     uint8_t* reportBuff)
547 {
548   
549   phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
550     USB_REQ_TYPE_CLASS;
551   
552   
553   phost->Control.setup.b.bRequest = USB_HID_SET_REPORT;
554   phost->Control.setup.b.wValue.w = (reportType << 8 ) | reportId;
555   
556   phost->Control.setup.b.wIndex.w = 0;
557   phost->Control.setup.b.wLength.w = reportLen;
558   
559   return USBH_CtlReq(pdev, phost, reportBuff , reportLen );
560 }
561
562
563 /**
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
569 */
570 static USBH_Status USBH_Set_Protocol(USB_OTG_CORE_HANDLE *pdev,
571                                      USBH_HOST *phost,
572                                      uint8_t protocol)
573 {
574   
575   
576   phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE |\
577     USB_REQ_TYPE_CLASS;
578   
579   
580   phost->Control.setup.b.bRequest = USB_HID_SET_PROTOCOL;
581   
582   if(protocol != 0)
583   {
584     /* Boot Protocol */
585     phost->Control.setup.b.wValue.w = 0;
586   }
587   else
588   {
589     /*Report Protocol*/
590     phost->Control.setup.b.wValue.w = 1;
591   }
592   
593   phost->Control.setup.b.wIndex.w = 0;
594   phost->Control.setup.b.wLength.w = 0;
595   
596   return USBH_CtlReq(pdev, phost, 0 , 0 );
597   
598 }
599
600 /**
601 * @brief  USBH_ParseHIDDesc 
602 *         This function Parse the HID descriptor
603 * @param  buf: Buffer where the source descriptor is available
604 * @retval None
605 */
606 static void  USBH_ParseHIDDesc (USBH_HIDDesc_TypeDef *desc, uint8_t *buf)
607 {
608   
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);
616   
617
618 /**
619 * @}
620 */ 
621
622 /**
623 * @}
624 */ 
625
626 /**
627 * @}
628 */
629
630
631 /**
632 * @}
633 */
634
635
636 /**
637 * @}
638 */
639
640 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/