common: Implement the receive path for the USB serial module.
[gps-watch.git] / src / common / virtual_com.c
1 /*
2  * The Clear BSD License
3  * Copyright (c) 2015, Freescale Semiconductor, Inc.
4  * Copyright 2016-2017 NXP
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modification,
8  * are permitted (subject to the limitations in the disclaimer below) provided
9  * that the following conditions are met:
10  *
11  * o Redistributions of source code must retain the above copyright notice, this list
12  *   of conditions and the following disclaimer.
13  *
14  * o Redistributions in binary form must reproduce the above copyright notice, this
15  *   list of conditions and the following disclaimer in the documentation and/or
16  *   other materials provided with the distribution.
17  *
18  * o Neither the name of the copyright holder nor the names of its
19  *   contributors may be used to endorse or promote products derived from this
20  *   software without specific prior written permission.
21  *
22  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 #include "fsl_device_registers.h"
35
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 #include "usb_device_config.h"
40 #include "usb.h"
41 #include "usb_device.h"
42
43 #include "usb_device_cdc_acm.h"
44 #include "usb_device_ch9.h"
45
46 #include "usb_device_descriptor.h"
47 #include "virtual_com.h"
48 #if (defined(FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT > 0U))
49 #include "fsl_sysmpu.h"
50 #endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */
51 #if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0)
52 #include "usb_phy.h"
53 #endif
54
55 #include "ringbuf.h"
56
57 /* Provided by users. */
58 extern void USB_DeviceClockInit(void);
59 extern void USB_DeviceIsrEnable(void);
60 /*******************************************************************************
61 * Definitions
62 ******************************************************************************/
63
64 /*******************************************************************************
65 * Variables
66 ******************************************************************************/
67
68 static uint8_t cdc_rx_buf_space[1024];
69
70 static struct ringbuf cdc_rx_buf =
71         RINGBUF_INIT (cdc_rx_buf_space, sizeof (cdc_rx_buf_space));
72
73 /* Data structure of virtual com device */
74 usb_cdc_vcom_struct_t s_cdcVcom;
75
76 /* Line codinig of cdc device */
77 static uint8_t s_lineCoding[LINE_CODING_SIZE] = {
78     /* E.g. 0x00,0xC2,0x01,0x00 : 0x0001C200 is 115200 bits per second */
79     (LINE_CODING_DTERATE >> 0U) & 0x000000FFU,
80     (LINE_CODING_DTERATE >> 8U) & 0x000000FFU,
81     (LINE_CODING_DTERATE >> 16U) & 0x000000FFU,
82     (LINE_CODING_DTERATE >> 24U) & 0x000000FFU,
83     LINE_CODING_CHARFORMAT,
84     LINE_CODING_PARITYTYPE,
85     LINE_CODING_DATABITS};
86
87 /* Abstract state of cdc device */
88 static uint8_t s_abstractState[COMM_FEATURE_DATA_SIZE] = {(STATUS_ABSTRACT_STATE >> 0U) & 0x00FFU,
89                                                           (STATUS_ABSTRACT_STATE >> 8U) & 0x00FFU};
90
91 /* Country code of cdc device */
92 static uint8_t s_countryCode[COMM_FEATURE_DATA_SIZE] = {(COUNTRY_SETTING >> 0U) & 0x00FFU,
93                                                         (COUNTRY_SETTING >> 8U) & 0x00FFU};
94
95 /* CDC ACM information */
96 static usb_cdc_acm_info_t s_usbCdcAcmInfo = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0};
97
98 /* Data buffer for receiving and sending*/
99 static uint8_t s_currRecvBuf[DATA_BUFF_SIZE];
100 volatile static uint32_t s_recvSize = 0;
101 volatile static uint32_t s_sendSize = 0;
102 volatile static uint8_t s_sendComplete = 0;
103 volatile static uint8_t s_currRecvIndex = 0;
104 static uint32_t s_usbBulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
105 /*******************************************************************************
106 * Prototypes
107 ******************************************************************************/
108
109 /*******************************************************************************
110 * Code
111 ******************************************************************************/
112 /*!
113  * @brief Interrupt in pipe callback function.
114  *
115  * This function serves as the callback function for interrupt in pipe.
116  *
117  * @param handle The USB device handle.
118  * @param message The endpoint callback message
119  * @param callbackParam The parameter of the callback.
120  *
121  * @return A USB error code or kStatus_USB_Success.
122  */
123 usb_status_t USB_DeviceCdcAcmInterruptIn(usb_device_handle handle,
124                                          usb_device_endpoint_callback_message_struct_t *message,
125                                          void *callbackParam)
126 {
127     usb_status_t error = kStatus_USB_Error;
128
129     return error;
130 }
131
132 /*!
133  * @brief Bulk in pipe callback function.
134  *
135  * This function serves as the callback function for bulk in pipe.
136  *
137  * @param handle The USB device handle.
138  * @param message The endpoint callback message
139  * @param callbackParam The parameter of the callback.
140  *
141  * @return A USB error code or kStatus_USB_Success.
142  */
143 usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle,
144                                     usb_device_endpoint_callback_message_struct_t *message,
145                                     void *callbackParam)
146 {
147     usb_status_t error = kStatus_USB_Error;
148
149     if ((message->length != 0) && (!(message->length % s_usbBulkMaxPacketSize)))
150     {
151         /* If the last packet is the size of endpoint, then send also zero-ended packet,
152          ** meaning that we want to inform the host that we do not have any additional
153          ** data, so it can flush the output.
154          */
155         USB_DeviceSendRequest(handle, USB_CDC_VCOM_BULK_IN_ENDPOINT, NULL, 0);
156     }
157     else if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions))
158     {
159         if ((message->buffer != NULL) || ((message->buffer == NULL) && (message->length == 0)))
160         {
161             /* User: add your own code for send complete event */
162             s_sendComplete = 1;
163                         USB_DeviceRecvRequest (handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize);
164 #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \
165     defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) &&             \
166     defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U)
167             USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK;
168 #endif
169         }
170     }
171     else if ((0 == s_sendComplete) && (1 == s_cdcVcom.attach) && (0 == s_cdcVcom.startTransactions))
172     {
173         s_sendComplete = 1;
174     }
175     else
176     {
177     }
178     return error;
179 }
180
181 /*!
182  * @brief Bulk out pipe callback function.
183  *
184  * This function serves as the callback function for bulk out pipe.
185  *
186  * @param handle The USB device handle.
187  * @param message The endpoint callback message
188  * @param callbackParam The parameter of the callback.
189  *
190  * @return A USB error code or kStatus_USB_Success.
191  */
192 usb_status_t USB_DeviceCdcAcmBulkOut(usb_device_handle handle,
193                                      usb_device_endpoint_callback_message_struct_t *message,
194                                      void *callbackParam)
195 {
196     usb_status_t error = kStatus_USB_Error;
197     if (USB_UNINITIALIZED_VAL_32 == message->length)
198     {
199         s_recvSize = 0xFFFFFFFFU;
200     }
201     else if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions))
202     {
203         s_recvSize = message->length;
204 #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \
205     defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) &&             \
206     defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U)
207         USB0->INTEN |= USB_INTEN_SOFTOKEN_MASK;
208 #endif
209
210                 if (s_recvSize) {
211                         for (uint32_t offset = 0; s_recvSize-- > 0; offset++) {
212                                 if (ringbuf_is_full (&cdc_rx_buf))
213                                         break;
214
215                                 ringbuf_write (&cdc_rx_buf, s_currRecvBuf[offset]);
216                         }
217
218                         s_recvSize = 0;
219                 } else
220
221         if (!s_recvSize)
222         {
223 #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \
224     defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) &&             \
225     defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U)
226             USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK;
227 #endif
228
229                         USB_DeviceRecvRequest (handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize);
230         }
231     }
232     else
233     {
234     }
235     return error;
236 }
237
238 /*!
239  * @brief Get the setup packet buffer.
240  *
241  * This function provides the buffer for setup packet.
242  *
243  * @param handle The USB device handle.
244  * @param setupBuffer The pointer to the address of setup packet buffer.
245  *
246  * @return A USB error code or kStatus_USB_Success.
247  */
248 usb_status_t USB_DeviceGetSetupBuffer(usb_device_handle handle, usb_setup_struct_t **setupBuffer)
249 {
250     static uint32_t cdcVcomSetup[2];
251     if (NULL == setupBuffer)
252     {
253         return kStatus_USB_InvalidParameter;
254     }
255     *setupBuffer = (usb_setup_struct_t *)&cdcVcomSetup;
256     return kStatus_USB_Success;
257 }
258
259 /*!
260  * @brief Get the setup packet data buffer.
261  *
262  * This function gets the data buffer for setup packet.
263  *
264  * @param handle The USB device handle.
265  * @param setup The pointer to the setup packet.
266  * @param length The pointer to the length of the data buffer.
267  * @param buffer The pointer to the address of setup packet data buffer.
268  *
269  * @return A USB error code or kStatus_USB_Success.
270  */
271 usb_status_t USB_DeviceGetClassReceiveBuffer(usb_device_handle handle,
272                                              usb_setup_struct_t *setup,
273                                              uint32_t *length,
274                                              uint8_t **buffer)
275 {
276     static uint8_t setupOut[8];
277     if ((NULL == buffer) || ((*length) > sizeof(setupOut)))
278     {
279         return kStatus_USB_InvalidRequest;
280     }
281     *buffer = setupOut;
282     return kStatus_USB_Success;
283 }
284
285 /*!
286  * @brief Configure remote wakeup feature.
287  *
288  * This function configures the remote wakeup feature.
289  *
290  * @param handle The USB device handle.
291  * @param enable 1: enable, 0: disable.
292  *
293  * @return A USB error code or kStatus_USB_Success.
294  */
295 usb_status_t USB_DeviceConfigureRemoteWakeup(usb_device_handle handle, uint8_t enable)
296 {
297     return kStatus_USB_InvalidRequest;
298 }
299
300 /*!
301  * @brief CDC class specific callback function.
302  *
303  * This function handles the CDC class specific requests.
304  *
305  * @param handle The USB device handle.
306  * @param setup The pointer to the setup packet.
307  * @param length The pointer to the length of the data buffer.
308  * @param buffer The pointer to the address of setup packet data buffer.
309  *
310  * @return A USB error code or kStatus_USB_Success.
311  */
312 usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle,
313                                            usb_setup_struct_t *setup,
314                                            uint32_t *length,
315                                            uint8_t **buffer)
316 {
317     usb_status_t error = kStatus_USB_InvalidRequest;
318
319     usb_cdc_acm_info_t *acmInfo = &s_usbCdcAcmInfo;
320     uint32_t len;
321     uint16_t *uartBitmap;
322     if (setup->wIndex != USB_CDC_VCOM_COMM_INTERFACE_INDEX)
323     {
324         return error;
325     }
326
327     switch (setup->bRequest)
328     {
329         case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
330             break;
331         case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
332             break;
333         case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE:
334             if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue)
335             {
336                 *buffer = s_abstractState;
337             }
338             else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue)
339             {
340                 *buffer = s_countryCode;
341             }
342             else
343             {
344             }
345             error = kStatus_USB_Success;
346             break;
347         case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE:
348             if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue)
349             {
350                 *buffer = s_abstractState;
351                 *length = COMM_FEATURE_DATA_SIZE;
352             }
353             else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue)
354             {
355                 *buffer = s_countryCode;
356                 *length = COMM_FEATURE_DATA_SIZE;
357             }
358             else
359             {
360             }
361             error = kStatus_USB_Success;
362             break;
363         case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE:
364             break;
365         case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING:
366             *buffer = s_lineCoding;
367             *length = LINE_CODING_SIZE;
368             error = kStatus_USB_Success;
369             break;
370         case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING:
371             *buffer = s_lineCoding;
372             error = kStatus_USB_Success;
373             break;
374         case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE:
375         {
376             acmInfo->dteStatus = setup->wValue;
377             /* activate/deactivate Tx carrier */
378             if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION)
379             {
380                 acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
381             }
382             else
383             {
384                 acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
385             }
386
387             /* activate carrier and DTE */
388             if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE)
389             {
390                 acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
391             }
392             else
393             {
394                 acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
395             }
396
397             /* Indicates to DCE if DTE is present or not */
398             acmInfo->dtePresent = (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) ? true : false;
399
400             /* Initialize the serial state buffer */
401             acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE;                        /* bmRequestType */
402             acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF; /* bNotification */
403             acmInfo->serialStateBuf[2] = 0x00;                                      /* wValue */
404             acmInfo->serialStateBuf[3] = 0x00;
405             acmInfo->serialStateBuf[4] = 0x00; /* wIndex */
406             acmInfo->serialStateBuf[5] = 0x00;
407             acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE; /* wLength */
408             acmInfo->serialStateBuf[7] = 0x00;
409             /* Notifiy to host the line state */
410             acmInfo->serialStateBuf[4] = setup->wIndex;
411             /* Lower byte of UART BITMAP */
412             uartBitmap = (uint16_t *)&acmInfo->serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE - 2];
413             *uartBitmap = acmInfo->uartState;
414             len = (uint32_t)(NOTIF_PACKET_SIZE + UART_BITMAP_SIZE);
415             error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT, acmInfo->serialStateBuf, len);
416
417             /* Update status */
418             if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION)
419             {
420                 /*    To do: CARRIER_ACTIVATED */
421             }
422             else
423             {
424                 /* To do: CARRIER_DEACTIVATED */
425             }
426             if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE)
427             {
428                 /* DTE_ACTIVATED */
429                 if (1 == s_cdcVcom.attach)
430                 {
431                     s_cdcVcom.startTransactions = 1;
432 #if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \
433     defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) &&             \
434     defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U)
435                     USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK;
436 #endif
437                 }
438             }
439             else
440             {
441                 /* DTE_DEACTIVATED */
442                 if (1 == s_cdcVcom.attach)
443                 {
444                     s_cdcVcom.startTransactions = 0;
445                 }
446             }
447         }
448         break;
449         case USB_DEVICE_CDC_REQUEST_SEND_BREAK:
450             break;
451         default:
452             break;
453     }
454
455     return error;
456 }
457
458 /*!
459  * @brief USB device callback function.
460  *
461  * This function handles the usb device specific requests.
462  *
463  * @param handle          The USB device handle.
464  * @param event           The USB device event type.
465  * @param param           The parameter of the device specific request.
466  *
467  * @return A USB error code or kStatus_USB_Success.
468  */
469 usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param)
470 {
471     usb_status_t error = kStatus_USB_Error;
472     uint8_t *temp8 = (uint8_t *)param;
473
474     switch (event)
475     {
476         case kUSB_DeviceEventBusReset:
477         {
478             USB_DeviceControlPipeInit(s_cdcVcom.deviceHandle);
479             s_cdcVcom.attach = 0;
480 #if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0)) || \
481     (defined(USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))
482             if (kStatus_USB_Success ==
483                 USB_DeviceGetStatus(s_cdcVcom.deviceHandle, kUSB_DeviceStatusSpeed, &s_cdcVcom.speed))
484             {
485                 USB_DeviceSetSpeed(handle, s_cdcVcom.speed);
486             }
487 #endif
488         }
489         break;
490         case kUSB_DeviceEventSetConfiguration:
491             if (param)
492             {
493                 s_cdcVcom.attach = 1;
494                 s_cdcVcom.currentConfiguration = *temp8;
495                 if (USB_CDC_VCOM_CONFIGURE_INDEX == (*temp8))
496                 {
497                     usb_device_endpoint_init_struct_t epInitStruct;
498                     usb_device_endpoint_callback_struct_t endpointCallback;
499
500                     /* Initiailize endpoint for interrupt pipe */
501                     endpointCallback.callbackFn = USB_DeviceCdcAcmInterruptIn;
502                     endpointCallback.callbackParam = handle;
503
504                     epInitStruct.zlt = 0;
505                     epInitStruct.transferType = USB_ENDPOINT_INTERRUPT;
506                     epInitStruct.endpointAddress = USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT |
507                                                    (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
508                     if (USB_SPEED_HIGH == s_cdcVcom.speed)
509                     {
510                         epInitStruct.maxPacketSize = HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE;
511                     }
512                     else
513                     {
514                         epInitStruct.maxPacketSize = FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE;
515                     }
516
517                     USB_DeviceInitEndpoint(s_cdcVcom.deviceHandle, &epInitStruct, &endpointCallback);
518
519                     /* Initiailize endpoints for bulk pipe */
520                     endpointCallback.callbackFn = USB_DeviceCdcAcmBulkIn;
521                     endpointCallback.callbackParam = handle;
522
523                     epInitStruct.zlt = 0;
524                     epInitStruct.transferType = USB_ENDPOINT_BULK;
525                     epInitStruct.endpointAddress =
526                         USB_CDC_VCOM_BULK_IN_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
527                     if (USB_SPEED_HIGH == s_cdcVcom.speed)
528                     {
529                         epInitStruct.maxPacketSize = HS_CDC_VCOM_BULK_IN_PACKET_SIZE;
530                     }
531                     else
532                     {
533                         epInitStruct.maxPacketSize = FS_CDC_VCOM_BULK_IN_PACKET_SIZE;
534                     }
535
536                     USB_DeviceInitEndpoint(s_cdcVcom.deviceHandle, &epInitStruct, &endpointCallback);
537
538                     endpointCallback.callbackFn = USB_DeviceCdcAcmBulkOut;
539                     endpointCallback.callbackParam = handle;
540
541                     epInitStruct.zlt = 0;
542                     epInitStruct.transferType = USB_ENDPOINT_BULK;
543                     epInitStruct.endpointAddress =
544                         USB_CDC_VCOM_BULK_OUT_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
545                     if (USB_SPEED_HIGH == s_cdcVcom.speed)
546                     {
547                         epInitStruct.maxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
548                     }
549                     else
550                     {
551                         epInitStruct.maxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
552                     }
553
554                     USB_DeviceInitEndpoint(s_cdcVcom.deviceHandle, &epInitStruct, &endpointCallback);
555
556                     if (USB_SPEED_HIGH == s_cdcVcom.speed)
557                     {
558                         s_usbBulkMaxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
559                     }
560                     else
561                     {
562                         s_usbBulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE;
563                     }
564
565                                         USB_DeviceRecvRequest (handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize);
566                 }
567             }
568             break;
569         default:
570             break;
571     }
572
573     return error;
574 }
575
576 /*!
577  * @brief USB configure endpoint function.
578  *
579  * This function configure endpoint status.
580  *
581  * @param handle The USB device handle.
582  * @param ep Endpoint address.
583  * @param status A flag to indicate whether to stall the endpoint. 1: stall, 0: unstall.
584  *
585  * @return A USB error code or kStatus_USB_Success.
586  */
587 usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status)
588 {
589     if (status)
590     {
591         return USB_DeviceStallEndpoint(handle, ep);
592     }
593     else
594     {
595         return USB_DeviceUnstallEndpoint(handle, ep);
596     }
597 }
598
599 /* See virtual_com.h for documentation of this function. */
600 void USB_VcomWriteBlocking(usb_device_handle baseAddr, const uint8_t *buf, size_t count)
601 {
602     while ((s_cdcVcom.attach != 1) || (s_cdcVcom.startTransactions != 1))
603     {
604     };
605     USB_DeviceSendRequest((usb_device_handle)baseAddr, USB_CDC_VCOM_BULK_IN_ENDPOINT, (uint8_t *)buf, count);
606     while (!s_sendComplete)
607     {
608     };
609     s_sendComplete = 0;
610 }
611
612 /* See virtual_com.h for documentation of this function. */
613 status_t USB_VcomReadBlocking(usb_device_handle baseAddr, uint8_t *buf, size_t count)
614 {
615     status_t error = kStatus_Success;
616     size_t bufIndex = 0U, bytesToReceive = 0U;
617     assert(count != 0U);
618
619     /* Waiting for the USB ready. */
620     while ((s_cdcVcom.attach != 1) || (s_cdcVcom.startTransactions != 1))
621     {
622     };
623
624     do
625     {
626         /* If no receive request. */
627         if (s_recvSize <= 0)
628         {
629             if (kStatus_USB_Success !=
630                 USB_DeviceRecvRequest(baseAddr, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize))
631             {
632                 return kStatus_Fail;
633             }
634             s_currRecvIndex = 0;
635         }
636         /* Waiting for data received by virtual com. */
637         while (s_recvSize <= 0)
638         {
639         };
640
641         /* When receive request is error. */
642         if (0xFFFFFFFFU == s_recvSize)
643         {
644             /* Waiting for the USB ready and transfer started. */
645             while ((s_cdcVcom.attach != 1) || (s_cdcVcom.startTransactions != 1))
646             {
647             };
648             s_recvSize = 0;
649         }
650         else
651         {
652             bytesToReceive = MIN(count, s_recvSize);
653             memcpy((void *)&buf[bufIndex], s_currRecvBuf + s_currRecvIndex, bytesToReceive);
654             count -= bytesToReceive;
655             s_recvSize -= bytesToReceive;
656             bufIndex += bytesToReceive;
657             s_currRecvIndex += bytesToReceive;
658         }
659     } while (0U != count);
660     return error;
661 }
662
663 /* See virtual_com.h for documentation of this function. */
664 usb_device_handle USB_VcomInit(void)
665 {
666     usb_device_handle deviceHandle = NULL;
667
668     USB_DeviceClockInit();
669
670 #if (defined(FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT > 0U))
671     SYSMPU_Enable(SYSMPU, 0);
672 #endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */
673
674     s_cdcVcom.speed = USB_SPEED_FULL;
675     s_cdcVcom.attach = 0;
676     s_cdcVcom.deviceHandle = NULL;
677
678     if (kStatus_USB_Success != USB_DeviceInit(CONTROLLER_ID, USB_DeviceCallback, &s_cdcVcom.deviceHandle))
679     {
680         deviceHandle = NULL;
681     }
682     else
683     {
684         deviceHandle = s_cdcVcom.deviceHandle;
685         USB_DeviceIsrEnable();
686         USB_DeviceRun(s_cdcVcom.deviceHandle);
687     }
688     return deviceHandle;
689 }
690
691 /* See virtual_com.h for documentation of this function. */
692 void USB_VcomDeinit(usb_device_handle deviceHandle)
693 {
694     USB_DeviceStop(deviceHandle);
695     USB_DeviceDeinit(deviceHandle);
696     s_cdcVcom.deviceHandle = NULL;
697 #if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0)
698     USB_EhciPhyDeinit(CONTROLLER_ID);
699 #endif
700 #if defined(USB_DEVICE_CONFIG_KHCI) && (USB_DEVICE_CONFIG_KHCI > 0)
701     CLOCK_DisableUsbfs0Clock();
702 #endif
703 #if defined(USB_DEVICE_CONFIG_LPCIP3511FS) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)
704     /* enable USB IP clock, user code. */
705     CLOCK_DisableClock(kCLOCK_Usbd0);
706 #endif /* USB_DEVICE_CONFIG_LPCIP3511FS */
707
708 #if defined(USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)
709 /* enable USB IP clock,user code. */
710 #endif /* USB_DEVICE_CONFIG_LPCIP3511HS */
711 }
712
713 void
714 USB0_IRQHandler (void)
715 {
716         USB_DeviceKhciIsrFunction (s_cdcVcom.deviceHandle);
717 }
718
719 bool usb_serial_read (char *c)
720 {
721         if (ringbuf_is_empty (&cdc_rx_buf)) {
722                 if (!s_recvSize || s_recvSize == (uint32_t) -1)
723                         USB_DeviceRecvRequest (s_cdcVcom.deviceHandle,
724                                                USB_CDC_VCOM_BULK_OUT_ENDPOINT,
725                                                s_currRecvBuf,
726                                                s_usbBulkMaxPacketSize);
727
728                 return false;
729         }
730
731         *c = ringbuf_read (&cdc_rx_buf);
732
733         return true;
734 }