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_CDC) && (USB_HOST_CONFIG_CDC))
11 #include "usb_host.h"
12 #include "usb_host_cdc.h"
13 #include "usb_host_devices.h"
14 
15 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
16 
USB_HostCdcClearInHaltCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)17 static void USB_HostCdcClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
18 {
19     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
20 
21     cdcInstance->controlTransfer = NULL;
22     if (cdcInstance->inCallbackFn != NULL)
23     {
24         /* callback to application, the callback function is initialized in USB_HostCdcDataRecv */
25         cdcInstance->inCallbackFn(cdcInstance->inCallbackParam, cdcInstance->stallDataBuffer,
26                                   cdcInstance->stallDataLength, kStatus_USB_TransferStall);
27     }
28     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
29 }
30 
USB_HostCdcClearOutHaltCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)31 static void USB_HostCdcClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
32 {
33     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
34 
35     cdcInstance->controlTransfer = NULL;
36     if (cdcInstance->outCallbackFn != NULL)
37     {
38         /* callback to application,the callback function is initialized in USB_HostCdcDataSend */
39         cdcInstance->outCallbackFn(cdcInstance->outCallbackParam, cdcInstance->stallDataBuffer,
40                                    cdcInstance->stallDataLength, kStatus_USB_TransferStall);
41     }
42     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
43 }
USB_HostCdcClearInterruptHaltCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)44 static void USB_HostCdcClearInterruptHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
45 {
46     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
47 
48     cdcInstance->controlTransfer = NULL;
49     if (cdcInstance->interruptCallbackFn != NULL)
50     {
51         /* callback to application */
52         cdcInstance->interruptCallbackFn(cdcInstance->interruptCallbackParam, cdcInstance->stallDataBuffer,
53                                          cdcInstance->stallDataLength, kStatus_USB_TransferStall);
54     }
55     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
56 }
57 
USB_HostCdcClearHalt(usb_host_cdc_instance_struct_t * cdcInstance,usb_host_transfer_t * stallTransfer,host_inner_transfer_callback_t callbackFn,uint8_t endpoint)58 static usb_status_t USB_HostCdcClearHalt(usb_host_cdc_instance_struct_t *cdcInstance,
59                                          usb_host_transfer_t *stallTransfer,
60                                          host_inner_transfer_callback_t callbackFn,
61                                          uint8_t endpoint)
62 {
63     usb_status_t status;
64     usb_host_transfer_t *transfer;
65 
66     /* malloc one transfer */
67     status = USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer);
68     if (status != kStatus_USB_Success)
69     {
70 #ifdef HOST_ECHO
71         usb_echo("allocate transfer error\r\n");
72 #endif
73         return status;
74     }
75     cdcInstance->stallDataBuffer = stallTransfer->transferBuffer;
76     cdcInstance->stallDataLength = stallTransfer->transferSofar;
77     /* save the application callback function */
78     cdcInstance->controlCallbackFn    = NULL;
79     cdcInstance->controlCallbackParam = NULL;
80     /* initialize transfer */
81     transfer->callbackFn                 = callbackFn;
82     transfer->callbackParam              = cdcInstance;
83     transfer->transferBuffer             = NULL;
84     transfer->transferLength             = 0;
85     transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_CLEAR_FEATURE;
86     transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT;
87     transfer->setupPacket->wValue  = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT);
88     transfer->setupPacket->wIndex  = USB_SHORT_TO_LITTLE_ENDIAN(endpoint);
89     transfer->setupPacket->wLength = 0;
90     status                         = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer);
91 
92     if (status != kStatus_USB_Success)
93     {
94         (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
95     }
96     cdcInstance->controlTransfer = transfer;
97 
98     return status;
99 }
100 #endif
101 
102 /*!
103  * @brief cdc data in pipe transfer callback.
104  *
105  * @param param       callback parameter.
106  * @param transfer    callback transfer.
107  * @param status      transfer status.
108  */
USB_HostCdcDataInPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)109 static void USB_HostCdcDataInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
110 {
111     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
112 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
113     if (status == kStatus_USB_TransferStall)
114     {
115         if (USB_HostCdcClearHalt(cdcInstance, transfer, USB_HostCdcClearInHaltCallback,
116                                  (USB_REQUEST_TYPE_DIR_IN |
117                                   ((usb_host_pipe_t *)cdcInstance->inPipe)->endpointAddress)) == kStatus_USB_Success)
118         {
119             (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
120             return;
121         }
122     }
123 #endif
124 
125     if (cdcInstance->inCallbackFn != NULL)
126     {
127         /* callback to application, the callback function is initialized in USB_HostCdcDataRecv */
128         cdcInstance->inCallbackFn(cdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar,
129                                   status);
130     }
131     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
132 }
133 
134 /*!
135  * @brief cdc data out pipe transfer callback.
136  *
137  * @param param       callback parameter.
138  * @param transfer    callback transfer.
139  * @param status      transfer status.
140  */
USB_HostCdcDataOutPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)141 static void USB_HostCdcDataOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
142 {
143     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
144 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
145     if (status == kStatus_USB_TransferStall)
146     {
147         if (USB_HostCdcClearHalt(cdcInstance, transfer, USB_HostCdcClearOutHaltCallback,
148                                  (USB_REQUEST_TYPE_DIR_OUT |
149                                   ((usb_host_pipe_t *)cdcInstance->outPipe)->endpointAddress)) == kStatus_USB_Success)
150         {
151             (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
152             return;
153         }
154     }
155 #endif
156     if (cdcInstance->outCallbackFn != NULL)
157     {
158         /* callback to application,the callback function is initialized in USB_HostCdcDataSend */
159         cdcInstance->outCallbackFn(cdcInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar,
160                                    status);
161     }
162 
163     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
164 }
165 
166 /*!
167  * @brief cdc data out pipe transfer callback.
168  *
169  * @param param       callback parameter.
170  * @param transfer    callback transfer.
171  * @param status      transfer status.
172  */
USB_HostCdcInterruptPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)173 static void USB_HostCdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
174 {
175     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
176 
177 #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL)
178     if (status == kStatus_USB_TransferStall)
179     {
180         if (USB_HostCdcClearHalt(
181                 cdcInstance, transfer, USB_HostCdcClearInterruptHaltCallback,
182                 (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)cdcInstance->interruptPipe)->endpointAddress)) ==
183             kStatus_USB_Success)
184         {
185             (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
186             return;
187         }
188     }
189 #endif
190 
191     if (cdcInstance->interruptCallbackFn != NULL)
192     {
193         cdcInstance->interruptCallbackFn(cdcInstance->interruptCallbackParam, transfer->transferBuffer,
194                                          transfer->transferSofar, status);
195     }
196     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
197 }
198 
199 /*!
200  * @brief cdc data out pipe transfer callback.
201  *
202  * @param param       callback parameter.
203  * @param transfer    callback transfer.
204  * @param status      transfer status.
205  */
USB_HostCdcControlPipeCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)206 static void USB_HostCdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
207 {
208     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
209 
210     if (cdcInstance->controlCallbackFn != NULL)
211     {
212         /* callback to application, callback function is initialized in the USB_HostCdcControl,
213         USB_HostCdcSetControlInterface
214         or USB_HostCdcSetDataInterface, but is the same function */
215         cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, transfer->transferBuffer,
216                                        transfer->transferSofar, status);
217     }
218     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
219 }
220 
221 /*!
222  * @brief cdc open data interface.
223  *
224  * @param cdcInstance     cdc instance pointer.
225  *
226  * @return kStatus_USB_Success or error codes.
227  */
USB_HostCdcOpenDataInterface(usb_host_cdc_instance_struct_t * cdcInstance)228 static usb_status_t USB_HostCdcOpenDataInterface(usb_host_cdc_instance_struct_t *cdcInstance)
229 {
230     usb_status_t status;
231     uint8_t ep_index = 0;
232     usb_host_pipe_init_t pipeInit;
233     usb_descriptor_endpoint_t *ep_desc = NULL;
234     usb_host_interface_t *interfaceHandle;
235 
236     if (cdcInstance->inPipe != NULL)
237     {
238         status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->inPipe);
239 
240         if (status != kStatus_USB_Success)
241         {
242 #ifdef HOST_ECHO
243             usb_echo("error when close pipe\r\n");
244 #endif
245         }
246         cdcInstance->inPipe = NULL;
247     }
248 
249     if (cdcInstance->outPipe != NULL)
250     {
251         status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->outPipe);
252 
253         if (status != kStatus_USB_Success)
254         {
255 #ifdef HOST_ECHO
256             usb_echo("error when close pipe\r\n");
257 #endif
258         }
259         cdcInstance->outPipe = NULL;
260     }
261     status = USB_HostOpenDeviceInterface(cdcInstance->deviceHandle, cdcInstance->dataInterfaceHandle);
262     if (status != kStatus_USB_Success)
263     {
264         return status;
265     }
266     /* open interface pipes */
267     interfaceHandle = (usb_host_interface_t *)cdcInstance->dataInterfaceHandle;
268 
269     for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index)
270     {
271         ep_desc = interfaceHandle->epList[ep_index].epDesc;
272         if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
273              USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
274             ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK))
275         {
276             pipeInit.devInstance     = cdcInstance->deviceHandle;
277             pipeInit.pipeType        = USB_ENDPOINT_BULK;
278             pipeInit.direction       = USB_IN;
279             pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
280             pipeInit.interval        = ep_desc->bInterval;
281             pipeInit.maxPacketSize   = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
282                                                  USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
283             pipeInit.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
284                                                   USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
285             pipeInit.nakCount        = USB_HOST_CONFIG_MAX_NAK;
286 
287             cdcInstance->bulkInPacketSize = pipeInit.maxPacketSize;
288             status                        = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->inPipe, &pipeInit);
289             if (status != kStatus_USB_Success)
290             {
291 #ifdef HOST_ECHO
292                 usb_echo("usb_host_audio_set_interface fail to open pipe\r\n");
293 #endif
294                 return kStatus_USB_Error;
295             }
296         }
297         else if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
298                   USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) &&
299                  ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK))
300         {
301             pipeInit.devInstance     = cdcInstance->deviceHandle;
302             pipeInit.pipeType        = USB_ENDPOINT_BULK;
303             pipeInit.direction       = USB_OUT;
304             pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
305             pipeInit.interval        = ep_desc->bInterval;
306             pipeInit.maxPacketSize   = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
307                                                  USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
308             pipeInit.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
309                                                   USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
310             pipeInit.nakCount        = USB_HOST_CONFIG_MAX_NAK;
311 
312             cdcInstance->bulkOutPacketSize = pipeInit.maxPacketSize;
313             status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->outPipe, &pipeInit);
314             if (status != kStatus_USB_Success)
315             {
316 #ifdef HOST_ECHO
317                 usb_echo("usb_host_cdc_set_dat_interface fail to open pipe\r\n");
318 #endif
319                 return kStatus_USB_Error;
320             }
321         }
322         else
323         {
324         }
325     }
326     return kStatus_USB_Success;
327 }
328 
329 /*!
330  * @brief cdc set data interface callback, open pipes.
331  *
332  * @param param       callback parameter.
333  * @param transfer    callback transfer.
334  * @param status      transfer status.
335  */
USB_HostCdcSetDataInterfaceCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)336 static void USB_HostCdcSetDataInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
337 {
338     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
339 
340     cdcInstance->controlTransfer = NULL;
341     if (status == kStatus_USB_Success)
342     {
343         status = USB_HostCdcOpenDataInterface(cdcInstance);
344     }
345 
346     if (cdcInstance->controlCallbackFn != NULL)
347     {
348         /* callback to application, callback function is initialized in the USB_HostCdcControl,
349         USB_HostCdcSetControlInterface
350         or USB_HostCdcSetDataInterface, but is the same function */
351         cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, NULL, 0, status);
352     }
353     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
354 }
355 
356 /*!
357  * @brief cdc open control interface.
358  *
359  * @param cdcInstance     cdc instance pointer.
360  *
361  * @return kStatus_USB_Success or error codes.
362  */
USB_HostCdcOpenControlInterface(usb_host_cdc_instance_struct_t * cdcInstance)363 static usb_status_t USB_HostCdcOpenControlInterface(usb_host_cdc_instance_struct_t *cdcInstance)
364 {
365     usb_status_t status;
366     uint8_t ep_index = 0;
367     usb_host_pipe_init_t pipeInit;
368     usb_descriptor_endpoint_t *ep_desc = NULL;
369     usb_host_interface_t *interfaceHandle;
370 
371     if (cdcInstance->interruptPipe != NULL)
372     {
373         status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL);
374         if (status != kStatus_USB_Success)
375         {
376 #ifdef HOST_ECHO
377             usb_echo("error when cancel pipe\r\n");
378 #endif
379         }
380         status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->interruptPipe);
381 
382         if (status != kStatus_USB_Success)
383         {
384 #ifdef HOST_ECHO
385             usb_echo("error when close pipe\r\n");
386 #endif
387         }
388         cdcInstance->interruptPipe = NULL;
389     }
390 
391     status = USB_HostOpenDeviceInterface(cdcInstance->deviceHandle, cdcInstance->controlInterfaceHandle);
392     if (status != kStatus_USB_Success)
393     {
394         return status;
395     }
396     /* open interface pipes */
397     interfaceHandle = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle;
398 
399     for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index)
400     {
401         ep_desc = interfaceHandle->epList[ep_index].epDesc;
402         if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
403              USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
404             ((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT))
405         {
406             pipeInit.devInstance     = cdcInstance->deviceHandle;
407             pipeInit.pipeType        = USB_ENDPOINT_INTERRUPT;
408             pipeInit.direction       = USB_IN;
409             pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
410             pipeInit.interval        = ep_desc->bInterval;
411             pipeInit.maxPacketSize   = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
412                                                  USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
413             pipeInit.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
414                                                   USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
415             pipeInit.nakCount        = USB_HOST_CONFIG_MAX_NAK;
416 
417             cdcInstance->packetSize = pipeInit.maxPacketSize;
418 
419             status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->interruptPipe, &pipeInit);
420             if (status != kStatus_USB_Success)
421             {
422 #ifdef HOST_ECHO
423                 usb_echo("USB_HostCdcSetControlInterface fail to open pipe\r\n");
424 #endif
425                 return kStatus_USB_Error;
426             }
427         }
428     }
429     return kStatus_USB_Success;
430 }
431 
432 /*!
433  * @brief cdc set control interface callback, open pipes.
434  *
435  * @param param       callback parameter.
436  * @param transfer    callback transfer.
437  * @param status      transfer status.
438  */
USB_HostCdcSetContorlInterfaceCallback(void * param,usb_host_transfer_t * transfer,usb_status_t status)439 static void USB_HostCdcSetContorlInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
440 {
441     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param;
442 
443     cdcInstance->controlTransfer = NULL;
444     if (status == kStatus_USB_Success)
445     {
446         status = USB_HostCdcOpenControlInterface(cdcInstance);
447     }
448 
449     if (cdcInstance->controlCallbackFn != NULL)
450     {
451         /* callback to application, callback function is initialized in the USB_HostCdcControl,
452         USB_HostCdcSetControlInterface
453         or USB_HostCdcSetDataInterface, but is the same function */
454         cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, NULL, 0, status);
455     }
456     (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
457 }
458 
459 /*!
460  * @brief initialize the cdc instance.
461  *
462  * This function allocate the resource for cdc instance.
463  *
464  * @param deviceHandle       the device handle.
465  * @param classHandle return class handle.
466  *
467  * @retval kStatus_USB_Success        The device is initialized successfully.
468  * @retval kStatus_USB_AllocFail      Allocate memory fail.
469  */
USB_HostCdcInit(usb_device_handle deviceHandle,usb_host_class_handle * classHandle)470 usb_status_t USB_HostCdcInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle)
471 {
472     usb_host_cdc_instance_struct_t *control_ptr =
473         (usb_host_cdc_instance_struct_t *)OSA_MemoryAllocate(sizeof(usb_host_cdc_instance_struct_t));
474     uint32_t info_value = 0U;
475     void *temp;
476 
477     if (control_ptr == NULL)
478     {
479         return kStatus_USB_AllocFail;
480     }
481 
482     control_ptr->deviceHandle           = deviceHandle;
483     control_ptr->controlInterfaceHandle = NULL;
484     control_ptr->dataInterfaceHandle    = NULL;
485     (void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetHostHandle, &info_value);
486     temp                    = (uint32_t *)info_value;
487     control_ptr->hostHandle = (usb_host_handle)temp;
488     (void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceControlPipe, &info_value);
489     temp                     = (uint32_t *)info_value;
490     control_ptr->controlPipe = (usb_host_pipe_handle)temp;
491 
492     *classHandle = control_ptr;
493     return kStatus_USB_Success;
494 }
495 
496 /*!
497  * @brief set control interface.
498  *
499  * This function bind the control interface with the cdc instance.
500  *
501  * @param classHandle      the class handle.
502  * @param interfaceHandle  the control interface handle.
503  * @param alternateSetting the alternate setting value.
504  * @param callbackFn       this callback is called after this function completes.
505  * @param callbackParam    the first parameter in the callback function.
506  *
507  * @retval kStatus_USB_Success        The device is initialized successfully.
508  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
509  * @retval kStatus_USB_Busy           There is no idle transfer.
510  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
511  * @retval kStatus_USB_Busy           callback return status, there is no idle pipe.
512  * @retval kStatus_USB_TransferStall  callback return status, the transfer is stall by device.
513  * @retval kStatus_USB_Error          callback return status, open pipe fail, please reference to USB_HostOpenPipe.
514  */
USB_HostCdcSetControlInterface(usb_host_class_handle classHandle,usb_host_interface_handle interfaceHandle,uint8_t alternateSetting,transfer_callback_t callbackFn,void * callbackParam)515 usb_status_t USB_HostCdcSetControlInterface(usb_host_class_handle classHandle,
516                                             usb_host_interface_handle interfaceHandle,
517                                             uint8_t alternateSetting,
518                                             transfer_callback_t callbackFn,
519                                             void *callbackParam)
520 {
521     usb_status_t status;
522     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
523     usb_host_transfer_t *transfer;
524 
525     status = kStatus_USB_Success;
526     if (classHandle == NULL)
527     {
528         return kStatus_USB_InvalidParameter;
529     }
530 
531     cdcInstance->controlInterfaceHandle = interfaceHandle;
532 
533     /* cancel transfers */
534     if (cdcInstance->interruptPipe != NULL)
535     {
536         status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL);
537 
538         if (status != kStatus_USB_Success)
539         {
540 #ifdef HOST_ECHO
541             usb_echo("error when cancel pipe\r\n");
542 #endif
543         }
544     }
545 
546     if (alternateSetting == 0U)
547     {
548         if (callbackFn != NULL)
549         {
550             status = USB_HostCdcOpenControlInterface(cdcInstance);
551             callbackFn(callbackParam, NULL, 0U, status);
552         }
553     }
554     else
555     {
556         if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
557         {
558 #ifdef HOST_ECHO
559             usb_echo("error to get transfer\r\n");
560 #endif
561             return kStatus_USB_Error;
562         }
563         cdcInstance->controlCallbackFn    = callbackFn;
564         cdcInstance->controlCallbackParam = callbackParam;
565         /* initialize transfer */
566         transfer->callbackFn                 = USB_HostCdcSetContorlInterfaceCallback;
567         transfer->callbackParam              = cdcInstance;
568         transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_SET_INTERFACE;
569         transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
570         transfer->setupPacket->wIndex        = USB_SHORT_TO_LITTLE_ENDIAN(
571             ((usb_host_interface_t *)cdcInstance->controlInterfaceHandle)->interfaceDesc->bInterfaceNumber);
572         transfer->setupPacket->wValue  = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting);
573         transfer->setupPacket->wLength = 0;
574         transfer->transferBuffer       = NULL;
575         transfer->transferLength       = 0;
576         status                         = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer);
577 
578         if (status == kStatus_USB_Success)
579         {
580             cdcInstance->controlTransfer = transfer;
581         }
582         else
583         {
584             (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
585         }
586     }
587 
588     return status;
589 }
590 
591 /*!
592  * @brief set data interface.
593  *
594  * This function bind the control interface with the cdc instance.
595  *
596  * @param classHandle      the class handle.
597  * @param interfaceHandle  the data interface handle.
598  * @param alternateSetting the alternate setting value.
599  * @param callbackFn       this callback is called after this function completes.
600  * @param callbackParam    the first parameter in the callback function.
601  *
602  * @retval kStatus_USB_Success        The device is initialized successfully.
603  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
604  * @retval kStatus_USB_Busy           There is no idle transfer.
605  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
606  * @retval kStatus_USB_Busy           callback return status, there is no idle pipe.
607  * @retval kStatus_USB_TransferStall  callback return status, the transfer is stall by device.
608  * @retval kStatus_USB_Error          callback return status, open pipe fail, please reference to USB_HostOpenPipe.
609  */
USB_HostCdcSetDataInterface(usb_host_class_handle classHandle,usb_host_interface_handle interfaceHandle,uint8_t alternateSetting,transfer_callback_t callbackFn,void * callbackParam)610 usb_status_t USB_HostCdcSetDataInterface(usb_host_class_handle classHandle,
611                                          usb_host_interface_handle interfaceHandle,
612                                          uint8_t alternateSetting,
613                                          transfer_callback_t callbackFn,
614                                          void *callbackParam)
615 {
616     usb_status_t status;
617     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
618     usb_host_transfer_t *transfer;
619 
620     status = kStatus_USB_Success;
621     if (classHandle == NULL)
622     {
623         return kStatus_USB_InvalidParameter;
624     }
625 
626     cdcInstance->dataInterfaceHandle = interfaceHandle;
627 
628     /* cancel transfers */
629     if (cdcInstance->inPipe != NULL)
630     {
631         status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->inPipe, NULL);
632 
633         if (status != kStatus_USB_Success)
634         {
635 #ifdef HOST_ECHO
636             usb_echo("error when cancel pipe\r\n");
637 #endif
638         }
639     }
640 
641     if (cdcInstance->outPipe != NULL)
642     {
643         status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->outPipe, NULL);
644 
645         if (status != kStatus_USB_Success)
646         {
647 #ifdef HOST_ECHO
648             usb_echo("error when cancel pipe\r\n");
649 #endif
650         }
651     }
652 
653 #if defined(USB_HOST_CONFIG_CDC_ECM) && USB_HOST_CONFIG_CDC_ECM
654     usb_host_interface_t *ifPointer  = (usb_host_interface_t *)interfaceHandle;
655     usb_descriptor_union_t *ifBuffer = (usb_descriptor_union_t *)(ifPointer->interfaceExtension);
656     uint32_t extIndex                = 0;
657 
658     for (; extIndex < ifPointer->interfaceExtensionLength;
659          extIndex += ifBuffer->common.bLength,
660          ifBuffer = (usb_descriptor_union_t *)((uint8_t *)ifBuffer + ifBuffer->common.bLength))
661     {
662         if (ifBuffer->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE &&
663             ifBuffer->interface.bAlternateSetting == alternateSetting)
664         {
665             ifPointer->epCount = ifBuffer->interface.bNumEndpoints;
666             break;
667         }
668     }
669 
670     for (uint32_t epIndex = 0; epIndex < ifPointer->epCount && extIndex < ifPointer->interfaceExtensionLength;
671          extIndex += ifBuffer->common.bLength,
672                   ifBuffer = (usb_descriptor_union_t *)((uint8_t *)ifBuffer + ifBuffer->common.bLength))
673     {
674         if (ifBuffer->common.bDescriptorType == USB_DESCRIPTOR_TYPE_ENDPOINT)
675         {
676             ifPointer->epList[epIndex].epDesc = (usb_descriptor_endpoint_t *)ifBuffer;
677             epIndex++;
678         }
679     }
680 #endif
681 
682     if (alternateSetting == 0U)
683     {
684         if (callbackFn != NULL)
685         {
686             status = USB_HostCdcOpenDataInterface(cdcInstance);
687             callbackFn(callbackParam, NULL, 0, status);
688         }
689     }
690     else
691     {
692         if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
693         {
694 #ifdef HOST_ECHO
695             usb_echo("error to get transfer\r\n");
696 #endif
697             return kStatus_USB_Error;
698         }
699         cdcInstance->controlCallbackFn    = callbackFn;
700         cdcInstance->controlCallbackParam = callbackParam;
701         /* initialize transfer */
702         transfer->callbackFn                 = USB_HostCdcSetDataInterfaceCallback;
703         transfer->callbackParam              = cdcInstance;
704         transfer->setupPacket->bRequest      = USB_REQUEST_STANDARD_SET_INTERFACE;
705         transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
706         transfer->setupPacket->wIndex        = USB_SHORT_TO_LITTLE_ENDIAN(
707             ((usb_host_interface_t *)cdcInstance->dataInterfaceHandle)->interfaceDesc->bInterfaceNumber);
708         transfer->setupPacket->wValue  = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting);
709         transfer->setupPacket->wLength = 0;
710         transfer->transferBuffer       = NULL;
711         transfer->transferLength       = 0;
712         status                         = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer);
713 
714         if (status == kStatus_USB_Success)
715         {
716             cdcInstance->controlTransfer = transfer;
717         }
718         else
719         {
720             (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
721         }
722     }
723 
724     return status;
725 }
726 
727 /*!
728  * @brief de-initialize the cdc instance.
729  *
730  * This function release the resource for cdc instance.
731  *
732  * @param deviceHandle   the device handle.
733  * @param classHandle    the class handle.
734  *
735  * @retval kStatus_USB_Success        The device is de-initialized successfully.
736  */
USB_HostCdcDeinit(usb_device_handle deviceHandle,usb_host_class_handle classHandle)737 usb_status_t USB_HostCdcDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle)
738 {
739     usb_status_t status                         = kStatus_USB_Error;
740     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
741 
742     if (deviceHandle == NULL)
743     {
744         return kStatus_USB_InvalidHandle;
745     }
746 
747     if (classHandle != NULL)
748     {
749         if (cdcInstance->interruptPipe != NULL)
750         {
751             status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL);
752             if (status != kStatus_USB_Success)
753             {
754 #ifdef HOST_ECHO
755                 usb_echo("error when Cancel pipe\r\n");
756 #endif
757             }
758             status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->interruptPipe);
759 
760             if (status != kStatus_USB_Success)
761             {
762 #ifdef HOST_ECHO
763                 usb_echo("error when close pipe\r\n");
764 #endif
765             }
766             cdcInstance->interruptPipe = NULL;
767         }
768 
769         (void)USB_HostCloseDeviceInterface(deviceHandle, cdcInstance->controlInterfaceHandle);
770 
771         if (cdcInstance->inPipe != NULL)
772         {
773             status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->inPipe, NULL);
774             if (status != kStatus_USB_Success)
775             {
776 #ifdef HOST_ECHO
777                 usb_echo("error when Cancel pipe\r\n");
778 #endif
779             }
780             status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->inPipe);
781 
782             if (status != kStatus_USB_Success)
783             {
784 #ifdef HOST_ECHO
785                 usb_echo("error when close pipe\r\n");
786 #endif
787             }
788             cdcInstance->inPipe = NULL;
789         }
790         if (cdcInstance->outPipe != NULL)
791         {
792             status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->outPipe, NULL);
793             if (status != kStatus_USB_Success)
794             {
795 #ifdef HOST_ECHO
796                 usb_echo("error when Cancel pipe\r\n");
797 #endif
798             }
799             status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->outPipe);
800 
801             if (status != kStatus_USB_Success)
802             {
803 #ifdef HOST_ECHO
804                 usb_echo("error when close pipe\r\n");
805 #endif
806             }
807             cdcInstance->outPipe = NULL;
808         }
809         if ((cdcInstance->controlPipe != NULL) && (cdcInstance->controlTransfer != NULL))
810         {
811             status =
812                 USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->controlPipe, cdcInstance->controlTransfer);
813         }
814         (void)USB_HostCloseDeviceInterface(deviceHandle, cdcInstance->dataInterfaceHandle);
815 
816         OSA_MemoryFree(cdcInstance);
817     }
818     else
819     {
820         (void)USB_HostCloseDeviceInterface(deviceHandle, NULL);
821         /*add for misra*/
822         status = kStatus_USB_Success;
823     }
824 
825     return status;
826 }
827 
828 /*!
829  * @brief receive data.
830  *
831  * This function implements cdc receiving data.
832  *
833  * @param classHandle    the class handle.
834  * @param buffer         the buffer pointer.
835  * @param bufferLength   the buffer length.
836  * @param callbackFn     this callback is called after this function completes.
837  * @param callbackParam  the first parameter in the callback function.
838  *
839  * @retval kStatus_USB_Success        receive request successfully.
840  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
841  * @retval kStatus_USB_Busy           There is no idle transfer.
842  * @retval kStatus_USB_Error          pipe is not initialized.
843  *                                    Or, send transfer fail, please reference to USB_HostRecv.
844  */
USB_HostCdcDataRecv(usb_host_class_handle classHandle,uint8_t * buffer,uint32_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)845 usb_status_t USB_HostCdcDataRecv(usb_host_class_handle classHandle,
846                                  uint8_t *buffer,
847                                  uint32_t bufferLength,
848                                  transfer_callback_t callbackFn,
849                                  void *callbackParam)
850 {
851     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
852     usb_host_transfer_t *transfer;
853 
854     if (classHandle == NULL)
855     {
856         return kStatus_USB_InvalidHandle;
857     }
858 
859     if (cdcInstance->inPipe == NULL)
860     {
861         return kStatus_USB_Error;
862     }
863 
864     if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
865     {
866 #ifdef HOST_ECHO
867         usb_echo("error to get transfer\r\n");
868 #endif
869         return kStatus_USB_Error;
870     }
871     cdcInstance->inCallbackFn    = callbackFn;
872     cdcInstance->inCallbackParam = callbackParam;
873     transfer->transferBuffer     = buffer;
874     transfer->transferLength     = bufferLength;
875     transfer->callbackFn         = USB_HostCdcDataInPipeCallback;
876     transfer->callbackParam      = cdcInstance;
877 
878     if (USB_HostRecv(cdcInstance->hostHandle, cdcInstance->inPipe, transfer) != kStatus_USB_Success)
879     {
880 #ifdef HOST_ECHO
881         usb_echo("failed to USB_HostRecv\r\n");
882 #endif
883         (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
884         return kStatus_USB_Error;
885     }
886 
887     return kStatus_USB_Success;
888 }
889 
890 /*!
891  * @brief send data.
892  *
893  * This function implements cdc sending data.
894  *
895  * @param classHandle    the class handle.
896  * @param buffer         the buffer pointer.
897  * @param bufferLength   the buffer length.
898  * @param callbackFn     this callback is called after this function completes.
899  * @param callbackParam  the first parameter in the callback function.
900  *
901  * @retval kStatus_USB_Success          receive request successfully.
902  * @retval kStatus_USB_InvalidHandle    The classHandle is NULL pointer.
903  * @retval kStatus_USB_Busy             There is no idle transfer.
904  * @retval kStatus_USB_Error            pipe is not initialized.
905  *                                    Or, send transfer fail, please reference to USB_HostSend.
906  */
USB_HostCdcDataSend(usb_host_class_handle classHandle,uint8_t * buffer,uint32_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)907 usb_status_t USB_HostCdcDataSend(usb_host_class_handle classHandle,
908                                  uint8_t *buffer,
909                                  uint32_t bufferLength,
910                                  transfer_callback_t callbackFn,
911                                  void *callbackParam)
912 {
913     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
914     usb_host_transfer_t *transfer;
915 
916     if (classHandle == NULL)
917     {
918         return kStatus_USB_InvalidHandle;
919     }
920 
921     if (cdcInstance->outPipe == NULL)
922     {
923         return kStatus_USB_Error;
924     }
925 
926     if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
927     {
928 #ifdef HOST_ECHO
929         usb_echo("error to get transfer\r\n");
930 #endif
931         return kStatus_USB_Error;
932     }
933     cdcInstance->outCallbackFn    = callbackFn;
934     cdcInstance->outCallbackParam = callbackParam;
935     transfer->transferBuffer      = buffer;
936     transfer->transferLength      = bufferLength;
937     transfer->callbackFn          = USB_HostCdcDataOutPipeCallback;
938     transfer->callbackParam       = cdcInstance;
939 
940     if (USB_HostSend(cdcInstance->hostHandle, cdcInstance->outPipe, transfer) != kStatus_USB_Success)
941     {
942 #ifdef HOST_ECHO
943         usb_echo("failed to USB_HostSend\r\n");
944 #endif
945         (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
946         return kStatus_USB_Error;
947     }
948     return kStatus_USB_Success;
949 }
950 
951 /*!
952  * @brief interrupt receive data.
953  *
954  * This function implements interrupt receiving data.
955  *
956  * @param classHandle     the class handle.
957  * @param buffer          the buffer pointer.
958  * @param bufferLength    the buffer length.
959  * @param callbackFn      this callback is called after this function completes.
960  * @param callbackParam   the first parameter in the callback function.
961  *
962  * @retval kStatus_USB_Success         receive request successfully.
963  * @retval kStatus_USB_InvalidHandle   The classHandle is NULL pointer.
964  * @retval kStatus_USB_Busy            There is no idle transfer.
965  * @retval kStatus_USB_Error           pipe is not initialized.
966  *                                    Or, send transfer fail, please reference to USB_HostRecv.
967  */
USB_HostCdcInterruptRecv(usb_host_class_handle classHandle,uint8_t * buffer,uint32_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)968 usb_status_t USB_HostCdcInterruptRecv(usb_host_class_handle classHandle,
969                                       uint8_t *buffer,
970                                       uint32_t bufferLength,
971                                       transfer_callback_t callbackFn,
972                                       void *callbackParam)
973 {
974     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
975     usb_host_transfer_t *transfer;
976 
977     if (classHandle == NULL)
978     {
979         return kStatus_USB_InvalidHandle;
980     }
981 
982     if (cdcInstance->interruptPipe == NULL)
983     {
984         return kStatus_USB_Error;
985     }
986 
987     if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
988     {
989 #ifdef HOST_ECHO
990         usb_echo("error to get transfer\r\n");
991 #endif
992         return kStatus_USB_Error;
993     }
994     cdcInstance->interruptCallbackFn    = callbackFn;
995     cdcInstance->interruptCallbackParam = callbackParam;
996     transfer->transferBuffer            = buffer;
997     transfer->transferLength            = bufferLength;
998     transfer->callbackFn                = USB_HostCdcInterruptPipeCallback;
999     transfer->callbackParam             = cdcInstance;
1000 
1001     if (USB_HostRecv(cdcInstance->hostHandle, cdcInstance->interruptPipe, transfer) != kStatus_USB_Success)
1002     {
1003 #ifdef HOST_ECHO
1004         usb_echo("failed to usb_interrupt_recv\r\n");
1005 #endif
1006         (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
1007         return kStatus_USB_Error;
1008     }
1009     return kStatus_USB_Success;
1010 }
1011 /*!
1012  * @brief get pipe max packet size.
1013  *
1014  * @param[in] classHandle the class handle.
1015  * @param[in] pipeType    It's value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or
1016  * USB_ENDPOINT_INTERRUPT.
1017  *                        Please reference to usb_spec.h
1018  * @param[in] direction   pipe direction.
1019  *
1020  * @retval 0        The classHandle is NULL.
1021  * @retval max packet size.
1022  */
USB_HostCdcGetPacketsize(usb_host_class_handle classHandle,uint8_t pipeType,uint8_t direction)1023 uint16_t USB_HostCdcGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction)
1024 {
1025     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
1026     if (classHandle == NULL)
1027     {
1028         return 0;
1029     }
1030 
1031     if (pipeType == USB_ENDPOINT_BULK)
1032     {
1033         if (direction == USB_IN)
1034         {
1035             return cdcInstance->bulkInPacketSize;
1036         }
1037         else
1038         {
1039             return cdcInstance->bulkOutPacketSize;
1040         }
1041     }
1042 
1043     return 0;
1044 }
1045 
1046 /*!
1047  * @brief cdc send control transfer common code.
1048  *
1049  * @param classHandle    the class handle.
1050  * @param request_type   setup packet request type.
1051  * @param request        setup packet request value.
1052  * @param wvalue_l       setup packet wvalue low byte.
1053  * @param wvalue_h       setup packet wvalue high byte.
1054  * @param wlength        setup packet wlength value.
1055  * @param data           data buffer pointer
1056  * @param callbackFn     this callback is called after this function completes.
1057  * @param callbackParam  the first parameter in the callback function.
1058  *
1059  * @return An error code or kStatus_USB_Success.
1060  */
USB_HostCdcControl(usb_host_class_handle classHandle,uint8_t request_type,uint8_t request,uint8_t wvalue_l,uint8_t wvalue_h,uint16_t wlength,uint8_t * data,transfer_callback_t callbackFn,void * callbackParam)1061 usb_status_t USB_HostCdcControl(usb_host_class_handle classHandle,
1062                                 uint8_t request_type,
1063                                 uint8_t request,
1064                                 uint8_t wvalue_l,
1065                                 uint8_t wvalue_h,
1066                                 uint16_t wlength,
1067                                 uint8_t *data,
1068                                 transfer_callback_t callbackFn,
1069                                 void *callbackParam)
1070 {
1071     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
1072     usb_host_transfer_t *transfer;
1073 
1074     if (classHandle == NULL)
1075     {
1076         return kStatus_USB_InvalidHandle;
1077     }
1078 
1079     if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success)
1080     {
1081 #ifdef HOST_ECHO
1082         usb_echo("error to get transfer\r\n");
1083 #endif
1084         return kStatus_USB_Error;
1085     }
1086     cdcInstance->controlCallbackFn    = callbackFn;
1087     cdcInstance->controlCallbackParam = callbackParam;
1088 
1089     transfer->transferBuffer             = data;
1090     transfer->transferLength             = wlength;
1091     transfer->callbackFn                 = USB_HostCdcControlPipeCallback;
1092     transfer->callbackParam              = cdcInstance;
1093     transfer->setupPacket->bmRequestType = request_type;
1094     transfer->setupPacket->bRequest      = request;
1095     transfer->setupPacket->wValue        = USB_SHORT_TO_LITTLE_ENDIAN(wvalue_l | (uint16_t)((uint16_t)wvalue_h << 8));
1096     transfer->setupPacket->wIndex        = USB_SHORT_TO_LITTLE_ENDIAN(
1097         ((usb_host_interface_t *)cdcInstance->controlInterfaceHandle)->interfaceDesc->bInterfaceNumber);
1098     transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength);
1099 
1100     if (USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer) != kStatus_USB_Success)
1101     {
1102 #ifdef HOST_ECHO
1103         usb_echo("failed for USB_HostSendSetup\r\n");
1104 #endif
1105         (void)USB_HostFreeTransfer(cdcInstance->hostHandle, transfer);
1106         return kStatus_USB_Error;
1107     }
1108     cdcInstance->controlTransfer = transfer;
1109 
1110     return kStatus_USB_Success;
1111 }
1112 
1113 /*!
1114  * @brief cdc get line coding.
1115  *
1116  * This function implements cdc GetLineCoding request.refer to pstn spec.
1117  *
1118  * @param classHandle    the class handle.
1119  * @param buffer         the buffer pointer.
1120  * @param bufferLength   the buffer length.
1121  * @param callbackFn     this callback is called after this function completes.
1122  * @param callbackParam  the first parameter in the callback function.
1123  *
1124  * @retval kStatus_USB_Success        request successfully.
1125  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1126  * @retval kStatus_USB_Busy           There is no idle transfer.
1127  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
1128  */
USB_HostCdcGetAcmLineCoding(usb_host_class_handle classHandle,usb_host_cdc_line_coding_struct_t * uartLineCoding,transfer_callback_t callbackFn,void * callbackParam)1129 usb_status_t USB_HostCdcGetAcmLineCoding(usb_host_class_handle classHandle,
1130                                          usb_host_cdc_line_coding_struct_t *uartLineCoding,
1131                                          transfer_callback_t callbackFn,
1132                                          void *callbackParam)
1133 {
1134     return USB_HostCdcControl(
1135         classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
1136         USB_HOST_CDC_GET_LINE_CODING, 0, 0, 7, (uint8_t *)uartLineCoding, callbackFn, callbackParam);
1137 }
1138 
1139 /*!
1140  * @brief cdc set line coding.
1141  *
1142  * This function implements cdc SetLineCoding request.refer to pstn spec.
1143  *
1144  * @param classHandle    the class handle.
1145  * @param buffer         the buffer pointer.
1146  * @param bufferLength   the buffer length.
1147  * @param callbackFn     this callback is called after this function completes.
1148  * @param callbackParam  the first parameter in the callback function.
1149  *
1150  * @retval kStatus_USB_Success        request successfully.
1151  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1152  * @retval kStatus_USB_Busy           There is no idle transfer.
1153  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
1154  */
USB_HostCdcSetAcmLineCoding(usb_host_class_handle classHandle,usb_host_cdc_line_coding_struct_t * uartLineCoding,transfer_callback_t callbackFn,void * callbackParam)1155 usb_status_t USB_HostCdcSetAcmLineCoding(usb_host_class_handle classHandle,
1156                                          usb_host_cdc_line_coding_struct_t *uartLineCoding,
1157                                          transfer_callback_t callbackFn,
1158                                          void *callbackParam)
1159 {
1160     return USB_HostCdcControl(
1161         classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
1162         USB_HOST_CDC_SET_LINE_CODING, 0, 0, 7, (uint8_t *)uartLineCoding, callbackFn, callbackParam);
1163 }
1164 
1165 /*!
1166  * @brief cdc setControlLineState.
1167  *
1168  * This function implements cdc etControlLineState request.refer to pstn spec.
1169  *
1170  * @param classHandle   the class handle.
1171  * @param buffer        the buffer pointer.
1172  * @param bufferLength  the buffer length.
1173  * @param callbackFn    this callback is called after this function completes.
1174  * @param callbackParam the first parameter in the callback function.
1175  *
1176  * @retval kStatus_USB_Success        request successfully.
1177  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1178  * @retval kStatus_USB_Busy           There is no idle transfer.
1179  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
1180  */
USB_HostCdcSetAcmCtrlState(usb_host_class_handle classHandle,uint8_t dtr,uint8_t rts,transfer_callback_t callbackFn,void * callbackParam)1181 usb_status_t USB_HostCdcSetAcmCtrlState(
1182     usb_host_class_handle classHandle, uint8_t dtr, uint8_t rts, transfer_callback_t callbackFn, void *callbackParam)
1183 {
1184     uint16_t lineState = 0U;
1185 
1186     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
1187 
1188     lineState = (0U != dtr) ? USB_HOST_CDC_CONTROL_LINE_STATE_DTR : 0U;
1189     lineState |= (0U != rts) ? USB_HOST_CDC_CONTROL_LINE_STATE_RTS : 0U;
1190     return USB_HostCdcControl(
1191         cdcInstance, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
1192         USB_HOST_CDC_SET_CONTROL_LINE_STATE, (uint8_t)USB_SHORT_GET_LOW(lineState), USB_SHORT_GET_HIGH(lineState), 0U,
1193         NULL, callbackFn, callbackParam);
1194 }
1195 
1196 /*!
1197  * @brief cdc send encapsulated command.
1198  *
1199  * This function implements cdc SEND_ENCAPSULATED_COMMAND request.refer to cdc 1.2 spec.
1200  *
1201  * @param classHandle    the class handle.
1202  * @param buffer         the buffer pointer.
1203  * @param bufferLength   the buffer length.
1204  * @param callbackFn     this callback is called after this function completes.
1205  * @param callbackParam  the first parameter in the callback function.
1206  *
1207  * @retval kStatus_USB_Success        request successfully.
1208  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1209  * @retval kStatus_USB_Busy           There is no idle transfer.
1210  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
1211  */
USB_HostCdcSendEncapsulatedCommand(usb_host_class_handle classHandle,uint8_t * buffer,uint16_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)1212 usb_status_t USB_HostCdcSendEncapsulatedCommand(usb_host_class_handle classHandle,
1213                                                 uint8_t *buffer,
1214                                                 uint16_t bufferLength,
1215                                                 transfer_callback_t callbackFn,
1216                                                 void *callbackParam)
1217 {
1218     return USB_HostCdcControl(
1219         classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
1220         USB_HOST_CDC_SEND_ENCAPSULATED_COMMAND, 0U, 0U, bufferLength, buffer, callbackFn, callbackParam);
1221 }
1222 
1223 /*!
1224  * @brief cdc get encapsulated response.
1225  *
1226  * This function implements cdc GET_ENCAPSULATED_RESPONSE request.refer to cdc 1.2 spec.
1227  *
1228  * @param classHandle    the class handle.
1229  * @param buffer         the buffer pointer.
1230  * @param bufferLength   the buffer length.
1231  * @param callbackFn     this callback is called after this function completes.
1232  * @param callbackParam  the first parameter in the callback function.
1233  *
1234  * @retval kStatus_USB_Success        request successfully.
1235  * @retval kStatus_USB_InvalidHandle  The classHandle is NULL pointer.
1236  * @retval kStatus_USB_Busy           There is no idle transfer.
1237  * @retval kStatus_USB_Error          send transfer fail, please reference to USB_HostSendSetup.
1238  */
USB_HostCdcGetEncapsulatedResponse(usb_host_class_handle classHandle,uint8_t * buffer,uint16_t bufferLength,transfer_callback_t callbackFn,void * callbackParam)1239 usb_status_t USB_HostCdcGetEncapsulatedResponse(usb_host_class_handle classHandle,
1240                                                 uint8_t *buffer,
1241                                                 uint16_t bufferLength,
1242                                                 transfer_callback_t callbackFn,
1243                                                 void *callbackParam)
1244 {
1245     return USB_HostCdcControl(
1246         classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
1247         USB_HOST_CDC_GET_ENCAPSULATED_RESPONSE, 0, 0, bufferLength, buffer, callbackFn, callbackParam);
1248 }
1249 
1250 /*!
1251  * @brief cdc get acm descriptor.
1252  *
1253  * This function is hunting for class specific acm decriptor in the configuration ,get the corresponding
1254  * descriptor .
1255  *
1256  * @param classHandle          the class handle.
1257  * @param headDesc             the head function descriptor pointer.
1258  * @param callManageDesc       the call management functional descriptor pointer.
1259  * @param abstractControlDesc  the abstract control management functional pointer.
1260  * @param unionInterfaceDesc   the union functional descriptor pointer.
1261  *
1262  * @retval kStatus_USB_Error          analyse descriptor error.
1263  */
USB_HostCdcGetAcmDescriptor(usb_host_class_handle classHandle,usb_host_cdc_head_function_desc_struct_t ** headDesc,usb_host_cdc_call_manage_desc_struct_t ** callManageDesc,usb_host_cdc_abstract_control_desc_struct_t ** abstractControlDesc,usb_host_cdc_union_interface_desc_struct_t ** unionInterfaceDesc)1264 usb_status_t USB_HostCdcGetAcmDescriptor(usb_host_class_handle classHandle,
1265                                          usb_host_cdc_head_function_desc_struct_t **headDesc,
1266                                          usb_host_cdc_call_manage_desc_struct_t **callManageDesc,
1267                                          usb_host_cdc_abstract_control_desc_struct_t **abstractControlDesc,
1268                                          usb_host_cdc_union_interface_desc_struct_t **unionInterfaceDesc)
1269 {
1270     usb_status_t status;
1271     usb_descriptor_union_t *ptr1;
1272     uint32_t end_address;
1273     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
1274     usb_cdc_func_desc_struct_t *cdc_common_ptr;
1275     usb_host_interface_t *interface_handle;
1276     void *temp;
1277 
1278     status           = kStatus_USB_Success;
1279     interface_handle = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle;
1280     temp             = (void *)interface_handle->interfaceExtension;
1281     ptr1             = (usb_descriptor_union_t *)temp;
1282     end_address      = (uint32_t)(interface_handle->interfaceExtension + interface_handle->interfaceExtensionLength);
1283 
1284     while ((uint32_t)ptr1 < end_address)
1285     {
1286         temp           = (void *)&ptr1->common;
1287         cdc_common_ptr = (usb_cdc_func_desc_struct_t *)temp;
1288         switch (cdc_common_ptr->common.bDescriptorSubtype)
1289         {
1290             case USB_HOST_DESC_SUBTYPE_HEADER:
1291                 *headDesc = &cdc_common_ptr->head;
1292                 if ((((uint32_t)((*headDesc)->bcdCDC[1U]) << 8U) + (*headDesc)->bcdCDC[0U]) > 0x0110U)
1293                 {
1294                     status = kStatus_USB_Error;
1295                 }
1296                 break;
1297             case USB_HOST_DESC_SUBTYPE_UNION:
1298                 if (cdc_common_ptr->unionDesc.bControlInterface == interface_handle->interfaceDesc->bInterfaceNumber)
1299                 {
1300                     *unionInterfaceDesc = &cdc_common_ptr->unionDesc;
1301                 }
1302                 else
1303                 {
1304                     status = kStatus_USB_Error;
1305                 }
1306                 break;
1307             case USB_HOST_DESC_SUBTYPE_CM:
1308                 *callManageDesc = &cdc_common_ptr->callManage;
1309                 break;
1310             case USB_HOST_DESC_SUBTYPE_ACM:
1311                 *abstractControlDesc = &cdc_common_ptr->acm;
1312                 break;
1313             default:
1314                 /*no action*/
1315                 break;
1316         }
1317 
1318         if (kStatus_USB_Success != status)
1319         {
1320             break;
1321         }
1322         temp = (void *)((uint8_t *)ptr1 + ptr1->common.bLength);
1323         ptr1 = (usb_descriptor_union_t *)temp;
1324     }
1325     cdcInstance->headDesc            = *headDesc;
1326     cdcInstance->callManageDesc      = *callManageDesc;
1327     cdcInstance->abstractControlDesc = *abstractControlDesc;
1328     cdcInstance->unionInterfaceDesc  = *unionInterfaceDesc;
1329     return status;
1330 }
1331 
USB_HostCdcGetEcmDescriptor(usb_host_class_handle classHandle,usb_host_cdc_head_function_desc_struct_t ** headDesc,usb_host_cdc_union_interface_desc_struct_t ** unionInterfaceDesc,usb_host_cdc_ethernet_networking_desc_struct_t ** ethernetNetworkingDesc)1332 usb_status_t USB_HostCdcGetEcmDescriptor(usb_host_class_handle classHandle,
1333                                          usb_host_cdc_head_function_desc_struct_t **headDesc,
1334                                          usb_host_cdc_union_interface_desc_struct_t **unionInterfaceDesc,
1335                                          usb_host_cdc_ethernet_networking_desc_struct_t **ethernetNetworkingDesc)
1336 {
1337     usb_status_t status = kStatus_USB_Success;
1338 
1339     usb_host_cdc_head_function_desc_struct_t *ifHeadDesc                     = NULL;
1340     usb_host_cdc_union_interface_desc_struct_t *ifUnionInterfaceDesc         = NULL;
1341     usb_host_cdc_ethernet_networking_desc_struct_t *ifEthernetNetworkingDesc = NULL;
1342 
1343     usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle;
1344     usb_host_interface_t *ifPointer             = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle;
1345     usb_descriptor_union_t *ifBuffer            = (usb_descriptor_union_t *)(ifPointer->interfaceExtension);
1346     usb_cdc_func_desc_struct_t *funcBuffer;
1347 
1348     for (uint32_t ifIndex  = 0; ifIndex < ifPointer->interfaceExtensionLength; ifIndex += ifBuffer->common.bLength,
1349                   ifBuffer = (usb_descriptor_union_t *)((uint8_t *)ifBuffer + ifBuffer->common.bLength))
1350     {
1351         if (ifBuffer->common.bDescriptorType == 0x24U)
1352         {
1353             funcBuffer = (usb_cdc_func_desc_struct_t *)ifBuffer;
1354             switch (funcBuffer->common.bDescriptorSubtype)
1355             {
1356                 case USB_HOST_DESC_SUBTYPE_HEADER:
1357                     ifHeadDesc = &funcBuffer->head;
1358                     if ((((uint32_t)(ifHeadDesc->bcdCDC[1U]) << 8U) + ifHeadDesc->bcdCDC[0U]) > 0x0110U)
1359                     {
1360                         status = kStatus_USB_Error;
1361                     }
1362                     break;
1363 
1364                 case USB_HOST_DESC_SUBTYPE_UNION:
1365                     if (funcBuffer->unionDesc.bControlInterface == ifPointer->interfaceDesc->bInterfaceNumber)
1366                     {
1367                         ifUnionInterfaceDesc = &funcBuffer->unionDesc;
1368                     }
1369                     else
1370                     {
1371                         status = kStatus_USB_Error;
1372                     }
1373                     break;
1374 
1375                 case USB_HOST_DESC_SUBTYPE_ECM:
1376                     ifEthernetNetworkingDesc            = &funcBuffer->ecm;
1377                     cdcInstance->headDesc               = ifHeadDesc;
1378                     cdcInstance->unionInterfaceDesc     = ifUnionInterfaceDesc;
1379                     cdcInstance->ethernetNetworkingDesc = ifEthernetNetworkingDesc;
1380                     if (headDesc)
1381                     {
1382                         *headDesc = cdcInstance->headDesc;
1383                     }
1384                     if (unionInterfaceDesc)
1385                     {
1386                         *unionInterfaceDesc = cdcInstance->unionInterfaceDesc;
1387                     }
1388                     if (ethernetNetworkingDesc)
1389                     {
1390                         *ethernetNetworkingDesc = cdcInstance->ethernetNetworkingDesc;
1391                     }
1392                     break;
1393 
1394                 default:
1395                     break;
1396             }
1397             if (status != kStatus_USB_Success)
1398             {
1399                 break;
1400             }
1401         }
1402     }
1403     return status;
1404 }
1405 #endif
1406