config: Add support for aspeed-uart-routing config directive
It accepts one or more words of the form SINK:SOURCE, where SOURCE is
written to the file SINK in the aspeed-uart-routing driver's sysfs
directory (they are thus expected to be things like "uart1", "uart2",
"io1", etc.).
Signed-off-by: Zev Weiss <zev@bewilderbeest.net>
Change-Id: Iacbc524340e4b73f3d122bc77670eedb3957a858
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0a0419..3edefa1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,10 @@
## [Unreleased]
+### Added
+
+1. config: Added support for the `aspeed-uart-routing` configuration key
+
### Removed
1. Deprecated D-Bus interface `xyz.openbmc_project.console` is no longer used.
diff --git a/console-server.c b/console-server.c
index 4f894a4..5715589 100644
--- a/console-server.c
+++ b/console-server.c
@@ -28,6 +28,7 @@
#include <err.h>
#include <string.h>
#include <getopt.h>
+#include <glob.h>
#include <limits.h>
#include <time.h>
#include <termios.h>
@@ -386,6 +387,112 @@
free(console->tty.dev);
}
+static int write_to_path(const char *path, const char *data)
+{
+ int rc = 0;
+ FILE *f = fopen(path, "w");
+ if (!f) {
+ return -1;
+ }
+
+ if (fprintf(f, "%s", data) < 0) {
+ rc = -1;
+ }
+
+ if (fclose(f)) {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+#define ASPEED_UART_ROUTING_PATTERN \
+ "/sys/bus/platform/drivers/aspeed-uart-routing/*.uart-routing"
+
+static void uart_routing_init(struct config *config)
+{
+ const char *muxcfg;
+ const char *p;
+ size_t buflen;
+ char *sink;
+ char *source;
+ char *muxdir;
+ char *path;
+ glob_t globbuf;
+
+ muxcfg = config_get_value(config, "aspeed-uart-routing");
+ if (!muxcfg) {
+ return;
+ }
+
+ /* Find the driver's sysfs directory */
+ if (glob(ASPEED_UART_ROUTING_PATTERN, GLOB_ERR | GLOB_NOSORT, NULL,
+ &globbuf) != 0) {
+ warn("Couldn't find uart-routing driver directory, cannot apply config");
+ return;
+ }
+ if (globbuf.gl_pathc != 1) {
+ warnx("Found %zd uart-routing driver directories, cannot apply config",
+ globbuf.gl_pathc);
+ goto out_free_glob;
+ }
+ muxdir = globbuf.gl_pathv[0];
+
+ /*
+ * Rather than faff about tracking a bunch of separate buffer sizes,
+ * just use one (worst-case) size for all of them -- +2 for a trailing
+ * NUL and a '/' separator to construct the sysfs file path.
+ */
+ buflen = strlen(muxdir) + strlen(muxcfg) + 2;
+
+ sink = malloc(buflen);
+ source = malloc(buflen);
+ path = malloc(buflen);
+ if (!path || !sink || !source) {
+ warnx("Out of memory applying uart routing config");
+ goto out_free_bufs;
+ }
+
+ p = muxcfg;
+ while (*p) {
+ ssize_t bytes_scanned;
+
+ if (sscanf(p, " %[^:/ \t]:%[^: \t] %zn", sink, source,
+ &bytes_scanned) != 2) {
+ warnx("Invalid syntax in aspeed uart config: '%s' not applied",
+ p);
+ break;
+ }
+ p += bytes_scanned;
+
+ /*
+ * Check that the sink name looks reasonable before proceeding
+ * (there are other writable files in the same directory that
+ * we shouldn't be touching, such as 'driver_override' and
+ * 'uevent').
+ */
+ if (strncmp(sink, "io", strlen("io")) != 0 &&
+ strncmp(sink, "uart", strlen("uart")) != 0) {
+ warnx("Skipping invalid uart routing name '%s' (must be ioN or uartN)",
+ sink);
+ continue;
+ }
+
+ snprintf(path, buflen, "%s/%s", muxdir, sink);
+ if (write_to_path(path, source)) {
+ warn("Failed to apply uart-routing config '%s:%s'",
+ sink, source);
+ }
+ }
+
+out_free_bufs:
+ free(path);
+ free(source);
+ free(sink);
+out_free_glob:
+ globfree(&globbuf);
+}
+
int console_data_out(struct console *console, const uint8_t *data, size_t len)
{
return write_buf_to_fd(console->tty.fd, data, len);
@@ -835,6 +942,8 @@
goto out_config_fini;
}
+ uart_routing_init(config);
+
rc = tty_init(console, config, config_tty_kname);
if (rc) {
goto out_config_fini;