WIP: USB
This commit is contained in:
@@ -0,0 +1,264 @@
|
||||
//! 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;
|
||||
}
|
||||
Reference in New Issue
Block a user