1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016, 2019 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 
12 #include "usb_device_config.h"
13 #include "usb.h"
14 #include "usb_device.h"
15 
16 #include "usb_device_class.h"
17 
18 #if USB_DEVICE_CONFIG_CDC_ACM
19 #include "usb_device_cdc_acm.h"
20 
21 /*******************************************************************************
22  * Definitions
23  ******************************************************************************/
24 #define USB_CDC_ACM_ENTER_CRITICAL() \
25     OSA_SR_ALLOC();                  \
26     OSA_ENTER_CRITICAL()
27 
28 #define USB_CDC_ACM_EXIT_CRITICAL() OSA_EXIT_CRITICAL()
29 
30 /*******************************************************************************
31  * Variables
32  ******************************************************************************/
33 /* CDC ACM device instance */
34 
USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE)35 USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_cdc_acm_struct_t
36     g_cdcAcmHandle[USB_DEVICE_CONFIG_CDC_ACM];
37 
38 /*******************************************************************************
39  * Code
40  ******************************************************************************/
41 
42 /*!
43  * @brief Allocates the CDC ACM device handle.
44  *
45  * This function allocates the CDC ACM device handle.
46  *
47  * @param handle The class handle of the CDC ACM class.
48  * @return A USB error code or kStatus_USB_Success.
49  */
50 static usb_status_t USB_DeviceCdcAcmAllocateHandle(usb_device_cdc_acm_struct_t **handle)
51 {
52     uint32_t count;
53     for (count = 0U; count < (uint32_t)USB_DEVICE_CONFIG_CDC_ACM; count++)
54     {
55         if (NULL == g_cdcAcmHandle[count].handle)
56         {
57             *handle = &g_cdcAcmHandle[count];
58             return kStatus_USB_Success;
59         }
60     }
61 
62     return kStatus_USB_Busy;
63 }
64 
65 /*!
66  * @brief Frees the CDC ACM device handle.
67  *
68  * This function frees the CDC ACM device handle.
69  *
70  * @param handle The class handle of the CDC ACM class.
71  * @return A USB error code or kStatus_USB_Success.
72  */
USB_DeviceCdcAcmFreeHandle(usb_device_cdc_acm_struct_t * handle)73 static usb_status_t USB_DeviceCdcAcmFreeHandle(usb_device_cdc_acm_struct_t *handle)
74 {
75     handle->handle        = NULL;
76     handle->configStruct  = NULL;
77     handle->configuration = 0U;
78     handle->alternate     = 0U;
79     return kStatus_USB_Success;
80 }
81 
82 /*!
83  * @brief Responds to the interrupt in endpoint event.
84  *
85  * This function responds to the interrupt in endpoint event.
86  *
87  * @param handle The device handle of the CDC ACM device.
88  * @param message The pointer to the message of the endpoint callback.
89  * @param callbackParam The pointer to the parameter of the callback.
90  * @return A USB error code or kStatus_USB_Success.
91  */
USB_DeviceCdcAcmInterruptIn(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)92 static usb_status_t USB_DeviceCdcAcmInterruptIn(usb_device_handle handle,
93                                                 usb_device_endpoint_callback_message_struct_t *message,
94                                                 void *callbackParam)
95 {
96     usb_device_cdc_acm_struct_t *cdcAcmHandle;
97     usb_status_t error = kStatus_USB_Error;
98     cdcAcmHandle       = (usb_device_cdc_acm_struct_t *)callbackParam;
99     if (NULL == cdcAcmHandle)
100     {
101         return kStatus_USB_InvalidHandle;
102     }
103 
104     cdcAcmHandle->interruptIn.isBusy = 0U;
105 
106     if ((NULL != cdcAcmHandle->configStruct) && (NULL != cdcAcmHandle->configStruct->classCallback))
107     {
108         /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
109         it is from the second parameter of classInit */
110         error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
111                                                           kUSB_DeviceCdcEventSerialStateNotif, message);
112     }
113     return error;
114 }
115 
116 /*!
117  * @brief Responds to the bulk in endpoint event.
118  *
119  * This function responds to the bulk in endpoint event.
120  *
121  * @param handle The device handle of the CDC ACM device.
122  * @param message The pointer to the message of the endpoint callback.
123  * @param callbackParam The pointer to the parameter of the callback.
124  * @return A USB error code or kStatus_USB_Success.
125  */
USB_DeviceCdcAcmBulkIn(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)126 static usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle,
127                                            usb_device_endpoint_callback_message_struct_t *message,
128                                            void *callbackParam)
129 {
130     usb_device_cdc_acm_struct_t *cdcAcmHandle;
131     usb_status_t status = kStatus_USB_Error;
132     cdcAcmHandle        = (usb_device_cdc_acm_struct_t *)callbackParam;
133 
134     if (NULL == cdcAcmHandle)
135     {
136         return kStatus_USB_InvalidHandle;
137     }
138 
139     cdcAcmHandle->bulkIn.isBusy = 0U;
140 
141     if ((NULL != cdcAcmHandle->configStruct) && (NULL != cdcAcmHandle->configStruct->classCallback))
142     {
143         /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
144         it is from the second parameter of classInit */
145         status = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
146                                                            kUSB_DeviceCdcEventSendResponse, message);
147     }
148     return status;
149 }
150 
151 /*!
152  * @brief Responds to the bulk out endpoint event.
153  *
154  * This function responds to the bulk out endpoint event.
155  *
156  * @param handle The device handle of the CDC ACM device.
157  * @param message The pointer to the message of the endpoint callback.
158  * @param callbackParam The pointer to the parameter of the callback.
159  * @return A USB error code or kStatus_USB_Success.
160  */
USB_DeviceCdcAcmBulkOut(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)161 static usb_status_t USB_DeviceCdcAcmBulkOut(usb_device_handle handle,
162                                             usb_device_endpoint_callback_message_struct_t *message,
163                                             void *callbackParam)
164 {
165     usb_device_cdc_acm_struct_t *cdcAcmHandle;
166     usb_status_t status = kStatus_USB_Error;
167     cdcAcmHandle        = (usb_device_cdc_acm_struct_t *)callbackParam;
168 
169     if (NULL == cdcAcmHandle)
170     {
171         return kStatus_USB_InvalidHandle;
172     }
173 
174     cdcAcmHandle->bulkOut.isBusy = 0U;
175 
176     if ((NULL != cdcAcmHandle->configStruct) && (NULL != cdcAcmHandle->configStruct->classCallback))
177     {
178         /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
179         it is from the second parameter of classInit */
180         status = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
181                                                            kUSB_DeviceCdcEventRecvResponse, message);
182     }
183     return status;
184 }
185 
186 /*!
187  * @brief Initializes the endpoints in CDC ACM class.
188  *
189  * This function initializes the endpoints in CDC ACM class.
190  *
191  * @param cdcAcmHandle The class handle of the CDC ACM class.
192  * @return A USB error code or kStatus_USB_Success.
193  */
USB_DeviceCdcAcmEndpointsInit(usb_device_cdc_acm_struct_t * cdcAcmHandle)194 static usb_status_t USB_DeviceCdcAcmEndpointsInit(usb_device_cdc_acm_struct_t *cdcAcmHandle)
195 {
196     usb_device_interface_list_t *interfaceList;
197     usb_device_interface_struct_t *interface = NULL;
198     usb_device_endpoint_callback_struct_t epCallback;
199     usb_status_t error = kStatus_USB_Error;
200     uint32_t count;
201     uint32_t index;
202 
203     if (NULL == cdcAcmHandle)
204     {
205         return error;
206     }
207     epCallback.callbackFn = (usb_device_endpoint_callback_t)NULL;
208     /* return error when configuration is invalid (0 or more than the configuration number) */
209     if ((cdcAcmHandle->configuration == 0U) ||
210         (cdcAcmHandle->configuration > cdcAcmHandle->configStruct->classInfomation->configurations))
211     {
212         return error;
213     }
214 
215     interfaceList = &cdcAcmHandle->configStruct->classInfomation->interfaceList[cdcAcmHandle->configuration - 1U];
216 
217     for (count = 0U; count < interfaceList->count; count++)
218     {
219         if (USB_DEVICE_CONFIG_CDC_COMM_CLASS_CODE == interfaceList->interfaces[count].classCode)
220         {
221             for (index = 0U; index < interfaceList->interfaces[count].count; index++)
222             {
223                 if (interfaceList->interfaces[count].interface[index].alternateSetting == cdcAcmHandle->alternate)
224                 {
225                     interface = &interfaceList->interfaces[count].interface[index];
226                     break;
227                 }
228             }
229             cdcAcmHandle->interfaceNumber = interfaceList->interfaces[count].interfaceNumber;
230             break;
231         }
232     }
233     if (NULL == interface)
234     {
235         return error;
236     }
237     cdcAcmHandle->commInterfaceHandle = interface;
238     for (count = 0U; count < interface->endpointList.count; count++)
239     {
240         usb_device_endpoint_init_struct_t epInitStruct;
241         epInitStruct.zlt             = 0U;
242         epInitStruct.interval        = interface->endpointList.endpoint[count].interval;
243         epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
244         epInitStruct.maxPacketSize   = interface->endpointList.endpoint[count].maxPacketSize;
245         epInitStruct.transferType    = interface->endpointList.endpoint[count].transferType;
246 
247         if ((USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
248                         USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &&
249             (USB_ENDPOINT_INTERRUPT == epInitStruct.transferType))
250         {
251             cdcAcmHandle->interruptIn.ep = (epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
252             cdcAcmHandle->interruptIn.isBusy         = 0U;
253             cdcAcmHandle->interruptIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
254             cdcAcmHandle->interruptIn.pipeStall      = 0U;
255             cdcAcmHandle->interruptIn.pipeDataLen    = 0U;
256             epCallback.callbackFn                    = USB_DeviceCdcAcmInterruptIn;
257         }
258 
259         epCallback.callbackParam = cdcAcmHandle;
260 
261         error = USB_DeviceInitEndpoint(cdcAcmHandle->handle, &epInitStruct, &epCallback);
262         if (kStatus_USB_Success != error)
263         {
264             return error;
265         }
266     }
267 
268     for (count = 0U; count < interfaceList->count; count++)
269     {
270         if (USB_DEVICE_CONFIG_CDC_DATA_CLASS_CODE == interfaceList->interfaces[count].classCode)
271         {
272             for (index = 0U; index < interfaceList->interfaces[count].count; index++)
273             {
274                 if (interfaceList->interfaces[count].interface[index].alternateSetting == cdcAcmHandle->alternate)
275                 {
276                     interface = &interfaceList->interfaces[count].interface[index];
277                     break;
278                 }
279             }
280             break;
281         }
282     }
283 
284     cdcAcmHandle->dataInterfaceHandle = interface;
285 
286     for (count = 0U; count < interface->endpointList.count; count++)
287     {
288         usb_device_endpoint_init_struct_t epInitStruct;
289         epInitStruct.zlt             = 0U;
290         epInitStruct.interval        = interface->endpointList.endpoint[count].interval;
291         epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
292         epInitStruct.maxPacketSize   = interface->endpointList.endpoint[count].maxPacketSize;
293         epInitStruct.transferType    = interface->endpointList.endpoint[count].transferType;
294 
295         if ((USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
296                         USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &&
297             (USB_ENDPOINT_BULK == epInitStruct.transferType))
298         {
299             cdcAcmHandle->bulkIn.ep     = (epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
300             cdcAcmHandle->bulkIn.isBusy = 0U;
301             cdcAcmHandle->bulkIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
302             cdcAcmHandle->bulkIn.pipeStall      = 0U;
303             cdcAcmHandle->bulkIn.pipeDataLen    = 0U;
304             epCallback.callbackFn               = USB_DeviceCdcAcmBulkIn;
305         }
306         else if ((USB_OUT == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
307                               USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &&
308                  (USB_ENDPOINT_BULK == epInitStruct.transferType))
309         {
310             cdcAcmHandle->bulkOut.ep     = (epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
311             cdcAcmHandle->bulkOut.isBusy = 0U;
312             cdcAcmHandle->bulkOut.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
313             cdcAcmHandle->bulkOut.pipeStall      = 0U;
314             cdcAcmHandle->bulkOut.pipeDataLen    = 0U;
315             epCallback.callbackFn                = USB_DeviceCdcAcmBulkOut;
316         }
317         else
318         {
319             /*no action*/
320         }
321         epCallback.callbackParam = cdcAcmHandle;
322 
323         error = USB_DeviceInitEndpoint(cdcAcmHandle->handle, &epInitStruct, &epCallback);
324     }
325     return error;
326 }
327 
328 /*!
329  * @brief De-initializes the endpoints in CDC ACM class.
330  *
331  * This function de-initializes the endpoints in CDC ACM class.
332  *
333  * @param cdcAcmHandle The class handle of the CDC ACM class.
334  * @return A USB error code or kStatus_USB_Success.
335  */
USB_DeviceCdcAcmEndpointsDeinit(usb_device_cdc_acm_struct_t * cdcAcmHandle)336 static usb_status_t USB_DeviceCdcAcmEndpointsDeinit(usb_device_cdc_acm_struct_t *cdcAcmHandle)
337 {
338     usb_status_t status = kStatus_USB_Error;
339     uint32_t count;
340 
341     if ((NULL == cdcAcmHandle->commInterfaceHandle) || (NULL == cdcAcmHandle->dataInterfaceHandle))
342     {
343         return status;
344     }
345     for (count = 0U; count < cdcAcmHandle->commInterfaceHandle->endpointList.count; count++)
346     {
347         status = USB_DeviceDeinitEndpoint(
348             cdcAcmHandle->handle, cdcAcmHandle->commInterfaceHandle->endpointList.endpoint[count].endpointAddress);
349     }
350     for (count = 0U; count < cdcAcmHandle->dataInterfaceHandle->endpointList.count; count++)
351     {
352         status = USB_DeviceDeinitEndpoint(
353             cdcAcmHandle->handle, cdcAcmHandle->dataInterfaceHandle->endpointList.endpoint[count].endpointAddress);
354     }
355     cdcAcmHandle->commInterfaceHandle = NULL;
356     cdcAcmHandle->dataInterfaceHandle = NULL;
357 
358     return status;
359 }
360 
361 /*!
362  * @brief Handles the CDC ACM class event.
363  *
364  * This function responses to various events including the common device events and the class specific events.
365  * For class specific events, it calls the class callback defined in the application to deal with the class specific
366  * event.
367  *
368  * @param handle The class handle of the CDC ACM class.
369  * @param event The event type.
370  * @param param The class handle of the CDC ACM class.
371  * @return A USB error code or kStatus_USB_Success.
372  */
USB_DeviceCdcAcmEvent(void * handle,uint32_t event,void * param)373 usb_status_t USB_DeviceCdcAcmEvent(void *handle, uint32_t event, void *param)
374 {
375     usb_device_cdc_acm_struct_t *cdcAcmHandle;
376     usb_device_cdc_acm_request_param_struct_t reqParam;
377     usb_status_t error = kStatus_USB_Error;
378     uint32_t count;
379     uint16_t interfaceAlternate;
380     uint8_t *temp8;
381     uint8_t alternate;
382     usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
383     if ((NULL == param) || (NULL == handle))
384     {
385         return kStatus_USB_InvalidHandle;
386     }
387 
388     cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
389 
390     switch (eventCode)
391     {
392         case kUSB_DeviceClassEventDeviceReset:
393             /* Bus reset, clear the configuration. */
394             cdcAcmHandle->configuration = 0;
395             error                       = kStatus_USB_Success;
396             break;
397         case kUSB_DeviceClassEventSetConfiguration:
398             temp8 = ((uint8_t *)param);
399             if (NULL == cdcAcmHandle->configStruct)
400             {
401                 break;
402             }
403             if (*temp8 == cdcAcmHandle->configuration)
404             {
405                 error = kStatus_USB_Success;
406                 break;
407             }
408 
409             error                       = USB_DeviceCdcAcmEndpointsDeinit(cdcAcmHandle);
410             cdcAcmHandle->configuration = *temp8;
411             cdcAcmHandle->alternate     = 0U;
412             error                       = USB_DeviceCdcAcmEndpointsInit(cdcAcmHandle);
413             if (kStatus_USB_Success != error)
414             {
415 #if 0
416                 (void)usb_echo("kUSB_DeviceClassEventSetConfiguration, USB_DeviceInitEndpoint fail\r\n");
417 #endif
418             }
419             break;
420         case kUSB_DeviceClassEventSetInterface:
421             if (NULL == cdcAcmHandle->configStruct)
422             {
423                 break;
424             }
425 
426             interfaceAlternate = *((uint16_t *)param);
427             alternate          = (uint8_t)(interfaceAlternate & 0xFFU);
428 
429             if (cdcAcmHandle->interfaceNumber != ((uint8_t)(interfaceAlternate >> 8U)))
430             {
431                 break;
432             }
433             if (alternate == cdcAcmHandle->alternate)
434             {
435                 error = kStatus_USB_Success;
436                 break;
437             }
438             error                   = USB_DeviceCdcAcmEndpointsDeinit(cdcAcmHandle);
439             cdcAcmHandle->alternate = alternate;
440             error                   = USB_DeviceCdcAcmEndpointsInit(cdcAcmHandle);
441             if (kStatus_USB_Success != error)
442             {
443 #if 0
444                 (void)usb_echo("kUSB_DeviceClassEventSetInterface, USB_DeviceInitEndpoint fail\r\n");
445 #endif
446             }
447             break;
448         case kUSB_DeviceClassEventSetEndpointHalt:
449             if ((NULL == cdcAcmHandle->configStruct) || (NULL == cdcAcmHandle->commInterfaceHandle) ||
450                 (NULL == cdcAcmHandle->dataInterfaceHandle))
451             {
452                 break;
453             }
454             temp8 = ((uint8_t *)param);
455             for (count = 0U; count < cdcAcmHandle->commInterfaceHandle->endpointList.count; count++)
456             {
457                 if (*temp8 == cdcAcmHandle->commInterfaceHandle->endpointList.endpoint[count].endpointAddress)
458                 {
459                     cdcAcmHandle->interruptIn.pipeStall = 1U;
460                     error                               = USB_DeviceStallEndpoint(cdcAcmHandle->handle, *temp8);
461                 }
462             }
463             for (count = 0U; count < cdcAcmHandle->dataInterfaceHandle->endpointList.count; count++)
464             {
465                 if (*temp8 == cdcAcmHandle->dataInterfaceHandle->endpointList.endpoint[count].endpointAddress)
466                 {
467                     if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
468                                    USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
469                     {
470                         cdcAcmHandle->bulkIn.pipeStall = 1U;
471                     }
472                     else
473                     {
474                         cdcAcmHandle->bulkOut.pipeStall = 1U;
475                     }
476                     error = USB_DeviceStallEndpoint(cdcAcmHandle->handle, *temp8);
477                 }
478             }
479             break;
480         case kUSB_DeviceClassEventClearEndpointHalt:
481             if ((NULL == cdcAcmHandle->configStruct) || (NULL == cdcAcmHandle->commInterfaceHandle) ||
482                 (NULL == cdcAcmHandle->dataInterfaceHandle))
483             {
484                 break;
485             }
486             temp8 = ((uint8_t *)param);
487             for (count = 0U; count < cdcAcmHandle->commInterfaceHandle->endpointList.count; count++)
488             {
489                 if (*temp8 == cdcAcmHandle->commInterfaceHandle->endpointList.endpoint[count].endpointAddress)
490                 {
491                     error = USB_DeviceUnstallEndpoint(cdcAcmHandle->handle, *temp8);
492                     if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
493                                    USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
494                     {
495                         if (0U != cdcAcmHandle->interruptIn.pipeStall)
496                         {
497                             cdcAcmHandle->interruptIn.pipeStall = 0U;
498                             if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != cdcAcmHandle->interruptIn.pipeDataBuffer)
499                             {
500                                 error = USB_DeviceSendRequest(cdcAcmHandle->handle, (cdcAcmHandle->interruptIn.ep),
501                                                               cdcAcmHandle->interruptIn.pipeDataBuffer,
502                                                               cdcAcmHandle->interruptIn.pipeDataLen);
503                                 if (kStatus_USB_Success != error)
504                                 {
505                                     usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
506                                     endpointCallbackMessage.buffer  = cdcAcmHandle->interruptIn.pipeDataBuffer;
507                                     endpointCallbackMessage.length  = cdcAcmHandle->interruptIn.pipeDataLen;
508                                     endpointCallbackMessage.isSetup = 0U;
509 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
510                                     if (kStatus_USB_Success != USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle,
511                                                                                       (void *)&endpointCallbackMessage,
512                                                                                       handle))
513                                     {
514                                         return kStatus_USB_Error;
515                                     }
516 #else
517                                     (void)USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle, (void *)&endpointCallbackMessage,
518                                                                  handle);
519 #endif
520                                 }
521                                 cdcAcmHandle->interruptIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
522                                 cdcAcmHandle->interruptIn.pipeDataLen    = 0U;
523                             }
524                         }
525                     }
526                 }
527             }
528             for (count = 0U; count < cdcAcmHandle->dataInterfaceHandle->endpointList.count; count++)
529             {
530                 if (*temp8 == cdcAcmHandle->dataInterfaceHandle->endpointList.endpoint[count].endpointAddress)
531                 {
532                     error = USB_DeviceUnstallEndpoint(cdcAcmHandle->handle, *temp8);
533                     if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
534                                    USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
535                     {
536                         if (0U != cdcAcmHandle->bulkIn.pipeStall)
537                         {
538                             cdcAcmHandle->bulkIn.pipeStall = 0U;
539                             if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != cdcAcmHandle->bulkIn.pipeDataBuffer)
540                             {
541                                 error = USB_DeviceSendRequest(cdcAcmHandle->handle, (cdcAcmHandle->bulkIn.ep),
542                                                               cdcAcmHandle->bulkIn.pipeDataBuffer,
543                                                               cdcAcmHandle->bulkIn.pipeDataLen);
544                                 if (kStatus_USB_Success != error)
545                                 {
546                                     usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
547                                     endpointCallbackMessage.buffer  = cdcAcmHandle->bulkIn.pipeDataBuffer;
548                                     endpointCallbackMessage.length  = cdcAcmHandle->bulkIn.pipeDataLen;
549                                     endpointCallbackMessage.isSetup = 0U;
550 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
551                                     if (kStatus_USB_Success != USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle,
552                                                                                       (void *)&endpointCallbackMessage,
553                                                                                       handle))
554                                     {
555                                         return kStatus_USB_Error;
556                                     }
557 #else
558                                     (void)USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle, (void *)&endpointCallbackMessage,
559                                                                  handle);
560 #endif
561                                 }
562                                 cdcAcmHandle->bulkIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
563                                 cdcAcmHandle->bulkIn.pipeDataLen    = 0U;
564                             }
565                         }
566                     }
567                     else
568                     {
569                         if (0U != cdcAcmHandle->bulkOut.pipeStall)
570                         {
571                             cdcAcmHandle->bulkOut.pipeStall = 0U;
572                             if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != cdcAcmHandle->bulkOut.pipeDataBuffer)
573                             {
574                                 error = USB_DeviceRecvRequest(cdcAcmHandle->handle, (cdcAcmHandle->bulkOut.ep),
575                                                               cdcAcmHandle->bulkOut.pipeDataBuffer,
576                                                               cdcAcmHandle->bulkOut.pipeDataLen);
577                                 if (kStatus_USB_Success != error)
578                                 {
579                                     usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
580                                     endpointCallbackMessage.buffer  = cdcAcmHandle->bulkOut.pipeDataBuffer;
581                                     endpointCallbackMessage.length  = cdcAcmHandle->bulkOut.pipeDataLen;
582                                     endpointCallbackMessage.isSetup = 0U;
583 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
584                                     if (kStatus_USB_Success != USB_DeviceCdcAcmBulkOut(cdcAcmHandle->handle,
585                                                                                        (void *)&endpointCallbackMessage,
586                                                                                        handle))
587                                     {
588                                         return kStatus_USB_Error;
589                                     }
590 #else
591                                     (void)USB_DeviceCdcAcmBulkOut(cdcAcmHandle->handle,
592                                                                   (void *)&endpointCallbackMessage, handle);
593 #endif
594                                 }
595                                 cdcAcmHandle->bulkOut.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
596                                 cdcAcmHandle->bulkOut.pipeDataLen    = 0U;
597                             }
598                         }
599                     }
600                 }
601             }
602             break;
603         case kUSB_DeviceClassEventClassRequest:
604 
605         {
606             usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
607 
608             if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
609                 USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
610             {
611                 break;
612             }
613 
614             if ((controlRequest->setup->wIndex & 0xFFU) != cdcAcmHandle->interfaceNumber)
615             {
616                 break;
617             }
618 
619             error = kStatus_USB_InvalidRequest;
620             /* Standard CDC request */
621             reqParam.buffer         = &(controlRequest->buffer);
622             reqParam.length         = &(controlRequest->length);
623             reqParam.interfaceIndex = controlRequest->setup->wIndex;
624             reqParam.setupValue     = controlRequest->setup->wValue;
625             reqParam.isSetup        = controlRequest->isSetup;
626             switch (controlRequest->setup->bRequest)
627             {
628                 case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
629                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
630                          USB_REQUEST_TYPE_DIR_OUT) &&
631                         (controlRequest->setup->wLength != 0U))
632                     {
633                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
634                         it is from the second parameter of classInit */
635                         error = cdcAcmHandle->configStruct->classCallback(
636                             (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventSendEncapsulatedCommand, &reqParam);
637                     }
638                     break;
639                 case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
640                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
641                          USB_REQUEST_TYPE_DIR_IN) &&
642                         (controlRequest->setup->wLength != 0U))
643                     {
644                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
645                         it is from the second parameter of classInit */
646                         error = cdcAcmHandle->configStruct->classCallback(
647                             (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventGetEncapsulatedResponse, &reqParam);
648                     }
649                     break;
650                 case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE:
651                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
652                          USB_REQUEST_TYPE_DIR_OUT) &&
653                         (controlRequest->setup->wLength != 0U))
654                     {
655                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
656                         it is from the second parameter of classInit */
657                         error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
658                                                                           kUSB_DeviceCdcEventSetCommFeature, &reqParam);
659                     }
660                     break;
661                 case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE:
662                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
663                          USB_REQUEST_TYPE_DIR_IN) &&
664                         (controlRequest->setup->wLength != 0U))
665                     {
666                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
667                         it is from the second parameter of classInit */
668                         error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
669                                                                           kUSB_DeviceCdcEventGetCommFeature, &reqParam);
670                     }
671                     break;
672                 case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE:
673                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
674                          USB_REQUEST_TYPE_DIR_OUT) &&
675                         (controlRequest->setup->wLength == 0U))
676                     {
677                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
678                         it is from the second parameter of classInit */
679                         error = cdcAcmHandle->configStruct->classCallback(
680                             (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventClearCommFeature, &reqParam);
681                     }
682                     break;
683                 case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING:
684                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
685                          USB_REQUEST_TYPE_DIR_IN) &&
686                         (controlRequest->setup->wLength != 0U))
687                     {
688                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
689                         it is from the second parameter of classInit */
690                         error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
691                                                                           kUSB_DeviceCdcEventGetLineCoding, &reqParam);
692                     }
693                     break;
694                 case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING:
695                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
696                          USB_REQUEST_TYPE_DIR_OUT) &&
697                         (controlRequest->setup->wLength != 0U))
698                     {
699                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
700                         it is from the second parameter of classInit */
701                         error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
702                                                                           kUSB_DeviceCdcEventSetLineCoding, &reqParam);
703                     }
704                     break;
705                 case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE:
706                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
707                          USB_REQUEST_TYPE_DIR_OUT) &&
708                         (controlRequest->setup->wLength == 0U))
709                     {
710                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
711                         it is from the second parameter of classInit */
712                         error = cdcAcmHandle->configStruct->classCallback(
713                             (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventSetControlLineState, &reqParam);
714                     }
715                     break;
716                 case USB_DEVICE_CDC_REQUEST_SEND_BREAK:
717                     if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
718                          USB_REQUEST_TYPE_DIR_OUT) &&
719                         (controlRequest->setup->wLength == 0U))
720                     {
721                         /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
722                         it is from the second parameter of classInit */
723                         error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
724                                                                           kUSB_DeviceCdcEventSendBreak, &reqParam);
725                     }
726                     break;
727                 default:
728                     /* no action, return kStatus_USB_InvalidRequest */
729                     break;
730             }
731         }
732         break;
733         default:
734             /*no action*/
735             break;
736     }
737     return error;
738 }
739 
740 /*!
741  * @brief Initializes the USB CDC ACM class.
742  *
743  * This function obtains a usb device handle according to the controller id, initializes the CDC ACM class
744  * with the class configure parameters and creates the mutex for each pipe.
745  *
746  * @param controllerId The id of the controller. The value can be choosen from kUSB_ControllerKhci0,
747  *  kUSB_ControllerKhci1, kUSB_ControllerEhci0 or kUSB_ControllerEhci1.
748  * @param config The user configuration structure of type usb_device_class_config_struct_t. The user
749  *  populates the members of this structure and passes the pointer of this structure
750  *  into this function.
751  * @param handle  It is out parameter. The class handle of the CDC ACM class.
752  * @return A USB error code or kStatus_USB_Success.
753  */
USB_DeviceCdcAcmInit(uint8_t controllerId,usb_device_class_config_struct_t * config,class_handle_t * handle)754 usb_status_t USB_DeviceCdcAcmInit(uint8_t controllerId,
755                                   usb_device_class_config_struct_t *config,
756                                   class_handle_t *handle)
757 {
758     usb_device_cdc_acm_struct_t *cdcAcmHandle;
759     usb_status_t error;
760 
761     error = USB_DeviceCdcAcmAllocateHandle(&cdcAcmHandle);
762 
763     if (kStatus_USB_Success != error)
764     {
765         return error;
766     }
767 
768     error = USB_DeviceClassGetDeviceHandle(controllerId, &cdcAcmHandle->handle);
769 
770     if (kStatus_USB_Success != error)
771     {
772         return error;
773     }
774 
775     if (NULL == cdcAcmHandle->handle)
776     {
777         return kStatus_USB_InvalidHandle;
778     }
779     cdcAcmHandle->configStruct  = config;
780     cdcAcmHandle->configuration = 0U;
781     cdcAcmHandle->alternate     = 0xFF;
782 
783     cdcAcmHandle->bulkIn.mutex = (osa_mutex_handle_t)&cdcAcmHandle->bulkIn.mutexBuffer[0];
784     if (KOSA_StatusSuccess != OSA_MutexCreate((cdcAcmHandle->bulkIn.mutex)))
785     {
786 #if 0
787         (void)usb_echo("mutex create error!");
788 #endif
789     }
790     cdcAcmHandle->bulkOut.mutex = (osa_mutex_handle_t)&cdcAcmHandle->bulkOut.mutexBuffer[0];
791     if (KOSA_StatusSuccess != OSA_MutexCreate((cdcAcmHandle->bulkOut.mutex)))
792     {
793 #if 0
794         (void)usb_echo("mutex create error!");
795 #endif
796     }
797     cdcAcmHandle->interruptIn.mutex = (osa_mutex_handle_t)&cdcAcmHandle->interruptIn.mutexBuffer[0];
798     if (KOSA_StatusSuccess != OSA_MutexCreate((cdcAcmHandle->interruptIn.mutex)))
799     {
800 #if 0
801         (void)usb_echo("mutex create error!");
802 #endif
803     }
804     *handle = (class_handle_t)cdcAcmHandle;
805     return error;
806 }
807 
808 /*!
809  * @brief De-Initializes the USB CDC ACM class.
810  *
811  * This function destroys the mutex for each pipe, deinit each endpoint of the CDC ACM class and free
812  * the CDC ACM class handle.
813  *
814  * @param handle The class handle of the CDC ACM class.
815  * @return A USB error code or kStatus_USB_Success.
816  */
USB_DeviceCdcAcmDeinit(class_handle_t handle)817 usb_status_t USB_DeviceCdcAcmDeinit(class_handle_t handle)
818 {
819     usb_device_cdc_acm_struct_t *cdcAcmHandle;
820     usb_status_t error;
821 
822     cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
823 
824     if (NULL == cdcAcmHandle)
825     {
826         return kStatus_USB_InvalidHandle;
827     }
828     if (KOSA_StatusSuccess != OSA_MutexDestroy((cdcAcmHandle->bulkIn.mutex)))
829     {
830 #if 0
831         (void)usb_echo("mutex destroy error!");
832 #endif
833     }
834     if (KOSA_StatusSuccess != OSA_MutexDestroy((cdcAcmHandle->bulkOut.mutex)))
835     {
836 #if 0
837         (void)usb_echo("mutex destroy error!");
838 #endif
839     }
840     if (KOSA_StatusSuccess != OSA_MutexDestroy((cdcAcmHandle->interruptIn.mutex)))
841     {
842 #if 0
843         (void)usb_echo("mutex destroy error!");
844 #endif
845     }
846     error = USB_DeviceCdcAcmEndpointsDeinit(cdcAcmHandle);
847 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
848     if (kStatus_USB_Success != USB_DeviceCdcAcmFreeHandle(cdcAcmHandle))
849     {
850         return kStatus_USB_Error;
851     }
852 #else
853     (void)USB_DeviceCdcAcmFreeHandle(cdcAcmHandle);
854 #endif
855     return error;
856 }
857 
858 /*!
859  * @brief Prime the endpoint to send packet to host.
860  *
861  * This function checks whether the endpoint is sending packet, then it primes the endpoint
862  * with the buffer address and the buffer length if the pipe is not busy. Otherwise, it ignores this transfer by
863  * returning an error code.
864  *
865  * @param handle The class handle of the CDC ACM class.
866  * @param ep The endpoint number of the transfer.
867  * @param buffer The pointer to the buffer to be transferred.
868  * @param length The length of the buffer to be transferred.
869  * @return A USB error code or kStatus_USB_Success.
870  */
USB_DeviceCdcAcmSend(class_handle_t handle,uint8_t ep,uint8_t * buffer,uint32_t length)871 usb_status_t USB_DeviceCdcAcmSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
872 {
873     usb_device_cdc_acm_struct_t *cdcAcmHandle;
874     usb_status_t status                   = kStatus_USB_Error;
875     usb_device_cdc_acm_pipe_t *cdcAcmPipe = NULL;
876 
877     if (NULL == handle)
878     {
879         return kStatus_USB_InvalidHandle;
880     }
881     cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
882 
883     if (cdcAcmHandle->bulkIn.ep == ep)
884     {
885         cdcAcmPipe = &(cdcAcmHandle->bulkIn);
886     }
887     else if (cdcAcmHandle->interruptIn.ep == ep)
888     {
889         cdcAcmPipe = &(cdcAcmHandle->interruptIn);
890     }
891     else
892     {
893         /*no action*/
894     }
895 
896     if (NULL != cdcAcmPipe)
897     {
898         if (1U == cdcAcmPipe->isBusy)
899         {
900             return kStatus_USB_Busy;
901         }
902         cdcAcmPipe->isBusy = 1U;
903 
904         if (0u != cdcAcmPipe->pipeStall)
905         {
906             cdcAcmPipe->pipeDataBuffer = buffer;
907             cdcAcmPipe->pipeDataLen    = length;
908             return kStatus_USB_Success;
909         }
910 
911         status = USB_DeviceSendRequest(cdcAcmHandle->handle, ep, buffer, length);
912         if (kStatus_USB_Success != status)
913         {
914             cdcAcmPipe->isBusy = 0U;
915         }
916     }
917     return status;
918 }
919 
920 /*!
921  * @brief Prime the endpoint to receive packet from host.
922  *
923  * This function checks whether the endpoint is receiving packet, then it primes the endpoint
924  * with the buffer address and the buffer length if the pipe is not busy. Otherwise, it ignores this transfer by
925  * returning an error code.
926  *
927  * @param handle The class handle of the CDC ACM class.
928  * @param ep The endpoint number of the transfer.
929  * @param buffer The pointer to the buffer to be transferred.
930  * @param length The length of the buffer to be transferred.
931  * @return A USB error code or kStatus_USB_Success.
932  */
USB_DeviceCdcAcmRecv(class_handle_t handle,uint8_t ep,uint8_t * buffer,uint32_t length)933 usb_status_t USB_DeviceCdcAcmRecv(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
934 {
935     usb_device_cdc_acm_struct_t *cdcAcmHandle;
936     usb_status_t status;
937     if (NULL == handle)
938     {
939         return kStatus_USB_InvalidHandle;
940     }
941     cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
942 
943     if (1U == cdcAcmHandle->bulkOut.isBusy)
944     {
945         return kStatus_USB_Busy;
946     }
947     cdcAcmHandle->bulkOut.isBusy = 1U;
948 
949     if (0U != cdcAcmHandle->bulkOut.pipeStall)
950     {
951         cdcAcmHandle->bulkOut.pipeDataBuffer = buffer;
952         cdcAcmHandle->bulkOut.pipeDataLen    = length;
953         return kStatus_USB_Success;
954     }
955 
956     status = USB_DeviceRecvRequest(cdcAcmHandle->handle, ep, buffer, length);
957     if (kStatus_USB_Success != status)
958     {
959         cdcAcmHandle->bulkOut.isBusy = 0U;
960     }
961     return status;
962 }
963 
964 #endif /* USB_DEVICE_CONFIG_CDC_ACM */
965