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