mirror of
https://github.com/linux-msm/qdl.git
synced 2026-02-25 13:12:25 -08:00
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 <d.leo@arduino.cc> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
This commit is contained in:
committed by
Bjorn Andersson
parent
516a75ff89
commit
b9ad4ceaf8
16
firehose.c
16
firehose.c
@@ -642,7 +642,6 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
|
||||
size_t left;
|
||||
int ret;
|
||||
int n;
|
||||
bool expect_empty;
|
||||
|
||||
buf = malloc(qdl->max_payload_size);
|
||||
if (!buf)
|
||||
@@ -681,8 +680,7 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
|
||||
t0 = time(NULL);
|
||||
|
||||
left = read_op->num_sectors;
|
||||
expect_empty = false;
|
||||
while (left > 0 || expect_empty) {
|
||||
while (left > 0) {
|
||||
chunk_size = MIN(qdl->max_payload_size / sector_size, left);
|
||||
|
||||
n = qdl_read(qdl, buf, chunk_size * sector_size, 30000);
|
||||
@@ -690,13 +688,7 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
|
||||
err(1, "failed to read");
|
||||
}
|
||||
|
||||
if (n == 0 && expect_empty) {
|
||||
// Every second transfer is empty during this stage.
|
||||
expect_empty = false;
|
||||
continue;
|
||||
} else if (expect_empty) {
|
||||
err(1, "expected empty transfer but received non-empty transfer during read");
|
||||
} else if ((size_t)n != chunk_size * sector_size) {
|
||||
if ((size_t)n != chunk_size * sector_size) {
|
||||
err(1, "failed to read full sector");
|
||||
}
|
||||
|
||||
@@ -715,10 +707,6 @@ static int firehose_issue_read(struct qdl_device *qdl, struct read_op *read_op,
|
||||
}
|
||||
|
||||
left -= chunk_size;
|
||||
#ifndef _WIN32
|
||||
// on mac/linux, every other response is empty
|
||||
expect_empty = true;
|
||||
#endif
|
||||
|
||||
if (!quiet)
|
||||
ux_progress("%s", read_op->num_sectors - left, read_op->num_sectors, read_op->filename);
|
||||
|
||||
8
usb.c
8
usb.c
@@ -244,6 +244,14 @@ static int usb_read(struct qdl_device *qdl, void *buf, size_t len, unsigned int
|
||||
if (ret == LIBUSB_ERROR_TIMEOUT && actual == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
/* If what we read equals the endpoint's Max Packet Size, consume the ZLP explicitly */
|
||||
if ((len == actual) && !(actual % qdl_usb->in_maxpktsize)) {
|
||||
ret = libusb_bulk_transfer(qdl_usb->usb_handle, qdl_usb->in_ep,
|
||||
NULL, 0, NULL, timeout);
|
||||
if (ret)
|
||||
warnx("Unable to read ZLP: %s", libusb_strerror(ret));
|
||||
}
|
||||
|
||||
return actual;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user