1. はじめに
このセクションは非規範です。
ユニバーサル・シリアル・バス(USB)は、有線周辺機器における事実上の標準です。 ほとんどのUSBデバイスは、およそ十数種類の標準「デバイスクラス」のいずれかを実装しており、 これらはデバイスがサポートする機能やその機能の使い方に関するコマンド・データフォーマットを広告する方法を決定します。標準デバイスクラスにはキーボード、マウス、オーディオ、ビデオ、ストレージデバイスなどがあります。OSはこのようなデバイスを、OSベンダが提供する「クラスドライバー」でサポートします。しかし標準化されたデバイスクラスには当てはまらない膨大な種類のデバイスも存在します。こうしたデバイスでは、ハードウェアベンダが独自のネイティブドライバーやSDKを書く必要があり、開発者はそれを利用することになりますが、このネイティブコードによりウェブからデバイスを利用することができなくなります。
WebUSB APIは、USBデバイスサービスを安全にウェブに公開する方法を提供します。 これは既存のネイティブUSBライブラリに慣れ親しんだ開発者にも分かりやすいAPIとなっており、既存仕様で定義されたデバイスインターフェイスも公開します。このAPIによってハードウェアメーカは自社デバイス用のクロスプラットフォームJavaScript SDKを構築できるようになります。これにより、新種のデバイスがウェブブラウザに特化したAPIを提供するほど普及するのを待つ必要がなく、ウェブ向けの革新的なハードウェアが初日から作れるようになり、ウェブにとって大きな利点になります。
USBについての詳細は§ 10 付録: USBの簡単な紹介をご覧ください。
2. 動機付けとなるアプリケーション
このセクションは非規範です。
2.1. 教育用デバイス
ウェブのソフトウェア配信モデルは教育アプリケーションにとって重要な要素です。なぜなら、それらはプラットフォーム互換性や管理者権限といった問題なく、どのコンピューターにもすぐロードできるからです。理科の授業ではコンピュータを使った計測やデータロギングが導入されています。これらのツールにはバンドルソフトウェアが必要ですが、新たなネイティブアプリが管理されたPCに増えるたび、IT部門に負担がかかりインストールも困難です。ウェブベースのハードウェアAPIにより、これらデバイスへの対応を既存のオンライン教材に直接組み込めるため、完全にシームレスな体験を実現できます。
多くのマイコン開発キットでプログラミングを学んでいる学生は、オンラインの開発ツールを使って自分のコードを書いたりアップロードできます。こうしたツールはすでに存在しますが、ブラウザとハードウェア間のインターフェイスにはネイティブコンポーネントが必要です。このネイティブな拡張は参入障壁となり、またウェブのサンドボックス環境内で動作するコードでは発生しないセキュリティ脆弱性をユーザーにさらすおそれがあります。
2.2. ウェブドライバー
ウェブの構成可能性によって、すべてウェブ技術だけで新しいハードウェアサポートのエコシステムを構築できます。3Dプリンターを例に取ると、3Dオブジェクト設計をホストしているサイトが直接印刷機能をそのページに統合したいとします。ウェブは2D印刷はサポートしていますが、3D用APIはありません。もしハードウェアベンダがWebUSB APIを使ってプリンタへデータを送る埋め込みページを公開すれば、他サイトもこうしたページを活用して、既存の地図埋め込みと同じような形でハードウェア連携機能を追加できます。
2.3. デバイスの更新と診断
Bluetoothのような無線プロトコルが消費者向けデバイスで便利な選択肢になる一方、USBポートは電源供給の容易な手段として、またデバイスが動作しない場合最後の接続手段として普及し続けています。サポートサイトに更新・診断ツールを統合することで、ハードウェアメーカーはプラットフォームを問わず顧客にツールを提供し、サポート問い合わせ時により良好な診断データを収集できます。ランディングページによって、メーカーはユーザーを自社ウェブサイトの該当サポート箇所へ誘導できます。
3. セキュリティおよびプライバシーの考慮事項
このセクションは非規範です。
WebUSB APIは強力な機能を持つため、ユーザーに新たなプライバシーおよびセキュリティリスクをもたらす可能性があります。こうしたリスクは大きく三つのカテゴリーに分類でき、以降のセクションで説明します。
3.1. デバイスへのアクセスの悪用
周辺機器には様々な用途があります。たとえばフラッシュドライブのようにデータを保存したり、カメラやマイクのように外部の情報を収集したり、プリンタのように外部の物を操作することもあります。上記の例はすべて、ウェブプラットフォームには悪用防止のセキュリティ機能付き高レベルAPIが用意されています。外部ドライブへのデータ保存や取得にはユーザーが手動でファイルを選ぶ必要があり、マイクやカメラの起動にはユーザーの権限許可が必要で、データ収集中にはインジケータが点灯します。印刷も明示的な操作が必要です。このAPIは既存の高レベルAPIに含まれないデバイス用の汎用的な仕組みを提供するため、同様に汎用的な悪用防止手段が求められます。
これらの保護の第一はrequestDevice()関数です。UA(ユーザーエージェント)はこの関数が呼ばれた際に権限プロンプトを表示する場合があります。たとえ悪意のないページでも、ユーザーがそのようなデバイス接続の可能性を認識する前に自動で接続が行われるのを防止することで、ユーザーのプライバシーも守られます。またUAは、デバイス接続が有効なときにインジケータを表示することもあります。
次に、本仕様は[powerful-features]で定義されるセキュアコンテキストのみからUSBデバイスへアクセスできるよう要求します。これにより、発信元で実行されているコードの正当性が確保され、デバイスから読み取ったデータが途中で傍受されないよう保証されます。
さらに、USBデバイスは複数の依頼元からのリクエストを区別できません。そのためOSは、USBインターフェイスに単一のユーザ空間またはカーネル空間ドライバしか割り当てられないようにしています。UAはユーザ空間ドライバとして振る舞うため、同時にUSBインターフェイスを占有できるのは一つの実行コンテキストだけです。claimInterface()
関数は、複数の実行コンテキストが同じインターフェイス獲得を試みた場合失敗します。
3.2. デバイスへの攻撃
歴史的に、高セキュリティ用途で設計されたのでなければ、USBデバイスは接続先ホストを信頼する設計となっており、ホストがデバイス機能へのアクセスを守る役割を担ってきました。本仕様策定にあたり、二つの選択肢が検討されました。一つ目はUAがリクエスト元のオリジンをデバイスに通知する案です。これはHTTPリクエストに含まれるReferrerヘッダーのようなものです。しかしこの方式だとアクセス制御の負担がデバイス側にかかってしまい、デバイスの処理能力・記憶容量が制限される中で避けたいコストになります。
そこで本仕様ではCORSに似た仕組みでUA側がアクセスを制御する方法を選びました。デバイスはUAに対し、許可されたオリジンの静的データ構造を渡します。既存デバイスへの移行期間のために、許可オリジン情報を外部の公開レジストリで管理する方式も考えられました。
しかしこの案にも大きな欠点がありました。新しいデバイスはWebUSB対応を考慮して設計する必要があり、公開レジストリも仕様化が難航しました。製品開発サイクルは長く、エディタドラフト段階では製品計画に影響を与える「力」はありません。また、この仕組みではサードパーティの開発者が自作アプリでデバイスを使う術がなく、イノベーションや開発者の恩恵が大きく後退します。
これらを踏まえ、著者らはrequestDevice()
メソッドが促す許可プロンプトや§ 8.1 Permissions
Policyとの連携が、デバイスへの不要なアクセスを防ぐために十分であると判断しました。
3.3. ホストへの攻撃
デバイスが不正に操作されると、その機能の悪用だけでなく、接続先ホストや、もし攻撃が永続化していれば後日接続された他ホストまでも攻撃されるおそれがあります。上記の方法はこうした攻撃経路軽減を目指しています。ただし一度第三者の制御下に落ちた(例: マルウェアファームウェア書き込み)デバイスについては、UAによる抑制には限界があります。
本仕様は、デバイスメーカーに対し、署名済みファームウェアアップデートの受け入れや、重要な設定変更には物理的アクセスを要するなど、防御を多層的に設計することを推奨します。
4. WebUSBディスクリプタとリクエスト
本仕様は、このAPIの実装に必要なデバイス固有情報収集のため、UAが使ってよいディスクリプタやコマンドを定義します。
4.1. WebUSBプラットフォーム機能ディスクリプタ
デバイスは、下記のプラットフォームディスクリプタをバイナリオブジェクトストアに含めることで、WebUSBコマンドセットのサポートを表明します:
| オフセット | フィールド | サイズ | 値 | 説明 |
|---|---|---|---|---|
| 0 | bLength | 1 | 数値 | このディスクリプタのサイズ。24を指定すること。 |
| 1 | bDescriptorType | 1 | 定数 | DEVICE CAPABILITYディスクリプタ型([USB31] 表9-6)。 |
| 2 | bDevCapabilityType | 1 | 定数 | PLATFORM機能タイプ([USB31] 表9-14)。 |
| 3 | bReserved | 1 | 数値 | 予約済みフィールド。0に設定すること。 |
| 4 | PlatformCapabilityUUID | 16 | UUID | {3408b638-09a9-47a0-8bfd-a0768815b665}を指定する。 |
| 20 | bcdVersion | 2 | BCD | サポートするプロトコルバージョン。0x0100を指定すること。 |
| 22 | bVendorCode | 1 | 数値 | WebUSBリクエストを発行する際のbRequest値。 |
| 23 | iLandingPage | 1 | 数値 | デバイスのランディングページのURLディスクリプタインデックス。 |
iLandingPageフィールドが0以外の場合、デバイスメーカーがユーザーに自社デバイス制御用に訪れてほしいランディングページの存在を示します。UAは、デバイス接続時にユーザーへこのURLへの移動を促す場合があります。
注: USBはリトルエンディアンバスのため、[RFC4122]に従うと、上記UUIDはバイト列{0x38, 0xB6, 0x08,
0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6,
0x65}として転送されます。
4.2. WebUSBデバイスリクエスト
本仕様で定義される制御転送はすべてベンダー固有リクエストとみなされます。WebUSBプラットフォーム機能ディスクリプタにあるVendorCode
値は、ホストがWebUSBリクエスト発行時にデバイスが期待するbRequestです。リクエストの種類はwIndexフィールドで指定します。
| 定数 | 値 |
|---|---|
| (予約) | 1 |
| GET_URL | 2 |
4.2.1. URLの取得
このリクエストは指定されたインデックスのURLディスクリプタを取得します。
デバイスは、指定されたインデックスのURLディスクリプタを返すか、インデックスが不正の場合は転送を停止(stall)しなければなりません(MUST)。
| bmRequestType | bRequest | wValue | wIndex | wLength | データ |
|---|---|---|---|---|---|
| 11000000B | bVendorCode
| ディスクリプタインデックス | GET_URL | ディスクリプタ長 | ディスクリプタ |
4.3. WebUSBディスクリプタ
これらのディスクリプタ型は、本仕様で定義されたリクエストによって返されます。
| 定数 | 値 |
|---|---|
| (予約) | 0-2 |
| WEBUSB_URL | 3 |
4.3.1. URLディスクリプタ
このディスクリプタは単一のURLを含み、URLの取得リクエストで返されます。
| オフセット | フィールド | サイズ | 値 | 説明 |
|---|---|---|---|---|
| 0 | bLength | 1 | 数値 | このディスクリプタのサイズ |
| 1 | bDescriptorType | 1 | 定数 | WEBUSB_URL |
| 2 | bScheme | 1 | 数値 | URLスキーム接頭辞 |
| 3 | URL | 可変 | 文字列 | UTF-8エンコードのURL(スキーム接頭辞を除く) |
bSchemeフィールドは次のいずれかの値でなければなりません(MUST):
| 値 | プレフィックス |
|---|---|
| 0 | "http://" |
| 1 | "https://" |
| 255 | ""(空文字列) |
特別な値255は、スキームを含めた全URLがURLフィールドにエンコードされていることを示します。
5. デバイスの列挙
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=> { // |device| をUIに追加する。 }); });
ページがロードされた後にユーザーがデバイスを 接続 または 切断 することがあるため、インターフェースを最新の状態に保つために、スクリプトもこれらのイベントのために登録しておくべきです。
navigator. usb. addEventListener( 'connect' , event=> { // |event.device| をUIに追加する。 }); navigator. usb. addEventListener( 'disconnect' , event=> { // |event.device| をUIから削除する。 });
ユーザーがページに初めて訪れた場合は、まだどのデバイスにもアクセス権がないので、まず requestDevice()
を 該当グローバルオブジェクト に 一時的なアクティベーション がある間に呼び出す必要があります。この場合、ページはベンダー
0xABCD の 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) { // デバイスが選択されませんでした。 } if ( device!== undefined ) { // |device| をUIに追加する。 } });
本仕様で定義されるメソッドは通常非同期に完了し、USB タスクソース に作業をキューイングします。
USBデバイス device は デバイスフィルタにマッチする filter の場合、次の手順が
match を返します:
-
deviceDesc を device の デバイスディスクリプタ とする。
-
filter.が存在し、vendorIddeviceDesc.idVendorがfilter.と等しくない場合、vendorIdmismatchを返す。 -
filter.が存在し、productIddeviceDesc.idProductがfilter.と等しくない場合、productIdmismatchを返す。 -
filter.が存在する場合、 serialNumber を ストリングディスクリプタ(インデックスserialNumberdeviceDesc.iSerialNumber)とする。 device から serialNumber 要求時にエラーとなるか、serialNumber がfilter.と等しくない場合、serialNumbermismatchを返す。 -
filter.が存在し、 device のいずれかのインターフェイス interface が filter で インターフェイスフィルタにマッチする 場合、classCodematchを返す。 -
filter.が存在しclassCodedeviceDesc.bDeviceClassがfilter.と等しくない場合、classCodemismatchを返す。 -
filter.が存在しsubclassCodedeviceDesc.bDeviceSubClassがfilter.と等しくない場合、subclassCodemismatchを返す。 -
filter.が存在しprotocolCodedeviceDesc.bDeviceProtocolがfilter.と等しくない場合、protocolCodemismatchを返す。 -
matchを返す。
注: 上記手順では
bDeviceClass, bDeviceSubClass および bDeviceProtocol フィールドを デバイスディスクリプタ
の一部としてだけでなく、
インターフェイスディスクリプタ
の一部であるかのようにも扱い、提供されたフィルタと比較します。
USBインターフェイス interface は インターフェイスフィルタにマッチする filter 場合、次の手順が match
を返します:
-
desc を interface の インターフェイスディスクリプタ とする。
-
filter.が存在しclassCodedesc.bInterfaceClassがfilter.と等しくない場合、classCodemismatchを返す。 -
filter.が存在しsubclassCodedesc.bInterfaceSubClassがfilter.と等しくない場合、subclassCodemismatchを返す。 -
filter.が存在しprotocolCodedesc.bInterfaceProtocolがfilter.と等しくない場合、protocolCodemismatchを返す。 -
matchを返す。
USBDeviceFilter
filter は 有効なフィルタ の場合、次の手順が valid を返します:
-
filter.が存在しproductIdfilter.が存在しない場合、vendorIdinvalidを返す。 -
filter.が存在しsubclassCodefilter.が存在しない場合、classCodeinvalidを返す。 -
filter.が存在しprotocolCodefilter.が存在しない場合、subclassCodeinvalidを返す。 -
validを返す。
UAは、システムに接続されているすべてのデバイスを列挙
できなければなりません(MUST)。
ただし、アルゴリズムが列挙を要求するたびにこれを毎回行う必要はありません。UAは最初の列挙結果をキャッシュし、その後はデバイスの接続・切断イベントを監視して、接続デバイスをキャッシュに追加し切断されたデバイスを削除することができます。この動作モードは、getDevices()
や requestDevice()
メソッドによるOS呼び出し回数やバス通信量を減らせるため好まれます。
onconnect
属性は connect イベントタイプのためのイベントハンドラーIDL属性です。
ondisconnect
属性は disconnect
イベントタイプのためのイベントハンドラーIDL属性です。
getDevices() メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
global を this の 該当グローバルオブジェクトとする。
-
document を global の 関連付けられたDocument(なければ
null)とする。 -
storage を:
-
USBPermissionStorageオブジェクト(ServiceWorkerGlobalScopeの場合は、そのスクリプト実行環境のもの) -
それ以外は現在のスクリプト実行環境の
USBPermissionStorageオブジェクト
-
-
promise を 新しいPromiseとする。
-
次の手順を 並列で実行する:
-
システムに接続されているすべてのデバイスを列挙 し、これを enumerationResult とする。
-
devices を新しい空の
Arrayとする。 -
enumerationResult 内の各 device について:
-
このメソッドへの最初の呼出しであれば デバイスの権限を確認(device, storage で)。
-
storage.
allowedDevices内で device が allowedDevice.[[devices]]に含まれているものを探す。 なければこのdeviceは次へ進む。
-
USBDeviceオブジェクトで device を表したものを devices に追加。 -
グローバルタスクをキューイング(USBタスクソース上、global に対して)し、promise を devices で resolve する。
-
-
promise を返す。
requestDevice(options)
メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
{ name: "usb" filters: options. filters exclusionFilters: options. exclusionFilters} permissionResult を、得られた
Promiseとする。 -
permissionResult が fulfillment された時は result で次の手順:
-
result.
devicesが空の場合は、 "NotFoundError"DOMExceptionを投げて処理を中止。 -
result.
devices[0] を返す。
-
Document
document,
USBPermissionStorage
storage,
USBPermissionDescriptor
options および
USBPermissionResult
status を引数に次の手順を実行する(MUST):
-
global を storage の 該当グローバルオブジェクトとする。
-
各 filter ∈ options.
filtersについて、 filter が 有効なフィルタではない場合は TypeError で reject された promise を返す。 -
各 exclusionFilter ∈ options.
exclusionFiltersについて、 exclusionFilter が 有効なフィルタではない場合は TypeError で reject された promise を返す。 -
アルゴリズムが global に一時的なアクティベーション がある間に呼び出されたことを確認。さもなくば、 "
SecurityError"DOMExceptionで reject された promise を返す。 -
promise を 新しいPromiseとする。
-
次の手順を 並列で実行する。
-
システムに接続されているすべてのデバイスを列挙する。結果を enumerationResult とする。
-
enumerationResult から ブロックリストされたデバイスを削除。
-
enumerationResult から options.
filtersのデバイスフィルタに マッチしない デバイスを削除。 -
enumerationResult から options.
exclusionFiltersのデバイスフィルタに マッチする デバイスを削除。 -
ユーザーに enumerationResult からデバイスを選択するよう促すプロンプトを表示。UAは各デバイスの人間が読める名前を表示すべき(SHOULD)。
-
ユーザーが device を選択するかプロンプトをキャンセルするのを待つ。
-
グローバルタスクをキューイング(USBタスクソース上、global)し、次の処理を行う:
-
status.
stateを"ask"に設定。 -
ユーザーがプロンプトをキャンセルした場合は、status.
devicesを空のFrozenArrayにし、 promise を resolve しundefinedで終了。 -
deviceObj を
USBDeviceオブジェクトで作成。 -
status.
devicesをFrozenArrayで deviceObj のみ含む配列に。 -
promise を resolve し
undefinedで終了。
-
-
-
promise を返す。
許可された USBデバイス device を USBPermissionStorage
storage に追加するには、 UA は次の手順を実行(MUST):
-
storage.内で、device が allowedDevice.allowedDevices[[devices]]に含まれているものを探す。あれば中止。 -
serialNumber をデバイスが持つ場合は device の シリアル番号、そうでなければ
undefined。 -
{ vendorId: vendorId, productId: productId, serialNumber: serialNumber }を、[[devices]]内部スロットに device だけを含めてstorage.に追加。allowedDevices
新しい USB デバイス の権限を確認するには、 USBPermissionStorage
storage で次を実行する(MUST):
-
serialNumber をデバイスが持つ場合はそれ、なければ
undefined。 -
storage.内で、allowedDevices-
allowedDevice.が vendorId に等しいvendorId -
allowedDevice.が productId に等しいproductId -
allowedDevice.が serialNumber に等しいserialNumber
-
-
一致する要素がなければ
nullを返す。 -
device を allowedDevice@
[[devices]]に追加。 -
allowedDevice を返す。
許可された USBデバイス の削除は、 USBPermissionStorage
storage で次を実行(MUST):
-
storage.内で、device が allowedDevice.allowedDevices[[devices]]に含まれているものを探し、なければ中止。 -
allowedDevice を
storage.から削除する。allowedDevices
5.1. イベント
dictionary :USBConnectionEventInit EventInit {required USBDevice ; }; [device Exposed =(Worker ,Window ),SecureContext ]interface :USBConnectionEvent Event {(constructor DOMString ,type USBConnectionEventInit ); [eventInitDict SameObject ]readonly attribute USBDevice ; };device
注: Worker は connect および disconnect イベント用のイベントリスナを登録できますが、ワーカーがアクティブでない限りそのイベントリスナは呼び出されません。
UA がホストに新しい USB device device の接続を検出したとき、スクリプト実行環境ごとに次の手順を実行しなければなりません(MUST):
-
storage を現在のスクリプト実行環境の
USBPermissionStorageオブジェクトとする。 -
device の権限を storage で確認し、その結果を allowedDevice とする。
-
allowedDevice が
nullであれば、これらの手順を中止する。 -
deviceObj を device を表す
USBDeviceオブジェクトとする。 -
connect という名前のイベントを発火 し、device の該当グローバルオブジェクトの
Navigatorオブジェクトのusb上で、USBConnectionEventを使用し、device属性を deviceObj に設定して発火する。
UA がホストから USB device device の切断を検出したとき、スクリプト実行環境ごとに次の手順を実行しなければなりません(MUST):
-
storage を現在のスクリプト実行環境の
USBPermissionStorageオブジェクトとする。 -
storage.
allowedDevices内で、device が allowedDevice.[[devices]]に含まれる要素 allowedDevice を検索し、該当する要素がなければこれらの手順を中止する。 -
device を allowedDevice@
[[devices]]から削除する。 -
もし
allowedDevice.がserialNumberundefinedであり、かつ allowedDevice@[[devices]]が空である場合は allowedDevice をstorage.から削除する。allowedDevices -
device を
USBDeviceオブジェクトとして用意する。 -
disconnect という名前のイベントを発火 し、device の該当グローバルオブジェクトの
Navigatorオブジェクトのusb上で、USBConnectionEventを使用し、device属性を device に設定して発火する。
6. デバイスの使用
bConfigurationValue 1)を持ち、単一のインターフェイス(bInterfaceNumber 1)に単一のバルクエンドポイント(bEndpointAddress 0x81、つまりエンドポイント1でINエンドポイント)があります。データがサンプリングされるとこのエンドポイントで取得できます。このエンドポイントの最大パケットサイズはすべての8チャネルが同時に有効になった場合をサポートするため16バイトです。しかしバス帯域幅を節約するため、任意のチャネルの組合せを有効/無効にできます。パケットは収集されたデータを送信するのに必要な長さだけになります。
まずデバイスを開き、最初のコンフィギュレーション(デバイスは1つしか持ちませんが、OS が列挙時に既にこれを選んでいない可能性があります)を選択し、データロギングインターフェイスをクレームします。
await device. open(); if ( device. configuration=== null ) await device. selectConfiguration( 1 ); await device. claimInterface( 1 );
このアプリケーションではチャネル1、2、5からの読み取りを行うため、これらのチャネルを有効にするために control transfer を送ります。
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 });
アプリケーションはデバイスのポーリングを開始できます。3チャネル分のデータだけを期待するため6バイトのバッファを要求します。完全なバッファを受信した場合、キャプチャした値(ビッグエンディアンで送信)がコンソールログに出力されます。もしデバイスがエラーを検出してエンドポイントをスタール(stall)した場合は、継続する前にエラーをクリアします。
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. USBDevice インターフェイス
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 (); };
USBDevice
のインスタンスは、次の表に記載された 内部スロット を用いて生成されます(非規範説明)。
| Internal Slot | 初期値 | 説明(非規範) |
|---|---|---|
[[configurations]]
| 空の sequence(USBConfiguration
の)
| デバイスがサポートするすべての構成。 |
[[configurationValue]]
| <本文で常に設定される> | デバイスの現在のコンフィギュレーション値。 |
[[selectedAlternateSetting]]
| 空の整数リスト | 現在のコンフィギュレーション上の各インターフェイスの現在のオルタネート設定。 |
[[claimedInterface]]
| 空の boolean リスト | 現在のコンフィギュレーション上の各インターフェイスのクレーム状態。 |
-
deviceDescriptor を、Get Descriptor を DEVICE に指定して取得した、接続されたデバイスのデバイスディスクリプタとする。
-
deviceDescriptor を返す。
-
deviceDescriptor を、接続されたUSBデバイスのデバイスディスクリプタを見つける ことによって得た結果とする。
-
numConfigurations を deviceDescriptor の
bNumConfigurationsとする。 -
configurationIndex を 0 とする。
-
configurationDescriptors を空のリストとする。
-
configurationIndex が numConfigurations より小さい間:
-
descriptors を、Get Descriptor を CONFIGURATION とし、DescriptorIndex を configurationIndex にして実行して得たディスクリプタのリストとする。
-
もし descriptors[0] の
bDescriptorTypeが CONFIGURATION と等しければ、descriptors[0] を configurationDescriptors に追加する。 -
configurationIndex を 1 増やす。
-
-
configurationDescriptors を返す。
-
global を interface の該当グローバルオブジェクトとする。
-
configuration を interface.
[[configuration]]とする。 -
device を configuration.
[[device]]とする。 -
もし configuration が 現在のコンフィギュレーションの検索 の結果と等しくなければ、返す。
-
もし インターフェイスがクレームされているかを調べる の結果が true でなければ、返す。
-
currAlternateInterface を 現在のオルタネート設定のためのオルタネイトインターフェイスを見つける の結果とする。
-
各 endpoint ∈ currAlternateInterface.
[[endpoints]]について:-
endpoint 上で現在スケジュールされているすべての転送を中止する。
-
グローバルタスクをキューイング(USBタスクソース上、global)し、関連する promise を "
AbortError"(DOMException)で reject する。
-
-
interfaceIndex を 0 とする。
-
interfaceIndex が configuration.
[[interfaces]]のサイズ未満である間:-
もし configuration.
[[interfaces]][interfaceIndex].[[interfaceNumber]]が interfaceNumber と等しければ、interfaceIndex を返す。 -
interfaceIndex を1増やす。
-
-
-1を返す。
-
alternateIndex を 0 とする。
-
alternateIndex が interface.
[[alternates]]のサイズ未満である間:-
もし interface.
[[alternates]][alternateIndex].[[alternateSetting]]が alternateSetting と等しければ、alternateIndex を返す。 -
alternateIndex を1増やす。
-
-
-1を返す。
-
各 configuration ∈ device.
[[configurations]]について:-
もし configuration.
[[configurationValue]]が device.[[configurationValue]]と等しければ、configuration を返す。
-
-
nullを返す。
-
configuration を 現在のコンフィギュレーションを見つける の結果とする。
-
もし configuration が
nullであればnullを返す。 -
各 interface ∈ configuration.
[[interfaces]]について:-
もし インターフェイスがクレームされているかを調べる の結果が true でなければ、continue。
-
alternate を 現在のオルタネート設定のためのオルタネートインターフェイスを見つける の結果とする。
-
各 endpoint ∈ alternate.
[[endpoints]]について:-
もし endpoint.
[[endpointAddress]]が endpointAddress と等しければ、endpoint を返す。
-
-
-
nullを返す。
-
もし device がもはやシステムに接続されていないなら、"
NotFoundError"(DOMException)で reject された promise を返す。 -
もし device.
openedが true でなければ、"InvalidStateError"(DOMException)で reject された promise を返す。 -
もし device.
[[configurationValue]]が 0 と等しければ、"InvalidStateError"(DOMException)で reject された promise を返す。 -
undefinedを返す。
USBDevice
オブジェクトが次の手順を実行して構築されます:
-
this の
[[configurationValue]]を Get Configuration の戻り値に設定する。 -
configurationDescriptors を 接続されたUSBデバイスのコンフィギュレーションディスクリプタ一覧を見つける の結果とする。
-
各 configurationDescriptor ∈ configurationDescriptors について:
-
configuration を new な
USBConfigurationオブジェクトとして作成する(device を this に、configurationValue を configurationDescriptor のbConfigurationValueに設定して USBConfiguration(device,configurationValue) を呼ぶ)。 -
configuration を this の
[[configurations]]に追加する。 -
もし configurationDescriptor の
bConfigurationValueが this の[[configurationValue]]と等しければ:-
numInterfaces を configuration.
[[interfaces]]のサイズとする。 -
this の
[[selectedAlternateSetting]]を numInterfaces にリサイズする。 -
this の
[[selectedAlternateSetting]]を 0 で埋める。 -
this の
[[claimedInterface]]を numInterfaces にリサイズする。 -
this の
[[claimedInterface]]をfalseで埋める。
-
-
すべてのUSBデバイスは default control
pipe を持たなければならず、それは endpointNumber 0 です。
6.1.1. 属性
usbVersionMajor, 型は octet、読み取り専用usbVersionMinor, 型は octet、読み取り専用usbVersionSubminor, 型は octet、読み取り専用-
usbVersionMajor,usbVersionMinorおよびusbVersionSubminor属性は、デバイスがサポートするUSBプロトコルのバージョンを宣言します。これらはデバイスディスクリプタのbcdUSBフィールドの値に対応し、値0xJJMNはメジャー版がJJ、マイナー版がM、サブマイナー版がNとなるものとします。 deviceClass, 型は octet、読み取り専用deviceSubclass, 型は octet、読み取り専用deviceProtocol, 型は octet、読み取り専用-
deviceClass,deviceSubclassおよびdeviceProtocol属性は、デバイスがサポートする通信インターフェイスを示します。これらはそれぞれデバイスディスクリプタのbDeviceClass、bDeviceSubClass、bDeviceProtocolフィールドの値に対応しなければなりません。 vendorId, 型は unsigned short、読み取り専用productId, 型は unsigned short、読み取り専用-
vendorIdおよびproductIdは、デバイスの vendor ID および product ID と一致している必要があります(MUST)。 deviceVersionMajor, 型は octet、読み取り専用deviceVersionMinor, 型は octet、読み取り専用deviceVersionSubminor, 型は octet、読み取り専用-
deviceVersionMajor,deviceVersionMinorおよびdeviceVersionSubminor属性は、デバイスメーカーが定義するデバイスのリリース番号を示します。これはデバイスディスクリプタのbcdDeviceフィールドの値に対応し、値0xJJMNはメジャーがJJ、マイナーがM、サブマイナーがNとなるものとします。 manufacturerName, 型は DOMString、読み取り専用、nullableproductName, 型は DOMString、読み取り専用、nullableserialNumber, 型は DOMString、読み取り専用、nullable-
manufacturerName,productNameおよびserialNumber属性は、該当する場合はデバイスディスクリプタのiManufacturer、iProduct、iSerialNumberフィールドで参照される string descriptors の値を含むべきです(SHOULD)。 configuration, 型は USBConfiguration、読み取り専用、nullable-
configuration属性は、デバイスで現在選択されている構成(configuration)を含み、その値はUSBConfigurationのいずれかでありconfigurationsに含まれていなければならない(SHALL)。configurationの getter の手順は次の通りです:-
現在のコンフィギュレーションを見つける を this と共に実行し、その結果を返します。
-
configurations, 型は FrozenArray<USBConfiguration>、読み取り専用-
configurations属性は、デバイスがサポートするコンフィギュレーションを表す sequence を含みます。configurationsの getter の手順は次の通りです:-
このオブジェクトの内部スロット
[[configurations]]を返します。
-
opened, 型は boolean、 読み取り専用-
opened属性は、現在の実行コンテキストによってデバイスが open されている場合trueに、そうでない場合はfalseに設定されるものとします(SHALL)。
6.1.2. メソッド
open() メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
global を this の該当グローバルオブジェクトとします。
-
もし this がもはやシステムに接続されていない場合、"
NotFoundError"(DOMException)で reject された promise を返します。 -
次の手順を並列で実行します。
-
デバイスとのセッションを開始するために必要なプラットフォーム固有の処理を行います。
-
グローバルタスクをUSBタスクソース上にキューイングし、次の手順を実行します:
-
上記のプラットフォーム固有の処理が何らかの理由で失敗した場合、promise を "
NetworkError"(DOMException)で reject し、処理を中止します。 -
Resolve によって promise を
undefinedで解決します。
-
-
-
promise を返します。
close() メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
global を this の該当グローバルオブジェクトとします。
-
もし this がもはやシステムに接続されていない場合、"
NotFoundError"(DOMException)で reject された promise を返します。 -
このデバイスに対して現在実行中の他のアルゴリズムをすべて中止し、それらに関連する promise を "
AbortError"(DOMException)で reject します。 -
次の手順を並列で実行します。
-
各クレームされたインターフェイスについて
releaseInterface(interfaceNumber)が呼ばれたかのように、クレームを解除するためのプラットフォーム固有の処理を行います。 -
デバイスとのセッションを終了するためのプラットフォーム固有の処理を行います。
-
グローバルタスクをUSBタスクソース上にキューイングし、次の手順を実行します:
-
-
promise を返します。
注: ECMAcript のコードが USBDevice
のインスタンス device をもはや参照できない場合、UA は device.close()
を実行することが推奨されます(SHOULD)。
forget() メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
device を this とします。
-
storage を現在のスクリプト実行環境の
USBPermissionStorageオブジェクトとします。 -
Remove device from storage を storage を使って実行します。
-
undefined で解決された promise を返します。
注: ユーザーエージェントは複数API間の権限を統合する(例: WebHID と WebUSB のデバイスアクセスを統一された低レベルデバイスアクセス権で追跡する)ことを選択する場合があります。そのため、このメソッドは将来的に追加の(未指定の)権限も取り消す可能性があります。
selectConfiguration(configurationValue)
メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
global を this の該当グローバルオブジェクトとします。
-
もし this がもはやシステムに接続されていない場合、"
NotFoundError"(DOMException)で reject された promise を返します。 -
selectedConfiguration を
nullに設定します。 -
各 configuration ∈ this.
[[configurations]]について:-
もし configuration.
[[configurationValue]]が configurationValue と等しければ、selectedConfiguration に configuration を設定してループを抜けます。
-
-
もし selectedConfiguration が
nullのままであれば、"NotFoundError"(DOMException)で reject された promise を返します。 -
もし this.
openedがtrueでない場合、"InvalidStateError"(DOMException)で reject された promise を返します。 -
activeConfiguration を 現在のコンフィギュレーションを見つける を this で実行した結果とします。
-
次の手順を並列で実行します。
-
もし activeConfiguration が
nullでない場合:-
各 interface ∈ activeConfiguration.
[[interfaces]]について、abort transfers currently scheduled on an interface を実行します。
-
-
SET_CONFIGURATIONコントロール転送を発行し、configurationValueを指定します。 -
グローバルタスクをUSBタスクソース上にキューイングし、次の手順を実行します:
-
上記のコントロール転送が失敗した場合、promise を "
NetworkError"(DOMException)で reject し、処理を中止します。 -
numInterfaces を selectedConfiguration.
[[interfaces]]のサイズとします。 -
this の
[[selectedAlternateSetting]]を numInterfaces にリサイズします。 -
this の
[[selectedAlternateSetting]]を 0 で埋めます。 -
this の
[[claimedInterface]]を numInterfaces にリサイズします。 -
this の
[[claimedInterface]]をfalseで埋めます。 -
this の内部スロット
[[configurationValue]]を configurationValue に設定します。 -
Resolve によって promise を
undefinedで解決します。
-
-
-
promise を返します。
claimInterface(interfaceNumber)
メソッドが呼び出された場合、次の手順を実行しなければなりません(MUST):
-
global を this の該当グローバルオブジェクトとします。
-
もし check if the device is configured を this で実行して Promise が返される場合、その値を返します。
-
activeConfiguration を 現在のコンフィギュレーションを見つける を this で実行した結果とします。
-
interfaces を activeConfiguration.
[[interfaces]]とします。 -
interfaceIndex を find the interface index を interfaceNumber と activeConfiguration で実行した結果とします。
-
もし interfaceIndex が
-1であれば、"NotFoundError"(DOMException)で reject された promise を返します。 -
もし this.
[[claimedInterface]][interfaceIndex] がtrueであれば、undefinedで解決された promise を返します。 -
unrestricted を
falseに設定します。 -
document を global の関連ドキュメント(存在しなければ
null)とします。 -
もし document が
nullでなく、かつ document がポリシー制御機能"usb-unrestricted"の使用を許可されている場合、unrestricted をtrueにします。 -
もし interfaces[interfaceIndex].
[[isProtectedClass]]がtrueであり、かつ unrestricted がfalseであれば、"SecurityError"(DOMException)で reject された promise を返します。 -
promise を新しい Promise として作成します。
-
次の手順を並列で実行します。
-
現在の実行コンテキストのために interfaces[interfaceIndex] に対する排他制御を要求するためのプラットフォーム固有の処理を行います。
-
グローバルタスクをUSBタスクソース上にキューイングし、次の手順を実行します:
-
上記のプラットフォーム固有の処理が失敗した場合、promise を "
NetworkError"(DOMException)で reject し、処理を中止します。 -
this.
[[claimedInterface]][interfaceIndex] をtrueに設定します。 -
Resolve によって promise を
undefinedで解決します。
-
-
-
promise を返します。
releaseInterface(interfaceNumber)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
activeConfiguration を、現在の構成を見つける を this に対して行った結果とする。
-
interfaces を activeConfiguration.
[[interfaces]]とする。 -
interfaceIndex を、インターフェイスのインデックスを見つける を interfaceNumber と activeConfiguration を用いて行った結果とする。
-
もし interfaceIndex が
-1と等しければ、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
もし this.
[[claimedInterface]][interfaceIndex] がfalseなら、 次の値で解決される promise を返す:undefined。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
interfaces[interfaceIndex] に対する排他的制御を放棄するために必要なプラットフォーム固有の手順を実行する。
-
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
this.
[[selectedAlternateSetting]][interfaceIndex] を0に設定する。 -
this.
[[claimedInterface]][interfaceIndex] をfalseに設定する。 -
解決する: promise を
undefinedで。
-
-
-
promise を返す。
selectAlternateInterface(interfaceNumber, alternateSetting)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
activeConfiguration を、現在の構成を見つける を this に対して行った結果とする。
-
interfaces を activeConfiguration.
[[interfaces]]とする。 -
interfaceIndex を、インターフェイスのインデックスを見つける を interfaceNumber と activeConfiguration で行った結果とする。
-
もし interfaceIndex が
-1と等しければ、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
もし this.
[[claimedInterface]][interfaceIndex] がfalseなら、 次の理由で拒否される promise を返す: "InvalidStateError"DOMException。 -
interface を interfaces[interfaceIndex] とする。
-
alternateIndex を、代替設定のインデックスを見つける を alternateSetting と interface で行った結果とする。
-
もし alternateIndex が
-1と等しければ、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
インターフェイス上で現在スケジュールされている転送を中止する を interface に対して実行する。
-
SET_INTERFACEの 制御転送 を発行し、interfaceNumberを interfaceNumber に、alternateSettingを alternateSetting に設定する。 -
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
上記の 制御転送 が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を中止する。 -
this.
[[selectedAlternateSetting]][interfaceIndex] を alternateSetting に設定する。 -
解決する: promise を
undefinedで。
-
-
-
promise を返す。
controlTransferIn(setup, length)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
制御転送パラメーターの妥当性を確認する を this と setup に対して行い、
Promiseを返すなら、その値を返す。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
もし length が 0 より大きいなら、buffer を length バイトの領域を持つホストバッファーとする。
-
制御転送 を this に対して発行し、セットアップパケットのパラメーターには setup で与えられたものを用い、
bmRequestTypeのデータ転送方向を "device to host" に、wLengthを length に設定する。 もし定義されていれば、この転送に対する応答として受信したデータを書き込む宛先として buffer も与える。 -
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
bytesTransferred を、buffer に書き込まれたバイト数とする。
-
result を 新たな
USBInTransferResultとする。 -
もしデバイスからデータを受信していれば、新たな
ArrayBufferを作成し、buffer の先頭 bytesTransferred バイトを含め、 result.dataをそれの上に構築した 新たなDataViewに設定する。 -
result.
statusを次のように設定する。-
"stall": デバイスが デフォルト制御パイプ をストールで応答した場合。 -
"babble": デバイスが length バイトを超えるデータで応答した場合。 -
"ok": 上記以外の場合。
-
-
その他の理由で転送が失敗した場合、拒否する: promise を "
NetworkError" で、 これ以降の手順を中止する。 -
解決する: promise を result で。
-
-
-
promise を返す。
controlTransferOut(setup, data)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
制御転送パラメーターの妥当性を確認する を this と setup に対して行い、
Promiseを返すなら、その値を返す。 -
バッファソースのコピーを取得し、data から結果を bytes とする。
-
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
制御転送 を this に対して発行し、セットアップパケットのパラメーターには setup を用い、
bmRequestTypeのデータ転送方向を "host to device" に、wLengthを 長さ (bytes の) に設定する。 -
転送のデータステージで bytes を送信する。
-
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
result を 新たな
USBOutTransferResultとする。 -
result.
statusを次のように設定する。-
"stall": デバイスが デフォルト制御パイプ をストールで応答した場合。 -
"ok": 上記以外の場合。また、result.bytesWrittenを 長さ (bytes の) に設定する。
-
-
その他の理由で転送が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を中止する。 -
解決する: promise を result で。
-
-
-
promise を返す。
clearHalt(direction, endpointNumber)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
endpointAddress を、もし direction が
"in"と等しければendpointNumber | 0x80、それ以外は endpointNumber とする。 -
endpoint を、エンドポイントを見つける を endpointAddress と this で行った結果とする。
-
もし endpoint が
nullなら、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
ClearFeature(ENDPOINT_HALT)の 制御転送 をデバイスに対して発行し、 endpoint のハルト状態を解除する。 -
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
上記の 制御転送 が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を中止する。 -
解決する: promise を
undefinedで。
-
-
-
promise を返す。
transferIn(endpointNumber, length)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
endpointAddress を
endpointNumber | 0x80(すなわち"in"方向)とする。 -
endpoint を、エンドポイントを見つける を endpointAddress と this で行った結果とする。
-
もし endpoint が
nullなら、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
もし endpoint.
typeが"bulk"または"interrupt"と等しくないなら、 次の理由で拒否される promise を返す: "InvalidAccessError"DOMException。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
buffer を length バイトの領域を持つホストバッファーとする。
-
endpoint に適した方法で、バルク または インタラプト の IN 転送 を endpoint に対して実行し、デバイスから length バイトのデータを受信して buffer に書き込む。
-
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
bytesTransferred を、buffer に書き込まれたバイト数とする。
-
result を 新たな
USBInTransferResultとする。 -
もしデバイスからデータが受信されていれば、新たな
ArrayBufferを作成し、buffer の先頭 bytesTransferred バイトを含め、 result.dataをそれの上に構築した 新たなDataViewに設定する。 -
result.
statusを次のように設定する。 -
その他の理由で転送が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を中止する。 -
解決する: promise を result で。
-
-
-
promise を返す。
transferOut(endpointNumber, data)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
endpointAddress を endpointNumber(すなわち
"out"方向)とする。 -
endpoint を、エンドポイントを見つける を endpointAddress と this で行った結果とする。
-
もし endpoint が
nullなら、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
もし endpoint.
typeが"bulk"または"interrupt"と等しくないなら、 次の理由で拒否される promise を返す: "InvalidAccessError"DOMException。 -
バッファソースのコピーを取得し、data から結果を bytes とする。
-
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
endpoint に適した方法で、バルク または インタラプト の OUT 転送 を endpoint に対して実行し、bytes をデバイスに送信する。
-
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
result を 新たな
USBOutTransferResultとする。 -
result.
bytesWrittenを、デバイスに正常に送信されたデータ量に設定する。 -
result.
statusを次のように設定する。 -
その他の理由で転送が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を中止する。 -
解決する: promise を result で。
-
-
-
promise を返す。
isochronousTransferIn(endpointNumber, packetLengths)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
endpointAddress を
endpointNumber | 0x80(すなわち"in"方向)とする。 -
endpoint を、エンドポイントを見つける を endpointAddress と this で行った結果とする。
-
もし endpoint が
nullなら、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
もし endpoint.
typeが"isochronous"と等しくないなら、 次の理由で拒否される promise を返す: "InvalidAccessError"DOMException。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
totalLength を packetLengths の要素の合計とする。
-
buffer を totalLength バイトの領域を持つホストバッファーとする。
-
アイソクロナス IN 転送を endpoint に対して実行し、packetLengths に従ってデバイスからパケットを buffer に読み込む。
-
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
result を 新たな
USBIsochronousInTransferResultとする。 -
data を 新たな
ArrayBufferとし、buffer で初期化する。 -
各パケット i について、
0からpacketLengths.length - 1まで繰り返す:-
packet を 新たな
USBIsochronousInTransferPacketとする。 -
view を、新たな
DataViewとし、デバイスからこのパケットで受信したデータを含む data の該当部分上に構築する。 packet.dataを view に設定する。 -
packet.
statusを次のように設定する。 -
その他の理由で転送が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を 中止する。 -
result.
packets[i] を packet に設定する。
-
-
解決する: promise を result で。
-
-
-
promise を返す。
isochronousTransferOut(endpointNumber, data, packetLengths)
メソッドは、呼び出されたとき、次の手順を実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
endpointAddress を endpointNumber(すなわち
"out"方向)とする。 -
endpoint を、エンドポイントを見つける を endpointAddress と this で行った結果とする。
-
もし endpoint が
nullなら、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
もし endpoint.
typeが"isochronous"と等しくないなら、 次の理由で拒否される promise を返す: "InvalidAccessError"DOMException。 -
バッファソースのコピーを取得し、data から結果を bytes とする。
-
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
アイソクロナス OUT 転送 を endpoint に対して実行し、bytes を
packetLengths.length個のパケットに分割して 書き込む。各パケットの大きさは packetLengths[i](i は0からpacketLengths.length - 1)とする。 -
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
result を 新たな
USBIsochronousOutTransferResultとする。 -
各パケット i について、
0からpacketLengths.length - 1まで繰り返す:-
packet を 新たな
USBIsochronousOutTransferPacketとする。 -
packet.
bytesWrittenを、このパケットの一部としてデバイスに正常に送信されたデータ量に設定する。 -
packet.
statusを次のように設定する。 -
その他の理由で転送が失敗した場合、拒否する: promise を "
NetworkError"DOMExceptionで、これ以降の手順を 中止する。 -
result.
packets[i] を packet に設定する。
-
-
解決する: promise を result で。
-
-
-
promise を返す。
reset() メソッドは、呼び出されたとき、次の手順を
実行しなければならない。
-
global を、this の 関連する大域オブジェクトとする。
-
デバイスが構成済みか確認する を this に対して行い、
Promiseを返すなら、その値を返す。 -
promise を 新たな promise とする。
-
次の手順を 並列に実行する。
-
デバイス上のすべての操作を中止し、大域タスクをキューに入れ、USB タスクソース 上で、それらに関連付けられた promise を "
AbortError"DOMExceptionで 拒否する。 -
デバイスをソフトリセットするために必要なプラットフォーム固有の操作を実行する。
-
大域タスクをキューに入れ、USB タスクソース 上で global を与えて 次の手順を実行する:
-
ソフトリセットが失敗した場合、拒否する: promise を "
NetworkError" で、これ以降の手順を中止する。 -
解決する: promise を
undefinedで。
-
-
-
promise を返す。
リセット後、デバイスはどの構成になりますか? [Issue #36]
6.2. USBControlTransferParameters 辞書
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
USBDevice
device と USBControlTransferParameters
setup について、
次の手順を実行する:
-
configuration を、現在の構成を見つける を device に対して行った結果とする。
-
もし configuration が
nullなら、undefinedを返す。 -
もし setup.
recipientが"interface"なら、 次の手順を実行する:-
interfaceNumber を、setup.
indexの下位 8 ビットとする。 -
interfaceIndex を、インターフェイスのインデックスを見つける を interfaceNumber と configuration で行った結果とする。
-
もし interfaceIndex が
-1と等しければ、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
interface を configuration.
[[interfaces]][interfaceIndex] とする。 -
インターフェイスがクレームされているかを判定する を interface に対して行った結果が
trueでないなら、次の理由で拒否される promise を返す: "InvalidStateError"DOMException。
-
-
もし setup.
recipientが"endpoint"なら、 次の手順を実行する:-
endpointAddress を setup.
indexとする。 -
endpoint を、エンドポイントを見つける を endpointAddress と device で行った結果とする。
-
もし endpoint が
nullなら、次の理由で拒否される promise を返す: "NotFoundError"DOMException。 -
alternate を endpoint.
[[alternateInterface]]とする。 -
interface を alternate.
[[interface]]とする。 -
インターフェイスがクレームされているかを判定する を interface に対して行った結果が
falseなら、次の理由で拒否される promise を返す: "InvalidStateError"DOMException。
-
-
undefinedを返す。
6.2.1. メンバー
requestType, 型 USBRequestType-
requestType属性は、セットアップパケット のbmRequestTypeフィールドの一部を設定し、 このリクエストが USB 標準、特定の USB デバイスクラス仕様、またはベンダー固有プロトコルのいずれに属するかを示す。 recipient, 型 USBRecipient-
recipient属性は、セットアップパケット のbmRequestTypeフィールドの一部を設定し、 control transfer の宛先がデバイス全体か、特定のインターフェイスまたはエンドポイントかを示す。 request, 型 octet-
request属性は、セットアップパケット のbRequestフィールドを設定する。有効なリクエストは USB 標準、USB デバイスクラス仕様、またはデバイスベンダーによって定義される。 value, 型 unsigned short-
valueおよびindex属性は、それぞれ セットアップパケット のwValueとwIndexフィールドを設定する。これらのフィールドの意味は行われるリクエストによって異なる。
6.3. USBConfiguration インターフェイス
[Exposed =(Worker ,Window ),SecureContext ]interface {USBConfiguration constructor (USBDevice ,device octet );configurationValue readonly attribute octet configurationValue ;readonly attribute DOMString ?configurationName ;readonly attribute FrozenArray <USBInterface >interfaces ; };
USBConfiguration
のインスタンスは、次の表に示す 内部スロット を持って生成される:
| 内部スロット | 初期値 | 説明(参考) |
|---|---|---|
[[device]]
| <常に本文で設定> | USBDevice
オブジェクト。this が属する。
|
[[interfaces]]
| sequence(USBInterface)の空配列
| この構成でサポートされるすべてのインターフェイス。 |
[[configurationValue]]
| <常に本文で設定> | この構成の構成値。 |
-
deviceDescriptor を、接続された USB デバイスのデバイスディスクリプタを見つける の結果とする。
-
numConfigurations を deviceDescriptor の
bNumConfigurationsとする。 -
configurationIndex を 0 とする。
-
configurationIndex が numConfigurations より小さいあいだ:
-
descriptors を、ディスクリプタ のリストで、Get Descriptor を
DescriptorTypeにCONFIGURATIONを、DescriptorIndexに configurationIndex を設定して実行した結果とする。 -
もし descriptors[0] の
bDescriptorTypeがCONFIGURATIONと等しく、かつ descriptors のbConfigurationValueが configurationValue と等しければ、 descriptors を返す。 -
configurationIndex を 1 増やす。
-
-
empty の結果を返す。
6.3.1. コンストラクター
USBConfiguration(device, configurationValue)
コンストラクターは、呼び出されたとき、次の手順を実行しなければならない:
-
this.
[[device]]を device に設定する。 -
this.
[[configurationValue]]を configurationValue に設定する。 -
descriptors を、構成のためのディスクリプタの一覧を見つける を
configurationValueに configurationValue を設定して実行した結果とする。 -
seen を空の 順序付き集合 とする。
-
各 descriptor について(descriptors の要素):
-
もし descriptor の
bDescriptorTypeがINTERFACEと等しくなければ、続行する。 -
もし descriptor の
bInterfaceNumberが seen に含まれていれば、 続行する。 -
interface を、新たな
USBInterfaceオブジェクトとして、 USBInterface(configuration,interfaceNumber) を用いて生成する。ここで configuration は this、 interfaceNumber は descriptor のbInterfaceNumberとする。 -
追加する: interface を this.
[[interfaces]]に。 -
追加する: descriptor の
bInterfaceNumberを seen に。
-
6.3.2. 属性
configurationValue, 型 octet、読み取り専用-
各デバイス構成は、一意の
configurationValueを持たなければならず、これはそれを定義する 構成ディスクリプタ のbConfigurationValueフィールドと一致しなければならない。 configurationName, 型 DOMString、読み取り専用、nullable-
configurationName属性は、定義されている場合、構成ディスクリプタ のiConfigurationフィールドが参照する 文字列ディスクリプタ の値を含むことが望ましい(SHOULD)。 interfaces, 型 FrozenArray<USBInterface>、読み取り専用-
interfaces属性には、このデバイス構成によって公開されるインターフェイスの一覧が含まれていなければならない(SHALL)。interfacesの getter 手順は次のとおり:-
this.
[[interfaces]]を返す。
-
デバイス構成に関する非規範的な情報を含めること。 [Issue #46]
6.4. USBInterface インターフェイス
[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 ; };
USBInterface
のインスタンスは、次の表に示す 内部スロット を持って生成される:
| 内部スロット | 初期値 | 説明(参考) |
|---|---|---|
[[configuration]]
| <常に本文で設定> | USBConfiguration
オブジェクト。this が属する。
|
[[interfaceNumber]]
| <常に本文で設定> | このインターフェイスのインターフェイス番号。 |
[[alternates]]
| sequence(USBAlternateInterface)の空配列
| このインターフェイスでサポートされるすべての代替設定。 |
[[isProtectedClass]]
| false
| このインターフェイスに保護対象のクラスに属する代替設定があるかどうか。 |
インターフェイスディスクリプタ
interface は、かつその場合に限り、
interface の bInterfaceClass が次のいずれかの値と等しいとき、
保護対象のインターフェイスクラスを持つ。
| コード | 説明 |
|---|---|
0x01
| オーディオ |
0x03
| HID(ヒューマンインターフェイスデバイス) |
0x08
| マスストレージ |
0x0B
| スマートカード |
0x0E
| ビデオ |
0x10
| オーディオ/ビデオデバイス |
0xE0
| ワイヤレスコントローラー |
Note: 本仕様は、ユーザーを悪意あるコンテンツから保護するために機微なデバイスへのアクセスを制限することと、 可能な限り多くのデバイスをサポートすることのバランスを取ることを目指している。序文で述べたとおり、 この API の目標は他のより高水準の API でカバーされていないデバイスをサポートすることにある。上記のリストには、 そのような高水準 API が存在し、本 API による低水準アクセスよりもユーザーのプライバシーとセキュリティをより強く保護する インターフェイスクラスが含まれている。
-
configuration を interface.
[[configuration]]とする。 -
device を configuration.
[[device]]とする。 -
もし configuration が、device に対する 現在の構成を見つける の結果と同一でなければ、
falseを返す。 -
interfaceIndex を、インターフェイスのインデックスを見つける を interface.
[[interfaceNumber]]と configuration で行った結果とする。 -
表明: interfaceIndex は
-1と等しくない。 -
device.
[[claimedInterface]][interfaceIndex] を返す。
-
configuration を interface.
[[configuration]]とする。 -
device を configuration.
[[device]]とする。 -
alternateIndex を 0 とする。
-
インターフェイスがクレームされているかを判定する を interface に対して行った結果が
trueの場合:-
interfaceIndex を、インターフェイスのインデックスを見つける を interface.
[[interfaceNumber]]と configuration で行った結果とする。 -
表明: interfaceIndex は
-1と等しくない。 -
alternateIndex を、代替インデックスを見つける を device.
[[selectedAlternateSetting]][interfaceIndex] と interface で行った結果に設定する。
-
-
表明: alternateIndex は
-1と等しくない。 -
interface.
alternates[alternateIndex] を返す。
Note: インターフェイスディスクリプタ [USB31] によれば、インターフェイスには少なくとも 1 つの代替設定が存在する。 つまり、インターフェイスディスクリプタ には 少なくとも 1 つの代替設定がなければならない。
6.4.1. コンストラクター
USBInterface(configuration, interfaceNumber)
コンストラクターは、呼び出されたとき、次の手順を実行しなければならない:
-
this.
[[configuration]]を configuration に設定する。 -
this.
[[interfaceNumber]]を interfaceNumber に設定する。 -
descriptors を、構成のためのディスクリプタの一覧を見つける を
configurationValueに configuration.[[configurationValue]]を設定して実行した結果とする。 -
各 descriptor について(descriptors の要素):
-
もし descriptor の
bDescriptorTypeがINTERFACEと等しくなければ、続行する。 -
もし descriptor の
bInterfaceNumberが interfaceNumber と等しくなければ、続行する。 -
もし descriptor が 保護対象のインターフェイスクラスを持つ なら、 this.
[[isProtectedClass]]をtrueに設定する。 -
alternate を、新たな
USBAlternateInterfaceオブジェクトとして、 USBAlternateInterface(deviceInterface,alternateSetting) を用いて生成する。ここで deviceInterface は this、 alternateSetting は descriptor のbAlternateSettingとする。 -
追加する: alternate を this.
[[alternates]]に。
-
6.4.2. 属性
interfaceNumber, 型 octet、読み取り専用-
各インターフェイスは、
alternatesの集合を提供し、これらはそれぞれの インターフェイスディスクリプタ にある 単一のbInterfaceNumberフィールドで識別される。interfaceNumber属性はこのフィールドと一致しなければならない。interfaceNumberの getter 手順は次のとおり:-
this.
[[interfaceNumber]]を返す。
-
alternate, 型 USBAlternateInterface、読み取り専用-
alternate属性は、このインターフェイスで現在選択されているUSBAlternateInterfaceに設定されなければならない。既定では、bAlternateSettingが0のものとする。alternateの getter 手順は次のとおり:-
現在の代替設定に対応する代替インターフェイスを見つける を this に対して行った結果を返す。
-
alternates, 型 FrozenArray<USBAlternateInterface>、読み取り専用-
alternatesメソッドは、USBAlternateInterfaceオブジェクトの集合を提供し、これらはそれぞれの インターフェイスディスクリプタ にある 単一のbInterfaceNumberフィールドで識別される。alternatesの getter 手順は次のとおり:-
this.
[[alternates]]を返す。
-
claimed, 型 boolean、読み取り専用-
claimed属性は、当該インターフェイスが現在の実行コンテキストによりクレームされているときtrueに、 それ以外の場合はfalseに設定されなければならない。claimedの getter 手順は次のとおり:-
インターフェイスがクレームされているかを判定する を this に対して行った結果を返す。
-
6.5. USBAlternateInterface インターフェイス
[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 ; };
USBAlternateInterface
のインスタンスは、次の表に示す 内部スロット を持って生成される:
| 内部スロット | 初期値 | 説明(参考) |
|---|---|---|
[[interface]]
| <常に本文で設定> | USBInterface
オブジェクト。this が属する。
|
[[endpoints]]
| sequence(USBEndpoint)の空配列
| このインターフェイスによって公開されるすべてのエンドポイント。 |
[[alternateSetting]]
| <常に本文で設定> | このインターフェイスの代替設定。 |
-
descriptors を、構成のためのディスクリプタの一覧を見つける を configurationValue で行った結果とする。
-
endpointDescriptors を空の list とする。
-
index を 0 とする。
-
index が サイズ(descriptors の)より小さいあいだ:
-
descriptor を descriptors[index] とする。
-
もし descriptor の
bDescriptorTypeがINTERFACEと等しくなければ、 index を 1 増やして続行する。 -
もし descriptor の
bInterfaceNumberが interfaceNumber と等しくなければ、 index を 1 増やして続行する。 -
もし descriptor の
bAlternateSettingが alternateSetting と等しくなければ、 index を 1 増やして続行する。 -
もし
bNumEndpointsが 0 と等しければ、endpointDescriptors を返す。 -
numEndpoints を descriptor の
bNumEndpointsとする。 -
indexEndpoints を 0 とする。
-
offset を index + 1 とする。
-
indexEndpoints が numEndpoints より小さいあいだ:
-
追加する: descriptors[indexEndpoints + offset] を endpointDescriptors に。
-
indexEndpoints を 1 増やす。
-
-
endpointDescriptors を返す。
-
6.5.1. コンストラクター
USBAlternateInterface(deviceInterface, alternateSetting)
コンストラクターは、呼び出されたとき、次の手順を実行しなければならない:
-
this.
[[interface]]を deviceInterface に設定する。 -
this.
[[alternateSetting]]を alternateSetting に設定する。 -
descriptors を、エンドポイントディスクリプタの一覧を見つける を
interfaceNumberに deviceInterface.interfaceNumber、alternateSettingに alternateSetting、configurationValueに deviceInterface.[[configuration]].[[configurationValue]]を設定して実行した結果とする。 -
各 descriptor について(descriptors の要素):
-
もし descriptor の
bmAttributesが コントロール転送タイプ(すなわち エンドポイントディスクリプタ に従いビット0..1が00)を示すなら、続行する。 -
endpointAddress を descriptor の
bEndpointAddressとする。 -
dir を、もし
endpointAddress & 0x80が0なら"out"、 それ以外は"in"とする。 -
endpoint を、新たな
USBEndpointオブジェクトとして、 USBEndpoint(alternate,endpointNumber,direction) を用いて生成する。ここで alternate は this、 endpointNumber はendpointAddress & 0xF、 direction は dir とする。 -
追加する: endpoint を this.
[[endpoints]]に。
-
6.5.2. 属性
alternateSetting, 型 octet、読み取り専用-
各代替インターフェイス構成は、与えられたインターフェイス内で一意の
alternateSettingを持たなければならず、これはそれを定義する インターフェイスディスクリプタ のbAlternateSettingフィールドと一致しなければならない。 interfaceClass, 型 octet、読み取り専用interfaceSubclass, 型 octet、読み取り専用interfaceProtocol, 型 octet、読み取り専用-
interfaceClass、interfaceSubclass、 およびinterfaceProtocol属性は、当該インターフェイスがサポートする通信インターフェイスを宣言する。これらはそれぞれ、 インターフェイスディスクリプタ のbInterfaceClass、bInterfaceSubClass、bInterfaceProtocolの各フィールドの値と一致しなければならない。 interfaceName, 型 DOMString、読み取り専用、nullable-
interfaceName属性は、定義されている場合、インターフェイスディスクリプタ のiInterfaceフィールドで インデックス付けされる 文字列ディスクリプタ の値を含むことが望ましい(SHOULD)。 endpoints, 型 FrozenArray<USBEndpoint>、読み取り専用-
endpoints属性には、このインターフェイスによって公開されるエンドポイントの一覧が含まれていなければならない(SHALL)。これらのエンドポイントは、 当該 インターフェイスディスクリプタ に含まれる エンドポイントディスクリプタ から構築されなければならず、 この配列の要素数は インターフェイスディスクリプタ のbNumEndpointsの値と一致しなければならない。endpointsの getter 手順は次のとおり:-
this.
[[endpoints]]を返す。
-
6.6. USBEndpoint インターフェイス
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 ; };
USBEndpoint
のインスタンスは、次の表に記載の 内部スロット を伴って作成される。
| 内部スロット | 初期値 | 説明(非規範) |
|---|---|---|
[[alternateInterface]]
| <本文で常に設定> | USBAlternateInterface
オブジェクト。this が属する。
|
[[endpointAddress]]
| <本文で常に設定> | このエンドポイントのエンドポイントアドレス。 |
-
alternateInterface を endpoint.
[[alternateInterface]]とする。 -
interface を alternateInterface.
[[interface]]とする。 -
configuration を interface.
[[configuration]]とする。 -
endpointDescriptors を、
alternateSettingに alternateInterface.alternateSettingを、interfaceNumberに interface.interfaceNumberを、configurationValueに configuration.configurationValueを設定して エンドポイントディスクリプタの一覧を見つける を実行した結果とする。 -
各 endpointDescriptor(endpointDescriptors の要素)について:
-
もし endpoint.
[[endpointAddress]]が endpointDescriptor のbEndpointAddressと等しければ、 endpointDescriptor を返す。
-
6.6.1. コンストラクター
endpointNumber(alternate, endpointNumber, direction)
コンストラクターは、呼び出されたとき、次の手順を実行しなければならない:
-
this.
[[alternateInterface]]を alternate に設定する。 -
endpointAddress を次のように設定する。もし direction が
"in"ならendpointNumber | 0x80、 それ以外の場合は endpointNumber。 -
this.
[[endpointAddress]]を endpointAddress に設定する。
6.6.2. 属性
endpointNumber, 型 octet、読み取り専用direction, 型 USBDirection、読み取り専用-
特定のデバイス構成内の各エンドポイントは、
endpointNumberとdirectionの組み合わせが一意でなければならない(SHALL)。endpointNumberは、当該エンドポイントを定義する エンドポイントディスクリプタ のbEndpointAddressフィールドの 下位 4 ビットと等しくなければならない(MUST)。direction属性は、このエンドポイントがサポートする転送方向を表し、bEndpointAddressの最上位ビットが セットされている場合は"in"、 それ以外は"out"に等しい。 エンドポイントは、デバイスからホストへのINまたはホストからデバイスへのOUTのいずれかのデータを運ぶ。 type, 型 USBEndpointType、読み取り専用-
type属性は、このエンドポイントがサポートするデータ転送の種類を表す。typeの getter 手順は次のとおり:-
endpointDescriptor を、エンドポイントディスクリプタを見つける を this に対して実行した結果とする。
-
attr を endpointDescriptor の
bmAttributesとする。 -
typeBits を
attr & 0x3とする。 -
もし typeBits が
b01と等しければ、"isochronous"を返す。 -
もし typeBits が
b10と等しければ、"bulk"を返す。 -
もし typeBits が
b11と等しければ、"interrupt"を返す。
Note: USBAlternateInterface(deviceInterface,alternateSetting) の手順に従うと、コントロール転送タイプに属するエンドポイントオブジェクトは存在しないはずである。
-
packetSize, 型 unsigned long、読み取り専用-
packetSize属性は、このエンドポイントで用いられるパケットサイズを表し、当該エンドポイントを定義する エンドポイントディスクリプタ のwMaxPacketSizeの値と等しくなければならない(MUST)。High-Speed の High-Bandwidth エンドポイントでは、マイクロフレームあたり複数のトランザクションを発行することによる乗数が含まれる。SuperSpeed デバイスでは、 SuperSpeed Endpoint Companion ディスクリプタのbMaxBurstフィールドによる乗数が含まれる。packetSizeの getter 手順は次のとおり:-
endpointDescriptor を、エンドポイントディスクリプタを見つける を this に対して実行した結果とする。
-
endpointDescriptor の
wMaxPacketSizeを返す。
-
7. USB ブロックリスト
// USBBlocklistEntry is never exposed.dictionary {USBBlocklistEntry required unsigned short ;idVendor required unsigned short ;idProduct required unsigned short ; };bcdDevice
この仕様は、本リポジトリの blocklist.txt ファイルに依存して、 ウェブサイトがアクセスできるデバイスの集合を制限する。
URL
url にあるブロックリストを 解析する
結果は、次のアルゴリズムで生成される list の USBBlocklistEntry
オブジェクトである:
-
url を取得し、その本文を UTF-8 としてデコードしたものを contents とする。
-
lines を、厳密分割 により contents の先頭からコードポイント
'\n'で分割した結果とする。 -
blocklist を空の list とする。
-
各 line(lines の要素)について:
-
line を、先頭から
'#'に等しくないコードポイントの列を 収集 した結果に置き換える。 -
line を、前後の ASCII 空白の除去 結果に置き換える。
-
components を、厳密分割 により line の先頭から コードポイント
':'で分割した結果とする。 -
idVendor を、components[0] を 16 進数として解釈した結果とする。
-
idProduct を、components[1] を 16 進数として解釈した結果とする。
-
bcdDevice を
0xFFFFとする。 -
もし size(components)が 3 なら、 bcdDevice を components[2] を 16 進数として解釈した結果に設定する。
-
append する: idVendor, idProduct, bcdDevice を持つ新しい
USBBlocklistEntryを blocklist に。
-
-
blocklist を返す。
USB ブロックリスト は、 parsing the blocklist を https://raw.githubusercontent.com/WICG/webusb/main/blocklist.txt で行った結果である。UA はこのブロックリストを定期的に再取得すべきだが、その頻度は未規定である。
USBDevice
device は、次の手順が "blocked" を返す場合、ブロック対象 である(Document
document に対して):
-
もし document が
nullではなく、かつ document が allowed to use として名付けられた policy-controlled feature の"usb-unrestricted"を許可されているなら、 "not blocked" を返す。 -
各 entry(USB ブロックリスト の要素)について:
-
bcdDevice を device.
deviceVersionMajor<< 8 + device.deviceVersionMinor<< 4 + device.deviceVersionSubminorとする。 -
もし bcdDevice が entry.
bcdDevice以下なら、 "blocked" を返す。
-
"not blocked" を返す。
8. 統合
8.1. Permissions Policy
この仕様は、トークン "usb" により識別される
policy-controlled feature を定義する。
これは、usb
属性を Navigator
オブジェクト上に公開するかどうかを制御する。
この機能の 既定の許可リスト は ["self"] である。
この仕様は 2 つ目の
policy-controlled feature を定義する。これはトークン
"usb-unrestricted" により識別され、
ブロックリストに載っている USB デバイスおよび保護対象クラスのデバイスインターフェイスへのアクセス可否を制御する。
この機能は、Web Application Manifest で当該機能を宣言した
Isolated Web Apps
に対してのみ有効化されなければならない(MUST)。
[APPMANIFEST]
この機能の 既定の許可リスト は ["self"] である。
通常、これは トップレベルの traversable にある
Document
では既定で許可されることを意味する。しかし、この機能はマニフェストで宣言された Isolated Web Apps に対してのみ有効化されるという要件により、
実質的な既定の許可リストは ["none"] となる。
8.2. Permission API
[permissions] API は、 ウェブサイトがユーザーに権限を要求し、どの権限が付与されているかを照会するための統一的な手段を提供する。
"usb" という
powerful feature は次のように定義される:
- permission descriptor type
-
dictionary :USBPermissionDescriptor PermissionDescriptor {sequence <USBDeviceFilter >;filters sequence <USBDeviceFilter >; };exclusionFilters - extra permission data type
-
USBPermissionStorageとして定義される:dictionary {AllowedUSBDevice required octet ;vendorId required octet ;productId DOMString ; };serialNumber dictionary {USBPermissionStorage sequence <AllowedUSBDevice >= []; };allowedDevices AllowedUSBDeviceのインスタンスは、USB デバイスの配列を保持する 内部スロット[[devices]]を持つ。 - permission result type
-
[
Exposed =(Worker ,Window )]interface :USBPermissionResult PermissionStatus {attribute FrozenArray <USBDevice >; };devices - permission query algorithm
-
"usb" 権限を照会する ために、
USBPermissionDescriptordesc、USBPermissionStoragestorage、およびUSBPermissionResultstatus を用いて、UA は次を行う:-
もし
desc.が設定されているなら、filtersdesc.内の各 filter について、 それが 有効なフィルターでない 場合はfiltersTypeErrorを送出し、 これ以降の手順を中止する。 -
もし
desc.が設定されているなら、exclusionFiltersdesc.内の各 exclusionFilter について、 それが 有効なフィルターでない 場合はexclusionFiltersTypeErrorを送出し、 これ以降の手順を中止する。 -
matchingDevices を新しい
Arrayとする。 -
storage.内の各 allowedDevice について、 さらにallowedDevicesallowedDevice@内の各 device について、 次の副手順を実行する:[[devices]]-
もし
desc.が設定されており、device がfiltersdesc.内の いずれの デバイスフィルターに一致 しないなら、 次の device に進む。filters -
もし
desc.が設定されており、device がexclusionFiltersdesc.内の デバイスフィルターに一致 するなら、 次の device に進む。exclusionFilters -
device を表す
USBDeviceを取得し、 matchingDevices に追加する。
-
-
status.を、その内容が matchingDevices である新しいdevicesFrozenArrayに設定する。
-
- permission request algorithm
- "usb" 権限を要求する。
9. 用語
この仕様では、[USB31] から採用した複数の用語を使用する。 参照は Universal Serial Bus のバージョン 3.1 に対して行っているが、これらの概念の多くは 以前のバージョンにも存在する。本仕様に関係する USB バージョン間の重要な差異は明示的に言及する。
Descriptors は、 デバイスから読み取ることができ、その特性および機能を記述するバイナリデータ構造である:
-
device descriptor はデバイス全体に適用される情報を含み、 [USB31] の 9.6.1 節に記載されている。
-
configuration descriptor は、ホストが選択可能な特定の デバイスインターフェイスとエンドポイントの集合を記述する。そのフィールドは [USB31] の 9.6.3 節に記載されている。
-
interface descriptor は、プロトコルと通信エンドポイントを含む、 デバイスの特定の機能コンポーネントのインターフェイスを記述する。そのフィールドは [USB31] の 9.6.5 節に記載されている。
-
interface association descriptor は、単一の機能ユニットに属する複数の インターフェイス間の関連付けを作成する。そのフィールドは [USB31] の 9.6.4 節に記載されている。
-
endpoint descriptor は、デバイスへ送信またはデバイスから受信されるデータの経路を記述する。 そのフィールドは [USB31] の 9.6.6 節に記載されている。
-
string descriptor は単一の UTF16-LE 文字列を含み、他のディスクリプタからインデックスで参照される。 そのフィールドは [USB31] の 9.6.9 節に記載されている。
Binary Object Store(BOS)は、標準のデバイス ディスクリプタよりも自由形式の追加ディスクリプタ集合である。特筆すべきは Platform Descriptor であり、 第三者(本仕様のような)が独自のディスクリプタ型を宣言することを可能にする。 これらは UUID によって識別される。Binary Object Store は [USB31] の 9.6.2 節で説明されている。
USB device は単一の
device descriptor を持ち、
そこから 1 つ以上の configuration descriptor へとリンクする。
vendor ID は
USB-IF によってデバイス製造者へ割り当てられ、device descriptor の
idVendor フィールドに保存される。
product
ID は製造者によって割り当てられ、
device descriptor の
idProduct フィールドに保存される。
serial
number は任意のプロパティであり、
device descriptor の
iSerialNumber フィールドが 0 でない場合に定義され、そのインデックスが参照する
string descriptor である。
Get Configuration は、 現在のデバイス構成値を取得する要求であり、[USB31] の 9.4.2 節に記載されている。
Set Descriptor は、 指定した Descriptor Type と Descriptor Index のディスクリプタを取得する要求であり、 [USB31] の 9.4.8 節に記載されている。
Get Descriptor は、 指定した Descriptor Type と Descriptor Index のディスクリプタを取得する要求であり、 [USB31] の 9.4.3 節に記載されている。
Note: デバイスの descriptors はほとんどの場合変化しない(Set Descriptor によって descriptors が変更される場合を除く)。 デバイスへの冗長な Get Descriptor トラフィックを削減するために、 実装は descriptors を保存する リードスルー/ライトスルーのキャッシュ層を持つことができる。
control transfer は、 もっとも一般的にデバイスの構成に使用される USB トラフィックの特別なクラスである。 これは 3 つの段階、すなわち setup、data、status からなる。setup stage では、要求パラメータ(転送方向や後続データのサイズを含む)を含む setup packet がデバイスに送られる。 data stage では、そのデータが デバイスへ送信されるか、デバイスから受信される。status stage では、要求の成功が確認されるか、失敗が通知される。
10. 付録: USB の簡単な紹介
この節は規範ではない。
USB はネットワークであるが、従来の TCP/IP ネットワークとは大きく異なる。実際には RPC システムに近い。 すべてのトラフィックはホスト(あなたのコンピュータ)によって制御される。スマートフォンのように USB ホストと USB クライアントの両方として動作できるデバイスもあるが、一度に担える役割は一方のみである。
10.1. ディスクリプタ
USB デバイスは、descriptors と呼ばれる バイナリ構造の集合をホストに提供することで自らを識別する。ホストが最初に読むのは device descriptor であり、USB-IF によって割り当てられた ベンダーおよびプロダクト ID、製造者などの基本情報を含む。その後、ホストはデバイスの configuration descriptor を読み取る。 これは、公開されるインターフェイスやエンドポイントを含むデバイスの機能を記述する。 クラスはデバイスレベルまたは個々のインターフェイスで宣言できる。複数のインターフェイスで 異なる機能を提供するデバイスは 複合デバイス(composite device) と呼ばれる。
10.2. 転送
データがホストからデバイスへ、またはその逆方向へ移動する場合でも、転送は常にホストによって開始される。 OUT transfers はホストからデバイスへのデータを運び、 デバイスが受信を確認するまで待機することがある。IN transfers はデバイスからホストへのデータを運び、 デバイスが送信すべきデータを用意するまで待機しなければならないことがある。転送はデバイスのいずれかの エンドポイントに対して実行され、送信するトラフィックの種類に応じて異なるタイプがある。
-
Bulk transfers は、 利用可能な帯域で大量のデータを送るのに適している。USB マスストレージデバイスへの読み書きに使用される。
-
Interrupt transfers は、(大きな bulk transfers によってブロックされないよう帯域を予約することで)遅延の保証を提供するが、 パケットサイズは制限される。これは信号送出やマウスの移動・ボタン押下のような小さなパケットに用いられる。
-
Isochronous transfers も帯域を予約するが、配送を保証しない。音声や映像などのストリーミングデータに用いられる。
-
すべてのデバイスは特別な default endpoint も持つ。通常のエンドポイントは一方向のみでデータを運ぶのに対し、 control transfers には常にデバイスへ送られる SETUP パケット と呼ばれる小さなヘッダがあり、 これは要求パラメータを含む。さらに、より大きなデータペイロードは IN または OUT のいずれかとなる。