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