인프라

[RaspberryPI] 라즈베리 파이 dwc 커스텀 usb_hid_gadget 설정

하루이2222 2024. 8. 30. 22:39

라즈베리 파이를 USB 키보드/마우스로 설정하기 (TinyPilot HID 설정 가이드)

TinyPilot과 같은 원격 KVM(Keyboard, Video, Mouse) 프로젝트 구성 시, 라즈베리 파이는 단순한 소형 컴퓨터가 아닌, 연결된 서버를 제어하는 주변 장치 역할을 수행해야 함. 즉, 라즈베리 파이의 USB 포트가 키보드와 마우스처럼 동작하도록 설정하는 것이 필요함.

이 가이드는 라즈베리 파이가 USB '호스트(Host)'가 아닌 USB '가젯(Gadget)'으로 작동하도록 설정하는 과정을 상세히 기술함. 이 과정은 커널 모듈에 대한 이해와 USB 장치의 동작 방식을 직접 구성하는 내용을 포함하고 있음.


1. 핵심 용어 이해

본격적인 설정에 앞서, 이 작업에 필요한 세 가지 핵심 요소(UDC, dwc2, g_ether)와 그 관계를 이해해야 함.

하드웨어와 소프트웨어의 계층 구조

각 요소의 관계는 하드웨어에서 상위 응용 프로그램으로 이어지는 계층 구조로 파악할 수 있음.

  • 최하위 계층: UDC (USB Device Controller)
    • USB 통신을 물리적으로 처리하는 하드웨어 컨트롤러임. USB 포트 자체를 관리하며, 호스트 PC와의 직접적인 데이터 통신을 담당함.
  • 중간 계층: dwc2 (USB 컨트롤러 드라이버)
    • UDC 하드웨어를 제어하는 소프트웨어 드라이버임. 이 드라이버를 활성화해야 라즈베리 파이가 USB 주변 장치 모드(Gadget Mode)로 동작할 수 있음.
  • 상위 계층: g_ether / HID (USB Gadget 드라이버)
    • dwc2 위에서 동작하며, 라즈베리 파이에 특정 USB 장치의 '정체성'을 부여하는 드라이버임. 예를 들어, g_ether는 가상 네트워크 어댑터로, hid는 키보드나 마우스 같은 입력 장치로 동작하게 만듦.

핵심 문제: UDC는 한 번에 하나의 Gadget 드라이버만 지원함. 라즈비안 OS는 기본적으로 네트워크 연결을 위해 g_ether 모듈을 활성화하는 경우가 많음. g_ether가 UDC를 점유하고 있으면, 우리가 설정하려는 키보드/마우스(HID) Gadget을 활성화할 수 없음. 따라서 가장 먼저 g_ether의 점유를 해제하는 작업이 필요함.


2. 단계별 라즈베리 파이 USB Gadget 설정

Step 1: 기존 g_ether 모듈 비활성화 및 dwc2 활성화

먼저 UDC를 점유하고 있을 수 있는 g_ether 모듈을 제거하고, USB Gadget 모드의 기반이 되는 dwc2를 활성화했음. 아래 스크립트는 이 전체 과정을 포함하여 최종적인 HID 장치를 설정함.

#!/bin/bash

# ===================================================================
# [최종 해결안] TinyPilot 호환 하이브리드 절대좌표 마우스 설정
# - 키보드: 표준 장치 (/dev/hidg0)
# - 마우스: 7바이트를 받지만 휠 데이터는 무시하는 장치 (/dev/hidg1)
# ===================================================================

# USB Gadget 설정 디렉토리
GADGET_DIR="/sys/kernel/config/usb_gadget/g1"

echo "Loading composite module..."
sudo modprobe libcomposite

# --- 0. 이미 /dev/hidg* 존재 시 바로 종료 ---
if [ -e /dev/hidg0 ] && [ -e /dev/hidg1 ]; then
  echo "✅ HID gadget devices already exist (/dev/hidg0, /dev/hidg1). Skipping setup."
  exit 0
fi

# --- 1. 기존 설정 정리 ---
if [ -d "$GADGET_DIR" ]; then
  echo "Removing existing gadget configuration..."
  echo "" | sudo tee "$GADGET_DIR/UDC" > /dev/null 2>&1 || true
  sleep 1
  if [ -d "$GADGET_DIR/configs/c.1" ]; then
    sudo find "$GADGET_DIR/configs/c.1" -type l -exec rm {} \;
  fi
  sudo rm -rf "$GADGET_DIR"
fi

# --- 2. 가젯 기본 설정 ---
echo "Creating new USB Gadget configuration..."
sudo mkdir -p "$GADGET_DIR"
cd "$GADGET_DIR" || { echo "Failed to cd to $GADGET_DIR"; exit 1; }

echo 0x1d6b | sudo tee idVendor
echo 0x0104 | sudo tee idProduct
echo 0x0100 | sudo tee bcdDevice
echo 0x0200 | sudo tee bcdUSB

sudo mkdir -p strings/0x409
echo "tinypilot-hid-final" | sudo tee strings/0x409/serialnumber
echo "TinyPilot" | sudo tee strings/0x409/manufacturer
echo "Hybrid HID (Kbd+AbsMouse)" | sudo tee strings/0x409/product

# --- 3. HID 함수 설정 ---

# 🔹 키보드 (hid.usb0) - 변경 없음
echo "Setting up Keyboard (hid.usb0)..."
sudo mkdir -p functions/hid.usb0
echo 1 | sudo tee functions/hid.usb0/protocol
echo 1 | sudo tee functions/hid.usb0/subclass
echo 8 | sudo tee functions/hid.usb0/report_length
sudo bash -c 'printf "\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x95\x08\x75\x01\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0" > functions/hid.usb0/report_desc'

# 🔹 하이브리드 절대좌표 마우스 (hid.usb1)
echo "Setting up HYBRID Absolute Mouse (hid.usb1)..."
sudo mkdir -p functions/hid.usb1
echo 0 | sudo tee functions/hid.usb1/protocol
echo 0 | sudo tee functions/hid.usb1/subclass
# 보고서 길이를 7바이트로 설정하여 TinyPilot과 맞춤
echo 7 | sudo tee functions/hid.usb1/report_length
# Report Descriptor: 버튼, X/Y좌표는 해석하고 나머지 2바이트는 무시(패딩 처리)
sudo bash -c 'printf "\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x16\x00\x00\x26\xff\x7f\x75\x10\x95\x02\x81\x02\x95\x02\x75\x08\x81\x01\xc0\xc0" > functions/hid.usb1/report_desc'

# --- 4. USB 구성 및 장치 연결 ---
echo "Linking functions to configuration..."
sudo mkdir -p configs/c.1/strings/0x409
echo "Default Configuration" | sudo tee configs/c.1/strings/0x409/configuration
echo 250 | sudo tee configs/c.1/MaxPower

sudo ln -s functions/hid.usb0 configs/c.1/
sudo ln -s functions/hid.usb1 configs/c.1/

# --- 5. UDC 활성화 및 권한 설정 ---
echo "Activating UDC..."
UDC_DEVICE=$(ls /sys/class/udc | head -n 1)
if [ -z "$UDC_DEVICE" ]; then
  echo "❌ Error: No UDC device found!"
  exit 1
fi
echo "$UDC_DEVICE" | sudo tee UDC

sleep 1
echo "Setting permissions for /dev/hidg*..."
sudo chmod 666 /dev/hidg0 2>/dev/null
sudo chmod 666 /dev/hidg1 2>/dev/null

echo "✅ Final Hybrid HID Gadget setup complete. Please check the TinyPilot web interface."

이후 추가된 내용: https://developsvai5096.tistory.com/110

Step 3: 스크립트 실행 및 자동화

  1. 실행 권한 부여 및 실행

    sudo chmod +x /usr/local/bin/setup_usb_gadget.sh
    sudo /usr/local/bin/setup_usb_gadget.sh
  2. 부팅 시 자동 실행
    위 스크립트가 설정하는 /sys 경로는 임시 파일 시스템이므로 재부팅 시 초기화됨. 따라서 매 부팅 시마다 스크립트가 실행되도록 설정해야 함. rc.local 파일이나 systemd 서비스를 이용하는 것이 일반적인 방법임.

Step 4: 최종 확인

모든 설정이 완료되면, 시스템은 이 가상 HID 장치를 제어할 수 있는 디바이스 파일을 생성함.

ls /dev/hidg*

명령어 실행 결과, /dev/hidg0(키보드), /dev/hidg1(마우스)와 같은 파일들이 확인되면 설정에 성공한 것임. 이제 TinyPilot과 같은 애플리케이션이 이 파일에 데이터를 쓰는 방식으로 원격지 컴퓨터에 키보드 입력과 마우스 움직임을 전송할 수 있음.