리눅스 시스템에서 USB 장치 모드(Peripheral Mode)를 구현하기 위한 핵심 요소는 USB 가젯(Gadget) 서브시스템입니다. 관련 소스 코드는 주로 커널 내의
drivers/usb/gadget/ 경로에서 관리됩니다.
USB 장치 논리 계층 구조
USB 장치는 호스트와의 통신을 위해 복잡한 계층 구조를 가집니다. 일반적인 구조는 루트(Root)에서 포트(Port), 장치(Device), 그리고 최종적으로 여러 개의 엔드포인트(EP)로 이어집니다. 장치 기술자(Descriptor)의 관점에서 본 구조는 다음과 같습니다.
Device Descriptor
└── Configuration 0
├── Interface 0 (e.g., HID 인터페이스)
│ ├── HID Descriptor
│ └── Endpoint 1 (IN)
└── Interface 1 (e.g., Data 인터페이스)
├── Endpoint 2 (OUT)
└── Endpoint 3 (IN)
USB 컨트롤러는 물리적인 대역폭과 엔드포인트 개수에 제한이 있으므로, 설계 시 장치가 사용하는 엔드포인트 총합이 컨트롤러의 사양을 초과하지 않도록 주의해야 합니다. 이를 초과할 경우 열거(Enumeration) 단계에서 실패할 수 있습니다.
가젯 드라이버의 주요 계층
가젯 프레임워크는 유연한 구성을 위해 계층화되어 있습니다.
usb/gadget/configfs.c: 유저 스페이스에서 USB 기능을 동적으로 구성하기 위한 ConfigFS 인터페이스.
usb/gadget/functions.c: 개별 USB 기능들의 공통 로직 관리.
usb/gadget/function/f_*.c: RNDIS, UVC, Storage 등 구체적인 USB 클래스 구현체.
RNDIS 가젯 구현 예시
안드로이드 기기에서 흔히 사용하는 USB 테더링(USB 가상 랜카드)은 RNDIS 기능을 통해 구현됩니다.
f_rndis.c에서 드라이버 등록은 다음과 같은 매크로를 통해 이루어집니다.
static struct usb_function_instance *custom_rndis_alloc_inst(void)
{
struct f_rndis_opts *opts;
// 인스턴스 초기화 로직
return &opts->func_inst;
}
static struct usb_function *custom_rndis_alloc_func(struct usb_function_instance *fi)
{
struct f_rndis *rndis_dev;
// 기능 할당 및 엔드포인트 설정 로직
return &rndis_dev->func;
}
DECLARE_USB_FUNCTION_INIT(rndis_mod, custom_rndis_alloc_inst, custom_rndis_alloc_func);
이 매크로는 드라이버 로드 시
usb_function_register를 호출하며, 두 가지 핵심 콜백을 등록합니다.
alloc_inst: USB 인스턴스 초기화 및 ConfigFS 속성 설정.
alloc_func: 엔드포인트 기술자 처리 및 실제 기능 할당.
UVC(USB Video Class) 가젯 아키텍처
UVC 가젯은
f_uvc.c(어댑터 계층)와
uvc_v4l2.c(V4L2 인터페이스 계층)로 나뉩니다. 이 구조는 USB로 들어오는 비디오 데이터를 커널의 V4L2 프레임워크와 연결합니다.
f_uvc.c는
vdev 프라이빗 데이터를 통해 가상 V4L2 장치를 제어하며, V4L2 API를 사용하여 표준 비디오 장치로 등록됩니다.
// V4L2 장치 등록 예시
struct video_device *v_dev = &uvc->vdev;
v_dev->fops = &uvc_v4l2_fops;
video_set_drvdata(v_dev, uvc);
ret = video_register_device(v_dev, VFL_TYPE_VIDEO, -1);
구현 시
uvc_v4l2_fops와
uvc_v4l2_ioctl_ops를 통해 호스트의 요청(해상도 변경, 스트리밍 제어 등)을 처리합니다.
엔드포인트 및 대역폭 점검
가젯 기기를 개발할 때 대역폭 소모량과 엔드포인트 할당 상태를 확인하는 것이 중요합니다.
usbmon 기반의
usbtop 도구를 사용하거나 디버그 파일 시스템을 조회할 수 있습니다.
# 현재 연결된 장치 및 엔드포인트 상태 확인
cat /sys/kernel/debug/usb/devices
출력 정보 중
B 항목은 할당된 대역폭을 나타내며,
Int(인터럽트) 및
Iso(등시성) 전송 엔드포인트 개수를 유심히 살펴봐야 합니다. 컨트롤러마다 주기적 엔드포인트(Periodic Endpoints) 제한이 다르기 때문입니다.
또한, USB 호스트가
SET_INTERFACE 명령을 보내면 드라이버의
set_alt 함수가 호출됩니다. 예를 들어 UAC2(Audio Class) 드라이버에서는
afunc_set_alt 함수를 통해 샘플링 레이트를 변경하거나 재생/녹음 상태를 전환하는 로직을 수행합니다.