1. 소개
이 절은 비규범적(non-normative)입니다.
범용 직렬 버스(USB)는 유선 주변기기의 사실상 표준입니다. 대부분의 USB 장치는 약 12개의 표준 "디바이스 클래스" 중 하나를 구현합니다. 이들은 장치가 지원하는 기능을 광고하고, 해당 기능 사용을 위한 명령 및 데이터 포맷을 규정합니다. 표준 디바이스 클래스에는 키보드, 마우스, 오디오, 비디오 및 저장 장치 등이 포함됩니다. 운영 체제는 이러한 장치를 OS 공급자가 제공하는 "클래스 드라이버"를 이용해 지원합니다. 하지만 표준화된 디바이스 클래스에 속하지 않는 장치도 많이 존재합니다. 이러한 장치는 하드웨어 공급업체가 자체 드라이버와 SDK를 직접 작성해야 하며, 이 네이티브 코드는 해당 장치가 웹에서 사용되는 것을 어렵게 만듭니다.
WebUSB API는 USB 장치 서비스를 웹에 안전하게 노출할 수 있는 방법을 제공합니다. 기존 네이티브 USB 라이브러리를 사용해 본 개발자들이 익숙하게 느낄 수 있는 API와 기존 명세에 정의된 디바이스 인터페이스를 노출합니다. 이 API를 사용하면 하드웨어 제조사는 자체 장치용 크로스플랫폼 JavaScript SDK를 만들 수 있습니다. 이로 인해 새로운 유형의 장치가 브라우저에 특정 API가 제공될 만큼 대중화될 때까지 기다릴 필요 없이, 웹을 위한 혁신적인 하드웨어가 처음부터 바로 개발될 수 있게 됩니다.
USB에 대한 자세한 정보는 § 10 부록: USB 간략 소개를 참고하세요.
2. 적용 동기 예시
이 절은 비규범적(non-normative)입니다.
2.1. 교육용 장치
웹의 소프트웨어 전달 모델은 플랫폼 호환성이나 관리자 권한 문제 없이 어디서든 빠르게 로드할 수 있기 때문에 교육용 애플리케이션을 가능케 하는 핵심 요소입니다. 과학 수업에서는 컴퓨터 기반 측정 및 데이터 로깅을 활용하고 있습니다. 이러한 도구들은 번들 소프트웨어를 필요로 하지만, 새로운 네이티브 앱을 추가할 때마다 IT 부서의 부담이 커지기 때문에 관리되는 컴퓨터에 설치하기 힘들 수 있습니다. 웹 기반 하드웨어 API를 사용하면 이런 장치 지원을 기존 온라인 강의 자료에 직접 빌드할 수 있어, 완전히 매끄러운 경험을 제공합니다.
다양한 마이크로컨트롤러 개발 키트로 코딩을 배우는 학생들은 온라인 개발 도구를 사용하여 코드를 작성 및 업로드할 수 있습니다. 이미 이러한 도구가 존재하지만 브라우저와 하드웨어를 연결하려면 네이티브 컴포넌트가 별도로 필요합니다. 이 네이티브 확장들은 진입 장벽을 높이고, 샌드박스 기반 웹 환경 내 코드에서는 노출되지 않는 보안 취약점에 사용자를 노출시킬 수 있습니다.
2.2. 웹 드라이버(Web Drivers)
웹의 조합성(composability)은 완전히 웹 기술만으로 새로운 하드웨어 지원 생태계를 구축할 수 있게 합니다. 3D 프린터 예시를 들면, 3D 오브젝트 디자인을 호스팅하는 사이트가 프린트 기능을 직접 통합하고 싶어할 수 있습니다. 웹은 2D 프린팅은 지원하지만 3D 프린팅용 API는 없습니다. 제조사가 WebUSB API를 사용하여 자신의 프린터에 데이터를 보내는 임베드 페이지를 제공한다면, 사이트들은 지도 삽입 기능처럼 해당 페이지를 활용하여 하드웨어 지원을 쉽게 추가할 수 있습니다.
2.3. 장치 업데이트 및 진단
블루투스와 같은 무선 프로토콜이 소비자 장치에 더 편리하게 쓰이기도 하지만, USB 포트는 전원 공급에 용이하며 장치에 문제가 있을 때 최후의 연결수단으로 계속 널리 사용되고 있습니다. 하드웨어 제조사가 지원 웹사이트에 업데이트/진단 도구를 통합하면 고객이 어떤 플랫폼에서도 도구를 사용할 수 있으며, 웹사이트를 통해 지원을 받을 때 더 나은 진단 데이터를 수집할 수 있습니다. 랜딩 페이지는 사용자가 적절한 도움을 받을 수 있도록 제조사가 해당 웹사이트의 올바른 위치로 안내할 수 있는 방법을 제공합니다.
3. 보안 및 개인정보 보호 고려사항
이 절은 비규범적(non-normative)입니다.
WebUSB API는 강력한 기능을 제공하는 동시에, 사용자가 새로운 보안·개인정보 침해 위험에 노출될 수 있습니다. 이러한 위험은 크게 세 가지로 구분되며, 아래의 절에서 다룹니다.
3.1. 장치 접근권 남용
주변기기는 다양한 용도로 사용될 수 있습니다. 플래시 드라이브처럼 데이터를 저장할 수도 있고, 카메라나 마이크처럼 외부 정보를 수집할 수도 있으며, 프린터처럼 외부 세계에 영향을 줄 수도 있습니다. 이런 예시들은 모두 악의적인 사이트로 인한 오남용을 막기 위해 웹 플랫폼에서 고수준 API에 보안 장치를 마련하고 있습니다. 예를 들어 외장 드라이브로의 데이터 저장은 사용자가 파일을 직접 선택해야 하고, 마이크나 카메라 켜기는 사용자 허가가 필요하며, 장치 활성시 표시등이 켜질 수 있습니다. 프린트 또한 직접 사용자 조작이 필요합니다. 이 API는 기존 고수준 API들이 다루지 않는 장치에도 범용적으로 연결할 수 있도록 하지만, 악의적 웹 페이지의 오남용을 막는 범용적 보호장치 역시 필요합니다.
첫 번째 보호장치는 requestDevice()
함수입니다. UA는 이 함수 호출 시 권한 요청 페이지(프롬프트)를 표시할 수 있습니다. 이 동작은 악의적 웹페이지뿐 아니라, 사용자가 연결 가능한 장치가 있다는 사실을 미리 알지 못하는
경우에도 연결 전 허가를 받음으로써 개인정보 보호도 돕습니다. UA는 장치 연결이 활성 상태일 때 인디케이터(표시)를 표시할 수도 있습니다.
둘째로, 이 명세는 [powerful-features]에서 설명된 '보안 컨텍스트'에서만 USB 장치 접근을 허용하도록 요구합니다. 이를 통해 오리진에서 실행 중인 코드의 신뢰성과 장치에서 읽은 데이터가 전송 중에 탈취당하지 않음을 보장합니다.
끝으로, USB 장치들은 여러 주체의 요청을 구별할 수 없기 때문에 운영체제는 단일 USB 인터페이스를 동시에 하나의 사용자 공간 또는 커널 공간 드라이버만 가지도록 허용합니다. UA는 사용자
공간 드라이버 역할을 하므로, 한 번에 하나의 실행 컨텍스트만 USB 인터페이스를 점유할 수 있습니다. claimInterface()
함수는 여러 실행 컨텍스트가 동시에 인터페이스를 점유하려 할 경우 실패합니다.
3.2. 장치 공격
과거에는 높은 보안을 요구하는 경우가 아니라면 대부분의 USB 장치는 자신이 연결된 호스트를 신뢰하도록 설계됐으며, 호스트가 전통적으로 장치가 제공하는 기능에 대한 접근을 통제해왔습니다. 이
명세를 개발하며 두 가지 대안을 고려했습니다. 첫째, UA가 요청 발생 오리진을 장치에 알릴 수 있습니다. 이는 HTTP 요청에 첨부되는 Referrer 헤더와
유사합니다. 문제는 이 방식이 접근 통제의 부담을 장치에 부과한다는 점입니다. 많은 장치가 매우 제한된 처리능력/저장공간만 제공하므로, 장치가 담당해야 할 작업량은 최대한 줄이려고 했습니다.
이 명세 초안 단계에서 채택된 초기 방법은 UA가 [CORS]와 비슷한 메커니즘을 통해 접근을 제어하도록 요구하는 것이었습니다. 장치는 자신이 허용하는 오리진 리스트를 UA에 정적 데이터 구조로 제공할 수 있는 기능을 갖추거나, 기존 장치 지원을 위해 퍼블릭 레지스트리에 제공할 수도 있다고 제안되었습니다.
이 방법의 문제점은 두 가지입니다. 첫째, 제조사는 WebUSB를 고려해 신제품을 만들어야 하거나, 명확히 명세하기 힘든 퍼블릭 레지스트리 시스템에 의존해야 합니다. 제품 개발 주기는 길고, 에디터 초안 단계인 현 명세는 시장에 영향을 미칠만한 권위를 갖지 않습니다. 둘째, 서드파티 개발자가 이 API로 장치를 사용할 방법이 없으므로 혁신과 개발자 수 모두 한계가 있었습니다.
이 옵션들을 모두 검토한 끝에, 작성자들은 requestDevice()
방식으로 권한 프롬프트를 제공하고 § 8.1 권한 정책(Permissions Policy)과 연동하는 현 구조면
충분한 장치 보안 대책이 된다고 결론지었습니다.
3.3. 호스트 공격
만약 장치가 해킹된다면, 그 자체 기능 오남용 외에도 장치를 통해 연결된 호스트(혹은 향후 연결될 모든 호스트)를 다시 공격받을 수 있습니다. 위의 방법들은 이 명세가 이런 공격 경로를 최소화하려는 방식들입니다. 그러나 일단 장치가 공격자에게 넘어가면(예, 악의적 펌웨어 이미지를 업로드), UA가 추가 피해를 막을 방법은 없습니다.
따라서 이 명세는 디바이스 제조사가 방어적 설계를 채택할 것을 권장합니다. 예를 들어 서명된 펌웨어 업데이트만 적용하거나, 일부 설정 변경에는 물리적 접근을 요구하는 식입니다.
4. WebUSB 디스크립터 및 요청
이 명세는 UA가 API 구현시 장치에 대해 얻을 수 있는 정보를 위해 사용할 수 있는 디스크립터와 명령을 정의합니다.
4.1. WebUSB 플랫폼 기능 디스크립터(Platform Capability Descriptor)
장치는 다음 Platform Descriptor를 자신의 Binary Object Store에 포함시켜 WebUSB 명령 세트 지원을 알립니다:
| Offset | Field | Size | Value | 설명 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 이 디스크립터의 크기. 반드시 24로 설정해야 합니다. |
| 1 | bDescriptorType | 1 | Constant | DEVICE CAPABILITY 디스크립터 타입 ([USB31] Table 9-6). |
| 2 | bDevCapabilityType | 1 | Constant | PLATFORM capability 타입 ([USB31] Table 9-14). |
| 3 | bReserved | 1 | Number | 예약 필드, 반드시 0이어야 합니다. |
| 4 | PlatformCapabilityUUID | 16 | UUID | {3408b638-09a9-47a0-8bfd-a0768815b665}로 설정되어야 함. |
| 20 | bcdVersion | 2 | BCD | 지원 프로토콜 버전. 반드시 0x0100. |
| 22 | bVendorCode | 1 | Number | WebUSB 요청을 수행할 때 사용하는 bRequest 값. |
| 23 | iLandingPage | 1 | Number | 장치의 랜딩 페이지의 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 장치 요청
이 명세가 정의한 모든 제어 전송(control
transfer)
은 벤더 전용 요청으로 간주합니다. WebUSB 플랫폼 기능 디스크립터의 bVendorCode 값은
호스트가 장치에 제어 전송 을 할 때 사용할
bRequest 값을 제공합니다.
요청 타입은 wIndex 필드에 정의됩니다.
| Constant | Value |
|---|---|
| (Reserved) | 1 |
| GET_URL | 2 |
4.2.1. URL 얻기(Get URL)
이 요청은 지정된 인덱스의 URL 디스크립터를 가져옵니다.
장치는 해당 인덱스의 URL 디스크립터를 반환하거나, 인덱스가 유효하지 않으면 전송을 스톨(stall)해야 합니다.
| bmRequestType | bRequest | wValue | wIndex | wLength | Data |
|---|---|---|---|---|---|
| 11000000B | bVendorCode
| Descriptor Index | GET_URL | Descriptor Length | Descriptor |
4.3. WebUSB 디스크립터
이 명세서에 정의된 요청에 의해 반환되는 디스크립터 타입입니다.
| Constant | Value |
|---|---|
| (Reserved) | 0-2 |
| WEBUSB_URL | 3 |
4.3.1. URL 디스크립터
이 디스크립터는 한 개의 URL을 포함하며, Get URL 요청에 의해 반환됩니다.
| Offset | Field | Size | Value | 설명 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 이 디스크립터의 크기. |
| 1 | bDescriptorType | 1 | Constant | WEBUSB_URL. |
| 2 | bScheme | 1 | Number | URL scheme prefix. |
| 3 | URL | Variable | String | UTF-8로 인코딩된 URL(스킴 프리픽스 제외). |
bScheme 필드는 다음 값 중 하나여야 합니다:
| Value | Prefix |
|---|---|
| 0 | "http://" |
| 1 | "https://" |
| 255 | "" |
특수 값 255는 scheme을 포함한 전체 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에 추가합니다. }); });
페이지가 로드된 후에도 사용자가 장치를 연결하거나 연결 해제할 수 있으므로, UI 상태를 최신으로 유지하려면 스크립트에서도 이러한 이벤트를 등록해야 합니다.
navigator. usb. addEventListener( 'connect' , event=> { // |event.device|를 UI에 추가합니다. }); navigator. usb. addEventListener( 'disconnect' , event=> { // |event.device|를 UI에서 제거합니다. });
사용자가 페이지를 처음 방문한 경우에는 어떤 장치에도 접근 권한이 없으므로, 관련 전역 객체에 일시적 활성화가 있을 때, 먼저 requestDevice()를
호출해야 합니다.
이 예제에서는 vendor가 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 작업 소스(task source)에 작업을 큐잉합니다.
USB 장치 device는 디바이스
필터에 일치한다 filter 는 아래 단계가 match를 반환하면 참입니다:
-
deviceDesc를 device의 디바이스 디스크립터로 둡니다.
-
filter.가 있으면vendorIddeviceDesc.idVendor와 같지 않으면mismatch를 반환합니다. -
filter.가 있으면productIddeviceDesc.idProduct와 같지 않으면mismatch를 반환합니다. -
filter.가 있으면, serialNumber를 문자열 디스크립터 중serialNumberdeviceDesc.iSerialNumber로 둡니다. device가 serialNumber 요청에 오류를 반환하거나, serialNumber가filter.와 다르면serialNumbermismatch를 반환합니다. -
filter.가 있으면, device 내 어디든 interface가 filter로 인터페이스 필터 일치라면classCodematch를 반환합니다. -
filter.가 있으면classCodedeviceDesc.bDeviceClass가 다르면mismatch를 반환합니다. -
filter.가 있으면subclassCodedeviceDesc.bDeviceSubClass가 다르면mismatch를 반환합니다. -
filter.가 있으면protocolCodedeviceDesc.bDeviceProtocol가 다르면mismatch를 반환합니다. -
match를 반환합니다.
참고: 위 단계는 디바이스 디스크립터의 bDeviceClass,
bDeviceSubClass, bDeviceProtocol 필드를 인터페이스 디스크립터에서 비교하는 것처럼 처리합니다.
USB 인터페이스 interface가 인터페이스 필터에
일치 filter 이려면 다음 단계가 match를 반환해야 합니다:
-
desc를 interface의 인터페이스 디스크립터로 둡니다.
-
filter.가 있으면classCodedesc.bInterfaceClass가 다르면mismatch를 반환합니다. -
filter.가 있으면subclassCodedesc.bInterfaceSubClass가 다르면mismatch를 반환합니다. -
filter.가 있으면protocolCodedesc.bInterfaceProtocol가 다르면mismatch를 반환합니다. -
match를 반환합니다.
USBDeviceFilter
filter는 유효한 필터이다가 아래 단계가 valid를 반환하면 참입니다:
-
filter.가 있으나,subclassCodefilter.가 없다면classCodeinvalid반환. -
filter.가 있으나,protocolCodefilter.가 없다면subclassCodeinvalid반환. -
valid반환.
UA는 시스템에 연결된 모든 장치를 나열할 수 있어야 합니다.
단, 알고리즘마다 매번 나열을 수행할 필요는 없습니다. UA는 최초 나열 결과를 캐싱한 뒤 장치 연결/해제 이벤트를 모니터링하고,
연결된 장치는 캐시된 나열에 추가하고, 해제된 장치는 제거할 수 있습니다. 이런 동작 방식이 OS 호출 횟수와 버스 트래픽을 줄이기 때문에 바람직합니다.
이 모드는 getDevices()
및 requestDevice()
호출로 발생하는 시스템 부하를 낮춥니다.
onconnect
속성은 connect 이벤트 타입의 이벤트 핸들러 IDL 속성입니다.
ondisconnect
속성은 disconnect 이벤트 타입의 이벤트 핸들러 IDL
속성입니다.
getDevices() 메서드는 호출될 때 반드시 다음 단계를 실행해야 합니다:
-
document를 global의 연결된 Document로 하고, 연결된
Document가 없으면null로 둡니다. -
storage를 다음과 같이 둡니다:
-
연관된 service worker client의 스크립트 실행 환경에 있는
USBPermissionStorage객체, 만약 global이ServiceWorkerGlobalScope라면. -
그 외의 경우, 현재 스크립트 실행 환경의
USBPermissionStorage객체.
-
-
promise를 새로운 promise로 둡니다.
-
다음 단계를 병렬로 실행합니다:
-
시스템에 연결된 모든 장치 나열을 수행하고, 이 결과를 enumerationResult로 둡니다.
-
devices를 새로운 빈
Array로 둡니다. -
enumerationResult의 각 device에 대해 다음을 수행:
-
device가 document에 대해 차단 목록(blocklisted)이면, continue합니다.
-
이 메서드의 첫 번째 호출이라면 storage로 device의 권한 확인을 수행합니다.
-
storage.
allowedDevices중에서 device가 allowedDevice.[[devices]]에 존재하는 요소를 탐색하고, 없다면 다음 device로 넘어갑니다.
-
-
device를 나타내는
USBDevice객체를 devices에 추가합니다. -
글로벌 작업을 대기열에 추가하여 USB 작업 소스에 global과 함께 promise를 devices로 resolve 하도록 합니다.
-
-
promise를 반환합니다.
requestDevice(options) 메서드는 호출될 때 다음 단계를 반드시
실행해야 합니다:
-
다음 기술(descriptor)에 대한 권한을 요청합니다.
{ name: "usb" filters: options. filters exclusionFilters: options. exclusionFilters} permissionResult를 결과로 나오는
Promise로 둡니다. -
permissionResult가 result와 함께 이행(fulfillment)될 때 다음 단계를 실행합니다:
-
result.
devices가 비어 있다면, "NotFoundError"DOMException을 발생시키고, 이 단계를 중단합니다. -
result.
devices[0]을 반환합니다.
-
Document
document, USBPermissionStorage
storage, USBPermissionDescriptor
options와
USBPermissionResult
status가 주어지면 UA는 반드시 다음 단계를 실행해야 합니다:
-
global을 storage의 관련 전역 객체로 둡니다.
-
각 filter에 대해 options.
filters내에 filter가 유효하지 않은 필터라면, 거부된 promise를TypeError와 함께 반환합니다. -
각 exclusionFilter에 대해 options.
exclusionFilters내에 exclusionFilter가 유효하지 않은 필터라면, 거부된 promise를TypeError와 함께 반환합니다. -
이 알고리즘이 global에 일시적 활성화(transient activation) 상태에서 트리거됐는지 확인합니다. 아니라면, 거부된 promise를 "
SecurityError"DOMException과 함께 반환합니다. -
promise를 새로운 promise로 둡니다.
-
다음 단계를 병렬로 실행합니다.
-
시스템에 연결된 모든 장치 나열을 수행하고, 결과를 enumerationResult로 둡니다.
-
document에 대해 차단 목록에 포함된 장치는 enumerationResult에서 제거합니다.
-
options.
filters중 어느 필터에도 일치하지 않는 장치는 enumerationResult에서 제거합니다. -
options.
exclusionFilters중 어느 필터에 일치하는 장치는 enumerationResult에서 제거합니다. -
사용자에게 enumerationResult에서 장치를 선택하라는 안내 프롬프트를 표시합니다. UA는 각 장치의 사람이 알아볼 수 있는 이름을 표시해야 합니다.
-
사용자가 device를 선택하거나 프롬프트를 취소할 때까지 대기합니다.
-
글로벌 작업을 대기열에 USB 작업 소스 global에 추가하여 다음 단계를 실행:
-
status.
state값을"ask"로 설정합니다. -
사용자가 프롬프트를 취소했다면 status.
devices를 빈FrozenArray로 하고, resolve promise withundefined하여 이 단계를 중단합니다. -
deviceObj를 device를 나타내는
USBDevice객체로 둡니다. -
status.
devices값을 deviceObj 하나만 들어있는 새로운FrozenArray로 설정합니다. -
resolve promise with
undefined합니다.
-
-
-
promise를 반환합니다.
허용된 USB
device를 USBPermissionStorage
storage에 추가하려면, UA는 반드시 다음 단계를 실행해야 합니다:
-
storage.
allowedDevices중에서 device가 allowedDevice@[[devices]]에 포함된 요소를 찾고, 존재한다면 이 단계를 중단합니다. -
vendorId 및 productId를 device의 vendor ID와 product ID로 둡니다.
-
serialNumber를 device의 serial number로, 없다면
undefined로 둡니다. -
{ vendorId: vendorId, productId: productId, serialNumber: serialNumber }을[[devices]]슬롯에 device만 포함된 상태로storage.에 추가합니다.allowedDevices
새로운 USB device의 권한 확인 시, USBPermissionStorage
storage가 주어진 경우, UA는 반드시 다음 단계를 실행해야 합니다:
-
vendorId 및 productId를 device의 vendor ID와 product ID로 둡니다.
-
serialNumber를 device에 있으면 그 값으로, 없으면
undefined로 둡니다. -
storage.
allowedDevices내에서 다음 조건을 모두 만족하는 allowedDevice를 찾습니다:-
allowedDevice.값이 vendorId와 같습니다.vendorId -
allowedDevice.값이 productId와 같습니다.productId -
allowedDevice.값이 serialNumber와 같습니다.serialNumber
-
-
이런 요소가 없으면
null을 반환합니다. -
device를 allowedDevice@
[[devices]]에 추가합니다. -
allowedDevice를 반환합니다.
허용된 USB device를 제거하려면, USBPermissionStorage
storage가 주어진 경우 UA는 반드시 다음 단계를 실행해야 합니다:
-
storage.
allowedDevices내에서 device가 allowedDevice@[[devices]]에 포함된 요소를 찾고, 없으면 중단합니다. -
storage.에서 allowedDevice를 제거합니다.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
참고: Workers는 connect 및 disconnect 이벤트에 대한 이벤트 리스너를 등록할 수 있으나, 워커가 활성 상태가 아니면 이벤트 리스너는 호출되지 않습니다.
UA가 호스트에 새 USB 장치 device가 연결된 것을 감지하면 각 스크립트 실행 환경에 대해 다음 단계를 수행해야 합니다:
-
현재 스크립트 실행 환경에서 storage를
USBPermissionStorage객체로 둡니다. -
device에 대한 권한을 확인하고 결과를 allowedDevice로 둡니다.
-
만약 allowedDevice가
null이면, 이 단계를 중단합니다. -
deviceObj를 device를 나타내는
USBDevice객체로 둡니다. -
이벤트 발생을 사용하여 connect라는 이름의 이벤트를 device의 관련 전역 객체의
Navigator객체의usb에서 발생시키되,USBConnectionEvent를 사용하고,device속성을 deviceObj로 설정합니다.
UA가 호스트에서 USB 장치 device가 분리된 것을 감지하면 각 스크립트 실행 환경에 대해 다음 단계를 수행해야 합니다:
-
현재 스크립트 실행 환경에서 storage를
USBPermissionStorage객체로 둡니다. -
storage.
allowedDevices에서 device가 allowedDevice의 [[devices]]에 있는 요소 allowedDevice를 검색합니다. 그런 요소가 없으면 이 단계를 중단합니다. -
device를 allowedDevice의 [[devices]]에서 제거합니다.
-
만약 allowedDevice의
serialNumber가undefined이고 allowedDevice의 [[devices]]가 비어있다면, allowedDevice를 storage.allowedDevices에서 제거합니다. -
device를 device를 나타내는
USBDevice객체로 둡니다. -
이벤트 발생을 사용하여 disconnect라는 이름의 이벤트를 device의 관련 전역 객체의
Navigator객체의usb에서 발생시키되,USBConnectionEvent를 사용하고,device속성을 device로 설정합니다.
6. 장치 사용법
bConfigurationValue 1)
과 단일 인터페이스(bInterfaceNumber 1), 단일 벌크 엔드포인트(bEndpointAddress 0x81 — 즉 endpoint 1
이고 IN 엔드포인트)을 가집니다. 데이터가 샘플링되면 이 엔드포인트에서 이용할 수 있습니다. 이 엔드포인트의 최대 패킷 크기는 모든 8개 채널이 동시에 활성화되는 것을 지원하기 위해
16바이트입니다. 그러나 버스 대역폭을 절약하기 위해 임의의 채널 조합을 활성화하거나 비활성화할 수 있습니다. 패킷은 전송된 데이터에 필요한 길이만큼만 전송됩니다.
시작하려면 장치를 열고, 첫 번째 구성을 선택(장치에는 하나뿐이지만 운영 체제가 열거과정에서 이미 선택했을 수 있음)하고 데이터 로깅 인터페이스를 클레임합니다,
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바이트 버퍼를 요청합니다. 완전한 버퍼를 받는 한 캡처된 값들(빅 엔디안으로 전송됨)은 콘솔 로그에 출력됩니다. 장치가 오류를 만나 엔드포인트를 스톨한 경우에는 계속하기 전에 오류를 클리어합니다,
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 of USBConfiguration
| 이 장치가 지원하는 모든 구성들. |
[[configurationValue]]
| <문서에서 항상 설정됨> | 장치의 현재 구성 값. |
[[selectedAlternateSetting]]
| 빈 정수 리스트 | 현재 구성에서 각 인터페이스의 현재 대체 설정. |
[[claimedInterface]]
| 빈 불리언 리스트 | 현재 구성에서 각 인터페이스의 클레임 상태. |
-
연결된 장치의 deviceDescriptor를 device descriptor로 두되, Get Descriptor를 수행하여
DescriptorType을DEVICE로 설정합니다. -
deviceDescriptor를 반환합니다.
-
deviceDescriptor를 연결된 USB 장치의 디바이스 디스크립터를 찾는 결과로 둡니다.
-
numConfigurations를 deviceDescriptor의
bNumConfigurations로 둡니다. -
configurationIndex를 0으로 둡니다.
-
configurationDescriptors를 빈 리스트로 둡니다.
-
만약 configurationIndex가 numConfigurations보다 작을 동안:
-
Get Descriptor를
DescriptorType=CONFIGURATION,DescriptorIndex=configurationIndex로 수행하여 descriptors를 얻습니다. -
만약 descriptors[0]의
bDescriptorType이CONFIGURATION와 같다면, descriptors[0]을 configurationDescriptors에 추가합니다. -
configurationIndex를 1씩 증가시킵니다.
-
-
configurationDescriptors를 반환합니다.
-
global를 interface의 관련 전역 객체로 둡니다.
-
configuration를 interface.[[configuration]]로 둡니다.
-
device를 configuration.[[device]]로 둡니다.
-
만약 configuration이 device로 현재 구성을 찾은 결과와 같지 않다면, 반환합니다.
-
만약 인터페이스가 클레임되었는지 찾은 결과가
true가 아니라면, 반환합니다. -
currAlternateInterface를 현재 대체 설정에 대한 대체 인터페이스를 찾은 결과로 둡니다.
-
각 endpoint에 대해 currAlternateInterface.[[endpoints]]에 대해:
-
endpoint에 현재 스케줄된 모든 전송을 중단합니다.
-
관련된 프로미스들을 거부하기 위해 주어진 global에 대한 USB 작업 소스에서 전역 태스크를 큐에 추가하고, 연관된 프로미스들을 "AbortError"
AbortErrorDOMException로 거부합니다.
-
-
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를 device로 현재 구성을 찾은 결과로 둡니다.
-
만약 configuration가
null이면,null을 반환합니다. -
각 interface에 대해 configuration.[[interfaces]]를 반복합니다:
-
만약 인터페이스가 클레임되었는지 찾은 결과가
true가 아니라면, 계속합니다. -
alternate를 현재 대체 설정에 대한 대체 인터페이스를 찾은 결과로 둡니다.
-
각 endpoint에 대해 alternate.[[endpoints]]를 반복합니다:
-
만약 endpoint.[[endpointAddress]]가 endpointAddress와 같다면, endpoint를 반환합니다.
-
-
-
null을 반환합니다.
-
만약 device가 더 이상 시스템에 연결되어 있지 않다면, "
NotFoundError"DOMException으로 거부된 프로미스를 반환합니다. -
만약 device.
opened가true가 아니라면, "InvalidStateError"DOMException로 거부된 프로미스를 반환합니다. -
만약 device.[[configurationValue]]가
0과 같다면, "InvalidStateError"DOMException로 거부된 프로미스를 반환합니다. -
undefined를 반환합니다.
USBDevice
객체가 다음 단계를 수행하여 생성됩니다:
-
this.[[configurationValue]]를 Get Configuration의 반환값으로 설정합니다.
-
configurationDescriptors를 연결된 USB 장치에 대한 구성 디스크립터 목록을 찾은 결과로 둡니다.
-
각 configurationDescriptor에 대해 다음을 수행합니다:
-
configuration를 새로운
USBConfiguration객체로 만들되, USBConfiguration(device,configurationValue)를 사용하고, device를 this로, configurationValue를 configurationDescriptor의bConfigurationValue로 설정합니다. -
Append 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값은 major 버전JJ, minor 버전M, subminor 버전N을 나타냅니다. deviceClass, 유형 octet, 읽기 전용deviceSubclass, 유형 octet, 읽기 전용deviceProtocol, 유형 octet, 읽기 전용-
deviceClass,deviceSubclass및deviceProtocol속성은 장치가 지원하는 통신 인터페이스를 선언합니다. 이들은 각각 device descriptor의bDeviceClass,bDeviceSubClass및bDeviceProtocol필드 값과 일치해야 합니다. vendorId, 유형 unsigned short, 읽기 전용productId, 유형 unsigned short, 읽기 전용-
vendorId및productId는 장치의 vendor ID와 product ID와 동일해야 합니다. deviceVersionMajor, 유형 octet, 읽기 전용deviceVersionMinor, 유형 octet, 읽기 전용deviceVersionSubminor, 유형 octet, 읽기 전용-
deviceVersionMajor,deviceVersionMinor및deviceVersionSubminor속성은 제조업체가 정의한 장치 릴리스 번호를 선언합니다. 이는 device descriptor의bcdDevice필드 값과 일치해야 하며,0xJJMN값은 major 버전JJ, minor 버전M, subminor 버전N을 나타냅니다. manufacturerName, 유형 DOMString, 읽기 전용, nullableproductName, 유형 DOMString, 읽기 전용, nullableserialNumber, 유형 DOMString, 읽기 전용, nullable-
manufacturerName,productName및serialNumber속성은 각 device descriptor의iManufacturer,iProduct,iSerialNumber필드로 인덱스된 string descriptors의 값을 포함해야 합니다(정의되어 있는 경우). configuration, 유형 USBConfiguration, 읽기 전용, nullable-
configuration속성은 장치에 대해 현재 선택된 구성을 포함하며, 반드시USBConfiguration객체 중 하나이어야 하며, 이는configurations에 포함되어야 합니다.configuration게터 동작은 다음과 같습니다: configurations, 유형 FrozenArray<USBConfiguration>, 읽기 전용-
configurations속성은 장치가 지원하는 구성들을 나타내는 sequence를 포함합니다.configurations게터 동작은 다음과 같습니다:-
this.
[[configurations]]를 반환합니다.
-
opened, 유형 boolean, 읽기 전용-
opened속성은 현재 실행 컨텍스트에 의해 장치가 열려 있으면true로 설정되어야 하며, 그렇지 않으면false로 설정되어야 합니다.
6.1.2. 메서드
open() 메서드는 호출 시 다음 단계를 반드시 실행해야 합니다:
-
global를 this의 관련 전역 객체로 둡니다.
-
만약 this가 더 이상 시스템에 연결되어 있지 않다면, "
NotFoundError"DOMException으로 거부된 프로미스를 반환합니다. -
다음 단계를 병렬로 실행합니다.
-
장치와의 세션을 시작하기 위한 플랫폼 특유의 필요한 단계를 수행합니다.
-
USB 작업 소스에 대하여 global에 대한 전역 태스크를 큐에 추가하여 다음 단계를 실행합니다:
-
만약 위 플랫폼 단계가 실패하면 reject하여 promise를 "
NetworkError"DOMException로 거부하고 이 단계를 중단합니다. -
Resolve하여 promise를
undefined로 해결합니다.
-
-
-
promise를 반환합니다.
close() 메서드는 호출 시 다음 단계를 반드시 실행해야 합니다:
-
global를 this의 관련 전역 객체로 둡니다.
-
만약 this가 더 이상 시스템에 연결되어 있지 않다면, "
NotFoundError"DOMException으로 거부된 프로미스를 반환합니다. -
이 장치에 대해 현재 실행 중인 다른 모든 알고리즘을 중단하고 관련 프로미스들을 "
AbortError"DOMException으로 reject합니다. -
다음 단계를 병렬로 실행합니다.
-
각 클레임된 인터페이스에 대해
releaseInterface(interfaceNumber)가 호출된 것처럼 플랫폼 특유의 필요한 단계를 수행하여 모든 클레임된 인터페이스를 해제합니다. -
장치와의 세션을 종료하기 위한 플랫폼 특유의 필요한 단계를 수행합니다.
-
USB 작업 소스에 대하여 global에 대한 전역 태스크를 큐에 추가하여 다음 단계를 실행합니다:
-
-
promise를 반환합니다.
참고: 더 이상 어떤 [ECMAScript] 코드도
USBDevice
device 인스턴스를 관찰할 수 없게 되면, UA는 device.close()를
실행할 것을 권장합니다.
forget() 메서드는 호출 시 다음 단계를 반드시 실행해야 합니다:
-
device를 this로 둡니다.
-
storage를 현재 스크립트 실행 환경의
USBPermissionStorage객체로 둡니다. -
Remove device from storage를 storage로 실행합니다.
-
undefined로 해결된 프로미스를 반환합니다.
참고: 사용자 에이전트는 예를 들어 WebHID와 WebUSB 장치 접근을 통합된 저레벨 장치 접근 권한으로 추적하는 등 API 간 권한을 결합하도록 결정할 수 있습니다. 이 때문에 이 메서드는 향후 추가적인(아직 명시되지 않은) 권한도 취소할 수 있습니다.
selectConfiguration(configurationValue)
메서드는 호출 시 다음 단계를 반드시 실행해야 합니다:
-
global를 this의 관련 전역 객체로 둡니다.
-
만약 this가 더 이상 시스템에 연결되어 있지 않다면, "
NotFoundError"DOMException으로 거부된 프로미스를 반환합니다. -
selectedConfiguration를
null로 둡니다. -
this.[[configurations]]의 각 configuration에 대해 반복하며:
-
만약 configuration.[[configurationValue]]가 configurationValue와 같다면 selectedConfiguration를 configuration으로 설정하고 반복을 중단합니다.
-
-
만약 selectedConfiguration가
null이면, "NotFoundError"DOMException으로 거부된 프로미스를 반환합니다. -
만약 this.
opened가true가 아니면, "InvalidStateError"DOMException으로 거부된 프로미스를 반환합니다. -
다음 단계를 병렬로 실행합니다.
-
만약 activeConfiguration가
null이 아니라면:-
각 interface에 대해 activeConfiguration.[[interfaces]]를 반복하며, 해당 인터페이스에서 현재 스케줄된 전송을 중단합니다.
-
-
SET_CONFIGURATION제어 전송을 실행하여configurationValue를 지정된 configurationValue로 설정합니다. -
USB 작업 소스에 대하여 global의 전역 태스크를 큐에 추가하여 다음 단계를 실행합니다:
-
만약 위의 제어 전송이 실패하면 reject하여 promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단합니다. -
numInterfaces를 selectedConfiguration.[[interfaces]]의 크기로 둡니다.
-
this.[[selectedAlternateSetting]]의 크기를 numInterfaces로 조정합니다.
-
[[selectedAlternateSetting]]을 0으로 채웁니다.
-
[[claimedInterface]]의 크기를 numInterfaces로 조정합니다.
-
[[claimedInterface]]를
false로 채웁니다. -
this.[[configurationValue]]를 configurationValue로 설정합니다.
-
Resolve하여 promise를
undefined로 해결합니다.
-
-
-
promise를 반환합니다.
claimInterface(interfaceNumber) 메서드는 호출
시 다음 단계를 반드시 실행해야 합니다:
-
global를 this의 관련 전역 객체로 둡니다.
-
만약 장치가 구성되어 있는지 확인가 이 this에 대해
Promise를 반환하면, 그 값을 반환합니다. -
interfaces를 activeConfiguration.[[interfaces]]로 둡니다.
-
interfaceIndex를 인터페이스 인덱스 찾기로 구한 값(인수: interfaceNumber, activeConfiguration)으로 둡니다.
-
만약 interfaceIndex가
-1이면, "NotFoundError"DOMException으로 거부된 프로미스를 반환합니다. -
만약 this.[[claimedInterface]][interfaceIndex]가
true이면undefined로 해결된 프로미스를 반환합니다. -
unrestricted를
false로 둡니다. -
document를 global의 연관 Document로 두거나, 연관 Document가 없으면
null로 둡니다. -
만약 document가
null이 아니고, document가 정책 제어 기능"usb-unrestricted"을 사용할 수 있도록 허용되어 있다면 unrestricted를true로 설정합니다. -
만약 interfaces[interfaceIndex].[[isProtectedClass]]가
true이고 unrestricted가false이면 "SecurityError"DOMException으로 거부된 프로미스를 반환합니다. -
promise를 새 프로미스로 둡니다.
-
다음 단계를 병렬로 실행합니다.
-
현재 실행 컨텍스트에 대해 interfaces[interfaceIndex]에 대한 단독 제어를 요청하는 플랫폼 특유의 단계를 수행합니다.
-
USB 작업 소스에 대하여 global의 전역 태스크를 큐에 추가하여 다음 단계를 실행합니다:
-
만약 위 플랫폼 단계가 실패하면 reject하여 promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단합니다. -
this.[[claimedInterface]][interfaceIndex]를
true로 설정합니다. -
Resolve하여 promise를
undefined로 해결합니다.
-
-
-
promise를 반환합니다.
releaseInterface(interfaceNumber)
메서드는,
호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
activeConfiguration을 finding the current configuration을 this와 함께 수행한 결과로 한다.
-
interfaces를 activeConfiguration.
[[interfaces]]로 한다. -
interfaceIndex를 finding the interface index를 interfaceNumber 및 activeConfiguration과 함께 수행한 결과로 한다.
-
interfaceIndex가
-1과 같다면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
this.
[[claimedInterface]][interfaceIndex] 가false이면, undefined로 이행된 promise를 반환한다. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
interfaces[interfaceIndex]에 대한 독점 제어를 포기하기 위해 필요한 플랫폼별 단계를 수행한다.
-
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
this.
[[selectedAlternateSetting]][interfaceIndex] 를0으로 설정한다. -
this.
[[claimedInterface]][interfaceIndex] 를false로 설정한다. -
Resolve promise를
undefined로 이행한다.
-
-
-
promise를 반환한다.
selectAlternateInterface(interfaceNumber, alternateSetting)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
activeConfiguration을 finding the current configuration을 this와 함께 수행한 결과로 한다.
-
interfaces를 activeConfiguration.
[[interfaces]]로 한다. -
interfaceIndex를 finding the interface index를 interfaceNumber와 activeConfiguration으로 수행한 결과로 한다.
-
interfaceIndex가
-1과 같다면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
this.
[[claimedInterface]][interfaceIndex] 가false라면, 다음으로 거부된 promise를 반환한다: "InvalidStateError"DOMException. -
interface를 interfaces[interfaceIndex]로 한다.
-
alternateIndex를 finding the alternate index를 alternateSetting과 interface로 수행한 결과로 한다.
-
alternateIndex가
-1과 같다면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
인터페이스에 현재 예약된 전송 중단을 interface로 수행한다.
-
SET_INTERFACEcontrol transfer를 발행하되,interfaceNumber는 interfaceNumber로,alternateSetting은 alternateSetting으로 설정한다. -
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
위의 control transfer가 실패했다면 reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
this.
[[selectedAlternateSetting]][interfaceIndex] 를 alternateSetting으로 설정한다. -
Resolve promise를
undefined로 이행한다.
-
-
-
promise를 반환한다.
controlTransferIn(setup, length)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
check the validity of the control transfer parameters를 this와 setup으로 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
length가 0보다 크면, buffer를 length 바이트를 담을 공간을 가진 호스트 버퍼로 한다.
-
control transfer를 this에 대해 발행하되, setup packet 매개변수는 setup에서 제공된 값을 사용하고,
bmRequestType의 데이터 전송 방향은 "device to host"로,wLength는 length로 설정한다. 정의되어 있다면, 이 전송에 대한 응답으로 수신된 데이터를 기록할 대상로서 buffer도 제공한다. -
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
bytesTransferred를 buffer에 기록된 바이트 수로 한다.
-
result를 새로운
USBInTransferResult로 한다. -
장치로부터 데이터를 수신했다면, 새로운
ArrayBuffer를 생성하되 buffer의 처음 bytesTransferred 바이트를 포함하도록 하고, result.data를 그 위에 구성한 새로운DataView로 설정한다. -
result.
status를 다음과 같이 설정한다. -
그 밖의 이유로 전송이 실패했다면 reject promise를 "
NetworkError"로 거부하고 이 단계를 중단한다. -
Resolve promise를 result로 이행한다.
-
-
-
promise를 반환한다.
controlTransferOut(setup, data)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
check the validity of the control transfer parameters를 this와 setup으로 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
버퍼 소스의 복사본을 가져와 data에서 결과를 bytes로 한다.
-
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
control transfer를 this에 대해 발행하되, setup packet 매개변수는 setup에서 제공된 값을 사용하고,
bmRequestType의 데이터 전송 방향은 "host to device"로,wLength는 bytes의 길이로 설정한다. -
전송의 data stage에서 bytes를 전송한다.
-
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
result를 새로운
USBOutTransferResult로 한다. -
result.
status를 다음과 같이 설정한다.-
"ok": 그 외의 경우이며, 이때 result.bytesWritten을 bytes의 길이로 설정한다.
-
그 밖의 이유로 전송이 실패하면 reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
Resolve promise를 result로 이행한다.
-
-
-
promise를 반환한다.
clearHalt(direction, endpointNumber)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
endpointAddress를 direction이
"in"과 같으면endpointNumber | 0x80으로, 그렇지 않으면 endpointNumber로 한다. -
endpoint를 finding the endpoint를 endpointAddress와 this로 수행한 결과로 한다.
-
endpoint가
null이면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
ClearFeature(ENDPOINT_HALT)control transfer를 장치에 발행해 endpoint의 중지(halts) 상태를 해제한다. -
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
위의 control transfer가 실패했다면, reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
Resolve promise를
undefined로 이행한다.
-
-
-
promise를 반환한다.
transferIn(endpointNumber, length)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
endpointAddress를
endpointNumber | 0x80(즉,"in"방향)으로 한다. -
endpoint를 finding the endpoint를 endpointAddress와 this로 수행한 결과로 한다.
-
endpoint가
null이면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
endpoint.
type이"bulk"또는"interrupt"와 같지 않다면, 다음으로 거부된 promise를 반환한다: "InvalidAccessError"DOMException. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
buffer를 length 바이트를 담을 공간을 가진 호스트 버퍼로 한다.
-
endpoint에 적합한 방식으로 bulk 또는 interrupt IN transfer를 수행하여 장치로부터 length 바이트의 데이터를 buffer로 수신한다.
-
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
bytesTransferred를 buffer에 기록된 바이트 수로 한다.
-
result를 새로운
USBInTransferResult로 한다. -
장치로부터 데이터를 수신했다면, 새로운
ArrayBuffer를 생성하되 buffer의 처음 bytesTransferred 바이트를 포함하도록 하고, result.data를 그 위에 구성한 새로운DataView로 설정한다. -
result.
status를 다음과 같이 설정한다. -
그 밖의 이유로 전송이 실패했다면 reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
Resolve promise를 result로 이행한다.
-
-
-
promise를 반환한다.
transferOut(endpointNumber, data)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
endpointAddress를 endpointNumber(즉,
"out"방향)로 한다. -
endpoint를 finding the endpoint를 endpointAddress와 this로 수행한 결과로 한다.
-
endpoint가
null이면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
endpoint.
type이"bulk"또는"interrupt"와 같지 않다면, 다음으로 거부된 promise를 반환한다: "InvalidAccessError"DOMException. -
버퍼 소스의 복사본을 가져와 data에서 결과를 bytes로 한다.
-
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
endpoint에 적합한 방식으로 bulk 또는 interrupt OUT transfer를 수행하여 bytes를 장치로 전송한다.
-
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
result를 새로운
USBOutTransferResult로 한다. -
result.
bytesWritten을 장치로 성공적으로 전송된 데이터의 양으로 설정한다. -
result.
status를 다음과 같이 설정한다. -
그 밖의 이유로 전송이 실패했다면 reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
Resolve promise를 result로 이행한다.
-
-
-
promise를 반환한다.
isochronousTransferIn(endpointNumber, packetLengths)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
endpointAddress를
endpointNumber | 0x80(즉,"in"방향)으로 한다. -
endpoint를 finding the endpoint를 endpointAddress와 this로 수행한 결과로 한다.
-
endpoint가
null이면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
endpoint.
type이"isochronous"와 같지 않다면, 다음으로 거부된 promise를 반환한다: "InvalidAccessError"DOMException. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
totalLength를 packetLengths의 모든 요소의 합으로 한다.
-
buffer를 totalLength 바이트를 담을 공간을 가진 호스트 버퍼로 한다.
-
isochronous IN transfer를 endpoint에서 수행하여 장치로부터 패킷을 buffer로 읽되, packetLengths에 따라 진행한다.
-
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
result를 새로운
USBIsochronousInTransferResult로 한다. -
data를 새로운
ArrayBuffer로 하되 buffer로 초기화한다. -
각 패킷 i에 대해
0부터packetLengths.length - 1까지 반복한다:-
packet을 새로운
USBIsochronousInTransferPacket으로 한다. -
view를 새로운
DataView로 하되 이 패킷에 대해 장치에서 수신된 데이터를 포함하는 data의 일부분 위에 구성하고, packet.data를 view로 설정한다. -
packet.
status를 다음과 같이 설정한다. -
그 밖의 이유로 전송이 실패하면 reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
result.
packets[i] 를 packet으로 설정한다.
-
-
Resolve promise를 result로 이행한다.
-
-
-
promise를 반환한다.
isochronousTransferOut(endpointNumber, data, packetLengths)
메서드는, 호출되면 다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
endpointAddress를 endpointNumber(즉,
"out"방향)로 한다. -
endpoint를 finding the endpoint를 endpointAddress와 this로 수행한 결과로 한다.
-
endpoint가
null이면, 다음으로 거부된 promise를 반환한다: "NotFoundError"DOMException. -
endpoint.
type이"isochronous"와 같지 않다면, 다음으로 거부된 promise를 반환한다: "InvalidAccessError"DOMException. -
버퍼 소스의 복사본을 가져와 data에서 결과를 bytes로 한다.
-
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
isochronous OUT transfer를 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를 다음과 같이 설정한다. -
그 밖의 이유로 전송이 실패하면 reject promise를 "
NetworkError"DOMException으로 거부하고 이 단계를 중단한다. -
result.
packets[i] 를 packet으로 설정한다.
-
-
Resolve promise를 result로 이행한다.
-
-
-
promise를 반환한다.
reset() 메서드는, 호출되면
다음 단계를 반드시 수행해야 한다:
-
check if the device is configured를 this와 함께 수행한 결과가
Promise를 반환하면, 그 값을 반환한다. -
promise를 새로운 promise로 한다.
-
다음 단계를 병렬로 수행한다.
-
장치의 모든 작업을 중단하고, 그들의 연결된 promise를 "글로벌 태스크를 큐에 넣어 USB 작업 소스에서 reject 하되 "
AbortError"DOMException으로 거부하도록 한다. -
장치를 소프트 리셋하기 위한 필요한 플랫폼별 작업을 수행한다.
-
글로벌 태스크를 큐에 넣어 USB 작업 소스에서 global을 주어 다음 단계를 실행한다:
-
소프트 리셋이 실패했다면, reject promise를 "
NetworkError"로 거부하고 이 단계를 중단한다. -
Resolve 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과 같다면, a promise rejected with "NotFoundError"DOMException을 반환한다. -
interface를 configuration.
[[interfaces]][interfaceIndex]로 한다. -
interface로 해당 인터페이스가 클레임되었는지 찾기의 결과가
true가 아니면, a promise rejected with "InvalidStateError"DOMException을 반환한다.
-
-
setup.
recipient가"endpoint"이면, 다음 단계를 수행한다:-
endpointAddress를 setup.
index로 한다. -
endpoint를 endpointAddress 및 device로 엔드포인트 찾기의 결과로 한다.
-
endpoint가
null이면, a promise rejected with "NotFoundError"DOMException을 반환한다. -
alternate를 endpoint.
[[alternateInterface]]로 한다. -
interface를 alternate.
[[interface]]로 한다. -
interface로 해당 인터페이스가 클레임되었는지 찾기의 결과가
false이면, a promise rejected with "InvalidStateError"DOMException을 반환한다.
-
-
undefined를 반환한다.
6.2.1. 멤버
requestType, 유형 USBRequestType-
requestType속성은 setup packet의bmRequestType필드의 일부를 채워 이 요청이 USB 표준의 일부인지, 특정 USB 장치 클래스 명세의 일부인지, 또는 벤더 전용 프로토콜인지 나타낸다. recipient, 유형 USBRecipient-
recipient속성은 setup packet의bmRequestType필드의 일부를 채워 control transfer가 전체 장치를 대상으로 하는지, 특정 인터페이스 또는 엔드포인트를 대상으로 하는지 나타낸다. request, 유형 octet-
request속성은 setup packet의bRequest필드를 채운다. 유효한 요청은 USB 표준, USB 장치 클래스 명세 또는 장치 벤더에 의해 정의된다. value, 유형 unsigned short-
value및index속성은 각각 setup packet의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 (비어 있음) of USBInterface
| 이 구성에서 지원되는 모든 인터페이스. |
[[configurationValue]]
| <항상 본문에서 설정> | 이 구성의 구성 값. |
-
deviceDescriptor를 연결된 USB 장치의 디바이스 디스크립터 찾기의 결과로 한다.
-
numConfigurations를 deviceDescriptor의
bNumConfigurations로 한다. -
configurationIndex를 0으로 한다.
-
configurationIndex가 numConfigurations보다 작은 동안:
-
descriptors를 descriptors의 목록으로 하되, Get Descriptor를 수행하면서
DescriptorType은CONFIGURATION으로,DescriptorIndex는 configurationIndex로 설정한다. -
descriptors[0]의
bDescriptorType이CONFIGURATION과 같고, descriptors의bConfigurationValue가 configurationValue와 같다면, descriptors를 반환한다. -
configurationIndex를 1 증가시킨다.
-
-
empty 결과를 반환한다.
6.3.1. 생성자
USBConfiguration(device, configurationValue)
생성자는 호출될 때 MUST 다음 단계를 수행한다:
-
this.
[[device]]를 device로 설정한다. -
this.
[[configurationValue]]를 configurationValue로 설정한다. -
descriptors를
configurationValue를 configurationValue로 설정하여 구성에 대한 디스크립터 목록을 찾기의 결과로 한다. -
seen을 비어 있는 ordered set으로 한다.
-
각 descriptors의 descriptor에 대해:
-
descriptor의
bDescriptorType이INTERFACE와 같지 않다면, 다음으로 진행한다. -
descriptor의
bInterfaceNumber가 seen 안에 있으면, 다음으로 진행한다. -
interface를 새로운
USBInterface객체로 하되, USBInterface(configuration,interfaceNumber)를 사용하고 configuration은 this로, interfaceNumber는 descriptor의bInterfaceNumber로 설정한다. -
Append interface를 this.
[[interfaces]]에 추가한다. -
Append descriptor의
bInterfaceNumber를 seen에 추가한다.
-
6.3.2. 속성
configurationValue, 유형 octet, readonly-
각 장치 구성은 이를 정의하는 configuration descriptor의
bConfigurationValue필드와 일치하는 고유한configurationValue를 가져야 한다(SHALL). configurationName, 유형 DOMString, readonly, nullable-
configurationName속성은, 정의되어 있다면, configuration descriptor의iConfiguration필드가 참조하는 string descriptor의 값을 포함해야 한다(SHOULD). interfaces, 유형 FrozenArray<USBInterface>, readonly-
interfaces속성은 이 장치 구성에 의해 노출되는 인터페이스 목록을 포함해야 한다(SHALL).interfaces게터 단계는 다음과 같다:-
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 (비어 있음) of USBAlternateInterface
| 이 인터페이스가 지원하는 모든 대체 설정. |
[[isProtectedClass]]
| false
| 이 인터페이스가 보호된 클래스에 속하는 어떤 대체 설정이라도 가지는지 여부. |
interface
descriptor interface는 그리고 오직 그때에만
interface의 bInterfaceClass가 다음 값 중 하나와 같을 때
보호된 인터페이스
클래스를 가진다.
| 코드 | 설명 |
|---|---|
0x01
| Audio |
0x03
| HID (Human Interface Device) |
0x08
| Mass Storage |
0x0B
| Smart Card |
0x0E
| Video |
0x10
| Audio/Video Devices |
0xE0
| Wireless Controller |
Note: 본 명세는 가능한 한 많은 장치를 지원하면서도 민감한 장치에 대한 접근을 제한하여 악성 콘텐츠로부터 사용자를 보호하는 균형을 추구한다. 서론에서 언급했듯이 이 API의 목표는 다른, 더 높은 수준의 API로 다루어지지 않는 장치를 지원하는 것이다. 위 목록에는 그러한 높은 수준의 API가 존재하여 사용자 프라이버시와 보안을 이 API를 통한 저수준 접근보다 더 잘 보호해주는 인터페이스 클래스들이 포함되어 있다.
-
configuration을 interface.
[[configuration]]로 한다. -
device를 configuration.
[[device]]로 한다. -
configuration이 device로 현재 구성을 찾기의 결과와 동일하지 않다면,
false를 반환한다. -
interfaceIndex를 interface.
[[interfaceNumber]]및 configuration으로 인터페이스 인덱스를 찾기의 결과로 한다. -
Assert: interfaceIndex는
-1이 아니다. -
device.
[[claimedInterface]][interfaceIndex]를 반환한다.
-
configuration을 interface.
[[configuration]]로 한다. -
device를 configuration.
[[device]]로 한다. -
alternateIndex를 0으로 한다.
-
interface로 인터페이스가 클레임되었는지 찾기의 결과가
true이면:-
interfaceIndex를 interface.
[[interfaceNumber]]및 configuration으로 인터페이스 인덱스를 찾기의 결과로 한다. -
Assert: interfaceIndex는
-1이 아니다. -
alternateIndex를 device.
[[selectedAlternateSetting]][interfaceIndex] 및 interface로 대체 인덱스를 찾기의 결과로 설정한다.
-
-
Assert: alternateIndex는
-1이 아니다. -
interface.
alternates[alternateIndex]를 반환한다.
Note: Interface Descriptor [USB31]에 따르면 인터페이스에는 적어도 하나의 대체 설정이 있어야 한다. 즉, Interface Descriptor에는 최소한 하나의 대체 설정이 존재해야 한다.
6.4.1. 생성자
USBInterface(configuration, interfaceNumber)
생성자는 호출될 때 MUST 다음 단계를 수행한다:
-
this.
[[configuration]]를 configuration로 설정한다. -
this.
[[interfaceNumber]]를 interfaceNumber로 설정한다. -
descriptors를
configurationValue를 configuration.[[configurationValue]]로 설정하여 구성에 대한 디스크립터 목록을 찾기의 결과로 한다. -
각 descriptors의 descriptor에 대하여:
-
descriptor의
bDescriptorType이INTERFACE와 같지 않다면, 계속한다. -
descriptor의
bInterfaceNumber가 interfaceNumber와 같지 않다면, 계속한다. -
descriptor가 보호된 인터페이스 클래스를 가진다면, this.
[[isProtectedClass]]를true로 설정한다. -
alternate를 새로운
USBAlternateInterface객체로 하되, USBAlternateInterface(deviceInterface,alternateSetting)를 사용하고 deviceInterface는 this로, alternateSetting은 descriptor의bAlternateSetting으로 설정한다. -
Append alternate를 this.
[[alternates]]에 추가한다.
-
6.4.2. 속성
interfaceNumber, 유형 octet, readonly-
각 인터페이스는 interface descriptors에 있는 단일
bInterfaceNumber필드로 식별되는alternates모음을 제공한다.interfaceNumber속성은 이 필드와 일치해야 한다(MUST).interfaceNumber게터 단계는 다음과 같다.-
this.
[[interfaceNumber]]를 반환한다.
-
alternate, 유형 USBAlternateInterface, readonly-
alternate속성은 이 인터페이스에 대해 현재 선택된USBAlternateInterface로 설정되어야 하며(SHALL), 기본값으로는bAlternateSetting이0인 인터페이스여야 한다(SHALL).alternate게터 단계는 다음과 같다:-
현재 대체 설정에 대한 대체 인터페이스 찾기의 결과를 this로 반환한다.
-
alternates, 유형 FrozenArray<USBAlternateInterface>, readonly-
alternates메서드는 단일bInterfaceNumber필드로 식별되는USBAlternateInterface객체들의 모음을 제공합니다. 이bInterfaceNumber는 각 객체의 interface descriptor에서 찾을 수 있습니다.alternates게터 단계는 다음과 같다:-
this.
[[alternates]]를 반환한다.
-
claimed, 유형 boolean, readonly-
claimed속성은 현재 실행 컨텍스트에 의해 인터페이스가 클레임되었을 때true로, 그렇지 않으면false로 설정되어야 한다(SHALL).claimed게터 단계는 다음과 같다:-
인터페이스가 클레임되었는지 찾기의 결과를 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 (비어 있음) of USBEndpoint
| 이 인터페이스가 노출하는 모든 엔드포인트. |
[[alternateSetting]]
| <항상 본문에서 설정> | 이 인터페이스의 대체 설정 값. |
-
descriptors를 configurationValue로 구성에 대한 디스크립터 목록을 찾기의 결과로 한다.
-
endpointDescriptors를 비어 있는 list로 한다.
-
index를 0으로 한다.
-
index가 descriptors의 size보다 작은 동안:
-
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보다 작은 동안:
-
Append descriptors[indexEndpoints + offset]를 endpointDescriptors에 추가한다.
-
indexEndpoints를 1 증가시킨다.
-
-
endpointDescriptors를 반환한다.
-
6.5.1. 생성자
USBAlternateInterface(deviceInterface, alternateSetting)
생성자는 호출될 때 MUST 다음 단계를 수행한다:
-
this.
[[interface]]를 deviceInterface로 설정한다. -
this.
[[alternateSetting]]를 alternateSetting으로 설정한다. -
descriptors를
interfaceNumber를 deviceInterface.interfaceNumber로,alternateSetting을 alternateSetting으로,configurationValue를 deviceInterface.[[configuration]].[[configurationValue]]로 설정하여 엔드포인트 디스크립터 목록을 찾기의 결과로 한다. -
각 descriptors의 descriptor에 대하여:
-
descriptor의
bmAttributes가 Control Transfer Type(즉, endpoint descriptor에 따라 비트0..1이00)을 나타내면, 계속한다. -
endpointAddress를 descriptor의
bEndpointAddress로 한다. -
endpointAddress & 0x80이0이면 dir을"out"으로, 그렇지 않으면"in"으로 한다. -
endpoint를 새로운
USBEndpoint객체로 하되, USBEndpoint(alternate,endpointNumber,direction)를 사용하고 alternate는 this로, endpointNumber는endpointAddress & 0xF로, direction은 dir로 설정한다. -
Append endpoint를 this.
[[endpoints]]에 추가한다.
-
6.5.2. 속성
alternateSetting, 유형 octet, readonly-
각 대체 인터페이스 구성은 주어진 인터페이스 내에서 고유한
alternateSetting을 가져야 하며(SHALL), 이는 이를 정의하는 interface descriptor의bAlternateSetting필드와 일치해야 한다. interfaceClass, 유형 octet, readonlyinterfaceSubclass, 유형 octet, readonlyinterfaceProtocol, 유형 octet, readonly-
interfaceClass,interfaceSubclass,interfaceProtocol속성은 인터페이스가 지원하는 통신 인터페이스를 선언한다. 이 값들은 각각 interface descriptor의bInterfaceClass,bInterfaceSubClass,bInterfaceProtocol필드 값과 일치해야 한다(MUST). interfaceName, 유형 DOMString, readonly, nullable-
interfaceName속성은, 정의되어 있다면, interface descriptor의iInterface필드로 색인되는 string descriptor의 값을 포함해야 한다(SHOULD). endpoints, 유형 FrozenArray<USBEndpoint>, readonly-
endpoints속성은 이 인터페이스에 의해 노출되는 엔드포인트 목록을 포함해야 한다(SHALL). 이 엔드포인트들은 이 interface descriptor에 포함된 endpoint descriptors로부터 채워져야 하며(SHALL), 이 시퀀스의 원소 수는 interface descriptor의bNumEndpoints값과 일치해야 한다(SHALL).endpoints게터 단계는 다음과 같다:-
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 (of 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, readonlydirection, 유형 USBDirection, readonly-
특정 장치 구성 내부의 각 엔드포인트는
endpointNumber와direction의 조합이 고유해야 한다.
endpointNumber는 해당 엔드포인트를 정의하는 엔드포인트 디스크립터의bEndpointAddress필드의 하위 4비트와 반드시 같아야 한다(MUST).direction속성은 해당 엔드포인트가 지원하는 데이터 전송 방향을 나타내며,bEndpointAddress의 최상위 비트가 설정되어 있으면"in"이고, 아니면"out"이다. 엔드포인트는 데이터를IN방향(장치→호스트) 또는OUT방향(호스트→장치) 중 하나로만 전송할 수 있다. type, 유형 USBEndpointType, readonly-
type속성은 해당 엔드포인트가 지원하는 데이터 전송 타입을 나타낸다.type게터의 단계는 다음과 같다:-
endpointDescriptor를 엔드포인트 디스크립터 찾기의 결과로 this를 인자로 한다.
-
attr를 endpointDescriptor의
bmAttributes로 한다. -
typeBits를
attr & 0x3로 한다. -
typeBits가
b01이면"isochronous"를 반환한다. -
typeBits가
b10이면"bulk"를 반환한다. -
typeBits가
b11이면"interrupt"를 반환한다.
참고: USBAlternateInterface(deviceInterface,alternateSetting)의 단계에 따라 Control Transfer Type에 속하는 엔드포인트 객체는 생성되지 않는다.
-
packetSize, 유형 unsigned long, readonly-
packetSize속성은 해당 엔드포인트에서 사용되는 패킷 크기를 나타내며, 해당 엔드포인트를 정의하는 엔드포인트 디스크립터의wMaxPacketSize값과 반드시 같아야 한다(MUST). 하이스피드, 고대역폭 엔드포인트의 경우 이 값은 마이크로프레임당 여러 트랜잭션에 따른 곱하기 계수를 포함한다. 슈퍼스피드 장치의 경우 이 값은 슈퍼스피드 엔드포인트 동반 디스크립터의bMaxBurst필드에 의한 곱하기 계수를 포함한다.packetSize게터의 단계는 다음과 같다:-
endpointDescriptor를 엔드포인트 디스크립터 찾기의 결과로 this를 인자로 한다.
-
endpointDescriptor의
wMaxPacketSize를 반환한다.
-
7. USB 차단 목록
// USBBlocklistEntry는 외부에 노출되지 않습니다.dictionary {USBBlocklistEntry required unsigned short ;idVendor required unsigned short ;idProduct required unsigned short ; };bcdDevice
이 명세는 이 저장소의 blocklist.txt 파일에 의존하여, 웹사이트가 접근할 수 있는 디바이스의 범위를 제한합니다.
차단 목록 해석의 결과는
URL
url에서 다음과 같은 알고리즘을 통해 생성되는 list 형식의 USBBlocklistEntry
객체들입니다:
-
url을 가져오고, 그 body를 UTF-8로 디코딩하여 contents로 한다.
-
lines를 strictly splitting을 이용해 contents를
'\n'코드 포인트 기준으로 분할한 결과로 한다. -
blocklist를 빈 list로 한다.
-
각 lines의 line에 대해:
-
line을, 시작부터
'#'가 아닌 모든 코드 포인트 시퀀스 추출로 변환한다. -
line에서 앞뒤의 ASCII 공백 문자 제거 결과로 다시 line을 설정한다.
-
components를 strictly splitting을 사용하여 line을
':'기준으로 분할한 결과로 한다. -
idVendor를 components[0]을 16진수로 해석한 값으로 한다.
-
idProduct를 components[1]을 16진수로 해석한 값으로 한다.
-
bcdDevice를
0xFFFF로 한다. -
components의 size가 3이면, bcdDevice를 components[2]의 16진수 해석값으로 한다.
-
새로운
USBBlocklistEntry를 idVendor, idProduct, bcdDevice와 함께 생성해 blocklist에 추가한다.
-
-
blocklist를 반환한다.
USB 차단 목록은 차단 목록 해석 결과로, https://raw.githubusercontent.com/WICG/webusb/main/blocklist.txt에서 불러온 목록이다. UA는 이 리스트를 주기적으로 다시 받아야 하지만, 얼마나 자주 받아야 하는지는 명시되지 않는다.
USBDevice
device가
Document
document에 대해 차단됨(blocklisted) 상태인지는, 아래 단계가 "blocked"를 반환할 때 그렇다:
-
document가
null이 아니고, document가 "usb-unrestricted"라는 정책 제어 기능을 사용할 수 있다면, "not blocked"를 반환한다. -
-
bcdDevice를 device.
deviceVersionMajor<< 8 + device.deviceVersionMinor<< 4 + device.deviceVersionSubminor로 한다. -
bcdDevice가 entry.
bcdDevice보다 작거나 같으면, "blocked"를 반환한다.
-
"not blocked"를 반환한다.
8. 통합
8.1. 권한 정책
이 명세는 정책 제어 기능을 정의합니다. 이 기능은 "usb" 토큰으로 식별되며,
usb
속성이 Navigator
객체에 노출될지 여부를 제어합니다.
이 기능의 기본 허용 목록은
["self"] 입니다.
이 명세는 두 번째 정책 제어 기능도 정의합니다.
"usb-unrestricted" 토큰으로 식별되는 이 기능은 차단 목록에 있는 USB 디바이스와 보호된 클래스를 가진 디바이스 인터페이스에 대한 접근을 제어합니다.
이 기능은 Isolated Web Apps에서 Web
Application Manifest [APPMANIFEST]에 해당 기능을 선언한 경우에만 활성화되어야 합니다(MUST).
이 기능의 기본 허용 목록도 ["self"]입니다.
일반적으로 이 기능은 최상위 탐색 컨텍스트의 Document에
허용되어야 한다고 볼 수 있습니다. 그러나 매니페스트에 이 기능이 선언된 Isolated Web Apps에서만 기능이 활성화되어야 하므로, 실질적 기본 허용 목록은
["none"]입니다.
8.2. 권한 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인스턴스들은 내부 슬롯[[devices]]을 갖는데, 이 슬롯에는 USB 디바이스의 배열이 저장됩니다. - permission result type
-
[
Exposed =(Worker ,Window )]interface :USBPermissionResult PermissionStatus {attribute FrozenArray <USBDevice >; };devices - permission query algorithm
-
"usb" 권한 쿼리를
USBPermissionDescriptordesc,USBPermissionStoragestorage,USBPermissionResultstatus로 수행할 때, UA는 다음을 따라야 한다:-
desc.값이 설정되어 있으면,filtersdesc.의 각 filter에 대해 filter가 유효한 필터가 아니면filtersTypeError를 발생시키고, 단계를 중단한다. -
desc.값이 설정되어 있으면,exclusionFiltersdesc.의 각 exclusionFilter에 대해 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" 권한 요청(Request the "usb" permission).
9. 용어 정의
이 명세서는 [USB31]에서 가져온 여러 용어를 사용합니다. Universal Serial Bus 3.1 버전을 참조하고 있으나, 이러한 개념들은 이전 버전에도 존재합니다. 이 명세에 영향을 미치는 USB 버전 간의 중요한 차이점들은 별도로 명시합니다.
디스크립터(Descriptor)는 디바이스로부터 읽을 수 있으며 장치의 속성과 기능을 설명하는 이진 데이터 구조입니다:
-
디바이스 디스크립터(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 디바이스는 하나의 디바이스 디스크립터를 가지고,
이는 하나 이상의 구성
디스크립터와 연결됩니다. 벤더 ID(vendor
ID)는 USB-IF가 장치 제조업체에 할당하며, 디바이스 디스크립터의 idVendor 필드에 저장됩니다. 제품 ID(product
ID)는 제조사가 할당하며 디바이스 디스크립터의 idProduct 필드에 저장됩니다. 시리얼
번호(serial number)는 선택적 속성으로, 디바이스 디스크립터의 iSerialNumber 필드가 0이 아닐 때
정의되며, 그 인덱스로 참조되는 문자열
디스크립터(string descriptor) 값입니다.
Get Configuration은 현재 장치의 구성값을 요청하는 명령이며, [USB31]의 9.4.2절에 설명됩니다.
Set Descriptor는 지정된 디스크립터 타입 및 디스크립터 인덱스 값을 가진 디스크립터를 얻는 요청으로, [USB31]의 9.4.8절에 설명되어 있습니다.
Get Descriptor는 지정된 디스크립터 타입 및 인덱스 값을 가진 디스크립터를 얻는 요청으로, [USB31]의 9.4.3절에서 설명합니다.
참고: 장치의 디스크립터는 대부분의 경우 변하지 않으며(가끔 Set Descriptor에 의해 변경될 수 있음), 불필요한 Get Descriptor 트래픽을 줄이기 위해 디스크립터 정보를 저장하는 읽기/쓰기 캐시 계층을 구현할 수 있습니다.
컨트롤 전송(control transfer)은 디바이스를 구성할 때 가장 자주 사용되는 USB 트래픽의 특별한 유형입니다. 3단계( 세트업, 데이터, 상태 )로 이루어집니다. 세트업 단계(setup stage)에서 세트업 패킷(setup packet)을 장치로 전송하며, 이때 전송 방향 및 데이터 크기 등 요청 파라미터가 포함됩니다. 데이터 단계(data stage)는 데이터를 장치에 보내거나 장치로부터 수신하며, 상태 단계(status stage)에서 요청이 성공적으로 처리된 경우 이를 확인하거나, 실패가 발생하면 신호합니다.
10. 부록: USB 간략 소개
이 섹션은 비규범적입니다.
USB는 네트워크이지만, 전통적인 TCP/IP 네트워크와 매우 다릅니다. 실제로는 RPC 시스템에 더 가깝습니다. 모든 트래픽은 호스트(즉, 여러분의 컴퓨터)가 지시합니다. 일부 스마트폰과 같은 장치는 USB 호스트와 USB 클라이언트 역할을 모두 할 수 있지만 한 번에 한 역할만 수행합니다.
10.1. 디스크립터
USB 장치는 디스크립터라고 불리는 일련의 이진 구조를 호스트에 제공하여 자신을 식별합니다. 호스트가 처음 읽는 것은 디바이스 디스크립터로, 벤더 및 제조사에 의해 할당된 벤더/제품 ID, 제조사 등 기본 정보를 담고 있습니다. 그 다음으로 호스트는 해당 장치의 구성 디스크립터를 읽을 수 있는데, 이 디스크립터는 인터페이스와 엔드포인트 등 장치의 기능을 설명합니다. 클래스는 장치 레벨이나 각 인터페이스에 선언할 수 있습니다. 여러 기능을 제공하는 여러 인터페이스를 가진 장치는 복합 장치(composite device)로 알려져 있습니다.
10.2. 전송(Transfers)
데이터가 호스트에서 장치로 이동하든 반대로 이동하든, 전송은 항상 호스트가 시작합니다. OUT 전송은 데이터를 호스트에서 장치로 보내며, 장치가 데이터 수신을 확인할 때까지 대기할 수 있습니다. IN 전송은 데이터를 장치에서 호스트로 보내며, 장치가 보낼 데이터를 준비할 때까지 기다릴 수 있습니다. 전송은 장치의 엔드포인트 중 하나를 대상으로 수행되며, 전송되는 트래픽 종류에 따라 여러 종류가 존재합니다.
-
벌크 전송(Bulk transfers)은 사용 가능한 대역폭을 최대한 활용하여 많은 데이터를 전송하는 데 적합합니다. 이는 USB 대용량 저장장치의 데이터 읽기·쓰기에 사용됩니다.
-
인터럽트 전송(Interrupt transfers)은 지연 시간이 보장되도록(대용량 벌크 전송에 의해 차단되지 않도록 대역폭을 예약) 하지만 패킷 크기는 제한됩니다. 신호 전달이나 마우스 이동, 버튼 클릭 등 작은 패킷에 사용됩니다.
-
등시성 전송(Isochronous transfers)도 대역폭을 예약하지만 데이터의 정확한 전달은 보장하지 않습니다. 오디오·비디오 스트리밍 데이터에 사용됩니다.
-
모든 장치는 기본 엔드포인트(default endpoint)를 가지고 있습니다. 일반적인 엔드포인트는 항상 한쪽 방향만의 데이터를 전달하지만, 컨트롤 전송(control transfers)의 경우 작은 헤더( SETUP 패킷 )가 장치로 꼭 전송되고, 이 요청 파라미터 외에도 IN 또는 OUT 양방향이 가능한 데이터 페이로드를 가질 수 있습니다.