Zpět na domů

Píšeme USB ovladače s libusb: průvodce pro vývojáře

Článek vysvětluje vytváření USB ovladačů prostřednictvím libusb bez práce s kódem jádra. Prozkoumán příklad s Androidem v režimu fastboot, analýza VID/PID, požadavky prostřednictvím Control Endpoint a dekódování deskriptorů. Materiál je určen pro middle/senior vývojáře.

USB ovladače za 5 minut: od teorie k funkčnímu kódu
Advertisement 728x90

# USB ovladače bez bolesti: od teorie k kódu na libusb

Psaní ovladačů pro USB zařízení často děsí vývojáře složitostí low-level kódu. S vhodným nástrojem, jako je libusb, se však proces stává srovnatelně obtížným se síťovým programováním přes sokety. V tomto článku si rozebereme, jak vytvořit ovladač pro USB zařízení na příkladu Android zařízení v režimu bootloaderu.

Základy USB: co by měl vědět vývojář

USB specifikace definuje standardní mechanismus identifikace zařízení prostřednictvím VID (Vendor ID) a PID (Product ID). Tyto identifikátory přiděluje výrobci (VID – USB-IF) a konkrétnímu produktu (PID – samotný výrobce). Při připojení zařízení host požaduje deskriptory – binární struktury ve firmwaru obsahující informace o třídě zařízení, jeho schopnostech a požadovaném ovladači. Klíčový bod: většinu úkolů lze vyřešit v uživatelském prostoru prostřednictvím standardních ovladačů jako Winusb.sys (Windows) nebo usbfs (Linux), bez práce s kódem jádra.

Důležité je pochopit terminologii:

Google AdInline article slot
  • Koncový bod (Endpoint): Logický kanál pro přenos dat (Control, Bulk, Interrupt, Isochronous).
  • Deskriptor zařízení: Kořenová struktura s VID/PID a základními parametry.
  • Třída zařízení: Standardizovaná funkčnost (HID, Mass Storage), ale mnohá zařízení používají Vendor Specific Class.

Příprava zařízení: výběr a nastavení

Jako příklad vezmeme Android zařízení v režimu Bootloader (fastboot). Tento výběr je opodstatněný:

  • Dostupnost: většina chytrých telefonů podporuje přechod do fastboot.
  • Jednoduchost protokolu: dokumentace k fastboot je otevřená a minimalistická.
  • Absence předinstalovaných ovladačů: OS nepřebírá komunikaci.

Přepnutí do režimu Bootloader obvykle vyžaduje podržení kombinace tlačítek při zapnutí (např. tlačítko zesílení hlasitosti + napájení). Pro identifikaci zařízení v Linuxu použijte lsusb:

$ lsusb
Bus 008 Device 014: ID 18d1:4ee0 Google Inc. Nexus/Pixel Device (fastboot)

Zde je 18d1 VID společnosti Google, 4ee0 PID pro fastboot. Ve Windows poskytuje analogické informace USB Device Tree Viewer. Klíčový bod: pokud OS načte ovladač (např. v Správci zařízení se zobrazí se symbolem ⚠️), bude nutná výměna za Winusb.sys přes Zadig.

Google AdInline article slot

Zjišťování zařízení: od ruční analýzy k programové realizaci

Proces zjišťování (enumeration) se spustí automaticky při připojení. OS analyzuje VID/PID a třídu zařízení pro výběr ovladače. Pro uživatelský prostor tento proces realizujeme přes libusb. Podívejme se na kód registrace obslužné rutiny připojení:

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

auto hotplug_callback(
    libusb_context *ctx,
    libusb_device *device,
    libusb_hotplug_event event,
    void *user_data
) -> int {
    std::println("Device plugged in!");
    return 0;
}

auto main() -> int {
    libusb_context *context = nullptr;
    libusb_init(&context);

    libusb_hotplug_callback_handle handle;
    libusb_hotplug_register_callback(
        context,
        LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
        LIBUSB_HOTPLUG_ENUMERATE,
        0x18d1, 0x4ee0,
        LIBUSB_HOTPLUG_MATCH_ANY,
        hotplug_callback, nullptr,
        &handle
    );

    while (true) {
        if (libusb_handle_events(context) < 0) break;
    }

    libusb_hotplug_deregister_callback(context, handle);
    libusb_exit(context);
}

Tento kód inicializuje libusb, zaregistruje callback pro zařízení s VID=0x18d1 a PID=0x4ee0 a čeká na připojení. Při úspěšném spuštění vypíše "Device plugged in!". Na Windows může být nutné odpojení jádra:

libusb_detach_kernel_driver(handle, 0);

Komunikace se zařízením přes Control Endpoint

Pro základní interakci použijeme Control Endpoint (ID 0x00) – standardní kanál pro servisní požadavky. Realizujeme odeslání požadavku GET_STATUS:

Google AdInline article slot
libusb_device_handle *handle = nullptr;
libusb_open(device, &handle);

std::vector<std::uint8_t> data(0xFF);
const auto result = libusb_control_transfer(
    handle,
    LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_STANDARD,
    LIBUSB_REQUEST_GET_STATUS,
    0x00, 0x00,
    data.data(), data.size(),
    1000
);

if (result >= 0) print_bytes(std::span(data).subspan(0, result));
libusb_close(handle);

Úspěšná odpověď (např. 01 00) se dekóduje podle specifikace: první bajt – zdroj napájení (1 = z baterie), druhý – podpora vzdáleného probuzení (0 = nepodporováno). Control Endpoint umožňuje odesílat i další standardní požadavky (GET_DESCRIPTOR, SET_CONFIGURATION), což je klíčové pro získání deskriptorů.

Požadavek na deskriptory: klíč k pochopení zařízení

Deskriptory jsou základem interakce s USB zařízením. Požádáme o deskriptor zařízení přes GET_DESCRIPTOR:

const auto result = libusb_control_transfer(
    handle,
    LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_STANDARD,
    LIBUSB_REQUEST_GET_DESCRIPTOR,
    (LIBUSB_DT_DEVICE << 8), // Typ deskriptoru
    0x00,
    data.data(), data.size(),
    1000
);

Získaná data obsahují strukturu libusb_device_descriptor s poli:

  • bcdUSB: Verze USB specifikace
  • bMaxPacketSize0: Maximální velikost paketu pro Control Endpoint
  • idVendor/idProduct: VID a PID
  • bNumConfigurations: Počet konfigurací

Analýza deskriptorů umožňuje určit podporované rozhraní a koncové body. Pro získání konfiguračního deskriptoru změňte typ požadavku na LIBUSB_DT_CONFIG a uveďte index konfigurace v wIndex.

Co je důležité

  • Práce v uživatelském prostoru: Používejte libusb místo kódu jádra – snadnější ladění a bezpečnější.
  • VID/PID – hlavní identifikátory: Na nich je postaveno přiřazení ovladače, třída zařízení je často neinformative (Vendor Specific Class).
  • Control Endpoint – základní nástroj: Přes něj získáváte deskriptory a ovládáte zařízení před nastavením dalších endpointů.
  • Deskriptory – zdroj pravdy: Jejich struktura je popsána v USB specifikaci, dekódování poskytuje úplný přehled o schopnostech zařízení.

— Editorial Team

Advertisement 728x90

Číst dál