ftdi: make the timeout be based on actual real time

bperrybap reported on github that the ftdi timeouts can be excessive:

  "the timeout period while waiting for read data to be 10x or even 100x
   longer than it should be when there are read issues on the data cable
   particularly when using Android and USB OTG cables. i.e. a 5 second
   read timeout for not receiving data can be as long as 7 minutes"

and the reason is that the code at one point tried to use the regular
"gettimeofday()" to handle timeouts, but that doesn't exist in Windows.

We already have Windows-specific code to sleep for a number of
milliseconds in "ftdi_serial_sleep()", let's just extend that same
concept and add a "ftdi_serial_get_msec()" that returns the number of
msec's since some arbitrary point in time.

On Windows, that's just "GetTickCount()", and in sane environments it's
just a trivial wrapper around gettimeofday() to turn sec/usec into msec.

NOTE! The actual msec value doesn't have any meaning.  Only the
difference between two calls to ftdi_serial_get_msec() is meaningful.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2018-10-07 12:41:21 -07:00 committed by Dirk Hohndel
parent 9e3a22c522
commit 7618240009

View file

@ -103,6 +103,20 @@ static dc_status_t serial_ftdi_get_transmitted (ftdi_serial_t *device)
return DC_STATUS_UNSUPPORTED;
}
/*
* Get an msec value on some random base
*/
static unsigned int serial_ftdi_get_msec(void)
{
#ifdef _WIN32
return GetTickCount();
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}
static dc_status_t serial_ftdi_sleep (void *io, unsigned int timeout)
{
ftdi_serial_t *device = io;
@ -390,8 +404,7 @@ static dc_status_t serial_ftdi_read (void *io, void *data, size_t size, size_t *
if (timeout == -1)
timeout = 10000;
int backoff = 1;
int slept = 0;
unsigned int start_time = serial_ftdi_get_msec();
unsigned int nbytes = 0;
while (nbytes < size) {
int n = ftdi_read_data (device->ftdi_ctx, (unsigned char *) data + nbytes, size - nbytes);
@ -401,12 +414,11 @@ static dc_status_t serial_ftdi_read (void *io, void *data, size_t size, size_t *
ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
return DC_STATUS_IO; //Error during read call.
} else if (n == 0) {
if (slept >= timeout) {
if (serial_ftdi_get_msec() - start_time > timeout) {
ERROR(device->context, "%s", "FTDI read timed out.");
return DC_STATUS_TIMEOUT;
}
serial_ftdi_sleep (device, backoff);
slept += backoff;
serial_ftdi_sleep (device, 1);
}
nbytes += n;