USB 서브시스템

USB 서브시스템을 프로토콜 계층, 컨트롤러 드라이버, 사용자 공간(User Space) 인터페이스까지 통합 관점으로 심층 분석합니다. USB Core와 URB 흐름, EHCI/XHCI host controller 동작, enumeration과 descriptor 파싱, class driver 작성 패턴, Gadget/UDC 기반 디바이스 에뮬레이션, Type-C/PD 및 USB4/Thunderbolt 연동, autosuspend/runtime PM 정책, usbmon·tracepoint·wireshark를 활용한 패킷(Packet) 디버깅(Debugging)까지 실전 제품 개발과 장애 분석에 필요한 내용을 폭넓게 다룹니다.

전제 조건: 디바이스 드라이버인터럽트(Interrupt) 문서를 먼저 읽으세요. 버스(Bus)/열거/프로브(Probe) 경로는 초기화 순서와 자원 등록 규칙이 핵심이므로, 장치 발견부터 바인딩까지 흐름을 먼저 고정해야 합니다.
일상 비유: 이 주제는 터미널 입출고 게이트 운영과 비슷합니다. 차량(디바이스)이 들어오면 게이트 규칙(버스 규약)에 맞춰 배정하고 점검하듯이, 드라이버도 바인딩 규약을 정확히 따라야 합니다.

핵심 요약

  • USB Enumeration — 장치 연결 시 허브가 포트 변화를 감지하고, 커널이 장치 디스크립터를 읽어 주소를 할당하고 드라이버를 바인딩하는 전체 과정입니다.
  • Transfer Types — Control(설정/상태), Bulk(대용량 데이터), Interrupt(주기적 소량), Isochronous(실시간 스트리밍) 네 가지 전송 타입이 대역폭과 지연 특성이 다릅니다.
  • URB (USB Request Block) — USB I/O의 기본 단위로, 드라이버가 usb_submit_urb()로 제출하고 완료 콜백에서 결과를 수신하는 비동기 요청 구조체입니다.
  • Host Controller (xHCI/EHCI) — USB 호스트 컨트롤러 하드웨어를 추상화하는 HCD(Host Controller Driver)로, xHCI는 USB 3.x를 지원하며 EHCI는 USB 2.0 전용입니다.
  • usb_driver / usb_deviceusb_register()로 등록하며, id_table의 Vendor/Product ID 매칭으로 probe()가 호출되는 USB 디바이스 모델입니다.
  • USB Class Drivers — HID(키보드/마우스), Mass Storage(USB 메모리), CDC-ACM(시리얼) 등 USB 클래스 규격별 공통 드라이버가 상위 계층을 구성합니다.
  • USB Gadget — 리눅스 장치가 USB 디바이스(Device) 역할을 할 때 사용하는 프레임워크로, ConfigFS 기반으로 기능(Function)을 동적 구성합니다.
  • OTG (On-The-Go) — 하나의 포트가 호스트와 디바이스 역할을 동적으로 전환할 수 있는 프로토콜로, ID 핀 상태에 따라 역할이 결정됩니다.

단계별 이해

  1. USB 열거(Enumeration) 과정 파악 — 장치 연결 → 포트 리셋 → 디스크립터 읽기 → 주소 할당 → 설정 선택 → 드라이버 바인딩 순서를 이해합니다.

    lsusb -v로 장치 디스크립터, 설정 디스크립터, 인터페이스 디스크립터 계층을 확인하고, usbmon으로 실제 열거 패킷을 캡처합니다.

  2. URB 기반 I/O 흐름 추적 — 드라이버가 URB를 할당하고 제출하면 HCD가 하드웨어에 스케줄링하고, 완료 시 콜백이 호출되는 비동기 흐름을 따라갑니다.

    usb_alloc_urb()usb_fill_bulk_urb()usb_submit_urb() → 완료 콜백 패턴이 USB 드라이버의 기본 I/O 구조입니다.

  3. 전송 타입별 특성과 엔드포인트 이해 — Control/Bulk/Interrupt/Isochronous 각 타입의 대역폭 보장, 재전송 정책, 지연 특성 차이를 파악합니다.

    엔드포인트 디스크립터의 bmAttributeswMaxPacketSize가 전송 타입과 최대 패킷 크기를 결정합니다.

  4. Host Controller Driver 구조 파악 — xHCI의 링 버퍼(Command/Transfer/Event Ring) 기반 스케줄링 구조를 이해합니다.

    /sys/bus/usb/devices/에서 USB 장치 트리를 확인하고, /sys/kernel/debug/usb/에서 HCD 상태를 점검합니다.

  5. USB Gadget과 ConfigFS 활용 — 임베디드 장치에서 리눅스를 USB 디바이스로 동작시키는 gadget 프레임워크의 ConfigFS 기반 구성을 실습합니다.

    /sys/kernel/config/usb_gadget/에서 기능(Function)을 추가하고 UDC(USB Device Controller)에 바인딩하는 절차를 확인합니다.

관련 표준: USB 2.0 Specification, USB 3.2 Specification, USB4 Specification, USB Type-C Specification, USB Power Delivery Specification — Linux USB 서브시스템이 구현하는 버스 프로토콜 규격입니다.

USB 개요

USB (Universal Serial Bus)는 1996년 Intel, Compaq, Microsoft 등이 공동으로 제안한 범용 직렬 버스 규격입니다. 키보드, 마우스부터 외장 스토리지, 네트워크 어댑터, 비디오 캡처 장치까지 거의 모든 주변기기의 사실상 표준 인터페이스로 자리 잡았습니다. Linux 커널은 USB 서브시스템을 통해 호스트 컨트롤러 관리, 디바이스 열거, 드라이버 바인딩, 전원 관리(Power Management)를 통합적으로 처리합니다.

USB Device Descriptor / Endpoint HCD (xHCI/EHCI) URB 스케줄링 USB Core / Driver Enumeration + Binding

USB 버전 발전

규격연도최대 속도인코딩커넥터
USB 1.019961.5 Mbps (Low Speed)NRZIType-A/B
USB 1.1199812 Mbps (Full Speed)NRZIType-A/B
USB 2.02000480 Mbps (High Speed)NRZIType-A/B, Mini, Micro
USB 3.020085 Gbps (SuperSpeed)8b/10bType-A (청색), Type-B SS, Micro-B SS
USB 3.1201310 Gbps (SuperSpeed+)128b/132bType-C
USB 3.2201720 Gbps (2x2 레인)128b/132bType-C 전용
USB4201940 Gbps (Gen 3x2)PAM3 (64b/66b)Type-C 전용
USB4 v2.0202280 Gbps (Gen 4)PAM3Type-C 전용
USB4와 Thunderbolt: USB4는 Thunderbolt 3 프로토콜을 기반으로 하며, PCIe 터널(Tunnel)링과 DisplayPort Alt Mode를 지원합니다. Linux 커널의 Thunderbolt 드라이버(drivers/thunderbolt/)가 USB4 호스트 컨트롤러도 함께 관리합니다.

프로토콜 계층 구조

USB 통신은 다음과 같은 계층으로 구성됩니다:

계층역할주요 요소
Client Software클래스/벤더 드라이버, 유저스페이스 앱usb_driver, libusb
USB System SoftwareUSB Core, 디바이스 열거, 대역폭(Bandwidth) 관리usb_device, usb_bus
USB Host Controller하드웨어 트랜잭션(Transaction) 스케줄링, 데이터 전송xHCI, EHCI, OHCI, UHCI
USB Bus Interface전기/물리 시그널(Signal)링, 패킷 인코딩차동 시그널링, NRZI/8b10b

USB 프로토콜 기초

디스크립터 계층

USB 디바이스는 자신의 기능을 디스크립터(Descriptor) 계층 구조로 기술합니다. 호스트는 열거(Enumeration) 과정에서 이 디스크립터를 읽어 적절한 드라이버를 바인딩합니다:

Device Descriptor (1개) Configuration Descriptor (1개 이상) Interface Descriptor (1개 이상) Endpoint (0개 이상) Class-Specific (선택) Interface Association (복합 디바이스) String Descriptor (선택) 포함 포함 연관 포함 확장 참조
디스크립터bDescriptorType핵심 필드설명
Device0x01idVendor, idProduct, bDeviceClass디바이스 전체 정보, VID/PID로 드라이버 매칭
Configuration0x02bNumInterfaces, bMaxPower전원 특성, 인터페이스 구성
Interface0x04bInterfaceClass/SubClass/Protocol기능 단위, 클래스 드라이버 매칭 기준
Endpoint0x05bEndpointAddress, bmAttributes, wMaxPacketSize데이터 파이프 정의, 전송 타입/방향/크기
/* 커널 내부: USB Device Descriptor 구조체 */
/* include/uapi/linux/usb/ch9.h */
struct usb_device_descriptor {
    __u8  bLength;             /* 18 */
    __u8  bDescriptorType;     /* USB_DT_DEVICE (0x01) */
    __le16 bcdUSB;             /* USB 규격 버전 (BCD: 0x0200 = USB 2.0) */
    __u8  bDeviceClass;        /* 디바이스 클래스 (0x00이면 인터페이스 레벨) */
    __u8  bDeviceSubClass;
    __u8  bDeviceProtocol;
    __u8  bMaxPacketSize0;     /* EP0 최대 패킷 크기 (8/16/32/64) */
    __le16 idVendor;           /* Vendor ID */
    __le16 idProduct;          /* Product ID */
    __le16 bcdDevice;          /* 디바이스 릴리즈 번호 */
    __u8  iManufacturer;       /* 제조사 문자열 인덱스 */
    __u8  iProduct;            /* 제품명 문자열 인덱스 */
    __u8  iSerialNumber;       /* 시리얼 번호 문자열 인덱스 */
    __u8  bNumConfigurations;  /* Configuration 수 */
} __attribute__ ((packed));
코드 설명

include/uapi/linux/usb/ch9.h에 정의된 usb_device_descriptor는 USB 디바이스의 최상위 디스크립터로, 호스트가 열거(Enumeration) 과정에서 가장 먼저 읽는 18바이트 구조체입니다.

  • bcdUSB디바이스가 준수하는 USB 규격 버전을 BCD(Binary Coded Decimal)로 나타냅니다. 예를 들어 0x0200은 USB 2.0입니다.
  • bDeviceClass디바이스 전체의 클래스 코드입니다. 0x00이면 인터페이스 레벨에서 클래스를 지정하며, 복합(Composite) 디바이스에서 흔히 사용됩니다.
  • bMaxPacketSize0Endpoint 0(Control)의 최대 패킷 크기입니다. 속도별로 8(Low Speed), 64(Full/High Speed) 등 고정 값이 사용됩니다.
  • idVendor / idProductUSB-IF가 할당하는 벤더 ID와 제품 ID로, 드라이버 매칭의 기본 키입니다. usb_device_id 테이블에서 이 값으로 바인딩 대상을 결정합니다.
  • bNumConfigurations디바이스가 지원하는 Configuration 수입니다. 대부분의 디바이스는 1개만 가지지만, 전원 모드에 따라 여러 Configuration을 제공하는 경우도 있습니다.
  • __attribute__((packed))구조체 패딩을 방지하여 USB 와이어 포맷과 메모리 레이아웃이 정확히 일치하도록 합니다.

전송 타입

USB는 4가지 전송 타입을 정의하며, 각각 다른 특성과 용도를 가집니다:

전송 타입특성대역폭 보장오류 재전송(Retransmission)용도
Control양방향, 셋업+데이터+상태 단계예약됨 (10~20%)디바이스 설정, 디스크립터 읽기, 벤더 요청
Bulk대용량, 잔여 대역폭 사용없음 (잔여 사용)Mass Storage, 프린터, 네트워크 데이터
Interrupt소량, 폴링(Polling) 주기 보장예약됨키보드, 마우스, 조이스틱, HID
Isochronous실시간(Real-time), 일정 대역폭예약됨없음오디오, 비디오, 웹캠
Endpoint 방향: Endpoint 주소의 비트 7이 방향을 나타냅니다. 0x81은 IN (디바이스 → 호스트) Endpoint 1, 0x02는 OUT (호스트 → 디바이스) Endpoint 2입니다. Endpoint 0(EP0)은 항상 양방향 Control 전송에 사용됩니다.

열거 (Enumeration) 과정

USB 디바이스가 연결되면 호스트는 다음 순서로 디바이스를 인식합니다:

  1. 연결 감지 — Hub가 포트 상태 변경을 인터럽트로 호스트에 통보
  2. 포트 리셋 — 호스트가 해당 포트에 USB Reset 시그널 전송 (SE0, 10~50ms)
  3. 속도 감지 — D+/D- 풀업 저항 위치로 Low/Full/High Speed 결정
  4. 기본 주소 할당 — 디바이스는 주소 0으로 응답, 호스트가 SET_ADDRESS(1~127) 전송
  5. 디스크립터 읽기 — GET_DESCRIPTOR로 Device, Configuration, Interface, Endpoint 정보 수집
  6. Configuration 선택 — SET_CONFIGURATION으로 활성 Configuration 설정
  7. 드라이버 바인딩 — 커널이 VID/PID 또는 클래스 코드 기반으로 적합한 드라이버를 probe

USB 디바이스 열거 상세 흐름

USB 디바이스가 물리적으로 연결되면 커널은 Hub 드라이버를 기점으로 복잡한 열거(Enumeration) 과정을 수행합니다. 이 과정은 전기적 감지, 속도 협상, 주소 할당, 디스크립터 수집, Configuration 선택, 드라이버 바인딩까지 여러 단계로 구성됩니다.

USB 디바이스 열거 상세 흐름 Phase 1: 물리 감지 1. D+/D- 전압 변화 감지 2. Hub 인터럽트 URB 완료 3. hub_irq() → kick_hub_wq() 4. 100ms debounce 대기 5. PORT_CONNECTION 비트 확인 Phase 2: 리셋과 속도 감지 1. hub_port_init() 호출 2. 포트 리셋 (SE0, 10~50ms) 3. D+/D- 풀업으로 속도 판별 4. USB 3.x: LTSSM → Polling 상태 5. usb_device 구조체 할당 Phase 3: 주소와 디스크립터 1. 주소 0에서 첫 8B 디스크립터 읽기 2. bMaxPacketSize0 → EP0 크기 확정 3. SET_ADDRESS(1~127) 전송 4. 전체 Device Descriptor 읽기 (18B) 5. xHCI: Enable Slot → Address Device Phase 4: Configuration 파싱과 선택 1. GET_DESCRIPTOR(Configuration) → 모든 Config 읽기 2. usb_parse_configuration(): IF/EP/Class 디스크립터 파싱 3. IAD(Interface Association) 처리 — 복합 디바이스 4. usb_choose_configuration(): 최적 Config 자동 선택 5. SET_CONFIGURATION 전송 → 디바이스 활성화 Phase 5: 드라이버 바인딩 1. device_add() → 디바이스 모델 등록 2. 각 usb_interface에 대해 bus match 실행 3. usb_device_id 테이블 매칭 (VID/PID/Class) 4. probe() 콜백 호출 → 드라이버 초기화 5. sysfs에 디바이스/인터페이스 노드 생성 열거 단계별 소요 시간 (일반적 범위) 연결 감지 + debounce: ~100ms | 포트 리셋: 10~50ms | SET_ADDRESS: <1ms 디스크립터 수집: 5~50ms | Configuration: <5ms | 드라이버 probe: 드라이버 의존적 총 열거 시간: 일반적으로 200~500ms (USB 2.0), USB 3.x는 LTSSM 협상으로 약간 더 소요 실패 시 재시도: hub_port_init()이 최대 2회 리셋 재시도, 실패 시 disabled 상태 xHCI 특이점: Slot 할당 → Address Device (BSR=1) → EP0 크기 확인 → Address Device (BSR=0)

USB 3.x 열거의 차이점

USB 3.x 디바이스는 USB 2.0과 열거 흐름이 유사하지만 몇 가지 중요한 차이가 있습니다:

항목USB 2.0USB 3.x
속도 감지D+/D- 풀업 저항LTSSM(Link Training and Status State Machine)
리셋 방식SE0 시그널 (10~50ms)Warm/Hot Reset + LFPS 핸드셰이크
EP0 크기8/16/32/64 (디스크립터에서 확인)항상 512 바이트 (고정)
주소 할당SET_ADDRESS 제어 전송xHCI Address Device 명령
BOS Descriptor없음 (선택적)필수 — USB 3.x 성능/SS 디스크립터 포함
링크 전력Suspend/Resume만U0/U1/U2/U3 다단계 LPM
/* USB 3.x BOS(Binary device Object Store) Descriptor */
/* GET_DESCRIPTOR(BOS)로 읽으며, 디바이스의 확장 성능 정보 포함 */
/*
 * BOS Descriptor 하위 구조:
 *   USB 2.0 Extension  — LPM(L1) 지원 여부
 *   SuperSpeed Cap      — 지원 속도, U1/U2 탈출 지연 시간
 *   SuperSpeedPlus Cap  — Gen 2x2 등 확장 속도 지원
 *   Container ID        — 디바이스 고유 식별자 (UUID)
 *   Platform Cap        — WebUSB, MS OS 2.0 등 플랫폼 확장
 *
 * 커널 처리: usb_get_bos_descriptor() → usb_device.bos에 저장
 * U1/U2 지연 값으로 LPM 정책 결정
 */

Linux USB Core

Linux USB Core(drivers/usb/core/)는 호스트 컨트롤러와 디바이스 드라이버 사이의 중간 계층으로, 디바이스 열거, URB 관리, 전원 관리, 드라이버 매칭을 담당합니다.

핵심 자료구조

구조체(Struct)헤더역할
struct usb_bus<linux/usb.h>USB 버스 인스턴스, HCD와 1:1 대응
struct usb_device<linux/usb.h>USB 디바이스 인스턴스 (디스크립터, 상태, 파이프 정보)
struct usb_interface<linux/usb.h>인터페이스 단위 — 드라이버가 바인딩하는 대상
struct usb_host_config<linux/usb.h>Configuration Descriptor 파싱 결과
struct usb_host_interface<linux/usb.h>Interface Descriptor + Endpoint 배열
struct usb_host_endpoint<linux/usb.h>Endpoint Descriptor + URB 큐
/* struct usb_device 주요 필드 (simplified) */
/* include/linux/usb.h */
struct usb_device {
    int                     devnum;          /* 버스 내 디바이스 주소 (1~127) */
    char                    devpath[16];     /* sysfs 경로 문자열 */
    enum usb_device_state   state;           /* 연결 상태 */
    enum usb_device_speed   speed;           /* Low/Full/High/Super/Super+ */

    struct usb_device_descriptor descriptor;  /* Device Descriptor 사본 */
    struct usb_host_config  *config;         /* 모든 Configuration 배열 */
    struct usb_host_config  *actconfig;      /* 현재 활성 Configuration */

    struct usb_host_endpoint ep0;            /* Endpoint 0 (Control) */
    struct usb_host_endpoint *ep_in[16];     /* IN Endpoint 배열 */
    struct usb_host_endpoint *ep_out[16];    /* OUT Endpoint 배열 */

    struct usb_device       *parent;         /* 부모 Hub (Root Hub는 NULL) */
    struct usb_bus          *bus;            /* 소속 버스 */
    struct device           dev;             /* 범용 디바이스 모델 */

    int                     maxchild;        /* Hub인 경우 하위 포트 수 */
    unsigned                can_submit:1;    /* URB 제출 가능 여부 */
    /* ... */
};
/* struct usb_interface — 드라이버가 bind하는 단위 */
struct usb_interface {
    struct usb_host_interface *altsetting;    /* Alternate Setting 배열 */
    struct usb_host_interface *cur_altsetting; /* 현재 활성 설정 */
    unsigned                num_altsetting;  /* Alternate Setting 개수 */

    struct usb_interface_cache *intf_cache;
    struct device           dev;             /* 디바이스 모델 (드라이버 바인딩 대상) */
    int                     minor;           /* USB minor 번호 (-1 = 미사용) */
    /* ... */
};
코드 설명

include/linux/usb.h에 정의된 두 핵심 자료구조입니다. usb_device는 물리적 USB 디바이스 전체를, usb_interface는 드라이버가 실제로 바인딩하는 논리 단위를 나타냅니다.

  • devnum버스 내에서 고유한 디바이스 주소(1~127)입니다. SET_ADDRESS 요청으로 열거 시 할당됩니다.
  • speedenum usb_device_speed로 Low/Full/High/Super/Super+ 속도를 구분합니다. HCD가 포트 리셋 후 결정합니다.
  • actconfig현재 활성화된 Configuration을 가리킵니다. usb_set_configuration() 호출 시 설정됩니다.
  • ep0, ep_in[], ep_out[]Endpoint 0는 모든 디바이스에 존재하는 양방향 Control 엔드포인트이며, ep_in/ep_out 배열(각 16개)이 방향별 엔드포인트를 관리합니다.
  • parent / busUSB 디바이스 트리 구조를 형성합니다. Root Hub는 parent가 NULL이고, bus는 소속 호스트 컨트롤러에 1:1 대응합니다.
  • usb_interface.altsetting하나의 인터페이스가 여러 Alternate Setting을 가질 수 있으며, usb_set_interface()로 전환합니다. 대역폭 요구가 다른 모드(예: 비디오 해상도)를 지원하는 데 사용됩니다.
  • usb_interface.devLinux 디바이스 모델의 struct device를 내장하여, usb_driverprobe()/disconnect()가 이 인터페이스 단위로 호출됩니다.
Interface vs Device: USB 드라이버는 usb_device 전체가 아니라 usb_interface에 바인딩됩니다. 하나의 USB 디바이스가 여러 인터페이스를 가질 수 있고, 각 인터페이스에 서로 다른 드라이버가 바인딩될 수 있습니다 (예: CDC-ACM은 Control + Data 두 개의 인터페이스를 가집니다).

USB 스택 내부 구조

USB Core의 자료구조는 계층적으로 연결됩니다. usb_bus는 호스트 컨트롤러에 1:1 대응하고, 그 아래에 usb_device가 트리 형태로 구성됩니다. 각 usb_device는 하나 이상의 usb_interface를 가지며, 인터페이스에는 데이터 전송을 위한 usb_host_endpoint가 연결됩니다.

USB Core 자료구조 계층 struct usb_bus HCD 1:1 대응, 버스 번호, Root Hub 포인터 struct usb_device (Root Hub) devnum=1, parent=NULL, speed, state struct usb_device (Dev N) descriptor, actconfig, ep0, ep_in[], ep_out[] struct usb_device (Dev M) 같은 버스의 다른 디바이스 struct usb_interface [0] 드라이버 바인딩 대상, cur_altsetting struct usb_interface [1] 복합 디바이스의 두 번째 IF usb_host_endpoint EP 0x81 (Bulk IN) usb_host_endpoint EP 0x02 (Bulk OUT) 범례 usb_bus (HCD) usb_device (물리 장치) usb_interface (바인딩 단위) usb_host_endpoint (데이터 파이프)

디바이스 열거 내부 흐름

디바이스 연결 시 USB Core 내부에서 수행되는 열거(Enumeration) 과정의 핵심 함수 호출 순서입니다. Hub 드라이버의 hub_event()가 포트 변경 감지를 시작으로 전체 열거를 주도합니다:

/* drivers/usb/core/hub.c — 디바이스 열거 내부 흐름 */

/* 1. Hub 인터럽트 URB가 포트 상태 변경 감지 */
hub_irq()
  → kick_hub_wq()            /* Hub 이벤트 워크큐 스케줄 */

/* 2. 워크큐에서 hub_event() 실행 */
hub_event()
  → port_event()             /* 각 포트의 상태 변경 처리 */hub_port_connect_change()
      → hub_port_init()       /* 포트 리셋 + 속도 감지 */hub_set_address()    /* SET_ADDRESS(1~127) */usb_get_device_descriptor() /* 64바이트 Device Descriptor */usb_new_device()       /* 디바이스 등록 시작 */

/* 3. usb_new_device() 상세 */
usb_new_device(struct usb_device *udev)
{
    usb_enumerate_device(udev);
      → usb_get_configuration()    /* 모든 Configuration Descriptor 읽기 */usb_parse_configuration() /* Interface/Endpoint 파싱 */usb_get_string()           /* 제조사/제품명 문자열 */

    usb_choose_configuration(udev); /* 최적 Configuration 자동 선택 */
    usb_set_configuration(udev, config_num);

    device_add(&udev->dev);         /* 디바이스 모델 등록 → probe 트리거 */
}

디스크립터 파싱과 Configuration 선택

usb_parse_configuration()은 호스트가 GET_DESCRIPTOR로 수신한 원시 바이트 스트림을 파싱하여 커널 자료구조로 변환합니다. Configuration Descriptor를 기준으로 하위 Interface/Endpoint를 순차적으로 파싱합니다:

/* drivers/usb/core/config.c — Configuration 파싱 핵심 로직 */

/* usb_parse_configuration()이 처리하는 디스크립터 순서:
 *   Configuration Descriptor (bDescriptorType=0x02)
 *     └─ Interface Association Descriptor (IAD, 0x0B) — 복합 디바이스용
 *     └─ Interface Descriptor (0x04)
 *        └─ Class-Specific Descriptor (클래스별)
 *        └─ Endpoint Descriptor (0x05)
 *           └─ SS Endpoint Companion (0x30) — USB 3.x
 *           └─ SSP Isoc Endpoint Companion (0x31) — USB 3.1+
 */

/* Configuration 자동 선택 기준 (usb_choose_configuration) */
/*
 * 1. bNumInterfaces가 가장 많은 Configuration 우선
 * 2. 첫 Interface의 bInterfaceClass가 벤더 전용(0xFF)이 아닌 것 우선
 * 3. 위 조건이 같으면 첫 번째 Configuration 선택
 * 4. USB 허브는 항상 Configuration 1 선택
 *
 * 드라이버가 직접 선택하려면:
 *   usb_driver_set_configuration(udev, config_value);
 */
Alternate Setting: 하나의 인터페이스가 여러 Alternate Setting을 가질 수 있습니다. 예를 들어 USB 오디오 장치는 Alternate 0에서는 대역폭 0(유휴), Alternate 1에서 오디오 스트리밍용 Isochronous Endpoint를 활성화합니다. usb_set_interface(udev, ifnum, alt)로 전환합니다.

USB 드라이버 모델

드라이버 골격

#include <linux/module.h>
#include <linux/usb.h>

#define MY_VENDOR_ID   0x1234
#define MY_PRODUCT_ID  0x5678

struct my_usb_dev {
    struct usb_device    *udev;       /* USB 디바이스 */
    struct usb_interface  *intf;       /* 바인딩된 인터페이스 */
    unsigned char        *bulk_in_buf; /* Bulk IN 수신 버퍼 */
    size_t               bulk_in_size;
    __u8                 bulk_in_ep;  /* Bulk IN endpoint 주소 */
    __u8                 bulk_out_ep; /* Bulk OUT endpoint 주소 */
};

static int my_usb_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(intf);
    struct usb_host_interface *iface_desc;
    struct usb_endpoint_descriptor *ep;
    struct my_usb_dev *dev;
    int i;

    iface_desc = intf->cur_altsetting;

    /* private 데이터 할당 */
    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;

    dev->udev = usb_get_dev(udev);
    dev->intf = intf;

    /* Endpoint 탐색 */
    for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
        ep = &iface_desc->endpoint[i].desc;

        if (usb_endpoint_is_bulk_in(ep)) {
            dev->bulk_in_size = usb_endpoint_maxp(ep);
            dev->bulk_in_ep = ep->bEndpointAddress;
            dev->bulk_in_buf = kmalloc(dev->bulk_in_size,
                                       GFP_KERNEL);
        }
        if (usb_endpoint_is_bulk_out(ep))
            dev->bulk_out_ep = ep->bEndpointAddress;
    }

    usb_set_intfdata(intf, dev);

    dev_info(&intf->dev, "USB device probed: %04x:%04x\\n",
             le16_to_cpu(udev->descriptor.idVendor),
             le16_to_cpu(udev->descriptor.idProduct));
    return 0;
}

static void my_usb_disconnect(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    usb_set_intfdata(intf, NULL);
    usb_put_dev(dev->udev);
    kfree(dev->bulk_in_buf);
    kfree(dev);

    dev_info(&intf->dev, "USB device disconnected\\n");
}

/* USB Device ID 테이블 — 드라이버가 지원하는 디바이스 목록 */
static const struct usb_device_id my_usb_ids[] = {
    { USB_DEVICE(MY_VENDOR_ID, MY_PRODUCT_ID) },
    { }  /* 종료 마커 */
};
MODULE_DEVICE_TABLE(usb, my_usb_ids);

static struct usb_driver my_usb_driver = {
    .name       = "my_usb",
    .id_table   = my_usb_ids,
    .probe      = my_usb_probe,
    .disconnect = my_usb_disconnect,
};
module_usb_driver(my_usb_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Example USB driver");
코드 설명

drivers/usb/core/driver.c 기반의 USB 드라이버 등록/해제와 probe/disconnect 콜백 전체 패턴을 보여주는 최소 예제입니다.

  • struct my_usb_dev드라이버 전용 컨텍스트 구조체입니다. usb_device 포인터, 바인딩된 인터페이스, Bulk 엔드포인트 정보와 수신 버퍼를 보관합니다.
  • my_usb_probe()USB Core가 ID 테이블 매칭에 성공하면 호출합니다. interface_to_usbdev()로 상위 usb_device를 얻고, cur_altsetting의 엔드포인트 디스크립터를 순회하여 Bulk IN/OUT 주소를 저장합니다.
  • usb_get_dev() / usb_put_dev()usb_device의 참조 카운트를 증감합니다. probe()에서 증가, disconnect()에서 감소하여 디바이스 해제 시점을 안전하게 관리합니다.
  • usb_set_intfdata()인터페이스에 드라이버 전용 데이터를 연결합니다. 이후 usb_get_intfdata()로 콜백에서 꺼내 씁니다.
  • usb_device_id / USB_DEVICE()드라이버가 지원하는 디바이스 목록입니다. MODULE_DEVICE_TABLE()은 모듈 로딩 시스템(modalias)이 자동 바인딩할 수 있도록 별도 섹션에 ID를 기록합니다.
  • module_usb_driver()usb_register()/usb_deregister()를 래핑하는 편의 매크로로, module_init/module_exit 보일러플레이트를 자동 생성합니다.

USB ID 매칭 매크로(Macro)

매크로매칭 기준
USB_DEVICE(vendor, product)Vendor + Product ID
USB_DEVICE_VER(vendor, product, lo, hi)+ bcdDevice 범위
USB_DEVICE_INTERFACE_CLASS(vend, prod, cl)+ Interface Class
USB_DEVICE_INTERFACE_PROTOCOL(vend, prod, pr)+ Interface Protocol
USB_INTERFACE_INFO(cl, sc, pr)Interface Class/SubClass/Protocol
USB_DEVICE_INFO(cl, sc, pr)Device Class/SubClass/Protocol

드라이버 라이프사이클

USB 드라이버 라이프사이클 디바이스 연결 hub_event()/usb_new_device() 디스크립터 파싱 device_add() bus_probe_device() usb_device_match() usb_probe_interface() driver->probe() 정상 동작 분리 시: usb_disconnect()/device_del()

드라이버 매칭/바인딩 상세

USB Core의 usb_device_match()는 등록된 usb_driverid_table과 디바이스의 디스크립터 정보를 비교하여 적합한 드라이버를 찾습니다. 매칭이 성공하면 usb_probe_interface()를 거쳐 드라이버의 probe()가 호출됩니다.

USB 드라이버 매칭/바인딩 흐름 device_add(&intf->dev) bus_probe_device() usb_device_match() id_table 순회: VID/PID, Class/SubClass/Protocol 비교 Match Flags USB_DEVICE_ID_MATCH_VENDOR USB_DEVICE_ID_MATCH_PRODUCT USB_DEVICE_ID_MATCH_INT_CLASS USB_DEVICE_ID_MATCH_INT_PROTOCOL usb_probe_interface() driver->probe(intf, id) 분리 시 (Disconnect) 1. usb_unbind_interface() 2. driver->disconnect(intf) 3. usb_disable_interface() 4. device_del(&intf->dev) 5. usb_release_interface() 순서 중요: URB 취소 후 리소스 해제 수행 리셋 콜백 pre_reset(intf) post_reset(intf) 디바이스 리셋 전후 호출

매칭 플래그(match_flags)usb_device_id 구조체의 어떤 필드를 비교할지 결정합니다. USB_DEVICE() 매크로는 Vendor/Product ID만 비교하고, USB_INTERFACE_INFO()는 클래스/서브클래스/프로토콜을 비교합니다. 여러 플래그를 OR 조합하면 더 세밀한 매칭이 가능합니다.

분리(Disconnect) 처리 순서가 중요합니다. 드라이버의 disconnect() 콜백(Callback)이 호출되기 전에 usb_unbind_interface()가 인터페이스를 비활성화하며, disconnect() 내에서 반드시 진행 중인 URB를 usb_kill_urb()로 취소하고, 할당된 리소스를 해제해야 합니다. pre_reset()/post_reset() 콜백은 usb_reset_device() 호출 시 디바이스 리셋 전후에 드라이버 상태를 저장/복원할 기회를 제공합니다.

/* disconnect 및 pre_reset/post_reset 콜백 패턴 */

static void my_usb_disconnect(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    /* 1. 인터페이스 데이터 클리어 (재진입 방지) */
    usb_set_intfdata(intf, NULL);

    /* 2. 진행 중인 URB 모두 취소 (동기적으로 대기) */
    usb_kill_urb(dev->int_urb);
    usb_kill_urb(dev->bulk_urb);

    /* 3. 유저스페이스 인터페이스 해제 */
    usb_deregister_dev(intf, &my_class);

    /* 4. 리소스 해제 */
    usb_free_urb(dev->int_urb);
    usb_put_dev(dev->udev);
    kfree(dev);
}

/* pre_reset: 디바이스 리셋 직전 호출 */
static int my_pre_reset(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);
    /* URB 중지, 상태 저장 */
    usb_kill_urb(dev->bulk_urb);
    return 0;
}

/* post_reset: 디바이스 리셋 완료 후 호출 */
static int my_post_reset(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);
    /* 엔드포인트 재확인, URB 재제출 */
    usb_submit_urb(dev->bulk_urb, GFP_NOIO);
    return 0;
}

URB (USB Request Block)

URB (USB Request Block)은 USB 드라이버가 데이터를 전송하기 위해 USB Core에 제출하는 요청 단위입니다. 네트워크의 sk_buff, 블록 I/O의 bio에 해당하는 USB 서브시스템의 핵심 자료구조입니다.

struct urb 주요 필드

/* include/linux/usb.h */
struct urb {
    struct list_head       urb_list;        /* HCD 내부 리스트 */
    struct usb_device      *dev;            /* 대상 디바이스 */
    unsigned int           pipe;            /* 파이프 (endpoint + 방향 + 타입) */
    int                    status;          /* 완료 상태 (0=성공) */
    unsigned int           transfer_flags;  /* URB 플래그 */
    void                   *transfer_buffer; /* 데이터 버퍼 (kmalloc) */
    dma_addr_t             transfer_dma;    /* DMA 주소 (선택) */
    u32                    transfer_buffer_length; /* 버퍼 크기 */
    u32                    actual_length;   /* 실제 전송된 바이트 수 */
    unsigned char          *setup_packet;   /* Control 전송용 SETUP 패킷 */
    int                    interval;        /* Interrupt/Isoc 폴링 간격 */
    int                    number_of_packets; /* Isoc 패킷 수 */
    struct usb_iso_packet_descriptor iso_frame_desc[]; /* Isoc 프레임 */
    usb_complete_t         complete;        /* 완료 콜백 함수 */
    void                   *context;        /* 콜백 컨텍스트 */
    /* ... */
};
코드 설명

include/linux/usb.h에 정의된 struct urb은 USB 데이터 전송의 핵심 요청 단위입니다. 네트워크의 sk_buff, 블록 I/O의 bio에 대응하는 USB 서브시스템의 I/O 기술자입니다.

  • pipe엔드포인트 번호, 방향(IN/OUT), 전송 타입(Control/Bulk/Interrupt/Isochronous)을 하나의 unsigned int로 인코딩합니다. usb_sndbulkpipe() 등의 매크로로 생성합니다.
  • status완료 콜백에서 전송 결과를 나타냅니다. 0이면 성공, -ENOENT/-ECONNRESET은 드라이버에 의한 정상 취소, -ESHUTDOWN은 디바이스 분리를 의미합니다.
  • transfer_buffer / transfer_dmaCPU 주소와 DMA 주소를 각각 보관합니다. URB_NO_TRANSFER_DMA_MAP 플래그 설정 시 HCD가 DMA 매핑을 건너뜁니다.
  • actual_length실제 전송된 바이트 수입니다. Short 패킷 수신 시 transfer_buffer_length보다 작을 수 있습니다.
  • setup_packetControl 전송 전용 8바이트 SETUP 데이터를 가리킵니다. Bulk/Interrupt/Isochronous 전송에서는 NULL입니다.
  • intervalInterrupt/Isochronous 전송의 폴링 간격입니다. Full Speed는 ms, High Speed 이상은 마이크로프레임(125us) 단위입니다.
  • complete / context전송 완료 시 인터럽트 컨텍스트에서 호출되는 콜백과 그 인자입니다. drivers/usb/core/urb.cusb_giveback_urb()가 이를 호출합니다.

URB 라이프사이클

단계함수설명
1usb_alloc_urb()URB 할당
2usb_fill_*_urb()전송 타입별 필드 초기화
3usb_submit_urb()USB Core/HCD 큐에 제출
4HCD 처리하드웨어 전송 수행
5complete()완료 콜백 실행 (인터럽트 컨텍스트)
6usb_free_urb()참조 카운트(Reference Count) 기반 해제

URB 초기화 헬퍼

/* Bulk 전송 URB 초기화 */
static void usb_fill_bulk_urb(
    struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,           /* usb_sndbulkpipe() / usb_rcvbulkpipe() */
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context);

/* Interrupt 전송 URB 초기화 */
static void usb_fill_int_urb(
    struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context,
    int interval);              /* 폴링 간격 (ms 또는 microframes) */

/* Control 전송 URB 초기화 */
static void usb_fill_control_urb(
    struct urb *urb,
    struct usb_device *dev,
    unsigned int pipe,
    unsigned char *setup_packet,  /* 8바이트 SETUP 데이터 */
    void *transfer_buffer,
    int buffer_length,
    usb_complete_t complete_fn,
    void *context);
코드 설명

include/linux/usb.h에 정의된 URB 초기화 헬퍼 함수들입니다. 전송 타입(Bulk/Interrupt/Control)별로 struct urb의 필드를 올바르게 채워주는 인라인 함수이며, Isochronous 전송은 별도로 수동 초기화해야 합니다.

  • usb_fill_bulk_urb()Bulk 전송용입니다. pipeusb_sndbulkpipe()(송신) 또는 usb_rcvbulkpipe()(수신)로 생성한 파이프를 전달합니다. 대용량 데이터(Mass Storage, 네트워크)에 사용됩니다.
  • usb_fill_int_urb()Interrupt 전송용입니다. 마지막 인자 interval이 폴링 주기를 지정합니다. HID(키보드/마우스) 등 소량 주기적 데이터에 사용됩니다.
  • usb_fill_control_urb()Control 전송용입니다. setup_packet 인자로 8바이트 SETUP 데이터(bmRequestType, bRequest, wValue, wIndex, wLength)를 전달합니다. 디바이스 설정 및 벤더 요청에 사용됩니다.
  • complete_fn / context세 함수 모두 완료 콜백과 콜백 컨텍스트를 받습니다. 콜백은 인터럽트 컨텍스트에서 실행되므로 sleep이 불가능하고, GFP_ATOMIC만 사용할 수 있습니다.

비동기 Bulk 전송 예제

static void my_bulk_complete(struct urb *urb)
{
    struct my_usb_dev *dev = urb->context;

    if (urb->status) {
        if (urb->status == -ENOENT ||
            urb->status == -ECONNRESET ||
            urb->status == -ESHUTDOWN) {
            /* URB 취소됨 — 정상적인 종료 */
            return;
        }
        dev_err(&dev->intf->dev,
                "bulk read failed: %d\\n", urb->status);
        return;
    }

    /* 수신 데이터 처리 */
    dev_info(&dev->intf->dev,
             "received %d bytes\\n", urb->actual_length);

    /* 연속 수신을 위해 URB 재제출 */
    usb_submit_urb(urb, GFP_ATOMIC);
}

static int my_start_bulk_read(struct my_usb_dev *dev)
{
    struct urb *urb;
    int ret;

    urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!urb)
        return -ENOMEM;

    usb_fill_bulk_urb(urb, dev->udev,
        usb_rcvbulkpipe(dev->udev, dev->bulk_in_ep),
        dev->bulk_in_buf,
        dev->bulk_in_size,
        my_bulk_complete,
        dev);

    ret = usb_submit_urb(urb, GFP_KERNEL);
    if (ret) {
        dev_err(&dev->intf->dev,
                "failed to submit URB: %d\\n", ret);
        usb_free_urb(urb);
    }
    return ret;
}
코드 설명

비동기 Bulk 수신의 전형적인 패턴입니다. drivers/usb/core/urb.cusb_submit_urb()로 URB를 HCD에 제출하고, 완료 콜백에서 데이터를 처리한 뒤 재제출하는 연속 수신 루프를 구성합니다.

  • my_bulk_complete()URB 완료 콜백입니다. 인터럽트 컨텍스트에서 호출되므로 sleep 불가이며, urb->context로 드라이버 데이터에 접근합니다.
  • -ENOENT / -ECONNRESET / -ESHUTDOWN세 에러 코드는 각각 usb_kill_urb(), usb_unlink_urb(), 디바이스 분리에 의한 정상적인 URB 취소를 나타냅니다. 이 경우 재제출 없이 즉시 반환해야 합니다.
  • usb_submit_urb(urb, GFP_ATOMIC)콜백 내에서 재제출 시 반드시 GFP_ATOMIC을 사용합니다. 이 패턴으로 연속 수신을 구현하며, 중단 시 재제출을 하지 않으면 자연스럽게 멈춥니다.
  • usb_alloc_urb(0, GFP_KERNEL)첫 번째 인자 0은 Isochronous 패킷 수입니다. Bulk 전송은 0을 전달합니다. 프로세스 컨텍스트이므로 GFP_KERNEL을 사용합니다.
  • usb_fill_bulk_urb()usb_rcvbulkpipe()로 수신 방향 파이프를 생성하고, 사전 할당된 버퍼와 완료 콜백을 설정합니다.
  • usb_free_urb()제출 실패 시 즉시 해제합니다. 제출 성공 후에는 완료 콜백이 호출된 뒤에만 해제해야 합니다.

동기 전송 래퍼

간단한 전송에는 URB를 직접 관리하지 않고 동기 래퍼를 사용할 수 있습니다:

/* 동기 Bulk 전송 */
int actual_len;
int ret = usb_bulk_msg(dev->udev,
    usb_rcvbulkpipe(dev->udev, dev->bulk_in_ep),
    dev->bulk_in_buf,
    dev->bulk_in_size,
    &actual_len,
    5000);  /* 타임아웃 (ms) */

/* 동기 Control 전송 */
ret = usb_control_msg(dev->udev,
    usb_sndctrlpipe(dev->udev, 0),
    0x09,                        /* bRequest: SET_CONFIGURATION */
    USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
    1,                           /* wValue */
    0,                           /* wIndex */
    NULL,                        /* data */
    0,                           /* size */
    5000);                       /* 타임아웃 (ms) */

/* 동기 Interrupt 전송 */
ret = usb_interrupt_msg(dev->udev,
    usb_rcvintpipe(dev->udev, dev->int_in_ep),
    dev->int_buf, dev->int_buf_size,
    &actual_len, 5000);
주의: usb_bulk_msg(), usb_control_msg() 같은 동기 API는 내부에서 wait_for_completion()을 호출하므로 인터럽트 컨텍스트나 URB 완료 콜백 내에서 사용하면 안 됩니다. 이런 경우에는 비동기 URB를 사용해야 합니다.

파이프(Pipe) 매크로

매크로용도
usb_sndctrlpipe(dev, ep)Control OUT 파이프
usb_rcvctrlpipe(dev, ep)Control IN 파이프
usb_sndbulkpipe(dev, ep)Bulk OUT 파이프
usb_rcvbulkpipe(dev, ep)Bulk IN 파이프
usb_sndintpipe(dev, ep)Interrupt OUT 파이프
usb_rcvintpipe(dev, ep)Interrupt IN 파이프
usb_sndisocpipe(dev, ep)Isochronous OUT 파이프
usb_rcvisocpipe(dev, ep)Isochronous IN 파이프

URB 완료 콜백과 오류 처리

URB의 완료 콜백(complete)은 USB 드라이버의 핵심 비동기 처리 메커니즘입니다. 콜백은 인터럽트 컨텍스트(하드웨어 IRQ 또는 softirq)에서 호출되므로, 수면(sleep) 불가능한 환경에서 실행됩니다. URB 상태 코드를 정확히 처리하는 것이 안정적인 USB 드라이버의 핵심입니다.

URB 상태 코드

상태 코드의미드라이버 동작
00성공데이터 처리 후 URB 재제출
-ENOENT-2usb_kill_urb()로 취소됨정리 중 — 재제출 금지
-ECONNRESET-104usb_unlink_urb()로 해제됨정리 중 — 재제출 금지
-ESHUTDOWN-108디바이스/HCD 제거됨모든 I/O 중단, 자원 해제
-EPIPE-32Endpoint Stall (HALT)usb_clear_halt() 호출 후 재시도
-EOVERFLOW-75수신 데이터가 버퍼(Buffer) 초과버퍼 크기 확인, 오류 보고
-ETIMEDOUT-110전송 타임아웃디바이스 리셋 검토
-EPROTO-71프로토콜 오류 (비트 스터핑 등)하드웨어 문제 — 재시도/리셋
-EILSEQ-84CRC 오류 (데이터 무결성(Integrity) 실패)케이블/커넥터 확인, 재시도
-EREMOTEIO-121Short packet (요청보다 적게 수신)URB_SHORT_NOT_OK 플래그 시 오류
-ENODEV-19디바이스 분리됨모든 I/O 중단, 자원 해제
/* URB 완료 콜백 견고한 구현 패턴 */
static void robust_urb_complete(struct urb *urb)
{
    struct my_usb_dev *dev = urb->context;
    int status = urb->status;

    switch (status) {
    case 0:
        /* 성공 — 데이터 처리 */
        process_data(dev, urb->transfer_buffer, urb->actual_length);
        break;
    case -ENOENT:      /* usb_kill_urb() */
    case -ECONNRESET:  /* usb_unlink_urb() */
    case -ESHUTDOWN:   /* HCD/디바이스 제거 */
        /* 정리 중 — 재제출하지 않음 */
        return;
    case -EPIPE:
        /* Endpoint Stall — 워크큐에서 clear_halt 처리 */
        schedule_work(&dev->stall_work);
        return;
    case -EOVERFLOW:
        dev_err(&dev->intf->dev, "buffer overflow\\n");
        return;
    default:
        /* 기타 오류 — 제한적 재시도 */
        if (++dev->error_count < 3) {
            dev_warn(&dev->intf->dev,
                     "URB error %d, retry %d\\n",
                     status, dev->error_count);
        } else {
            dev_err(&dev->intf->dev,
                    "URB error %d, giving up\\n", status);
            return;
        }
        break;
    }

    /* URB 재제출 (인터럽트 컨텍스트이므로 GFP_ATOMIC) */
    status = usb_submit_urb(urb, GFP_ATOMIC);
    if (status)
        dev_err(&dev->intf->dev,
                "resubmit URB failed: %d\\n", status);
}

URB 취소와 동기화

함수동작컨텍스트사용 시점
usb_kill_urb()URB 취소 + 콜백 완료 대기 (동기)프로세스 (sleep OK)disconnect(), remove()
usb_unlink_urb()URB 취소 요청 (비동기)어디서든 (atomic OK)콜백 내, 빠른 취소
usb_poison_urb()URB 취소 + 향후 재제출 영구 차단프로세스 (sleep OK)디바이스 분리 최종 단계
usb_kill_anchored_urbs()앵커된 모든 URB 일괄 취소프로세스 (sleep OK)대량 URB 정리
/* USB Anchor를 이용한 URB 일괄 관리 */
struct usb_anchor my_anchor;

/* 초기화 */
init_usb_anchor(&my_anchor);

/* URB 제출 시 앵커에 등록 */
usb_anchor_urb(urb, &my_anchor);
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret)
    usb_unanchor_urb(urb);

/* disconnect 시 모든 URB 일괄 취소 */
usb_kill_anchored_urbs(&my_anchor);

/* 또는 타임아웃 기반 대기 */
if (!usb_wait_anchor_empty_timeout(&my_anchor, 1000))
    usb_kill_anchored_urbs(&my_anchor);

Host Controller Driver (HCD)

HCD(Host Controller Driver)는 USB 호스트 컨트롤러 하드웨어를 직접 제어하는 최하위 계층 드라이버입니다. USB Core가 제출한 URB를 하드웨어 트랜잭션으로 변환하여 실행합니다.

호스트 컨트롤러 종류

HCD규격USB 속도특징커널 드라이버
UHCIIntelUSB 1.x (LS/FS)소프트웨어 스케줄링, CPU 부하 높음uhci-hcd
OHCICompaq/Microsoft/NSCUSB 1.x (LS/FS)하드웨어 스케줄링, 임베디드 주력ohci-hcd
EHCIIntelUSB 2.0 (HS)Companion Controller(UHCI/OHCI)와 쌍ehci-hcd
xHCIIntelUSB 1.x ~ 3.x모든 속도 통합, 스트림 지원xhci-hcd
xHCI 통합: xHCI(eXtensible Host Controller Interface)는 USB 1.x/2.0/3.x 전 속도를 단일 컨트롤러로 지원합니다. EHCI와 달리 Companion Controller가 필요 없으며, 현대 시스템의 표준 HCD입니다.

struct hc_driver

/* include/linux/usb/hcd.h */
struct hc_driver {
    const char  *description;
    const char  *product_desc;
    size_t      hcd_priv_size;   /* HCD private 데이터 크기 */

    /* HCD 생명주기 */
    int  (*reset)(struct usb_hcd *hcd);
    int  (*start)(struct usb_hcd *hcd);
    void (*stop)(struct usb_hcd *hcd);
    void (*shutdown)(struct usb_hcd *hcd);

    /* URB 관리 */
    int  (*urb_enqueue)(struct usb_hcd *hcd,
                        struct urb *urb, gfp_t mem_flags);
    int  (*urb_dequeue)(struct usb_hcd *hcd,
                        struct urb *urb, int status);

    /* Root Hub 조작 */
    int  (*hub_status_data)(struct usb_hcd *hcd,
                            char *buf);
    int  (*hub_control)(struct usb_hcd *hcd,
                        u16 typeReq, u16 wValue,
                        u16 wIndex, char *buf,
                        u16 wLength);

    /* Endpoint 관리 */
    void (*endpoint_reset)(struct usb_hcd *hcd,
                           struct usb_host_endpoint *ep);
    void (*endpoint_disable)(struct usb_hcd *hcd,
                            struct usb_host_endpoint *ep);
    /* ... */
};
코드 설명

include/linux/usb/hcd.h에 정의된 struct hc_driver는 호스트 컨트롤러 드라이버(HCD)가 USB Core에 제공하는 오퍼레이션 테이블입니다. xHCI(drivers/usb/host/xhci.c), EHCI, OHCI 등 각 HCD가 이 콜백들을 구현합니다.

  • reset() / start() / stop()HCD 생명주기 콜백입니다. reset()은 하드웨어 초기화, start()는 Root Hub 활성화, stop()은 컨트롤러 중지를 수행합니다. drivers/usb/core/hcd.cusb_add_hcd()가 이 순서로 호출합니다.
  • urb_enqueue()USB Core가 usb_submit_urb() 호출 시 최종적으로 도달하는 콜백입니다. HCD는 URB를 하드웨어 전송 큐(xHCI의 경우 Transfer Ring)에 삽입합니다.
  • urb_dequeue()usb_kill_urb()/usb_unlink_urb() 호출 시 진행 중인 URB를 하드웨어 큐에서 제거합니다.
  • hub_status_data() / hub_control()가상 Root Hub 에뮬레이션 콜백입니다. 물리적 Root Hub가 별도 USB 디바이스로 존재하지 않으므로, HCD가 포트 상태 변경 감지와 허브 제어 요청을 소프트웨어로 처리합니다.
  • endpoint_reset() / endpoint_disable()엔드포인트 리셋(STALL 클리어) 및 비활성화 시 HCD 하드웨어 상태를 정리합니다. xHCI의 경우 Endpoint Context를 갱신합니다.
  • hcd_priv_sizeHCD별 전용 데이터 크기입니다. usb_create_hcd()struct usb_hcd 뒤에 이 크기만큼 추가 메모리를 할당합니다.

xHCI 내부 구조

xHCI는 링 버퍼(Ring) 기반의 명령/전송 메커니즘을 사용합니다:

링 타입방향용도
Command RingSW → HWSlot 활성화/비활성화, Endpoint 구성, 주소 할당
Event RingHW → SW명령 완료, 전송 완료, 포트 상태 변경 알림
Transfer RingSW → HW데이터 전송 요청 (Endpoint별 1개)
xHCI 메모리 구조 (DMA 메모리) Device Context Base Address Array [0] Scratchpad Buffer Pointer [1] → Slot 1 Device Context [2] → Slot 2 Device Context ... Device Context (Slot N) Slot Context (디바이스 상태, 주소) EP 0 Context (Control) + Transfer Ring EP 1 OUT Context + Transfer Ring EP 1 IN Context + Transfer Ring ... (최대 EP 30 OUT/IN) Command Ring 호스트→xHC 명령 (Enable Slot 등) Event Ring xHC→호스트 이벤트 (완료, 오류 등) Transfer Ring 동작 원리 • TRB(Transfer Request Block) 단위로 구성 — Normal/Setup/Status/Link TRB • Enqueue Pointer(SW 쓰기) / Dequeue Pointer(xHC 읽기) 로 링 관리 • Doorbell Register 쓰기로 xHC에 새 TRB 알림 • 완료 시 Event Ring에 Transfer Event TRB 생성 → 드라이버 인터럽트 처리

xHCI Transfer Ring / Event Ring 상세

xHCI의 Transfer Ring과 Event Ring은 호스트 메모리(DMA 가능 영역)에 TRB(Transfer Request Block) 배열로 구성됩니다. 각 TRB는 16바이트 크기이며, Enqueue Pointer(소프트웨어 쓰기 위치)와 Dequeue Pointer(하드웨어 읽기 위치)로 링을 관리합니다.

xHCI Transfer Ring / Event Ring 구조 Transfer Ring (Endpoint별 1개) Setup TRB Data TRB Status TRB Normal TRB Normal TRB Link TRB Link → 링 시작으로 순환 Enqueue Pointer (SW) 소프트웨어가 새 TRB를 쓰는 위치 Dequeue Pointer (xHC) 하드웨어가 다음 처리할 TRB 위치 Cycle Bit: Producer/Consumer 동기화 Doorbell Register 쓰기 → xHC 전송 시작 Event Ring (Interrupter별 1개) Transfer Event TRB Command Compl. TRB Port Status TRB 기타 Event TRB Event Ring Segment Table (ERST) Ring Base Address + Ring Size 엔트리 다중 세그먼트로 확장 가능 Dequeue Pointer (SW) 드라이버가 처리 완료한 위치 기록 Enqueue Pointer (xHC) 하드웨어가 새 이벤트를 쓰는 위치 MSI-X 인터럽트 → ISR에서 이벤트 폴링 주요 TRB 타입 (Type ID) Normal (1): Bulk/Interrupt 데이터 전송 | Setup (2): Control SETUP 단계 | Data (3): Control DATA 단계 Status (4): Control STATUS 단계 | Isoch (5): Isochronous 전송 | Link (6): 링 세그먼트 연결 No-Op (8): 빈 TRB | Enable Slot (9): 슬롯 활성화 | Disable Slot (10): 슬롯 비활성화 Address Device (11): 주소 할당 | Configure EP (12): 엔드포인트 구성 | Evaluate Context (13): 컨텍스트 갱신

xHCI 레지스터(Register) 맵

xHCI 호스트 컨트롤러는 PCI BAR0에 매핑(Mapping)된 MMIO 레지스터 공간을 4개 영역으로 구분합니다. 각 영역은 오프셋(Offset) 기반으로 접근하며, Capability 레지스터에서 각 영역의 시작 오프셋을 읽습니다:

영역오프셋 결정주요 레지스터용도
CapabilityBAR0 + 0x00CAPLENGTH, HCSPARAMS1/2/3, HCCPARAMS1/2컨트롤러 성능/한계 정보 (읽기 전용(Read-Only))
OperationalBAR0 + CAPLENGTHUSBCMD, USBSTS, DNCTRL, CRCR, DCBAAP, CONFIG컨트롤러 제어, DCBAA/Command Ring 설정
RuntimeBAR0 + RTSOFFIMAN, IMOD, ERSTSZ, ERSTBA, ERDP (Interrupter별)인터럽트 관리, Event Ring 설정
DoorbellBAR0 + DBOFFDB[0] (Command), DB[1..MAX_SLOTS] (EP별)xHC에 새 작업 알림
/* drivers/usb/host/xhci.h — xHCI 레지스터 접근 (간략) */

/* Capability 레지스터에서 오프셋 추출 */
u32 cap_length = readl(&xhci->cap_regs->hc_capbase) & 0xFF;
u32 rts_offset = readl(&xhci->cap_regs->run_regs_off) & ~0x1F;
u32 db_offset  = readl(&xhci->cap_regs->db_off) & ~0x3;

/* Operational 레지스터 */
xhci->op_regs = (void *)xhci->cap_regs + cap_length;
writel(CMD_RUN, &xhci->op_regs->command);   /* 컨트롤러 시작 */

/* Doorbell 레지스터로 xHC에 새 TRB 알림 */
xhci->dba = (void *)xhci->cap_regs + db_offset;
writel(ep_index, &xhci->dba->doorbell[slot_id]); /* EP별 doorbell */
/* xHCI 대역폭 스케줄링 개요 */
/*
 * xHCI는 USB 2.0(Microframe 기반)과 USB 3.x(Service Interval 기반)
 * 의 대역폭을 각각 독립적으로 스케줄링합니다.
 *
 * Periodic (Interrupt/Isochronous) 엔드포인트 추가 시:
 * 1. Add Endpoint Command → xHC가 대역폭 계산
 * 2. 부족하면 Bandwidth Error (Completion Code 34) 반환
 * 3. 성공하면 Configure Endpoint Command로 확정
 *
 * USB 3.x Streams (Bulk 전용):
 * - 하나의 Bulk EP에 여러 Stream ID → 각각 독립 Transfer Ring
 * - UAS(USB Attached SCSI)에서 명령 큐잉에 활용
 * - xhci_alloc_streams() / xhci_free_streams() 로 관리
 */

HCD 내부 비교: xHCI vs EHCI vs OHCI

각 HCD는 URB를 하드웨어 트랜잭션으로 변환하는 방식이 근본적으로 다릅니다. 스케줄링 메커니즘, 메모리 구조, DMA 패턴을 비교하면 USB 성능 차이를 이해할 수 있습니다.

특성OHCIEHCIxHCI
스케줄링하드웨어 (ED/TD 리스트)하드웨어 (QH/qTD)하드웨어 (Ring Buffer + TRB)
데이터 구조Endpoint Descriptor(ED) + Transfer Descriptor(TD)Queue Head(QH) + Queue Transfer Descriptor(qTD)Device Context + Transfer Ring(TRB)
USB 속도Low/Full Speed만High Speed (LS/FS는 Companion 위임)전 속도 통합 (LS/FS/HS/SS/SS+)
Companion 필요아니오예 (OHCI/UHCI가 LS/FS 처리)아니오 (통합)
스트림 지원없음없음있음 (Bulk EP당 최대 65535 스트림)
MSI-X 지원없음제한적있음 (Interrupter별 이벤트 링)
64-bit DMA아니오제한적 (EHCI 64-bit 확장)네이티브 64-bit
Endpoint 대역폭하드웨어 자동주기적 스케줄링 테이블EP Context의 Max ESIT Payload
HCD별 URB → 하드웨어 전송 변환 struct urb OHCI Endpoint Descriptor (ED) Transfer Descriptor (TD) HCCA (프레임 리스트) ED→TD 리스트 순회 Done Queue로 완료 TD 수집 HW가 ED 리스트 자동 스케줄링 프레임당 1ms 주기 폴링 EHCI Queue Head (QH) queue Transfer Descriptor (qTD) Periodic Frame List (4K 엔트리) Async: QH 순환 리스트 Periodic: 프레임 리스트 인덱싱 Split Transaction (LS/FS) 마이크로프레임 125μs 주기 xHCI Device/Endpoint Context Transfer Request Block (TRB) DCBAA + Ring Buffer EP별 독립 Transfer Ring Doorbell로 HW에 알림 Event Ring으로 완료 수신 MSI-X 인터럽트 분산 처리
/* HCD별 urb_enqueue 내부 흐름 비교 */

/* OHCI: ohci_urb_enqueue() */
/*
 * 1. ED(Endpoint Descriptor) 찾기/생성
 * 2. TD(Transfer Descriptor) 체인 할당 (데이터 크기에 따라 N개)
 * 3. TD를 ED의 큐에 연결
 * 4. ED를 적절한 스케줄 리스트에 삽입
 *    - Control/Bulk: 비동기 리스트
 *    - Interrupt: HCCA의 주기적 프레임 리스트
 *    - Isochronous: 프레임 리스트 직접 삽입
 * 5. HW가 프레임마다 리스트를 순회하며 처리
 */

/* EHCI: ehci_urb_enqueue() */
/*
 * 1. QH(Queue Head) 찾기/생성
 * 2. qTD 체인 할당 (최대 5개 버퍼 포인터/qTD)
 * 3. qTD를 QH의 오버레이에 연결
 * 4. Async 스케줄: QH를 순환 리스트에 삽입
 *    Periodic 스케줄: 프레임 리스트 슬롯에 연결
 * 5. LS/FS 디바이스: Split Transaction (CSPLIT/SSPLIT)
 */

/* xHCI: xhci_urb_enqueue() */
/*
 * 1. Slot/EP에 대응하는 Transfer Ring 찾기
 * 2. TRB 체인 구성 (Normal/Setup/Data/Status TRB)
 * 3. TRB를 Transfer Ring의 Enqueue Pointer에 기록
 * 4. Doorbell Register 쓰기 → xHC에 새 작업 알림
 * 5. 완료 시 Event Ring에 Transfer Event TRB 생성
 * 6. ISR에서 Event Ring 폴링 → URB 완료 콜백 호출
 */

USB Gadget Framework

USB Gadget Framework는 Linux 시스템을 USB 디바이스 (Function)로 동작하게 하는 프레임워크입니다. 임베디드 시스템, SBC(Single Board Computer), 스마트폰 등에서 호스트에 연결될 때 다양한 USB 기능(Mass Storage, Ethernet, Serial 등)을 제공합니다.

Gadget 아키텍처

계층역할예시
Gadget Function DriverUSB 클래스 기능 구현f_mass_storage, f_ecm, f_acm, f_hid
Composite Framework여러 Function을 하나의 Configuration으로 합성usb_composite_driver
UDC (USB Device Controller)디바이스 컨트롤러 하드웨어 제어dwc3, musb, cdns3, fotg210
USB Gadget 스택 구조 Gadget Function Drivers f_mass_storage f_ecm (NIC) f_acm (UART) f_hid / f_uvc 사용자 정의... Composite Framework usb_composite_driver — 여러 기능 합성, Config/Interface 관리 USB Gadget API usb_gadget_driver / usb_ep_ops — HAL 인터페이스 UDC Driver dwc3 / musb / cdns3 / chipidea — 플랫폼별 컨트롤러 드라이버 USB Device Controller Hardware

ConfigFS Gadget

ConfigFS를 통해 유저스페이스에서 USB Gadget을 동적으로 구성할 수 있습니다. 커널 모듈(Kernel Module) 재컴파일 없이 USB 디바이스 기능을 조합합니다:

# ConfigFS USB Gadget 생성 예제: CDC ECM (Ethernet) + ACM (Serial)

# 1. Gadget 디렉토리 생성
cd /sys/kernel/config/usb_gadget
mkdir my_gadget && cd my_gadget

# 2. 디바이스 디스크립터 설정
echo 0x1d6b > idVendor     # Linux Foundation
echo 0x0104 > idProduct    # Multifunction Composite Gadget
echo 0x0100 > bcdDevice
echo 0x0200 > bcdUSB

# 3. 영문 문자열 설정
mkdir strings/0x409
echo "0123456789" > strings/0x409/serialnumber
echo "Linux"      > strings/0x409/manufacturer
echo "My Gadget"  > strings/0x409/product

# 4. Configuration 생성
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ECM + ACM" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower   # 500mA (USB 2.0 단위: 2mA)

# 5. Function 인스턴스 생성
mkdir functions/ecm.usb0           # CDC ECM (Ethernet)
mkdir functions/acm.GS0            # CDC ACM (Serial)

# 6. Function을 Configuration에 링크
ln -s functions/ecm.usb0 configs/c.1/
ln -s functions/acm.GS0  configs/c.1/

# 7. UDC에 바인딩 (활성화)
ls /sys/class/udc                  # 사용 가능한 UDC 확인
echo "fe980000.usb" > UDC          # UDC 이름 기록 → 호스트에 연결됨

# 비활성화
echo "" > UDC

FunctionFS

FunctionFS는 USB Gadget Function의 로직을 유저스페이스에서 구현할 수 있게 하는 파일시스템(Filesystem)입니다. 커널 드라이버 없이 사용자 정의 USB 프로토콜을 구현할 수 있습니다:

/* 유저스페이스 FunctionFS 사용 예제 (간략) */
#include <linux/usb/functionfs.h>

/* 1. FunctionFS 마운트 */
/* mount -t functionfs my_func /dev/ffs-my_func */

/* 2. ep0에 디스크립터 기록 */
int ep0_fd = open("/dev/ffs-my_func/ep0", O_RDWR);
write(ep0_fd, &descriptors, sizeof(descriptors));
write(ep0_fd, &strings, sizeof(strings));

/* 3. Endpoint 파일 열기 */
int ep1_fd = open("/dev/ffs-my_func/ep1", O_RDWR);  /* Bulk IN */
int ep2_fd = open("/dev/ffs-my_func/ep2", O_RDWR);  /* Bulk OUT */

/* 4. 데이터 송수신 */
read(ep2_fd, buf, sizeof(buf));   /* Bulk OUT에서 수신 */
write(ep1_fd, buf, len);           /* Bulk IN으로 송신 */

Composite Gadget 실전 구현

Composite Framework는 여러 USB Function을 하나의 USB 디바이스로 합성하는 프레임워크입니다. 예를 들어 하나의 임베디드 보드가 동시에 Ethernet(ECM), Serial(ACM), Mass Storage 기능을 제공할 수 있습니다. 커널 모듈 방식과 ConfigFS 방식 두 가지로 구현할 수 있습니다.

커널 모듈 방식 Composite Gadget

/* 커널 모듈 기반 Composite Gadget 골격 */
#include <linux/module.h>
#include <linux/usb/composite.h>

/* 디바이스 디스크립터 */
static struct usb_device_descriptor device_desc = {
    .bLength            = USB_DT_DEVICE_SIZE,
    .bDescriptorType    = USB_DT_DEVICE,
    .bcdUSB             = cpu_to_le16(0x0200),
    .bDeviceClass       = USB_CLASS_MISC,     /* IAD 사용 시 */
    .bDeviceSubClass    = 0x02,              /* Common Class */
    .bDeviceProtocol    = 0x01,              /* IAD */
    .idVendor           = cpu_to_le16(0x1d6b),
    .idProduct          = cpu_to_le16(0x0104),
};

/* Configuration 바인드 — Function 인스턴스 추가 */
static int my_config_bind(struct usb_configuration *c)
{
    struct usb_function *f_ecm, *f_acm;

    f_ecm = usb_get_function(fi_ecm);     /* ECM 인스턴스 획득 */
    usb_add_function(c, f_ecm);            /* Configuration에 추가 */

    f_acm = usb_get_function(fi_acm);     /* ACM 인스턴스 획득 */
    usb_add_function(c, f_acm);

    return 0;
}

static struct usb_configuration my_config = {
    .label          = "My Composite Config",
    .bConfigurationValue = 1,
    .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
    .MaxPower       = 250,  /* 500mA (USB 2.0 단위: 2mA) */
};

/* Composite 드라이버 바인드 */
static int my_composite_bind(struct usb_composite_dev *cdev)
{
    /* Function Instance 할당 */
    fi_ecm = usb_get_function_instance("ecm");
    fi_acm = usb_get_function_instance("acm");

    /* Configuration 추가 */
    usb_add_config(cdev, &my_config, my_config_bind);

    return 0;
}

static struct usb_composite_driver my_composite_driver = {
    .name       = "my_gadget",
    .dev        = &device_desc,
    .strings    = my_strings,
    .max_speed  = USB_SPEED_SUPER,
    .bind       = my_composite_bind,
    .unbind     = my_composite_unbind,
};

module_usb_composite_driver(my_composite_driver);
코드 설명

USB Gadget/UDC 프레임워크(drivers/usb/gadget/composite.c)를 사용하여 임베디드 디바이스를 USB 주변기기로 동작시키는 Composite Gadget 골격입니다. 호스트측 드라이버와 반대 방향으로, 디바이스측 USB Function을 정의합니다.

  • usb_device_descriptorGadget이 호스트에 보고할 디바이스 디스크립터입니다. USB_CLASS_MISC + SubClass 0x02 + Protocol 0x01은 IAD(Interface Association Descriptor) 사용을 나타내며, 복합 디바이스의 표준 조합입니다.
  • usb_get_function_instance()이름으로 등록된 Gadget Function(예: "ecm", "acm")의 인스턴스를 할당합니다. 커널에 내장된 f_ecm, f_acm 등의 모듈이 이 이름으로 등록되어 있습니다.
  • usb_add_function()Configuration에 Function을 추가합니다. 하나의 Configuration에 여러 Function(ECM + ACM 등)을 추가하면 복합 USB 디바이스가 됩니다.
  • usb_configuration.MaxPowerUSB 2.0 단위로 2mA이므로, 250은 500mA를 의미합니다. 호스트의 전원 공급 능력에 맞춰 설정해야 합니다.
  • usb_composite_driverComposite 프레임워크의 최상위 드라이버 구조체입니다. max_speed로 지원 가능한 최대 속도를 선언하고, bind/unbind에서 Function Instance와 Configuration을 관리합니다.
  • module_usb_composite_driver()usb_composite_probe()/usb_composite_unregister()를 래핑하는 편의 매크로로, UDC(USB Device Controller)에 Gadget 드라이버를 등록/해제합니다.

주요 내장 Gadget Function

Function 이름ConfigFS 이름용도호스트측 드라이버
f_ecmecm.<name>CDC ECM Ethernetcdc_ether
f_ncmncm.<name>CDC NCM 고성능 Ethernetcdc_ncm
f_rndisrndis.<name>RNDIS Ethernet (Windows 호환)rndis_host
f_acmacm.<name>CDC ACM 가상 시리얼cdc-acm
f_mass_storagemass_storage.<name>USB Mass Storageusb-storage
f_hidhid.<name>HID (키보드/마우스 에뮬레이션)usbhid
f_uvcuvc.<name>UVC 웹캠 에뮬레이션uvcvideo
f_midimidi.<name>USB MIDIsnd-usb-audio
f_printerprinter.<name>USB 프린터usblp
f_fs (FunctionFS)ffs.<name>유저스페이스 구현 Function벤더 드라이버/libusb

UDC (USB Device Controller) 드라이버

UDC 드라이버하드웨어USB 속도주요 사용처
dwc3DesignWare USB3 DRDSS/HS/FSARM SoC (Qualcomm, Samsung, TI 등)
dwc2DesignWare USB2 OTGHS/FSRaspberry Pi, STM32, Allwinner
musbMentor USB OTGHS/FSTI OMAP/AM3x, Allwinner
cdns3Cadence USB3 DRDSS/HS/FSTI J7, Intel Elkhart Lake
chipideaChipIdea USB2 OTGHS/FSNXP i.MX, Qualcomm
fotg210Faraday FOTG210HS/FSGemini, Cortina Access
dummy_hcd가상 HCD/UDCSS/HS/FS개발/테스트용

USB 클래스 드라이버

USB 클래스 드라이버는 USB-IF가 정의한 표준 디바이스 클래스를 구현합니다. VID/PID에 무관하게 클래스 코드만으로 드라이버가 매칭됩니다.

HID (Human Interface Device)

속성
Interface Class0x03
전송 타입Interrupt (IN/OUT)
커널 드라이버usbhid (drivers/hid/usbhid/)
디바이스 예시키보드, 마우스, 게임패드, 터치스크린
/* HID Report Descriptor 파싱 흐름 */
/* drivers/hid/usbhid/hid-core.c */
usbhid_probe()
  → hid_parse()            /* HID Report Descriptor 파싱 */hid_hw_start()         /* Input 디바이스 등록 */usb_fill_int_urb()     /* Interrupt IN URB 설정 */usb_submit_urb()       /* 입력 이벤트 수신 시작 */

Mass Storage

속성
Interface Class0x08
SubClass0x06 (SCSI transparent)
Protocol0x50 (Bulk-Only Transport, BOT)
전송 타입Bulk (IN + OUT)
커널 드라이버usb-storage, uas (UASP)
USB Mass Storage BOT 전송 순서 Host Device 1) CBW (31B) 전송 2) Data 단계 (IN 또는 OUT, 선택) 3) CSW (13B) 수신 CBW 필드: Signature(0x43425355), Tag, DataLength, Flags(IN/OUT), LUN, CDB Length, CDB(16B)
UAS (USB Attached SCSI): USB 3.0부터 지원되는 UAS(UASP) 프로토콜은 BOT 대비 명령 큐잉, 스트림 지원, 낮은 레이턴시로 성능이 크게 향상됩니다. 커널의 uas 드라이버(drivers/usb/storage/uas.c)가 담당합니다.

CDC (Communications Device Class)

서브클래스용도커널 드라이버호스트측 인터페이스
ACM (Abstract Control Model)가상 시리얼 포트cdc-acm/dev/ttyACM*
ECM (Ethernet Control Model)Ethernet 어댑터cdc_ethereth* / usb*
NCM (Network Control Model)고성능 Ethernet (USB 3.0+)cdc_ncmeth* / usb*
EEM (Ethernet Emulation Model)가상 Ethernet (Control IF 없음)cdc_eemusb*
MBIM모바일 광대역 (LTE/5G)cdc_mbimwwan*

Audio Class

속성
Interface Class0x01
전송 타입Isochronous (오디오 스트림), Interrupt (MIDI)
커널 드라이버snd-usb-audio (sound/usb/)
디바이스 예시USB 헤드셋, DAC, 마이크, MIDI 컨트롤러
USB 오디오 오프로드 (v6.16+): 커널 6.16에서 USB 오디오에 오프로드 모드가 추가되었습니다. 오디오 DSP/코프로세서가 USB 오디오 스트림을 직접 처리하여, 메인 CPU가 오디오 데이터 전송에 관여하지 않습니다. 이를 통해 모바일 기기에서 USB DAC 사용 시 전력 소모를 줄이고, CPU를 절전 상태로 유지할 수 있습니다. Qualcomm SoC의 ADSP(Audio DSP)와 연동하는 구현이 포함되어 있습니다.

주요 USB 클래스 코드

Class이름예시
0x01AudioUSB 사운드 카드, 마이크
0x02CDC (Communications)모뎀, Ethernet, 시리얼
0x03HID키보드, 마우스, 게임패드
0x06Still Image디지털 카메라 (PTP)
0x07PrinterUSB 프린터
0x08Mass StorageUSB 메모리, 외장 하드
0x09HubUSB 허브
0x0ACDC-DataCDC 데이터 인터페이스
0x0EVideo웹캠, 비디오 캡처
0xE0Wireless ControllerBluetooth 어댑터
0xEFMiscellaneousIAD(Interface Association)
0xFEApplication SpecificDFU (Device Firmware Upgrade)
0xFFVendor Specific벤더 전용 프로토콜

HID Report Descriptor 파싱 흐름

HID(Human Interface Device) 드라이버는 디바이스가 제공하는 Report Descriptor를 파싱하여 입력/출력 필드를 자동으로 매핑합니다. Report Descriptor는 바이트 스트림으로 인코딩된 계층적 구조이며, Global/Local/Main 아이템으로 구성됩니다.

HID Report Descriptor 파싱 흐름 GET_DESCRIPTOR (HID Report, Type=0x22) 바이트 스트림 수신 0x05 0x01 0x09 0x06 ... hid_parse_report() 아이템 단위 파싱 HID Item 타입 Global Items Usage Page, Logical Min/Max, Report Size/Count Local Items Usage, Usage Min/Max, Designator Main Items Input, Output, Feature, Collection, End Collection 파싱 결과: struct hid_device report_enum[HID_INPUT_REPORT]: Input 리포트 목록 report_enum[HID_OUTPUT_REPORT]: Output 리포트 목록 각 Report → hid_field[] → hid_usage[] Usage → input_dev 이벤트 매핑 (EV_KEY, EV_REL 등) hid_input_report() → input_event() → 유저스페이스 전달 Input 서브시스템 연동 hid_hw_start() → hid_connect() → hidinput_connect(): input_dev 등록 → hidraw_connect(): /dev/hidraw* 생성 Interrupt IN URB 수신 → hid_input_report() → extract_field() → input_event() 전달
/* HID Report Descriptor 바이트 예제: USB 키보드 (간략) */
/*
 * 0x05, 0x01,       // Usage Page (Generic Desktop)
 * 0x09, 0x06,       // Usage (Keyboard)
 * 0xA1, 0x01,       // Collection (Application)
 *   0x05, 0x07,     //   Usage Page (Key Codes)
 *   0x19, 0xE0,     //   Usage Minimum (Left Control)
 *   0x29, 0xE7,     //   Usage Maximum (Right GUI)
 *   0x15, 0x00,     //   Logical Minimum (0)
 *   0x25, 0x01,     //   Logical Maximum (1)
 *   0x75, 0x01,     //   Report Size (1 bit)
 *   0x95, 0x08,     //   Report Count (8 modifiers)
 *   0x81, 0x02,     //   Input (Data, Variable, Absolute) → 8 modifier bits
 *   0x95, 0x06,     //   Report Count (6 keys)
 *   0x75, 0x08,     //   Report Size (8 bits each)
 *   0x19, 0x00,     //   Usage Minimum (0)
 *   0x29, 0xFF,     //   Usage Maximum (255)
 *   0x81, 0x00,     //   Input (Data, Array) → 6 key codes
 * 0xC0              // End Collection
 *
 * → 총 8바이트 Report: [Modifiers(1B)] [Reserved(1B)] [Key1..Key6(6B)]
 * → usbhid-dump으로 실제 디바이스의 Report Descriptor 확인 가능
 */

UAS (USB Attached SCSI) 프로토콜

UAS는 USB 3.0 이상에서 Mass Storage의 BOT(Bulk-Only Transport)를 대체하는 고성능 프로토콜입니다. xHCI의 Streams 기능을 활용하여 하나의 Bulk Endpoint에 여러 독립 스트림을 할당하고, 명령 큐잉과 비순차 완료를 지원합니다:

특성BOT (Bulk-Only Transport)UAS (USB Attached SCSI)
명령 큐잉불가 (한 번에 1개 명령)가능 (최대 32+ 큐 깊이)
완료 순서순차 (FIFO)비순차 (Out-of-Order)
Endpoint 수2개 (Bulk IN + OUT)4개 (Command/Status/Data IN/OUT)
xHCI Streams미사용활용 (Stream ID = Tag)
오버헤드(Overhead)CBW/CSW 31+13 바이트IU 헤더 8~16 바이트
성능 향상기준~20~40% IOPS 향상 (랜덤 I/O 기준)

CDC 변형 비교: ACM/ECM/NCM/MBIM

CDC(Communications Device Class)는 다양한 하위 모델을 정의합니다. 각 변형은 다른 프레이밍과 집적(aggregation) 방식을 사용하여 네트워크 성능과 호환성에 큰 차이가 있습니다:

CDC 변형SubClass데이터 프레이밍패킷 집적최대 성능주요 용도
ACM0x02시리얼 스트림없음~10 MbpsAT 모뎀, 디버그 콘솔
ECM0x06Ethernet 프레임 (1:1)없음~200 MbpsUSB 2.0 Ethernet 어댑터
NCM0x0DNTB (Network Transfer Block)다중 프레임 집적~900 MbpsUSB 3.0+ 고성능 NIC
MBIM0x0ENCM 기반 + 제어 채널다중 프레임 집적~1 GbpsLTE/5G 모뎀
EEM0x0CEEM 패킷 캡슐화(Encapsulation)가능~200 MbpsControl IF 불필요 장치
/* NCM vs ECM 성능 차이의 핵심: NTB (Network Transfer Block) */
/*
 * ECM: USB 전송 1회 = Ethernet 프레임 1개
 *   → USB 전송 오버헤드가 패킷마다 발생
 *
 * NCM: USB 전송 1회 = NTB 1개 = 다수의 Ethernet 프레임 포함
 *   NTB 구조:
 *   ┌─────────────┬──────────────┬──────────────┬────────┐
 *   │ NTH (12B)   │ NDP (가변)   │ Datagram 1   │ Dgram 2│
 *   │ dwSignature │ wNdpIndex    │ (Eth Frame)  │ ...    │
 *   │ wBlockLen   │ Pointer Tbl  │              │        │
 *   └─────────────┴──────────────┴──────────────┴────────┘
 *   NTH: NTB Header, NDP: NTB Datagram Pointer
 *   최대 NTB 크기: 16KB (USB 2.0) ~ 65535B (USB 3.x)
 *
 * 결과: NCM은 USB 전송 1회로 수십 개 패킷을 보내
 *       프로토콜 오버헤드를 크게 줄입니다.
 */

USB Type-C와 Power Delivery

USB Type-C는 단순한 커넥터 규격을 넘어 전원 공급(PD), 대체 모드(Alt Mode), 역할 전환(DRP) 등 복잡한 기능을 제공합니다. Linux 커널은 Type-C 서브시스템을 통해 이를 관리합니다.

Type-C 서브시스템

구성 요소역할커널 경로
typec coreType-C 포트/파트너/케이블 모델링drivers/usb/typec/
UCSIUSB Type-C Connector System Software Interfacedrivers/usb/typec/ucsi/
TCPMType-C Port Manager (PD 상태 머신)drivers/usb/typec/tcpm/
tcpciType-C Port Controller Interface 드라이버drivers/usb/typec/tcpm/tcpci.c
Alt Mode driversDisplayPort, TBT3 등 대체 모드drivers/usb/typec/altmodes/

PD (Power Delivery) 협상

USB PD는 Type-C CC(Configuration Channel) 라인을 통해 전원 협상을 수행합니다:

PD 버전최대 전력전압 범위
USB 2.0/3.0 기본4.5W (5V/900mA)5V 고정
USB Type-C 기본15W (5V/3A)5V 고정
PD 2.0/3.0100W (20V/5A)5V, 9V, 15V, 20V
PD 3.1 (EPR)240W (48V/5A)최대 48V (Extended Power Range)
USB PD 협상 흐름 Source (전원 공급) Sink (전원 수신) Source_Capabilities (PDO 목록) Request (원하는 PDO 선택) Accept PS_RDY (전압/전류 전환 완료) 전원 계약 체결 완료 PDO 타입: Fixed, Variable, Battery, PPS, AVS(PD 3.1 EPR)
# sysfs에서 Type-C 정보 확인
ls /sys/class/typec/

# 포트 정보
cat /sys/class/typec/port0/data_role         # [host] device
cat /sys/class/typec/port0/power_role        # [source] sink
cat /sys/class/typec/port0/preferred_role    # sink / source / none
cat /sys/class/typec/port0/port_type         # dual / source / sink

# 연결된 파트너 정보
cat /sys/class/typec/port0-partner/type      # UFP / DFP
cat /sys/class/typec/port0-partner/usb_power_delivery/
ls /sys/class/typec/port0-partner/identity/  # VDM ID 정보

# 역할 전환 (DRP 포트)
echo "device" > /sys/class/typec/port0/data_role
echo "sink"   > /sys/class/typec/port0/power_role

Type-C CC 라인 감지와 방향 결정

USB Type-C 커넥터는 CC1/CC2(Configuration Channel) 핀을 통해 연결 감지, 방향 결정, 역할 협상을 수행합니다. Source 측은 Rp(풀업), Sink 측은 Rd(풀다운) 저항을 연결하며, CC 라인의 전압 레벨로 연결 상태와 전류 공급 능력을 판단합니다.

Type-C CC 라인 감지 및 방향 결정 Source (DFP / 전원 공급) CC1 ──── Rp (풀업 → VCONN 또는 VBUS) CC2 ──── Rp (풀업 → VCONN 또는 VBUS) Rp 전류 광고 (CC 전압 레벨) Default USB (500/900mA): Rp = 56kΩ → ~0.4V 1.5A: Rp = 22kΩ → ~0.66V 3.0A: Rp = 10kΩ → ~1.23V PD 사용 시: CC 라인으로 PD 메시지 통신 Sink (UFP / 전원 수신) CC1 ──── Rd (풀다운, 5.1kΩ → GND) CC2 ──── Rd (풀다운, 5.1kΩ → GND) CC 라인으로 결정되는 정보 1. 연결 감지: Rp-Rd 분압 전압 변화 2. 방향(Orientation): CC1 또는 CC2 활성 3. 전류 능력: Rp 값으로 판단 4. 케이블 타입: Ra(1kΩ)=전자마크 케이블 CC 라인 플러그 방향(Orientation) 감지 정방향 삽입 (Normal) CC1 활성 (Rp-Rd 연결) → 데이터 TX/RX 핀 매핑 CC2: VCONN (전자마크 케이블 전원) 또는 미연결 SBU1/SBU2: Alt Mode 신호 (DP AUX 등) 역방향 삽입 (Flipped) CC2 활성 (Rp-Rd 연결) → 핀 크로스 매핑 MUX가 SS 데이터 라인 방향 전환 Type-C PHY가 자동으로 처리

PD 협상 상태 머신

USB PD(Power Delivery)의 전원 협상은 CC 라인을 통한 메시지 교환으로 이루어집니다. TCPM(Type-C Port Manager)이 PD 상태 머신을 구현하며, Source와 Sink 간 PDO(Power Data Object) 교환을 통해 최적의 전원 계약을 체결합니다.

PD 협상 상태 머신 (Source → Sink) SRC_STARTUP VBUS 5V 공급 시작 SRC_DISCOVERY Source_Capabilities 전송 SRC_NEGOTIATE Request 수신 + 평가 SRC_TRANSITION 전압 전환 중 SRC_READY 전원 계약 완료 (PS_RDY) PDO (Power Data Object) 형식 — 32비트 Fixed Supply Type[31:30]=00 전압(50mV단위), 전류(10mA) 5V/9V/15V/20V 고정 Variable Supply Type[31:30]=10 최소/최대 전압 범위 가변 전원 공급 PPS (APDO) Type[31:30]=11, Sub=0 20mV 단위 전압 조절 50mA 단위 전류 제한 AVS (APDO) Type[31:30]=11, Sub=1 PD 3.1 EPR 전용 15~48V, 최대 5A (240W) EPR (PD 3.1) Extended Power Range 28V/36V/48V 고정 추가 EPR_Source/Sink_Cap 별도 TCPM (Type-C Port Manager) drivers/usb/typec/tcpm/tcpm.c PD 상태 머신 전체 구현 (~4000줄) TCPC(Port Controller) 하드웨어 추상화 VDM(Vendor Defined Message) 처리 Alt Mode 진입/탈출 관리 UCSI (Connector System SW Interface) drivers/usb/typec/ucsi/ucsi.c 펌웨어 기반 Type-C 관리 인터페이스 ACPI/PCI 백엔드 (플랫폼 의존) Command/Notification 모델 PPM(Platform Policy Manager) 위임

UCSI 명령/알림 모델

UCSI(USB Type-C Connector System Software Interface)는 인텔이 표준화한 펌웨어(Firmware) 기반 Type-C 관리 인터페이스입니다. 운영체제(OPM)가 플랫폼 정책 관리자(PPM)에게 명령을 보내고, PPM이 CC 감지와 PD 협상을 자체 처리한 뒤 알림으로 결과를 보고합니다:

/* drivers/usb/typec/ucsi/ucsi.c — UCSI 명령 인터페이스 */

/* UCSI 주요 명령 (Command) */
enum ucsi_command {
    UCSI_PPM_RESET          = 0x01,  /* PPM 초기화 */
    UCSI_CANCEL             = 0x02,  /* 진행 중인 명령 취소 */
    UCSI_CONNECTOR_RESET    = 0x03,  /* 특정 커넥터 리셋 */
    UCSI_ACK_CC_CI          = 0x04,  /* 알림 확인 응답 */
    UCSI_SET_NOTIFICATION_ENABLE = 0x05, /* 알림 활성화 */
    UCSI_GET_CAPABILITY     = 0x06,  /* PPM 성능 조회 */
    UCSI_GET_CONNECTOR_CAPABILITY = 0x07,
    UCSI_SET_UOM            = 0x08,  /* USB Operation Mode 설정 */
    UCSI_SET_PDR            = 0x0B,  /* Power Direction Role 설정 */
    UCSI_GET_PDOS           = 0x10,  /* PDO 목록 조회 */
    UCSI_GET_CONNECTOR_STATUS = 0x12, /* 커넥터 상태 조회 */
};

typec connector class API

커널의 typec 클래스는 Type-C 포트, 파트너, 케이블을 sysfs에 등록하고 유저스페이스에 노출합니다. TCPM이나 UCSI 드라이버가 이 API를 호출하여 상태를 업데이트합니다:

/* drivers/usb/typec/class.c — Connector Class API (간략) */

/* 1. 포트 등록 */
struct typec_port *port = typec_register_port(dev, &cap);
/* cap: typec_capability 구조체 — 역할, 전압, Alt Mode 등 */

/* 2. 파트너 연결 시 */
struct typec_partner *partner = typec_register_partner(port, &desc);
/* desc: 파트너 정보 — UFP/DFP, USB PD 버전, Identity */

/* 3. 상태 업데이트 */
typec_set_data_role(port, TYPEC_HOST);     /* DFP */
typec_set_pwr_role(port, TYPEC_SOURCE);    /* Source */
typec_set_orientation(port, TYPEC_ORIENTATION_NORMAL);

/* 4. PD 계약 등록 */
struct usb_power_delivery *pd;
pd = usb_power_delivery_register(dev, &pd_desc);
typec_port_set_usb_power_delivery(port, pd);

/* 5. 분리 시 */
typec_unregister_partner(partner);
typec_unregister_port(port);
PD 3.1 EPR(Extended Power Range): PD 3.1은 기존 20V/5A(100W) 한계를 넘어 28V, 36V, 48V 고정 전압과 AVS(Adjustable Voltage Supply)를 추가하여 최대 240W까지 지원합니다. EPR 진입에는 Source와 Sink 모두 EPR 지원을 선언하고, 전자마크(E-Marked) 케이블이 EPR 레이팅을 보고해야 합니다. 커널의 TCPM은 SRC_EPR_KEEP_ALIVE 상태를 통해 EPR 세션을 유지합니다.

TCPM/TCPC 상태 머신 상세

TCPM(Type-C Port Manager)은 Linux 커널의 USB Type-C PD 상태 머신 구현체입니다. drivers/usb/typec/tcpm/tcpm.c에 약 7000줄 규모로 구현되어 있으며, CC 감지, PD 협상, 역할 전환, VDM(Vendor Defined Message), Alt Mode 진입까지 Type-C의 모든 동적 동작을 관리합니다.

TCPM 주요 상태

상태 그룹주요 상태설명
연결 감지TOGGLING, SRC_UNATTACHED, SNK_UNATTACHEDCC 라인 모니터링, DRP 토글
연결 확립SRC_ATTACHED, SNK_ATTACHED, ACC_UNATTACHEDCC 라인 확정, VBUS 감지/공급
PD 탐색SRC_STARTUP, SNK_STARTUP, SRC_DISCOVERYPD 통신 개시, Source_Cap 교환
PD 협상SRC_NEGOTIATE, SNK_NEGOTIATE, SNK_TRANSITION_SINKPDO 선택, 전원 계약 체결
정상 동작SRC_READY, SNK_READY전원 계약 완료, VDM/Alt Mode 가능
역할 전환PR_SWAP_*, DR_SWAP_*, VCONN_SWAP_*Power Role, Data Role, VCONN Swap
오류/복구ERROR_RECOVERY, HARD_RESET_*, SOFT_RESET_*PD 통신 오류 복구
TCPM 상태 전이 개요 (Source 경로) TOGGLING DRP CC 토글 SRC_ATTACHED CC 확정, VBUS ON SRC_STARTUP PD 통신 시작 SRC_DISCOVERY Source_Cap 전송 SRC_NEGOTIATE Request 수신/평가 SRC_READY 계약 완료, VDM/AltMode 가능 역할 전환 (Swap) PR_SWAP: Source ↔ Sink 전환 DR_SWAP: Host ↔ Device 전환 VCONN_SWAP: VCONN 공급자 전환 오류 복구 Soft Reset: PD 프로토콜 재시작 Hard Reset: VBUS 차단 + CC 재연결 Error Recovery: 모든 상태 초기화 VDM / Alt Mode Discover Identity/SVIDs Discover Modes Enter Mode (DP/TBT3) TCPC (Type-C Port Controller) 하드웨어 인터페이스 tcpm_register_port() → tcpc_dev ops: init, get_vbus, set_vbus, set_cc, get_cc, set_polarity, set_pd_rx, pd_transmit TCPCI(I2C 표준), FUSB302, RT1711H, STUSB4500 등이 TCPC 구현 | Alert IRQ → tcpm_pd_event()
/* drivers/usb/typec/tcpm/tcpm.c — TCPC 콜백 인터페이스 */
struct tcpc_dev {
    /* CC 라인 제어 */
    int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc);
    int (*get_cc)(struct tcpc_dev *dev,
                  enum typec_cc_status *cc1, enum typec_cc_status *cc2);

    /* VBUS 제어 */
    int (*get_vbus)(struct tcpc_dev *dev);
    int (*set_vbus)(struct tcpc_dev *dev, bool on, bool charge);

    /* PD 메시지 송수신 */
    int (*set_pd_rx)(struct tcpc_dev *dev, bool on);
    int (*pd_transmit)(struct tcpc_dev *dev,
                       enum tcpm_transmit_type type,
                       const struct pd_message *msg,
                       unsigned int negotiated_rev);

    /* 역할/극성 설정 */
    int (*set_polarity)(struct tcpc_dev *dev,
                        enum typec_cc_polarity polarity);
    int (*set_roles)(struct tcpc_dev *dev, bool attached,
                     enum typec_role role, enum typec_data_role data);

    /* VCONN 제어 */
    int (*set_vconn)(struct tcpc_dev *dev, bool on);
    /* ... */
};

Thunderbolt / USB4

Thunderbolt은 Intel이 개발한 고속 인터커넥트 기술로, PCIe와 DisplayPort를 단일 케이블로 터널링합니다. USB4는 Thunderbolt 3 프로토콜을 USB-IF가 공개 표준으로 채택한 것이며, Linux 커널에서는 동일한 drivers/thunderbolt/ 드라이버가 Thunderbolt 1~4와 USB4를 모두 관리합니다.

용어 정리: Intel은 Thunderbolt 3 프로토콜 사양을 USB-IF에 기증했고, 이것이 USB4 1.0이 되었습니다. Thunderbolt 4는 USB4의 인증 프로그램이며, Thunderbolt 5(2024)는 USB4 v2.0 기반에 Intel 독자 확장(120 Gbps 대역폭 공유)을 추가한 버전입니다.

세대별 비교

세대연도최대 대역폭프로토콜커넥터PCIe 터널링데이지 체인
Thunderbolt 120112×10 GbpsPCIe 2.0 + DPMini DisplayPortPCIe 2.0 ×4최대 6대
Thunderbolt 2201320 Gbps (채널 결합)PCIe 2.0 + DP 1.2Mini DisplayPortPCIe 2.0 ×4최대 6대
Thunderbolt 3201540 GbpsPCIe 3.0 + DP 1.2/1.4USB Type-CPCIe 3.0 ×4최대 6대
USB4 1.0201940 Gbps (Gen 3×2)PCIe + DP 터널링USB Type-C선택적트리 토폴로지(Topology)
Thunderbolt 4202040 GbpsUSB4 + Intel 인증USB Type-CPCIe 3.0 ×4 (32 Gbps 필수)허브를 통한 트리
USB4 v2.0202280 Gbps (Gen 4)PCIe + DP 2.1 터널링USB Type-C선택적트리 토폴로지
Thunderbolt 5202480/120 Gbps (PAM-3)USB4 v2.0 + 대역폭 공유USB Type-CPCIe 4.0 ×4 (64 Gbps)트리 토폴로지

아키텍처: 터널링과 어댑터

Thunderbolt/USB4의 핵심 개념은 터널링입니다. 단일 물리 링크 위에 여러 프로토콜을 동시에 멀티플렉싱합니다:

Thunderbolt / USB4 링크 아키텍처 Physical Layer (USB Type-C) 40 Gbps (Gen 3x2) / 80 Gbps (Gen 4), lane bonding Transport Layer (터널링) PCIe Tunnel DP Tunnel USB3 Tunnel DMA/Host Adapter Layer (Router 내부) Lane / DP / USB3 / PCIe / Protocol(DMA) Adapter 각 어댑터가 터널 endpoint로 동작 대역폭 분배 예 (40 Gbps 링크) DP 17.28 Gbps + PCIe 약 22 Gbps + USB3 10 Gbps 유휴 터널 대역폭은 동적으로 재할당(QoS 기반)

라우터(Router)는 Thunderbolt/USB4 토폴로지의 핵심 구성 요소입니다. 각 장치(호스트, 허브, 도크)에 하나 이상의 라우터가 있으며, 라우터에는 여러 어댑터(Adapter)가 연결됩니다:

어댑터 유형역할커널 표현
Lane Adapter물리 링크 관리, 레인 본딩(Bonding)struct tb_port (type=1)
PCIe Down/Up AdapterPCIe 터널의 송/수신 엔드포인트struct tb_port (type=PCIe)
DP IN/OUT AdapterDisplayPort 터널 엔드포인트struct tb_port (type=DP)
USB3 Down/Up AdapterUSB 3.x 터널 엔드포인트struct tb_port (type=USB3)
Protocol Adapter (DMA)호스트 메모리 DMA, 네트워킹struct tb_port (type=DMA)

토폴로지와 라우팅(Routing)

Thunderbolt/USB4 토폴로지와 라우팅 Host Router Router A (Dock) PCIe → NVMe SSD DP → Monitor Router B (eGPU) PCIe Adapter → GPU 고대역폭 compute/render Router C (Hub) USB3 Adapter → USB Hub 다중 다운스트림 분기 Route String 라우팅 64-bit route string 사용 각 홉마다 포트 번호 인코딩 최대 7홉 깊이 TBT3/USB4 공통 개념 경로 계산 후 tunnel/path 구성 USB4 트리 토폴로지 데이지 체인보다 허브 중심 분기 한 포트당 하나의 직접 연결 터널별 독립 대역폭 정책 CM이 전체 토폴로지 관리 hotplug 시 경로 재계산

Linux 커널 Thunderbolt 드라이버

커널의 Thunderbolt 드라이버(drivers/thunderbolt/)는 Thunderbolt 1~4와 USB4를 통합 관리합니다:

파일역할
tb.c코어 로직, 연결 관리자(Connection Manager) 구현
switch.c라우터(스위치) 초기화, 열거(enumeration)
tunnel.cPCIe/DP/USB3/DMA 터널 생성 및 관리
path.c터널 경로(path) 설정, 홉 구성
nhi.cNative Host Interface — 호스트 컨트롤러 PCIe 드라이버
ctl.c컨트롤 채널 (라우터 간 통신, 설정 공간 읽기/쓰기)
icm.cIntel Connection Manager (펌웨어 기반 CM)
usb4.cUSB4 전용 레지스터/오퍼레이션
usb4_port.cUSB4 포트 관리, 링크 재훈련
xdomain.c크로스 도메인(peer-to-peer) 디스커버리, 서비스 프로토콜
eeprom.c디바이스 ROM (DROM) 파싱 — 장치 ID 정보
dma_port.cDMA 포트 기반 NVM(Non-Volatile Memory) 펌웨어 업데이트
retimer.cUSB4 리타이머 펌웨어 업데이트
clx.cCL0s/CL1/CL2 링크 절전 상태 관리

연결 관리자 (Connection Manager)

Thunderbolt/USB4에서 연결 관리자(CM)는 터널 생성, 대역폭 할당, 보안 정책을 결정하는 핵심 컴포넌트입니다. Linux에는 두 가지 CM이 있습니다:

CM 유형설명사용 조건
ICM (Intel CM)인텔 펌웨어 기반 CM. 커널은 펌웨어에 메시지를 보내 터널 생성을 요청Thunderbolt 1~3 (Alpine/Titan Ridge)
Software CM커널이 직접 라우터 설정 공간을 제어하여 터널 생성USB4 호스트, Ice Lake+, Apple Silicon
/* drivers/thunderbolt/tb.c — Software CM의 핵심 구조 */
static const struct tb_cm_ops tb_cm_ops = {
    .start             = tb_start,
    .stop              = tb_stop,
    .suspend_noirq     = tb_suspend_noirq,
    .resume_noirq      = tb_resume_noirq,
    .handle_event      = tb_handle_event,
    .disapprove_switch = tb_disconnect_and_release_dp,
    .approve_switch    = tb_tunnel_pci,
    .approve_xdomain_paths = tb_approve_xdomain_paths,
    .runtime_suspend   = tb_runtime_suspend,
    .runtime_resume    = tb_runtime_resume,
};

/* Software CM 디바이스 연결 시 터널 생성 흐름 */
/*
 * 1. NHI가 Hotplug 이벤트 수신 (인터럽트)
 * 2. tb_handle_event() 호출 → TB_CFG_PKG_EVENT
 * 3. 새 라우터(switch) 열거: tb_scan_port()
 * 4. 보안 레벨 확인 후 승인
 * 5. 터널 생성: tb_tunnel_pci(), tb_tunnel_dp(), tb_tunnel_usb3()
 * 6. 대역폭 분배: tb_reclaim_usb3_bandwidth()
 * 7. PCIe 핫플러그로 downstream 디바이스 열거
 */

핵심 자료구조

/* include/linux/thunderbolt.h */

/* struct tb — Thunderbolt 도메인(버스) */
struct tb {
    struct device dev;
    struct mutex lock;          /* 도메인 잠금 */
    struct tb_nhi *nhi;         /* Native Host Interface */
    struct tb_ctl *ctl;         /* 컨트롤 채널 */
    struct tb_switch *root_switch; /* 호스트 라우터 */
    const struct tb_cm_ops *cm_ops; /* CM 콜백 */
    int index;                  /* 도메인 번호 */
    enum tb_security_level security_level;
};

/* struct tb_switch — 라우터(스위치) */
struct tb_switch {
    struct device dev;
    struct tb *tb;              /* 소속 도메인 */
    u64 route;                  /* route string */
    u16 vendor;                 /* 벤더 ID */
    u16 device;                 /* 디바이스 ID */
    struct tb_port *ports;      /* 어댑터(포트) 배열 */
    unsigned int config_space_len; /* 설정 공간 크기 */
    bool is_unplugged;          /* 제거됨 플래그 */
    u8 link_speed;              /* Gbps */
    u8 link_width;              /* 1 또는 2 (레인 수) */
    enum tb_clx clx;            /* CL 절전 상태 */
    unsigned int generation;     /* TBT 세대 */
};

/* struct tb_port — 어댑터(포트) */
struct tb_port {
    struct tb_switch *sw;       /* 소속 라우터 */
    u8 port;                    /* 포트 번호 */
    enum tb_port_type type;     /* Lane/PCIe/DP/USB3/DMA */
    struct tb_port *remote;     /* 연결된 원격 포트 */
    struct tb_port *dual_link_port; /* 듀얼 레인 파트너 */
    unsigned int total_credits; /* 대역폭 크레딧 */
};

/* struct tb_tunnel — 터널 (PCIe, DP, USB3, DMA) */
struct tb_tunnel {
    struct tb *tb;
    struct tb_port *src_port;   /* 소스 어댑터 */
    struct tb_port *dst_port;   /* 목적지 어댑터 */
    struct tb_path **paths;     /* 경로 배열 */
    unsigned int npaths;
    enum tb_tunnel_type type;   /* PCIe/DP/USB3/DMA */
    int allocated_up;            /* 할당된 업스트림 Mbps */
    int allocated_down;          /* 할당된 다운스트림 Mbps */
};

터널 생성 과정

/* drivers/thunderbolt/tunnel.c — PCIe 터널 생성 */
struct tb_tunnel *tb_tunnel_alloc_pci(
    struct tb *tb,
    struct tb_port *up,      /* PCIe Up Adapter (디바이스 측) */
    struct tb_port *down     /* PCIe Down Adapter (호스트 측) */
)
{
    struct tb_tunnel *tunnel;
    struct tb_path *path;

    tunnel = tb_tunnel_alloc(tb, 2, TB_TUNNEL_PCI);
    /* path[0]: downstream (호스트→디바이스) */
    path = tb_path_alloc(tb, down, TB_PCI_HOPID, up, TB_PCI_HOPID);
    tunnel->paths[0] = path;
    /* path[1]: upstream (디바이스→호스트) */
    path = tb_path_alloc(tb, up, TB_PCI_HOPID, down, TB_PCI_HOPID);
    tunnel->paths[1] = path;

    return tunnel;
}

/* 터널 활성화 시 각 홉의 라우터 설정 공간에 path를 기록 */
int tb_tunnel_activate(struct tb_tunnel *tunnel)
{
    for (int i = 0; i < tunnel->npaths; i++) {
        tb_path_activate(tunnel->paths[i]);
        /* 각 홉의 라우터에 in_port, in_hop, out_port, out_hop 설정 */
    }
    return 0;
}

대역폭 관리

USB4/Thunderbolt 4 이상에서는 터널 간 대역폭을 동적으로 분배합니다. DP 터널이 필요로 하는 대역폭에 따라 PCIe와 USB3 터널의 할당량이 조정됩니다:

/* drivers/thunderbolt/tunnel.c — 대역폭 재분배 */

/* USB3 터널의 대역폭을 DP 터널을 위해 양보 */
static int tb_reclaim_usb3_bandwidth(struct tb *tb,
    struct tb_port *port)
{
    /* 1. 현재 USB3 터널의 실제 사용량 확인 */
    /* 2. 미사용 대역폭을 DP 터널에 재할당 */
    /* 3. USB3 터널의 보장 최소 대역폭(1 Gbps) 유지 */
}

/*
 * 대역폭 그룹 (Bandwidth Group):
 * - USB4 v2.0에서 도입된 QoS 메커니즘
 * - 같은 그룹의 터널은 대역폭을 공유
 * - DP 터널은 높은 우선순위, PCIe는 Best-Effort
 *
 * 40 Gbps 링크 대역폭 분배 예시:
 *   DP (4K@60):  ~17 Gbps (보장)
 *   USB3:        ~5 Gbps  (보장 최소, 최대 10 Gbps)
 *   PCIe:        나머지    (Best-Effort, 최대 ~32 Gbps)
 */

보안 레벨

Thunderbolt의 PCIe 터널링은 DMA를 통한 직접 메모리 접근(DMA)을 허용하므로, 보안이 중요합니다:

보안 레벨설명sysfs 값
none모든 디바이스 자동 연결 (보안 없음)none
user사용자 승인 후 연결 (기본값)user
secure디바이스 키 기반 인증 후 연결secure
dponlyDisplayPort 터널만 허용 (PCIe 차단)dponly
usbonlyUSB 터널만 허용 (PCIe/DP 차단)usbonly
nopcieUSB4: PCIe 터널 없음 (USB3 + DP만)nopcie
# 도메인 보안 레벨 확인
cat /sys/bus/thunderbolt/devices/domain0/security

# 디바이스 승인 (user 모드)
echo 1 > /sys/bus/thunderbolt/devices/0-1/authorized

# 디바이스 키 기반 인증 (secure 모드)
# 1. 처음 연결 시 challenge 키 저장
cat /sys/bus/thunderbolt/devices/0-1/key
# 2. 재연결 시 저장된 키로 인증
echo "<saved-key>" > /sys/bus/thunderbolt/devices/0-1/key
echo 2 > /sys/bus/thunderbolt/devices/0-1/authorized
DMA 공격 방어: IOMMU(Intel VT-d / AMD-Vi)를 활성화하여 Thunderbolt 디바이스의 DMA 접근 범위를 제한하세요. 보안 목적이라면 패스스루 성향의 iommu=pt 대신 strict 모드(CONFIG_IOMMU_DEFAULT_DMA_STRICT=y 또는 iommu.strict=1)를 우선 검토하고, 플랫폼 정책에 맞게 조합을 선택해야 합니다. 최신 커널은 CONFIG_THUNDERBOLT_DMA_PROTECTION 지원 여부도 함께 확인하세요.

보안 레벨 상세 및 인증 흐름

Thunderbolt의 보안 레벨은 PCIe DMA 터널링으로 인한 메모리 직접 접근 위험을 관리합니다. 각 레벨은 디바이스 연결 시 요구하는 인증 수준이 다르며, IOMMU 보호와 함께 다층 방어를 구성합니다.

Thunderbolt 보안 레벨과 IOMMU 보호 SL0: none 자동 연결 (인증 없음) 모든 터널 즉시 생성 보안 취약 — 개발용 BIOS에서 설정 또는 thunderbolt.host_reset=1 SL1: user 사용자 승인 필요 (기본값) authorized=0 → 승인 대기 echo 1 > authorized bolt 데몬이 UI로 확인 ACL로 자동 승인 가능 SL2: secure 키 기반 챌린지 인증 첫 연결: 디바이스 키 저장 재연결: 챌린지-응답 검증 HMAC-SHA256 기반 authorized=2 (키 인증) SL3: dponly / nopcie PCIe 터널 완전 차단 DP + USB3만 허용 DMA 공격 원천 차단 eGPU/NVMe 사용 불가 보안 최우선 환경용 SL2 (secure) 인증 흐름 디바이스 연결 키 확인 (key 읽기) 챌린지 전송/검증 authorized=2 설정 터널 생성 인증 실패 시: authorized=0 유지, PCIe 터널 생성 거부, dmesg에 경고 기록 Boot ACL: 부팅 시 자동 승인할 디바이스 UUID 목록 (BIOS/EFI 변수 저장, /sys/.../boot_acl) IOMMU 기반 DMA 보호 계층 1. IOMMU Strict 모드: 모든 DMA 매핑을 페이지 단위로 검증, 접근 범위 제한 2. Pre-boot DMA Protection: BIOS가 부팅 전 IOMMU로 Thunderbolt DMA 차단 (DMAR ACPI 테이블) 3. CONFIG_THUNDERBOLT_DMA_PROTECTION=y: 커널이 IOMMU DMA 보호 상태 확인 및 보고 4. 보안 레벨 + IOMMU 조합이 최선: SL1(user) + IOMMU Strict = 실용성과 보안의 균형 5. ACS(Access Control Services): PCIe 레벨에서 피어-투-피어 DMA 방지, Thunderbolt 브리지에 적용 6. sysfs 확인: cat /sys/bus/thunderbolt/devices/domain0/iommu_dma_protection → 1(보호 활성)

NHI 드라이버와 CM 상태 전환

NHI(Native Host Interface)는 Thunderbolt 호스트 컨트롤러의 PCI 디바이스 드라이버입니다. PCI BAR0에 매핑된 레지스터를 통해 송수신 링 버퍼를 관리하고, MSI-X 인터럽트로 이벤트를 수신합니다:

/* drivers/thunderbolt/nhi.c — NHI PCI 드라이버 구조 */

struct tb_nhi {
    struct pci_dev *pdev;
    void __iomem *iobase;         /* PCI BAR0 매핑 */
    struct tb_ring **tx_rings;     /* 송신 링 배열 */
    struct tb_ring **rx_rings;     /* 수신 링 배열 */
    int hop_count;                /* 사용 가능한 HopID 수 */
    int msix_ida;                 /* MSI-X 벡터 관리 */
};

/* NHI 링 구조: DMA 기반 송수신 버퍼 */
struct tb_ring {
    struct tb_ring_desc *descriptors;  /* DMA 디스크립터 배열 */
    dma_addr_t descriptors_dma;
    unsigned int head;                /* SW 쓰기 포인터 */
    unsigned int tail;                /* HW 읽기 포인터 */
    unsigned int size;                /* 링 크기 */
    int hop;                          /* HopID */
    void (*callback)(struct tb_ring *, struct ring_frame *, bool);
};

Connection Manager(CM) 상태 전환은 디바이스의 핫플러그(Hotplug), 절전, 에러 복구를 관리합니다. Software CM의 주요 상태 전환은 다음과 같습니다:

/* Software CM 상태 전환 흐름 */
/*
 * [IDLE] ──hotplug──→ [SCANNING]
 *   │                    │
 *   │                    ├── tb_scan_port()
 *   │                    ├── tb_switch_alloc() → tb_switch_add()
 *   │                    ├── 보안 레벨 확인
 *   │                    └── tb_tunnel_pci() / tb_tunnel_dp() / tb_tunnel_usb3()
 *   │                         │
 *   │                         ↓
 *   │                    [ACTIVE] ──unplug──→ [REMOVING]
 *   │                         │                   │
 *   │                         │                   ├── tb_tunnel_deactivate()
 *   │                         │                   ├── tb_switch_remove()
 *   │                         │                   └── 대역폭 재계산
 *   │                         │                        │
 *   ←──────────────────────────←────────────────────────┘
 *
 * Suspend 시: tb_suspend_noirq() → 터널 상태 저장
 * Resume 시: tb_resume_noirq() → 라우터 재열거 + 터널 복원
 *
 * 터널 대역폭 QoS:
 * - DP 터널: 해상도/주사율 기반 보장 대역폭 계산
 * - USB3 터널: 최소 1 Gbps 보장, 유휴 시 DP/PCIe에 양보
 * - PCIe 터널: Best-Effort, 잔여 대역폭 사용
 * - tb_reclaim_usb3_bandwidth()로 동적 재분배
 */

sysfs 인터페이스

# Thunderbolt/USB4 도메인 정보
ls /sys/bus/thunderbolt/devices/
# domain0       — 도메인 (버스)
# 0-0           — 호스트 라우터 (route 0)
# 0-1           — 첫 번째 연결 디바이스 (route 1)
# 0-301         — 두 번째 홉 디바이스 (route 0x301)

# 라우터(스위치) 속성
cat /sys/bus/thunderbolt/devices/0-1/device_name  # 디바이스 이름
cat /sys/bus/thunderbolt/devices/0-1/vendor_name  # 벤더 이름
cat /sys/bus/thunderbolt/devices/0-1/generation   # TBT 세대 (1-4) 또는 USB4
cat /sys/bus/thunderbolt/devices/0-1/authorized   # 승인 상태
cat /sys/bus/thunderbolt/devices/0-1/link_speed   # 링크 속도 (Gbps)
cat /sys/bus/thunderbolt/devices/0-1/link_width   # 레인 수 (1 또는 2)
cat /sys/bus/thunderbolt/devices/0-1/rx_speed     # USB4: 수신 속도
cat /sys/bus/thunderbolt/devices/0-1/rx_lanes     # USB4: 수신 레인 수
cat /sys/bus/thunderbolt/devices/0-1/tx_speed     # USB4: 송신 속도
cat /sys/bus/thunderbolt/devices/0-1/tx_lanes     # USB4: 송신 레인 수
cat /sys/bus/thunderbolt/devices/0-1/nvm_version  # 펌웨어 버전

# NVM(펌웨어) 업데이트
# 1. 펌웨어 이미지를 nvm_non_active_store에 기록
dd if=firmware.bin of=/sys/bus/thunderbolt/devices/0-1/nvm_non_active_store
# 2. 인증(플래시) 시작
echo 1 > /sys/bus/thunderbolt/devices/0-1/nvm_authenticate
# 3. 상태 확인 (0 = 성공)
cat /sys/bus/thunderbolt/devices/0-1/nvm_authenticate

Thunderbolt 네트워킹

Thunderbolt은 두 호스트 간 고속 IP 네트워킹을 지원합니다. 커널의 thunderbolt-net 드라이버가 DMA 터널을 통해 가상 이더넷 인터페이스를 생성합니다:

# thunderbolt-net 커널 모듈 로드
modprobe thunderbolt_net

# Thunderbolt 케이블로 두 호스트 연결 시 자동으로 네트워크 인터페이스 생성
ip link show thunderbolt0   # 또는 thunderbolt1, ...

# IP 주소 설정 (양쪽 호스트)
# Host A:
ip addr add 172.16.0.1/24 dev thunderbolt0
ip link set thunderbolt0 up
# Host B:
ip addr add 172.16.0.2/24 dev thunderbolt0
ip link set thunderbolt0 up

# 대역폭 테스트 (Thunderbolt 3: ~22 Gbps 실측)
iperf3 -s                        # Host A: 서버
iperf3 -c 172.16.0.1 -t 30      # Host B: 클라이언트
XDomain 프로토콜: Thunderbolt 네트워킹은 XDomain(크로스 도메인) 디스커버리 프로토콜을 사용합니다. 두 호스트가 연결되면 UUID 교환 → 프로퍼티 디렉터리 교환 → DMA 터널 설정 → 네트워크 인터페이스 생성 순서로 자동 설정됩니다. drivers/thunderbolt/xdomain.cdrivers/net/thunderbolt/에 구현되어 있습니다.

PCIe 터널링과 eGPU

Thunderbolt PCIe 터널을 통해 외부 GPU(eGPU), NVMe 스토리지, 네트워크 카드 등을 연결할 수 있습니다:

# Thunderbolt을 통해 연결된 PCIe 디바이스 확인
lspci -vt | grep -A2 "Thunderbolt"
# -[0000:00]-+-00.0  Intel ... Host Bridge
#            +-0d.2  Intel ... Thunderbolt 4 NHI
#            \-0d.0-[01-04]--+-00.0  Intel ... USB4 Root Port
#                            \-[02-04]--+-00.0  eGPU (NVIDIA/AMD)

# eGPU PCIe 대역폭 확인
lspci -vvs 02:00.0 | grep -i "lnksta"
# LnkSta: Speed 8GT/s (ok), Width x4 (ok)
# → PCIe 3.0 x4 = ~32 Gbps (Thunderbolt 3/4 최대)

# eGPU 핫플러그 이벤트 모니터링
udevadm monitor --subsystem-match=thunderbolt
udevadm monitor --subsystem-match=pci

# 안전한 eGPU 제거
# 1. GPU를 사용하는 프로세스 종료
# 2. PCIe 디바이스 제거
echo 1 > /sys/bus/pci/devices/0000:02:00.0/remove
# 3. Thunderbolt 디바이스 분리
eGPU 대역폭 제한: Thunderbolt 3/4의 PCIe 터널은 최대 PCIe 3.0 ×4 (약 32 Gbps)를 제공합니다. 이는 데스크톱 PCIe 4.0 ×16 (약 256 Gbps)의 1/8 수준이므로, GPU 성능이 약 10~25% 하락할 수 있습니다. Thunderbolt 5에서는 PCIe 4.0 ×4 (약 64 Gbps)로 개선됩니다.

DisplayPort 터널링

Thunderbolt/USB4는 DisplayPort 신호를 터널링하여 외부 모니터를 연결합니다:

연결 방식설명대역폭
DP Alt ModeType-C 핀을 DP 신호로 직접 사용 (터널링 아님)DP 1.4: 32.4 Gbps
DP Tunnel (TBT3/USB4)Thunderbolt 링크 위에 DP 패킷 터널링링크 대역폭에서 동적 할당
DP 2.1 Tunnel (USB4 v2)UHBR 레이트 터널링최대 80 Gbps
# 연결된 DP 터널 확인 (debugfs)
cat /sys/kernel/debug/thunderbolt/0-0/tunnels
# DP IN:  port 3 → port 12 (0-1), allocated_bw: 17280 Mbps
# PCIe:   port 1 → port 9 (0-1), allocated_bw: 22000 Mbps
# USB3:   port 2 → port 10 (0-1), allocated_bw: 10000 Mbps

# DRM/KMS에서 Thunderbolt 연결 모니터 확인
cat /sys/class/drm/card0-DP-*/status    # connected
cat /sys/class/drm/card0-DP-*/edid | edid-decode

전원 관리

절전 상태설명복구 시간
CL0s링크 유휴 시 저전력 (PCIe L0s와 유사)~수 μs
CL1더 깊은 링크 절전 (PCIe L1과 유사)~수십 μs
CL2USB4: 가장 깊은 절전, PHY 전원 차단~수 ms
RTD3Runtime D3 — 컨트롤러 전원 완전 차단~수백 ms
# Thunderbolt 런타임 PM 상태 확인
cat /sys/bus/thunderbolt/devices/0-0/power/runtime_status
# active / suspended

# RTD3 활성화 확인 (기본 활성화)
cat /sys/bus/thunderbolt/devices/domain0/boot_acl

# CLx 상태 확인
cat /sys/bus/thunderbolt/devices/0-1/clx    # cl0s, cl1, cl2 또는 disabled

# 전원 관리 관련 커널 메시지
dmesg | grep -i "thunderbolt.*power\|thunderbolt.*CLx\|thunderbolt.*RTD3"

디버깅

# 커널 로그에서 Thunderbolt/USB4 메시지 확인
dmesg | grep -i thunderbolt
# thunderbolt 0-1: new device found, vendor=0x8086 device=0x1234
# thunderbolt 0-1: Thunderbolt 4 device

# 동적 디버그 활성화 (상세 로깅)
echo "module thunderbolt +p" > /sys/kernel/debug/dynamic_debug/control

# debugfs 정보
ls /sys/kernel/debug/thunderbolt/
# 0-0/  — 호스트 라우터 디버그 정보
# 0-1/  — 연결 디바이스 디버그 정보

# 라우터 설정 공간 덤프
cat /sys/kernel/debug/thunderbolt/0-1/regs

# 트레이스포인트
echo 1 > /sys/kernel/debug/tracing/events/thunderbolt/enable
cat /sys/kernel/debug/tracing/trace_pipe
# tb_cfg_read/write: 라우터 설정 공간 접근 추적
# tb_tx/rx: 컨트롤 패킷 송수신 추적

# boltctl — 유저스페이스 관리 도구 (bolt 프로젝트)
boltctl list                  # 연결된 디바이스 목록
boltctl info 0-1             # 디바이스 상세 정보
boltctl authorize 0-1        # 디바이스 승인
boltctl enroll 0-1           # 디바이스 등록 (자동 승인)
boltctl forget 0-1           # 등록 해제
boltctl monitor              # 실시간 이벤트 모니터링

Thunderbolt/USB4 Kconfig 옵션

옵션설명
CONFIG_USB4Thunderbolt/USB4 서브시스템 활성화 (이전명: CONFIG_THUNDERBOLT)
CONFIG_USB4_DEBUGFS_WRITEdebugfs를 통한 라우터 설정 공간 쓰기 허용 (디버깅용)
CONFIG_USB4_DMA_TESTDMA 트래픽 테스트 드라이버 (개발/테스트용)
CONFIG_USB4_KUNIT_TESTThunderbolt KUnit 테스트
CONFIG_THUNDERBOLT_NETThunderbolt 네트워킹 (호스트 간 IP)
CONFIG_THUNDERBOLT_DMA_PROTECTION부팅 시 IOMMU 기반 DMA 보호 자동 적용
CONFIG_HOTPLUG_PCI_PCIEPCIe 핫플러그 (Thunderbolt PCIe 터널에 필요)
CONFIG_ACPI_HOTPLUG_MEMORYACPI 기반 Thunderbolt 독 메모리 핫플러그

usbfs와 libusb

usbfs는 유저스페이스에서 USB 디바이스에 직접 접근할 수 있게 하는 파일시스템입니다. 커널 드라이버 없이도 /dev/bus/usb/를 통해 Control, Bulk, Interrupt, Isochronous 전송을 수행할 수 있습니다.

usbfs 접근 구조

경로의미
/dev/bus/usb/001/001Bus 1의 Root Hub (Device 1)
/dev/bus/usb/001/002Bus 1의 연결 디바이스
/dev/bus/usb/002/001Bus 2의 Root Hub 또는 디바이스

각 디바이스 파일은 캐릭터 디바이스이며, ioctl()로 다음 트랜잭션을 수행합니다: USBDEVFS_CONTROL, USBDEVFS_BULK, USBDEVFS_SUBMITURB, USBDEVFS_REAPURB, USBDEVFS_CLAIMINTERFACE, USBDEVFS_RELEASEINTERFACE, USBDEVFS_RESETEP, USBDEVFS_RESET.

libusb 사용 예제

libusb는 usbfs 위에 구축된 크로스 플랫폼 유저스페이스 USB 라이브러리입니다:

#include <libusb-1.0/libusb.h>
#include <stdio.h>

#define VENDOR_ID   0x1234
#define PRODUCT_ID  0x5678
#define EP_BULK_IN  0x81
#define EP_BULK_OUT 0x02

int main(void)
{
    libusb_device_handle *handle;
    int ret, transferred;
    unsigned char buf[64];

    /* 1. 라이브러리 초기화 */
    libusb_init(NULL);

    /* 2. 디바이스 열기 */
    handle = libusb_open_device_with_vid_pid(
        NULL, VENDOR_ID, PRODUCT_ID);
    if (!handle) {
        fprintf(stderr, "Device not found\\n");
        return 1;
    }

    /* 3. 커널 드라이버 분리 (필요 시) */
    if (libusb_kernel_driver_active(handle, 0) == 1)
        libusb_detach_kernel_driver(handle, 0);

    /* 4. 인터페이스 점유 */
    libusb_claim_interface(handle, 0);

    /* 5. Bulk OUT 전송 (호스트 → 디바이스) */
    unsigned char tx_data[] = {0x01, 0x02, 0x03};
    ret = libusb_bulk_transfer(handle, EP_BULK_OUT,
        tx_data, sizeof(tx_data), &transferred, 5000);
    printf("Sent %d bytes\\n", transferred);

    /* 6. Bulk IN 전송 (디바이스 → 호스트) */
    ret = libusb_bulk_transfer(handle, EP_BULK_IN,
        buf, sizeof(buf), &transferred, 5000);
    printf("Received %d bytes\\n", transferred);

    /* 7. 정리 */
    libusb_release_interface(handle, 0);
    libusb_close(handle);
    libusb_exit(NULL);
    return 0;
}
권한 설정: usbfs 접근에는 root 권한이 필요합니다. udev 규칙으로 특정 VID/PID에 대해 일반 사용자 접근을 허용할 수 있습니다:
SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", MODE="0666"

USB 전원 관리

USB 전원 관리는 사용하지 않는 디바이스를 저전력 상태(Suspend)로 전환하여 전력 소모를 줄입니다. Linux 커널은 USB 디바이스 레벨과 인터페이스 레벨 모두에서 전원 관리를 지원합니다.

Autosuspend

Autosuspend는 디바이스가 일정 시간 유휴 상태(Idle State)이면 자동으로 Suspend하는 메커니즘입니다:

# autosuspend 설정 (sysfs)
# 디바이스별 경로: /sys/bus/usb/devices/<busnum>-<port>/power/

# autosuspend 활성화
echo "auto" > /sys/bus/usb/devices/1-2/power/control

# autosuspend 비활성화 (항상 활성)
echo "on" > /sys/bus/usb/devices/1-2/power/control

# autosuspend 대기 시간 (초) — 0이면 즉시 suspend
echo 2 > /sys/bus/usb/devices/1-2/power/autosuspend_delay_ms

# 현재 전원 상태 확인
cat /sys/bus/usb/devices/1-2/power/runtime_status
# active / suspended / suspending

# USB autosuspend 전역 기본값 (커널 파라미터)
# usbcore.autosuspend=2  (2초 후 자동 suspend)
# usbcore.autosuspend=-1 (autosuspend 비활성화)

Remote Wakeup

Remote Wakeup은 Suspend된 디바이스가 이벤트 발생 시 호스트를 깨울 수 있는 기능입니다 (예: 마우스 움직임, 키보드 입력):

/* 드라이버에서 autosuspend / remote wakeup 지원 */
static int my_usb_probe(struct usb_interface *intf,
                        const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(intf);

    /* ... 드라이버 초기화 ... */

    /* Remote Wakeup 허용 */
    device_set_wakeup_enable(&udev->dev, 1);

    /* autosuspend 활성화 */
    usb_enable_autosuspend(udev);

    return 0;
}

/* Suspend 콜백 */
static int my_usb_suspend(struct usb_interface *intf,
                          pm_message_t message)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    /* 진행 중인 URB 취소 */
    usb_kill_urb(dev->bulk_urb);

    return 0;
}

/* Resume 콜백 */
static int my_usb_resume(struct usb_interface *intf)
{
    struct my_usb_dev *dev = usb_get_intfdata(intf);

    /* URB 재제출 */
    usb_submit_urb(dev->bulk_urb, GFP_NOIO);

    return 0;
}

static struct usb_driver my_usb_driver = {
    .name       = "my_usb",
    .id_table   = my_usb_ids,
    .probe      = my_usb_probe,
    .disconnect = my_usb_disconnect,
    .suspend    = my_usb_suspend,
    .resume     = my_usb_resume,
    .supports_autosuspend = 1,  /* autosuspend 지원 선언 */
};

Selective Suspend

용어설명
Global Suspend전체 USB 버스 Suspend (시스템 Sleep 시)
Selective Suspend개별 디바이스만 Suspend (런타임 PM)
L1 (LPM)USB 2.0 Link Power Management — 빠른 진입/탈출
U1/U2/U3USB 3.x Link States — U1/U2(저전력), U3(Suspend)
Autosuspend 주의: 모든 USB 디바이스가 Suspend/Resume을 올바르게 구현하는 것은 아닙니다. 일부 디바이스는 Suspend 후 응답하지 않거나 데이터를 잃을 수 있습니다. 문제가 있는 디바이스는 echo "on" > power/control로 autosuspend를 비활성화하거나, 커널의 USB quirks 테이블에 등록합니다.

USB 3.x는 링크 레벨에서 4가지 전력 상태(U0~U3)를 정의합니다. U1/U2는 LPM(Link Power Management)을 통해 유휴 시 자동 전환되며, U3는 전통적인 Suspend 상태입니다. 상태 전환은 링크 양쪽이 LPM 토큰(LGO_U1/LGO_U2)을 교환하여 합의합니다.

USB 3.x Link Power State 전환 U0 (Active) 정상 동작 상태, 데이터 전송 가능 U1 (Standby) 내부 클록 유지, ~수 μs 복구 U2 (Sleep) 클록 정지, ~수십 μs~ms 복구 U3 (Suspend) PHY 전원 차단, ~수 ms 복구 LGO_U1 LFPS wakeup LGO_U2 LFPS wakeup 타이머 만료 시 깊은 절전 전환 SET_FEATURE SET_FEATURE Remote Wakeup / Resume LPM 토큰 (Link Management Packet) LGO_U1/LGO_U2: 상대방에게 상태 전환 요청 LAU/LXU: 승인(Accept) / 거부(Reject) 응답

Selective Suspend 메커니즘 상세

USB의 Selective Suspend는 시스템이 활성(S0) 상태에서 개별 디바이스만 Suspend하는 런타임 PM 메커니즘입니다. USB 2.0 LPM(L1 상태)과 USB 3.x U1/U2는 하드웨어가 자동으로 전환하는 반면, Selective Suspend(U3/L2)는 소프트웨어가 명시적으로 제어합니다:

메커니즘적용 버전진입 방법복구 시간절전 효과
USB 2.0 LPM (L1)USB 2.0 AddendumHW 자동 (Extended Token)~50~300 μs중간 (PHY 유지)
USB 3.x U1USB 3.0+HW 자동 (LGO_U1 토큰)~수 μs낮음 (클록 유지)
USB 3.x U2USB 3.0+HW 자동 (LGO_U2 토큰)~수십 μs~ms중간 (클록 정지)
Selective Suspend (U3/L2)USB 1.1+SW 명시적 (SET_FEATURE)~수 ms~20ms높음 (PHY 전원 차단)

BESL(Best Effort Service Latency)은 USB 2.0 LPM에서 디바이스가 L1 상태에서 복구하는 데 필요한 시간을 호스트에 알리는 메커니즘입니다. BESL 값이 클수록 깊은 절전이 가능하지만 복구 시간이 길어집니다. xHCI 드라이버는 Endpoint의 BESL 값을 확인하여 LPM 정책을 조정합니다.

Remote Wakeup은 Suspend 상태의 디바이스가 호스트를 깨울 수 있는 기능입니다. USB 2.0에서는 D+/D- 라인에 Resume 신호를 보내고, USB 3.x에서는 LFPS(Low Frequency Periodic Signaling)를 사용합니다. 드라이버는 device_set_wakeup_enable()으로 Remote Wakeup을 허용하고, 호스트는 SET_FEATURE(DEVICE_REMOTE_WAKEUP)로 디바이스에 통보합니다. Suspend 중 디바이스 이벤트(키보드 입력, 마우스 이동 등) 발생 시 디바이스가 스스로 Resume 신호를 생성하여 호스트를 깨웁니다.

디버깅

lsusb

# 연결된 USB 디바이스 목록
lsusb

# 트리 구조 (토폴로지)
lsusb -t

# 특정 디바이스 상세 정보 (모든 디스크립터 덤프)
lsusb -v -d 1234:5678

# 특정 버스/디바이스
lsusb -v -s 001:003

# 출력 예시 (lsusb -t)
# /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 10000M
#     |__ Port 1: Dev 2, If 0, Class=Mass Storage, Driver=uas, 5000M
# /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 480M
#     |__ Port 3: Dev 5, If 0, Class=HID, Driver=usbhid, 12M
#     |__ Port 3: Dev 5, If 1, Class=HID, Driver=usbhid, 12M
#     |__ Port 9: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M

usbmon

usbmon은 USB 트래픽을 모니터링하는 커널 기능입니다. /sys/kernel/debug/usb/usbmon/을 통해 접근합니다:

# usbmon 모듈 로드
modprobe usbmon

# debugfs 마운트 확인
mount -t debugfs none /sys/kernel/debug 2>/dev/null

# 텍스트 형식 모니터링 (Bus 1)
cat /sys/kernel/debug/usb/usbmon/1t

# 모든 버스 모니터링
cat /sys/kernel/debug/usb/usbmon/0t

# 바이너리 형식 (Wireshark용)
cat /sys/kernel/debug/usb/usbmon/1u > capture.bin

# usbmon 텍스트 출력 형식:
# URB_TAG TIMESTAMP EVENT_TYPE ADDRESS:EP STATUS LENGTH DATA
# d5ea8c00 3575914555 S Bi:1:003:1 -115 31 = 55534253 ...
#   S = Submit, C = Complete
#   Bi = Bulk IN, Bo = Bulk OUT, Ci = Control IN

Wireshark를 이용한 USB 분석

# Wireshark에서 USB 캡처 (usbmon 인터페이스 선택)
# 또는 tcpdump로 캡처 파일 생성
tcpdump -i usbmon1 -w usb_capture.pcap

# Wireshark에서 열기
wireshark usb_capture.pcap

# Wireshark 필터 예시:
# usb.transfer_type == URB_BULK
# usb.device_address == 3
# usb.endpoint_address == 0x81
# usb.idVendor == 0x1234

sysfs USB 정보

sysfs USB 디바이스 정보 구조 `/sys/bus/usb/devices/1-2/` 장치 루트 디렉터리 기본 식별자 idVendor / idProduct manufacturer / product serial / bcdDevice bDeviceClass/SubClass bDeviceProtocol version / speed 구성/전송 특성 bNumConfigurations bNumInterfaces bMaxPacketSize0 bMaxPower configuration urbnum 상태/정책 authorized / removable avoid_reset_quirk maxchild (hub) connected_duration runtime PM 상태 wakeup 정책 `power/` 디렉터리 control (auto/on) autosuspend_delay_ms runtime_status wakeup (enabled/disabled) connected_duration 인터페이스/엔드포인트 `1-2:1.0/`, `1-2:1.1/` bInterfaceClass/SubClass bInterfaceProtocol bNumEndpoints driver/ (바인딩 드라이버) ep_81/ → type / direction wMaxPacketSize / interval

커널 디버깅

# USB 관련 커널 메시지
dmesg | grep -i usb

# Dynamic Debug 활성화
echo 'module usbcore +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module xhci_hcd +p' > /sys/kernel/debug/dynamic_debug/control
echo 'module usbhid +p' > /sys/kernel/debug/dynamic_debug/control

# USB 디바이스 수동 리셋
echo 0 > /sys/bus/usb/devices/1-2/authorized
echo 1 > /sys/bus/usb/devices/1-2/authorized

# USB 바인딩/언바인딩
echo "1-2:1.0" > /sys/bus/usb/drivers/usbhid/unbind
echo "1-2:1.0" > /sys/bus/usb/drivers/usbhid/bind

# quirks 설정 (모듈 파라미터)
# usbcore.quirks=VID:PID:flags
# 예: usbcore.quirks=0x1234:0x5678:gn  (RESET_RESUME + NO_SET_INTF)

디버깅 도구 요약

도구용도설치
lsusbUSB 디바이스 목록 및 디스크립터 덤프(Dump)usbutils
usbmon커널 레벨 USB 트래픽 모니터링커널 내장 (CONFIG_USB_MON)
WiresharkGUI USB 프로토콜 분석wireshark
usbhid-dumpHID Report Descriptor 덤프usbutils
usb-devices텍스트 기반 디바이스 정보usbutils
usbipUSB over IP (원격 디바이스 공유)usbip

USB 보안

USB는 설계 초기부터 신뢰 기반 프로토콜이었으나, BadUSB, DMA 공격, 악성 디바이스 등 다양한 보안 위협이 알려지면서 커널 레벨의 방어 메커니즘이 중요해졌습니다.

USB 디바이스 인증 (USB Authentication)

USB-IF는 USB 3.2 규격에 USB Authentication 프로토콜을 추가했습니다. 공개키 기반(RSA/ECDSA) 인증으로 디바이스의 정당성을 검증합니다. 현재 Linux 커널에는 완전한 구현이 없지만, Thunderbolt의 보안 레벨(secure 모드)이 유사한 기능을 제공합니다.

커널 USB 인가(Authorization) 메커니즘

# USB 디바이스 인가 제어 (커널 내장 메커니즘)

# 버스 전체 기본 인가 정책
# 0: 새 디바이스 기본 비인가 (수동 승인 필요)
# 1: 새 디바이스 자동 인가 (기본값)
echo 0 > /sys/bus/usb/devices/usb1/authorized_default

# 개별 디바이스 인가/비인가
echo 0 > /sys/bus/usb/devices/1-2/authorized  # 비인가 (드라이버 언바인드)
echo 1 > /sys/bus/usb/devices/1-2/authorized  # 인가 (드라이버 바인딩)

# 인터페이스 레벨 인가
echo 0 > /sys/bus/usb/devices/1-2:1.0/authorized

USBGuard

USBGuard는 USB 디바이스 접근을 정책 기반으로 제어하는 유저스페이스 데몬입니다. 커널의 authorized sysfs 인터페이스를 활용하여 화이트리스트/블랙리스트 정책을 적용합니다.

# USBGuard 기본 사용법
usbguard list-devices                    # 연결된 디바이스 목록
usbguard allow-device <id>               # 디바이스 허용
usbguard block-device <id>               # 디바이스 차단
usbguard generate-policy > rules.conf    # 현재 상태 기반 정책 생성

# 정책 규칙 예시 (/etc/usbguard/rules.conf)
# 키보드/마우스 허용
allow with-interface equals { 03:01:01 03:01:02 }
# 특정 VID/PID 허용
allow id 1d6b:0002
# Mass Storage 차단
reject with-interface equals { 08:*:* }

BadUSB 방어

공격 유형설명방어 방법
HID 위장USB 메모리가 키보드로 가장하여 명령 주입USBGuard 인터페이스 정책, authorized_default=0
DMA 공격FireWire/Thunderbolt DMA로 메모리 직접 접근IOMMU 활성화, Thunderbolt 보안 레벨
펌웨어 변조USB 컨트롤러 펌웨어 재프로그래밍서명 검증(Signature Verification), USB Authentication (미래)
Juice Jacking충전 포트를 통한 데이터 탈취USBGuard, 데이터 라인 차단 케이블
디스크립터 퍼징악의적 디스크립터로 커널 파서 취약점(Vulnerability) 공격커널 퍼징 테스트, syzkaller, 디스크립터 검증 강화
lockdown 모드: 커널의 CONFIG_SECURITY_LOCKDOWN_LSM을 활성화하면 Secure Boot 환경에서 /dev/mem, iopl(), ACPI 테이블 덮어쓰기 등을 차단하여 USB 기반 DMA 공격의 영향을 줄일 수 있습니다.

USB 가상화(Virtualization)

USB 디바이스를 가상 머신에서 사용하거나 네트워크를 통해 원격 공유하려면 USB 가상화 기술이 필요합니다. Linux 커널은 VHCI(Virtual Host Controller Interface)와 USB/IP를 제공합니다.

USB/IP (USB over IP)

USB/IP는 USB 디바이스를 네트워크를 통해 원격 공유하는 커널 모듈입니다. 서버 측에서 물리 USB 디바이스를 내보내고, 클라이언트 측에서 가상 HCD(VHCI)를 통해 로컬 디바이스처럼 사용합니다.

# USB/IP 서버 측 (디바이스를 가진 머신)
modprobe usbip-host
usbipd -D                                # 데몬 시작
usbip list -l                            # 로컬 디바이스 목록
usbip bind -b 1-2                        # 디바이스 내보내기

# USB/IP 클라이언트 측 (디바이스를 사용할 머신)
modprobe vhci-hcd                        # VHCI 로드
usbip list -r server_ip                  # 서버의 내보낸 디바이스 목록
usbip attach -r server_ip -b 1-2         # 디바이스 연결

# 연결 해제
usbip detach -p 0                        # 포트 0 분리

# 클라이언트에서 디바이스가 로컬처럼 보임
lsusb  # VHCI에 연결된 원격 디바이스 표시

가상 머신 USB Pass-through

방식메커니즘성능호환성보안
VFIO USB호스트 USB 디바이스를 VM에 직접 할당네이티브높음IOMMU 그룹 격리(Isolation)
QEMU USB Pass-throughQEMU가 호스트 usbfs를 통해 VM에 전달중간높음QEMU 프로세스 권한
virtio-usb (실험적)virtio 기반 반가상화(Paravirtualization) USB HCD높음제한적virtio 채널 격리
USB/IP (VHCI)네트워크 기반 USB 포워딩낮음 (네트워크 지연)범용암호화(Encryption) 필요 (SSH 터널)
# QEMU USB 패스스루 예제
# 방법 1: 호스트 USB 디바이스 직접 할당 (VID/PID 기반)
qemu-system-x86_64 \
  -usb \
  -device usb-host,vendorid=0x1234,productid=0x5678

# 방법 2: 호스트 버스/디바이스 번호 기반
qemu-system-x86_64 \
  -usb \
  -device usb-host,hostbus=1,hostaddr=3

# 방법 3: VFIO USB 그룹 패스스루 (IOMMU 필요)
# USB 컨트롤러 전체를 VM에 할당
echo "0000:00:14.0" > /sys/bus/pci/devices/0000:00:14.0/driver/unbind
echo "0000:00:14.0" > /sys/bus/pci/drivers/vfio-pci/bind
qemu-system-x86_64 \
  -device vfio-pci,host=0000:00:14.0

dummy_hcd를 이용한 USB 테스트

dummy_hcd는 물리 USB 하드웨어 없이 가상 HCD/UDC 쌍을 생성하여 USB Gadget 드라이버를 테스트할 수 있게 합니다:

# dummy_hcd 로드 — 가상 Host + Device 컨트롤러 쌍 생성
modprobe dummy_hcd

# UDC 확인
ls /sys/class/udc/  # dummy_udc.0 표시

# ConfigFS로 Gadget 연결
echo "dummy_udc.0" > /sys/kernel/config/usb_gadget/my_gadget/UDC

# 호스트 측에서 가상 디바이스가 열거됨
lsusb  # dummy_hcd에 연결된 Gadget 표시

# 용도: Gadget Function 개발/테스트, CI/CD 파이프라인, 퍼징

USB 성능 최적화

USB 성능은 전송 타입, URB 크기, DMA 설정, 스케줄링 정책에 따라 크게 달라집니다. 최대 처리량(Throughput)을 달성하려면 프로토콜 오버헤드를 최소화하고 하드웨어 기능을 최대한 활용해야 합니다.

Bulk 스트림

USB 3.0 이상에서는 하나의 Bulk Endpoint에 여러 Stream을 할당할 수 있습니다. 각 Stream은 독립적인 Transfer Ring을 가지므로, 명령 큐잉과 비순차 완료가 가능합니다. UAS(USB Attached SCSI)가 대표적인 활용 사례입니다.

/* Bulk Streams API */

/* 스트림 할당 */
int num_streams = usb_alloc_streams(
    intf,                      /* usb_interface */
    eps,                       /* Endpoint 배열 */
    num_eps,                   /* Endpoint 수 */
    num_streams_requested,     /* 요청 스트림 수 */
    GFP_KERNEL);
/* 반환: 실제 할당된 스트림 수 (요청보다 적을 수 있음) */

/* URB에 Stream ID 설정 */
urb->stream_id = stream_id;   /* 1 ~ num_streams */
usb_submit_urb(urb, GFP_KERNEL);

/* 스트림 해제 */
usb_free_streams(intf, eps, num_eps, GFP_KERNEL);

DMA와 Scatter-Gather

최적화 기법설명API
DMA 매핑URB의 transfer_dma 필드에 DMA 주소 직접 설정URB_NO_TRANSFER_DMA_MAP 플래그
Scatter-Gather비연속 메모리를 단일 USB 전송으로 모음usb_sg_init() / usb_sg_wait()
Zero-copy커널-유저 간 데이터 복사 회피usb_alloc_coherent() + mmap
URB 배치여러 URB를 동시 제출하여 파이프라인(Pipeline) 효과다수 URB 동시 usb_submit_urb()
/* Scatter-Gather 전송 예제 */
struct usb_sg_request sg_req;
struct scatterlist sg[4];
int ret;

/* scatterlist 설정 (비연속 버퍼들) */
sg_init_table(sg, 4);
sg_set_buf(&sg[0], buf1, len1);
sg_set_buf(&sg[1], buf2, len2);
sg_set_buf(&sg[2], buf3, len3);
sg_set_buf(&sg[3], buf4, len4);

/* SG 요청 초기화 */
ret = usb_sg_init(&sg_req, udev,
    usb_sndbulkpipe(udev, ep),
    0,          /* 전송 플래그 */
    sg, 4,      /* scatterlist, 엔트리 수 */
    total_len,  /* 총 바이트 수 */
    GFP_KERNEL);

/* 동기 전송 실행 */
usb_sg_wait(&sg_req);
if (sg_req.status)
    dev_err(&intf->dev, "SG transfer failed: %d\\n",
            sg_req.status);

성능 튜닝 가이드

항목권장 설정효과
URB 크기Bulk: 16~64KB (USB 2.0), 64~256KB (USB 3.x)프로토콜 오버헤드 감소
URB 동시 제출2~8개 URB 파이프라인HW 유휴 시간 제거
Bulk StreamsUAS: 32개 스트림명령 큐잉, 비순차 완료
NCM vs ECMCDC NCM 사용 (USB 3.x 네트워킹)패킷 집적으로 ~4x 처리량
LPM 비활성화지연 민감 응용에서 U1/U2 비활성화레이턴시 감소 (처리량 교환)
autosuspend 조정고빈도 I/O 시 autosuspend_delay 증가Resume 오버헤드 감소
IOMMU 모드성능 우선: iommu=pt, 보안 우선: strictDMA 매핑 오버헤드 감소/격리

USB 트레이싱과 ftrace

USB 서브시스템은 ftrace의 tracepoint를 활용하여 URB 제출/완료, xHCI 이벤트, Gadget 동작 등을 추적할 수 있습니다. usbmon보다 세밀한 커널 내부 동작을 분석할 때 유용합니다.

USB tracepoint 목록

# 사용 가능한 USB tracepoint 확인
ls /sys/kernel/debug/tracing/events/xhci-hcd/
# xhci_address_ctx, xhci_cmd_completion, xhci_dbg_address,
# xhci_handle_event, xhci_urb_enqueue, xhci_urb_dequeue, ...

ls /sys/kernel/debug/tracing/events/gadget/
# usb_gadget_connect, usb_gadget_disconnect,
# usb_ep_queue, usb_ep_dequeue, usb_gadget_giveback_request, ...

# xHCI URB 흐름 추적
echo 1 > /sys/kernel/debug/tracing/events/xhci-hcd/xhci_urb_enqueue/enable
echo 1 > /sys/kernel/debug/tracing/events/xhci-hcd/xhci_urb_dequeue/enable
echo 1 > /sys/kernel/debug/tracing/events/xhci-hcd/xhci_cmd_completion/enable

# 트레이스 출력 확인
cat /sys/kernel/debug/tracing/trace_pipe

# Gadget 동작 추적
echo 1 > /sys/kernel/debug/tracing/events/gadget/enable

# trace-cmd를 이용한 USB 트레이싱
trace-cmd record -e xhci-hcd -e gadget sleep 5
trace-cmd report

perf를 이용한 USB 성능 분석

# USB IRQ 처리 시간 분석
perf record -g -a -e irq:irq_handler_entry -e irq:irq_handler_exit sleep 5
perf report

# xHCI 이벤트 핸들러 프로파일링
perf top -g -p $(pgrep -f "kworker.*xhci")

# USB Storage I/O 레이턴시 분석
perf trace -e 'usb:*' -p $(pgrep usb-storage) -- sleep 10

# BPF 기반 USB 레이턴시 히스토그램 (bpftrace)
bpftrace -e '
tracepoint:xhci-hcd:xhci_urb_enqueue { @start[arg0] = nsecs; }
tracepoint:xhci-hcd:xhci_urb_dequeue /@start[arg0]/ {
    @us = hist((nsecs - @start[arg0]) / 1000);
    delete(@start[arg0]);
}'

커널 6.x USB 변경사항

커널 6.x 시리즈에서는 USB 서브시스템에 다양한 개선과 새로운 기능이 추가되었습니다.

커널 버전변경사항영향
6.0USB4 v2.0 (80 Gbps) 초기 지원, xHCI 드라이버 개선Thunderbolt 5 준비
6.1Type-C retimer 펌웨어 업데이트, UCSI 개선USB4 리타이머 관리
6.2USB4 CL(Link) 절전 상태 개선, DP 터널 대역폭 관리전력 소모 감소
6.3xHCI PME 처리 개선, USB3 LPM BESL 지원 확대Suspend/Resume 안정성
6.4Type-C USB Power Delivery 3.1 EPR(240W) 지원고전력 충전 지원
6.5USB4 v2.0 대역폭 할당 개선, Thunderbolt 대역폭 그룹멀티 터널 성능 최적화
6.6xHCI interrupter 개선 (오디오 클래스용), NCM 다중 큐USB 오디오 레이턴시 감소
6.7USB4 DisplayPort 대역폭 협상 개선, TCPM PD 3.1 안정화DP Alt Mode 화질 개선
6.8gadget: USB 요청 완료 워크큐 최적화, dwc3 성능 개선Gadget 처리량 향상
6.9xHCI 세그먼트 할당 최적화, USB4 CLx 절전 개선메모리 사용량 감소
6.10typec: 커넥터 클래스 리팩터링, PD 개정 3.2 준비Type-C 드라이버 유지보수성
6.11USB4 v2.0 80 Gbps 대칭 터널링, DisplayPort 2.1 터널차세대 대역폭 활용
6.12+xHCI interrupter 다중화 (USB Audio offload 기반), USB PD 3.2오디오 오프로드, 고급 전원 관리
USB Audio Offload (6.16+): 커널 6.16에서 USB 오디오에 오프로드 모드가 추가되었습니다. xHCI의 다중 Interrupter를 활용하여 오디오 DSP가 USB 전송을 직접 처리하고, 메인 CPU는 절전 상태를 유지합니다. Qualcomm ADSP 연동 구현이 포함되어 있습니다.

폐기 예정 및 제거된 기능

기능상태대안
UHCI HCD유지보수 모드 (신규 하드웨어 없음)xHCI가 LS/FS 통합 지원
usbfs procfs (/proc/bus/usb/)제거됨/dev/bus/usb/ (devtmpfs)
g_multi 등 레거시 Gadget폐기 예정ConfigFS 기반 Gadget 구성
CONFIG_USB_OTG (구형)리팩터링 중Type-C DRD(Dual-Role Device) 모델

커널 소스 구조

경로설명
drivers/usb/core/USB Core (열거, URB, Hub, 드라이버 매칭)
drivers/usb/host/HCD 드라이버 (xhci, ehci, ohci, uhci)
drivers/usb/gadget/USB Gadget Framework (UDC, composite, function)
drivers/usb/storage/USB Mass Storage 드라이버 (usb-storage, uas)
drivers/usb/class/USB 클래스 드라이버 (cdc-acm, usblp)
drivers/usb/serial/USB-Serial 어댑터 드라이버
drivers/usb/typec/Type-C 서브시스템 (TCPM, UCSI, Alt Mode)
drivers/hid/usbhid/USB HID 드라이버
sound/usb/USB Audio 드라이버
drivers/net/usb/USB 네트워크 드라이버 (cdc_ether, cdc_ncm, rndis)
drivers/media/usb/USB 미디어 드라이버 (UVC 웹캠 등)
include/linux/usb.hUSB Core API 헤더
include/linux/usb/hcd.hHCD API 헤더
include/linux/usb/gadget.hGadget API 헤더
include/linux/usb/ch9.hUSB Chapter 9 상수/구조체 (uapi)
drivers/thunderbolt/Thunderbolt/USB4 코어 (CM, 터널, 라우터, NHI)
drivers/net/thunderbolt/Thunderbolt 네트워킹 드라이버
include/linux/thunderbolt.hThunderbolt/USB4 API 헤더

주요 Kconfig 옵션

옵션설명
CONFIG_USBUSB 서브시스템 활성화
CONFIG_USB_XHCI_HCDxHCI 호스트 컨트롤러 드라이버
CONFIG_USB_EHCI_HCDEHCI 호스트 컨트롤러 드라이버
CONFIG_USB_OHCI_HCDOHCI 호스트 컨트롤러 드라이버
CONFIG_USB_STORAGEUSB Mass Storage 드라이버
CONFIG_USB_UASUSB Attached SCSI (UASP) 드라이버
CONFIG_USB_HIDUSB HID 드라이버
CONFIG_USB_ACMCDC ACM (가상 시리얼) 드라이버
CONFIG_USB_NET_CDCETHERCDC Ethernet 드라이버
CONFIG_USB_NET_CDC_NCMCDC NCM 네트워크 드라이버
CONFIG_SND_USB_AUDIOUSB Audio 드라이버
CONFIG_USB_GADGETUSB Gadget Framework
CONFIG_USB_CONFIGFSConfigFS 기반 USB Gadget 구성
CONFIG_USB_FUNCTIONFSFunctionFS (유저스페이스 Gadget)
CONFIG_TYPECUSB Type-C 서브시스템
CONFIG_TYPEC_TCPMType-C Port Manager
CONFIG_TYPEC_UCSIUCSI Type-C 인터페이스
CONFIG_USB4Thunderbolt/USB4 서브시스템
CONFIG_THUNDERBOLT_NETThunderbolt 네트워킹 (호스트 간 IP)
CONFIG_USB_MONusbmon (USB 트래픽 모니터링)

참고자료

커널 공식 문서

커널 소스 코드

규격 문서

외부 자료

USB와 관련된 다른 주제를 더 깊이 이해하고 싶다면 다음 문서를 참고하세요.