blob: 7e33e53d58e4bceac161b366008993e7b4518b82 [file] [log] [blame]
/*
* Copyright (c) 2016-2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Sample app for WebUSB enabled custom class driver.
*
* Sample app for WebUSB enabled custom class driver. The received
* data is echoed back to the WebUSB based application running in
* the browser at host.
*/
#define LOG_LEVEL CONFIG_USB_DEVICE_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main);
#include <zephyr/sys/byteorder.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/usb/bos.h>
#include "webusb.h"
/* Predefined response to control commands related to MS OS 2.0 descriptors */
static const uint8_t msos2_descriptor[] = {
/* MS OS 2.0 set header descriptor */
0x0A, 0x00, /* Descriptor size (10 bytes) */
0x00, 0x00, /* MS_OS_20_SET_HEADER_DESCRIPTOR */
0x00, 0x00, 0x03, 0x06, /* Windows version (8.1) (0x06030000) */
(0x0A + 0x14 + 0x08), 0x00, /* Length of the MS OS 2.0 descriptor set */
/* MS OS 2.0 function subset ID descriptor
* This means that the descriptors below will only apply to one
* set of interfaces
*/
0x08, 0x00, /* Descriptor size (8 bytes) */
0x02, 0x00, /* MS_OS_20_SUBSET_HEADER_FUNCTION */
0x02, /* Index of first interface this subset applies to. */
0x00, /* reserved */
(0x08 + 0x14), 0x00, /* Length of the MS OS 2.0 descriptor subset */
/* MS OS 2.0 compatible ID descriptor */
0x14, 0x00, /* Descriptor size */
0x03, 0x00, /* MS_OS_20_FEATURE_COMPATIBLE_ID */
/* 8-byte compatible ID string, then 8-byte sub-compatible ID string */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_webusb_desc {
struct usb_bos_platform_descriptor platform;
struct usb_bos_capability_webusb cap;
} __packed bos_cap_webusb = {
/* WebUSB Platform Capability Descriptor:
* https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
*/
.platform = {
.bLength = sizeof(struct usb_bos_platform_descriptor)
+ sizeof(struct usb_bos_capability_webusb),
.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM,
.bReserved = 0,
/* WebUSB Platform Capability UUID
* 3408b638-09a9-47a0-8bfd-a0768815b665
*/
.PlatformCapabilityUUID = {
0x38, 0xB6, 0x08, 0x34,
0xA9, 0x09,
0xA0, 0x47,
0x8B, 0xFD,
0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65,
},
},
.cap = {
.bcdVersion = sys_cpu_to_le16(0x0100),
.bVendorCode = 0x01,
.iLandingPage = 0x01
}
};
USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_msosv2_desc {
struct usb_bos_platform_descriptor platform;
struct usb_bos_capability_msos cap;
} __packed bos_cap_msosv2 = {
/* Microsoft OS 2.0 Platform Capability Descriptor
* See https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/
* microsoft-defined-usb-descriptors
* Adapted from the source:
* https://github.com/sowbug/weblight/blob/master/firmware/webusb.c
* (BSD-2) Thanks http://janaxelson.com/files/ms_os_20_descriptors.c
*/
.platform = {
.bLength = sizeof(struct usb_bos_platform_descriptor)
+ sizeof(struct usb_bos_capability_msos),
.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_BOS_CAPABILITY_PLATFORM,
.bReserved = 0,
.PlatformCapabilityUUID = {
/**
* MS OS 2.0 Platform Capability ID
* D8DD60DF-4589-4CC7-9CD2-659D9E648A9F
*/
0xDF, 0x60, 0xDD, 0xD8,
0x89, 0x45,
0xC7, 0x4C,
0x9C, 0xD2,
0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,
},
},
.cap = {
/* Windows version (8.1) (0x06030000) */
.dwWindowsVersion = sys_cpu_to_le32(0x06030000),
.wMSOSDescriptorSetTotalLength =
sys_cpu_to_le16(sizeof(msos2_descriptor)),
.bMS_VendorCode = 0x02,
.bAltEnumCode = 0x00
},
};
USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_capability_lpm bos_cap_lpm = {
.bLength = sizeof(struct usb_bos_capability_lpm),
.bDescriptorType = USB_DESC_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_BOS_CAPABILITY_EXTENSION,
/**
* BIT(1) - LPM support
* BIT(2) - BESL support
*/
.bmAttributes = BIT(1) | BIT(2),
};
/* WebUSB Device Requests */
static const uint8_t webusb_allowed_origins[] = {
/* Allowed Origins Header:
* https://wicg.github.io/webusb/#get-allowed-origins
*/
0x05, 0x00, 0x0D, 0x00, 0x01,
/* Configuration Subset Header:
* https://wicg.github.io/webusb/#configuration-subset-header
*/
0x04, 0x01, 0x01, 0x01,
/* Function Subset Header:
* https://wicg.github.io/webusb/#function-subset-header
*/
0x04, 0x02, 0x02, 0x01
};
/* Number of allowed origins */
#define NUMBER_OF_ALLOWED_ORIGINS 1
/* URL Descriptor: https://wicg.github.io/webusb/#url-descriptor */
static const uint8_t webusb_origin_url[] = {
/* Length, DescriptorType, Scheme */
0x11, 0x03, 0x00,
'l', 'o', 'c', 'a', 'l', 'h', 'o', 's', 't', ':', '8', '0', '0', '0'
};
/* Predefined response to control commands related to MS OS 1.0 descriptors
* Please note that this code only defines "extended compat ID OS feature
* descriptors" and not "extended properties OS features descriptors"
*/
#define MSOS_STRING_LENGTH 18
static struct string_desc {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bString[MSOS_STRING_LENGTH];
} __packed msos1_string_descriptor = {
.bLength = MSOS_STRING_LENGTH,
.bDescriptorType = USB_DESC_STRING,
/* Signature MSFT100 */
.bString = {
'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00,
'1', 0x00, '0', 0x00, '0', 0x00,
0x03, /* Vendor Code, used for a control request */
0x00, /* Padding byte for VendorCode looks like UTF16 */
},
};
static const uint8_t msos1_compatid_descriptor[] = {
/* See https://github.com/pbatard/libwdi/wiki/WCID-Devices */
/* MS OS 1.0 header section */
0x28, 0x00, 0x00, 0x00, /* Descriptor size (40 bytes) */
0x00, 0x01, /* Version 1.00 */
0x04, 0x00, /* Type: Extended compat ID descriptor */
0x01, /* Number of function sections */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reserved */
/* MS OS 1.0 function section */
0x02, /* Index of interface this section applies to. */
0x01, /* reserved */
/* 8-byte compatible ID string, then 8-byte sub-compatible ID string */
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* reserved */
};
/**
* @brief Custom handler for standard requests in
* order to catch the request and return the
* WebUSB Platform Capability Descriptor.
*
* @param pSetup Information about the request to execute.
* @param len Size of the buffer.
* @param data Buffer containing the request result.
*
* @return 0 on success, negative errno code on fail
*/
int custom_handle_req(struct usb_setup_packet *pSetup,
int32_t *len, uint8_t **data)
{
if (usb_reqtype_is_to_device(pSetup)) {
return -ENOTSUP;
}
if (USB_GET_DESCRIPTOR_TYPE(pSetup->wValue) == USB_DESC_STRING &&
USB_GET_DESCRIPTOR_INDEX(pSetup->wValue) == 0xEE) {
*data = (uint8_t *)(&msos1_string_descriptor);
*len = sizeof(msos1_string_descriptor);
LOG_DBG("Get MS OS Descriptor v1 string");
return 0;
}
return -EINVAL;
}
/**
* @brief Handler called for vendor specific commands. This includes
* WebUSB allowed origins and MS OS 1.0 and 2.0 descriptors.
*
* @param pSetup Information about the request to execute.
* @param len Size of the buffer.
* @param data Buffer containing the request result.
*
* @return 0 on success, negative errno code on fail.
*/
int vendor_handle_req(struct usb_setup_packet *pSetup,
int32_t *len, uint8_t **data)
{
if (usb_reqtype_is_to_device(pSetup)) {
return -ENOTSUP;
}
/* Get Allowed origins request */
if (pSetup->bRequest == 0x01 && pSetup->wIndex == 0x01) {
*data = (uint8_t *)(&webusb_allowed_origins);
*len = sizeof(webusb_allowed_origins);
LOG_DBG("Get webusb_allowed_origins");
return 0;
} else if (pSetup->bRequest == 0x01 && pSetup->wIndex == 0x02) {
/* Get URL request */
uint8_t index = USB_GET_DESCRIPTOR_INDEX(pSetup->wValue);
if (index == 0U || index > NUMBER_OF_ALLOWED_ORIGINS) {
return -ENOTSUP;
}
*data = (uint8_t *)(&webusb_origin_url);
*len = sizeof(webusb_origin_url);
LOG_DBG("Get webusb_origin_url");
return 0;
} else if (pSetup->bRequest == 0x02 && pSetup->wIndex == 0x07) {
/* Get MS OS 2.0 Descriptors request */
/* 0x07 means "MS_OS_20_DESCRIPTOR_INDEX" */
*data = (uint8_t *)(&msos2_descriptor);
*len = sizeof(msos2_descriptor);
LOG_DBG("Get MS OS Descriptors v2");
return 0;
} else if (pSetup->bRequest == 0x03 && pSetup->wIndex == 0x04) {
/* Get MS OS 1.0 Descriptors request */
/* 0x04 means "Extended compat ID".
* Use 0x05 instead for "Extended properties".
*/
*data = (uint8_t *)(&msos1_compatid_descriptor);
*len = sizeof(msos1_compatid_descriptor);
LOG_DBG("Get MS OS Descriptors CompatibleID");
return 0;
}
return -ENOTSUP;
}
/* Custom and Vendor request handlers */
static struct webusb_req_handlers req_handlers = {
.custom_handler = custom_handle_req,
.vendor_handler = vendor_handle_req,
};
void main(void)
{
int ret;
LOG_DBG("");
usb_bos_register_cap((void *)&bos_cap_webusb);
usb_bos_register_cap((void *)&bos_cap_msosv2);
usb_bos_register_cap((void *)&bos_cap_lpm);
/* Set the custom and vendor request handlers */
webusb_register_request_handlers(&req_handlers);
ret = usb_enable(NULL);
if (ret != 0) {
LOG_ERR("Failed to enable USB");
return;
}
}