From a6f0b058349af9abea454623c2144872f1b178d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Thu, 28 Jan 2021 14:37:59 +0100 Subject: [PATCH] usb_host: properly handle ISOC read requests * Update the 'packet_size' information with the actual length for each isoc frame to be able to handle short reads at the client side. * Copy the whole transfer buffer because the host controller stores the data at the original offsets, i.e., the buffer is not densely packed. Fixes #4018. --- repos/dde_linux/src/drivers/usb/raw/raw.cc | 15 +++++++++++++-- repos/dde_linux/src/drivers/usb_host/raw.cc | 15 +++++++++++++-- repos/os/include/usb_session/usb_session.h | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/repos/dde_linux/src/drivers/usb/raw/raw.cc b/repos/dde_linux/src/drivers/usb/raw/raw.cc index ea295ed19d..b469ef76f0 100644 --- a/repos/dde_linux/src/drivers/usb/raw/raw.cc +++ b/repos/dde_linux/src/drivers/usb/raw/raw.cc @@ -278,9 +278,20 @@ class Usb::Worker : public Genode::Weak_object p.transfer.actual_size = urb->actual_length; p.succeded = true; - if (read) + if (read) { + /* make sure the client sees the actual amount of data */ + for (int i = 0; i < urb->number_of_packets; i++) { + p.transfer.actual_packet_size[i] = urb->iso_frame_desc[i].actual_length; + } + + /* + * We have to copy the whole transfer buffer because the + * controller used the offsets into the original buffer to + * store the data. + */ Genode::memcpy(_sink->packet_content(p), urb->transfer_buffer, - urb->actual_length); + urb->transfer_buffer_length); + } } else if (urb->status == -ESHUTDOWN) { p.error = Packet_descriptor::NO_DEVICE_ERROR; } else if ((urb->status == -EPROTO) || (urb->status == -EILSEQ)) { diff --git a/repos/dde_linux/src/drivers/usb_host/raw.cc b/repos/dde_linux/src/drivers/usb_host/raw.cc index 82930d2c8c..dd542a0f25 100644 --- a/repos/dde_linux/src/drivers/usb_host/raw.cc +++ b/repos/dde_linux/src/drivers/usb_host/raw.cc @@ -286,9 +286,20 @@ class Usb::Worker : public Genode::Weak_object p.transfer.actual_size = urb->actual_length; p.succeded = true; - if (read) + if (read) { + /* make sure the client sees the actual amount of data */ + for (int i = 0; i < urb->number_of_packets; i++) { + p.transfer.actual_packet_size[i] = urb->iso_frame_desc[i].actual_length; + } + + /* + * We have to copy the whole transfer buffer because the + * controller used the offsets into the original buffer to + * store the data. + */ Genode::memcpy(_sink->packet_content(p), urb->transfer_buffer, - urb->actual_length); + urb->transfer_buffer_length); + } } else if (urb->status == -ESHUTDOWN) { p.error = Packet_descriptor::NO_DEVICE_ERROR; } else if ((urb->status == -EPROTO) || (urb->status == -EILSEQ)) { diff --git a/repos/os/include/usb_session/usb_session.h b/repos/os/include/usb_session/usb_session.h index a097b0ffd7..c987abbd6e 100644 --- a/repos/os/include/usb_session/usb_session.h +++ b/repos/os/include/usb_session/usb_session.h @@ -68,6 +68,7 @@ struct Usb::Packet_descriptor : Genode::Packet_descriptor int polling_interval; /* for interrupt transfers */ int number_of_packets; size_t packet_size[MAX_PACKETS]; + size_t actual_packet_size[MAX_PACKETS]; } transfer; struct