74 lines
2.5 KiB
Zig
74 lines
2.5 KiB
Zig
//! 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);
|
|
}
|