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