1. Introduction
This section is non-normative.
The Universal Serial Bus (USB) is the de-facto standard for wired peripherals. Most USB devices implement one of roughly a dozen standard "device classes" which specify a way for the device to advertise the features it supports and commands and data formats for using those features. Standard device classes include keyboard, mice, audio, video and storage devices. Operating systems support such devices using the "class driver" provided by the OS vendor. There is however a long tail of devices that do not fit into one of the standardized device classes. These devices require hardware vendors to write native drivers and SDKs in order for developers to take advantage of them and this native code prevents these devices from being used by the web.
The WebUSB API provides a way to safely expose USB device services to the web. It provides an API familiar to developers who have used existing native USB libraries and exposes the device interfaces defined by existing specifications. With this API hardware manufacturers will have the ability to build cross-platform JavaScript SDKs for their devices. This will be good for the web because, instead of waiting for a new kind of device to be popular enough for browsers to provide a specific API, new and innovative hardware can be built for the web from day one.
For more information about USB see §9 Appendix: A Brief Introduction to USB.
2. Motivating Applications
This section is non-normative.
2.1. Educational Devices
The software delivery model of the web is a key enabler for educational applications because they can be quickly loaded on any computer without questions of platform compatibility or administrative credentials. Science classes are incorporating computerized measurement and data logging into their lessons. These tools require bundled software that may be difficult to install on managed computers as every new native application adds overhead to an already stressed IT department. Web-based hardware APIs allow support for these devices to be built directly into existing online course materials, providing a completely seamless experience.
Students learning to code with one of the many microcontroller development kits can take advantage of online developer tools to write and upload their code. These tools already exist however they require a native component to interface between the browser and the hardware. These native extensions add a barrier to entry and may expose the user to security vulnerabilities in a way that that code running in the sandboxed web environment does not.
2.2. Web Drivers
The composablity of the web allows a new ecosystem of hardware support to be built entirely from web technology. Taking 3D printers an example, imagine that a site hosting 3D object designs wants to integrate printing directly into their page. The web supports 2D printing but there is no API for the 3D variety. If manufacturers host embeddable pages that use the WebUSB API to send data to their printers, sites can use these pages to integrate support for the hardware in the same way that features such as embedded maps are added to many existing sites.
2.3. Devices Updates and Diagnostics
While wireless protocols such as Bluetooth are often the more convenient choice for consumer devices USB ports continue to proliferate because they are an easy solution for power delivery and can serve as the connection of last resort when the device isn’t working. By integrating update and diagnostic tools into their support site a hardware manufacturer can provide tools for customers on any platform and collect better diagnostic data when a customer reaches out for support through their website. The landing page provides a way for the device manufacturer to direct the user to the right part of their website for help with their device.
3. Security and Privacy Considerations
This section is non-normative.
The WebUSB API is a powerful feature and has the possibility to expose users to a number of new privacy and security risks. These risks can be broadly divided into three categories that will be described in the sections below.
3.1. Abusing Access to a Device
Peripheral devices can serve a number of purposes. They may store data, as a flash drive does. They may collect information about the outside world as a camera or microphone does. They may manipulate objects in the outside world as a printer does. Each of the examples above have high-level APIs in the web platform with security features that aim to prevent their abuse by a malicious website. Storing data to or from an external drive requires the user to select the file manually. Turning on the microphone or camera requires permission from the user and may activate an indicator to let the user know data collection is in progress. Printing a document requires explicit action as well. This API provides a generic mechanism to connect to devices not covered by these existing high-level APIs and so it requires a similarly generic mechanism for preventing a malicious page from abusing a device.
The first of these protections is the requestDevice()
function. The UA
may display a permission prompt when this function is called. Even for a
non-malicious page this action also preserves user privacy by preventing a site
from connecting to a device before the user is aware that such a connection is
possible. The UA may also display an indicator when a device connection is
active.
Secondly, this specification requires that only secure contexts as described in [powerful-features] can access USB devices. This ensures both the authenticity of the code executing on behalf of the origin and that data read from the device may not be intercepted in transit.
Lastly, since USB devices are unable to distinguish requests from multiple
sources, operating systems only allow a USB interface to have a single owning
user-space or kernel-space driver. The UA acts as a user-space driver, therefore
allowing only a single execution context to claim a USB interface at a time. The claimInterface()
function will fail if multiple execution contexts
attempt to claim an interface.
3.2. Attacking a Device
Historically, unless they were created for high security applications, USB
devices have been designed to trust the host they are connected to and so the
host is the traditional guardian of access to the capabilities a device
provides. In the development of this specification two possibilities were
considered. First, the UA could notify the device of the origin from which a
request originated. This would be similar to the Referrer
header
included in HTTP request. The difficulty of this approach is that it places
the burden of access control on the device. Devices often have very limited
processing and storage capabilities and so an effort was made to limit the
amount of work necessary on the part of the device.
The approach initially chosen during drafting of this specification was to instead require that the UA control access though a mechanism similiar to [CORS]. The device could provide the UA with a set of static data structures defining a set of origins that are allowed to connect to it. To support a transition period for existing devices it was proposed that information about allowed origins could also be provided out of band through some kind of public registry.
A downside of this approach was two-fold. First, it required vendors to build new devices with WebUSB in mind or rely on a public registry system that proved difficult to specify. Product development cycles are long and as only an Editor’s Draft this specification does not have the clout necessary to influence product planning. Second, it provided no mechanism for third-party developers to use this API with a device. This limited innovation and the number of developers who could take advantage of this new capability.
After considering these options the authors have decided that the permission
prompt encouraged by the requestDevice()
method and the integration with §7.1 Feature Policy provide adequate protection against unwanted access to a
device.
3.3. Attacking the Host
If a device is compromised then in addition to abusing its own capabilities the attacker may also use it to in turn attack the host to which it is connected or if the exploit is persistent any host it is connected to later. The methods above are the ways in which this specification attempts to mitigate this attack vector for once the device is under the control of an attacker (for example, by uploading a malicious firmware image) there is nothing that can be done by the UA to prevent further damage.
This specification recommends device manufacturers practice defense in depth by designing their devices to only accept signed firmware updates and/or require physical access to the device in order to apply some configuration changes.
4. WebUSB Descriptors and Requests
This specification defines descriptors and commands the UA MAY use to gather information about the device specific to implementing this API.
4.1. WebUSB Platform Capability Descriptor
A device announces support for the WebUSB command set by including the following Platform Descriptor in its Binary Object Store:
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | bLength | 1 | Number | Size of this descriptor. Must be set to 24. |
1 | bDescriptorType | 1 | Constant | DEVICE CAPABILITY descriptor type ([USB31] Table 9-6). |
2 | bDevCapabilityType | 1 | Constant | PLATFORM capability type ([USB31] Table 9-14). |
3 | bReserved | 1 | Number | This field is reserved and shall be set to zero. |
4 | PlatformCapabilityUUID | 16 | UUID | Must be set to {3408b638-09a9-47a0-8bfd-a0768815b665}. |
20 | bcdVersion | 2 | BCD | Protocol version supported. Must be set to 0x0100. |
22 | bVendorCode | 1 | Number | bRequest value used for issuing WebUSB requests. |
23 | iLandingPage | 1 | Number | URL descriptor index of the device’s landing page. |
The iLandingPage
field, when non-zero, indicates a landing page which the device manufacturer would like the user to
visit in order to control their device. The UA MAY suggest the user navigate
to this URL when the device is connected.
Note: The USB is a little-endian bus and so according to [RFC4122] the UUID
above MUST be sent over the wire as the byte sequence {0x38, 0xB6, 0x08,
0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6,
0x65}
.
4.2. WebUSB Device Requests
All control transfers defined by this specification are considered to
be vendor-specific requests. The bVendorCode
value found
in the WebUSB Platform Capability Descriptor provides the UA
with the bRequest
the device expects the host to use when
issuing control transfers these requests. The request type is then
specified in the wIndex
field.
Constant | Value |
---|---|
(Reserved) | 1 |
GET_URL | 2 |
4.2.1. Get URL
This request fetches the URL descriptor with the given index.
The device MUST respond with the URL Descriptor at the given index or stall the transfer if the index is invalid.
bmRequestType | bRequest | wValue | wIndex | wLength | Data |
---|---|---|---|---|---|
11000000B | bVendorCode
| Descriptor Index | GET_URL | Descriptor Length | Descriptor |
4.3. WebUSB Descriptors
These descriptor types are returned by requests defined in this specification.
Constant | Value |
---|---|
(Reserved) | 0-2 |
WEBUSB_URL | 3 |
4.3.1. URL Descriptor
This descriptor contains a single URL and is returned by the Get URL request.
Offset | Field | Size | Value | Description |
---|---|---|---|---|
0 | bLength | 1 | Number | Size of this descriptor. |
1 | bDescriptorType | 1 | Constant | WEBUSB_URL. |
2 | bScheme | 1 | Number | URL scheme prefix. |
3 | URL | Variable | String | UTF-8 encoded URL (excluding the scheme prefix). |
The bScheme
field MUST be one of these values:
Value | Prefix |
---|---|
0 | "http://" |
1 | "https://" |
255 | "" |
The special value 255
indicates that the entire URL, including
scheme, is encoded in the URL
field.
5. Device Enumeration
dictionary {
USBDeviceFilter unsigned short ;
vendorId unsigned short ;
productId octet ;
classCode octet ;
subclassCode octet ;
protocolCode DOMString ; };
serialNumber dictionary {
USBDeviceRequestOptions required sequence <USBDeviceFilter >; }; [
filters Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface :
USB EventTarget {attribute EventHandler ;
onconnect attribute EventHandler ;
ondisconnect Promise <sequence <USBDevice >>(); [
getDevices Exposed =Window ]Promise <USBDevice >(
requestDevice USBDeviceRequestOptions ); }; [
options Exposed =Window ,SecureContext ]partial interface Navigator { [SameObject ]readonly attribute USB ; }; [
usb Exposed =(DedicatedWorker ,SharedWorker ),SecureContext ]partial interface WorkerNavigator { [SameObject ]readonly attribute USB ; };
usb
getDevices()
,
document. addEventListener( 'DOMContentLoaded' , async() => { let devices= await navigator. usb. getDevices(); devices. forEach( device=> { // Add |device| to the UI. }); });
After the page is loaded the user may connect or disconnect a device from their system so script should also register for these events in order to keep the interface up-to-date,
navigator. usb. addEventListener( 'connect' , event=> { // Add |event.device| to the UI. }); navigator. usb. addEventListener( 'disconnect' , event=> { // Remove |event.device| from the UI. });
If this is the first time the user has visited the page then it won’t have
permission to access any devices so the page must first call requestDevice()
in response to a user gesture. In this case the page
supports devices from vendor 0xABCD
that carry the vendor-specific
subclass 0x01
,
let button= document. getElementById( 'request-device' ); button. addEventListener( 'click' , async() => { let device; try { device= await navigator. usb. requestDevice({ filters: [{ vendorId: 0xABCD , classCode: 0xFF , // vendor-specific protocolCode: 0x01 }]}); } catch ( err) { // No device was selected. } if ( device!== undefined ) { // Add |device| to the UI. } });
A USB device device matches a device
filter filter if the following steps return match
:
-
Let deviceDesc be device’s device descriptor.
-
If
filter.
is present andvendorId
deviceDesc.idVendor
does not equalfilter.
, returnvendorId
mismatch
. -
If
filter.
is present andproductId
deviceDesc.idProduct
does not equalfilter.
, returnproductId
mismatch
. -
If
filter.
is present then, let serialNumber be the string descriptor with indexserialNumber
deviceDesc.iSerialNumber
. If device returns an error when requesting serialNumber or serialNumber is not equal tofilter.
, returnserialNumber
mismatch
. -
If
filter.
is present and, for any of device’s interface’s interface, interface matches the interface filter filter, returnclassCode
match
. -
If
filter.
is present andclassCode
deviceDesc.bDeviceClass
is not equal tofilter.
, returnclassCode
mismatch
. -
If
filter.
is present andsubclassCode
deviceDesc.bDeviceSubClass
is not equal tofilter.
, returnsubclassCode
mismatch
. -
If
filter.
is present andprotocolCode
deviceDesc.bDeviceProtocol
is not equal tofilter.
, returnprotocolCode
mismatch
. -
Return
match
.
Note: The steps above treat the bDeviceClass
, bDeviceSubClass
and bDeviceProtocol
fields of the device descriptor as though they were part of an interface
descriptor which is also compared against the provided filter.
A USB interface interface matches
an interface filter filter if the following steps return match
:
-
Let desc be interface’s interface descriptor.
-
If
filter.
is present andclassCode
desc.bInterfaceClass
is not equal tofilter.
, returnclassCode
mismatch
. -
If
filter.
is present andsubclassCode
desc.bInterfaceSubClass
is not equal tofilter.
, returnsubclassCode
mismatch
. -
If
filter.
is present andprotocolCode
desc.bInterfaceProtocol
is not equal tofilter.
, returnprotocolCode
mismatch
. -
Return
match
.
A USBDeviceFilter
filter is valid if the following steps
return valid
:
-
If
filter.
is present andproductId
filter.
is not present, returnvendorId
invalid
. -
If
filter.
is present andsubclassCode
filter.
is not present, returnclassCode
invalid
. -
If
filter.
is present andprotocolCode
filter.
is not present, returnsubclassCode
invalid
. -
Return
valid
.
The UA MUST be able to enumerate all devices attached to the system.
It is, however NOT required to perform this work each time an algorithm
requests an enumeration. The UA MAY cache the result of the first enumeration
it performs and then begin monitoring for device connection and disconnection
events, adding connected devices to its cached enumeration and removing
disconnected devices. This mode of operation is preferred as it reduces the
number of operating system calls made and amount of bus traffic generated by
the getDevices()
and requestDevice()
methods.
The onconnect
attribute is an Event handler IDL attribute for the connect event type.
The ondisconnect
attribute is an Event handler IDL attribute for the disconnect event type.
The getDevices()
method, when invoked, MUST return a new Promise
and
run the following steps in parallel:
-
Enumerate all devices attached to the system. Let this result be enumerationResult.
-
Let devices be a new empty
Array
. -
For each device in enumerationResult:
-
If this is the first call to this method, check permissions for device.
-
Search for an element allowedDevice in
storage.
where device is in allowedDevice@allowedDevices
[[devices]]
. If no such element exists, continue to the next device. -
Add the
USBDevice
object representing device to devices.
-
-
Resolve promise with devices.
The requestDevice()
method, when invoked, MUST run the following steps:
-
Request permission to use the following descriptor,
{ name: "usb" filters: options. filters} Let permissionResult be the resulting
Promise
. -
Return the result of transforming permissionResult with a fullfillment handler that takes an argument result and runs the following steps:
-
If
result.
is empty, throw adevices
NotFoundError
and abort these steps. -
Return
result.
.devices
[0]
-
To request the "usb" permission, given a USBPermissionStorage
storage, a USBPermissionDescriptor
options and a USBPermissionResult
status, the UA MUST return a new Promise
promise and run the following
steps in parallel:
-
For each filter in
options.
if filter is not a valid filter reject promise with afilters
TypeError
and abort these steps. -
If the algorithm is not triggered by user activation, reject promise with a
SecurityError
and abort these steps. -
Set
status.
to `"ask"`.state
-
Enumerate all devices attached to the system. Let this result be enumerationResult.
-
Remove devices from enumerationResult if they do not match a device filter in
options.
.filters
-
Display a prompt to the user requesting they select a device from enumerationResult. The UA SHOULD show a human-readable name for each device.
-
Wait for the user to have selected a device or cancelled the prompt.
-
If the user cancels the prompt, set
status.
to an emptydevices
FrozenArray
, resolve promise withundefined
, and abort these steps. -
Let deviceObj be the
USBDevice
object representing device. -
Set
status.
to a newdevices
FrozenArray
containing deviceObj as its only element. -
Resolve promise with
undefined
.
To add an allowed USB device device to USBPermissionStorage
storage, the UA MUST run the following
steps:
-
Search for an element allowedDevice in
storage.
where device is in allowedDevice@allowedDevices
[[devices]]
. If one is found, abort these steps. -
Let vendorId and productId be device’s vendor ID and product ID.
-
Let serialNumber be device’s serial number if it has one, otherwise
undefined
. -
Append
{ vendorId: vendorId, productId: productId, serialNumber: serialNumber }
, with a[[devices]]
internal slot containing a single entry device tostorage.
.allowedDevices
To check permissions for a new USB device device, given a USBPermissionStorage
storage,
the UA MUST run the following steps:
-
Let vendorId and productId be device’s vendor ID and product ID.
-
Let serialNumber be device’s if it has one, otherwise
undefined
. -
Search for an element allowedDevice in
storage.
where:allowedDevices
-
allowedDevice.
equals vendorId.vendorId
-
allowedDevice.
equals productId.productId
-
allowedDevice.
equals serialNumber.serialNumber
-
-
If no such element exists, return
null
. -
Add device to allowedDevice@
[[devices]]
. -
Return allowedDevice.
5.1. Events
dictionary :
USBConnectionEventInit EventInit {required USBDevice ; }; [
device (
Constructor DOMString ,
type USBConnectionEventInit ),
eventInitDict Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface :
USBConnectionEvent Event { [SameObject ]readonly attribute USBDevice ; };
device
When the UA detects a new USB device device connected to the host it MUST perform the following steps for each script execution environment:
-
Let storage be the
USBPermissionStorage
object in the current script execution environment. -
Check permissions for device with storage and let allowedDevice be the result.
-
If allowedDevice is
null
, abort these steps. -
Let deviceObj be the
USBDevice
object representing device. -
Let event be a new
USBConnectionEvent
, with thedevice
attribute set to deviceObj. -
Fire an event named connect on
usb
, using event as the event object.
When the UA detects a USB device device has been disconnected from the host it MUST perform the following steps for each script execution environment:
-
Let storage be the
USBPermissionStorage
object in the current script execution environment. -
Search for an element allowedDevice in
storage.
where device is in allowedDevice@allowedDevices
[[devices]]
, if no such element exists, abort these steps. -
Remove device from allowedDevice@
[[devices]]
. -
If
allowedDevice.
isserialNumber
undefined
and allowedDevice@[[devices]]
is empty remove allowedDevice fromstorage.
.allowedDevices
-
Let device be the
USBDevice
object representing device. -
Let event be a new
USBConnectionEvent
, with thedevice
attribute set to device. -
Fire an event named disconnect on
usb
, using event as the event object.
6. Device Usage
[Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBDevice readonly attribute octet ;
usbVersionMajor readonly attribute octet ;
usbVersionMinor readonly attribute octet ;
usbVersionSubminor readonly attribute octet ;
deviceClass readonly attribute octet ;
deviceSubclass readonly attribute octet ;
deviceProtocol readonly attribute unsigned short ;
vendorId readonly attribute unsigned short ;
productId readonly attribute octet ;
deviceVersionMajor readonly attribute octet ;
deviceVersionMinor readonly attribute octet ;
deviceVersionSubminor readonly attribute DOMString ?;
manufacturerName readonly attribute DOMString ?;
productName readonly attribute DOMString ?;
serialNumber readonly attribute USBConfiguration ?;
configuration readonly attribute FrozenArray <USBConfiguration >;
configurations readonly attribute boolean ;
opened Promise <void >();
open Promise <void >();
close Promise <void >(
selectConfiguration octet );
configurationValue Promise <void >(
claimInterface octet );
interfaceNumber Promise <void >(
releaseInterface octet );
interfaceNumber Promise <void >(
selectAlternateInterface octet ,
interfaceNumber octet );
alternateSetting Promise <USBInTransferResult >(
controlTransferIn USBControlTransferParameters ,
setup unsigned short );
length Promise <USBOutTransferResult >(
controlTransferOut USBControlTransferParameters ,
setup optional BufferSource );
data Promise <void >(
clearHalt USBDirection ,
direction octet );
endpointNumber Promise <USBInTransferResult >(
transferIn octet ,
endpointNumber unsigned long );
length Promise <USBOutTransferResult >(
transferOut octet ,
endpointNumber BufferSource );
data Promise <USBIsochronousInTransferResult >(
isochronousTransferIn octet ,
endpointNumber sequence <unsigned long >);
packetLengths Promise <USBIsochronousOutTransferResult >(
isochronousTransferOut octet ,
endpointNumber BufferSource ,
data sequence <unsigned long >);
packetLengths Promise <void >(); };
reset
bConfigurationValue 1
)
with a single interface (bInterfaceNumber 1
) with a single
bulk endpoint (bEndpointAddress 0x81
which means that it is
endpoint 1 and an IN endpoint). When data is sampled it is available on this
endpoint. The maximum packet size on this endpoint is 16 bytes to support all 8
channels being activated at the same time. To save bus bandwidth, however, any
combination of channels can be activated and deactivated. The packet will only
be the length necessary to transmit the data collected.
To get started we open the device, select the first configuration (it only has one but the operating system may not have already done this during enumeration) and claim the data logging interface,
await device. open(); if ( device. configuration=== null ) await device. selectConfiguration( 1 ); await device. claimInterface( 1 );
For this particular application we care about reading from channels 1, 2 and 5 so we issue a control transfer to activate these channels,
await device. controlTransferOut({ requestType: ' vendor ' , recipient: ' interface ' , request: 0x01 , // vendor-specific request: enable channels value: 0x0013 , // 0b00010011 (channels 1, 2 and 5) index: 0x0001 // Interface 1 is the recipient });
The application may now start polling the device for data. As we only expect data from 3 channels we request a 6 byte buffer. As long as we receive a complete buffer the captured values (transmitted in big endian) are printed to the console log. If the device has encountered an error and signals this by stalling the endpoint then the error is cleared before continuing,
while ( true ) { let result= await data. transferIn( 1 , 6 ); if ( result. data&& result. data. byteLength=== 6 ) { console. log( 'Channel 1: ' + result. data. getUint16( 0 )); console. log( 'Channel 2: ' + result. data. getUint16( 2 )); console. log( 'Channel 5: ' + result. data. getUint16( 4 )); } if ( result. status=== 'stall' ) { console. warn( 'Endpoint stalled. Clearing.' ); await device. clearHalt( 1 ); } }
The usbVersionMajor
, usbVersionMinor
and usbVersionSubminor
attributes declare the USB protocol version
supported by the device. They SHALL correspond to the value of the bcdUSB
field of the device descriptor such that a value of 0xJJMN
has major version JJ
, minor version M
and subminor version N
.
The deviceClass
, deviceSubclass
and deviceProtocol
attributes declare the communication interface
supported by the device. They MUST correspond respectively to the values of the bDeviceClass
, bDeviceSubClass
and bDeviceProtocol
fields of the device descriptor.
The vendorId
and productId
MUST be equal to the
device’s vendor ID and product ID.
The deviceVersionMajor
, deviceVersionMinor
and deviceVersionSubminor
attributes declare the device release
number as defined by the device manufacturer. It SHALL correspond to the value
of the bcdDevice
field of the device descriptor such that a
value of 0xJJMN
has major version JJ
, minor version M
and subminor version N
.
The manufacturerName
, productName
and serialNumber
attributes SHOULD contain the values of the string
descriptors indexed by the iManufacturer
, iProduct
and iSerialNumber
fields of the device descriptor if each is
defined.
The configuration
attribute contains the currently selected
configuration for the device and SHALL be one of the configurations listed in configurations
. It MAY be null
if the device is in
an unconfigured state and MUST be updated by selectConfiguration()
.
The configurations
attribute contains a list of configurations
supported by the device. These configurations SHALL be populated from the
configuration descriptors reported by the device and the number of elements in
this list SHALL match the value of the bNumConfigurations
field of
the device descriptor.
The opened
attribute SHALL be set to true
when the
device is opened by the current execution context and SHALL be set to false
otherwise.
The open()
method, when invoked, MUST return a new Promise
promise and run the following steps in parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
If
device.
isopened
true
resolve promise and abort these steps. -
Perform the necessary platform-specific steps to begin a session with the device. If these fail for any reason reject promise with a
NetworkError
and abort these steps.
The close()
method, when invoked, MUST return a new Promise
promise and run the following steps in parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
If
device.
isopened
false
resolve promise and abort these steps. -
Abort all other algorithms currently running against this device and reject their associated promises with an
AbortError
. -
Perform the necessary platform-specific steps to release any claimed interfaces as if
releaseInterface(interfaceNumber)
had been called for each claimed interface. -
Perform the necessary platform-specific steps to end the session with the device.
When no [ECMAScript] code can observe an instance of USBDevice
device anymore, the UA SHOULD run device.close()
.
The selectConfiguration(configurationValue)
method, when invoked,
MUST return a new Promise
promise and run the following steps in
parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let configuration be the device configuration with
bConfigurationValue
equal to configurationValue. If no such configuration exists, reject promise with aNotFoundError
and abort these steps. -
If
device.
is not equal toopened
true
reject promise with anInvalidStateError
and abort these steps. -
Abort all transfers currently scheduled on endpoints other than the default control pipe and reject their associated promises with a
AbortError
. -
Issue a
SET_CONFIGURATION
control transfer to the device to set configurationValue as its active configuration. If this step fails reject promise with aNetworkError
and abort these steps. -
Set
device.
to configuration and resolve promise.configuration
The claimInterface(interfaceNumber)
method, when invoked, MUST
return a new Promise
promise and run the following steps in
parallel:
-
If the device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let interface be the interface in the active configuration with
bInterfaceNumber
equal to interfaceNumber. If no such interface exists, reject promise with aNotFoundError
and abort these steps. -
If
device.
is notopened
true
, reject promise with anInvalidStateError
and abort these steps. -
If
interface.
isclaimed
true
, resolve promise and abort these steps. -
Perform the necessary platform-specific steps to request exclusive control over interface for the current execution context. If this fails, reject promise with a
NetworkError
and abort these steps.
The releaseInterface(interfaceNumber)
method, when invoked, MUST
return a new Promise
promise and run the following steps in
parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let interface be the interface in the active configuration with
bInterfaceNumber
equal to interfaceNumber. If no such interface exists, reject promise with aNotFoundError
and abort these steps. -
If
device.
is notopened
true
, reject promise with anInvalidStateError
and abort these steps. -
If
interface.
isclaimed
false
, resolve promise and abort these steps. -
Perform the necessary platform-specific steps to reliquish exclusive control over interface.
The selectAlternateInterface(interfaceNumber, alternateSetting)
method, when invoked, MUST return a new Promise
promise and run the
following steps in parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let interface be the interface in the active configuration with
bInterfaceNumber
equal to interfaceNumber. If no such interface exists, reject promise with aNotFoundError
and abort these steps. -
If
device.
oropened
interface.
is notclaimed
true
, reject promise with anInvalidStateError
and abort these steps. -
Abort all transfers currently scheduled on endpoints associated with the previously selected alternate setting of interface and reject their associated promises with a
AbortError
. -
Issue a
SET_INTERFACE
control transfer to the device to set alternateSetting as the current configuration of interface. If this step fails reject promise with aNetworkError
and abort these steps. -
Resolve promise.
The controlTransferIn(setup, length)
method, when invoked, MUST
return a new Promise
promise and run the following steps in
parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
If
device.
is not equal toopened
true
reject promise with anInvalidStateError
and abort these steps. -
Check the validity of the control transfer parameters and abort these steps if promise is rejected.
-
If length is greater than 0, let buffer be a host buffer with space for length bytes.
-
Issue a control transfer to device with the setup packet parameters provided in setup, the data transfer direction in
bmRequestType
set to "device to host" andwLength
set to length. If defined also provide buffer as the destination to write data received in response to this transfer. -
Let bytesTransferred be the number of bytes written to buffer.
-
Let result be a new
USBInTransferResult
. -
If data was received from device create a new
ArrayBuffer
containing the first bytesTransferred bytes of buffer and setresult.
to a newdata
DataView
constructed over it. -
If device responded by stalling the default control pipe set
result.
tostatus
"stall"
. -
If device responded with more than length bytes of data set
result.
tostatus
"babble"
and otherwise set it to"ok"
. -
If the transfer fails for any other reason reject promise with a
NetworkError
and abort these steps. -
Resolve promise with result.
The controlTransferOut(setup, data)
method, when invoked, must
return a new Promise
promise and run the following steps in
parallel:
-
If the device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
If
device.
is not equal toopened
true
reject promise with anInvalidStateError
and abort these steps. -
Check the validity of the control transfer parameters and abort these steps if promise is rejected.
-
Issue a control transfer with the setup packet populated by setup and the data transfer direction in
bmRequestType
set to "host to device" andwLength
set todata.length
. Transmit data in the data stage of the transfer. -
Let result be a new
USBOutTransferResult
. -
If the device responds by stalling the default control pipe set
result.
tostatus
"stall"
. -
If the device acknowledges the transfer set
result.
tostatus
"ok"
andresult.
tobytesWritten
data.length
. -
If the transfer fails for any other reason reject promise with a
NetworkError
and abort these steps. -
Resolve promise with result.
The clearHalt(direction, endpointNumber)
method, when invoked,
MUST return a new Promise
promise and run the following steps in
parallel:
-
If the device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let endpoint be the endpoint in the active configuration with
bEndpointAddress
corresponding to direction and endpointNumber. If no such endpoint exists reject promise and abort these steps. -
If
device.
oropened
interface.
is notclaimed
true
, reject promise with anInvalidStateError
and abort these steps. -
Issue a
ClearFeature(ENDPOINT_HALT)
control transfer to the device to clear the halt condition on endpoint. -
On failure reject promise with a
NetworkError
, otherwise resolve promise.
The transferIn(endpointNumber, length)
method, when invoked, MUST
return a new Promise
promise and run the following steps in
parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let endpoint be the IN endpoint in the active configuration with
bEndpointAddress
corresponding to endpointNumber. If there is no such endpoint reject promise with aNotFoundError
and abort these steps. -
If endpoint is not a bulk or interrupt endpoint reject promise with an
InvalidAccessError
and abort these steps. -
If
device.
oropened
interface.
is notclaimed
true
, reject promise with anInvalidStateError
and abort these steps. -
Let buffer be a host buffer with space for length bytes.
-
As appropriate for endpoint enqueue a bulk or interrupt IN transfer on endpoint to receive length bytes of data from the device into buffer.
-
Let bytesTransferred be the number of bytes written to buffer.
-
Let result be a new
USBInTransferResult
. -
If data was received from device create a new
ArrayBuffer
containing the first bytesTransferred bytes of buffer and setresult.
to a newdata
DataView
constructed over it. -
If device responded with more than length bytes of data set
result.
tostatus
"babble"
. -
If the transfer ended because endpoint is halted set
result.
tostatus
"stall"
. -
If device acknowledged the complete transfer set
result.
tostatus
"ok"
. -
If the transfer failed for any other reason reject promise with a
NetworkError
and abort these steps. -
Resolve promise with result.
The transferOut(endpointNumber, data)
method, when invoked, MUST
return a new Promise
promise and run the following steps in
parallel:
-
If the device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let endpoint be the OUT endpoint in the active configuration with
bEndpointAddress
corresponding to endpointNumber. If there is no such endpoint reject promise with aNotFoundError
and abort these steps. -
If endpoint is not a bulk or interrupt endpoint reject promise with an
InvalidAccessError
and abort these steps. -
If
device.
oropened
interface.
is notclaimed
true
, reject promise with anInvalidStateError
and abort these steps. -
As appropriate for endpoint enqueue a bulk or interrupt OUT transfer on endpoint to transmit data to the device.
-
Let result be a new
USBOutTransferResult
. -
Set
result.
to the amount of data successfully sent to the device.bytesWritten
-
If the device acknowledges the complete transfer set
result.
tostatus
"ok"
. -
If the transfer fails for any other reason reject promise with a
NetworkError
and abort these steps. -
Resolve promise with result.
The isochronousTransferIn(endpointNumber, packetLengths)
method,
when invoked, MUST return a new Promise
promise and run the following
steps in parallel:
-
If the device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let endpoint be the IN endpoint in the active configuration with
bEndpointAddress
corresponding to endpointNumber. If there is no such endpoint reject promise with aNotFoundError
and abort these steps. -
If endpoint is not an isochronous endpoint reject promise with an
InvalidAccessError
and abort these steps. -
If
device.
oropened
interface.
is notclaimed
true
, reject promise with anInvalidStateError
and abort these steps. -
Let length be the sum of the elements of packetLengths.
-
Let buffer be a new
ArrayBuffer
of length bytes. -
Let result be a new
USBIsochronousInTransferResult
and setresult.
to a newdata
DataView
constructed over buffer. -
Enqueue an isochronous IN transfer on endpoint that will write up to length bytes of data from the device into buffer.
-
For each packet i from
0
topacketLengths.length - 1
:-
Let packet be a new
USBIsochronousInTransferPacket
and setresult.
to packet.packets
[i] -
Let view be a new
DataView
over the portion of buffer containing the data received from the device for this packet and setpacket.
to view.data
-
If the device responds with more than
packetLengths[i]
bytes of data setpacket.
tostatus
"babble"
. -
If the transfer ends because endpoint is stalled set
packet.
tostatus
"stall"
. -
If the device acknowledges the complete transfer set
packet.
tostatus
"ok"
. -
If the transfer fails for any other reason reject promise with a
NetworkError
and abort these steps.
-
-
Resolve promise with result.
The isochronousTransferOut(endpointNumber, data, packetLengths)
method, when invoked, MUST return a new Promise
promise and run the
following steps in parallel:
-
If the device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
Let endpoint be the OUT endpoint in the active configuration with
bEndpointAddress
corresponding to endpointNumber. If there is no such endpoint reject promise with aNotFoundError
and abort these steps. -
If endpoint is not an isochronous endpoint reject promise with an
InvalidAccessError
and abort these steps. -
If
device.
oropened
interface.
is notclaimed
true
, reject promise with anInvalidStateError
and abort these steps. -
Let length be the sum of the elements of packetLengths.
-
Let result be a new
USBIsochronousOutTransferResult
. -
Enqueue an isochronous OUT transfer on endpoint that will write buffer to the device, divided into
packetLength.length
packets ofpacketLength[i]
bytes (for packets i from0
topacketLengths.length - 1
). -
For each packet i from
0
topacketLengths.length - 1
the host attempts to send to the device:-
Let packet be a new
USBIsochronousOutTransferPacket
and setresult.
to packet.packets
[i] -
Let
packet.
be the amount of data successfully sent to the device as part of this packet.bytesWritten
-
If the transfer ends because endpoint is stalled set
packet.
tostatus
"stall"
. -
If the device acknowledges the complete transfer set
packet.
tostatus
"ok"
. -
If the transfer fails for any other reason reject promise with a
NetworkError
and abort these steps.
-
-
Resolve promise with result.
The reset()
method, when invoked, MUST return a new Promise
promise and run the following steps in parallel:
-
Let device be the target
USBDevice
object. -
If device is no longer connected to the system, reject promise with a
NotFoundError
and abort these steps. -
If
device.
is not equal toopened
true
reject promise with anInvalidStateError
and abort these steps. -
Abort all operations on the device and reject their associated promises with an
AbortError
. -
Perform the necessary platform-specific operation to soft reset the device.
-
On failure reject promise with a
NetworkError
, otherwise resolve promise.
What configuration is the device in after it resets? <https://github.com/WICG/webusb/issues/36>
6.1. Transfers
enum {
USBRequestType ,
"standard" ,
"class" };
"vendor" enum {
USBRecipient ,
"device" ,
"interface" ,
"endpoint" };
"other" enum {
USBTransferStatus ,
"ok" ,
"stall" };
"babble" dictionary {
USBControlTransferParameters required USBRequestType ;
requestType required USBRecipient ;
recipient required octet ;
request required unsigned short ;
value required unsigned short ; }; [
index (
Constructor USBTransferStatus ,
status optional DataView ?),
data Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBInTransferResult readonly attribute DataView ?;
data readonly attribute USBTransferStatus ; }; [
status (
Constructor USBTransferStatus ,
status optional unsigned long = 0),
bytesWritten Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBOutTransferResult readonly attribute unsigned long ;
bytesWritten readonly attribute USBTransferStatus ; }; [
status (
Constructor USBTransferStatus ,
status optional DataView ?),
data Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBIsochronousInTransferPacket readonly attribute DataView ?;
data readonly attribute USBTransferStatus ; }; [
status (
Constructor sequence <USBIsochronousInTransferPacket >,
packets optional DataView ?),
data Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBIsochronousInTransferResult readonly attribute DataView ?;
data readonly attribute FrozenArray <USBIsochronousInTransferPacket >; }; [
packets (
Constructor USBTransferStatus ,
status optional unsigned long = 0),
bytesWritten Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBIsochronousOutTransferPacket readonly attribute unsigned long ;
bytesWritten readonly attribute USBTransferStatus ; }; [
status (
Constructor sequence <USBIsochronousOutTransferPacket >),
packets Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBIsochronousOutTransferResult readonly attribute FrozenArray <USBIsochronousOutTransferPacket >; };
packets
A control transfer is a special class of USB traffic most commonly used for configuring a device. It consists of three stages: setup, data and status. In the setup stage a setup packet is transmitted to the device containing request parameters including the transfer direction and size of the data to follow. In the data stage that data is either sent to or received from the device. In the status stage successful handling of the request is acknowledged or a failure is signaled.
All USB devices MUST have a default control pipe which is endpointNumber 0
.
The requestType
attribute populates part of
the bmRequestType
field of the setup packet to indicate
whether this request is part of the USB standard, a particular USB device class
specification or a vendor-specific protocol.
The recipient
attribute populates part of the bmRequestType
field of the setup packet to indicate whether
the control transfer is addressed to the entire device, or a specific
interface or endpoint.
The request
attribute populates the bRequest
field of the setup packet. Valid requests are
defined by the USB standard, USB device class specifications or the device
vendor.
The value
and index
attributes populate the wValue
and wIndex
fields of the setup packet respectively. The meaning of these fields depends on the request being made.
To check the validity of the control transfer parameters perform the following steps:
-
Let setup be the
USBControlTransferParameters
created for the transfer. -
Let promise be the promise created for the transfer.
-
Let configuration be the active configuration. If the device is not configured abort these steps.
-
If
setup.
isrecipient
"interface"
, perform the following steps:-
Let interfaceNumber be the lower 8 bits of
setup.
.index
-
Let interface be the interface in the | configuration| with
bInterfaceNumber
equal to interfaceNumber. If no such interface exists, reject promise with aNotFoundError
and abort these steps. -
If
interface.
is not equal toclaimed
true
, reject promise with anInvalidStateError
and abort these steps.
-
-
If
setup.
isrecipient
"endpoint"
, run the following steps:-
Let endpointNumber be defined as the lower 4 bits of
setup.
.index
-
Let direction be defined as
"in"
if the 8th bit ofsetup.
isindex
1
and"out"
otherwise. -
Let endpoint be the endpoint in the active configuration with
bEndpointAddress
corresponding to direction and endpointNumber. If no such endpoint exists, reject promise with aNotFoundError
and abort these steps. -
Let interface be the interface in which endpoint is defined. If
interface.
is not equal toclaimed
true
, reject promise with anInvalidStateError
.
-
6.2. Configurations
[(
Constructor USBDevice ,
device octet ),
configurationValue Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBConfiguration readonly attribute octet ;
configurationValue readonly attribute DOMString ?;
configurationName readonly attribute FrozenArray <USBInterface >; };
interfaces
Each device configuration SHALL have a unique configurationValue
that matches the bConfigurationValue
fields of the configuration descriptor that defines it.
The configurationName
attribute SHOULD contain the value
of the string descriptor referenced by the iConfiguration
field of the configuration descriptor, if defined.
The interfaces
attribute SHALL contain a list of
interfaces exposed by this device configuration. These interfaces SHALL by
populated by collecting the interface descriptors contained within this configuration descriptor and organizing them by bInterfaceNumber
.
Include some non-normative information about device configurations. <https://github.com/WICG/webusb/issues/46>
6.3. Interfaces
[(
Constructor USBConfiguration ,
configuration octet ),
interfaceNumber Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBInterface readonly attribute octet ;
interfaceNumber readonly attribute USBAlternateInterface ;
alternate readonly attribute FrozenArray <USBAlternateInterface >;
alternates readonly attribute boolean ; }; [
claimed (
Constructor USBInterface ,
deviceInterface octet ),
alternateSetting Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBAlternateInterface readonly attribute octet ;
alternateSetting readonly attribute octet ;
interfaceClass readonly attribute octet ;
interfaceSubclass readonly attribute octet ;
interfaceProtocol readonly attribute DOMString ?;
interfaceName readonly attribute FrozenArray <USBEndpoint >; };
endpoints
Each interface provides a collection of alternates
identified
by a single bInterfaceNumber
field found in their interface
descriptors. The interfaceNumber
attribute MUST match this
field.
The alternate
attribute SHALL be set to the USBAlternateInterface
that is currently selected for this interface, which
by default SHALL be the one with bAlternateSetting
equal to 0
.
The alternates
attribute SHALL contain a list of all alternate
interface configurations available for this interface.
The claimed
attribute SHALL be set to true
when
the interface is claimed by the current execution context and SHALL be set to false
otherwise.
Each alternative interface configuration SHALL have a unique alternateSetting
within a given interface that
matches the bAlternateSetting
field of the interface
descriptor that defines it.
The interfaceClass
, interfaceSubclass
and interfaceProtocol
attributes declare the
communication interface supported by the interface. They MUST correspond
respectively to the values of the bInterfaceClass
, bInterfaceSubClass
and bInterfaceProtocol
fields of
the interface descriptor.
The interfaceName
attribute SHOULD contain the value
of the string descriptor indexed by the iInterface
field of
the interface descriptor, if defined.
The endpoints
attribute SHALL contain a list of
endpoints exposed by this interface. These endpoints SHALL by populated from
the endpoint descriptors contained within this interface descriptor and the number of elements in this sequence SHALL
match the value of the bNumEndpoints
field of the interface descriptor.
A device’s active configuration is the combination of the USBConfiguration
selected by calling selectConfiguration(configurationValue)
and the set of USBAlternateInterface
s selected by calling selectAlternateInterface(interfaceNumber, alternateSetting)
. A
device MAY, by default, be left in an unconfigured state, referred to as
configuration 0
or may automatically be set to whatever
configuration has bConfigurationValue
equal to 1
.
When a configuration is set all interfaces within that configuration
automatically have the USBAlternateInterface
with bAlternateSetting
equal to 0
selected by default. It
is therefore unnecessary to call selectAlternateInterface(interfaceNumber, alternateSetting)
with alternateSetting equal to 0
for each interface when opening a
device.
6.4. Endpoints
enum {
USBDirection ,
"in" };
"out" enum {
USBEndpointType ,
"bulk" ,
"interrupt" }; [
"isochronous" (
Constructor USBAlternateInterface ,
alternate octet ,
endpointNumber USBDirection ),
direction Exposed =(DedicatedWorker ,SharedWorker ,Window ),SecureContext ]interface {
USBEndpoint readonly attribute octet ;
endpointNumber readonly attribute USBDirection ;
direction readonly attribute USBEndpointType ;
type readonly attribute unsigned long ; };
packetSize
Each endpoint within a particular device configuration SHALL have a unique
combination of endpointNumber
and direction
.
The endpointNumber
MUST equal the 4 least significant bits of
the bEndpointAddress
field of the endpoint descriptor defining the endpoint.
The direction
attribute declares the transfer direction
supported by this endpoint and is equal to "in"
if the most
significant bit of the bEndpointAddress
is set and "out"
otherwise. An endpoint may either carry data IN
from the device to host or OUT
from host to device.
The type
attribute declares the type of data transfer supported
by this endpoint.
The packetSize
attribute declares the packet size employed by
this endpoint and MUST be equal to the value of the wMaxPacketSize
of the endpoint descriptor defining it. In a High-Speed, High-Bandwidth
endpoint this value will include the multiplication factor provided by issuing
multiple transactions per microframe. In a SuperSpeed device this value will
include the multiplication factor provided by the bMaxBurst
field
of the SuperSpeed Endpoint Companion descriptor.
7. Integrations
7.1. Feature Policy
This specification defines a feature that controls whether the usb
attribute is exposed on the Navigator
object.
The feature name for this feature is "usb"
.
The default allowlist for this feature is ["self"]
.
7.2. Permission API
The [permissions] API provides a uniform way for websites to request permissions from users and query which permissions they have.
The "usb"
powerful feature is
defined as follows:
- permission descriptor type
-
dictionary
:USBPermissionDescriptor PermissionDescriptor {sequence <USBDeviceFilter >
; };filters - extra permission data type
-
USBPermissionStorage
, defined as:dictionary
{AllowedUSBDevice required octet
;vendorId required octet
;productId DOMString
; };serialNumber dictionary
{USBPermissionStorage sequence <AllowedUSBDevice >
= []; };allowedDevices AllowedUSBDevice
instances have an internal slot[[devices]]
that holds an array of USB devices. - permission result type
-
interface
:USBPermissionResult PermissionStatus {attribute FrozenArray <USBDevice >
; };devices - permission query algorithm
-
To query the "usb" permission with a
USBPermissionDescriptor
desc, aUSBPermissionStorage
storage, and aUSBPermissionResult
status, the UA must:-
If
desc.
is set then, for each filter infilters
desc.
if filter is not a valid filter then raise afilters
TypeError
and abort these steps. -
Let matchingDevices be a new
Array
. -
For each allowedDevice in
storage.
and for each device inallowedDevices
allowedDevice@
, run the following substeps:[[devices]]
-
If
desc.
is set and device does not match a device filter infilters
desc.
, continue to the next device.filters
-
Get the
USBDevice
representing device and add it to matchingDevices.
-
-
Set
status.
to a newdevices
FrozenArray
whose contents are matchingDevices.
-
- permission request algorithm
- Request the "usb" permission.
8. Terminology
This specification uses several terms taken from [USB31]. While reference is made to version 3.1 of the Universal Serial Bus many of these concepts exist in previous versions as well. Significant differences between USB versions that have bearing on this specification will be called out explicitly.
Descriptors are binary data structures that can be read from a device and describe its properties and function:
-
The device descriptor contains information applicable to the entire devices and is described in section 9.6.1 of [USB31].
-
A configuration descriptor describes a particular set of device interfaces and endpoints that can be selected by the host. Its fields are described in section 9.6.3 of [USB31].
-
An interface descriptor describes the interface of a particular functional component of a device including its protocol and communication endpoints. Its fields are described in section 9.6.5 of [USB31].
-
An interface association descriptor creates an association between multiple interfaces that are part of a single functional unit of a device. Its fields are described in section 9.6.4 of [USB31].
-
An endpoint descriptor describes a channel through which data is either sent to or received from the device. Its fields are described in section 9.6.6 of [USB31].
-
A string descriptor contains a single UTF16-LE string and is referenced by index by other descriptors. Its fields are described in section 9.6.9 of [USB31].
The Binary Object Store (BOS) is an additional set of descriptors that are more free-form than the standard device descriptors. Of note is the Platform Descriptor type which allows third parties (such as this specification) to declare their own types of descriptors. Each of these is identified by a UUID. The Binary Object Store is described in section 9.6.2 of [USB31].
A USB device has a single device descriptor which links to
one or more configuration descriptors. It’s vendor ID is
assigned to the device manufacturer by the USB-IF and is stored in the idVendor
field of the device descriptor. It’s product
ID is assigned by the manufacturer and is stored in the idProduct
field of the device descriptor. It’s serial
number is an optional property that is defined if the iSerialNumber
field of the device descriptor is not equal
to 0
and is the string descriptor referred to by that index.
9. Appendix: A Brief Introduction to USB
This section is non-normative.
USB is a network but it’s very different from traditional TCP/IP networks. It is really more like an RPC system. All traffic is directed by the host, that is, your computer. Though some devices like smartphones can act as both a USB host and USB client they can only take on one role at a time.
9.1. Descriptors
USB devices identify themselves to the host by providing a set of binary structures known as descriptors. The first one read by the host is the device descriptor which contains basic information such as the vendor and product IDs assigned by the USB-IF and the manufacturer. The host may then read the device’s configuration descriptor which is a description of the device’s capabilities including the interfaces and endpoints it exposes. A class can be declared at the device level or for individual interfaces. A device with multiple interfaces providing different functions is known as a composite device.
9.2. Transfers
Whether data is traveling from host to device or the other way around the transfer is always initiated by the host. OUT transfers carry data from host to device and may wait until the device acknowledges the data has been received. IN transfers carry data from device to host and may have to wait until the device has some data to send. Transfers are executed against one of a device’s endpoints and there are different kinds depending on what type of traffic is being sent.
-
Bulk transfers are good for sending lots of data with whatever bandwidth is available. This is what is used to read and write data to USB mass storage devices.
-
Interrupt transfers offer guaranteed latency (by reserving bandwidth so that they can’t be blocked by a large bulk transfers) but with limited packet sizes. These are used for signaling and for small packets like mouse movements and button presses.
-
Isochronous transfers also reserve bandwidth but they don’t guarantee delivery. They’re used for streaming data like audio and video.
-
Every device also has a special default endpoint. While regular endpoints only carry data in one direction or the other control transfers have a small header called the SETUP packet that is always sent to the device and contains request parameters in addition to a larger data payload that can be either IN or OUT.