Linux Audio

Check our new training course

Loading...
/*
 * Copyright (c) 2018 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <ztest.h>
#include <tc_util.h>

#include <sys/byteorder.h>
#include <usb/usb_device.h>
#include <usb/usb_common.h>

#include <usb/bos.h>

/* Helpers */
static void hexdump(const u8_t *data, size_t len)
{
	int n = 0;

	while (len--) {
		if (n % 16 == 0) {
			printk("%08X ", n);
		}

		printk("%02X ", *data++);

		n++;
		if (n % 8 == 0) {
			if (n % 16 == 0) {
				printk("\n");
			} else {
				printk(" ");
			}
		}
	}

	if (n % 16) {
		printk("\n");
	}
}

/*
 * Compare old style USB BOS definition with section aligned
 */

static const u8_t dummy_descriptor[] = {
	0x00, 0x01, 0x02
};

static struct webusb_bos_desc {
	struct usb_bos_descriptor bos;
	struct usb_bos_platform_descriptor platform_webusb;
	struct usb_bos_capability_webusb capability_data_webusb;
	struct usb_bos_platform_descriptor platform_msos;
	struct usb_bos_capability_msos capability_data_msos;
} __packed webusb_bos_descriptor = {
	.bos = {
		.bLength = sizeof(struct usb_bos_descriptor),
		.bDescriptorType = USB_BINARY_OBJECT_STORE_DESC,
		.wTotalLength = sizeof(struct webusb_bos_desc),
		.bNumDeviceCaps = 2,
	},
	/* WebUSB Platform Capability Descriptor:
	 * https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
	 */
	.platform_webusb = {
		.bLength = sizeof(struct usb_bos_platform_descriptor)
			+ sizeof(struct usb_bos_capability_webusb),
		.bDescriptorType = USB_DEVICE_CAPABILITY_DESC,
		.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,
		},
	},
	.capability_data_webusb = {
		.bcdVersion = sys_cpu_to_le16(0x0100),
		.bVendorCode = 0x01,
		.iLandingPage = 0x01
	},
	/* 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_msos = {
		.bLength = sizeof(struct usb_bos_platform_descriptor)
			+ sizeof(struct usb_bos_capability_msos),
		.bDescriptorType = USB_DEVICE_CAPABILITY_DESC,
		.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,
		},
	},
	.capability_data_msos = {
		/* Windows version (8.1) (0x06030000) */
		.dwWindowsVersion = sys_cpu_to_le32(0x06030000),
		.wMSOSDescriptorSetTotalLength =
			sys_cpu_to_le16(sizeof(dummy_descriptor)),
		.bMS_VendorCode = 0x02,
		.bAltEnumCode = 0x00
	}
};

/* In a case linker places data in a different order */
static struct webusb_bos_desc_2 {
	struct usb_bos_descriptor bos;
	struct usb_bos_platform_descriptor platform_msos;
	struct usb_bos_capability_msos capability_data_msos;
	struct usb_bos_platform_descriptor platform_webusb;
	struct usb_bos_capability_webusb capability_data_webusb;
} __packed webusb_bos_descriptor_2;

USB_DEVICE_BOS_DESC_DEFINE_CAP struct usb_bos_webusb {
	struct usb_bos_platform_descriptor platform;
	struct usb_bos_capability_webusb cap;
} __packed cap_webusb = {
	.platform = {
		.bLength = sizeof(struct usb_bos_platform_descriptor) +
			sizeof(struct usb_bos_capability_webusb),
		.bDescriptorType = USB_DEVICE_CAPABILITY_DESC,
		.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 {
	struct usb_bos_platform_descriptor platform;
	struct usb_bos_capability_msos cap;
} __packed cap_msosv2 = {
	.platform = {
		.bLength = sizeof(struct usb_bos_platform_descriptor)
			+ sizeof(struct usb_bos_capability_msos),
		.bDescriptorType = USB_DEVICE_CAPABILITY_DESC,
		.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(dummy_descriptor)),
		.bMS_VendorCode = 0x02,
		.bAltEnumCode = 0x00,
	},
};

static void test_usb_bos_macros(void)
{
	const struct usb_bos_descriptor *hdr = usb_bos_get_header();
	size_t len = usb_bos_get_length();

	TC_PRINT("length %zu\n", len);

	usb_bos_register_cap((void *)&cap_webusb);
	usb_bos_register_cap((void *)&cap_msosv2);

	/* usb_bos_fix_total_length(); corrected with register */

	hexdump((void *)hdr, len);
	hexdump((void *)&webusb_bos_descriptor, len);
	hexdump((void *)&webusb_bos_descriptor_2, len);

	zassert_true(len ==
		     sizeof(struct usb_bos_descriptor) +
		     sizeof(cap_webusb) +
		     sizeof(cap_msosv2),
		     "Incorrect calculated length");
	zassert_true(!memcmp(hdr, &webusb_bos_descriptor, len) ||
		     !memcmp(hdr, &webusb_bos_descriptor_2, len),
		     "Wrong data");
}

static void test_usb_bos(void)
{
	struct usb_setup_packet setup;
	s32_t len = 0;
	u8_t *data = NULL;
	int ret;

	/* Already registered due to previous test */

	setup.wValue = (DESCRIPTOR_TYPE_BOS & 0xFF) << 8;

	ret = usb_handle_bos(&setup, &len, &data);

	TC_PRINT("%s: ret %d len %u data %p\n", __func__, ret, len, data);

	zassert_true(!ret, "Return code failed");
	zassert_equal(len, sizeof(webusb_bos_descriptor), "Wrong length");
	zassert_true(!memcmp(data, &webusb_bos_descriptor, len) ||
		     !memcmp(data, &webusb_bos_descriptor_2, len),
		     "Wrong data");
}

/*test case main entry*/
void test_main(void)
{
	/* Prepare webusb_bos_descriptor_2 */
	memcpy(&webusb_bos_descriptor_2.bos,
	       &webusb_bos_descriptor.bos,
	       sizeof(struct usb_bos_descriptor));

	memcpy(&webusb_bos_descriptor_2.platform_msos,
	       &webusb_bos_descriptor.platform_msos,
	       sizeof(struct usb_bos_platform_descriptor));
	memcpy(&webusb_bos_descriptor_2.capability_data_msos,
	       &webusb_bos_descriptor.capability_data_msos,
	       sizeof(struct usb_bos_capability_msos));

	memcpy(&webusb_bos_descriptor_2.platform_webusb,
	       &webusb_bos_descriptor.platform_webusb,
	       sizeof(struct usb_bos_platform_descriptor));
	memcpy(&webusb_bos_descriptor_2.capability_data_webusb,
	       &webusb_bos_descriptor.capability_data_webusb,
	       sizeof(struct usb_bos_capability_webusb));

	ztest_test_suite(test_osdesc,
			 ztest_unit_test(test_usb_bos_macros),
			 ztest_unit_test(test_usb_bos));
	ztest_run_test_suite(test_osdesc);
}