//! USB Mass Storage Bulk-Only Transport (BOT) wire structures โ€” the Command and //! Command Status Wrappers that bracket every command (USB MSC BOT ยง5). Pure data //! definitions, host-testable in isolation. The command inside the CBW is a SCSI //! CDB (see scsi.zig); the transport here just carries it and reports status. //! //! One command is three bulk transfers: CBW out, an optional data stage, CSW in. const std = @import("std"); /// "USBC" โ€” the signature at the head of every Command Block Wrapper. pub const cbw_signature: u32 = 0x43425355; /// "USBS" โ€” the signature at the head of every Command Status Wrapper. pub const csw_signature: u32 = 0x53425355; /// CBW `flags`: set for a device-to-host (IN) data stage, clear for OUT. pub const flag_data_in: u8 = 0x80; /// The 31-byte Command Block Wrapper, sent on the bulk-OUT endpoint. pub const CommandBlockWrapper = extern struct { signature: u32 align(1) = cbw_signature, tag: u32 align(1), data_transfer_length: u32 align(1), flags: u8, lun: u8, cdb_length: u8, cdb: [16]u8 = [_]u8{0} ** 16, }; /// A device's answer to a command (the CSW `status` byte). pub const CommandStatus = enum(u8) { passed = 0, failed = 1, phase_error = 2, _, }; /// The 13-byte Command Status Wrapper, read from the bulk-IN endpoint. pub const CommandStatusWrapper = extern struct { signature: u32 align(1) = csw_signature, tag: u32 align(1), data_residue: u32 align(1), status: u8, }; comptime { std.debug.assert(@sizeOf(CommandBlockWrapper) == 31); std.debug.assert(@sizeOf(CommandStatusWrapper) == 13); } test "wrapper sizes and signatures match the specification" { const cbw = CommandBlockWrapper{ .tag = 0x11223344, .data_transfer_length = 512, .flags = flag_data_in, .lun = 0, .cdb_length = 10, }; const bytes = std.mem.asBytes(&cbw); try std.testing.expectEqual(@as(usize, 31), bytes.len); // "USBC" little-endian. try std.testing.expectEqualSlices(u8, "USBC", bytes[0..4]); try std.testing.expectEqual(flag_data_in, bytes[12]); const csw = std.mem.bytesToValue(CommandStatusWrapper, &[_]u8{ 0x55, 0x53, 0x42, 0x53, // "USBS" 0x44, 0x33, 0x22, 0x11, // tag 0x00, 0x00, 0x00, 0x00, // residue 0x00, // passed }); try std.testing.expectEqual(csw_signature, csw.signature); try std.testing.expectEqual(@as(u32, 0x11223344), csw.tag); try std.testing.expectEqual(@as(u8, @intFromEnum(CommandStatus.passed)), csw.status); }