265 lines
9.2 KiB
Zig
265 lines
9.2 KiB
Zig
//! USB class-code decoding: turn the (class, subclass, protocol) triple a USB device or
|
|
//! interface reports in its descriptors into typed values. The device descriptor carries one
|
|
//! triple for the whole device, and each interface descriptor carries its own; a class code
|
|
//! of zero at the device level defers entirely to the interfaces. Subclass and protocol
|
|
//! codes are qualified by the class code — the same value means different things under
|
|
//! different classes — so there is no single SubClass or Protocol enum: each class with
|
|
//! spec-defined codes gets its own namespace below. Pure reference data (from the USB-IF
|
|
//! defined class codes; see https://www.usb.org/defined-class-codes) — no hardware access —
|
|
//! so it is shared by kernel discovery and any user-space tool (device naming, driver
|
|
//! matching).
|
|
|
|
// Base class codes (assigned by the USB-IF). The comment on each value notes where the code
|
|
// may legally appear: in the device descriptor, in interface descriptors, or both.
|
|
const Class = enum(u8) {
|
|
// Use class information in the interface descriptors (device descriptor only). Each
|
|
// interface within a configuration specifies its own class information and the various
|
|
// interfaces operate independently.
|
|
per_interface = 0x00,
|
|
// Audio: speakers, microphones, sound cards (interface)
|
|
audio = 0x01,
|
|
// Communications and CDC control: modems, network adapters (both)
|
|
communications = 0x02,
|
|
// Human Interface Device: keyboards, mice, game controllers (interface)
|
|
hid = 0x03,
|
|
// Physical: force-feedback devices (interface)
|
|
physical = 0x05,
|
|
// Image: still-imaging cameras, scanners (interface)
|
|
image = 0x06,
|
|
// Printer (interface)
|
|
printer = 0x07,
|
|
// Mass storage: flash drives, external disks, card readers (interface)
|
|
mass_storage = 0x08,
|
|
// Hub (device descriptor only)
|
|
hub = 0x09,
|
|
// CDC-Data: the data interfaces paired with a communications control interface
|
|
// (interface)
|
|
cdc_data = 0x0A,
|
|
// Smart card readers (interface)
|
|
smart_card = 0x0B,
|
|
// Content security (interface)
|
|
content_security = 0x0D,
|
|
// Video: webcams (interface)
|
|
video = 0x0E,
|
|
// Personal healthcare devices (interface)
|
|
personal_healthcare = 0x0F,
|
|
// Audio/Video devices (interface)
|
|
audio_video = 0x10,
|
|
// Billboard: describes alternate modes a USB Type-C device supports (device descriptor
|
|
// only)
|
|
billboard = 0x11,
|
|
// USB Type-C bridge (interface)
|
|
type_c_bridge = 0x12,
|
|
// USB Bulk Display Protocol devices (interface)
|
|
bulk_display = 0x13,
|
|
// MCTP over USB protocol endpoint devices (interface)
|
|
mctp = 0x14,
|
|
// I3C devices (interface)
|
|
i3c = 0x3C,
|
|
// Diagnostic devices (both)
|
|
diagnostic = 0xDC,
|
|
// Wireless controllers: Bluetooth adapters (interface)
|
|
wireless_controller = 0xE0,
|
|
// Miscellaneous (both)
|
|
miscellaneous = 0xEF,
|
|
// Application-specific: firmware upgrade, IrDA bridges, test and measurement
|
|
// (interface)
|
|
application_specific = 0xFE,
|
|
// Vendor-specific (both)
|
|
vendor_specific = 0xFF,
|
|
_,
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.hub. Hubs have no subclass codes; the
|
|
// protocol distinguishes the hub's transaction-translator arrangement.
|
|
const hub = struct {
|
|
const Protocol = enum(u8) {
|
|
// Full-speed hub
|
|
full_speed = 0x00,
|
|
// Hi-speed hub with a single transaction translator
|
|
hi_speed_single_tt = 0x01,
|
|
// Hi-speed hub with multiple transaction translators
|
|
hi_speed_multi_tt = 0x02,
|
|
// SuperSpeed hub (USB 3)
|
|
super_speed = 0x03,
|
|
_,
|
|
};
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.hid.
|
|
const hid = struct {
|
|
const SubClass = enum(u8) {
|
|
// No subclass
|
|
none = 0x00,
|
|
// Boot interface: the device also supports the simplified boot protocol, usable by
|
|
// firmware before a full HID report-descriptor parser is available
|
|
boot = 0x01,
|
|
_,
|
|
};
|
|
|
|
// Only meaningful when the subclass is boot
|
|
const Protocol = enum(u8) {
|
|
none = 0x00,
|
|
keyboard = 0x01,
|
|
mouse = 0x02,
|
|
_,
|
|
};
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.mass_storage. The subclass identifies the
|
|
// command set the device understands; the protocol identifies the transport used to carry
|
|
// commands, data, and status over the bus.
|
|
const mass_storage = struct {
|
|
const SubClass = enum(u8) {
|
|
// SCSI command set not reported; de facto, treat as scsi
|
|
not_reported = 0x00,
|
|
// Reduced Block Commands: typically flash devices
|
|
rbc = 0x01,
|
|
// MMC-5 (ATAPI): CD and DVD drives
|
|
atapi = 0x02,
|
|
// QIC-157 tape drives (obsolete)
|
|
qic_157 = 0x03,
|
|
// UFI: floppy disk drives
|
|
ufi = 0x04,
|
|
// SFF-8070i (obsolete)
|
|
sff_8070i = 0x05,
|
|
// Transparent SCSI command set: the common case for flash drives and disks
|
|
scsi = 0x06,
|
|
// LSD FS: negotiated access to large storage devices
|
|
lsd_fs = 0x07,
|
|
// IEEE 1667
|
|
ieee_1667 = 0x08,
|
|
// Vendor-specific
|
|
vendor_specific = 0xFF,
|
|
_,
|
|
};
|
|
|
|
const Protocol = enum(u8) {
|
|
// Control/Bulk/Interrupt with command completion interrupt
|
|
cbi_completion_interrupt = 0x00,
|
|
// Control/Bulk/Interrupt without command completion interrupt
|
|
cbi = 0x01,
|
|
// Bulk-only transport: the common case for flash drives and disks
|
|
bulk_only = 0x50,
|
|
// USB attached SCSI
|
|
uas = 0x62,
|
|
// Vendor-specific
|
|
vendor_specific = 0xFF,
|
|
_,
|
|
};
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.communications (CDC). The protocol codes
|
|
// are model-specific; the useful invariant is the subclass, which selects the control model
|
|
// the interface implements.
|
|
const communications = struct {
|
|
const SubClass = enum(u8) {
|
|
// Direct line control model
|
|
direct_line = 0x01,
|
|
// Abstract control model: USB modems and serial adapters
|
|
abstract_control = 0x02,
|
|
// Telephone control model
|
|
telephone = 0x03,
|
|
// Multi-channel control model
|
|
multi_channel = 0x04,
|
|
// CAPI control model
|
|
capi = 0x05,
|
|
// Ethernet networking control model
|
|
ethernet = 0x06,
|
|
// ATM networking control model
|
|
atm = 0x07,
|
|
// Wireless handset control model
|
|
wireless_handset = 0x08,
|
|
// Device management
|
|
device_management = 0x09,
|
|
// Mobile direct line model
|
|
mobile_direct_line = 0x0A,
|
|
// OBEX
|
|
obex = 0x0B,
|
|
// Ethernet emulation model
|
|
ethernet_emulation = 0x0C,
|
|
// Network control model
|
|
network_control = 0x0D,
|
|
_,
|
|
};
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.wireless_controller.
|
|
const wireless_controller = struct {
|
|
const SubClass = enum(u8) {
|
|
// Radio frequency controllers
|
|
radio_frequency = 0x01,
|
|
_,
|
|
};
|
|
|
|
// Only meaningful when the subclass is radio_frequency
|
|
const Protocol = enum(u8) {
|
|
// Bluetooth programming interface
|
|
bluetooth = 0x01,
|
|
// Ultra-wideband radio control
|
|
ultra_wideband = 0x02,
|
|
// Remote NDIS
|
|
remote_ndis = 0x03,
|
|
// Bluetooth AMP controller
|
|
bluetooth_amp = 0x04,
|
|
_,
|
|
};
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.miscellaneous.
|
|
const miscellaneous = struct {
|
|
const SubClass = enum(u8) {
|
|
// Common class
|
|
common = 0x02,
|
|
_,
|
|
};
|
|
|
|
// Only meaningful when the subclass is common
|
|
const Protocol = enum(u8) {
|
|
// Interface association descriptor: at the device level, announces that the
|
|
// configuration groups interfaces into functions with IADs
|
|
interface_association = 0x01,
|
|
_,
|
|
};
|
|
};
|
|
|
|
// Subclass and protocol codes qualified by Class.application_specific.
|
|
const application_specific = struct {
|
|
const SubClass = enum(u8) {
|
|
// Device firmware upgrade
|
|
firmware_upgrade = 0x01,
|
|
// IrDA bridge
|
|
irda_bridge = 0x02,
|
|
// Test and measurement
|
|
test_and_measurement = 0x03,
|
|
_,
|
|
};
|
|
};
|
|
|
|
test "class codes match the USB-IF assignments" {
|
|
const std = @import("std");
|
|
const expectEqual = std.testing.expectEqual;
|
|
|
|
try expectEqual(0x03, @intFromEnum(Class.hid));
|
|
try expectEqual(0x09, @intFromEnum(Class.hub));
|
|
try expectEqual(0xFF, @intFromEnum(Class.vendor_specific));
|
|
|
|
// A typical flash drive: mass storage, transparent SCSI, bulk-only transport.
|
|
try expectEqual(0x06, @intFromEnum(mass_storage.SubClass.scsi));
|
|
try expectEqual(0x50, @intFromEnum(mass_storage.Protocol.bulk_only));
|
|
|
|
// A boot keyboard: HID, boot subclass, keyboard protocol.
|
|
try expectEqual(0x01, @intFromEnum(hid.SubClass.boot));
|
|
try expectEqual(0x01, @intFromEnum(hid.Protocol.keyboard));
|
|
|
|
// Class codes are non-exhaustive: unlisted values pass through undamaged.
|
|
const unknown: Class = @enumFromInt(0x42);
|
|
try expectEqual(0x42, @intFromEnum(unknown));
|
|
|
|
_ = hub.Protocol.hi_speed_multi_tt;
|
|
_ = communications.SubClass.abstract_control;
|
|
_ = wireless_controller.Protocol.bluetooth;
|
|
_ = miscellaneous.Protocol.interface_association;
|
|
_ = application_specific.SubClass.firmware_upgrade;
|
|
}
|