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