usb: bos: Add USB BOS descriptors API

Add API for USB BOS Descriptors.

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
diff --git a/include/usb/bos.h b/include/usb/bos.h
new file mode 100644
index 0000000..bd29617
--- /dev/null
+++ b/include/usb/bos.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#if defined(CONFIG_USB_DEVICE_BOS)
+#define USB_DEVICE_BOS_DESC_DEFINE_HDR \
+	static __in_section(usb, bos_desc_area, 0) __used
+#define USB_DEVICE_BOS_DESC_DEFINE_CAP \
+	static __in_section(usb, bos_desc_area, 1) __used
+
+/* BOS descriptor type */
+#define DESCRIPTOR_TYPE_BOS		0x0F
+
+#define USB_BOS_CAPABILITY_PLATFORM	0x05
+
+/* BOS Capability Descriptor */
+struct usb_bos_platform_descriptor {
+	u8_t bLength;
+	u8_t bDescriptorType;
+	u8_t bDevCapabilityType;
+	u8_t bReserved;
+	u8_t PlatformCapabilityUUID[16];
+} __packed;
+
+/* BOS Descriptor */
+struct usb_bos_descriptor {
+	u8_t bLength;
+	u8_t bDescriptorType;
+	u16_t wTotalLength;
+	u8_t bNumDeviceCaps;
+} __packed;
+
+/* BOS Capability webusb */
+struct usb_bos_capability_webusb {
+	u16_t bcdVersion;
+	u8_t bVendorCode;
+	u8_t iLandingPage;
+} __packed;
+
+/* BOS Capability MS OS Descriptors version 2 */
+struct usb_bos_capability_msos {
+	u32_t dwWindowsVersion;
+	u16_t wMSOSDescriptorSetTotalLength;
+	u8_t bMS_VendorCode;
+	u8_t bAltEnumCode;
+} __packed;
+
+size_t usb_bos_get_length(void);
+void usb_bos_fix_total_length(void);
+void usb_bos_register_cap(struct usb_bos_platform_descriptor *hdr);
+const void *usb_bos_get_header(void);
+int usb_handle_bos(struct usb_setup_packet *setup, s32_t *len, u8_t **data);
+#else
+#define usb_handle_bos(x, y, z)		-ENOTSUP
+#endif
diff --git a/include/usb/usb_common.h b/include/usb/usb_common.h
index de9f58f..8e80444 100644
--- a/include/usb/usb_common.h
+++ b/include/usb/usb_common.h
@@ -198,25 +198,4 @@
 	u8_t bInterval;
 } __packed;
 
-/** Binary Device Object Store (BOS) */
-
-#define USB_BOS_CAPABILITY_PLATFORM	0x05
-
-/** BOS Capability Descriptor */
-struct usb_bos_platform_descriptor {
-	u8_t bLength;
-	u8_t bDescriptorType;
-	u8_t bDevCapabilityType;
-	u8_t bReserved;
-	u8_t PlatformCapabilityUUID[16];
-} __packed;
-
-/** BOS Descriptor */
-struct usb_bos_descriptor {
-	u8_t bLength;
-	u8_t bDescriptorType;
-	u16_t wTotalLength;
-	u8_t bNumDeviceCaps;
-} __packed;
-
 #endif /* USB_COMMON_H_ */
diff --git a/subsys/usb/CMakeLists.txt b/subsys/usb/CMakeLists.txt
index b9227fe..05d5eb3 100644
--- a/subsys/usb/CMakeLists.txt
+++ b/subsys/usb/CMakeLists.txt
@@ -7,6 +7,12 @@
   add_subdirectory(class)
 endif()
 
+if(CONFIG_USB_DEVICE_BOS)
+  zephyr_sources(
+    bos.c
+    )
+endif()
+
 if(CONFIG_USB_DEVICE_VID EQUAL 0x2FE3)
   message(WARNING
     "CONFIG_USB_DEVICE_VID has default value 0x2FE3.
diff --git a/subsys/usb/Kconfig b/subsys/usb/Kconfig
index d5baa25..b293635 100644
--- a/subsys/usb/Kconfig
+++ b/subsys/usb/Kconfig
@@ -86,6 +86,11 @@
 	default 64
 	default 256 if USB_DEVICE_NETWORK_RNDIS
 
+config USB_DEVICE_BOS
+	bool
+	prompt "Enable USB Binary Device Object Store (BOS)"
+	default n
+
 source "subsys/usb/class/Kconfig"
 
 endif # USB_DEVICE_STACK
diff --git a/subsys/usb/bos.c b/subsys/usb/bos.c
new file mode 100644
index 0000000..5403b21
--- /dev/null
+++ b/subsys/usb/bos.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#define SYS_LOG_LEVEL CONFIG_SYS_LOG_USB_DEVICE_LEVEL
+#define SYS_LOG_DOMAIN "usb/bos"
+#include <logging/sys_log.h>
+
+#include <zephyr.h>
+
+#include <usb/usb_device.h>
+#include <usb/usb_common.h>
+
+#include <usb/bos.h>
+
+extern const u8_t __usb_bos_desc_start[];
+extern const u8_t __usb_bos_desc_end[];
+
+USB_DEVICE_BOS_DESC_DEFINE_HDR struct usb_bos_descriptor hdr = {
+	.bLength = sizeof(struct usb_bos_descriptor),
+	.bDescriptorType = USB_BINARY_OBJECT_STORE_DESC,
+	.wTotalLength = 0, /* should be corrected with register */
+	.bNumDeviceCaps = 0, /* should be set with register */
+};
+
+size_t usb_bos_get_length(void)
+{
+	return __usb_bos_desc_end - __usb_bos_desc_start;
+}
+
+const void *usb_bos_get_header(void)
+{
+	return __usb_bos_desc_start;
+}
+
+void usb_bos_fix_total_length(void)
+{
+	struct usb_bos_descriptor *hdr = (void *)__usb_bos_desc_start;
+
+	hdr->wTotalLength = usb_bos_get_length();
+}
+
+void usb_bos_register_cap(struct usb_bos_platform_descriptor *desc)
+{
+	struct usb_bos_descriptor *hdr = (void *)__usb_bos_desc_start;
+
+	/* Has effect only on first register */
+	hdr->wTotalLength = usb_bos_get_length();
+
+	hdr->bNumDeviceCaps += 1;
+}
+
+int usb_handle_bos(struct usb_setup_packet *setup,
+		   s32_t *len, u8_t **data)
+{
+	SYS_LOG_DBG("wValue 0x%x", setup->wValue);
+
+	if (GET_DESC_TYPE(setup->wValue) == DESCRIPTOR_TYPE_BOS) {
+		*data = (u8_t *)usb_bos_get_header();
+		*len = usb_bos_get_length();
+
+		return 0;
+	}
+
+	return -ENOTSUP;
+}
diff --git a/subsys/usb/usb_device.c b/subsys/usb/usb_device.c
index 33def4a..3196f05 100644
--- a/subsys/usb/usb_device.c
+++ b/subsys/usb/usb_device.c
@@ -74,6 +74,8 @@
 #define SYS_LOG_NO_NEWLINE
 #include <logging/sys_log.h>
 
+#include <usb/bos.h>
+
 #define MAX_DESC_HANDLERS           4 /** Device, interface, endpoint, other */
 
 /* general descriptor field offsets */
@@ -782,6 +784,10 @@
 {
 	int rc = 0;
 
+	if (!usb_handle_bos(setup, len, data_buf)) {
+		return 0;
+	}
+
 	/* try the custom request handler first */
 	if (usb_dev.custom_req_handler &&
 	    !usb_dev.custom_req_handler(setup, len, data_buf)) {