Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial BOS/WebUSB/WinUSB support #91

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Demos/Device/LowLevel/BulkVendor/BulkVendor.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,5 @@ void EVENT_USB_Device_ConfigurationChanged(void)
void EVENT_USB_Device_ControlRequest(void)
{
// Process vendor specific control requests here
USB_Process_BOS();
}
86 changes: 86 additions & 0 deletions Demos/Device/LowLevel/BulkVendor/Descriptors.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,37 @@

#include "Descriptors.h"

#define WEBUSB_ID 0x01
#define MS_OS_ID 0x02

const uint8_t PROGMEM MS_OS_Descriptor[] =
{
MS_OS_DESCRIPTOR_SET(
MS_OS_CONFIG_SUBSET_HEADER(0x00, // Config 0
MS_OS_FUNCTION_SUBSET_HEADER(INTERFACE_ID_Vendor, // Interface ID
MS_OS_COMPAT_ID_WINUSB
)
)
)
};

const uint8_t PROGMEM WebUSBAllowedOrigins[] = {
WEBUSB_ALLOWED_ORIGINS_HEADER(1, // 1 config header present
WEBUSB_CONFIG_SUBSET_HEADER(0x00, 1, // Config 0, 1 function header
// Config interface accessible from the web, 2 valid URLs
WEBUSB_FUNCTION_SUBSET_HEADER(INTERFACE_ID_Vendor, URL_ID_Config, URL_ID_Localhost)
)
)
};

const uint8_t PROGMEM BOSDescriptor[] =
{
BOS_DESCRIPTOR(2, // 2 capability descriptors in use
WEBUSB_CAPABILITY_DESCRIPTOR(WEBUSB_ID, URL_ID_Config), // Vendor request ID, URL ID to take the user to
// Required to force WinUSB driver for driverless WebUSB compatibility
MS_OS_20_CAPABILITY_DESCRIPTOR(MS_OS_ID, sizeof(MS_OS_Descriptor)) // Vendor request ID, Descriptor set length
)
};

/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall
* device characteristics, including the supported USB version, control endpoint size and the
Expand Down Expand Up @@ -65,6 +96,57 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
.NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS
};

const USB_Descriptor_URL_t PROGMEM ConfigURL = URL_STRING_DESCRIPTOR(URL_HTTP, "www.fourwalledcubicle.com/LUFA.php");
const USB_Descriptor_URL_t PROGMEM LocalhostURL = URL_STRING_DESCRIPTOR(URL_HTTP, "localhost");

void USB_Process_BOS(void) {
const void* Address = NULL;
uint16_t Size = 0;

if(!(Endpoint_IsSETUPReceived()) ||
USB_ControlRequest.bmRequestType != (REQDIR_DEVICETOHOST | REQTYPE_VENDOR | REQREC_DEVICE)) {
return;
}
switch(USB_ControlRequest.bRequest) {
case WEBUSB_ID:
switch(USB_ControlRequest.wIndex) {
case WEBUSB_REQUEST_GET_ALLOWED_ORIGINS:
Address = &WebUSBAllowedOrigins;
Size = sizeof(WebUSBAllowedOrigins);
break;
case WEBUSB_REQUEST_GET_URL:
switch(USB_ControlRequest.wValue) {
case URL_ID_Localhost:
Address = &LocalhostURL;
Size = pgm_read_byte(&LocalhostURL.Header.Size);
break;
case URL_ID_Config:
Address = &ConfigURL;
Size = pgm_read_byte(&ConfigURL.Header.Size);
break;
}
break;
}
break;
case MS_OS_ID:
if(USB_ControlRequest.wIndex == MS_OS_20_DESCRIPTOR_INDEX) {
Address = &MS_OS_Descriptor;
Size = sizeof(MS_OS_Descriptor);
}
break;
default:
return;
}
if(Address != NULL) {
Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);

Endpoint_ClearSETUP();

Endpoint_Write_Control_PStream_LE(Address, Size);
Endpoint_ClearOUT();
}
}

/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage
* of the device in one of its supported configurations, including information about any device interfaces
* and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting
Expand Down Expand Up @@ -168,6 +250,10 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
Address = &ConfigurationDescriptor;
Size = sizeof(USB_Descriptor_Configuration_t);
break;
case DTYPE_BOS:
Address = &BOSDescriptor;
Size = sizeof(BOSDescriptor);
break;
case DTYPE_String:
switch (DescriptorNumber)
{
Expand Down
8 changes: 8 additions & 0 deletions Demos/Device/LowLevel/BulkVendor/Descriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,19 @@
STRING_ID_Product = 2, /**< Product string ID */
};

enum URLDescriptors_t
{
URL_ID_Localhost = 1,
URL_ID_Config = 2,
};

/* Function Prototypes: */
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
const uint16_t wIndex,
const void** const DescriptorAddress)
ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3);

void USB_Process_BOS(void);

#endif

174 changes: 174 additions & 0 deletions LUFA/Drivers/USB/Core/StdDescriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,127 @@
*/
#define ENDPOINT_USAGE_IMPLICIT_FEEDBACK (2 << 4)
//@}

/* Binary Object Store (BOS) macros: */

#define UUID(...) __VA_ARGS__

#define _BOS_ENCODE_16(Data) ((Data) & 0xFF), (((Data) >> 8) & 0xFF)

#define BOS_DESCRIPTOR(NumberOfCapabilityDescriptors, ...) \
5, /* Size of the BOS header */ \
DTYPE_BOS, \
_BOS_ENCODE_16(sizeof((uint8_t[]){__VA_ARGS__}) + 5),\
NumberOfCapabilityDescriptors, \
__VA_ARGS__

#define BOS_CAPABILITY_DESCRIPTOR(CapabilityType, ...) \
sizeof((uint8_t[]){__VA_ARGS__}) + 3, /* Descriptor size */ \
DTYPE_DeviceCapability, /* Descriptor type */ \
(CapabilityType), /* Capability type */ \
__VA_ARGS__ /* Capability dependant */

#define BOS_CAPABILITY_PLATFORM_DESCRIPTOR(CapabilityUUID, ...) \
BOS_CAPABILITY_DESCRIPTOR( \
USB_Capability_Platform, /* Capability type */ \
0, /* Reserved */ \
CapabilityUUID, /* Platform specific UUID */ \
__VA_ARGS__ /* Capability data */ \
)

/* MS OS 2.0 macros: */

#define MS_OS_20_DESCRIPTOR_INDEX 0x07
#define MS_OS_20_SET_ALT_ENUMERATION 0x08

/* Windows version (8.1), minimum allowed for MS OS 2.0 */
#define WINVER_81 0x00, 0x00, 0x03, 0x06

#define _COMPAT_ID(...) __VA_ARGS__

#define MS_OS_20_CAPABILITY_DESCRIPTOR(MSRequestCode, DescriptorSetLength) \
BOS_CAPABILITY_PLATFORM_DESCRIPTOR( \
/* MS OS 2.0 UUID */ \
UUID(0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F), \
/* These 4 values can be repeated for different versions */ \
WINVER_81, /* version */ \
_BOS_ENCODE_16(DescriptorSetLength), \
MSRequestCode, \
0x00 /* Alternate enumeration code - not supported */ \
)

#define MS_OS_DESCRIPTOR_SET(...) \
_BOS_ENCODE_16(10), /* header size */ \
_BOS_ENCODE_16(MS_OS_20_SET_HEADER_DESCRIPTOR), /* type */ \
WINVER_81, /* version */ \
_BOS_ENCODE_16(sizeof((uint8_t[]){__VA_ARGS__}) + 10), /* Total length */ \
__VA_ARGS__

#define MS_OS_CONFIG_SUBSET_HEADER(ConfigValue, ...) \
_BOS_ENCODE_16(8), /* header size */ \
_BOS_ENCODE_16(MS_OS_20_SUBSET_HEADER_CONFIGURATION ), /* type */ \
ConfigValue, /* Configuration value to which this subset applies */ \
0x00, /* Reserved */ \
_BOS_ENCODE_16(sizeof((uint8_t[]){__VA_ARGS__}) + 8), /* Total length */ \
__VA_ARGS__

#define MS_OS_FUNCTION_SUBSET_HEADER(InterfaceNum, ...) \
_BOS_ENCODE_16(8), /* header size */ \
_BOS_ENCODE_16(MS_OS_20_SUBSET_HEADER_FUNCTION), /* type */ \
InterfaceNum, /* first interface to which this subset applies */ \
0x00, /* Reserved */ \
_BOS_ENCODE_16(sizeof((uint8_t[]){__VA_ARGS__}) + 8), /* Total length */ \
__VA_ARGS__

#define MS_OS_COMPATIBLE_ID_DESCRIPTOR(CompatibleID, SubCompatibleID) \
_BOS_ENCODE_16(20), /* descriptor size */ \
_BOS_ENCODE_16(MS_OS_20_FEATURE_COMPATIBLE_ID), /* type */ \
CompatibleID, \
SubCompatibleID

#define MS_OS_COMPAT_ID_WINUSB \
MS_OS_COMPATIBLE_ID_DESCRIPTOR( \
_COMPAT_ID('W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00), \
_COMPAT_ID(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) \
)

/* WebUSB Macros: */

#define WEBUSB_REQUEST_GET_ALLOWED_ORIGINS 0x01
#define WEBUSB_REQUEST_GET_URL 0x02

#define WEBUSB_CAPABILITY_DESCRIPTOR(WebUSBRequestCode, LandingPageURLIndex) \
BOS_CAPABILITY_PLATFORM_DESCRIPTOR( \
/* WebUSB UUID */ \
UUID(0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65), \
0x00, 0x01, /* Protocol version. Must be 0x0100 */ \
WebUSBRequestCode, LandingPageURLIndex \
)


#define WEBUSB_ALLOWED_ORIGINS_HEADER(NumberOfConfigurationHeaders, ...) \
5, /* Size */ \
WebUSB_Descriptor_Set_Header, /* Type */ \
_BOS_ENCODE_16(sizeof((uint8_t[]){__VA_ARGS__}) + 5), /* Total size */ \
NumberOfConfigurationHeaders, \
/* TODO: Could have origins here too, useful? */ \
__VA_ARGS__

#define WEBUSB_CONFIG_SUBSET_HEADER(ConfigValue, NumberOfFunctionHeaders, ...) \
4, /* Size */ \
WebUSB_Configuration_Subset_Header, /* Type */ \
ConfigValue, \
NumberOfFunctionHeaders, \
/* TODO: Could have origins here too, useful? */ \
__VA_ARGS__

#define WEBUSB_FUNCTION_SUBSET_HEADER(InterfaceNum, ...) \
sizeof((uint8_t[]){__VA_ARGS__}) + 3, /* size */ \
WebUSB_Function_Subset_Header, /* Type */ \
InterfaceNum, \
__VA_ARGS__ /* URL Descriptor Indices which are valid */

#define URL_STRING_DESCRIPTOR(URLScheme, String) { .Header = {.Size = sizeof(USB_Descriptor_URL_t) + (sizeof(String) - 1), .Type = WebUSB_URL}, .Scheme = URLScheme, .URL = String }

/* Enums: */
/** Enum for the possible standard descriptor types, as given in each descriptor's header. */
Expand All @@ -208,6 +329,8 @@
DTYPE_Other = 0x07, /**< Indicates that the descriptor is of other type. */
DTYPE_InterfacePower = 0x08, /**< Indicates that the descriptor is an interface power descriptor. */
DTYPE_InterfaceAssociation = 0x0B, /**< Indicates that the descriptor is an interface association descriptor. */
DTYPE_BOS = 0x0F, /**< Indicates that the descriptor is a Binary Device Object Store descriptor. */
DTYPE_DeviceCapability = 0x10, /**< Indicates that the descriptor is a device capability descriptor. */
DTYPE_CSInterface = 0x24, /**< Indicates that the descriptor is a class specific interface descriptor. */
DTYPE_CSEndpoint = 0x25, /**< Indicates that the descriptor is a class specific endpoint descriptor. */
};
Expand Down Expand Up @@ -243,6 +366,48 @@
* Interface Association Descriptor protocol.
*/
};

enum USB_Descriptor_DeviceCapabilityCode_t
{
USB_Capability_Wireless_USB = 0x01,
USB_Capability_USB2_Extension = 0x02,
USB_Capability_SuperSpeed = 0x03,
USB_Capability_ContainerId = 0x04,
USB_Capability_Platform = 0x05,
USB_Capability_PowerDelivery = 0x06,
USB_Capability_BatteryInfo = 0x07,
USB_Capability_ConsumerPort = 0x08,
USB_Capability_ProviderPort = 0x09,
USB_Capability_SuperSpeedPlus = 0x0A,
USB_Capability_PrecisionTimeMeasurement = 0x0B,
USB_Capability_WirelessUSBExt = 0x0C
};

enum MS_OS_20_Descriptor_Types_t
{
MS_OS_20_SET_HEADER_DESCRIPTOR = 0x00,
MS_OS_20_SUBSET_HEADER_CONFIGURATION = 0x01,
MS_OS_20_SUBSET_HEADER_FUNCTION = 0x02,
MS_OS_20_FEATURE_COMPATIBLE_ID = 0x03,
MS_OS_20_FEATURE_REG_PROPERTY = 0x04,
MS_OS_20_FEATURE_MIN_RESUME_TIME = 0x05,
MS_OS_20_FEATURE_MODEL_ID = 0x06,
MS_OS_20_FEATURE_CCGP_DEVICE = 0x07
};

enum WebUSB_URL_Schemes_t
{
URL_HTTP = 0,
URL_HTTPS = 1
};

enum WebUSB_Descriptor_Types_t
{
WebUSB_Descriptor_Set_Header = 0,
WebUSB_Configuration_Subset_Header = 1,
WebUSB_Function_Subset_Header = 2,
WebUSB_URL = 3
};

/* Type Defines: */
/** \brief Standard USB Descriptor Header (LUFA naming conventions).
Expand Down Expand Up @@ -625,6 +790,15 @@
* interface association.
*/
} ATTR_PACKED USB_StdDescriptor_Interface_Association_t;

typedef struct
{
USB_Descriptor_Header_t Header; /**< Descriptor header, including type and size. */

uint8_t Scheme; /**< URL Scheme. */

uint8_t URL[];
} ATTR_PACKED USB_Descriptor_URL_t;

/** \brief Standard USB Endpoint Descriptor (LUFA naming conventions).
*
Expand Down