1 /*
2  * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "usb_device_config.h"
10 #include "usb.h"
11 #include "usb_device.h"
12 
13 #include "usb_device_class.h"
14 
15 #if ((defined(USB_DEVICE_CONFIG_HID)) && (USB_DEVICE_CONFIG_HID > 0U))
16 #include "usb_device_hid.h"
17 
18 /*******************************************************************************
19  * Definitions
20  ******************************************************************************/
21 
22 /*******************************************************************************
23  * Prototypes
24  ******************************************************************************/
25 
26 static usb_status_t USB_DeviceHidAllocateHandle(usb_device_hid_struct_t **handle);
27 static usb_status_t USB_DeviceHidFreeHandle(usb_device_hid_struct_t *handle);
28 static usb_status_t USB_DeviceHidInterruptIn(usb_device_handle handle,
29                                              usb_device_endpoint_callback_message_struct_t *message,
30                                              void *callbackParam);
31 static usb_status_t USB_DeviceHidInterruptOut(usb_device_handle handle,
32                                               usb_device_endpoint_callback_message_struct_t *message,
33                                               void *callbackParam);
34 static usb_status_t USB_DeviceHidEndpointsInit(usb_device_hid_struct_t *hidHandle);
35 static usb_status_t USB_DeviceHidEndpointsDeinit(usb_device_hid_struct_t *hidHandle);
36 
37 /*******************************************************************************
38  * Variables
39  ******************************************************************************/
40 
USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE)41 USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_hid_struct_t
42     s_UsbDeviceHidHandle[USB_DEVICE_CONFIG_HID];
43 
44 /*******************************************************************************
45  * Code
46  ******************************************************************************/
47 
48 /*!
49  * @brief Allocate a device hid class handle.
50  *
51  * This function allocates a device hid class handle.
52  *
53  * @param handle          It is out parameter, is used to return pointer of the device hid class handle to the caller.
54  *
55  * @retval kStatus_USB_Success              Get a device hid class handle successfully.
56  * @retval kStatus_USB_Busy                 Cannot allocate a device hid class handle.
57  */
58 static usb_status_t USB_DeviceHidAllocateHandle(usb_device_hid_struct_t **handle)
59 {
60     uint32_t count;
61     for (count = 0U; count < USB_DEVICE_CONFIG_HID; count++)
62     {
63         if (NULL == s_UsbDeviceHidHandle[count].handle)
64         {
65             *handle = &s_UsbDeviceHidHandle[count];
66             return kStatus_USB_Success;
67         }
68     }
69 
70     return kStatus_USB_Busy;
71 }
72 
73 /*!
74  * @brief Free a device hid class handle.
75  *
76  * This function frees a device hid class handle.
77  *
78  * @param handle          The device hid class handle.
79  *
80  * @retval kStatus_USB_Success              Free device hid class handle successfully.
81  */
USB_DeviceHidFreeHandle(usb_device_hid_struct_t * handle)82 static usb_status_t USB_DeviceHidFreeHandle(usb_device_hid_struct_t *handle)
83 {
84     handle->handle        = NULL;
85     handle->configStruct  = (usb_device_class_config_struct_t *)NULL;
86     handle->configuration = 0U;
87     handle->alternate     = 0U;
88     return kStatus_USB_Success;
89 }
90 
91 /*!
92  * @brief Interrupt IN endpoint callback function.
93  *
94  * This callback function is used to notify uplayer the transfser result of a transfer.
95  * This callback pointer is passed when the interrupt IN pipe initialized.
96  *
97  * @param handle          The device handle. It equals the value returned from USB_DeviceInit.
98  * @param message         The result of the interrupt IN pipe transfer.
99  * @param callbackParam  The parameter for this callback. It is same with
100  * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the HID class handle.
101  *
102  * @return A USB error code or kStatus_USB_Success.
103  */
USB_DeviceHidInterruptIn(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)104 static usb_status_t USB_DeviceHidInterruptIn(usb_device_handle handle,
105                                              usb_device_endpoint_callback_message_struct_t *message,
106                                              void *callbackParam)
107 {
108     usb_device_hid_struct_t *hidHandle;
109     usb_status_t status = kStatus_USB_Error;
110 
111     /* Get the HID class handle */
112     hidHandle = (usb_device_hid_struct_t *)callbackParam;
113 
114     if (NULL == hidHandle)
115     {
116         return kStatus_USB_InvalidHandle;
117     }
118     hidHandle->interruptInPipeBusy = 0U;
119     if ((NULL != hidHandle->configStruct) && (NULL != hidHandle->configStruct->classCallback))
120     {
121         /* Notify the application data sent by calling the hid class callback. classCallback is initialized
122            in classInit of s_UsbDeviceClassInterfaceMap,it is from the second parameter of classInit */
123         status =
124             hidHandle->configStruct->classCallback((class_handle_t)hidHandle, kUSB_DeviceHidEventSendResponse, message);
125     }
126 
127     return status;
128 }
129 
130 /*!
131  * @brief Interrupt OUT endpoint callback function.
132  *
133  * This callback function is used to notify uplayer the transfser result of a transfer.
134  * This callback pointer is passed when the interrupt OUT pipe initialized.
135  *
136  * @param handle          The device handle. It equals the value returned from USB_DeviceInit.
137  * @param message         The result of the interrupt OUT pipe transfer.
138  * @param callbackParam  The parameter for this callback. It is same with
139  * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the HID class handle.
140  *
141  * @return A USB error code or kStatus_USB_Success.
142  */
USB_DeviceHidInterruptOut(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)143 static usb_status_t USB_DeviceHidInterruptOut(usb_device_handle handle,
144                                               usb_device_endpoint_callback_message_struct_t *message,
145                                               void *callbackParam)
146 {
147     usb_device_hid_struct_t *hidHandle;
148     usb_status_t status = kStatus_USB_Error;
149 
150     /* Get the HID class handle */
151     hidHandle = (usb_device_hid_struct_t *)callbackParam;
152 
153     if (NULL == hidHandle)
154     {
155         return kStatus_USB_InvalidHandle;
156     }
157     hidHandle->interruptOutPipeBusy = 0U;
158     if ((NULL != hidHandle->configStruct) && (NULL != hidHandle->configStruct->classCallback))
159     {
160         /* Notify the application data sent by calling the hid class callback. classCallback is initialized
161            in classInit of s_UsbDeviceClassInterfaceMap,it is from the second parameter of classInit */
162         status =
163             hidHandle->configStruct->classCallback((class_handle_t)hidHandle, kUSB_DeviceHidEventRecvResponse, message);
164     }
165 
166     return status;
167 }
168 
169 /*!
170  * @brief Initialize the endpoints of the hid class.
171  *
172  * This callback function is used to initialize the endpoints of the hid class.
173  *
174  * @param hidHandle          The device hid class handle. It equals the value returned from
175  * usb_device_class_config_struct_t::classHandle.
176  *
177  * @return A USB error code or kStatus_USB_Success.
178  */
USB_DeviceHidEndpointsInit(usb_device_hid_struct_t * hidHandle)179 static usb_status_t USB_DeviceHidEndpointsInit(usb_device_hid_struct_t *hidHandle)
180 {
181     usb_device_interface_list_t *interfaceList;
182     usb_device_interface_struct_t *interface = (usb_device_interface_struct_t *)NULL;
183     usb_status_t status                      = kStatus_USB_Error;
184     uint32_t count;
185     uint32_t index;
186 
187     /* Check the configuration is valid or not. */
188     if (0U == hidHandle->configuration)
189     {
190         return status;
191     }
192 
193     if (hidHandle->configuration > hidHandle->configStruct->classInfomation->configurations)
194     {
195         return status;
196     }
197 
198     /* Get the interface list of the new configuration. */
199     if (NULL == hidHandle->configStruct->classInfomation->interfaceList)
200     {
201         return status;
202     }
203     interfaceList = &hidHandle->configStruct->classInfomation->interfaceList[hidHandle->configuration - 1U];
204 
205     /* Find interface by using the alternate setting of the interface. */
206     for (count = 0U; count < interfaceList->count; count++)
207     {
208         if (USB_DEVICE_CONFIG_HID_CLASS_CODE == interfaceList->interfaces[count].classCode)
209         {
210             for (index = 0U; index < interfaceList->interfaces[count].count; index++)
211             {
212                 if (interfaceList->interfaces[count].interface[index].alternateSetting == hidHandle->alternate)
213                 {
214                     interface = &interfaceList->interfaces[count].interface[index];
215                     break;
216                 }
217             }
218             hidHandle->interfaceNumber = interfaceList->interfaces[count].interfaceNumber;
219             break;
220         }
221     }
222     if (NULL == interface)
223     {
224         /* Return error if the interface is not found. */
225         return status;
226     }
227 
228     /* Keep new interface handle. */
229     hidHandle->interfaceHandle = interface;
230 
231     /* Initialize the endpoints of the new interface. */
232     for (count = 0U; count < interface->endpointList.count; count++)
233     {
234         usb_device_endpoint_init_struct_t epInitStruct;
235         usb_device_endpoint_callback_struct_t epCallback;
236         epInitStruct.zlt             = 0U;
237         epInitStruct.interval        = interface->endpointList.endpoint[count].interval;
238         epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
239         epInitStruct.maxPacketSize   = interface->endpointList.endpoint[count].maxPacketSize;
240         epInitStruct.transferType    = interface->endpointList.endpoint[count].transferType;
241 
242         if (USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
243                        USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
244         {
245             epCallback.callbackFn                = USB_DeviceHidInterruptIn;
246             hidHandle->interruptInPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
247             hidHandle->interruptInPipeStall      = 0U;
248             hidHandle->interruptInPipeDataLen    = 0U;
249         }
250         else
251         {
252             epCallback.callbackFn                 = USB_DeviceHidInterruptOut;
253             hidHandle->interruptOutPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
254             hidHandle->interruptOutPipeStall      = 0U;
255             hidHandle->interruptOutPipeDataLen    = 0U;
256         }
257         epCallback.callbackParam = hidHandle;
258 
259         status = USB_DeviceInitEndpoint(hidHandle->handle, &epInitStruct, &epCallback);
260     }
261     return status;
262 }
263 
264 /*!
265  * @brief De-initialize the endpoints of the hid class.
266  *
267  * This callback function is used to de-initialize the endpoints of the hid class.
268  *
269  * @param hidHandle          The device hid class handle. It equals the value returned from
270  * usb_device_class_config_struct_t::classHandle.
271  *
272  * @return A USB error code or kStatus_USB_Success.
273  */
USB_DeviceHidEndpointsDeinit(usb_device_hid_struct_t * hidHandle)274 static usb_status_t USB_DeviceHidEndpointsDeinit(usb_device_hid_struct_t *hidHandle)
275 {
276     usb_status_t status = kStatus_USB_Error;
277     uint32_t count;
278 
279     if (NULL == hidHandle->interfaceHandle)
280     {
281         return status;
282     }
283     /* De-initialize all endpoints of the interface */
284     for (count = 0U; count < hidHandle->interfaceHandle->endpointList.count; count++)
285     {
286         status = USB_DeviceDeinitEndpoint(hidHandle->handle,
287                                           hidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress);
288     }
289     hidHandle->interfaceHandle = NULL;
290     return status;
291 }
292 
293 /*!
294  * @brief Handle the event passed to the hid class.
295  *
296  * This function handles the event passed to the hid class.
297  *
298  * @param handle          The hid class handle, got from the usb_device_class_config_struct_t::classHandle.
299  * @param event           The event codes. Please refer to the enumeration usb_device_class_event_t.
300  * @param param           The param type is determined by the event code.
301  *
302  * @return A USB error code or kStatus_USB_Success.
303  * @retval kStatus_USB_Success              Free device handle successfully.
304  * @retval kStatus_USB_InvalidParameter     The device handle not be found.
305  * @retval kStatus_USB_InvalidRequest       The request is invalid, and the control pipe will be stalled by the caller.
306  */
USB_DeviceHidEvent(void * handle,uint32_t event,void * param)307 usb_status_t USB_DeviceHidEvent(void *handle, uint32_t event, void *param)
308 {
309     usb_device_hid_struct_t *hidHandle;
310     usb_device_hid_report_struct_t report;
311     usb_status_t error = kStatus_USB_Error;
312     uint16_t interfaceAlternate;
313     uint32_t count;
314     uint8_t *temp8;
315     uint8_t alternate;
316     usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
317 
318     if ((NULL == param) || (NULL == handle))
319     {
320         return kStatus_USB_InvalidHandle;
321     }
322     report.reportBuffer = (uint8_t *)NULL;
323     report.reportLength = 0U;
324 
325     /* Get the hid class handle. */
326     hidHandle = (usb_device_hid_struct_t *)handle;
327 
328     switch (eventCode)
329     {
330         case kUSB_DeviceClassEventDeviceReset:
331             /* Bus reset, clear the configuration. */
332             hidHandle->configuration        = 0U;
333             hidHandle->interruptInPipeBusy  = 0U;
334             hidHandle->interruptOutPipeBusy = 0U;
335             hidHandle->interfaceHandle      = NULL;
336             error                           = kStatus_USB_Success;
337             break;
338         case kUSB_DeviceClassEventSetConfiguration:
339             /* Get the new configuration. */
340             temp8 = ((uint8_t *)param);
341             if (NULL == hidHandle->configStruct)
342             {
343                 break;
344             }
345             if (*temp8 == hidHandle->configuration)
346             {
347                 error = kStatus_USB_Success;
348                 break;
349             }
350 
351             /* De-initialize the endpoints when current configuration is none zero. */
352             if (0U != hidHandle->configuration)
353             {
354                 error = USB_DeviceHidEndpointsDeinit(hidHandle);
355             }
356             /* Save new configuration. */
357             hidHandle->configuration = *temp8;
358             /* Clear the alternate setting value. */
359             hidHandle->alternate = 0U;
360 
361             /* Initialize the endpoints of the new current configuration by using the alternate setting 0. */
362             error = USB_DeviceHidEndpointsInit(hidHandle);
363             break;
364         case kUSB_DeviceClassEventSetInterface:
365             if (NULL == hidHandle->configStruct)
366             {
367                 break;
368             }
369             /* Get the new alternate setting of the interface */
370             interfaceAlternate = *((uint16_t *)param);
371             /* Get the alternate setting value */
372             alternate = (uint8_t)(interfaceAlternate & 0xFFU);
373 
374             /* Whether the interface belongs to the class. */
375             if (hidHandle->interfaceNumber != ((uint8_t)(interfaceAlternate >> 8U)))
376             {
377                 break;
378             }
379             /* Only handle new alternate setting. */
380             if (alternate == hidHandle->alternate)
381             {
382                 error = kStatus_USB_Success;
383                 break;
384             }
385             /* De-initialize old endpoints */
386             error                = USB_DeviceHidEndpointsDeinit(hidHandle);
387             hidHandle->alternate = alternate;
388             /* Initialize new endpoints */
389             error = USB_DeviceHidEndpointsInit(hidHandle);
390             break;
391         case kUSB_DeviceClassEventSetEndpointHalt:
392             if ((NULL == hidHandle->configStruct) || (NULL == hidHandle->interfaceHandle))
393             {
394                 break;
395             }
396             /* Get the endpoint address */
397             temp8 = ((uint8_t *)param);
398             for (count = 0U; count < hidHandle->interfaceHandle->endpointList.count; count++)
399             {
400                 if (*temp8 == hidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress)
401                 {
402                     /* Only stall the endpoint belongs to the class */
403                     if (USB_IN == ((hidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress &
404                                     USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
405                                    USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
406                     {
407                         hidHandle->interruptInPipeStall = 1U;
408                     }
409                     else
410                     {
411                         hidHandle->interruptOutPipeStall = 1U;
412                     }
413                     error = USB_DeviceStallEndpoint(hidHandle->handle, *temp8);
414                 }
415             }
416             break;
417         case kUSB_DeviceClassEventClearEndpointHalt:
418             if ((NULL == hidHandle->configStruct) || (NULL == hidHandle->interfaceHandle))
419             {
420                 break;
421             }
422             /* Get the endpoint address */
423             temp8 = ((uint8_t *)param);
424             for (count = 0U; count < hidHandle->interfaceHandle->endpointList.count; count++)
425             {
426                 if (*temp8 == hidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress)
427                 {
428                     /* Only un-stall the endpoint belongs to the class */
429                     error = USB_DeviceUnstallEndpoint(hidHandle->handle, *temp8);
430                     if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
431                                    USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
432                     {
433                         if (0U != hidHandle->interruptInPipeStall)
434                         {
435                             hidHandle->interruptInPipeStall = 0U;
436                             if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != hidHandle->interruptInPipeDataBuffer)
437                             {
438                                 error = USB_DeviceSendRequest(
439                                     hidHandle->handle,
440                                     (hidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress &
441                                      USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK),
442                                     hidHandle->interruptInPipeDataBuffer, hidHandle->interruptInPipeDataLen);
443                                 if (kStatus_USB_Success != error)
444                                 {
445                                     usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
446                                     endpointCallbackMessage.buffer  = hidHandle->interruptInPipeDataBuffer;
447                                     endpointCallbackMessage.length  = hidHandle->interruptInPipeDataLen;
448                                     endpointCallbackMessage.isSetup = 0U;
449 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
450                                     if (kStatus_USB_Success !=
451                                         USB_DeviceHidInterruptIn(hidHandle->handle, (void *)&endpointCallbackMessage,
452                                                                  handle))
453                                     {
454                                         return kStatus_USB_Error;
455                                     }
456 #else
457                                     (void)USB_DeviceHidInterruptIn(hidHandle->handle, (void *)&endpointCallbackMessage,
458                                                                    handle);
459 #endif
460                                 }
461                                 hidHandle->interruptInPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
462                                 hidHandle->interruptInPipeDataLen    = 0U;
463                             }
464                         }
465                     }
466                     else
467                     {
468                         if (0U != hidHandle->interruptOutPipeStall)
469                         {
470                             hidHandle->interruptOutPipeStall = 0U;
471                             if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != hidHandle->interruptOutPipeDataBuffer)
472                             {
473                                 error = USB_DeviceRecvRequest(
474                                     hidHandle->handle,
475                                     (hidHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress &
476                                      USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK),
477                                     hidHandle->interruptOutPipeDataBuffer, hidHandle->interruptOutPipeDataLen);
478                                 if (kStatus_USB_Success != error)
479                                 {
480                                     usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
481                                     endpointCallbackMessage.buffer  = hidHandle->interruptOutPipeDataBuffer;
482                                     endpointCallbackMessage.length  = hidHandle->interruptOutPipeDataLen;
483                                     endpointCallbackMessage.isSetup = 0U;
484 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
485                                     if (kStatus_USB_Success !=
486                                         USB_DeviceHidInterruptOut(hidHandle->handle, (void *)&endpointCallbackMessage,
487                                                                   handle))
488                                     {
489                                         return kStatus_USB_Error;
490                                     }
491 #else
492                                     (void)USB_DeviceHidInterruptOut(hidHandle->handle, (void *)&endpointCallbackMessage,
493                                                                     handle);
494 #endif
495                                 }
496                                 hidHandle->interruptOutPipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
497                                 hidHandle->interruptOutPipeDataLen    = 0U;
498                             }
499                         }
500                     }
501                 }
502             }
503             break;
504         case kUSB_DeviceClassEventClassRequest:
505         {
506             /* Handle the hid class specific request. */
507             usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
508 
509             if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
510                 USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
511             {
512                 break;
513             }
514 
515             if ((controlRequest->setup->wIndex & 0xFFU) != hidHandle->interfaceNumber)
516             {
517                 break;
518             }
519 
520             error = kStatus_USB_InvalidRequest;
521             switch (controlRequest->setup->bRequest)
522             {
523                 case USB_DEVICE_HID_REQUEST_GET_REPORT:
524                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
525                          USB_REQUEST_TYPE_DIR_IN) &&
526                         (controlRequest->setup->wLength != 0U))
527                     {
528                         /* Get report request */
529                         report.reportType = (uint8_t)((controlRequest->setup->wValue & 0xFF00U) >> 0x08U);
530                         report.reportId   = (uint8_t)(controlRequest->setup->wValue & 0x00FFU);
531                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
532                            it is from the second parameter of classInit */
533                         error                  = hidHandle->configStruct->classCallback((class_handle_t)hidHandle,
534                                                                        kUSB_DeviceHidEventGetReport, &report);
535                         controlRequest->buffer = report.reportBuffer;
536                         controlRequest->length = report.reportLength;
537                     }
538                     break;
539                 case USB_DEVICE_HID_REQUEST_GET_IDLE:
540                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
541                          USB_REQUEST_TYPE_DIR_IN) &&
542                         (controlRequest->setup->wLength != 0U))
543                     {
544                         /* Get idle request, classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
545                            it is from the second parameter of classInit */
546                         error = hidHandle->configStruct->classCallback(
547                             (class_handle_t)hidHandle, kUSB_DeviceHidEventGetIdle, &hidHandle->idleRate);
548                         controlRequest->buffer = &hidHandle->idleRate;
549                         controlRequest->length = sizeof(hidHandle->idleRate);
550                     }
551                     break;
552                 case USB_DEVICE_HID_REQUEST_GET_PROTOCOL:
553                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
554                          USB_REQUEST_TYPE_DIR_IN) &&
555                         (controlRequest->setup->wLength != 0U))
556                     {
557                         /* Get protocol request, classCallback is initialized in classInit of
558                            s_UsbDeviceClassInterfaceMap,
559                            it is from the second parameter of classInit */
560                         error = hidHandle->configStruct->classCallback(
561                             (class_handle_t)hidHandle, kUSB_DeviceHidEventGetProtocol, &hidHandle->protocol);
562                         controlRequest->buffer = &hidHandle->protocol;
563                         controlRequest->length = sizeof(hidHandle->protocol);
564                     }
565                     break;
566                 case USB_DEVICE_HID_REQUEST_SET_REPORT:
567                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
568                          USB_REQUEST_TYPE_DIR_OUT) &&
569                         (controlRequest->setup->wLength != 0U))
570                     {
571                         /* Set report request */
572                         report.reportType = (uint8_t)((controlRequest->setup->wValue & 0xFF00U) >> 0x08U);
573                         report.reportId   = (uint8_t)(controlRequest->setup->wValue & 0x00FFU);
574                         if (0U != controlRequest->isSetup)
575                         {
576                             report.reportLength = controlRequest->length;
577                             /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
578                                it is from the second parameter of classInit */
579                             error = hidHandle->configStruct->classCallback(
580                                 (class_handle_t)hidHandle, kUSB_DeviceHidEventRequestReportBuffer, &report);
581                             controlRequest->buffer = report.reportBuffer;
582                             controlRequest->length = report.reportLength;
583                         }
584                         else
585                         {
586                             report.reportBuffer = controlRequest->buffer;
587                             report.reportLength = controlRequest->length;
588                             /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
589                                it is from the second parameter of classInit */
590                             error = hidHandle->configStruct->classCallback((class_handle_t)hidHandle,
591                                                                            kUSB_DeviceHidEventSetReport, &report);
592                         }
593                     }
594                     break;
595                 case USB_DEVICE_HID_REQUEST_SET_IDLE:
596                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
597                          USB_REQUEST_TYPE_DIR_OUT) &&
598                         (controlRequest->setup->wLength == 0U))
599                     {
600                         /* Set idle request */
601                         hidHandle->idleRate = (uint8_t)((controlRequest->setup->wValue & 0xFF00U) >> 0x08U);
602                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
603                            it is from the second parameter of classInit */
604                         error = hidHandle->configStruct->classCallback(
605                             (class_handle_t)hidHandle, kUSB_DeviceHidEventSetIdle, &hidHandle->idleRate);
606                     }
607                     break;
608                 case USB_DEVICE_HID_REQUEST_SET_PROTOCOL:
609                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
610                          USB_REQUEST_TYPE_DIR_OUT) &&
611                         (controlRequest->setup->wLength == 0U))
612                     {
613                         /* Set protocol request */
614                         hidHandle->protocol = (uint8_t)((controlRequest->setup->wValue & 0x00FFU));
615                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
616                            it is from the second parameter of classInit */
617                         error = hidHandle->configStruct->classCallback(
618                             (class_handle_t)hidHandle, kUSB_DeviceHidEventSetProtocol, &hidHandle->protocol);
619                     }
620                     break;
621                 default:
622                     /* no action, return kStatus_USB_InvalidRequest */
623                     break;
624             }
625         }
626         break;
627         default:
628             /*no action*/
629             break;
630     }
631     return error;
632 }
633 
634 /*!
635  * @brief Initialize the hid class.
636  *
637  * This function is used to initialize the hid class.
638  *
639  * @param controllerId   The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
640  * @param config          The class configuration information.
641  * @param handle          It is out parameter, is used to return pointer of the hid class handle to the caller.
642  *
643  * @return A USB error code or kStatus_USB_Success.
644  */
USB_DeviceHidInit(uint8_t controllerId,usb_device_class_config_struct_t * config,class_handle_t * handle)645 usb_status_t USB_DeviceHidInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle)
646 {
647     usb_device_hid_struct_t *hidHandle;
648     usb_status_t error;
649 
650     /* Allocate a hid class handle. */
651     error = USB_DeviceHidAllocateHandle(&hidHandle);
652 
653     if (kStatus_USB_Success != error)
654     {
655         return error;
656     }
657 
658     /* Get the device handle according to the controller id. */
659     error = USB_DeviceClassGetDeviceHandle(controllerId, &hidHandle->handle);
660 
661     if (kStatus_USB_Success != error)
662     {
663         return error;
664     }
665 
666     if (NULL == hidHandle->handle)
667     {
668         return kStatus_USB_InvalidHandle;
669     }
670     /* Save the configuration of the class. */
671     hidHandle->configStruct = config;
672     /* Clear the configuration value. */
673     hidHandle->configuration = 0U;
674     hidHandle->alternate     = 0xffU;
675 
676     *handle = (class_handle_t)hidHandle;
677     return error;
678 }
679 
680 /*!
681  * @brief De-initialize the device hid class.
682  *
683  * The function de-initializes the device hid class.
684  *
685  * @param handle The hid class handle got from usb_device_class_config_struct_t::classHandle.
686  *
687  * @return A USB error code or kStatus_USB_Success.
688  */
USB_DeviceHidDeinit(class_handle_t handle)689 usb_status_t USB_DeviceHidDeinit(class_handle_t handle)
690 {
691     usb_device_hid_struct_t *hidHandle;
692     usb_status_t error;
693 
694     hidHandle = (usb_device_hid_struct_t *)handle;
695 
696     if (NULL == hidHandle)
697     {
698         return kStatus_USB_InvalidHandle;
699     }
700     /* De-initialzie the endpoints. */
701     error = USB_DeviceHidEndpointsDeinit(hidHandle);
702     /* Free the hid class handle. */
703 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
704     if (kStatus_USB_Success != USB_DeviceHidFreeHandle(hidHandle))
705     {
706         return kStatus_USB_Error;
707     }
708 #else
709     (void)USB_DeviceHidFreeHandle(hidHandle);
710 #endif
711     return error;
712 }
713 
714 /*!
715  * @brief Send data through a specified endpoint.
716  *
717  * The function is used to send data through a specified endpoint.
718  * The function calls USB_DeviceSendRequest internally.
719  *
720  * @param handle The hid class handle got from usb_device_class_config_struct_t::classHandle.
721  * @param ep     Endpoint index.
722  * @param buffer The memory address to hold the data need to be sent.
723  * @param length The data length need to be sent.
724  *
725  * @return A USB error code or kStatus_USB_Success.
726  *
727  * @note The return value just means if the sending request is successful or not; the transfer done is notified by
728  * USB_DeviceHidInterruptIn.
729  * Currently, only one transfer request can be supported for one specific endpoint.
730  * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application
731  * should implement a queue in the application level.
732  * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint
733  * callback).
734  */
USB_DeviceHidSend(class_handle_t handle,uint8_t ep,uint8_t * buffer,uint32_t length)735 usb_status_t USB_DeviceHidSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
736 {
737     usb_device_hid_struct_t *hidHandle;
738     usb_status_t error = kStatus_USB_Error;
739 
740     if (NULL == handle)
741     {
742         return kStatus_USB_InvalidHandle;
743     }
744     hidHandle = (usb_device_hid_struct_t *)handle;
745 
746     if (0U != hidHandle->interruptInPipeBusy)
747     {
748         return kStatus_USB_Busy;
749     }
750     hidHandle->interruptInPipeBusy = 1U;
751 
752     if (0U != hidHandle->interruptInPipeStall)
753     {
754         hidHandle->interruptInPipeDataBuffer = buffer;
755         hidHandle->interruptInPipeDataLen    = length;
756         return kStatus_USB_Success;
757     }
758     error = USB_DeviceSendRequest(hidHandle->handle, ep, buffer, length);
759     if (kStatus_USB_Success != error)
760     {
761         hidHandle->interruptInPipeBusy = 0U;
762     }
763     return error;
764 }
765 
766 /*!
767  * @brief Receive data through a specified endpoint.
768  *
769  * The function is used to receive data through a specified endpoint.
770  * The function calls USB_DeviceRecvRequest internally.
771  *
772  * @param handle The hid class handle got from usb_device_class_config_struct_t::classHandle.
773  * @param ep     Endpoint index.
774  * @param buffer The memory address to save the received data.
775  * @param length The data length want to be received.
776  *
777  * @return A USB error code or kStatus_USB_Success.
778  *
779  * @note The return value just means if the receiving request is successful or not; the transfer done is notified by
780  * USB_DeviceHidInterruptOut.
781  * Currently, only one transfer request can be supported for one specific endpoint.
782  * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application
783  * should implement a queue in the application level.
784  * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint
785  * callback).
786  */
USB_DeviceHidRecv(class_handle_t handle,uint8_t ep,uint8_t * buffer,uint32_t length)787 usb_status_t USB_DeviceHidRecv(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
788 {
789     usb_device_hid_struct_t *hidHandle;
790     usb_status_t error;
791 
792     if (NULL == handle)
793     {
794         return kStatus_USB_InvalidHandle;
795     }
796     hidHandle = (usb_device_hid_struct_t *)handle;
797 
798     if (0U != hidHandle->interruptOutPipeBusy)
799     {
800         return kStatus_USB_Busy;
801     }
802     hidHandle->interruptOutPipeBusy = 1U;
803 
804     if (0U != hidHandle->interruptOutPipeStall)
805     {
806         hidHandle->interruptOutPipeDataBuffer = buffer;
807         hidHandle->interruptOutPipeDataLen    = length;
808         return kStatus_USB_Success;
809     }
810     error = USB_DeviceRecvRequest(hidHandle->handle, ep, buffer, length);
811     if (kStatus_USB_Success != error)
812     {
813         hidHandle->interruptOutPipeBusy = 0U;
814     }
815     return error;
816 }
817 
818 #endif
819