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