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 § 10 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
§ 8.1
Permissions
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 sequence <USBDeviceFilter >= []; }; [exclusionFilters Exposed =(Worker ,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 =Worker ,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()
while
the
relevant
global
object
has
a
transient
activation
.
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 andvendorIddeviceDesc .idVendordoes not equalfilter ., returnvendorIdmismatch. -
If
filter .is present andproductIddeviceDesc .idProductdoes not equalfilter ., returnproductIdmismatch. -
If
filter .is present then, let serialNumber be the string descriptor with indexserialNumberdeviceDesc .iSerialNumber. If device returns an error when requesting serialNumber or serialNumber is not equal tofilter ., returnserialNumbermismatch. -
If
filter .is present and, for any of device ’s interface’s interface , interface matches the interface filter filter , returnclassCodematch. -
If
filter .is present andclassCodedeviceDesc .bDeviceClassis not equal tofilter ., returnclassCodemismatch. -
If
filter .is present andsubclassCodedeviceDesc .bDeviceSubClassis not equal tofilter ., returnsubclassCodemismatch. -
If
filter .is present andprotocolCodedeviceDesc .bDeviceProtocolis not equal tofilter ., returnprotocolCodemismatch. -
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 andclassCodedesc .bInterfaceClassis not equal tofilter ., returnclassCodemismatch. -
If
filter .is present andsubclassCodedesc .bInterfaceSubClassis not equal tofilter ., returnsubclassCodemismatch. -
If
filter .is present andprotocolCodedesc .bInterfaceProtocolis not equal tofilter ., returnprotocolCodemismatch. -
Return
match.
A
USBDeviceFilter
filter
is
valid
if
the
following
steps
return
valid
:
-
If
filter .is present andproductIdfilter .is not present, returnvendorIdinvalid. -
If
filter .is present andsubclassCodefilter .is not present, returnclassCodeinvalid. -
If
filter .is present andprotocolCodefilter .is not present, returnsubclassCodeinvalid. -
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
:
-
Let document be this ’s relevant global object 's associated Document , or
nullif there is no associatedDocument. -
Let storage be:
-
The
USBPermissionStorageobject in the script execution environment of the associated service worker client , if this 's relevant global object is aServiceWorkerGlobalScope. -
Otherwise, the
USBPermissionStorageobject in the current script execution environment.
-
-
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 device is blocklisted for document , continue .
-
If this is the first call to this method, check permissions for device with storage .
-
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
USBDeviceobject 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 exclusionFilters: options. exclusionFilters} Let permissionResult be the resulting
Promise. -
Upon fulfillment of permissionResult with result run the following steps:
-
If
result .is empty, throw adevicesNotFoundErrorand abort these steps. -
Return
result ..devices[0]
-
To
request
the
"usb"
permission
,
given
a
Document
document
,
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 afiltersTypeErrorand abort these steps. -
For each exclusionFilter in
options .if exclusionFilter is not a valid filter reject promise with aexclusionFiltersTypeErrorand abort these steps. -
Check that the algorithm was triggered while the relevant global object had a transient activation . Otherwise, reject promise with a
SecurityErrorand abort these steps. -
Set
status .tostate"ask". -
Enumerate all devices attached to the system . Let this result be enumerationResult .
-
Remove devices from enumerationResult if they are blocklisted for document .
-
Remove devices from enumerationResult if they do not match a device filter in
options ..filters -
Remove devices from enumerationResult if they match a device filter in
options ..exclusionFilters -
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 emptydevicesFrozenArray, resolve promise withundefined, and abort these steps. -
Let deviceObj be the
USBDeviceobject representing device . -
Set
status .to a newdevicesFrozenArraycontaining 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 .
To
remove
an
allowed
USB
device
device
,
given
a
USBPermissionStorage
storage
,
the
UA
MUST
run
the
following
steps:
-
Search for an element allowedDevice in
storage .where device is in allowedDevice @allowedDevices[[devices]], if no such element exists, abort these steps. -
Remove allowedDevice from
storage ..allowedDevices
5.1. Events
dictionary :USBConnectionEventInit EventInit {required USBDevice ; }; [device Exposed =(Worker ,Window ),SecureContext ]interface :USBConnectionEvent Event {(constructor DOMString ,type USBConnectionEventInit ); [eventInitDict SameObject ]readonly attribute USBDevice ; };device
Note: Workers may register event listeners for connect and disconnect events but the event listener will not be invoked unless the worker is active.
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
USBPermissionStorageobject 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
USBDeviceobject representing device . -
Fire an event named connect on device ’s relevant global object 's
Navigatorobject’susb, usingUSBConnectionEvent, with thedeviceattribute set to deviceObj .
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
USBPermissionStorageobject 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 .isserialNumberundefinedand allowedDevice @[[devices]]is empty remove allowedDevice fromstorage ..allowedDevices -
Let device be the
USBDeviceobject representing device . -
Fire an event named disconnect on device ’s relevant global object 's
Navigatorobject’susb, usingUSBConnectionEvent, with thedeviceattribute set to device .
6. Device Usage
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 device. 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 ); } }
6.1. The USBDevice Interface
enum {USBTransferStatus ,"ok" ,"stall" }; ["babble" Exposed =(Worker ,Window ),SecureContext ]interface {USBInTransferResult (constructor USBTransferStatus ,status optional DataView ?);data readonly attribute DataView ?;data readonly attribute USBTransferStatus ; }; [status Exposed =(Worker ,Window ),SecureContext ]interface {USBOutTransferResult (constructor USBTransferStatus ,status optional unsigned long = 0);bytesWritten readonly attribute unsigned long ;bytesWritten readonly attribute USBTransferStatus ; }; [status Exposed =(Worker ,Window ),SecureContext ]interface {USBIsochronousInTransferPacket (constructor USBTransferStatus ,status optional DataView ?);data readonly attribute DataView ?;data readonly attribute USBTransferStatus ; }; [status Exposed =(Worker ,Window ),SecureContext ]interface {USBIsochronousInTransferResult (constructor sequence <USBIsochronousInTransferPacket >,packets optional DataView ?);data readonly attribute DataView ?;data readonly attribute FrozenArray <USBIsochronousInTransferPacket >; }; [packets Exposed =(Worker ,Window ),SecureContext ]interface {USBIsochronousOutTransferPacket (constructor USBTransferStatus ,status optional unsigned long = 0);bytesWritten readonly attribute unsigned long ;bytesWritten readonly attribute USBTransferStatus ; }; [status Exposed =(Worker ,Window ),SecureContext ]interface {USBIsochronousOutTransferResult (constructor sequence <USBIsochronousOutTransferPacket >);packets readonly attribute FrozenArray <USBIsochronousOutTransferPacket >; }; [packets Exposed =(Worker ,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 <undefined >open ();Promise <undefined >close ();Promise <undefined >forget ();Promise <undefined >selectConfiguration (octet );configurationValue Promise <undefined >claimInterface (octet );interfaceNumber Promise <undefined >releaseInterface (octet );interfaceNumber Promise <undefined >selectAlternateInterface (octet ,interfaceNumber octet );alternateSetting Promise <USBInTransferResult >controlTransferIn (USBControlTransferParameters ,setup unsigned short );length Promise <USBOutTransferResult >controlTransferOut (USBControlTransferParameters ,setup optional BufferSource );data Promise <undefined >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 <undefined >reset (); };
Instances
of
USBDevice
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[configurations]]
|
An
empty
sequence
of
USBConfiguration
| All configurations supported by this device. |
[[configurationValue]]
| <always set in prose> | The current configuration value of the device. |
[[selectedAlternateSetting]]
| An empty list of integer | The current alternate setting for each interface on the current configuration. |
[[claimedInterface]]
| An empty list of boolean | The claimed status for each interface on the current configuration. |
-
Let deviceDescriptor be the device descriptor of the connected device by performing Get Descriptor with
DescriptorTypeset toDEVICE. -
Return deviceDescriptor .
-
Let deviceDescriptor be the result of finding the device descriptor for the connected USB device .
-
Let numConfigurations be
bNumConfigurationsof deviceDescriptor . -
Let configurationIndex be 0.
-
While configurationIndex is less than numConfigurations :
-
Let descriptors be the a list of descriptors by performing Get Descriptor with
DescriptorTypeset toCONFIGURATIONandDescriptorIndexset to configurationIndex . -
If the
bDescriptorTypeof the descriptors [0] is equal toCONFIGURATION, append descriptors [0] to configurationDescriptors . -
Increment configurationIndex by 1.
-
-
Return configurationDescriptors .
-
Let configuration be interface .
[[configuration]]. -
Let device be configuration .
[[device]]. -
If configuration is not the same as the result of finding the current configuration with device , return.
-
If the result of finding if the interface is claimed with interface is not
true, return. -
Let currAlternateInterface be the result of finding the alternate interface for the current alternate setting with interface .
-
For each endpoint of currAlternateInterface .
[[endpoints]]:-
Abort all transfers currently scheduled on endpoint and reject the associated promises with an
AbortError.
-
-
Let interfaceIndex be 0.
-
While interfaceIndex is less than the size of configuration .
[[interfaces]]:-
If configuration .
[[interfaces]][ interfaceIndex ].[[interfaceNumber]]is equal to interfaceNumber , return interfaceIndex . -
Increment interfaceIndex by 1.
-
-
Return
-1.
-
Let alternateIndex be 0.
-
While alternateIndex is less than the size of interface .
[[alternates]]:-
If interface .
[[alternates]][ alternateIndex ].[[alternateSetting]]is equal to alternateSetting , return alternateIndex . -
Increment alternateIndex by 1.
-
-
Return
-1.
-
For each configuration of device .
[[configurations]]:-
If configuration .
[[configurationValue]]is equal to device .[[configurationValue]], return configuration .
-
-
Return
null.
-
Let configuration be the result of finding the current configuration with device .
-
If configuration is
null, returnnull. -
For each interface of configuration .
[[interfaces]]:-
If the result of finding if the interface is claimed with interface is not
true, continue. -
Let alternate be the result of finding the alternate interface for the current alternate setting with interface .
-
For each endpoint of alternate .
[[endpoints]]:-
If endpoint .
[[endpointAddress]]is equal to endpointAddress , return endpoint
-
-
-
Return
null.
-
If the device is no longer connected to the system, reject promise with a
NotFoundErrorand abort these steps. -
If
device .is notopenedtrue, or device .[[configurationValue]]is equal to0, reject promise with anInvalidStateError.
USBDevice
object
representing
a
connected
USB
device
is
constructed
by
performing
the
following
steps:
-
Set this .
[[configurationValue]]to the returned value of Get Configuration . -
Let configurationDescriptors be the result of finding a list of configuration descriptors for the connected USB device .
-
For each configurationDescriptor of configurationDescriptors :
-
Let configuration be a new
USBConfigurationobject using USBConfiguration( device , configurationValue ) with device set to this and configurationValue set tobConfigurationValueof configurationDescriptor . -
Append configuration to this .
[[configurations]]. -
If
bConfigurationValueof configurationDescriptor is equal to this .[[configurationValue]]:-
Let numInterfaces be the size of configuration .
[[interfaces]]. -
Resize this .
[[selectedAlternateSetting]]to numInterfaces . -
Fill this .
[[selectedAlternateSetting]]with 0. -
Resize this .
[[claimedInterface]]to numInterfaces . -
Fill this .
[[claimedInterface]]withfalse.
-
-
All
USB
devices
MUST
have
a
default
control
pipe
which
is
endpointNumber
0
.
6.1.1. Attributes
-
usbVersionMajor, of type octet , readonlyusbVersionMinor, of type octet , readonlyusbVersionSubminor, of type octet , readonly -
The
usbVersionMajor,usbVersionMinorandusbVersionSubminorattributes declare the USB protocol version supported by the device. They SHALL correspond to the value of thebcdUSBfield of the device descriptor such that a value of0xJJMNhas major versionJJ, minor versionMand subminor versionN. -
deviceClass, of type octet , readonlydeviceSubclass, of type octet , readonlydeviceProtocol, of type octet , readonly -
The
deviceClass,deviceSubclassanddeviceProtocolattributes declare the communication interface supported by the device. They MUST correspond respectively to the values of thebDeviceClass,bDeviceSubClassandbDeviceProtocolfields of the device descriptor . -
vendorId, of type unsigned short , readonlyproductId, of type unsigned short , readonly -
The
vendorIdandproductIdMUST be equal to the device’s vendor ID and product ID . -
deviceVersionMajor, of type octet , readonlydeviceVersionMinor, of type octet , readonlydeviceVersionSubminor, of type octet , readonly -
The
deviceVersionMajor,deviceVersionMinoranddeviceVersionSubminorattributes declare the device release number as defined by the device manufacturer. It SHALL correspond to the value of thebcdDevicefield of the device descriptor such that a value of0xJJMNhas major versionJJ, minor versionMand subminor versionN. -
manufacturerName, of type DOMString , readonly, nullableproductName, of type DOMString , readonly, nullableserialNumber, of type DOMString , readonly, nullable -
The
manufacturerName,productNameandserialNumberattributes SHOULD contain the values of the string descriptors indexed by theiManufacturer,iProductandiSerialNumberfields of the device descriptor if each is defined. -
configuration, of type USBConfiguration , readonly, nullable -
The
configurationattribute contains the currently selected configuration for the device and SHALL be one of theUSBConfigurationinconfigurations.The
configurationgetter steps are:-
Return the result of finding the current configuration with this .
-
-
configurations, of type FrozenArray< USBConfiguration >, readonly -
The
configurationsattribute contains a sequence ofUSBConfigurationrepresenting configurations supported by the device.The
configurationsgetter steps are:-
Return this .
[[configurations]].
-
-
opened, of type boolean , readonly -
The
openedattribute SHALL be set totruewhen the device is opened by the current execution context and SHALL be set tofalseotherwise.
6.1.2. Methods
open()
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
If this is no longer connected to the system, reject promise with a
NotFoundErrorand abort these steps. -
If
this .isopenedtrueresolve 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
NetworkErrorand abort these steps.
close()
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
If this is no longer connected to the system, reject promise with a
NotFoundErrorand abort these steps. -
If
this .isopenedfalseresolve 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.
Note:
When
no
[ECMAScript]
code
can
observe
an
instance
of
USBDevice
device
anymore,
the
UA
SHOULD
run
device
.
close()
.
forget()
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Let device be this .
-
Let storage be the
USBPermissionStorageobject in the current script execution environment. -
Remove device from storage with storage .
-
Resolve promise .
Note: The user agent MAY decide to combine permissions across APIs, for instance tracking WebHID + WebUSB device access under a unified low-level device access permission. For this reason, this method may also revoke additional (unspecified yet) permissions in the future.
selectConfiguration(
configurationValue
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
If this is no longer connected to the system, reject promise with a
NotFoundErrorand abort these steps. -
Let selectedConfiguration be
null. -
For each configuration of this .
[[configurations]]:-
If configuration .
[[configurationValue]]is equal to configurationValue , set selectedConfiguration to configuration and break.
-
-
If selectedConfiguration is
null, reject promise with aNotFoundErrorand abort these steps. -
If
this .is not equal toopenedtruereject promise with anInvalidStateErrorand abort these steps. -
Let activeConfiguration be the result of finding the current configuration with this .
-
If activeConfiguration is not
null.-
For each interface of activeConfiguration .
[[interfaces]]:-
Abort transfers currently scheduled on an interface with interface .
-
-
-
Issue a
SET_CONFIGURATIONcontrol transfer withconfigurationValueset to the configurationValue . If this step fails reject promise with aNetworkErrorand abort these steps. -
Let numInterfaces be the size of selectedConfiguration .
[[interfaces]]. -
Resize this .
[[selectedAlternateSetting]]to numInterfaces . -
Fill this .
[[selectedAlternateSetting]]with 0. -
Resize this .
[[claimedInterface]]to numInterfaces . -
Fill this .
[[claimedInterface]]withfalse. -
Set this .
[[configurationValue]]to configurationValue and resolve promise .
claimInterface(
interfaceNumber
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let activeConfiguration be the result of finding the current configuration with this .
-
Let interfaces be activeConfiguration .
[[interfaces]]. -
Let interfaceIndex be the result of finding the interface index with interfaceNumber and activeConfiguration .
-
If interfaceIndex is equal to
-1, reject promise with aNotFoundErrorand abort these steps. -
If this .
[[claimedInterface]][ interfaceIndex ] istrue, resolve promise and abort these steps. -
Let unrestricted be
false. -
Let document be this ’s relevant global object 's associated Document , or
nullif there is no associatedDocument. -
If document is not
nulland document is allowed to use the policy-controlled feature named"usb-unrestricted", set unrestricted totrue. -
If interfaces [ interfaceIndex ].
[[isProtectedClass]]istrueand unrestricted isfalse, reject promise with aSecurityErrorand abort these steps. -
Perform the necessary platform-specific steps to request exclusive control over interfaces [ interfaceIndex ] for the current execution context. If this fails, reject promise with a
NetworkErrorand abort these steps. -
Set this .
[[claimedInterface]][ interfaceIndex ] totrueand resolve promise .
releaseInterface(
interfaceNumber
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let activeConfiguration be the result of finding the current configuration with this .
-
Let interfaces be activeConfiguration .
[[interfaces]]. -
Let interfaceIndex be the result of finding the interface index with interfaceNumber and activeConfiguration .
-
If interfaceIndex is equal to
-1, reject promise with aNotFoundErrorand abort these steps. -
If this .
[[claimedInterface]][ interfaceIndex ] isfalse, resolve promise and abort these steps. -
Perform the necessary platform-specific steps to reliquish exclusive control over interfaces [ interfaceIndex ].
-
Set this .
[[selectedAlternateSetting]][ interfaceIndex ] to0. -
Set this .
[[claimedInterface]][ interfaceIndex ] tofalseand resolve promise .
selectAlternateInterface(
interfaceNumber
,
alternateSetting
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let activeConfiguration be the result of finding the current configuration with this .
-
Let interfaces be activeConfiguration .
[[interfaces]]. -
Let interfaceIndex be the result of finding the interface index with interfaceNumber and activeConfiguration .
-
If interfaceIndex is equal to
-1, reject promise with aNotFoundErrorand abort these steps. -
If this .
[[claimedInterface]][ interfaceIndex is nottrue, reject promise with anInvalidStateErrorand abort these steps. -
Let interface be interfaces [ interfaceIndex ].
-
Let alternateIndex be the result of finding the alternate index with alternateSetting and interface .
-
If alternateIndex is equal to
-1, reject promise with aNotFoundErrorand abort these steps. -
Abort transfers currently scheduled on an interface with interface .
-
Issue a
SET_INTERFACEcontrol transfer withinterfaceNumberset to the interfaceNumber andalternateSettingset to the alternateSetting . If this step fails reject promise with aNetworkErrorand abort these steps. -
Set this .
[[selectedAlternateSetting]][ interfaceIndex ] to alternateSetting . -
Resolve promise .
controlTransferIn(
setup
,
length
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Check the validity of the control transfer parameters with this 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 this with the setup packet parameters provided in setup , the data transfer direction in
bmRequestTypeset to "device to host" andwLengthset 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 the device create a new
ArrayBuffercontaining the first bytesTransferred bytes of buffer and setresult .to a newdataDataViewconstructed over it. -
If the device responded by stalling the default control pipe set
result .tostatus"stall". -
If the 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
NetworkErrorand abort these steps. -
Resolve promise with result .
controlTransferOut(
setup
,
data
)
method,
when
invoked,
must
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Check the validity of the control transfer parameters with this 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
bmRequestTypeset to "host to device" andwLengthset 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 .tobytesWrittendata .length. -
If the transfer fails for any other reason reject promise with a
NetworkErrorand abort these steps. -
Resolve promise with result .
clearHalt(
direction
,
endpointNumber
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let endpointAddress be
endpointNumber | 0x80if direction is equal to"in", and endpointNumber otherwise. -
Let endpoint be the result of finding the endpoint with endpointAddress and this .
-
If endpoint is
null, reject promise with aNotFoundErrorand 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 .
transferIn(
endpointNumber
,
length
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let endpointAddress be
endpointNumber | 0x80(i.e"in"direction). -
Let endpoint be the result of finding the endpoint with endpointAddress and this .
-
If endpoint is
null, reject promise with aNotFoundErrorand abort these steps. -
If endpoint .
typeis not equal to"bulk", reject promise with anInvalidAccessErrorand 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 the device create a new
ArrayBuffercontaining the first bytesTransferred bytes of buffer and setresult .to a newdataDataViewconstructed over it. -
If the 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 the device acknowledged the complete transfer set
result .tostatus"ok". -
If the transfer failed for any other reason reject promise with a
NetworkErrorand abort these steps. -
Resolve promise with result .
transferOut(
endpointNumber
,
data
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let endpointAddress be endpointNumber (i.e
"out"direction). -
Let endpoint be the result of finding the endpoint with endpointAddress and this .
-
If endpoint is
null, reject promise with aNotFoundErrorand abort these steps. -
If endpoint .
typeis not equal to"bulk", reject promise with anInvalidAccessErrorand 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
NetworkErrorand abort these steps. -
Resolve promise with result .
isochronousTransferIn(
endpointNumber
,
packetLengths
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let endpointAddress be
endpointNumber | 0x80(i.e"in"direction). -
Let endpoint be the result of finding the endpoint with endpointAddress and this .
-
If endpoint is
null, reject promise with aNotFoundErrorand abort these steps. -
If endpoint .
typeis not equal to"isochronous", reject promise with anInvalidAccessErrorand abort these steps. -
Let length be the sum of the elements of packetLengths .
-
Let buffer be a new
ArrayBufferof length bytes. -
Let result be a new
USBIsochronousInTransferResultand setresult .to a newdataDataViewconstructed 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
0topacketLengths .length - 1:-
Let packet be a new
USBIsochronousInTransferPacketand setresult .to packet .packets[ i ] -
Let view be a new
DataViewover 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
NetworkErrorand abort these steps.
-
-
Resolve promise with result .
isochronousTransferOut(
endpointNumber
,
data
,
packetLengths
)
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
Let endpointAddress be endpointNumber (i.e
"out"direction). -
Let endpoint be the result of finding the endpoint with endpointAddress and this .
-
If endpoint is
null, reject promise with aNotFoundErrorand abort these steps. -
If endpoint .
typeis not equal to"isochronous", reject promise with anInvalidAccessErrorand abort these steps. -
Let result be a new
USBIsochronousOutTransferResult. -
Enqueue an isochronous OUT transfer on endpoint that will write data to the device, divided into
packetLength .lengthpackets ofpacketLength [i]bytes (for packets i from0topacketLengths .length - 1). -
For each packet i from
0topacketLengths .length - 1the host attempts to send to the device:-
Let packet be a new
USBIsochronousOutTransferPacketand 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
NetworkErrorand abort these steps.
-
-
Resolve promise with result .
reset()
method,
when
invoked,
MUST
return
a
new
Promise
promise
and
run
the
following
steps
in
parallel
:
-
Check if the device is configured with this and promise and abort these steps if promise is rejected.
-
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? [Issue #36]
6.2. The USBControlTransferParameters Dictionary
enum {USBRequestType ,"standard" ,"class" };"vendor" enum {USBRecipient ,"device" ,"interface" ,"endpoint" };"other" dictionary {USBControlTransferParameters required USBRequestType requestType ;required USBRecipient recipient ;required octet request ;required unsigned short value ;required unsigned short ; };index
-
Let setup be the
USBControlTransferParameterscreated for the transfer. -
Let promise be the promise created for the transfer.
-
Let configuration be the result of finding the current configuration with device .
-
If configuration is
null, abort these steps. -
If
setup .isrecipient"interface", perform the following steps:-
Let interfaceNumber be the lower 8 bits of
setup ..index -
Let interfaceIndex be the result of finding the interface index with interfaceNumber and configuration .
-
If interfaceIndex is equal to
-1, reject promise with aNotFoundErrorand abort these steps. -
Let interface be configuration .
[[interfaces]][ interfaceIndex ]. -
If the result of finding if the interface is claimed with interface is not
true, reject promise with anInvalidStateErrorand abort these steps.
-
-
If
setup .isrecipient"endpoint", run the following steps:-
Let endpointAddress be setup .
index. -
Let endpoint be the result of finding the endpoint with endpointAddress and device .
-
If endpoint is
null, reject promise with aNotFoundErrorand abort these steps. -
Let alternate be endpoint .
[[alternateInterface]]. -
Let interface be alternate .
[[interface]]. -
If the result of finding if the interface is claimed with interface is not
true, reject promise with anInvalidStateErrorand abort these steps.
-
6.2.1. Members
-
requestType, of type USBRequestType -
The
requestTypeattribute populates part of thebmRequestTypefield 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. -
recipient, of type USBRecipient -
The
recipientattribute populates part of thebmRequestTypefield of the setup packet to indicate whether the control transfer is addressed to the entire device, or a specific interface or endpoint. -
request, of type octet -
The
requestattribute populates thebRequestfield of the setup packet . Valid requests are defined by the USB standard, USB device class specifications or the device vendor. -
value, of type unsigned short -
The
valueandindexattributes populate thewValueandwIndexfields of the setup packet respectively. The meaning of these fields depends on the request being made.
6.3. The USBConfiguration Interface
[Exposed =(Worker ,Window ),SecureContext ]interface {USBConfiguration constructor (USBDevice ,device octet );configurationValue readonly attribute octet configurationValue ;readonly attribute DOMString ?configurationName ;readonly attribute FrozenArray <USBInterface >interfaces ; };
Instances
of
USBConfiguration
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[device]]
| <always set in prose> |
The
USBDevice
object
this
belongs
to.
|
[[interfaces]]
|
An
empty
sequence
of
USBInterface
| All interfaces supported this configuration. |
[[configurationValue]]
| <always set in prose> | The configuration value for this configuration. |
-
Let deviceDescriptor be the result of finding the device descriptor for the connected USB device .
-
Let numConfigurations be
bNumConfigurationsof deviceDescriptor . -
Let configurationIndex be 0.
-
While configurationIndex is less than numConfigurations :
-
Let descriptors be the a list of descriptors by performing Get Descriptor with
DescriptorTypeset toCONFIGURATIONandDescriptorIndexset to configurationIndex . -
If
bDescriptorTypeof descriptors [0] is equal toCONFIGURATIONandbConfigurationValueof descriptors is equal to configurationValue , return descriptors . -
Increment configurationIndex by 1.
-
-
Return empty result.
6.3.1. Constructors
USBConfiguration(
device
,
configurationValue
)
constructor
MUST,
when
called,
perform
the
following
steps:
-
Set this .
[[device]]to device . -
Set this .
[[configurationValue]]to configurationValue . -
Let descriptors be the result of finding a list of descriptors for a configuration with
configurationValueset to configurationValue . -
Let seen be an empty ordered set .
-
For each descriptor of descriptors :
-
If the
bDescriptorTypeof the descriptor is not equal toINTERFACE, continue. -
If the
bInterfaceNumberof the descriptor is in seen , continue. -
Let interface be a new
USBInterfaceobject using USBInterface( configuration , interfaceNumber ) with configuration set to this and interfaceNumber set tobInterfaceNumberof descriptor . -
Append interface to this .
[[interfaces]]. -
Append
bInterfaceNumberof descriptor to seen .
-
6.3.2. Attributes
-
configurationValue, of type octet , readonly -
Each device configuration SHALL have a unique
configurationValuethat matches thebConfigurationValuefields of the configuration descriptor that defines it. -
configurationName, of type DOMString , readonly, nullable -
The
configurationNameattribute SHOULD contain the value of the string descriptor referenced by theiConfigurationfield of the configuration descriptor , if defined. -
interfaces, of type FrozenArray< USBInterface >, readonly -
The
interfacesattribute SHALL contain a list of interfaces exposed by this device configuration.The
interfacesgetter steps are:-
Return this .
[[interfaces]].
-
Include some non-normative information about device configurations. [Issue #46]
6.4. The USBInterface Interface
[Exposed =(Worker ,Window ),SecureContext ]interface {USBInterface constructor (USBConfiguration ,configuration octet );interfaceNumber readonly attribute octet interfaceNumber ;readonly attribute USBAlternateInterface alternate ;readonly attribute FrozenArray <USBAlternateInterface >alternates ;readonly attribute boolean claimed ; };
Instances
of
USBInterface
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[configuration]]
| <always set in prose> |
The
USBConfiguration
object
this
belongs
to.
|
[[interfaceNumber]]
| <always set in prose> | The interface number for this interface. |
[[alternates]]
|
An
empty
sequence
of
USBAlternateInterface
| All alternate settings supported by this interface. |
[[isProtectedClass]]
|
false
| If this interface has any alternate setting belonging to a protected class. |
An
interface
descriptor
interface
has
a
protected
interface
class
if
and
only
if
interface
’s
bInterfaceClass
is
equal
to
one
of
the
following
values.
| Code | Description |
|---|---|
0x01
| Audio |
0x03
| HID (Human Interface Device) |
0x08
| Mass Storage |
0x0B
| Smart Card |
0x0E
| Video |
0x10
| Audio/Video Devices |
0xE0
| Wireless Controller |
Note: This specification attempts to strike a balance between protecting users from malicious content by limiting access to sensitive devices while enabling support for as many devices as possible. As stated in the introduction the goal of this API is to support devices which are not covered by other, more high level APIs. The list above includes interface classes for which such high level APIs exist and provide greater protection for user privacy and security than low level access through this API would.
-
Let configuration be interface .
[[configuration]]. -
Let device be configuration .
[[device]]. -
If configuration is not the same as the result of finding the current configuration with device , return
false. -
Let interfaceIndex be the result of finding the interface index with interface .
[[interfaceNumber]]and configuration . -
Assert : interfaceIndex is not equal to
-1. -
Return device .
[[claimedInterface]][ interfaceIndex ].
-
Let configuration be interface .
[[configuration]]. -
Let device be configuration .
[[device]]. -
Let alternateIndex be 0.
-
If the result of finding if the interface is claimed with interface is
true:-
Let interfaceIndex be the result of finding the interface index with interface .
[[interfaceNumber]]and configuration . -
Assert : interfaceIndex is not equal to
-1. -
Set alternateIndex to be the result of finding the alternate index with device .
[[selectedAlternateSetting]][ interfaceIndex ] and interface .
-
-
Assert : alternateIndex is not equal to
-1. -
Return interface .
alternates[ alternateIndex ].
Note: There is at least one alternate setting for an interface according to Interface Descriptor [USB31] , as there must at least one alternate setting in the Interface Descriptor .
6.4.1. Constructors
USBInterface(
configuration
,
interfaceNumber
)
constructor
MUST,
when
called,
perform
the
following
steps:
-
Set this .
[[configuration]]to configuration . -
Set this .
[[interfaceNumber]]to interfaceNumber . -
Let descriptors be the result of finding a list of descriptors for a configuration with
configurationValueset to configuration .[[configurationValue]]. -
For each descriptor of descriptors :
-
If
bDescriptorTypeof descriptor is not equal toINTERFACE, continue. -
If
bInterfaceNumberof descriptor is not equal to interfaceNumber , continue. -
If descriptor has a protected interface class , set this .
[[isProtectedClass]]totrue. -
Let alternate be a new
USBAlternateInterfaceobject using USBAlternateInterface( deviceInterface , alternateSetting ) with deviceInterface set to this and alternateSetting set to thebAlternateSettingof the descriptor . -
Append alternate to this .
[[alternates]].
-
6.4.2. Attributes
-
interfaceNumber, of type octet , readonly -
Each interface provides a collection of
alternatesidentified by a singlebInterfaceNumberfield found in their interface descriptors . TheinterfaceNumberattribute MUST match this field.The
interfaceNumbergetter steps are:.-
Return this .
[[interfaceNumber]].
-
-
alternate, of type USBAlternateInterface , readonly -
The
alternateattribute SHALL be set to theUSBAlternateInterfacethat is currently selected for this interface, which by default SHALL be the one withbAlternateSettingequal to0.The
alternategetter steps are:-
Return the result of finding the alternate interface for the current alternate setting with this .
-
-
alternates, of type FrozenArray< USBAlternateInterface >, readonly -
The
alternatesmethod provides a collection ofUSBAlternateInterfaceobjects identified by a singlebInterfaceNumberfield found in their interface descriptors .The
alternatesgetter steps are:-
Return this .
[[alternates]].
-
-
claimed, of type boolean , readonly -
The
claimedattribute SHALL be set totruewhen the interface is claimed by the current execution context and SHALL be set tofalseotherwise.The
claimedgetter steps are:-
Return the result of finding if the interface is claimed with this .
-
6.5. The USBAlternateInterface Interface
[Exposed =(Worker ,Window ),SecureContext ]interface {USBAlternateInterface constructor (USBInterface ,deviceInterface octet );alternateSetting 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 ; };
Instances
of
USBAlternateInterface
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[interface]]
| <always set in prose> |
The
USBInterface
object
this
belongs
to.
|
[[endpoints]]
|
An
empty
sequence
of
USBEndpoint
| All endpoints exposed by this interface. |
[[alternateSetting]]
| <always set in prose> | The alternate setting for this interface. |
-
Let descriptors as a result of finding a list of descriptors for a configuration with configurationValue .
-
Let endpointDescriptors as an empty list .
-
Let index be 0.
-
While index is less than the size of descriptors :
-
Let descriptor be descriptors [ index ].
-
If
bDescriptorTypeof descriptor is not equal toINTERFACE, increment index by 1 and continue. -
if
bInterfaceNumberof descriptor is not equal interfaceNumber , increment index by 1 and continue. -
if
bAlternateSettingof descriptor is not equal alternateSetting , increment index by 1 and continue. -
If
bNumEndpointsis equal to 0, return endpointDescriptors . -
Let numEndpoints be
bNumEndpointsof descriptor . -
Let indexEndpoints be 0.
-
Let offset be index + 1
-
While indexEndpoints is less than numEndpoints :
-
Append descriptors [ indexEndpoints + offset ] to endpointDescriptors .
-
Increment indexEndpoints by 1.
-
-
Return endpointDescriptors .
-
6.5.1. Constructors
USBAlternateInterface(
deviceInterface
,
alternateSetting
)
constructor
MUST,
when
called,
perform
the
following
steps:
-
Set this .
[[interface]]to deviceInterface . -
Set this .
[[alternateSetting]]to be alternateSetting . -
Let descriptors be the result of finding a list of endpoint descriptors with
interfaceNumberset to deviceInterface .interfaceNumber,alternateSettingset to alternateSetting , andconfigurationValueset to deviceInterface .[[configuration]].[[configurationValue]]. -
For each descriptor of descriptors :
-
If
bmAttributesof descriptor indicates it is a Control Transfer Type (i.e. bits0..1is00according to endpoint descriptor ), continue. -
Let endpointAddress be
bEndpointAddressof descriptor . -
Let dir be
"out"ifendpointAddress & 0x80is0, and"in"otherwise. -
Let endpoint be a new
USBEndpointobject using USBEndpoint( alternate , endpointNumber , direction ) with alternate set to this , endpointNumber set toendpointAddress & 0xF, and direction set to dir . -
Append endpoint to this .
[[endpoints]].
-
6.5.2. Attributes
-
alternateSetting, of type octet , readonly -
Each alternative interface configuration SHALL have a unique
alternateSettingwithin a given interface that matches thebAlternateSettingfield of the interface descriptor that defines it. -
interfaceClass, of type octet , readonlyinterfaceSubclass, of type octet , readonlyinterfaceProtocol, of type octet , readonly -
The
interfaceClass,interfaceSubclassandinterfaceProtocolattributes declare the communication interface supported by the interface. They MUST correspond respectively to the values of thebInterfaceClass,bInterfaceSubClassandbInterfaceProtocolfields of the interface descriptor . -
interfaceName, of type DOMString , readonly, nullable -
The
interfaceNameattribute SHOULD contain the value of the string descriptor indexed by theiInterfacefield of the interface descriptor , if defined. -
endpoints, of type FrozenArray< USBEndpoint >, readonly -
The
endpointsattribute 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 thebNumEndpointsfield of the interface descriptor .The
endpointsgetter steps are:-
Return this .
[[endpoints]].
-
6.6. The USBEndpoint Interface
enum {USBDirection ,"in" };"out" enum {USBEndpointType ,"bulk" ,"interrupt" }; ["isochronous" Exposed =(Worker ,Window ),SecureContext ]interface {USBEndpoint (constructor USBAlternateInterface ,alternate octet ,endpointNumber USBDirection );direction readonly attribute octet endpointNumber ;readonly attribute USBDirection direction ;readonly attribute USBEndpointType type ;readonly attribute unsigned long packetSize ; };
Instances
of
USBEndpoint
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[alternateInterface]]
| <always set in prose> |
The
USBAlternateInterface
object
this
belongs
to.
|
[[endpointAddress]]
| <always set in prose> | The endpoint address of this endpoint. |
-
Let alternateInterface be endpoint .
[[alternateInterface]]. -
Let interface be alternateInterface .
[[interface]]. -
Let configuration be interface .
[[configuration]]. -
Let endpointDescriptors be the result of finding a list of endpoint descriptors with
alternateSettingset to alternateInterface .alternateSetting,interfaceNumberset to interface .interfaceNumber, andconfigurationValueset to configuration .configurationValue. -
For each endpointDescriptor of endpointDescriptors :
-
If endpoint .
[[endpointAddress]]is equal tobEndpointAddressof endpointDescriptor , return endpointDescriptor .
-
6.6.1. Constructors
endpointNumber(
alternate
,
endpointNumber
,
direction
)
constructor
MUST,
when
called,
perform
the
following
steps:
-
Set this .
[[alternateInterface]]to alternate . -
Set endpointAddress to
endpointNumber | 0x80If direction is"in", and endpointNumber otherwise. -
Set this .
[[endpointAddress]]to endpointAddress .
6.6.2. Attributes
-
endpointNumber, of type octet , readonlydirection, of type USBDirection , readonly -
Each endpoint within a particular device configuration SHALL have a unique combination of
endpointNumberanddirection. TheendpointNumberMUST equal the 4 least significant bits of thebEndpointAddressfield of the endpoint descriptor defining the endpoint.The
directionattribute declares the transfer direction supported by this endpoint and is equal to"in"if the most significant bit of thebEndpointAddressis set and"out"otherwise. An endpoint may either carry dataINfrom the device to host orOUTfrom host to device. -
type, of type USBEndpointType , readonly -
The
typeattribute declares the type of data transfer supported by this endpoint.The
typegetter steps are:-
Let endpointDescriptor be the result of finding the endpoint descriptor with this .
-
Let attr be
bmAttributesof endpointDescriptor . -
Let typeBits be
attr & 0x3. -
If typeBits is equal to
b01, return"isochronous". -
If typeBits is equal to
b10, return"bulk". -
If typeBits is equal to
b11, return"interrupt".
Note: There shouldn’t be any endpoint object belongs to Control Transfer Type according to the steps in USBAlternateInterface(deviceInterface,alternateSetting) .
-
-
packetSize, of type unsigned long , readonly -
The
packetSizeattribute declares the packet size employed by this endpoint and MUST be equal to the value of thewMaxPacketSizeof 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 thebMaxBurstfield of the SuperSpeed Endpoint Companion descriptor.The
packetSizegetter steps are:-
Let endpointDescriptor be the result of finding the endpoint descriptor with this .
-
Return
wMaxPacketSizeof endpointDescriptor .
-
7. The USB Blocklist
// USBBlocklistEntry is never exposed.dictionary {USBBlocklistEntry required unsigned short ;idVendor required unsigned short ;idProduct required unsigned short ; };bcdDevice
This specification relies on a blocklist.txt file in this repository to restrict the set of devices a website can access.
The
result
of
parsing
the
blocklist
at
a
URL
url
is
a
list
of
USBBlocklistEntry
objects
produced
by
the
following
algorithm:
-
Fetch url and let contents be its body, decoded as UTF-8.
-
Let lines be the result of strictly splitting contents starting from the beginning of contents on code point
'\n'. -
Let blocklist be an empty list .
-
For each line of lines :
-
Set line to the result of collecting a sequence of code points not equal to
'#'from line starting from the beginning of line . -
Set line to the result of stripping leading and trailing ASCII whitespace from line .
-
Let components be the result of strictly splitting line starting from the beginning of line on code point
':'. -
Let idVendor be the result of interpreting components [0] as a hexadecimal number.
-
Let idProduct be the result of interpreting components [1] as a hexadecimal number.
-
Let bcdDevice be
0xFFFF. -
If the size of components is 3, set bcdDevice to the result of interpreting components [2] as a hexadecimal number.
-
Append a new
USBBlocklistEntrywith idVendor , idProduct , and bcdDevice to blocklist .
-
-
Return blocklist .
The USB blocklist is the result of parsing the blocklist at https://raw.githubusercontent.com/WICG/webusb/main/blocklist.txt . The UA should re-fetch the blocklist periodically, but it’s unspecified how often.
A
USBDevice
device
is
blocklisted
for
a
Document
document
if
the
following
steps
return
"blocked":
-
If document is not
nulland document is allowed to use the policy-controlled feature named"usb-unrestricted", return "not blocked". -
For each entry of the USB blocklist :
-
If device .
vendorIdis not equal to entry .idVendor, continue . -
If device .
productIdis not equal to entry .idProduct, continue . -
Let bcdDevice be device .
deviceVersionMajor<< 8 + device .deviceVersionMinor<< 4 + device .deviceVersionSubminor. -
If bcdDevice is less than or equal to entry .
bcdDevice, return "blocked".
-
-
Return "not blocked".
8. Integrations
8.1. Permissions Policy
This
specification
defines
a
policy-controlled
feature
,
identified
by
the
token
"usb"
,
that
controls
whether
the
usb
attribute
is
exposed
on
the
Navigator
object.
The
default
allowlist
for
this
feature
is
["self"]
.
This
specification
defines
a
second
policy-controlled
feature
,
identified
by
the
token
"usb-unrestricted"
,
that
controls
whether
blocklisted
USB
devices
and
device
interfaces
with
protected
classes
can
be
accessed.
This
feature
MUST
only
be
enabled
for
Isolated
Web
Apps
that
declare
the
feature
in
the
Web
Application
Manifest
[APPMANIFEST]
.
The
default
allowlist
for
this
feature
is
["self"]
.
Typically
this
would
imply
that
the
feature
is
allowed
in
Document
s
in
top-level
traversables
by
default.
However,
due
to
the
requirement
that
this
feature
is
only
enabled
for
Isolated
Web
Apps
with
the
feature
declared
in
the
manifest,
the
effective
default
allowlist
is
["none"]
.
8.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 sequence <USBDeviceFilter >; };exclusionFilters - extra permission data type
-
USBPermissionStorage, defined as:dictionary {AllowedUSBDevice required octet ;vendorId required octet ;productId DOMString ; };serialNumber dictionary {USBPermissionStorage sequence <AllowedUSBDevice >= []; };allowedDevices AllowedUSBDeviceinstances have an internal slot[[devices]]that holds an array of USB devices . - permission result type
-
[
Exposed =(Worker ,Window )]interface :USBPermissionResult PermissionStatus {attribute FrozenArray <USBDevice >; };devices - permission query algorithm
-
To
query
the
"usb"
permission
with
a
USBPermissionDescriptordesc , aUSBPermissionStoragestorage , and aUSBPermissionResultstatus , the UA must:-
If
desc .is set then, for each filter infiltersdesc .if filter is not a valid filter then raise afiltersTypeErrorand abort these steps. -
If
desc .is set then, for each exclusionFilter inexclusionFiltersdesc .if exclusionFilter is not a valid filter then raise aexclusionFiltersTypeErrorand abort these steps. -
Let matchingDevices be a new
Array. -
For each allowedDevice in
storage .and for each device inallowedDevicesallowedDevice @, run the following substeps:[[devices]]-
If
desc .is set and device does not match a device filter infiltersdesc ., continue to the next device .filters -
If
desc .is set and device matches a device filter inexclusionFiltersdesc ., continue to the next device .exclusionFilters -
Get the
USBDevicerepresenting device and add it to matchingDevices .
-
-
Set
status .to a newdevicesFrozenArraywhose contents are matchingDevices .
-
- permission request algorithm
- Request the "usb" permission .
9. 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.
The Get Configuration is a request to the current device configuration value, described in in section 9.4.2 of [USB31] .
The Set Descriptor is a request to get the descriptor with specified Descriptor Type and Descriptor Index, described in in section 9.4.8 of [USB31] .
The Get Descriptor is a request to get the descriptor with specified Descriptor Type and Descriptor Index, described in in section 9.4.3 of [USB31] .
Note: As descriptors of the device stay the same for the most of the time (with occasional occurrences of Set Descriptor which might modify the descriptors ). In order to save the redundant Get Descriptor traffic to the device, implementations could have a read-through & write-through cache layer to store the descriptors of the device.
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.
10. 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.
10.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 .
10.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.