usb-device-cdc: Fix lost data in read() path if short reads happened.

If the CDC receive buffer was full and some code read less than 64 bytes
(wMaxTransferSize), the CDC code would submit an OUT transfer with N<64
bytes length to fill the buffer back up.

However if the host had more than N bytes to send then it would still send
the full 64 bytes (correctly) in the transfer. The remaining (64-N) bytes
would be lost.

Adds the restriction that CDCInterface rxbuf has to be at least 64 bytes.

Fixes issue #885.

This work was funded through GitHub Sponsors.

Signed-off-by: Angus Gratton <angus@redyak.com.au>
pull/886/head
Angus Gratton 2024-06-18 17:17:46 +10:00 zatwierdzone przez Damien George
rodzic b5aa5f0d1b
commit 0a91a37563
2 zmienionych plików z 8 dodań i 4 usunięć

Wyświetl plik

@ -1,3 +1,3 @@
metadata(version="0.1.0")
metadata(version="0.1.1")
require("usb-device")
package("usb")

Wyświetl plik

@ -144,8 +144,8 @@ class CDCInterface(io.IOBase, Interface):
if flow != 0:
raise NotImplementedError # UART flow control currently not supported
if not (txbuf and rxbuf):
raise ValueError # Buffer sizes are required
if not (txbuf and rxbuf >= _BULK_EP_LEN):
raise ValueError # Buffer sizes are required, rxbuf must be at least one EP
self._timeout = timeout
self._wb = Buffer(txbuf)
@ -330,7 +330,11 @@ class CDCInterface(io.IOBase, Interface):
def _rd_xfer(self):
# Keep an active data OUT transfer to read data from the host,
# whenever the receive buffer has room for new data
if self.is_open() and not self.xfer_pending(self.ep_d_out) and self._rb.writable():
if (
self.is_open()
and not self.xfer_pending(self.ep_d_out)
and self._rb.writable() >= _BULK_EP_LEN
):
# Can only submit up to the endpoint length per transaction, otherwise we won't
# get any transfer callback until the full transaction completes.
self.submit_xfer(self.ep_d_out, self._rb.pend_write(_BULK_EP_LEN), self._rd_cb)