usb device driver

USB Device Driver - 1. 개념

jsh91 2023. 6. 26. 01:24

USB 2.0 속도

low speed : 12Mbps

high speed : 480Mbps

 

USB 3.0 속도

4.8Gbps

 

USB device driversms 가장 상위에 USB Root hub를 가지고 있으며 하위로 hub와 device가 연결된다

 

 

USB 2.0은 4개의 line으로 구성된다

D+, D-, VCC, GND

 

USB는 data통신을 하기 위해서 항상 Host에서 Device 데이터 요청(transaction)을 수행해야 된다

 

USB descriptor는 USB device의 기능을 표현하는 data structure이다

예를 들어 VID, PID, device class, end point 등등

 

Host와 Device는 end point를 통해 데이터를 주고 받는다.

 

usb는 4개의 데이터 통신 방법이 있다

1. control transfers : 전송: 연결 시 장치를 구성하는 데 사용되며 다른 장치별 목적(예: 장치별 레지스터 읽기/쓰기 액세스 및 장치의 다른 파이프 제어)에 사용할 수 있습니다. 제어 전송은 요청을 포함하는 설정 단계, 필요한 경우 호스트와 주고받는 데이터 단계, 전송 성공을 나타내는 상태 단계의 세 가지 단계로 구성됩니다. USB에는 제어 전송을 사용하여 구현되는 많은 표준화된 트랜잭션이 있습니다. 예를 들어 "주소 설정" 및 "설명자 가져오기" 트랜잭션은 위에서 설명한 장치 열거 절차에서 항상 활용됩니다. "구성 설정" 요청은 장치 열거 중에도 사용되는 또 다른 표준 트랜잭션입니다.

2. bulk data transfers : 비교적 많은 양의 데이터 또는 버스트 데이터를 전송할 수 있습니다. 대량 전송에는 타이밍이 보장되지 않지만 USB 버스가 다른 활동에 의해 점유되지 않는 경우 가장 빠른 데이터 전송 속도를 제공할 수 있습니다.

 

3. interrupt data transfers : 인간이 인지할 수 있는 반향 또는 피드백 응답 특성이 있는 문자 또는 좌표와 같은 시기적절하지만 안정적인 데이터 전달에 사용됩니다. 인터럽트 전송에는 최대 대기 시간이 보장됩니다. USB 마우스 및 키보드는 일반적으로 인터럽트 데이터 전송을 사용합니다.

 

4. isochronous data transfers : 사전 협상된 전송 대기 시간으로 사전 협상된 양의 USB 대역폭을 점유합니다. 등시 전송에는 타이밍이 보장되지만 오류 수정 기능은 없습니다. 등시성 데이터는 타이밍을 유지하기 위해 수신된 속도로 전달되어야 하며 추가로 전달 지연에 민감할 수 있습니다. 등시 전송의 일반적인 용도는 스트리밍 오디오 또는 비디오입니다.

 

 

USB device Class

USB 사양 및 추가 문서는 기능 및 인터페이스 요구 사항에 따라 USB 장치를 분류하는 여러 장치 클래스를 정의합니다. 호스트가 장치 정보를 검색할 때 클래스 분류는 호스트가 USB 장치와 통신하는 방법을 결정하는 데 도움이 됩니다. 허브는 USB 사양에 추가 요구 사항이 있는 특별히 지정된 장치 클래스입니다. 주변 장치 클래스의 다른 예로는 HID라고도 하는 휴먼 인터페이스, 프린터, 이미징, 대용량 저장 장치 및 통신이 있습니다. USB UART 장치는 일반적으로 USB 장치의 통신 장치 클래스(CDC)에 속합니다.

 

Human interface device class

HID 클래스 장치는 일반적으로 어느 정도 사람과 인터페이스합니다. HID 등급 장치에는 마우스, 키보드, 프린터 등이 포함됩니다. 그러나 HID 사양은 장치에 대한 기본 요구 사항과 데이터 전송을 위한 프로토콜을 정의할 뿐이며 장치가 반드시 직접적인 인간 상호 작용에 의존하는 것은 아닙니다. HID 장치는 HID 인터페이스를 표준화되고 효율적으로 유지하기 위해 부과되는 몇 가지 일반 요구 사항을 충족해야 합니다. 

 

• 모든 HID 장치에는 제어 엔드포인트(엔드포인트 0)와 인터럽트 IN 엔드포인트가 있어야 합니다. 많은 장치는 또한 인터럽트 OUT 끝점을 사용합니다. 대부분의 경우 HID 장치는 하나 이상의 OUT 및 하나의 IN 엔드포인트를 가질 수 없습니다. 

• 전송된 모든 데이터는 보고서 설명자에 구조가 정의된 보고서 형식이어야 합니다. 

• HID 장치는 모든 표준 USB 요청 외에도 표준 HID 요청에 응답해야 합니다. 

 

HID 장치가 정상 작동 모드로 들어가 데이터를 호스트로 전송하려면 먼저 장치가 올바르게 열거되어야 합니다. 열거 프로세스는 장치의 기능을 설명하는 장치에 저장된 설명자에 대해 호스트가 수행하는 여러 호출로 구성됩니다. 장치는 표준 형식을 따르는 설명자로 응답해야 합니다. 디스크립터에는 장치에 대한 모든 기본 정보가 포함됩니다. USB 사양은 검색된 일부 설명자를 정의하고 HID 사양은 다른 필수 설명자를 정의합니다. 다음 섹션에서는 호스트가 받을 것으로 예상하는 설명자 구조에 대해 설명합니다.

 

USB descriptors

호스트 소프트웨어는 장치가 연결되는 즉시 열거하는 동안 기본 엔드포인트에 다양한 표준 제어 요청을 전송하여 연결된 장치에서 설명자를 얻습니다. 이러한 요청은 검색할 설명자 유형을 지정합니다. 이러한 요청에 대한 응답으로 장치는 장치, 해당 구성, 인터페이스 및 관련 끝점에 대한 정보를 포함하는 설명자를 보냅니다. 장치 설명자는 전체 장치에 대한 정보를 포함합니다. 모든 USB 장치는 장치의 클래스 정보, 공급업체 및 제품 식별자, 구성 수를 나타내는 장치 설명자를 노출합니다. 각 구성은 인터페이스 수와 전원 특성을 나타내는 구성 설명자를 노출합니다. 각 인터페이스는 클래스 및 끝점 수에 대한 정보를 포함하는 각 대체 설정에 대한 인터페이스 설명자를 노출합니다. 각 인터페이스 내의 각 끝점은 끝점 유형과 최대 패킷 크기를 나타내는 끝점 설명자를 노출합니다. 디스크립터는 디스크립터 길이를 바이트 단위로 설명하는 바이트로 시작합니다. 이 길이는 길이를 저장하는 바이트를 포함하여 디스크립터의 총 바이트 수와 같습니다. 다음 바이트는 호스트가 설명자에 포함된 나머지 바이트를 올바르게 해석할 수 있도록 하는 설명자 유형을 나타냅니다. 나머지 바이트의 내용과 값은 전송되는 설명자의 유형에 따라 다릅니다. 설명자 구조는 사양을 정확히 따라야 합니다. 호스트는 크기 또는 값의 오류가 포함된 수신된 설명자를 무시하므로 잠재적으로 열거가 실패하고 장치와 호스트 간의 추가 통신이 금지됩니다.

 

USB device descriptors

모든 범용 직렬 버스(USB) 장치는 장치 관련 정보가 포함된 단일 장치 설명자를 제공할 수 있어야 합니다. 예를 들어 idVendor 및 idProduct 필드는 각각 공급업체 및 제품 식별자를 지정합니다. bcdUSB 필드는 장치가 준수하는 USB 사양의 버전을 나타냅니다. 예를 들어 0x0200은 장치가 USB 2.0 사양에 따라 설계되었음을 나타냅니다. bcdDevice 값은 장치 정의 개정 번호를 나타냅니다. 장치 설명자는 또한 장치가 지원하는 총 구성 수를 나타냅니다. 아래에서 모든 장치 설명자 필드를 포함하는 구조의 예를 볼 수 있습니다.

 

include/linux/usb/ch9.h

/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 bcdUSB;
	__u8  bDeviceClass;
	__u8  bDeviceSubClass;
	__u8  bDeviceProtocol;
	__u8  bMaxPacketSize0;
	__le16 idVendor;
	__le16 idProduct;
	__le16 bcdDevice;
	__u8  iManufacturer;
	__u8  iProduct;
	__u8  iSerialNumber;
	__u8  bNumConfigurations;
} __attribute__ ((packed));

 

- blength는 설명자 길이를 설명하며 모든 USB 장치 설명자에 공통되어야 합니다.


- bDescriptorType은 장치 설명자에 대한 상수 1바이트 지정자이며 모든 장치 설명자에 공통되어야 합니다.


- BCD로 인코딩된 2바이트 bcdUSB 항목은 장치가 따르는 USB 사양 릴리스 지침을 시스템에 알려줍니다. 호스트는 이 항목을 사용하여 장치에 로드할 드라이버를 결정하는 데 도움이 되므로 USB 사양의 향후 개정에 포함된 추가 또는 변경 사항을 활용하는 장치에서 이 번호를 변경해야 할 수 있습니다.


- USB 장치 클래스가 장치 설명자 내에서 정의되는 경우 이 항목 bDeviceClass에는 USB 사양에 정의된 상수가 포함됩니다. 다른 디스크립터에 정의된 장치 클래스는 장치 디스크립터의 장치 클래스 항목을 0x00으로 설정해야 합니다.
위에서 설명한 장치 클래스 항목이 0x00으로 설정되어 있으면 장치 bDeviceSubClass 항목도 0x00으로 설정되어야 합니다. 

 

- 장치의 하위 클래스 설정에 대한 호스트 정보를 알려줄 수 있습니다. bDeviceProtocol은 장치가 고속 전송을 지원하는지 여부를 호스트에 알려줄 수 있습니다. 위의 두 항목이 0x00으로 설정되어 있으면 이 항목도 0x00으로 설정되어야 합니다.


- bMaxPacketSize0 항목은 단일 제어 끝점 전송 내에 포함될 수 있는 최대 바이트 수를 호스트에 알려줍니다. 저속 장치의 경우 이 바이트를 8로 설정해야 하는 반면 최대 속도 장치는 8, 16, 32 또는 64의 최대 엔드포인트 0 패킷 크기를 가질 수 있습니다.


- 2바이트 항목 idVendor는 장치의 공급업체 ID를 식별합니다. 공급업체 ID는 USB.org 웹사이트를 통해 얻을 수 있습니다. 호스트 응용 프로그램은 연결된 USB 장치의 공급업체 ID를 검색하여 응용 프로그램에 필요한 특정 장치를 찾습니다.
Vendor ID와 마찬가지로 2바이트 항목 idProduct는 연결된 USB 장치를 고유하게 식별합니다. 제품 ID는 USB.org 웹 사이트를 통해 얻을 수 있습니다.

 

- bcdDevice는 각 USB 장치를 고유하게 식별하기 위해 공급업체 ID 및 제품 ID와 함께 사용됩니다.

- 다음 세 개의 1바이트 항목은 시스템 화면에 표시되는 연결된 장치를 설명하는 유니코드 문자열을 검색할 때 사용할 문자열 배열 인덱스를 호스트에 알려줍니다. 이 문자열은 연결된 장치의 제조업체를 설명합니다. 0x00의 iManufacturer 문자열 인덱스 값은 장치가 메모리에 저장된 이 문자열에 대한 값을 가지고 있지 않음을 호스트에 나타냅니다. 색인 iproduct는 호스트가 첨부된 제품을 설명하는 문자열을 검색하려고 할 때 사용됩니다. 예를 들어 문자열은 "USB 키보드"라고 읽을 수 있습니다.
인덱스 iSerialNumber가 가리키는 문자열에는 제품 일련 번호에 대한 유니코드 텍스트가 포함될 수 있습니다.

- bNumConfigurations는 장치가 지원하는 구성 수를 호스트에 알려줍니다. 구성은 끝점 구성을 포함하여 장치의 기능 기능에 대한 정의입니다. 모든 장치에는 하나 이상의 구성이 포함되어야 하지만 둘 이상이 지원될 수 있습니다.

 

USB configuration descriptor

USB 장치는 여러 가지 다른 구성을 가질 수 있지만 대부분의 장치에는 하나만 있습니다. 구성 설명자는 장치에 전원이 공급되는 방식, 최대 전력 소비 및 인터페이스 수를 지정합니다. 두 가지 구성이 가능합니다. 하나는 장치에 버스 전원이 공급되는 경우이고 다른 하나는 주 전원이 공급되는 경우입니다. 아래에서 모든 구성 설명자 필드를 포함하는 구조의 예를 볼 수 있습니다.

 

/* USB_DT_CONFIG: Configuration descriptor information.
 *
 * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
 * descriptor type is different.  Highspeed-capable devices can look
 * different depending on what speed they're currently running.  Only
 * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
 * descriptors.
 */
struct usb_config_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__le16 wTotalLength;
	__u8  bNumInterfaces;
	__u8  bConfigurationValue;
	__u8  iConfiguration;
	__u8  bmAttributes;
	__u8  bMaxPower;
} __attribute__ ((packed));

- blenght는 구성 설명자의 길이를 정의합니다. 이것은 표준 길이입니다. 

- bDescriptorTye는 구성 설명자를 위한 상수 1바이트 0x02 지정자입니다. 

- 2바이트 wTotalLength 항목은 이 설명자 및 이 구성과 관련된 다른 모든 설명자의 길이를 정의합니다. 예를 들어 길이는 구성 설명자, 인터페이스 설명자, HID 클래스 설명자 및 이 인터페이스와 연결된 두 개의 엔드포인트 설명자의 길이를 더하여 계산할 수 있습니다. 이 2바이트 항목은 "리틀 엔디안" 데이터 형식을 따릅니다. 항목은 이 설명자 및 이 구성과 관련된 다른 모든 설명자의 길이를 정의합니다. 

- bNumInterfaces 항목은 이 구성에 포함된 인터페이스 설정의 수를 정의합니다. 

- bConfigurationValue 항목은 SetConfiguration 요청에서 이 구성을 선택하는 데 사용됩니다. 

- iConfiguration 항목은 사람이 읽을 수 있는 형식으로 구성을 설명하는 문자열 설명자에 대한 인덱스입니다. 

- bmAttributes 항목은 디바이스가 원격 웨이크업과 같은 USB 기능을 지원하는지 여부를 호스트에 알려줍니다. 항목 비트는 이러한 조건을 설명하기 위해 설정되거나 지워집니다. 이 항목에 대한 자세한 내용은 USB 사양을 확인하십시오. 

- bMaxPower 항목은 장치가 이 구성에서 제대로 작동하는 데 필요한 전류량을 호스트에 알려줍니다.

 

USB interface descriptor

USB 인터페이스 설명자는 USB 인터페이스의 대체 설정에 대한 정보를 포함할 수 있습니다. 인터페이스 설명자에는 인터페이스 번호를 지정하는 bInterfaceNumber 필드와 해당 인터페이스에 대한 대체 설정을 허용하는 bAlternateSetting 필드가 있습니다. 예를 들어 두 개의 인터페이스가 있는 장치가 있을 수 있습니다. 

첫 번째 인터페이스는 bInterfaceNumber를 0으로 설정하여 첫 번째 인터페이스 설명자임을 나타내고 bAlternativeSetting을 0으로 설정할 수 있습니다. 

두 번째 인터페이스는 bInterfaceNumber를 1로 설정하고 bAlternativeSetting을 0(기본값)으로 설정할 수 있습니다. 이 두 번째 인터페이스에는 bAlternativeSetting이 1로 설정되어 두 번째 인터페이스의 대체 설정이 될 수도 있습니다. 

 

bNumEndpoints 항목은 인터페이스에서 사용하는 엔드포인트 수를 제공합니다.

 

bInterfaceClass, bInterfaceSubClass 및 bInterfaceProtocol 항목은 지원되는 클래스(HID, 대용량 저장소 등)를 지정합니다. 이렇게 하면 많은 장치가 클래스 드라이버를 사용하여 장치에 대한 특정 드라이버를 작성할 필요가 없습니다. iInterface 항목은 인터페이스의 문자열 설명을 허용합니다.

/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bInterfaceNumber;
	__u8  bAlternateSetting;
	__u8  bNumEndpoints;
	__u8  bInterfaceClass;
	__u8  bInterfaceSubClass;
	__u8  bInterfaceProtocol;
	__u8  iInterface;
} __attribute__ ((packed));

 

USB endpoint descriptor

USB 끝점 설명자는 끝점 0과 다른 끝점을 설명합니다. 엔드포인트 0은 다른 설명자보다 먼저 구성되는 제어 엔드포인트입니다. 호스트는 이러한 USB 끝점 설명자에서 반환된 정보를 사용하여 각 끝점에 대한 전송 유형, 방향, 폴링 간격 및 최대 패킷 크기를 지정합니다.

/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;

	__u8  bEndpointAddress;
	__u8  bmAttributes;
	__le16 wMaxPacketSize;
	__u8  bInterval;

	/* NOTE:  these two are _only_ in audio endpoints. */
	/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
	__u8  bRefresh;
	__u8  bSynchAddress;
} __attribute__ ((packed));

bEndpointAddress는 이 설명자가 설명하는 엔드포인트를 나타냅니다. 

bmAttributes는 전송 유형을 지정합니다. 이는 제어, 인터럽트, 등시성 또는 대량 전송일 수 있습니다. Isochronous 엔드포인트가 지정된 경우 동기화 및 사용 유형과 같은 추가 특성을 선택할 수 있습니다. 비트 0..1은 전송 유형입니다. 00 = 제어, 01 = 등시성, 10 = 벌크, 11 = 인터럽트. 비트 2..7은 예약되어 있습니다. 엔드포인트가 Isochronous인 경우 Bits 3..2 = 동기화 유형(Iso 모드): 00 = 동기화 없음, 01 = 비동기, 10 = 적응, 11 = 동기. 비트 5..4 = 사용 유형(Iso 모드): 00 = 데이터 엔드포인트, 01 = 피드백 엔드포인트, 10 = 명시적 피드백 데이터 엔드포인트, 11 = 예약됨. 

 

wMaxPacketSize 항목은 이 엔드포인트의 최대 페이로드 크기를 나타냅니다. 

 

bInterval 항목은 끝점 데이터 전송의 폴링 간격을 지정하는 데 사용됩니다. 대량 및 제어 끝점에 대해서는 무시됩니다. 단위는 프레임으로 표시되므로 저속/전속 장치의 경우 1ms, 고속 장치의 경우 125us에 해당합니다.

 

USB string descriptors

USB 문자열 설명자(USB_STRING_DESCRIPTOR)는 사람이 읽을 수 있는 정보를 다른 설명자에 제공합니다. 선택 사항입니다. 장치가 문자열 설명자를 지원하지 않는 경우 장치, 구성 및 인터페이스 설명자 내의 문자열 설명자에 대한 모든 참조는 0으로 설정되어야 합니다.

 

문자열 설명자는 단일 제품에서 여러 언어를 지원할 수 있도록 유니코드로 인코딩된 문자입니다. 문자열 설명자를 요청할 때 요청자는 USB-IF에서 정의한 16비트 언어 ID(LANGID)를 사용하여 원하는 언어를 지정합니다. 문자열 인덱스 0은 모든 언어에 사용되며 장치에서 지원하는 2바이트 LANGID 코드 배열을 포함하는 문자열 설명자를 반환합니다.

 

UNICODE 문자열 설명자는 NULL로 끝나지 않습니다. 문자열 길이는 설명자의 첫 번째 바이트 값에서 2를 빼서 계산합니다.

 

USB HID descriptor

USB HID 장치 클래스는 사람이 컴퓨터 시스템의 작동을 제어하는 ​​데 사용하는 장치를 지원합니다. HID 등급의 장치에는 최종 사용자에게 전달되는 다양한 유형의 출력이 있는 다양한 휴먼 인터페이스, 데이터 표시기 및 데이터 피드백 장치가 포함됩니다

 

USB HID device는 아래 descriptor들을 필요로 합니다.

• Standard device descriptor.  

• Standard configuration descriptor.  

• Standard interface descriptor for the HID class.  

• Class-specific HID descriptor.  

• Standard endpoint descriptor for interrupt IN endpoint.  

• Class-specific report descriptor.  

 

struct hid_class_descriptor {
	__u8  bDescriptorType;
	__le16 wDescriptorLength;
} __attribute__ ((packed));

struct hid_descriptor {
	__u8  bLength;
	__u8  bDescriptorType;
	__le16 bcdHID;
	__u8  bCountryCode;
	__u8  bNumDescriptors;

	struct hid_class_descriptor desc[1];
} __attribute__ ((packed));

 

- bLength 항목은 HID descriptor의 크기를 설명합니다. 이 HID 구성 정의에 포함된 하위 설명자(예: 보고서 설명자)의 수에 따라 달라질 수 있습니다.

- bDescriptorType 0x21 값은 장치 설명자를 위한 상수 1바이트 지정자이며 모든 HID 설명자에 공통되어야 합니다.

- 2바이트 bcdHID 항목은 장치가 따르는 HID 클래스 사양의 버전을 호스트에 알려줍니다. USB 사양에서는 이 값을 이진 코드 십진수로 형식화해야 합니다. 즉, 각 바이트의 상위 및 하위 니블이 숫자 0...9를 나타냅니다. 예를 들어, 0x0101은 숫자 0101을 나타내며 소수점이 포함된 개정 번호 1.01과 같습니다.

- 장치가 특정 국가로 현지화되도록 설계된 경우 bCountryCode 항목은 호스트에 국가를 알려줍니다. 항목을 0x00으로 설정하면 장치가 어떤 국가에도 현지화되도록 설계되지 않았음을 호스트에 알립니다. bNumDescriptors 항목은 이 HID 구성에 포함된 보고서 설명자 수를 호스트에 알려줍니다.

- 다음 2바이트 항목 쌍은 포함된 각 보고서 설명자를 설명합니다.

 

- bReportDescriptorType 항목은 이 HID 설명자의 전송을 따르는 첫 번째 설명자를 설명합니다. 예를 들어 값이 "0x22"이면 뒤에 오는 설명자가 보고서 설명자임을 나타냅니다.

- wItemLength 항목은 이전 항목에서 설명한 디스크립터의 크기를 호스트에 알려줍니다.

- HID report descriptor는 장치의 데이터 패킷을 설명하는 하드 코딩된 바이트 배열입니다. 여기에는 장치가 지원하는 패킷 수, 패킷 크기, 패킷의 각 바이트 및 비트 용도가 포함됩니다. 예를 들어, 계산기 프로그램 버튼이 있는 키보드는 버튼의 눌림/해제 상태가 데이터 패킷 번호 4의 6번째 바이트에서 2번째 비트로 저장됨을 호스트에 알릴 수 있습니다.

 

LInux USB subsystem

USB 지원은 2.2 커널 시리즈 초기에 Linux에 추가되었으며 그 이후로 계속 개발되었습니다. 각각의 차세대 USB에 대한 지원 외에도 다양한 호스트 컨트롤러가 지원되고 주변 장치용 새 드라이버가 추가되었으며 대기 시간 측정 및 향상된 전원 관리를 위한 고급 기능이 도입되었습니다. Linux에서 "USB Core"는 USB 주변 장치 및 호스트 컨트롤러를 지원하기 위해 구현된 특정 API입니다. 이 API는 일련의 데이터 구조, 매크로 및 함수를 정의하여 모든 하드웨어를 추상화합니다. USB 장치용 호스트 측 드라이버는 이러한 "usbcore" API와 통신합니다. 두 세트의 API가 있는데, 하나는 범용 USB 장치 드라이버(이 장을 통해 개발될 것)용이고 다른 하나는 코어의 일부인 드라이버용입니다. 이러한 핵심 드라이버에는 USB 장치 트리를 관리하는 허브 드라이버와 개별 버스를 제어하는 ​​여러 종류의 USB 호스트 어댑터 드라이버가 포함됩니다.

 

Linux USB API는 제어 및 대량 메시지에 대한 동기식 호출을 지원합니다. 또한 "URB"(USB 요청 블록)라는 요청 구조를 사용하여 모든 종류의 데이터 전송에 대한 비동기 호출을 지원합니다. 실제로 하드웨어(레지스터 읽기/쓰기, IRQ 처리 등)에 영향을 미치는 유일한 호스트 측 드라이버는 HCD(호스트 컨트롤러 장치) 드라이버입니다. 이론적으로 모든 HCD는 동일한 API를 통해 동일한 기능을 제공합니다. 실제로는 점점 더 사실이 되고 있지만, 특히 덜 일반적인 컨트롤러의 오류 처리에서 발생하는 차이점이 여전히 있습니다. 서로 다른 컨트롤러가 반드시 동일한 장애 측면을 보고하는 것은 아니며 장애 복구(URB 연결 해제와 같은 소프트웨어로 인한 장애 포함)는 아직 완전히 일관성이 없습니다. 이 장의 주요 초점은 Linux USB 장치 드라이버의 개발입니다. 다음의 모든 섹션은 이러한 유형의 드라이버 개발과 관련이 있습니다.

 

USB device driver registration

Linux USB 장치 드라이버가 가장 먼저 해야 할 일은 Linux USB 코어에 자신을 등록하여 드라이버가 지원하는 장치에 대한 정보와 드라이버가 지원하는 장치가 시스템에 삽입되거나 제거될 때 호출할 기능에 대한 정보를 제공하는 것입니다. 이 모든 정보는 usb_driver 구조의 USB 코어로 전달됩니다. 커널 소스 트리의 drivers/usb/misc/usbsevseg.c에 있는 USB 7 segment driver에 대한 아래의 usb_driver 정의를 참조하십시오.

static struct usb_driver sevseg_driver = {
	.name =		"usbsevseg",
	.probe =	sevseg_probe,
	.disconnect =	sevseg_disconnect,
	.suspend =	sevseg_suspend,
	.resume =	sevseg_resume,
	.reset_resume =	sevseg_reset_resume,
	.id_table =	id_table,
	.dev_groups =	sevseg_groups,
	.supports_autosuspend = 1,
};

.name은 드라이버를 설명하는 문자열입니다. 시스템 로그에 인쇄되는 정보 메시지에 사용됩니다. probe() 및 disconnect() 핫 플러그 ​​콜백은 id_table 변수에 제공된 정보와 일치하는 장치가 보이거나 제거될 때 호출됩니다.

 

probe() 함수는 USB 코어에 의해 드라이버로 호출되어 드라이버가 장치의 특정 인터페이스를 관리할 의향이 있는지 확인합니다. 그렇다면 probe()는 0을 반환하고 usb_set_intfdata()를 사용하여 드라이버 특정 데이터를 인터페이스와 연결합니다. 적절한 altsetting을 지정하기 위해 usb_set_interface()를 사용할 수도 있습니다. 인터페이스를 관리하지 않으려는 경우 -ENODEV를 반환하고 실제 IO 오류가 발생한 경우 적절한 음수 errno 값을 반환합니다.


int (* probe) (struct usb_interface *intf,const struct usb_device_id *id); 

 

disconnect() 콜백은 인터페이스에 더 이상 액세스할 수 없을 때 호출됩니다. 일반적으로 해당 장치의 연결이 끊어졌거나 드라이버 모듈이 언로드 중이기 때문입니다.

void disconnect(struct usb device *dev, void *drv context); 

usb_driver 구조에서 몇 가지 전원 관리(PM) 콜백이 정의됩니다. 

• suspend: 장치가 일시 중단될 때 호출됩니다. 

• 재개: 장치가 재개될 때 호출됩니다. 

• reset_resume: 일시 중단된 장치가 재개되지 않고 재설정되었을 때 호출됩니다. 

 

또한 usb_driver 구조에는 몇 가지 장치 수준 작업이 정의되어 있습니다. 

• pre_reset: 장치가 재설정되려고 할 때 호출됩니다.

• post_reset: 장치가 재설정된 후 호출됩니다.

 

USB 장치 드라이버는 ID 테이블을 사용하여 핫 플러그를 지원합니다. usb_driver 구조에 포함된 포인터 변수 id_table은 USB 장치 드라이버가 지원하는 장치를 알리는 usb_device_id 유형의 구조 배열을 가리킵니다. 대부분의 드라이버는 USB_DEVICE() 매크로를 사용하여 usb_device_id 구조를 생성합니다. 이러한 구조는 MODULE_DEVICE_TABLE(usb, xxx) 매크로를 사용하여 USB 코어에 등록됩니다. drivers/usb/misc/usbsevseg.c 드라이버에 포함된 다음 코드 행은 USB 장치를 생성하고 USB 코어에 등록합니다.

 

/* table of devices that work with this driver */  
static const struct usb_device_id id_table[] = 
{  
	{ USB_DEVICE(VENDOR_ID, PRODUCT_ID) },  
    {},  
};  

MODULE_DEVICE_TABLE(usb, id_table);

usb_driver 구조는 module_usb_driver() 함수를 사용하여 버스 코어에 등록됩니다.

module_usb_driver(sevseg_driver);



Linux host-side data types

USB 장치 드라이버는 실제로 장치가 아닌 인터페이스에 바인딩됩니다. 구분이 중요한 장치가 많지 않을 수도 있지만 "인터페이스 드라이버"라고 생각하십시오. 대부분의 USB 장치는 하나의 기능, 하나의 구성, 하나의 인터페이스 및 하나의 대체 설정으로 단순합니다. USB 인터페이스는 usb_interface 구조로 표시됩니다. 이것은 이 콜백 함수가 호출될 때 USB 코어가 USB 드라이버의 probe() 함수로 전달하는 것입니다.

/**
 * struct usb_interface - what usb device drivers talk to
 * @altsetting: array of interface structures, one for each alternate
 *	setting that may be selected.  Each one includes a set of
 *	endpoint configurations.  They will be in no particular order.
 * @cur_altsetting: the current altsetting.
 * @num_altsetting: number of altsettings defined.
 * @intf_assoc: interface association descriptor
 * @minor: the minor number assigned to this interface, if this
 *	interface is bound to a driver that uses the USB major number.
 *	If this interface does not use the USB major, this field should
 *	be unused.  The driver should set this value in the probe()
 *	function of the driver, after it has been assigned a minor
 *	number from the USB core by calling usb_register_dev().
 * @condition: binding state of the interface: not bound, binding
 *	(in probe()), bound to a driver, or unbinding (in disconnect())
 * @sysfs_files_created: sysfs attributes exist
 * @ep_devs_created: endpoint child pseudo-devices exist
 * @unregistering: flag set when the interface is being unregistered
 * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
 *	capability during autosuspend.
 * @needs_altsetting0: flag set when a set-interface request for altsetting 0
 *	has been deferred.
 * @needs_binding: flag set when the driver should be re-probed or unbound
 *	following a reset or suspend operation it doesn't support.
 * @authorized: This allows to (de)authorize individual interfaces instead
 *	a whole device in contrast to the device authorization.
 * @dev: driver model's view of this device
 * @usb_dev: if an interface is bound to the USB major, this will point
 *	to the sysfs representation for that device.
 * @reset_ws: Used for scheduling resets from atomic context.
 * @resetting_device: USB core reset the device, so use alt setting 0 as
 *	current; needs bandwidth alloc after reset.
 *
 * USB device drivers attach to interfaces on a physical device.  Each
 * interface encapsulates a single high level function, such as feeding
 * an audio stream to a speaker or reporting a change in a volume control.
 * Many USB devices only have one interface.  The protocol used to talk to
 * an interface's endpoints can be defined in a usb "class" specification,
 * or by a product's vendor.  The (default) control endpoint is part of
 * every interface, but is never listed among the interface's descriptors.
 *
 * The driver that is bound to the interface can use standard driver model
 * calls such as dev_get_drvdata() on the dev member of this structure.
 *
 * Each interface may have alternate settings.  The initial configuration
 * of a device sets altsetting 0, but the device driver can change
 * that setting using usb_set_interface().  Alternate settings are often
 * used to control the use of periodic endpoints, such as by having
 * different endpoints use different amounts of reserved USB bandwidth.
 * All standards-conformant USB devices that use isochronous endpoints
 * will use them in non-default settings.
 *
 * The USB specification says that alternate setting numbers must run from
 * 0 to one less than the total number of alternate settings.  But some
 * devices manage to mess this up, and the structures aren't necessarily
 * stored in numerical order anyhow.  Use usb_altnum_to_altsetting() to
 * look up an alternate setting in the altsetting array based on its number.
 */
struct usb_interface {
	/* array of alternate settings for this interface,
	 * stored in no particular order */
	struct usb_host_interface *altsetting;

	struct usb_host_interface *cur_altsetting;	/* the currently
					 * active alternate setting */
	unsigned num_altsetting;	/* number of alternate settings */

	/* If there is an interface association descriptor then it will list
	 * the associated interfaces */
	struct usb_interface_assoc_descriptor *intf_assoc;

	int minor;			/* minor number this interface is
					 * bound to */
	enum usb_interface_condition condition;		/* state of binding */
	unsigned sysfs_files_created:1;	/* the sysfs attributes exist */
	unsigned ep_devs_created:1;	/* endpoint "devices" exist */
	unsigned unregistering:1;	/* unregistration is in progress */
	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
	unsigned needs_altsetting0:1;	/* switch to altsetting 0 is pending */
	unsigned needs_binding:1;	/* needs delayed unbind/rebind */
	unsigned resetting_device:1;	/* true: bandwidth alloc after reset */
	unsigned authorized:1;		/* used for interface authorization */

	struct device dev;		/* interface specific device info */
	struct device *usb_dev;
	struct work_struct reset_ws;	/* for resets in atomic context */
};

다음은 usb_interface 구조의 주요 구성원입니다. 

• altsetting: usb_host_interface 구조의 배열로, 선택할 수 있는 각 대체 설정에 하나씩 있습니다. 각각에는 엔드포인트 구성 세트가 포함됩니다. 특별한 순서는 없습니다. 각 대체 설정에 대한 usb_host_interface 구조는 각 끝점에 대한 usb_endpoint_descriptor 구조에 액세스할 수 있도록 합니다. 

• cur_altsetting: 현재 altsetting입니다. 

• num_altsetting: 정의된 altsettings의 수입니다. 

 

각 인터페이스에는 대체 설정이 있을 수 있습니다. 장치의 초기 구성은 altsetting을 0으로 설정하지만 장치 드라이버는 usb_set_interface()를 사용하여 해당 설정을 변경할 수 있습니다. 대체 설정은 서로 다른 엔드포인트가 서로 다른 양의 예약된 USB 대역폭을 사용하도록 하는 것과 같이 주기적인 엔드포인트의 사용을 제어하는 ​​데 자주 사용됩니다. 등시성 끝점을 사용하는 모든 표준 준수 USB 장치는 기본값이 아닌 설정에서 이를 사용합니다.

 

usb_host_interface 구조는 usb_host_endpoint 구조의 배열을 포함합니다.

/* host-side wrapper for one interface setting’s parsed descriptors */  
struct usb_host_interface {  
	struct usb_interface_descriptor desc;  
	int extralen;  
	unsigned char *extra; /* Extra descriptors */  

/*  * array of desc.bNumEndpoints endpoints associated with this  
* interface setting. These will be in no particular order.  */  

	struct usb_host_endpoint *endpoint;  char *string; 

/* iInterface string, if present */  
};

각 usb_host_endpoint 구조에는 usb_endpoint_descriptor 구조가 포함됩니다.

struct usb_host_endpoint {  
	struct usb_endpoint_descriptor desc;  
	struct usb_ss_ep_comp_descriptor ss_ep_comp;  
	struct usb_ssp_isoc_ep_comp_descriptor ssp_isoc_ep_comp;  
	struct list_head urb_list;  
	void *hcpriv;  
	struct ep_device *ep_dev; /* For sysfs info */ 
	unsigned char *extra; /* Extra descriptors */  
	int extralen;  
    int enabled; 
    int streams;  
};

usb_endpoint_descriptor 구조에는 장치 자체에서 발표한 모든 USB 관련 데이터가 포함되어 있습니다.

struct usb_endpoint_descriptor {
	__u8 bLength;
	__u8 bDescriptorType;
	__u8 bEndpointAddress;
	__u8 bmAttributes;
	__le16 wMaxPacketSize;
	__u8 bInterval;
	
    	/* NOTE: these two are _only_ in audio endpoints. */ 
        /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
	__u8 bRefresh;
	__u8 bSynchAddress;
} __attribute__((packed));

다음 코드 스니펫을 사용하여 USB 인터페이스의 현재 altsetting에 포함된 IN 및 OUT 끝점 설명자에서 IN 및 OUT 끝점 주소를 얻을 수 있습니다.

struct usb_host_interface *altsetting = intf->cur_altsetting;
int ep_in,	ep_out; 

/* There are two usb_host_endpoint structures in this interface altsetting. 
Each usb_host_  endpoint structure contains a usb_endpoint_descriptor */

ep_in = altsetting->endpoint[0].desc.bEndpointAddress;
ep_out = altsetting->endpoint[1].desc.bEndpointAddress;

Liberal de los Ríos, Alberto.Linux Driver Development with Raspberry Pi -
			     Practical Labs(p.581).Kindle Edition.

 

USB request block (URB)

호스트와 장치 간의 모든 통신은 USB 요청 블록(urbs)을 사용하여 비동기적으로 수행됩니다.

• URB는 모든 USB 트랜잭션을 실행하고 데이터와 상태를 다시 전달하기 위한 모든 관련 정보로 구성됩니다.
• URB 실행은 본질적으로 비동기 작업입니다. 즉, usb_submit_urb() 호출은 요청된 작업을 성공적으로 대기열에 넣은 직후 반환됩니다.
• 하나의 URB에 대한 전송은 언제든지 usb_unlink_urb()를 호출하여 취소할 수 있습니다.
• 각 URB에는 작업이 성공적으로 완료되거나 취소된 후에 호출되는 완료 처리기가 있습니다. URB에는 완료 핸들러에 정보를 전달하기 위한 컨텍스트 포인터도 포함되어 있습니다.
• 장치의 각 끝점은 요청 대기열을 논리적으로 지원합니다. 드라이버가 다른 완료를 처리하는 동안 USB 하드웨어가 끝점으로 데이터를 계속 전송할 수 있도록 대기열을 채울 수 있습니다. 이는 USB 대역폭 사용을 최대화하고 주기적인 전송 모드를 사용할 때 장치로(또는 장치에서) 데이터의 원활한 스트리밍을 지원합니다.

 

/**
 * struct urb - USB Request Block
 * @urb_list: For use by current owner of the URB.
 * @anchor_list: membership in the list of an anchor
 * @anchor: to anchor URBs to a common mooring
 * @ep: Points to the endpoint's data structure.  Will eventually
 *	replace @pipe.
 * @pipe: Holds endpoint number, direction, type, and more.
 *	Create these values with the eight macros available;
 *	usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
 *	(control), "bulk", "int" (interrupt), or "iso" (isochronous).
 *	For example usb_sndbulkpipe() or usb_rcvintpipe().  Endpoint
 *	numbers range from zero to fifteen.  Note that "in" endpoint two
 *	is a different endpoint (and pipe) from "out" endpoint two.
 *	The current configuration controls the existence, type, and
 *	maximum packet size of any given endpoint.
 * @stream_id: the endpoint's stream ID for bulk streams
 * @dev: Identifies the USB device to perform the request.
 * @status: This is read in non-iso completion functions to get the
 *	status of the particular request.  ISO requests only use it
 *	to tell whether the URB was unlinked; detailed status for
 *	each frame is in the fields of the iso_frame-desc.
 * @transfer_flags: A variety of flags may be used to affect how URB
 *	submission, unlinking, or operation are handled.  Different
 *	kinds of URB can use different flags.
 * @transfer_buffer:  This identifies the buffer to (or from) which the I/O
 *	request will be performed unless URB_NO_TRANSFER_DMA_MAP is set
 *	(however, do not leave garbage in transfer_buffer even then).
 *	This buffer must be suitable for DMA; allocate it with
 *	kmalloc() or equivalent.  For transfers to "in" endpoints, contents
 *	of this buffer will be modified.  This buffer is used for the data
 *	stage of control transfers.
 * @transfer_dma: When transfer_flags includes URB_NO_TRANSFER_DMA_MAP,
 *	the device driver is saying that it provided this DMA address,
 *	which the host controller driver should use in preference to the
 *	transfer_buffer.
 * @sg: scatter gather buffer list, the buffer size of each element in
 * 	the list (except the last) must be divisible by the endpoint's
 * 	max packet size if no_sg_constraint isn't set in 'struct usb_bus'
 * @num_mapped_sgs: (internal) number of mapped sg entries
 * @num_sgs: number of entries in the sg list
 * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
 *	be broken up into chunks according to the current maximum packet
 *	size for the endpoint, which is a function of the configuration
 *	and is encoded in the pipe.  When the length is zero, neither
 *	transfer_buffer nor transfer_dma is used.
 * @actual_length: This is read in non-iso completion functions, and
 *	it tells how many bytes (out of transfer_buffer_length) were
 *	transferred.  It will normally be the same as requested, unless
 *	either an error was reported or a short read was performed.
 *	The URB_SHORT_NOT_OK transfer flag may be used to make such
 *	short reads be reported as errors.
 * @setup_packet: Only used for control transfers, this points to eight bytes
 *	of setup data.  Control transfers always start by sending this data
 *	to the device.  Then transfer_buffer is read or written, if needed.
 * @setup_dma: DMA pointer for the setup packet.  The caller must not use
 *	this field; setup_packet must point to a valid buffer.
 * @start_frame: Returns the initial frame for isochronous transfers.
 * @number_of_packets: Lists the number of ISO transfer buffers.
 * @interval: Specifies the polling interval for interrupt or isochronous
 *	transfers.  The units are frames (milliseconds) for full and low
 *	speed devices, and microframes (1/8 millisecond) for highspeed
 *	and SuperSpeed devices.
 * @error_count: Returns the number of ISO transfers that reported errors.
 * @context: For use in completion functions.  This normally points to
 *	request-specific driver context.
 * @complete: Completion handler. This URB is passed as the parameter to the
 *	completion function.  The completion function may then do what
 *	it likes with the URB, including resubmitting or freeing it.
 * @iso_frame_desc: Used to provide arrays of ISO transfer buffers and to
 *	collect the transfer status for each buffer.
 *
 * This structure identifies USB transfer requests.  URBs must be allocated by
 * calling usb_alloc_urb() and freed with a call to usb_free_urb().
 * Initialization may be done using various usb_fill_*_urb() functions.  URBs
 * are submitted using usb_submit_urb(), and pending requests may be canceled
 * using usb_unlink_urb() or usb_kill_urb().
 *
 * Data Transfer Buffers:
 *
 * Normally drivers provide I/O buffers allocated with kmalloc() or otherwise
 * taken from the general page pool.  That is provided by transfer_buffer
 * (control requests also use setup_packet), and host controller drivers
 * perform a dma mapping (and unmapping) for each buffer transferred.  Those
 * mapping operations can be expensive on some platforms (perhaps using a dma
 * bounce buffer or talking to an IOMMU),
 * although they're cheap on commodity x86 and ppc hardware.
 *
 * Alternatively, drivers may pass the URB_NO_TRANSFER_DMA_MAP transfer flag,
 * which tells the host controller driver that no such mapping is needed for
 * the transfer_buffer since
 * the device driver is DMA-aware.  For example, a device driver might
 * allocate a DMA buffer with usb_alloc_coherent() or call usb_buffer_map().
 * When this transfer flag is provided, host controller drivers will
 * attempt to use the dma address found in the transfer_dma
 * field rather than determining a dma address themselves.
 *
 * Note that transfer_buffer must still be set if the controller
 * does not support DMA (as indicated by hcd_uses_dma()) and when talking
 * to root hub. If you have to trasfer between highmem zone and the device
 * on such controller, create a bounce buffer or bail out with an error.
 * If transfer_buffer cannot be set (is in highmem) and the controller is DMA
 * capable, assign NULL to it, so that usbmon knows not to use the value.
 * The setup_packet must always be set, so it cannot be located in highmem.
 *
 * Initialization:
 *
 * All URBs submitted must initialize the dev, pipe, transfer_flags (may be
 * zero), and complete fields.  All URBs must also initialize
 * transfer_buffer and transfer_buffer_length.  They may provide the
 * URB_SHORT_NOT_OK transfer flag, indicating that short reads are
 * to be treated as errors; that flag is invalid for write requests.
 *
 * Bulk URBs may
 * use the URB_ZERO_PACKET transfer flag, indicating that bulk OUT transfers
 * should always terminate with a short packet, even if it means adding an
 * extra zero length packet.
 *
 * Control URBs must provide a valid pointer in the setup_packet field.
 * Unlike the transfer_buffer, the setup_packet may not be mapped for DMA
 * beforehand.
 *
 * Interrupt URBs must provide an interval, saying how often (in milliseconds
 * or, for highspeed devices, 125 microsecond units)
 * to poll for transfers.  After the URB has been submitted, the interval
 * field reflects how the transfer was actually scheduled.
 * The polling interval may be more frequent than requested.
 * For example, some controllers have a maximum interval of 32 milliseconds,
 * while others support intervals of up to 1024 milliseconds.
 * Isochronous URBs also have transfer intervals.  (Note that for isochronous
 * endpoints, as well as high speed interrupt endpoints, the encoding of
 * the transfer interval in the endpoint descriptor is logarithmic.
 * Device drivers must convert that value to linear units themselves.)
 *
 * If an isochronous endpoint queue isn't already running, the host
 * controller will schedule a new URB to start as soon as bandwidth
 * utilization allows.  If the queue is running then a new URB will be
 * scheduled to start in the first transfer slot following the end of the
 * preceding URB, if that slot has not already expired.  If the slot has
 * expired (which can happen when IRQ delivery is delayed for a long time),
 * the scheduling behavior depends on the URB_ISO_ASAP flag.  If the flag
 * is clear then the URB will be scheduled to start in the expired slot,
 * implying that some of its packets will not be transferred; if the flag
 * is set then the URB will be scheduled in the first unexpired slot,
 * breaking the queue's synchronization.  Upon URB completion, the
 * start_frame field will be set to the (micro)frame number in which the
 * transfer was scheduled.  Ranges for frame counter values are HC-specific
 * and can go from as low as 256 to as high as 65536 frames.
 *
 * Isochronous URBs have a different data transfer model, in part because
 * the quality of service is only "best effort".  Callers provide specially
 * allocated URBs, with number_of_packets worth of iso_frame_desc structures
 * at the end.  Each such packet is an individual ISO transfer.  Isochronous
 * URBs are normally queued, submitted by drivers to arrange that
 * transfers are at least double buffered, and then explicitly resubmitted
 * in completion handlers, so
 * that data (such as audio or video) streams at as constant a rate as the
 * host controller scheduler can support.
 *
 * Completion Callbacks:
 *
 * The completion callback is made in_interrupt(), and one of the first
 * things that a completion handler should do is check the status field.
 * The status field is provided for all URBs.  It is used to report
 * unlinked URBs, and status for all non-ISO transfers.  It should not
 * be examined before the URB is returned to the completion handler.
 *
 * The context field is normally used to link URBs back to the relevant
 * driver or request state.
 *
 * When the completion callback is invoked for non-isochronous URBs, the
 * actual_length field tells how many bytes were transferred.  This field
 * is updated even when the URB terminated with an error or was unlinked.
 *
 * ISO transfer status is reported in the status and actual_length fields
 * of the iso_frame_desc array, and the number of errors is reported in
 * error_count.  Completion callbacks for ISO transfers will normally
 * (re)submit URBs to ensure a constant transfer rate.
 *
 * Note that even fields marked "public" should not be touched by the driver
 * when the urb is owned by the hcd, that is, since the call to
 * usb_submit_urb() till the entry into the completion routine.
 */
struct urb {
	/* private: usb core and host controller only fields in the urb */
	struct kref kref;		/* reference count of the URB */
	int unlinked;			/* unlink error code */
	void *hcpriv;			/* private data for host controller */
	atomic_t use_count;		/* concurrent submissions counter */
	atomic_t reject;		/* submissions will fail */

	/* public: documented fields in the urb that can be used by drivers */
	struct list_head urb_list;	/* list head for use by the urb's
					 * current owner */
	struct list_head anchor_list;	/* the URB may be anchored */
	struct usb_anchor *anchor;
	struct usb_device *dev;		/* (in) pointer to associated device */
	struct usb_host_endpoint *ep;	/* (internal) pointer to endpoint */
	unsigned int pipe;		/* (in) pipe information */
	unsigned int stream_id;		/* (in) stream ID */
	int status;			/* (return) non-ISO status */
	unsigned int transfer_flags;	/* (in) URB_SHORT_NOT_OK | ...*/
	void *transfer_buffer;		/* (in) associated data buffer */
	dma_addr_t transfer_dma;	/* (in) dma addr for transfer_buffer */
	struct scatterlist *sg;		/* (in) scatter gather buffer list */
	int num_mapped_sgs;		/* (internal) mapped sg entries */
	int num_sgs;			/* (in) number of entries in the sg list */
	u32 transfer_buffer_length;	/* (in) data buffer length */
	u32 actual_length;		/* (return) actual transfer length */
	unsigned char *setup_packet;	/* (in) setup packet (control only) */
	dma_addr_t setup_dma;		/* (in) dma addr for setup_packet */
	int start_frame;		/* (modify) start frame (ISO) */
	int number_of_packets;		/* (in) number of ISO packets */
	int interval;			/* (modify) transfer interval
					 * (INT/ISO) */
	int error_count;		/* (return) number of ISO errors */
	void *context;			/* (in) context for completion */
	usb_complete_t complete;	/* (in) completion routine */
	struct usb_iso_packet_descriptor iso_frame_desc[0];
					/* (in) ISO ONLY */
};

USB 드라이버는 요청된 인터페이스의 적절한 끝점 설명자 값을 사용하여 "pipe"를 생성해야 합니다.


URBs are allocated by calling usb_alloc_urb():  

struct urb *usb_alloc_urb(int isoframes, int mem_flags); 


반환 값은 할당된 URB에 대한 포인터이며 할당에 실패하면 0입니다. isoframes 매개변수는 예약하려는 등시성 전송 프레임의 수를 지정합니다. CTRL/BULK/INT의 경우 0을 사용합니다. mem_flags 매개변수는 표준 메모리 할당 플래그를 포함하므로 기본 코드가 차단될지 여부를 제어할 수 있습니다.

To free an URB, use usb_free_urb():  

void usb_free_urb(struct urb *urb); 

인터럽트 전송은 주기적이며 2(1, 2, 4 등) 단위의 거듭제곱 간격으로 발생합니다. 단위는 전속 및 저속 장치용 프레임과 고속 장치용 마이크로프레임입니다. usb_fill_int_urb() 매크로를 사용하여 INT 전송 필드를 채울 수 있습니다. usb_fill_int_urb() 함수를 사용하여 쓰기 urb가 적절한 정보로 채워지면 urb의 완료 콜백이 자신의 콜백 함수를 호출하도록 지시해야 합니다. 이 함수는 urb가 USB 하위 시스템에 의해 완료될 때 호출됩니다. 콜백 함수는 인터럽트 컨텍스트에서 호출되므로 그 시간에 너무 많은 처리를 하지 않도록 주의해야 합니다. usb_submit_urb() 호출은 urb->interval을 요청된 간격 값보다 작거나 같은 구현된 간격 값으로 수정합니다.

An URB is submitted by using the function usb_submit_urb():  

int usb_submit_urb(struct urb *urb, int mem_flags);  

GFP_ATOMIC과 같은 매개 변수 mem_flags는 메모리가 부족할 때 하위 수준이 차단될 수 있는지 여부와 같은 메모리 할당을 제어합니다. 상태 0(요청 대기 중) 또는 일반적으로 다음으로 인해 발생하는 일부 오류 코드와 함께 즉시 반환됩니다.
• Out of memory (-ENOMEM).  

• Unplugged device (-ENODEV).  

• Stalled endpoint (-EPIPE).  

• Too many queued ISO transfers (-EAGAIN).  

• Too many requested ISO frames (-EFBIG).  

• Invalid INT interval (-EINVAL).  

• More than one packet for INT (-EINVAL). 


제출 후 urb->status는 -EINPROGRESS입니다. 그러나 완료 콜백을 제외하고 해당 값을 보면 안 됩니다.
제출했지만 아직 드라이버 파트너에게 반환되지 않은 URB를 취소하는 방법에는 두 가지가 있습니다. 비동기 취소의 경우 usb_unlink_urb()를 호출합니다.
int usb_unlink_urb(struct urb *urb); 

usb_unlink_urb() 함수는 내부 목록에서 urb를 제거하고 할당된 모든 HW 설명자를 해제합니다. 연결 해제를 반영하도록 상태가 변경됩니다. URB는 일반적으로 usb_unlink_urb()가 반환될 때 완료되지 않습니다. 완료 핸들러가 호출될 때까지 기다려야 합니다.
To cancel an URB synchronously, call usb_kill_urb(): 

void usb_kill_urb(struct urb *urb);

usb_kill_urb() 함수는 usb_unlink_urb()가 수행하는 모든 작업을 수행하고 추가로 URB가 반환되고 완료 처리기가 완료될 때까지 기다립니다.
완료 처리기는 다음 유형입니다.
typedef void (*usb_complete_t) (struct urb *);
완료 처리기에서 urb->status를 살펴보고 USB 오류를 감지해야 합니다. context 매개변수가 URB에 포함되어 있으므로 완료 핸들러에 정보를 전달할 수 있습니다.