//! 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; }