usb: don't 'correct' SuperSpeed EP0 max packet size — it's an exponent
Regression from the B3 MPS0 work, caught on real hardware: a SuperSpeed hub (and the SuperSpeed boot stick) failed to enumerate. bMaxPacketSize0 (device descriptor byte 7) is a LITERAL size for USB 2.0 and below (8/16/32/64) but an EXPONENT for SuperSpeed (9 = 2^9 = 512). The refresh read the exponent 9 as a size and issued Evaluate Context to set EP0 to 9 bytes, corrupting the control endpoint so every following transfer failed. SuperSpeed's EP0 is fixed at 512 and needs no correction, so the refresh is now skipped for speed >= 4; only full/low/high speed, where the field is a literal that can differ from the speed default, still run it. QEMU tolerated the wrong MPS0 — real silicon does not (the class of bug the harness can't reach, flagged real-HW-pending). This likely also explains intermittent no-storage/no-logs on a normal boot: the boot stick is SuperSpeed and hit the same corruption. Full suite green (orderly-shutdown's lone failure was its known QMP-timing flake — three clean re-runs).
This commit is contained in:
@@ -807,6 +807,15 @@ pub const Controller = struct {
|
||||
/// MPS0; QEMU forgives it — the classic full-speed-mouse-on-real-hardware
|
||||
/// failure (M20).
|
||||
fn refreshMaxPacketSize0(self: *Controller, device: *Device) bool {
|
||||
// SuperSpeed (and above) fix EP0's max packet size at 512, and encode
|
||||
// bMaxPacketSize0 as an EXPONENT (9 = 2^9 = 512), not a literal size —
|
||||
// the default is already correct and byte 7 must NOT be read as a size.
|
||||
// Only full/low/high speed carry a literal 8/16/32/64 that can differ
|
||||
// from the speed default and need this correction. (Reading the SS
|
||||
// exponent as a size set EP0 to 9 bytes and broke every following
|
||||
// transfer — a SuperSpeed hub failing to enumerate on real hardware.)
|
||||
if (device.speed >= 4) return true;
|
||||
|
||||
var head: [8]u8 = undefined;
|
||||
const request = usb_abi.getDescriptor(.device, 0, 0, 8);
|
||||
if (!self.controlTransfer(device, request, head[0..], true)) return false;
|
||||
|
||||
Reference in New Issue
Block a user