aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2020-11-18 15:18:05 -0600
committerRob Landley <rob@landley.net>2020-11-18 15:18:05 -0600
commitc251e32521229b7bd89a765481e2cd3b1ef02357 (patch)
treefad513b38735e8a486badeae8378f75baa96896f
parent0ea04980e327efaf315a58408d926b674b55cb32 (diff)
downloadtoybox-c251e32521229b7bd89a765481e2cd3b1ef02357.tar.gz
Fix microcom to set serial device's terminal correctly.
Can't use the same set_terminal() logic as ptys because it not displaying data, it should just accurately copy it.
-rw-r--r--lib/lib.h1
-rw-r--r--lib/tty.c14
-rw-r--r--toys/net/microcom.c19
3 files changed, 27 insertions, 7 deletions
diff --git a/lib/lib.h b/lib/lib.h
index 150133b6..431ce5ad 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -337,6 +337,7 @@ int terminal_probesize(unsigned *xx, unsigned *yy);
#define KEY_ALT (1<<18)
int scan_key(char *scratch, int timeout_ms);
int scan_key_getsize(char *scratch, int timeout_ms, unsigned *xx, unsigned *yy);
+void xsetspeed(struct termios *tio, int speed);
int set_terminal(int fd, int raw, int speed, struct termios *old);
void xset_terminal(int fd, int raw, int speed, struct termios *old);
void tty_esc(char *s);
diff --git a/lib/tty.c b/lib/tty.c
index a6b4576a..b0d0c5d5 100644
--- a/lib/tty.c
+++ b/lib/tty.c
@@ -61,6 +61,20 @@ int terminal_probesize(unsigned *xx, unsigned *yy)
return 0;
}
+void xsetspeed(struct termios *tio, int speed)
+{
+ int i, speeds[] = {50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800,
+ 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000};
+
+ // Find speed in table, adjust to constant
+ for (i = 0; i < ARRAY_LEN(speeds); i++) if (speeds[i] == speed) break;
+ if (i == ARRAY_LEN(speeds)) error_exit("unknown speed: %d", speed);
+ cfsetspeed(tio, i+1+4081*(i>15));
+}
+
+
// Reset terminal to known state, saving copy of old state if old != NULL.
int set_terminal(int fd, int raw, int speed, struct termios *old)
{
diff --git a/toys/net/microcom.c b/toys/net/microcom.c
index 62b020f2..963445c2 100644
--- a/toys/net/microcom.c
+++ b/toys/net/microcom.c
@@ -22,30 +22,35 @@ config MICROCOM
GLOBALS(
long s;
- int fd;
- struct termios original_stdin_state, original_fd_state;
+ int fd, stok;
+ struct termios old_stdin, old_fd;
)
// TODO: tty_sigreset outputs ansi escape sequences, how to disable?
static void restore_states(int i)
{
- tcsetattr(0, TCSAFLUSH, &TT.original_stdin_state);
- tcsetattr(TT.fd, TCSAFLUSH, &TT.original_fd_state);
+ if (TT.stok) tcsetattr(0, TCSAFLUSH, &TT.old_stdin);
+ tcsetattr(TT.fd, TCSAFLUSH, &TT.old_fd);
}
void microcom_main(void)
{
+ struct termios tio;
struct pollfd fds[2];
int i;
// Open with O_NDELAY, but switch back to blocking for reads.
TT.fd = xopen(*toys.optargs, O_RDWR | O_NOCTTY | O_NDELAY);
- if (-1==(i = fcntl(TT.fd, F_GETFL, 0)) || fcntl(TT.fd, F_SETFL, i&~O_NDELAY))
+ if (-1==(i = fcntl(TT.fd, F_GETFL, 0)) || fcntl(TT.fd, F_SETFL, i&~O_NDELAY)
+ || tcgetattr(TT.fd, &TT.old_fd))
perror_exit_raw(*toys.optargs);
// Set both input and output to raw mode.
- xset_terminal(TT.fd, 1, TT.s, &TT.original_fd_state);
- set_terminal(0, 1, 0, &TT.original_stdin_state);
+ memcpy(&tio, &TT.old_fd, sizeof(struct termios));
+ cfmakeraw(&tio);
+ xsetspeed(&tio, TT.s);
+ if (tcsetattr(TT.fd, TCSAFLUSH, &tio)) perror_exit("set speed");
+ if (!set_terminal(0, 1, 0, &TT.old_stdin)) TT.stok++;
// ...and arrange to restore things, however we may exit.
sigatexit(restore_states);