1 /*
2  * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016,2019 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "usb_host_config.h"
10 #if ((defined USB_HOST_CONFIG_PHDC) && (USB_HOST_CONFIG_PHDC))
11 #include "usb_host.h"
12 #include "usb_host_phdc.h"
13 /*******************************************************************************
14  * Definitions
15  ******************************************************************************/
16 
17 /*******************************************************************************
18  * Prototypes
19  ******************************************************************************/
20 
21 /*!
22  * @brief phdc control pipe transfer callback.
23  *
24  * @param param       callback parameter.
25  * @param transfer    callback transfer.
26  * @param status      transfer status.
27  */
28 static void USB_HostPhdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
29 
30 /*!
31  * @brief phdc set and clear feature endpoint halt callback.
32  *
33  * @param param       callback parameter.
34  * @param transfer    callback transfer.
35  * @param status      transfer status.
36  */
37 static void USB_HostPhdcSetClearFeatureEndpointHaltCallback(void *param,
38                                                             usb_host_transfer_t *transfer,
39                                                             usb_status_t status);
40 
41 /*!
42  * @brief phdc interrupt pipe transfer callback.
43  *
44  * @param param       callback parameter.
45  * @param transfer    callback transfer.
46  * @param status      transfer status.
47  */
48 static void USB_HostPhdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
49 
50 /*!
51  * @brief phdc bulk in pipe transfer callback.
52  *
53  * @param param       callback parameter.
54  * @param transfer    callback transfer.
55  * @param status      transfer status.
56  */
57 static void USB_HostPhdcBulkInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
58 
59 /*!
60  * @brief phdc bulk out pipe transfer callback.
61  *
62  * @param param       callback parameter.
63  * @param transfer    callback transfer.
64  * @param status      transfer status.
65  */
66 static void USB_HostPhdcBulkOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
67 
68 /*!
69  * @brief phdc set interface callback, open pipes.
70  *
71  * @param param       callback parameter.
72  * @param transfer    callback transfer.
73  * @param status      transfer status.
74  */
75 static void USB_HostPhdcSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
76 
77 /*******************************************************************************
78  * Variables
79  ******************************************************************************/
80 
81 /*! @brief meta-data message preamble signature string */
82 static char const metaDataMsgPreambleSignature[] = "PhdcQoSSignature";
83 
84 /*******************************************************************************
85  * Code
86  ******************************************************************************/
87 
88 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
89 
USB_HostPhdcClearInHaltCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)90 static void USB_HostPhdcClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
91 {
92     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
93 
94     phdcInstance->controlTransfer = NULL;
95     /* Reduces the number of bulk transfer to 0 to expect new message preamble transfer */
96     phdcInstance->numberTransferBulkIn = 0U;
97     if (phdcInstance->inCallbackFn != NULL)
98     {
99         /* callback to application, the callback function is initialized in USB_HostPhdcRecv */
100         phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, phdcInstance->stallDataBuffer,
101                                    phdcInstance->stallDataLength, kStatus_USB_TransferStall);
102     }
103     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
104 }
105 
USB_HostPhdcClearOutHaltCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)106 static void USB_HostPhdcClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
107 {
108     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
109 
110     phdcInstance->controlTransfer = NULL;
111     if (phdcInstance->outCallbackFn != NULL)
112     {
113         /* callback to application, callback function is initialized in USB_HostPhdcSend */
114         phdcInstance->outCallbackFn(phdcInstance->outCallbackParam, phdcInstance->stallDataBuffer,
115                                     phdcInstance->stallDataLength, kStatus_USB_TransferStall);
116     }
117     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
118 }
119 
USB_HostPhdcClearHalt(usb_host_phdc_instance_t * phdcInstance,usb_host_transfer_t * stallTransfer,host_inner_transfer_callback_t callbackFn,uint8_t endpoint)120 static usb_status_t USB_HostPhdcClearHalt(usb_host_phdc_instance_t *phdcInstance,
121                                           usb_host_transfer_t *stallTransfer,
122                                           host_inner_transfer_callback_t callbackFn,
123                                           uint8_t endpoint)
124 {
125     usb_status_t status;
126     usb_host_transfer_t *transfer;
127 
128     /* malloc one transfer */
129     status = USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer);
130     if (status != kStatus_USB_Success)
131     {
132 #ifdef HOST_ECHO
133         usb_echo("allocate transfer error\r\n");
134 #endif
135         return status;
136     }
137     phdcInstance->stallDataBuffer = stallTransfer->transferBuffer;
138     phdcInstance->stallDataLength = stallTransfer->transferSofar;
139     /* save the application callback function */
140     phdcInstance->controlCallbackFn    = NULL;
141     phdcInstance->controlCallbackParam = NULL;
142     /* initialize transfer */
143     transfer->callbackFn                 = callbackFn;
144     transfer->callbackParam              = phdcInstance;
145     transfer->transferBuffer             = NULL;
146     transfer->transferLength             = 0;
147     transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_CLEAR_FEATURE;
148     transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT;
149     transfer->setupPacket->wValue  = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT);
150     transfer->setupPacket->wIndex  = USB_SHORT_TO_LITTLE_ENDIAN(endpoint);
151     transfer->setupPacket->wLength = 0;
152     status                         = USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer);
153 
154     if (status != kStatus_USB_Success)
155     {
156         (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
157     }
158     phdcInstance->controlTransfer = transfer;
159 
160     return status;
161 }
162 
163 #endif
164 
165 /*!
166  * @brief phdc control pipe transfer callback.
167  *
168  * @param param       callback parameter.
169  * @param transfer    callback transfer.
170  * @param status      transfer status.
171  */
USB_HostPhdcControlPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)172 static void USB_HostPhdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
173 {
174     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
175     phdcInstance->controlTransfer          = NULL;
176     if (kStatus_USB_Success == status)
177     {
178         if (USB_HOST_PHDC_SET_FEATURE_REQUEST == transfer->setupPacket->bRequest)
179         {
180             /* Meta-data message preamble feature is enabled */
181             phdcInstance->isMessagePreambleEnabled = 1U;
182         }
183         else if (USB_HOST_PHDC_CLEAR_FEATURE_REQUEST == transfer->setupPacket->bRequest)
184         {
185             /* Meta-data message preamble feature is disable */
186             phdcInstance->isMessagePreambleEnabled = 0U;
187         }
188         else
189         {
190             /*no action*/
191         }
192     }
193     if (NULL != phdcInstance->controlCallbackFn)
194     {
195         /* callback function is initialized in USB_HostPhdcSetInterface */
196         phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, transfer->transferBuffer,
197                                         transfer->transferSofar, status);
198     }
199     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
200 }
201 
202 /*!
203  * @brief phdc set and clear feature endpoint halt callback for meta-data message preamble error.
204  *
205  * @param param       callback parameter.
206  * @param transfer    callback transfer.
207  * @param status      transfer status.
208  */
USB_HostPhdcSetClearFeatureEndpointHaltCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)209 static void USB_HostPhdcSetClearFeatureEndpointHaltCallback(void *param,
210                                                             usb_host_transfer_t *transfer,
211                                                             usb_status_t status)
212 {
213     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
214     phdcInstance->controlTransfer          = NULL;
215     if (kStatus_USB_Success == status)
216     {
217         if ((transfer->setupPacket->bRequest == USB_REQUEST_STANDARD_SET_FEATURE) &&
218             (transfer->setupPacket->bmRequestType == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) &&
219             (transfer->setupPacket->wValue ==
220              USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT)) &&
221             (transfer->setupPacket->wIndex ==
222              USB_SHORT_TO_LITTLE_ENDIAN(phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress)))
223         {
224             /* The host shall issue CLEAR_FEATURE ENDPOINT_HALT request to the device */
225             usb_host_process_feature_param_t featureParam;
226             featureParam.requestType         = (uint8_t)kRequestEndpoint;
227             featureParam.featureSelector     = USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT;
228             featureParam.interfaceOrEndpoint = phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress;
229             if (kStatus_USB_Success != USB_HostPhdcSetClearFeatureEndpointHalt(phdcInstance->hostHandle,
230                                                                                USB_REQUEST_STANDARD_CLEAR_FEATURE,
231                                                                                &featureParam, NULL, NULL))
232             {
233 #ifdef HOST_ECHO
234                 usb_echo("Error for USB_HostPhdcSetClearFeatureEndpointHalt\r\n");
235 #endif
236             }
237         }
238         if ((transfer->setupPacket->bRequest == USB_REQUEST_STANDARD_CLEAR_FEATURE) &&
239             (transfer->setupPacket->bmRequestType == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) &&
240             (transfer->setupPacket->wValue ==
241              USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT)) &&
242             (transfer->setupPacket->wIndex ==
243              USB_SHORT_TO_LITTLE_ENDIAN(phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress)))
244         {
245             /* Reduces the number of bulk transfer to 0 to expect new message preamble transfer */
246             phdcInstance->numberTransferBulkIn = 0U;
247         }
248     }
249     if (NULL != phdcInstance->controlCallbackFn)
250     {
251         /* Notify to application the status of request, callback function is initialized in USB_HostPhdcSetInterface */
252         phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, transfer->transferBuffer,
253                                         transfer->transferSofar, status);
254     }
255     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
256 }
257 
258 /*!
259  * @brief phdc interrupt pipe transfer callback.
260  *
261  * @param param       callback parameter.
262  * @param transfer    callback transfer.
263  * @param status      transfer status.
264  */
USB_HostPhdcInterruptPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)265 static void USB_HostPhdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
266 {
267     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
268 
269 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
270     if (status == kStatus_USB_TransferStall)
271     {
272         if (USB_HostPhdcClearHalt(
273                 phdcInstance, transfer, USB_HostPhdcClearInHaltCallback,
274                 (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)phdcInstance->interruptPipe)->endpointAddress)) ==
275             kStatus_USB_Success)
276         {
277             (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
278             return;
279         }
280     }
281 #endif
282     if (NULL != phdcInstance->inCallbackFn)
283     {
284         /* callback to application, the callback function is initialized in USB_HostPhdcRecv */
285         phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar,
286                                    status);
287     }
288     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
289 }
290 
291 /*!
292  * @brief phdc bulk in pipe transfer callback.
293  *
294  * @param param       callback parameter.
295  * @param transfer    callback transfer.
296  * @param status      transfer status.
297  */
USB_HostPhdcBulkInPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)298 static void USB_HostPhdcBulkInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
299 {
300     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
301     void *temp;
302 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
303     if (status == kStatus_USB_TransferStall)
304     {
305         if (USB_HostPhdcClearHalt(
306                 phdcInstance, transfer, USB_HostPhdcClearInHaltCallback,
307                 (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)phdcInstance->bulkInPipe)->endpointAddress)) ==
308             kStatus_USB_Success)
309         {
310             (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
311             return;
312         }
313     }
314 #endif
315     if (status == kStatus_USB_Success)
316     {
317         /* The meta-data message preamble is implemented and enabled */
318         if (phdcInstance->isMessagePreambleEnabled == 1U)
319         {
320             /* The meta-data message preamble feature is enabled, then all data transfers or sets
321             of data transfers shall be preceded by a meta-data message preamble transfer. The
322             numberTransferBulkIn is initialized as zero for receiving this message preamble data,
323             then it is updated to the value of bNumTransfers field of message preamble data */
324             if (0U != phdcInstance->numberTransferBulkIn)
325             {
326                 /* When numberTransferBulkIn reduces to 0, a new meta-data message preamble shall
327                 be transferred */
328                 phdcInstance->numberTransferBulkIn--;
329             }
330             else
331             {
332                 uint8_t preambleSignatureChecking = 1U;
333                 /* The received packet is meta-data message preamble */
334                 temp                                                   = (void *)transfer->transferBuffer;
335                 usb_host_phdc_metadata_preamble_t *metaDataMsgPreamble = (usb_host_phdc_metadata_preamble_t *)temp;
336                 /* Meta-data message preamble signature checking */
337                 for (uint8_t i = 0U; i < USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE; i++)
338                 {
339                     if (*(transfer->transferBuffer + i) != (uint8_t)metaDataMsgPreambleSignature[i])
340                     {
341                         preambleSignatureChecking = 0U;
342                         break;
343                     }
344                 }
345                 if (0U != preambleSignatureChecking)
346                 {
347                     /* Checks if the meta-data message preamble contains an invalid bmLatencyReliability value
348                     or bNumTransfers value */
349                     if ((0U == (metaDataMsgPreamble->bNumberTransfers)) || /* bNumTransfers shall never equal zero */
350                         (metaDataMsgPreamble->bQosEncodingVersion != 0x01U) || /* Encoding version should be 0x01 */
351                         ((metaDataMsgPreamble->bmLatencyReliability !=
352                           0x02U) && /* Medium.Good latency, reliability bin */
353                          (metaDataMsgPreamble->bmLatencyReliability !=
354                           0x04U) && /* Medium.Better latency, reliability bin */
355                          (metaDataMsgPreamble->bmLatencyReliability !=
356                           0x08U) && /* Medium.Best latency, reliability bin */
357                          (metaDataMsgPreamble->bmLatencyReliability !=
358                           0x10U) && /* High.Best latency, reliability bin */
359                          (metaDataMsgPreamble->bmLatencyReliability !=
360                           0x20U) /* VeryHigh.Best latency, reliability bin */))
361                     {
362                         /* The host shall issue SET_FEATURE ENDPOINT_HALT request to the device */
363                         usb_host_process_feature_param_t featureParam;
364                         featureParam.requestType     = (uint8_t)kRequestEndpoint;
365                         featureParam.featureSelector = USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT;
366                         featureParam.interfaceOrEndpoint =
367                             phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress;
368                         if (kStatus_USB_Success !=
369                             USB_HostPhdcSetClearFeatureEndpointHalt(
370                                 phdcInstance->hostHandle, USB_REQUEST_STANDARD_SET_FEATURE, &featureParam, NULL, NULL))
371                         {
372 #ifdef HOST_ECHO
373                             usb_echo(
374                                 "USB_HostPhdcBulkInPipeCallback: Error for "
375                                 "USB_HostPhdcSetClearFeatureEndpointHalt\r\n");
376 #endif
377                         }
378                     }
379                     else
380                     {
381                         /* The meta-data message preamble data is correct, update the phdc status and
382                          * numberTransferBulkIn value */
383                         phdcInstance->numberTransferBulkIn = metaDataMsgPreamble->bNumberTransfers;
384                     }
385                 }
386             }
387         }
388     }
389     if (NULL != phdcInstance->inCallbackFn)
390     {
391         /* callback to application, the callback function is initialized in USB_HostPhdcRecv */
392         phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar,
393                                    status);
394     }
395     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
396 }
397 
398 /*!
399  * @brief phdc bulk out pipe transfer callback.
400  *
401  * @param param       callback parameter.
402  * @param transfer    callback transfer.
403  * @param status      transfer status.
404  */
USB_HostPhdcBulkOutPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)405 static void USB_HostPhdcBulkOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
406 {
407     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
408 
409 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
410     if (status == kStatus_USB_TransferStall)
411     {
412         if (USB_HostPhdcClearHalt(
413                 phdcInstance, transfer, USB_HostPhdcClearOutHaltCallback,
414                 (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)phdcInstance->bulkOutPipe)->endpointAddress)) ==
415             kStatus_USB_Success)
416         {
417             (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
418             return;
419         }
420     }
421 #endif
422     if (NULL != phdcInstance->outCallbackFn)
423     {
424         /* callback to application, callback function is initialized in USB_HostPhdcSend */
425         phdcInstance->outCallbackFn(phdcInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar,
426                                     status);
427     }
428     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
429 }
430 
431 /*!
432  * @brief phdc open interface.
433  *
434  * @param phdcInstance     phdc instance pointer.
435  *
436  * @return kStatus_USB_Success or error codes.
437  */
USB_HostPhdcOpenInterface(usb_host_phdc_instance_t * phdcInstance)438 static usb_status_t USB_HostPhdcOpenInterface(usb_host_phdc_instance_t *phdcInstance)
439 {
440     usb_status_t status;
441     uint8_t epIndex = 0U;
442     usb_host_pipe_init_t pipeInit;
443     usb_descriptor_endpoint_t *epDesc = NULL;
444     usb_host_interface_t *interface;
445     if (NULL != phdcInstance->interruptPipe)
446     {
447         /* Close the PHDC interrupt pipe if it is opening */
448         status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->interruptPipe);
449 
450         if (status != kStatus_USB_Success)
451         {
452 #ifdef HOST_ECHO
453             usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n");
454 #endif
455         }
456         phdcInstance->interruptPipe = NULL;
457     }
458 
459     if (NULL != phdcInstance->bulkInPipe)
460     {
461         /* Close the PHDC bulk in pipe if it is opening */
462         status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkInPipe);
463 
464         if (status != kStatus_USB_Success)
465         {
466 #ifdef HOST_ECHO
467             usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n");
468 #endif
469         }
470         phdcInstance->bulkInPipe = NULL;
471     }
472 
473     if (NULL != phdcInstance->bulkOutPipe)
474     {
475         /* Close the PHDC bulk out pipe if it is opening */
476         status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkOutPipe);
477 
478         if (status != kStatus_USB_Success)
479         {
480 #ifdef HOST_ECHO
481             usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n");
482 #endif
483         }
484         phdcInstance->bulkOutPipe = NULL;
485     }
486 
487     /* open interface pipes */
488     interface = (usb_host_interface_t *)phdcInstance->interfaceHandle;
489     for (epIndex = 0U; epIndex < interface->epCount; ++epIndex)
490     {
491         epDesc = interface->epList[epIndex].epDesc;
492         if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
493              USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
494             ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT))
495         {
496             /* Initialize the interrupt pipe */
497             pipeInit.devInstance     = phdcInstance->deviceHandle;
498             pipeInit.pipeType        = USB_ENDPOINT_INTERRUPT;
499             pipeInit.direction       = USB_IN;
500             pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
501             pipeInit.interval        = epDesc->bInterval;
502             pipeInit.maxPacketSize   = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) &
503                                                  USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
504             pipeInit.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) &
505                                                   USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
506             pipeInit.nakCount        = USB_HOST_CONFIG_MAX_NAK;
507             status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->interruptPipe, &pipeInit);
508             if (status != kStatus_USB_Success)
509             {
510 #ifdef HOST_ECHO
511                 usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n");
512 #endif
513                 return kStatus_USB_Error;
514             }
515             /* save interrupt in endpoint information */
516             phdcInstance->interruptInEndpointInformation = interface->epList[epIndex];
517         }
518         else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
519                   USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
520                  ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK))
521         {
522             /* Initialize bulk in pipe */
523             pipeInit.devInstance     = phdcInstance->deviceHandle;
524             pipeInit.pipeType        = USB_ENDPOINT_BULK;
525             pipeInit.direction       = USB_IN;
526             pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
527             pipeInit.maxPacketSize   = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) &
528                                                  USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
529             pipeInit.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) &
530                                                   USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
531             pipeInit.nakCount        = USB_HOST_CONFIG_MAX_NAK;
532             pipeInit.interval        = 0U;
533             status                   = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->bulkInPipe, &pipeInit);
534             if (status != kStatus_USB_Success)
535             {
536 #ifdef HOST_ECHO
537                 usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n");
538 #endif
539                 return kStatus_USB_Error;
540             }
541             /* save bulk in endpoint information */
542             phdcInstance->bulkInEndpointInformation = interface->epList[epIndex];
543         }
544         else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
545                   USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) &&
546                  ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK))
547         {
548             /* Initialize bulk out pipe */
549             pipeInit.devInstance     = phdcInstance->deviceHandle;
550             pipeInit.pipeType        = USB_ENDPOINT_BULK;
551             pipeInit.direction       = USB_OUT;
552             pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
553             pipeInit.maxPacketSize   = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) &
554                                                  USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
555             pipeInit.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) &
556                                                   USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
557             pipeInit.nakCount        = USB_HOST_CONFIG_MAX_NAK;
558             pipeInit.interval        = 0U;
559             status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->bulkOutPipe, &pipeInit);
560             if (status != kStatus_USB_Success)
561             {
562 #ifdef HOST_ECHO
563                 usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n");
564 #endif
565                 return kStatus_USB_Error;
566             }
567             /* save bulk out endpoint information */
568             phdcInstance->bulkOutEndpointInformation = interface->epList[epIndex];
569         }
570         else
571         {
572             /*no action*/
573         }
574     }
575     return kStatus_USB_Success;
576 }
577 
578 /*!
579  * @brief phdc set interface callback, open pipes.
580  *
581  * @param param       callback parameter.
582  * @param transfer    callback transfer.
583  * @param status      transfer status.
584  */
USB_HostPhdcSetInterfaceCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)585 static void USB_HostPhdcSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
586 {
587     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param;
588 
589     phdcInstance->controlTransfer = NULL;
590     if (status == kStatus_USB_Success)
591     {
592         /* set interface is done, open the interface */
593         status = USB_HostPhdcOpenInterface(phdcInstance);
594     }
595 
596     if (NULL != phdcInstance->controlCallbackFn)
597     {
598         /* Notify to application the status of set interface request, callback function is initialized in
599          * USB_HostPhdcSetInterface */
600         phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, NULL, 0U, status);
601     }
602     (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
603 }
604 
605 /*!
606  * @brief set interface.
607  *
608  * This function binds the interface with the phdc instance.
609  *
610  * @param classHandle      the class handle.
611  * @param interfaceHandle  the interface handle.
612  * @param alternateSetting the alternate setting value.
613  * @param callbackFn       this callback is called after this function completes.
614  * @param callbackParam    the first parameter in the callback function.
615  *
616  * @retval kStatus_USB_Success        The device is initialized successfully.
617  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
618  * @retval kStatus_USB_Busy           There is no idle transfer.
619  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
620  * @retval kStatus_USB_Busy           callback return status, there is no idle pipe.
621  * @retval kStatus_USB_TransferStall  callback return status, the transfer is stall by device.
622  * @retval kStatus_USB_Error          callback return status, open pipe fail, please reference to USB_HostOpenPipe.
623  */
USB_HostPhdcSetInterface(usb_host_class_handle classHandle,usb_host_interface_handle interfaceHandle,uint8_t alternateSetting,transfer_callback_t callbackFn,void * callbackParam)624 usb_status_t USB_HostPhdcSetInterface(usb_host_class_handle classHandle,
625                                       usb_host_interface_handle interfaceHandle,
626                                       uint8_t alternateSetting,
627                                       transfer_callback_t callbackFn,
628                                       void *callbackParam)
629 {
630     usb_status_t status;
631     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
632     usb_host_transfer_t *transfer;
633 
634     if (NULL == classHandle)
635     {
636         return kStatus_USB_InvalidParameter;
637     }
638 
639     phdcInstance->interfaceHandle = interfaceHandle;
640 
641     status = USB_HostOpenDeviceInterface(phdcInstance->deviceHandle, interfaceHandle);
642     if (status != kStatus_USB_Success)
643     {
644         return status;
645     }
646 
647     /* Cancel interrupt transfers */
648     if (NULL != phdcInstance->interruptPipe)
649     {
650         status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->interruptPipe, NULL);
651         if (status != kStatus_USB_Success)
652         {
653 #ifdef HOST_ECHO
654             usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n");
655 #endif
656         }
657     }
658     /* Cancel bulk in transfers */
659     if (NULL != phdcInstance->bulkInPipe)
660     {
661         status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkInPipe, NULL);
662         if (status != kStatus_USB_Success)
663         {
664 #ifdef HOST_ECHO
665             usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n");
666 #endif
667         }
668     }
669     /* Cancel bulk out transfers */
670     if (NULL != phdcInstance->bulkOutPipe)
671     {
672         status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, NULL);
673         if (status != kStatus_USB_Success)
674         {
675 #ifdef HOST_ECHO
676             usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n");
677 #endif
678         }
679         phdcInstance->bulkOutPipe = NULL;
680     }
681     if (0U == alternateSetting)
682     {
683         if (NULL != callbackFn)
684         {
685             status = USB_HostPhdcOpenInterface(phdcInstance);
686             callbackFn(callbackParam, NULL, 0U, status);
687         }
688     }
689     else
690     {
691         /* Create transfer buffer */
692         if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
693         {
694 #ifdef HOST_ECHO
695             usb_echo("USB_HostPhdcSetInterface: Error to get transfer\r\n");
696 #endif
697             return kStatus_USB_Error;
698         }
699         /* Save application callback function and parameter */
700         phdcInstance->controlCallbackFn    = callbackFn;
701         phdcInstance->controlCallbackParam = callbackParam;
702         /* Initialize transfer */
703         transfer->callbackFn                 = USB_HostPhdcSetInterfaceCallback;
704         transfer->callbackParam              = phdcInstance;
705         transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_SET_INTERFACE;
706         transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
707         transfer->setupPacket->wIndex        = USB_SHORT_TO_LITTLE_ENDIAN(
708             ((usb_host_interface_t *)phdcInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber);
709         transfer->setupPacket->wValue  = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting);
710         transfer->setupPacket->wLength = 0;
711         transfer->transferBuffer       = NULL;
712         transfer->transferLength       = 0;
713         /* Send set interface request to device */
714         status = USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer);
715         if (status == kStatus_USB_Success)
716         {
717             phdcInstance->controlTransfer = transfer;
718         }
719         else
720         {
721             (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
722         }
723     }
724     return status;
725 }
726 
727 /*!
728  * @brief initialize the phdc instance.
729  *
730  * This function allocates the resource for phdc instance.
731  *
732  * @param deviceHandle       the device handle.
733  * @param classHandle        return class handle.
734  *
735  * @retval kStatus_USB_Success        The device is initialized successfully.
736  * @retval kStatus_USB_AllocFail      Allocate memory fail.
737  */
USB_HostPhdcInit(usb_host_handle deviceHandle,usb_host_class_handle * classHandle)738 usb_status_t USB_HostPhdcInit(usb_host_handle deviceHandle, usb_host_class_handle *classHandle)
739 {
740     usb_host_phdc_instance_t *phdcInstance =
741         (usb_host_phdc_instance_t *)OSA_MemoryAllocate(sizeof(usb_host_phdc_instance_t));
742     uint32_t infoValue = 0U;
743     uint32_t *temp;
744     if (NULL == phdcInstance)
745     {
746         return kStatus_USB_AllocFail;
747     }
748     /* Initialize PHDC instance */
749     phdcInstance->deviceHandle    = deviceHandle;
750     phdcInstance->interfaceHandle = NULL;
751     (void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetHostHandle, &infoValue);
752     temp                     = (uint32_t *)infoValue;
753     phdcInstance->hostHandle = (usb_host_handle)temp;
754     (void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceControlPipe, &infoValue);
755     temp                      = (uint32_t *)infoValue;
756     phdcInstance->controlPipe = (usb_host_pipe_handle)temp;
757 
758     *classHandle = phdcInstance;
759     return kStatus_USB_Success;
760 }
761 
762 /*!
763  * @brief de-initialize the phdc instance.
764  *
765  * This function release the resource for phdc instance.
766  *
767  * @param deviceHandle   the device handle.
768  * @param classHandle the class handle.
769  *
770  * @retval kStatus_USB_Success        The device is de-initialized successfully.
771  */
USB_HostPhdcDeinit(usb_host_handle deviceHandle,usb_host_class_handle classHandle)772 usb_status_t USB_HostPhdcDeinit(usb_host_handle deviceHandle, usb_host_class_handle classHandle)
773 {
774     usb_status_t status;
775     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
776 
777     if (NULL == deviceHandle)
778     {
779         return kStatus_USB_InvalidHandle;
780     }
781 
782     if (NULL != classHandle)
783     {
784         if (NULL != phdcInstance->interruptPipe)
785         {
786             /* Cancel/close interrupt transfers/pipe */
787             status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->interruptPipe, NULL);
788             if (status != kStatus_USB_Success)
789             {
790 #ifdef HOST_ECHO
791                 usb_echo("error when cancel pipe\r\n");
792 #endif
793             }
794             status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->interruptPipe);
795 
796             if (status != kStatus_USB_Success)
797             {
798 #ifdef HOST_ECHO
799                 usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n");
800 #endif
801             }
802             phdcInstance->interruptPipe = NULL;
803         }
804         if (NULL != phdcInstance->bulkInPipe)
805         {
806             /* Cancel/close bulk in transfers/pipe */
807             status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkInPipe, NULL);
808             if (status != kStatus_USB_Success)
809             {
810 #ifdef HOST_ECHO
811                 usb_echo("error when cancel pipe\r\n");
812 #endif
813             }
814             status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkInPipe);
815 
816             if (status != kStatus_USB_Success)
817             {
818 #ifdef HOST_ECHO
819                 usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n");
820 #endif
821             }
822             phdcInstance->bulkInPipe = NULL;
823         }
824         if (NULL != phdcInstance->bulkOutPipe)
825         {
826             /* Cancel/close bulk out transfers/pipe */
827             status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, NULL);
828             if (status != kStatus_USB_Success)
829             {
830 #ifdef HOST_ECHO
831                 usb_echo("error when cancel pipe\r\n");
832 #endif
833             }
834             status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkOutPipe);
835 
836             if (status != kStatus_USB_Success)
837             {
838 #ifdef HOST_ECHO
839                 usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n");
840 #endif
841             }
842             phdcInstance->bulkOutPipe = NULL;
843         }
844         if ((NULL != phdcInstance->controlPipe) && (NULL != phdcInstance->controlTransfer))
845         {
846             /* Cancel control transfers */
847             status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->controlPipe,
848                                             phdcInstance->controlTransfer);
849             if (status != kStatus_USB_Success)
850             {
851 #ifdef HOST_ECHO
852                 usb_echo("error when cancel pipe\r\n");
853 #endif
854             }
855         }
856         /* Close device interface */
857         (void)USB_HostCloseDeviceInterface(deviceHandle, phdcInstance->interfaceHandle);
858         /* Release PHDC instance */
859         OSA_MemoryFree(phdcInstance);
860     }
861     else
862     {
863         (void)USB_HostCloseDeviceInterface(deviceHandle, NULL);
864     }
865     return kStatus_USB_Success;
866 }
867 
868 /*!
869  * @brief receive data.
870  *
871  * This function implements phdc receiving data.
872  *
873  * @param classHandle   the class handle.
874  * @param qos           QoS of the data being received.
875  * @param buffer        the buffer pointer.
876  * @param bufferLength  the buffer length.
877  * @param callbackFn    this callback is called after this function completes.
878  * @param callbackParam the first parameter in the callback function.
879  *
880  * @retval kStatus_USB_Success        receive request successfully.
881  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
882  * @retval kStatus_USB_Busy           There is no idle transfer.
883  * @retval kStatus_USB_Error          pipe is not initialized.
884  *                                    Or, send transfer fail, please reference to USB_HostRecv.
885  */
USB_HostPhdcRecv(usb_host_class_handle classHandle,uint8_t qos,uint8_t * buffer,uint32_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)886 usb_status_t USB_HostPhdcRecv(usb_host_class_handle classHandle,
887                               uint8_t qos,
888                               uint8_t *buffer,
889                               uint32_t bufferLength,
890                               transfer_callback_t callbackFn,
891                               void *callbackParam)
892 {
893     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
894     usb_host_transfer_t *transfer;
895     usb_host_pipe_handle pipe;
896     usb_host_phdc_qos_descriptor_t *qosDesc = NULL;
897     void *temp;
898     if (NULL == classHandle)
899     {
900         return kStatus_USB_InvalidHandle;
901     }
902 
903     if ((NULL == phdcInstance->interruptPipe) && (NULL == phdcInstance->bulkInPipe))
904     {
905         return kStatus_USB_Error;
906     }
907     /* Allocate the transfer buffer */
908     if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
909     {
910 #ifdef HOST_ECHO
911         usb_echo("error to get transfer\r\n");
912 #endif
913         return kStatus_USB_Error;
914     }
915     /* Save application callback function and parameter */
916     phdcInstance->inCallbackFn    = callbackFn;
917     phdcInstance->inCallbackParam = callbackParam;
918     /* Initialize the transfer pointer */
919     transfer->transferBuffer = buffer;
920     transfer->transferLength = bufferLength;
921     transfer->callbackParam  = phdcInstance;
922     /* The on can receive the data on interrupt pipe or bulk in pipe depends on the QoS value */
923     pipe = (0U != (qos & 0x01U)) ? (phdcInstance->interruptPipe) : (phdcInstance->bulkInPipe);
924     if (pipe == phdcInstance->bulkInPipe)
925     {
926         /* get bulk in QoS descriptor */
927         temp                 = (void *)phdcInstance->bulkInEndpointInformation.epExtension;
928         qosDesc              = (usb_host_phdc_qos_descriptor_t *)temp;
929         transfer->callbackFn = USB_HostPhdcBulkInPipeCallback;
930     }
931     else
932     {
933         /* get interrupt in QoS descriptor */
934         temp                 = (void *)phdcInstance->interruptInEndpointInformation.epExtension;
935         qosDesc              = (usb_host_phdc_qos_descriptor_t *)temp;
936         transfer->callbackFn = USB_HostPhdcInterruptPipeCallback;
937     }
938     /* Latency and reliability checking */
939     if (0U == (qos & qosDesc->bmLatencyReliability))
940     {
941 #ifdef HOST_ECHO
942         usb_echo("USB_HostPhdcRecv, ERROR: invalid QoS bin");
943 #endif
944         return kStatus_USB_Error;
945     }
946     /* The previous control transfer is pending */
947     if (NULL != phdcInstance->controlTransfer)
948     {
949 #ifdef HOST_ECHO
950         usb_echo("USB_HostPhdcRecv, ERROR: Control transfer is in progress");
951 #endif
952         return kStatus_USB_Busy;
953     }
954     if (USB_HostRecv(phdcInstance->hostHandle, pipe, transfer) != kStatus_USB_Success)
955     {
956 #ifdef HOST_ECHO
957         usb_echo("fail to USB_HostRecv\r\n");
958 #endif
959         (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
960         return kStatus_USB_Error;
961     }
962 
963     return kStatus_USB_Success;
964 }
965 
966 /*!
967  * @brief send data.
968  *
969  * This function implements phdc sending data.
970  *
971  * @param classHandle   the class handle.
972  * @param buffer        the buffer pointer.
973  * @param bufferLength  the buffer length.
974  * @param callbackFn    this callback is called after this function completes.
975  * @param callbackParam the first parameter in the callback function.
976  *
977  * @retval kStatus_USB_Success        send request successfully.
978  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
979  * @retval kStatus_USB_Busy           There is no idle transfer.
980  * @retval kStatus_USB_Error          pipe is not initialized.
981  *                                    Or, send transfer fail, please reference to USB_HostSend.
982  */
USB_HostPhdcSend(usb_host_class_handle classHandle,uint8_t * buffer,uint32_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)983 usb_status_t USB_HostPhdcSend(usb_host_class_handle classHandle,
984                               uint8_t *buffer,
985                               uint32_t bufferLength,
986                               transfer_callback_t callbackFn,
987                               void *callbackParam)
988 {
989     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
990     usb_host_transfer_t *transfer;
991     void *temp;
992     usb_host_phdc_metadata_preamble_t *preamble;
993     usb_status_t status;
994     if (classHandle == NULL)
995     {
996         return kStatus_USB_InvalidHandle;
997     }
998 
999     if (NULL == phdcInstance->bulkOutPipe)
1000     {
1001         return kStatus_USB_Error;
1002     }
1003     if (NULL != phdcInstance->controlTransfer)
1004     {
1005         status = kStatus_USB_Busy;
1006 #ifdef HOST_ECHO
1007         usb_echo("USB_HostPhdcSend, Error: control transfer is in progress");
1008 #endif
1009         return status;
1010     }
1011     /* The meta-data message preamble is implemented and enabled */
1012     if (phdcInstance->isMessagePreambleEnabled == 1U)
1013     {
1014         /* The meta-data message preamble feature is enabled, then all data transfers or sets
1015         of data transfers shall be preceded by a meta-data message preamble transfer. The
1016         numberTransferBulkOut is initialized as zero for sending this message preamble data,
1017         then it is updated to the value of bNumTransfers field of message preamble data */
1018         if (0U != phdcInstance->numberTransferBulkOut)
1019         {
1020             /* When numberTransferBulkOut reduces to 0, a new meta-data message preamble shall
1021             be transferred */
1022             phdcInstance->numberTransferBulkOut--;
1023         }
1024         else
1025         {
1026             temp                                    = (void *)phdcInstance->bulkOutEndpointInformation.epExtension;
1027             usb_host_phdc_qos_descriptor_t *qosDesc = (usb_host_phdc_qos_descriptor_t *)temp;
1028             temp                                    = (void *)buffer;
1029             preamble                                = (usb_host_phdc_metadata_preamble_t *)temp;
1030             uint8_t latencyReliability              = preamble->bmLatencyReliability;
1031             /* Latency reliability validity checking */
1032             if ((latencyReliability != 0x02U) && /* Medium.Good latency, reliability bin */
1033                 (latencyReliability != 0x04U) && /* Medium.Better latency, reliability bin */
1034                 (latencyReliability != 0x08U) && /* Medium.Best latency, reliability bin */
1035                 (latencyReliability != 0x10U) && /* High.Best latency, reliability bin */
1036                 (latencyReliability != 0x20U) /* VeryHigh.Best latency, reliability bin */)
1037             {
1038                 status = kStatus_USB_InvalidRequest;
1039 #ifdef HOST_ECHO
1040                 usb_echo("USB_HostPhdcSend, Error: invalid LatencyReliability");
1041 #endif
1042                 return status;
1043             }
1044             /* LatencyReliablity checking */
1045             if (0U == (qosDesc->bmLatencyReliability & latencyReliability))
1046             {
1047                 status = kStatus_USB_Error;
1048 #ifdef HOST_ECHO
1049                 usb_echo("USB_HostPhdcSend, Error: the latency reliability is not supported by Bulk OUT endpoint");
1050 #endif
1051                 return status;
1052             }
1053             if (0U == preamble->bNumberTransfers)
1054             {
1055                 status = kStatus_USB_Error;
1056 #ifdef HOST_ECHO
1057                 usb_echo("USB_HostPhdcSend, Error: the numTransfer should never zero");
1058 #endif
1059                 return status;
1060             }
1061             /* Update the number of bulk out transfer */
1062             phdcInstance->numberTransferBulkOut = preamble->bNumberTransfers;
1063         }
1064     }
1065     /* Allocate the transfer pointer */
1066     if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
1067     {
1068 #ifdef HOST_ECHO
1069         usb_echo("error to get transfer\r\n");
1070 #endif
1071         return kStatus_USB_Error;
1072     }
1073     /* Save the application callback function and parameter */
1074     phdcInstance->outCallbackFn    = callbackFn;
1075     phdcInstance->outCallbackParam = callbackParam;
1076     /* Initialize the transfer pointer */
1077     transfer->transferBuffer = buffer;
1078     transfer->transferLength = bufferLength;
1079     transfer->callbackFn     = USB_HostPhdcBulkOutPipeCallback;
1080     transfer->callbackParam  = phdcInstance;
1081     if (USB_HostSend(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, transfer) != kStatus_USB_Success)
1082     {
1083 #ifdef HOST_ECHO
1084         usb_echo("fail to USB_HostSend\r\n");
1085 #endif
1086         (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
1087         return kStatus_USB_Error;
1088     }
1089     return kStatus_USB_Success;
1090 }
1091 
1092 /*!
1093  * @brief phdc sends control request.
1094  *
1095  * @param classHandle   the class handle.
1096  * @param request_type  setup packet request.
1097  * @param callbackFn    this callback is called after this function completes.
1098  * @param callbackParam the first parameter in the callback function.
1099  *
1100  * @retval kStatus_USB_Success        send request successfully.
1101  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1102  * @retval kStatus_USB_Busy           There is no idle transfer.
1103  * @retval kStatus_USB_Error          pipe is not initialized.
1104  *                                    Or, send transfer fail, please reference to USB_HostSend.
1105  */
USB_HostPhdcSendControlRequest(usb_host_class_handle classHandle,uint8_t request,transfer_callback_t callbackFn,void * callbackParam)1106 usb_status_t USB_HostPhdcSendControlRequest(usb_host_class_handle classHandle,
1107                                             uint8_t request,
1108                                             transfer_callback_t callbackFn,
1109                                             void *callbackParam)
1110 {
1111     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
1112     usb_status_t status                    = kStatus_USB_Success;
1113     usb_host_transfer_t *transfer;
1114 
1115     if (NULL == classHandle)
1116     {
1117         return kStatus_USB_InvalidHandle;
1118     }
1119 
1120     if (NULL == phdcInstance->controlPipe)
1121     {
1122         return kStatus_USB_Error;
1123     }
1124 
1125     if (NULL != phdcInstance->controlTransfer)
1126     {
1127         return kStatus_USB_Busy;
1128     }
1129     /* Allocate the transfer pointer */
1130     if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
1131     {
1132 #ifdef HOST_ECHO
1133         usb_echo("error to get transfer\r\n");
1134 #endif
1135         return kStatus_USB_Error;
1136     }
1137     /* Save the callback function and parameter */
1138     phdcInstance->controlCallbackFn    = callbackFn;
1139     phdcInstance->controlCallbackParam = callbackParam;
1140     /* Initialize the transfer pointer */
1141     transfer->callbackFn            = USB_HostPhdcControlPipeCallback;
1142     transfer->callbackParam         = phdcInstance;
1143     transfer->setupPacket->bRequest = request;
1144     transfer->setupPacket->wIndex   = USB_SHORT_TO_LITTLE_ENDIAN(
1145         ((usb_host_interface_t *)phdcInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber);
1146     switch (request)
1147     {
1148         case USB_HOST_PHDC_GET_STATUS_REQUEST:
1149             /* Initialize the PHDC get status request */
1150             transfer->setupPacket->wValue = 0U;
1151             transfer->setupPacket->bmRequestType =
1152                 USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
1153             transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(2U);
1154             break;
1155         case USB_HOST_PHDC_SET_FEATURE_REQUEST:
1156         case USB_HOST_PHDC_CLEAR_FEATURE_REQUEST:
1157             /* Initialize the PHDC set/clear feature request */
1158             transfer->setupPacket->bmRequestType =
1159                 USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
1160             transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(
1161                 USB_HOST_PHDC_FEATURE_METADATA | (uint16_t)((uint16_t)USB_HOST_PHDC_QOS_ENCODING_VERSION << 8U));
1162             transfer->setupPacket->wLength = 0U;
1163             break;
1164         default:
1165             status = kStatus_USB_InvalidRequest;
1166             break;
1167     }
1168     if (USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer) != kStatus_USB_Success)
1169     {
1170 #ifdef HOST_ECHO
1171         usb_echo("fail for USB_HostSendSetup\r\n");
1172 #endif
1173         (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
1174         return kStatus_USB_Error;
1175     }
1176     phdcInstance->controlTransfer = transfer;
1177 
1178     return status;
1179 }
1180 
1181 /*!
1182  * @brief phdc set and clear feature endpoint halt request for meta-data message preamble error.
1183  *
1184  * @param classHandle   the class handle.
1185  * @param request       setup packet request.
1186  * @param param         request parameter
1187  * @param callbackFn    this callback is called after this function completes.
1188  * @param callbackParam the first parameter in the callback function.
1189  *
1190  * @retval kStatus_USB_Success        send request successfully.
1191  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1192  * @retval kStatus_USB_Busy           There is no idle transfer.
1193  * @retval kStatus_USB_Error          pipe is not initialized.
1194  *                                    Or, send transfer fail, please reference to USB_HostSend.
1195  */
USB_HostPhdcSetClearFeatureEndpointHalt(usb_host_class_handle classHandle,uint8_t request,void * param,transfer_callback_t callbackFn,void * callbackParam)1196 usb_status_t USB_HostPhdcSetClearFeatureEndpointHalt(usb_host_class_handle classHandle,
1197                                                      uint8_t request,
1198                                                      void *param,
1199                                                      transfer_callback_t callbackFn,
1200                                                      void *callbackParam)
1201 {
1202     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
1203     usb_host_transfer_t *transfer;
1204     if (NULL == classHandle)
1205     {
1206         return kStatus_USB_InvalidHandle;
1207     }
1208 
1209     if (NULL == phdcInstance->controlPipe)
1210     {
1211         return kStatus_USB_Error;
1212     }
1213 
1214     if (NULL != phdcInstance->controlTransfer)
1215     {
1216         return kStatus_USB_Busy;
1217     }
1218     /* Allocate the transfer pointer */
1219     if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
1220     {
1221 #ifdef HOST_ECHO
1222         usb_echo("error to get transfer\r\n");
1223 #endif
1224         return kStatus_USB_Error;
1225     }
1226     /* Save application callback function and parameter */
1227     phdcInstance->controlCallbackFn    = callbackFn;
1228     phdcInstance->controlCallbackParam = callbackParam;
1229     /* Initialize the transfer request */
1230     transfer->callbackFn    = USB_HostPhdcSetClearFeatureEndpointHaltCallback;
1231     transfer->callbackParam = phdcInstance;
1232     if (kStatus_USB_Success != USB_HostRequestControl(phdcInstance->deviceHandle, request, transfer, param))
1233     {
1234 #ifdef HOST_ECHO
1235         usb_echo("fail for USB_HostRequestControl\r\n");
1236 #endif
1237         (void)USB_HostFreeTransfer(phdcInstance->hostHandle, transfer);
1238         return kStatus_USB_Error;
1239     }
1240     phdcInstance->controlTransfer = transfer;
1241 
1242     return kStatus_USB_Success;
1243 }
1244 
1245 /*!
1246  * @brief USB_HostPhdcGetEndpointInformation.
1247  * This function returns the PHDC endpoint information structure contains endpoint
1248  * descriptor and endpoint extended descriptor.
1249  *
1250  * @param classHandle   the class handle.
1251  * @param pipeType      pipe type.
1252  * @param direction     pipe direction.
1253  *
1254  * @retval endpointReturn   All input parameters are valid.
1255  * @retval NULL             One or more input parameters are invalid.
1256  */
USB_HostPhdcGetEndpointInformation(usb_host_class_handle classHandle,uint8_t pipeType,uint8_t direction)1257 usb_host_ep_t *USB_HostPhdcGetEndpointInformation(usb_host_class_handle classHandle,
1258                                                   uint8_t pipeType,
1259                                                   uint8_t direction)
1260 {
1261     usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle;
1262     usb_host_ep_t *endpointReturn          = NULL;
1263     if (NULL != classHandle)
1264     {
1265         if (pipeType == USB_ENDPOINT_BULK)
1266         {
1267             if (direction == USB_IN)
1268             {
1269                 /* bulk in endpoint information */
1270                 endpointReturn = (usb_host_ep_t *)&phdcInstance->bulkInEndpointInformation;
1271             }
1272             else
1273             {
1274                 /* bulk out endpoint information */
1275                 endpointReturn = (usb_host_ep_t *)&phdcInstance->bulkOutEndpointInformation;
1276             }
1277         }
1278         else if (pipeType == USB_ENDPOINT_INTERRUPT)
1279         {
1280             /* interrupt in endpoint information */
1281             endpointReturn = (usb_host_ep_t *)&phdcInstance->interruptInEndpointInformation;
1282         }
1283         else
1284         {
1285             /*no action*/
1286         }
1287     }
1288     return endpointReturn;
1289 }
1290 #endif
1291