From ac540b84b5ae5f9c6805d80ec69e0bec9ffc79a3 Mon Sep 17 00:00:00 2001 From: Colin Leroy-Mira Date: Sun, 15 Sep 2024 14:39:17 +0200 Subject: [PATCH] Wait after writing so userland gets expected speed Constrain tty0tty's bandwidth by waiting the required amount of time after writing bytes, so that userland can expect write/read speeds consistent with the current baud rate, data bits, parity and stop bits settings. --- module/tty0tty.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/module/tty0tty.c b/module/tty0tty.c index 96f6e80..03a7455 100644 --- a/module/tty0tty.c +++ b/module/tty0tty.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) #include @@ -97,6 +98,8 @@ struct tty0tty_serial { wait_queue_head_t wait; struct async_icount icount; + /* for timing control */ + u64 nanosecs_per_byte; }; static struct tty0tty_serial **tty0tty_table; /* initially all NULL */ @@ -224,6 +227,8 @@ static int tty0tty_write(struct tty_struct *tty, const unsigned char *buffer, struct tty0tty_serial *tty0tty = tty->driver_data; int retval = 0; struct tty_struct *ttyx = NULL; + u64 elapsed, delay; + ktime_t start_time = ktime_get_ns(); if (!tty0tty) return -ENODEV; @@ -261,6 +266,17 @@ static int tty0tty_write(struct tty_struct *tty, const unsigned char *buffer, retval = count; } + /* Compute time spent pushing this buffer */ + elapsed = ktime_get_ns() - start_time; + + /* Compute how much to wait to make sure this buffer is, from + * userland's point of view, pushed as slow as it would be on + * a real serial port */ + delay = ((count * tty0tty->nanosecs_per_byte) - elapsed) / 1000; + + if (delay > 1) + usleep_range(delay-1, delay); + exit: up(&tty0tty->sem); return retval; @@ -307,10 +323,13 @@ static void tty0tty_set_termios(struct tty_struct *tty, unsigned int iflag; unsigned int bits_per_byte; unsigned int baud_rate; - u64 nanosecs_per_byte; + struct tty0tty_serial *tty0tty = tty->driver_data; DEBUG_PRINTK(KERN_DEBUG "%s - \n", __FUNCTION__); + if (!tty0tty) + return; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) cflag = tty->termios.c_cflag; iflag = tty->termios.c_iflag; @@ -410,8 +429,8 @@ static void tty0tty_set_termios(struct tty_struct *tty, DEBUG_PRINTK(KERN_DEBUG " - baud rate = %d\n", baud_rate); /* get the time a real serial port would require to push a byte */ - nanosecs_per_byte = 1000000000ULL / (baud_rate / bits_per_byte); - DEBUG_PRINTK(KERN_DEBUG " - time per byte = %lluns\n", nanosecs_per_byte); + tty0tty->nanosecs_per_byte = 1000000000ULL / (baud_rate / bits_per_byte); + DEBUG_PRINTK(KERN_DEBUG " - time per byte = %lluns\n", tty0tty->nanosecs_per_byte); } //static int tty0tty_tiocmget(struct tty_struct *tty, struct file *file)