// SPDX-License-Identifier: Apache-2.0 // Copyright (C) 2020 IBM Corp. #include "array.h" #include "console.h" #include "log.h" #include "tty.h" #include "ccan/container_of/container_of.h" #include #include #include #include #include #include #include #define to_tty(console) container_of(console, struct tty, console) struct baud_map { int baud; speed_t speed; }; static const struct baud_map tty_baud_map[] = { { 1200, B1200 }, { 115200, B115200 }, { 0, B0 }, /* Sentinel */ }; static speed_t tty_find_speed(int baud) { int i; for (i = 0; tty_baud_map[i].baud && tty_baud_map[i].baud != baud; i++); return tty_baud_map[i].speed; } static int tty_set_baud(struct console *console, int baud) { struct tty *ctx = to_tty(console); struct termios termios; speed_t speed; int rc; speed = tty_find_speed(baud); if (speed == B0) { loge("Unable to find matching speed for %d\n", baud); return -EINVAL; } /* * We do a sketchy borrow of the fd from the prompt to set the baud rate. * We cache the fd internally so no magic is required */ rc = tcgetattr(ctx->fd, &termios); if (rc < 0) { return -errno; } rc = cfsetospeed(&termios, speed); if (rc < 0) { return -errno; } rc = cfsetispeed(&termios, speed); if (rc < 0) { return -errno; } rc = tcsetattr(ctx->fd, TCSADRAIN, &termios); if (rc < 0) { return -errno; } return 0; } static int tty_destroy(struct console *console) { struct tty *ctx = to_tty(console); free(ctx); return 0; } static const struct console_ops tty_ops = { .destroy = tty_destroy, .set_baud = tty_set_baud, }; /* Ownership of fd passes to the prompt associated with the debug instance */ int tty_init(struct tty *ctx, const char *path) { struct termios termios; ctx->console.ops = &tty_ops; logi("Opening %s\n", path); ctx->fd = open(path, O_RDWR); if (!ctx->fd) { loge("Error opening %s: %d\n", path, strerror(errno)); return -errno; } tcgetattr(ctx->fd, &termios); cfmakeraw(&termios); return ctx->fd; }