Skip to content

Commit ba94551

Browse files
author
Loic Poulain
committed
firehose/usb: Explicitly handle ZLP on USB read transfers
The assumption that every other Firehose read transfer is null is incorrect. A Zero-Length Packet (ZLP) is only sent when the received transfer size is a multiple of the USB IN endpoint's Max Packet Size. This is a way for the device to indicated end-of-transfer. Unconditionally expecting an empty packet was not an issue with USB 2.0, where the typical 512-byte sector size matches the bulk IN endpoint's Max Packet Size. However, with USB SuperSpeed (Max Packet Size = 1024), attempting to read an empty packet after a 512/1024-byte transfer is unnecessary and fails (timeout), resulting in errors during storage device sector size discovery: ``` waiting for programmer... qdl: failed to read: Resource temporarily unavailable ``` Fix and move ZLP handling to bus-specific code (usb.c). Reported-by: Danilo Leo <[email protected]> Signed-off-by: Loic Poulain <[email protected]>
1 parent a88edc5 commit ba94551

File tree

2 files changed

+10
-14
lines changed

2 files changed

+10
-14
lines changed

firehose.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,6 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
642642
size_t left;
643643
int ret;
644644
int n;
645-
bool expect_empty;
646645

647646
buf = malloc(qdl->max_payload_size);
648647
if (!buf)
@@ -681,22 +680,15 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
681680
t0 = time(NULL);
682681

683682
left = read_op->num_sectors;
684-
expect_empty = false;
685-
while (left > 0 || expect_empty) {
683+
while (left > 0) {
686684
chunk_size = MIN(qdl->max_payload_size / sector_size, left);
687685

688686
n = qdl_read(qdl, buf, chunk_size * sector_size, 30000);
689687
if (n < 0) {
690688
err(1, "failed to read");
691689
}
692690

693-
if (n == 0 && expect_empty) {
694-
// Every second transfer is empty during this stage.
695-
expect_empty = false;
696-
continue;
697-
} else if (expect_empty) {
698-
err(1, "expected empty transfer but received non-empty transfer during read");
699-
} else if ((size_t)n != chunk_size * sector_size) {
691+
if ((size_t)n != chunk_size * sector_size) {
700692
err(1, "failed to read full sector");
701693
}
702694

@@ -715,10 +707,6 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
715707
}
716708

717709
left -= chunk_size;
718-
#ifndef _WIN32
719-
// on mac/linux, every other response is empty
720-
expect_empty = true;
721-
#endif
722710

723711
if (!quiet)
724712
ux_progress("%s", read_op->num_sectors - left, read_op->num_sectors, read_op->filename);

usb.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ static int usb_read(struct qdl_device *qdl, void *buf, size_t len, unsigned int
244244
if (ret == LIBUSB_ERROR_TIMEOUT && actual == 0)
245245
return -ETIMEDOUT;
246246

247+
/* If what we read equals the endpoint's Max Packet Size, consume the ZLP explicitly */
248+
if ((len == actual) && !(actual % qdl_usb->in_maxpktsize)) {
249+
ret = libusb_bulk_transfer(qdl_usb->usb_handle, qdl_usb->in_ep,
250+
NULL, 0, NULL, timeout);
251+
if (ret)
252+
warnx("Unable to read ZLP: %s", libusb_strerror(ret));
253+
}
254+
247255
return actual;
248256
}
249257

0 commit comments

Comments
 (0)