usb: Add USB device core layer

USB Device core layer is a hardware independent interface between USB
device controller driver and USB device class drivers or customer
applications. It's a port of the LPCUSB device stack.

Change-Id: I9371ffab7034d20953fec0525e72fbe9e094c931
Signed-off-by: Adrian Bradianu <adrian.bradianu@windriver.com>
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
Signed-off-by: Jithu Joseph <jithu.joseph@intel.com>
diff --git a/Kconfig.zephyr b/Kconfig.zephyr
index 99d04a3..edfb44f 100644
--- a/Kconfig.zephyr
+++ b/Kconfig.zephyr
@@ -34,6 +34,8 @@
 
 source "ext/Kconfig"
 
+source "usb/Kconfig"
+
 #
 # The following are for Kconfig files for default values only.
 # These should be parsed at the end.
diff --git a/Makefile b/Makefile
index 4754176..e162edc 100644
--- a/Makefile
+++ b/Makefile
@@ -515,7 +515,7 @@
 	$(Q)$(MAKE) $(build)=$(@)
 
 
-core-y := lib/ kernel/ misc/ net/ boards/ arch/ ext/
+core-y := lib/ kernel/ misc/ net/ boards/ arch/ ext/ usb/
 drivers-y := drivers/
 
 ifneq ($(strip $(MAKEFILE_APP_DIR)),)
diff --git a/boards/arduino_101/board.h b/boards/arduino_101/board.h
index 55029f6..1c77998 100644
--- a/boards/arduino_101/board.h
+++ b/boards/arduino_101/board.h
@@ -19,4 +19,11 @@
 
 #include <soc.h>
 
+#if defined(CONFIG_USB)
+/* GPIO driver name */
+#define USB_GPIO_DRV_NAME	CONFIG_GPIO_QMSI_0_NAME
+/* GPIO pin for enabling VBUS */
+#define USB_VUSB_EN_GPIO	28
+#endif
+
 #endif /* __INC_BOARD_H */
diff --git a/boards/quark_se_devboard/board.h b/boards/quark_se_devboard/board.h
index 2954407..d75696a 100644
--- a/boards/quark_se_devboard/board.h
+++ b/boards/quark_se_devboard/board.h
@@ -46,4 +46,11 @@
 
 #endif /* CONFIG_NETWORKING_WITH_15_4_TI_CC2520 */
 
+#if defined(CONFIG_USB)
+/* GPIO driver name */
+#define USB_GPIO_DRV_NAME	CONFIG_GPIO_QMSI_0_NAME
+/* GPIO pin for enabling VBUS */
+#define USB_VUSB_EN_GPIO	28
+#endif
+
 #endif /* __BOARD_H__ */
diff --git a/include/usb/usb_common.h b/include/usb/usb_common.h
new file mode 100644
index 0000000..8b26c1e
--- /dev/null
+++ b/include/usb/usb_common.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ *
+ *
+ * Copyright(c) 2015,2016 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+/**
+ * @file
+ * @brief useful constants and macros for the USB application
+ *
+ * This file contains useful constants and macros for the USB applications.
+ */
+
+#ifndef USB_COMMON_H_
+#define USB_COMMON_H_
+
+/* Decriptor size in bytes */
+#define USB_DEVICE_DESC_SIZE            18
+#define USB_CONFIGURATION_DESC_SIZE     9
+#define USB_INTERFACE_DESC_SIZE         9
+#define USB_ENDPOINT_DESC_SIZE          7
+#define USB_STRING_DESC_SIZE            4
+#define USB_HID_DESC_SIZE               9
+#define USB_DFU_DESC_SIZE               9
+
+/* Descriptor type */
+#define USB_DEVICE_DESC                 0x01
+#define USB_CONFIGURATION_DESC          0x02
+#define USB_STRING_DESC                 0x03
+#define USB_INTERFACE_DESC              0x04
+#define USB_ENDPOINT_DESC               0x05
+#define USB_HID_DESC                    0x21
+#define USB_HID_REPORT_DESC             0x22
+#define USB_DFU_FUNCTIONAL_DESC         0x21
+
+/* Useful define */
+#define USB_1_1                         0x0110
+
+#define BCDDEVICE_RELNUM                0x0100
+
+/* 100mA max power, per 2mA units */
+/* USB 1.1 spec indicates 100mA(max) per unit load, up to 5 loads */
+#define MAX_LOW_POWER                   0x32
+#define MAX_HIGH_POWER                  0xFA
+
+/* bmAttributes:
+ * D7:Reserved, always 1,
+ * D6:Self-Powered -> 1,
+ * D5:Remote Wakeup -> 0,
+ * D4...0:Reserved -> 0
+ */
+#define USB_CONFIGURATION_ATTRIBUTES    0xC0
+
+/* Misc. macros */
+#define LOW_BYTE(x)                     ((x)&0xFF)
+#define HIGH_BYTE(x)                    ((x)>>8)
+
+/* Classes */
+#define COMMUNICATION_DEVICE_CLASS      0x02
+#define COMMUNICATION_DEVICE_CLASS_DATA 0x0A
+#define HID_CLASS                       0x03
+#define MASS_STORAGE_CLASS              0x08
+#define CUSTOM_CLASS                    0xFF
+#define DFU_CLASS                       0xFE
+
+/* Sub-classes */
+#define ACM_SUBCLASS                    0x02
+#define BOOT_INTERFACE_SUBCLASS         0x01
+#define SCSI_TRANSPARENT_SUBCLASS       0x06
+#define DFU_INTERFACE_SUBCLASS          0x01
+
+/* Protocols */
+#define V25TER_PROTOCOL                 0x01
+#define MOUSE_PROTOCOL                  0x02
+#define BULK_ONLY_PROTOCOL              0x50
+#define DFU_RUNTIME_PROTOCOL            0x01
+#define DFU_MODE_PROTOCOL               0x02
+
+#endif /* USB_COMMON_H_ */
diff --git a/usb/Kconfig b/usb/Kconfig
new file mode 100644
index 0000000..6fe1ff5
--- /dev/null
+++ b/usb/Kconfig
@@ -0,0 +1,36 @@
+# Kconfig - USB device stack configuration options
+
+#
+# Copyright (c) 2016 Wind River Systems, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+menuconfig USB_DEVICE_STACK
+	bool
+	prompt "USB device stack"
+	depends on USB
+	default n
+	help
+	Enable USB device stack.
+
+if USB_DEVICE_STACK
+
+config USB_DEBUG
+	bool
+	prompt "Enable USB debug options for the entire USB stack"
+	default n
+	help
+	This option enables the debug features for the USB device stack.
+
+endif # USB_DEVICE_STACK
diff --git a/usb/Makefile b/usb/Makefile
new file mode 100644
index 0000000..f4ad7c5
--- /dev/null
+++ b/usb/Makefile
@@ -0,0 +1,3 @@
+ccflags-y += -I${srctree}/include/drivers/usb -I${srctree}/usb/include
+
+obj-$(CONFIG_USB_DEVICE_STACK) += usb_device.o
diff --git a/usb/include/usb_device.h b/usb/include/usb_device.h
new file mode 100644
index 0000000..c71e97e
--- /dev/null
+++ b/usb/include/usb_device.h
@@ -0,0 +1,229 @@
+/*
+ *  LPCUSB, an USB device driver for LPC microcontrollers
+ *  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+ *  Copyright (c) 2016 Intel Corporation
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief USB device core layer APIs and structures
+ *
+ * This file contains the USB device core layer APIs and structures.
+ */
+
+#ifndef USB_DEVICE_H_
+#define USB_DEVICE_H_
+
+#include "usb_dc.h"
+#include "usbstruct.h"
+
+/*************************************************************************
+ *  USB configuration
+ **************************************************************************/
+
+#define MAX_PACKET_SIZE0    64        /**< maximum packet size for EP 0 */
+
+/*************************************************************************
+ *  USB application interface
+ **************************************************************************/
+
+/** setup packet definitions */
+struct usb_setup_packet {
+	uint8_t bmRequestType;  /**< characteristics of the specific request */
+	uint8_t bRequest;       /**< specific request */
+	uint16_t wValue;        /**< request specific parameter */
+	uint16_t wIndex;        /**< request specific parameter */
+	uint16_t wLength;       /**< length of data transferred in data phase */
+};
+
+/**
+ * Callback function signature for the device
+ */
+typedef void (*usb_status_callback)(enum usb_dc_status_code status_code);
+
+/**
+ * Callback function signature for the USB Endpoint status
+ */
+typedef void (*usb_ep_callback)(uint8_t ep,
+		enum usb_dc_ep_cb_status_code cb_status);
+
+/**
+ * Function which handles Class specific requests corresponding to an
+ * interface number specified in the device descriptor table
+ */
+typedef int (*usb_request_handler) (struct usb_setup_packet *detup,
+		int *transfer_len, uint8_t **payload_data);
+
+/*
+ * USB Endpoint Configuration
+ */
+struct usb_ep_cfg_data {
+	/**
+	 * Callback function for notification of data received and
+	 * available to application or transmit done, NULL if callback
+	 * not required by application code
+	 */
+	usb_ep_callback ep_cb;
+	/**
+	 * The number associated with the EP in the device configuration
+	 * structure
+	 *   IN  EP = 0x80 | \<endpoint number\>
+	 *   OUT EP = 0x00 | \<endpoint number\>
+	 */
+	uint8_t ep_addr;
+};
+
+/**
+ * USB Interface Configuration
+ */
+struct usb_interface_cfg_data {
+	/** Handler for USB Class specific Control (EP 0) communications */
+	usb_request_handler class_handler;
+	/**
+	 * The custom request handler gets a first chance at handling
+	 * the request before it is handed over to the 'chapter 9' request
+	 * handler
+	 */
+	usb_request_handler custom_handler;
+	/**
+	 * This data area, allocated by the application, is used to store
+	 * Class specific command data and must be large enough to store the
+	 * largest payload associated with the largest supported Class'
+	 * command set. This data area may be used for USB IN or OUT
+	 * communications
+	 */
+	uint8_t *payload_data;
+};
+
+/*
+ * @brief USB device configuration
+ *
+ * The Application instantiates this with given parameters added
+ * using the "usb_set_config" function. Once this function is called
+ * changes to this structure will result in undefined behaviour. This structure
+ * may only be updated after calls to usb_deconfig
+ */
+struct usb_cfg_data {
+	/**
+	 * USB device description, see
+	 * http://www.beyondlogic.org/usbnutshell/usb5.shtml#DeviceDescriptors
+	 */
+	const uint8_t *usb_device_description;
+	/** Callback to be notified on USB connection status change */
+	usb_status_callback cb_usb_status;
+	/** USB interface (Class) handler and storage space */
+	struct usb_interface_cfg_data interface;
+	/** Number of individual endpoints in the device configuration */
+	uint8_t num_endpoints;
+	/**
+	 * Pointer to an array of endpoint structs of length equal to the
+	 * number of EP associated with the device description,
+	 * not including control endpoints
+	 */
+	struct usb_ep_cfg_data *endpoint;
+};
+
+/*
+ * @brief configure USB controller
+ *
+ * Function to configure USB controller.
+ * Configuration parameters must be valid or an error is returned
+ *
+ * @param[in] config Pointer to configuration structure
+ *
+ * @return 0 on success, negative errno code on fail
+ */
+int usb_set_config(struct usb_cfg_data *config);
+
+/*
+ * @brief return the USB device to it's initial state
+ *
+ * @return 0 on success, negative errno code on fail
+ */
+int usb_deconfig(void);
+
+/*
+ * @brief enable USB for host/device connection
+ *
+ * Function to enable USB for host/device connection.
+ * Upon success, the USB module is no longer clock gated in hardware,
+ * it is now capable of transmitting and receiving on the USB bus and
+ * of generating interrupts.
+ *
+ * @return 0 on success, negative errno code on fail.
+ */
+int usb_enable(struct usb_cfg_data *config);
+
+/*
+ * @brief disable the USB device.
+ *
+ * Function to disable the USB device.
+ * Upon success, the specified USB interface is clock gated in hardware,
+ * it is no longer capable of generating interrupts.
+ *
+ * @return 0 on success, negative errno code on fail
+ */
+int usb_disable(void);
+
+/*
+ * @brief write data to the specified endpoint
+ *
+ * Function to write data to the specified endpoint. The supplied
+ * usb_ep_callback will be called when transmission is done.
+ *
+ * @param[in]  ep        Endpoint address corresponding to the one listed in the
+ *                       device configuration table
+ * @param[in]  data      Pointer to data to write
+ * @param[in]  data_len  Length of data requested to write. This may be zero for
+ *                       a zero length status packet.
+ * @param[out] bytes_ret Bytes written to the EP FIFO. This value may be NULL if
+ *                       the application expects all bytes to be written
+ *
+ * @return 0 on success, negative errno code on fail
+ */
+int usb_write(uint8_t ep, const uint8_t *data, uint32_t data_len,
+		uint32_t *bytes_ret);
+
+/*
+ * @brief read data from the specified endpoint
+ *
+ * This function is called by the Endpoint handler function, after an
+ * OUT interrupt has been received for that EP. The application must
+ * only call this function through the supplied usb_ep_callback function.
+ *
+ * @param[in]  ep           Endpoint address corresponding to the one listed in
+ *                          the device configuration table
+ * @param[in]  data         Pointer to data buffer to write to
+ * @param[in]  max_data_len Max length of data to read
+ * @param[out] ret_bytes    Number of bytes read. If data is NULL and
+ *                          max_data_len is 0 the number of bytes available
+ *                          for read is returned.
+ *
+ * @return  0 on success, negative errno code on fail
+ */
+int usb_read(uint8_t ep, uint8_t *data, uint32_t max_data_len,
+		uint32_t *ret_bytes);
+
+#endif /* USB_DEVICE_H_ */
diff --git a/usb/include/usbstruct.h b/usb/include/usbstruct.h
new file mode 100644
index 0000000..229065a
--- /dev/null
+++ b/usb/include/usbstruct.h
@@ -0,0 +1,111 @@
+/*
+ *  LPCUSB, an USB device driver for LPC microcontrollers
+ *  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+ *  Copyright (c) 2016 Intel Corporation
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief standard USB packet stuctures and defines
+ *
+ * This file contains stuctures and defines of the standard USB packets
+ */
+
+#ifndef _USBSTRUCT_H_
+#define _USBSTRUCT_H_
+
+#define REQTYPE_GET_DIR(x)          (((x)>>7)&0x01)
+#define REQTYPE_GET_TYPE(x)         (((x)>>5)&0x03)
+#define REQTYPE_GET_RECIP(x)        ((x)&0x1F)
+
+#define REQTYPE_DIR_TO_DEVICE       0
+#define REQTYPE_DIR_TO_HOST         1
+
+#define REQTYPE_TYPE_STANDARD       0
+#define REQTYPE_TYPE_CLASS          1
+#define REQTYPE_TYPE_VENDOR         2
+#define REQTYPE_TYPE_RESERVED       3
+
+#define REQTYPE_RECIP_DEVICE        0
+#define REQTYPE_RECIP_INTERFACE     1
+#define REQTYPE_RECIP_ENDPOINT      2
+#define REQTYPE_RECIP_OTHER         3
+
+/* standard requests */
+#define REQ_GET_STATUS              0x00
+#define REQ_CLEAR_FEATURE           0x01
+#define REQ_SET_FEATURE             0x03
+#define REQ_SET_ADDRESS             0x05
+#define REQ_GET_DESCRIPTOR          0x06
+#define REQ_SET_DESCRIPTOR          0x07
+#define REQ_GET_CONFIGURATION       0x08
+#define REQ_SET_CONFIGURATION       0x09
+#define REQ_GET_INTERFACE           0x0A
+#define REQ_SET_INTERFACE           0x0B
+#define REQ_SYNCH_FRAME             0x0C
+
+/* class requests HID */
+#define HID_GET_REPORT              0x01
+#define HID_GET_IDLE                0x02
+#define HID_GET_PROTOCOL            0x03
+#define HID_SET_REPORT              0x09
+#define HID_SET_IDLE                0x0A
+#define HID_SET_PROTOCOL            0x0B
+
+/* feature selectors */
+#define FEA_ENDPOINT_HALT           0x00
+#define FEA_REMOTE_WAKEUP           0x01
+#define FEA_TEST_MODE               0x02
+
+/*
+ *  USB descriptors
+ */
+
+/** USB descriptor header */
+struct usb_desc_header {
+	uint8_t bLength;               /**< descriptor length */
+	uint8_t bDescriptorType;       /**< descriptor type */
+};
+
+#define DESC_DEVICE                 1
+#define DESC_CONFIGURATION          2
+#define DESC_STRING                 3
+#define DESC_INTERFACE              4
+#define DESC_ENDPOINT               5
+#define DESC_DEVICE_QUALIFIER       6
+#define DESC_OTHER_SPEED            7
+#define DESC_INTERFACE_POWER        8
+
+#define CS_INTERFACE                0x24
+#define CS_ENDPOINT                 0x25
+
+#define DESC_HID_HID                0x21
+#define DESC_HID_REPORT             0x22
+#define DESC_HID_PHYSICAL           0x23
+
+#define GET_DESC_TYPE(x)            (((x)>>8)&0xFF)
+#define GET_DESC_INDEX(x)           ((x)&0xFF)
+
+#endif /* _USBSTRUCT_H_ */
diff --git a/usb/usb_device.c b/usb/usb_device.c
new file mode 100644
index 0000000..966e135
--- /dev/null
+++ b/usb/usb_device.c
@@ -0,0 +1,926 @@
+/*
+ *  LPCUSB, an USB device driver for LPC microcontrollers
+ *  Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+ *  Copyright (c) 2016 Intel Corporation
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. The name of the author may not be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief USB device core layer
+ *
+ * This module handles control transfer handler, standard request handler and
+ * USB Interface for customer application.
+ *
+ * Control transfers handler is normally installed on the
+ * endpoint 0 callback.
+ *
+ * Control transfers can be of the following type:
+ * 0 Standard;
+ * 1 Class;
+ * 2 Vendor;
+ * 3 Reserved.
+ *
+ * A callback can be installed for each of these control transfers using
+ * usb_register_request_handler.
+ * When an OUT request arrives, data is collected in the data store provided
+ * with the usb_register_request_handler call. When the transfer is done, the
+ * callback is called.
+ * When an IN request arrives, the callback is called immediately to either
+ * put the control transfer data in the data store, or to get a pointer to
+ * control transfer data. The data is then packetised and sent to the host.
+ *
+ * Standard request handler handles the 'chapter 9' processing, specifically
+ * the standard device requests in table 9-3 from the universal serial bus
+ * specification revision 2.0
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <misc/util.h>
+#include <misc/__assert.h>
+#include <board.h>
+#if defined(USB_VUSB_EN_GPIO)
+#include <gpio.h>
+#endif
+#include "usb_device.h"
+
+#ifndef CONFIG_USB_DEBUG
+#define DBG(...) { ; }
+#else
+#if defined(CONFIG_STDOUT_CONSOLE)
+#include <stdio.h>
+#define DBG printf
+#else
+#include <misc/printk.h>
+#define DBG printk
+#endif /* CONFIG_STDOUT_CONSOLE */
+#endif /* CONFIG_USB_DEBUG */
+
+#define MAX_DESC_HANDLERS           4 /** Device, interface, endpoint, other */
+
+/* general descriptor field offsets */
+#define DESC_bLength                0 /** Length offset */
+#define DESC_bDescriptorType        1 /** Descriptor type offset */
+
+/* config descriptor field offsets */
+#define CONF_DESC_wTotalLength      2 /** Total length offset */
+#define CONF_DESC_bConfigurationValue 5 /** Configuration value offset */
+#define CONF_DESC_bmAttributes      7 /** configuration characteristics */
+
+/* interface descriptor field offsets */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+
+/* endpoint descriptor field offsets */
+#define ENDP_DESC_bEndpointAddress  2 /** Endpoint address offset */
+#define ENDP_DESC_bmAttributes      3 /** Bulk or interrupt? */
+#define ENDP_DESC_wMaxPacketSize    4 /** Maximum packet size offset */
+
+#define MAX_NUM_REQ_HANDLERS        (4)
+#define MAX_STD_REQ_MSG_SIZE        8
+
+/* Default USB control EP, always 0 and 0x80 */
+#define USB_CONTROL_OUT_EP0         0
+#define USB_CONTROL_IN_EP0          0x80
+
+static struct usb_dev_priv {
+	/** Setup packet */
+	struct usb_setup_packet setup;
+	/** Pointer to data buffer */
+	uint8_t *data_buf;
+	/** Eemaining bytes in buffer */
+	int32_t data_buf_residue;
+	/** Total length of control transfer */
+	int32_t data_buf_len;
+	/** Installed custom request handler */
+	usb_request_handler custom_req_handler;
+	/** USB stack status clalback */
+	usb_status_callback status_callback;
+	/** Pointer to registered descriptors */
+	const uint8_t *descriptors;
+	/** Array of installed request handler callbacks */
+	usb_request_handler req_handlers[MAX_NUM_REQ_HANDLERS];
+	/** Array of installed request data pointers */
+	uint8_t *data_store[MAX_NUM_REQ_HANDLERS];
+	/* Buffer used for storing standard usb request data */
+	uint8_t std_req_data[MAX_STD_REQ_MSG_SIZE];
+	/** Variable to check whether the usb has been enabled */
+	bool enabled;
+	/** Currently selected configuration */
+	uint8_t configuration;
+} usb_dev;
+
+/*
+ * @brief print the contents of a setup packet
+ *
+ * @param [in] setup The setup packet
+ *
+ */
+static void usb_print_setup(struct usb_setup_packet *setup)
+{
+	/* avoid compiler warning if DBG is not defined */
+	setup = setup;
+
+	DBG("SETUP\n");
+	DBG("%x %x %x %x %x\n",
+	    setup->bmRequestType,
+	    setup->bRequest,
+	    setup->wValue,
+	    setup->wIndex,
+	    setup->wLength);
+}
+
+/*
+ * @brief handle a request by calling one of the installed request handlers
+ *
+ * Local function to handle a request by calling one of the installed request
+ * handlers. In case of data going from host to device, the data is at *ppbData.
+ * In case of data going from device to host, the handler can either choose to
+ * write its data at *ppbData or update the data pointer.
+ *
+ * @param [in]     setup The setup packet
+ * @param [in,out] len   Pointer to data length
+ * @param [in,out] data  Data buffer
+ *
+ * @return true if the request was handles successfully
+ */
+static bool usb_handle_request(struct usb_setup_packet *setup,
+		int32_t *len, uint8_t **data)
+{
+	uint32_t type = REQTYPE_GET_TYPE(setup->bmRequestType);
+	usb_request_handler handler = usb_dev.req_handlers[type];
+
+	DBG("** %d **\n", type);
+
+	if (type >= MAX_NUM_REQ_HANDLERS) {
+		DBG("Error Incorrect iType %d\n", type);
+		return false;
+	}
+
+	if (handler == NULL) {
+		DBG("No handler for reqtype %d\n", type);
+		return false;
+	}
+
+	if ((*handler)(setup, len, data) < 0) {
+		DBG("Handler Error %d\n", type);
+		usb_print_setup(setup);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * @brief send next chunk of data (possibly 0 bytes) to host
+ *
+ * @return N/A
+ */
+static void usb_data_to_host(void)
+{
+	uint32_t chunk = min(MAX_PACKET_SIZE0, usb_dev.data_buf_residue);
+
+	/*Always EP0 for control*/
+	usb_dc_ep_write(0x80, usb_dev.data_buf, chunk, &chunk);
+	usb_dev.data_buf += chunk;
+	usb_dev.data_buf_residue -= chunk;
+}
+
+/*
+ * @brief handle IN/OUT transfers on EP0
+ *
+ * @param [in] ep        Endpoint address
+ * @param [in] ep_status Endpoint status
+ *
+ * @return N/A
+ */
+static void usb_handle_control_transfer(uint8_t ep,
+		enum usb_dc_ep_cb_status_code ep_status)
+{
+	uint32_t chunk = 0;
+	uint32_t type = 0;
+	struct usb_setup_packet *setup = &usb_dev.setup;
+
+	DBG("usb_handle_control_transfer ep %x, status %x\n", ep, ep_status);
+	if (ep == USB_CONTROL_OUT_EP0 && ep_status == USB_DC_EP_SETUP) {
+		/*
+		 * OUT transfer, Setup packet,
+		 * reset request message state machine
+		 */
+		if (usb_dc_ep_read(ep,
+		    (uint8_t *)setup, sizeof(*setup), NULL) < 0) {
+			DBG("Read Setup Packet failed\n");
+			usb_dc_ep_set_stall(USB_CONTROL_IN_EP0);
+			return;
+		}
+
+		/* Defaults for data pointer and residue */
+		type = REQTYPE_GET_TYPE(setup->bmRequestType);
+		usb_dev.data_buf = usb_dev.data_store[type];
+		usb_dev.data_buf_residue = setup->wLength;
+		usb_dev.data_buf_len = setup->wLength;
+
+		if (!(setup->wLength == 0) &&
+		    !(REQTYPE_GET_DIR(setup->bmRequestType) ==
+		    REQTYPE_DIR_TO_HOST)) {
+			return;
+		}
+
+		/* Ask installed handler to process request */
+		if (!usb_handle_request(setup,
+		    &usb_dev.data_buf_len, &usb_dev.data_buf)) {
+			DBG("usb_handle_request failed\n");
+			usb_dc_ep_set_stall(USB_CONTROL_IN_EP0);
+			return;
+		}
+
+		/* Send smallest of requested and offered length */
+		usb_dev.data_buf_residue = min(usb_dev.data_buf_len,
+			    setup->wLength);
+		/* Send first part (possibly a zero-length status message) */
+		usb_data_to_host();
+	} else if (ep == USB_CONTROL_OUT_EP0) {
+		/* OUT transfer, data or status packets */
+		if (usb_dev.data_buf_residue <= 0) {
+			/* absorb zero-length status message */
+			if (usb_dc_ep_read(USB_CONTROL_OUT_EP0,
+			    usb_dev.data_buf, 0, &chunk) < 0) {
+				DBG("Read DATA Packet failed\n");
+				usb_dc_ep_set_stall(USB_CONTROL_IN_EP0);
+			}
+			DBG(chunk > 0 ? "?" : "");
+			return;
+		}
+
+		if (usb_dc_ep_read(USB_CONTROL_OUT_EP0,
+		    usb_dev.data_buf,
+		    usb_dev.data_buf_residue, &chunk) < 0) {
+			DBG("Read DATA Packet failed\n");
+			usb_dc_ep_set_stall(USB_CONTROL_IN_EP0);
+			return;
+		}
+
+		usb_dev.data_buf += chunk;
+		usb_dev.data_buf_residue -= chunk;
+		if (usb_dev.data_buf_residue == 0) {
+			/* Received all, send data to handler */
+			type = REQTYPE_GET_TYPE(setup->bmRequestType);
+			usb_dev.data_buf = usb_dev.data_store[type];
+			if (!usb_handle_request(setup,
+			    &usb_dev.data_buf_len,	&usb_dev.data_buf)) {
+				DBG("usb_handle_request1 failed\n");
+				usb_dc_ep_set_stall(USB_CONTROL_IN_EP0);
+				return;
+			}
+
+			/*Send status to host*/
+			DBG(">> usb_data_to_host(2)\n");
+			usb_data_to_host();
+		}
+	} else if (ep == USB_CONTROL_IN_EP0) {
+		/* Send more data if available */
+		if (usb_dev.data_buf_residue != 0) {
+			usb_data_to_host();
+		}
+	} else {
+		__ASSERT_NO_MSG(false);
+	}
+}
+
+
+/*
+ * @brief register a callback for handling requests
+ *
+ * @param [in] type       Type of request, e.g. REQTYPE_TYPE_STANDARD
+ * @param [in] handler    Callback function pointer
+ * @param [in] data_store Data storage area for this type of request
+ *
+ * @return N/A
+ */
+static void usb_register_request_handler(int32_t type,
+		usb_request_handler handler, uint8_t *data_store)
+{
+	usb_dev.req_handlers[type] = handler;
+	usb_dev.data_store[type] = data_store;
+}
+
+/*
+ * @brief register a pointer to a descriptor block
+ *
+ * This function registers a pointer to a descriptor block containing all
+ * descriptors for the device.
+ *
+ * @param [in] usb_descriptors The descriptor byte array
+ */
+static void usb_register_descriptors(const uint8_t *usb_descriptors)
+{
+	usb_dev.descriptors = usb_descriptors;
+}
+
+/*
+ * @brief get specified USB descriptor
+ *
+ * This function parses the list of installed USB descriptors and attempts
+ * to find the specified USB descriptor.
+ *
+ * @param [in]  type_index Type and index of the descriptor
+ * @param [in]  lang_id    Language ID of the descriptor (currently unused)
+ * @param [out] len        Descriptor length
+ * @param [out] data       Descriptor data
+ *
+ * @return true if the descriptor was found, false otherwise
+ */
+static bool usb_get_descriptor(uint16_t type_index, uint16_t lang_id,
+		int32_t *len, uint8_t **data)
+{
+	uint8_t type = 0;
+	uint8_t index = 0;
+	uint8_t *p = NULL;
+	int32_t cur_index = 0;
+	bool found = false;
+
+	__ASSERT_NO_MSG(usb_descriptors != NULL);
+
+	/*Avoid compiler warning until this is used for something*/
+	lang_id = lang_id;
+
+	type = GET_DESC_TYPE(type_index);
+	index = GET_DESC_INDEX(type_index);
+
+	p = (uint8_t *)usb_dev.descriptors;
+	cur_index = 0;
+
+	while (p[DESC_bLength] != 0) {
+		if (p[DESC_bDescriptorType] == type) {
+			if (cur_index == index) {
+				found = true;
+				break;
+			}
+			cur_index++;
+		}
+		/* skip to next descriptor */
+		p += p[DESC_bLength];
+	}
+
+	if (found) {
+		/* set data pointer */
+		*data = p;
+		/* get length from structure */
+		if (type == DESC_CONFIGURATION) {
+			/* configuration descriptor is an
+			 * exception, length is at offset
+			 * 2 and 3
+			 */
+			*len = (p[CONF_DESC_wTotalLength]) |
+			    (p[CONF_DESC_wTotalLength + 1] << 8);
+		} else {
+			/* normally length is at offset 0 */
+			*len = p[DESC_bLength];
+		}
+	} else {
+		/* nothing found */
+		DBG("Desc %x not found!\n", type_index);
+	}
+	return found;
+}
+
+/*
+ * @brief set USB configuration
+ *
+ * This function configures the device according to the specified configuration
+ * index and alternate setting by parsing the installed USB descriptor list.
+ * A configuration index of 0 unconfigures the device.
+ *
+ * @param [in] config_index Configuration index
+ * @param [in] alt_setting  Alternate setting number
+ *
+ * @return true if successfully configured false if error or unconfigured
+ */
+static bool usb_set_configuration(uint8_t config_index, uint8_t alt_setting)
+{
+	uint8_t *p = NULL;
+	uint8_t cur_config = 0;
+	uint8_t cur_alt_setting = 0;
+
+	__ASSERT_NO_MSG(usb_descriptors != NULL);
+
+	if (config_index == 0) {
+		/* unconfigure device */
+		DBG("Device not configured - invalid configuration offset\n");
+		return true;
+	}
+
+	/* configure endpoints for this configuration/altsetting */
+	p = (uint8_t *)usb_dev.descriptors;
+	cur_config = 0xFF;
+	cur_alt_setting = 0xFF;
+
+	while (p[DESC_bLength] != 0) {
+		switch (p[DESC_bDescriptorType]) {
+		case DESC_CONFIGURATION:
+			/* remember current configuration index */
+			cur_config = p[CONF_DESC_bConfigurationValue];
+			break;
+
+		case DESC_INTERFACE:
+			/* remember current alternate setting */
+			cur_alt_setting =
+			    p[INTF_DESC_bAlternateSetting];
+			break;
+
+		case DESC_ENDPOINT:
+			if ((cur_config == config_index) &&
+			    (cur_alt_setting == alt_setting)) {
+				struct usb_dc_ep_cfg_data ep_cfg;
+				/* endpoint found for desired config
+				 * and alternate setting
+				 */
+				ep_cfg.ep_type =
+				    p[ENDP_DESC_bmAttributes];
+				ep_cfg.ep_mps =
+				    (p[ENDP_DESC_wMaxPacketSize]) |
+				    (p[ENDP_DESC_wMaxPacketSize + 1]
+					    << 8);
+				ep_cfg.ep_addr =
+				    p[ENDP_DESC_bEndpointAddress];
+				usb_dc_ep_configure(&ep_cfg);
+				usb_dc_ep_enable(ep_cfg.ep_addr);
+			}
+			break;
+
+		default:
+			break;
+		}
+		/* skip to next descriptor */
+		p += p[DESC_bLength];
+	}
+	if (usb_dev.status_callback)
+		usb_dev.status_callback(USB_DC_CONFIGURED);
+
+	return true;
+}
+
+/*
+ * @brief handle a standard device request
+ *
+ * @param [in]     setup    The setup packet
+ * @param [in,out] len      Pointer to data length
+ * @param [in,out] data_buf Data buffer
+ *
+ * @return true if the request was handled successfully
+ */
+static bool usb_handle_std_device_req(struct usb_setup_packet *setup,
+		int32_t *len, uint8_t **data_buf)
+{
+	bool ret = true;
+	uint8_t *data = *data_buf;
+
+	switch (setup->bRequest) {
+	case REQ_GET_STATUS:
+		DBG("REQ_GET_STATUS\n");
+		/* bit 0: self-powered */
+		/* bit 1: remote wakeup = not supported */
+		data[0] = 0;
+		data[1] = 0;
+		*len = 2;
+		break;
+
+	case REQ_SET_ADDRESS:
+		DBG("REQ_SET_ADDRESS\n");
+		usb_dc_set_address(setup->wValue);
+		break;
+
+	case REQ_GET_DESCRIPTOR:
+		DBG("REQ_GET_DESCRIPTOR\n");
+		ret = usb_get_descriptor(setup->wValue,
+		    setup->wIndex, len, data_buf);
+		break;
+
+	case REQ_GET_CONFIGURATION:
+		DBG("REQ_GET_CONFIGURATION\n");
+		/* indicate if we are configured */
+		data[0] = usb_dev.configuration;
+		*len = 1;
+		break;
+
+	case REQ_SET_CONFIGURATION:
+		DBG("REQ_SET_CONFIGURATION\n");
+		if (!usb_set_configuration(setup->wValue & 0xFF, 0)) {
+			DBG("USBSetConfiguration failed!\n");
+			ret = false;
+		} else {
+			/* configuration successful,
+			 * update current configuration
+			 */
+			usb_dev.configuration = setup->wValue & 0xFF;
+		}
+		break;
+
+	case REQ_CLEAR_FEATURE:
+		DBG("REQ_CLEAR_FEATURE\n");
+		break;
+	case REQ_SET_FEATURE:
+		DBG("REQ_SET_FEATURE\n");
+
+		if (setup->wValue == FEA_REMOTE_WAKEUP) {
+			/* put DEVICE_REMOTE_WAKEUP code here */
+		}
+
+		if (setup->wValue == FEA_TEST_MODE) {
+			/* put TEST_MODE code here */
+		}
+		ret = false;
+		break;
+
+	case REQ_SET_DESCRIPTOR:
+		DBG("Device req %x not implemented\n", setup->bRequest);
+		ret = false;
+		break;
+
+	default:
+		DBG("Illegal device req %x\n", setup->bRequest);
+		ret = false;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * @brief handle a standard interface request
+ *
+ * @param [in]     setup    The setup packet
+ * @param [in,out] len      Pointer to data length
+ * @param [in]     data_buf Data buffer
+ *
+ * @return true if the request was handled successfully
+ */
+static bool usb_handle_std_interface_req(struct usb_setup_packet *setup,
+		int32_t *len, uint8_t **data_buf)
+{
+	uint8_t *data = *data_buf;
+
+	switch (setup->bRequest) {
+	case REQ_GET_STATUS:
+		/* no bits specified */
+		data[0] = 0;
+		data[1] = 0;
+		*len = 2;
+		break;
+
+	case REQ_CLEAR_FEATURE:
+	case REQ_SET_FEATURE:
+		/* not defined for interface */
+		return false;
+
+	case REQ_GET_INTERFACE:
+		/* there is only one interface, return n-1 (= 0) */
+		data[0] = 0;
+		*len = 1;
+		break;
+
+	case REQ_SET_INTERFACE:
+		DBG("REQ_SET_INTERFACE\n");
+		*len = 0;
+		break;
+
+	default:
+		DBG("Illegal interface req %d\n", setup->bRequest);
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ * @brief handle a standard endpoint request
+ *
+ * @param [in]     setup    The setup packet
+ * @param [in,out] len      Pointer to data length
+ * @param [in]     data_buf Data buffer
+ *
+ * @return true if the request was handled successfully
+ */
+static bool usb_handle_std_endpoint_req(struct usb_setup_packet *setup,
+		int32_t *len, uint8_t **data_buf)
+{
+	uint8_t *data = *data_buf;
+
+	switch (setup->bRequest) {
+	case REQ_GET_STATUS:
+		/* bit 0 = endpointed halted or not */
+		usb_dc_ep_is_stalled(setup->wIndex, &data[0]);
+		data[1] = 0;
+		*len = 2;
+		break;
+
+	case REQ_CLEAR_FEATURE:
+		if (setup->wValue == FEA_ENDPOINT_HALT) {
+			/* clear HALT by unstalling */
+			usb_dc_ep_clear_stall(setup->wIndex);
+			break;
+		}
+		/* only ENDPOINT_HALT defined for endpoints */
+		return false;
+
+	case REQ_SET_FEATURE:
+		if (setup->wValue == FEA_ENDPOINT_HALT) {
+			/* set HALT by stalling */
+			usb_dc_ep_set_stall(setup->wIndex);
+			break;
+		}
+		/* only ENDPOINT_HALT defined for endpoints */
+		return false;
+
+	case REQ_SYNCH_FRAME:
+		DBG("EP req %d not implemented\n", setup->bRequest);
+		return false;
+
+	default:
+		DBG("Illegal EP req %d\n", setup->bRequest);
+		return false;
+	}
+
+	return true;
+}
+
+
+/*
+ * @brief default handler for standard ('chapter 9') requests
+ *
+ * If a custom request handler was installed, this handler is called first.
+ *
+ * @param [in]     setup    The setup packet
+ * @param [in,out] len      Pointer to data length
+ * @param [in]     data_buf Data buffer
+ *
+ * @return true if the request was handled successfully
+ */
+static int usb_handle_standard_request(struct usb_setup_packet *setup,
+		int32_t *len, uint8_t **data_buf)
+{
+	int rc = 0;
+	/* try the custom request handler first */
+	if ((usb_dev.custom_req_handler != NULL) &&
+		(!usb_dev.custom_req_handler(setup, len, data_buf)))
+		return 0;
+
+	switch (REQTYPE_GET_RECIP(setup->bmRequestType)) {
+	case REQTYPE_RECIP_DEVICE:
+		if (usb_handle_std_device_req(setup, len, data_buf) == false)
+			rc = -EINVAL;
+		break;
+	case REQTYPE_RECIP_INTERFACE:
+		if (usb_handle_std_interface_req(setup, len, data_buf) == false)
+			rc = -EINVAL;
+		break;
+	case REQTYPE_RECIP_ENDPOINT:
+		if (usb_handle_std_endpoint_req(setup, len, data_buf) == false)
+			rc = -EINVAL;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+
+/*
+ * @brief Registers a callback for custom device requests
+ *
+ * In usb_register_custom_req_handler, the custom request handler gets a first
+ * chance at handling the request before it is handed over to the 'chapter 9'
+ * request handler.
+ *
+ * This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
+ * request is sent to an interface, which is not covered by the 'chapter 9'
+ * specification.
+ *
+ * @param [in] handler Callback function pointer
+ */
+static void usb_register_custom_req_handler(usb_request_handler handler)
+{
+	usb_dev.custom_req_handler = handler;
+}
+
+/*
+ * @brief register a callback for device status
+ *
+ * This function registers a callback for device status. The registered callback
+ * is used to report changes in the status of the device controller.
+ *
+ * @param [in] cb Callback function pointer
+ */
+static void usb_register_status_callback(usb_status_callback cb)
+{
+	usb_dev.status_callback = cb;
+}
+
+/**
+ * @brief turn on/off USB VBUS voltage
+ *
+ * @param on Set to false to turn off and to true to turn on VBUS
+ *
+ * @return 0 on success, negative errno code on fail
+ */
+static int usb_vbus_set(bool on)
+{
+#if defined(USB_VUSB_EN_GPIO)
+	int ret = 0;
+	struct device *gpio_dev = device_get_binding(USB_GPIO_DRV_NAME);
+
+	if (!gpio_dev) {
+		DBG("USB requires GPIO. Cannot find %s!\n", USB_GPIO_DRV_NAME);
+		return -ENODEV;
+	}
+
+	/* Enable USB IO */
+	ret = gpio_pin_configure(gpio_dev, USB_VUSB_EN_GPIO, GPIO_DIR_OUT);
+	if (ret)
+		return ret;
+
+	ret = gpio_pin_write(gpio_dev, USB_VUSB_EN_GPIO, on == true ? 1 : 0);
+	if (ret)
+		return ret;
+#endif
+
+	return 0;
+}
+
+int usb_set_config(struct usb_cfg_data *config)
+{
+	if (!config)
+		return -EINVAL;
+
+	/* register descriptors */
+	usb_register_descriptors(config->usb_device_description);
+
+	/* register standard request handler */
+	usb_register_request_handler(REQTYPE_TYPE_STANDARD,
+	    &(usb_handle_standard_request), usb_dev.std_req_data);
+
+	/* register class request handlers for each interface*/
+	if (config->interface.class_handler != NULL) {
+		usb_register_request_handler(REQTYPE_TYPE_CLASS,
+		    config->interface.class_handler,
+		    config->interface.payload_data);
+	}
+	/* register class request handlers for each interface*/
+	if (config->interface.custom_handler != NULL) {
+		usb_register_custom_req_handler(
+		    config->interface.custom_handler);
+	}
+
+	/* register status callback */
+	if (config->cb_usb_status != NULL) {
+		usb_register_status_callback(config->cb_usb_status);
+	}
+
+	return 0;
+}
+
+int usb_deconfig(void)
+{
+	/* unregister descriptors */
+	usb_register_descriptors(NULL);
+
+	/* unegister standard request handler */
+	usb_register_request_handler(REQTYPE_TYPE_STANDARD, NULL, NULL);
+
+	/* unregister class request handlers for each interface*/
+	usb_register_request_handler(REQTYPE_TYPE_CLASS, NULL, NULL);
+
+	/* unregister class request handlers for each interface*/
+	usb_register_custom_req_handler(NULL);
+
+	/* unregister status callback */
+	usb_register_status_callback(NULL);
+
+	/* Reset USB controller */
+	usb_dc_reset();
+
+	return 0;
+}
+
+int usb_enable(struct usb_cfg_data *config)
+{
+	int ret;
+	uint32_t i;
+	struct usb_dc_ep_cfg_data ep0_cfg;
+
+	if (true == usb_dev.enabled) {
+		return 0;
+	}
+
+	/* Enable VBUS if needed */
+	ret = usb_vbus_set(true);
+	if (ret < 0)
+		return ret;
+
+	ret = usb_dc_set_status_callback(config->cb_usb_status);
+	if (ret < 0)
+		return ret;
+
+	ret = usb_dc_attach();
+	if (ret < 0)
+		return ret;
+
+	/* Configure control EP */
+	ep0_cfg.ep_mps = MAX_PACKET_SIZE0;
+	ep0_cfg.ep_type = USB_DC_EP_CONTROL;
+
+	ep0_cfg.ep_addr = USB_CONTROL_OUT_EP0;
+	ret = usb_dc_ep_configure(&ep0_cfg);
+	if (ret < 0)
+		return ret;
+
+	ep0_cfg.ep_addr = USB_CONTROL_IN_EP0;
+	ret = usb_dc_ep_configure(&ep0_cfg);
+	if (ret < 0)
+		return ret;
+
+	/*register endpoint 0 handlers*/
+	ret = usb_dc_ep_set_callback(USB_CONTROL_OUT_EP0,
+	    usb_handle_control_transfer);
+	if (ret < 0)
+		return ret;
+	ret = usb_dc_ep_set_callback(USB_CONTROL_IN_EP0,
+	    usb_handle_control_transfer);
+	if (ret < 0)
+		return ret;
+
+	/*register endpoint handlers*/
+	for (i = 0; i < config->num_endpoints; i++) {
+		ret = usb_dc_ep_set_callback(config->endpoint[i].ep_addr,
+		    config->endpoint[i].ep_cb);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* enable control EP */
+	ret = usb_dc_ep_enable(USB_CONTROL_OUT_EP0);
+	if (ret < 0)
+		return ret;
+
+	ret = usb_dc_ep_enable(USB_CONTROL_IN_EP0);
+	if (ret < 0)
+		return ret;
+
+	usb_dev.enabled = true;
+
+	return 0;
+}
+
+int usb_disable(void)
+{
+	int ret;
+
+	if (true != usb_dev.enabled) {
+		/*Already disabled*/
+		return 0;
+	}
+
+	ret = usb_dc_detach();
+	if (ret < 0)
+		return ret;
+
+	/* Disable VBUS if needed */
+	usb_vbus_set(false);
+
+	usb_dev.enabled = false;
+
+	return 0;
+}
+
+int usb_write(uint8_t ep, const uint8_t *data, uint32_t data_len,
+		uint32_t *bytes_ret)
+{
+	return usb_dc_ep_write(ep, data, data_len, bytes_ret);
+}
+
+int usb_read(uint8_t ep, uint8_t *data, uint32_t max_data_len,
+		uint32_t *ret_bytes)
+{
+	return usb_dc_ep_read(ep, data, max_data_len, ret_bytes);
+}