summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-02-08 08:27:01 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2016-02-08 08:27:01 +0100
commitc0735348802c29cc46db3758b5e477f2bc8ff058 (patch)
tree957d0ef3824de67e6c1ba48002f8ff008d1d81ae /common
parenta22f59c178355ea3efe376739591a43c8ac877d1 (diff)
parent36d5eea256ff81ddb108180f655dd6921fe70e8d (diff)
downloadbarebox-c0735348802c29cc46db3758b5e477f2bc8ff058.tar.gz
barebox-c0735348802c29cc46db3758b5e477f2bc8ff058.tar.xz
Merge branch 'for-next/ratp'
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig10
-rw-r--r--common/Makefile2
-rw-r--r--common/console.c25
-rw-r--r--common/ratp.c511
4 files changed, 545 insertions, 3 deletions
diff --git a/common/Kconfig b/common/Kconfig
index 345de505c0..fc3ed8e57d 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -620,6 +620,16 @@ config PBL_CONSOLE
must be running at the address it's linked at and bss must
be cleared. On ARM that would be after setup_c().
+config CONSOLE_RATP
+ bool
+ select RATP
+ prompt "RATP console support"
+ help
+ This option adds support for remote controlling barebox via serial
+ port. The regular console is designed for human interaction whereas
+ this option adds a machine readable interface for controlling barebox.
+ Say yes here if you want to control barebox from a remote host.
+
config PARTITION
bool
prompt "Enable Partitions"
diff --git a/common/Makefile b/common/Makefile
index ffaf8e7b42..d99ca7b7ac 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_RESET_SOURCE) += reset_source.o
obj-$(CONFIG_SHELL_HUSH) += hush.o
obj-$(CONFIG_SHELL_SIMPLE) += parser.o
obj-$(CONFIG_STATE) += state.o
+obj-$(CONFIG_RATP) += ratp.o
obj-$(CONFIG_UIMAGE) += image.o uimage.o
obj-$(CONFIG_FITIMAGE) += image-fit.o
obj-$(CONFIG_MENUTREE) += menutree.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_IMD) += imd.o
obj-$(CONFIG_FILE_LIST) += file-list.o
obj-$(CONFIG_FIRMWARE) += firmware.o
obj-$(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB) += imx-bbu-nand-fcb.o
+obj-$(CONFIG_CONSOLE_RATP) += ratp.o
quiet_cmd_pwd_h = PWDH $@
ifdef CONFIG_PASSWORD
diff --git a/common/console.c b/common/console.c
index 4a1d2576d0..a541892583 100644
--- a/common/console.c
+++ b/common/console.c
@@ -31,6 +31,7 @@
#include <kfifo.h>
#include <module.h>
#include <poller.h>
+#include <ratp_bb.h>
#include <magicvar.h>
#include <globalvar.h>
#include <linux/list.h>
@@ -313,8 +314,16 @@ static int getc_raw(void)
if (!(cdev->f_active & CONSOLE_STDIN))
continue;
active = 1;
- if (cdev->tstc(cdev))
- return cdev->getc(cdev);
+ if (cdev->tstc(cdev)) {
+ int ch = cdev->getc(cdev);
+
+ if (IS_ENABLED(CONFIG_RATP) && ch == 0x01) {
+ barebox_ratp(cdev);
+ return -1;
+ }
+
+ return ch;
+ }
}
if (!active)
/* no active console found. bail out */
@@ -349,16 +358,26 @@ int getc(void)
start = get_time_ns();
while (1) {
if (tstc_raw()) {
- kfifo_putc(console_input_fifo, getc_raw());
+ int c = getc_raw();
+
+ if (c < 0)
+ break;
+
+ kfifo_putc(console_input_fifo, c);
start = get_time_ns();
}
+
if (is_timeout(start, 100 * USECOND) &&
kfifo_len(console_input_fifo))
break;
}
+ if (!kfifo_len(console_input_fifo))
+ return -1;
+
kfifo_getc(console_input_fifo, &ch);
+
return ch;
}
EXPORT_SYMBOL(getc);
diff --git a/common/ratp.c b/common/ratp.c
new file mode 100644
index 0000000000..2fef3cc0fe
--- /dev/null
+++ b/common/ratp.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2015 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "barebox-ratp: " fmt
+
+#include <common.h>
+#include <command.h>
+#include <kfifo.h>
+#include <malloc.h>
+#include <init.h>
+#include <ratp.h>
+#include <command.h>
+#include <byteorder.h>
+#include <environment.h>
+#include <kfifo.h>
+#include <poller.h>
+#include <linux/sizes.h>
+#include <ratp_bb.h>
+#include <fs.h>
+
+#define BB_RATP_TYPE_COMMAND 1
+#define BB_RATP_TYPE_COMMAND_RETURN 2
+#define BB_RATP_TYPE_CONSOLEMSG 3
+#define BB_RATP_TYPE_PING 4
+#define BB_RATP_TYPE_PONG 5
+#define BB_RATP_TYPE_GETENV 6
+#define BB_RATP_TYPE_GETENV_RETURN 7
+#define BB_RATP_TYPE_FS 8
+#define BB_RATP_TYPE_FS_RETURN 9
+
+struct ratp_bb {
+ uint16_t type;
+ uint16_t flags;
+ uint8_t data[];
+};
+
+struct ratp_bb_command_return {
+ uint32_t errno;
+};
+
+struct ratp_ctx {
+ struct console_device *cdev;
+ struct ratp ratp;
+ int ratp_status;
+ struct console_device ratp_console;
+ int have_synch;
+ int in_ratp_console;
+
+ u8 sendbuf[256];
+ u8 sendbuf_len;
+
+ int old_active;
+
+ struct kfifo *console_recv_fifo;
+ struct kfifo *console_transmit_fifo;
+
+ struct ratp_bb_pkt *fs_rx;
+
+ struct poller_struct poller;
+};
+
+static int console_recv(struct ratp *r, uint8_t *data)
+{
+ struct ratp_ctx *ctx = container_of(r, struct ratp_ctx, ratp);
+ struct console_device *cdev = ctx->cdev;
+
+ if (ctx->have_synch) {
+ ctx->have_synch = 0;
+ *data = 0x01;
+ return 0;
+ }
+
+ if (!cdev->tstc(cdev))
+ return -EAGAIN;
+
+ *data = cdev->getc(cdev);
+
+ return 0;
+}
+
+static int console_send(struct ratp *r, void *pkt, int len)
+{
+ struct ratp_ctx *ctx = container_of(r, struct ratp_ctx, ratp);
+ struct console_device *cdev = ctx->cdev;
+ const uint8_t *buf = pkt;
+ int i;
+
+ for (i = 0; i < len; i++)
+ cdev->putc(cdev, buf[i]);
+
+ return 0;
+}
+
+static void *xmemdup_add_zero(const void *buf, int len)
+{
+ void *ret;
+
+ ret = xzalloc(len + 1);
+ *(uint8_t *)(ret + len) = 0;
+ memcpy(ret, buf, len);
+
+ return ret;
+}
+
+static void ratp_queue_console_tx(struct ratp_ctx *ctx)
+{
+ u8 buf[255];
+ struct ratp_bb *rbb = (void *)buf;
+ unsigned int now, maxlen = 255 - sizeof(*rbb);
+ int ret;
+
+ rbb->type = cpu_to_be16(BB_RATP_TYPE_CONSOLEMSG);
+
+ while (1) {
+ now = min(maxlen, kfifo_len(ctx->console_transmit_fifo));
+ if (!now)
+ break;
+
+ kfifo_get(ctx->console_transmit_fifo, rbb->data, now);
+
+ ret = ratp_send(&ctx->ratp, rbb, now + sizeof(*rbb));
+ if (ret)
+ return;
+ }
+}
+
+static int ratp_bb_send_command_return(struct ratp_ctx *ctx, uint32_t errno)
+{
+ void *buf;
+ struct ratp_bb *rbb;
+ struct ratp_bb_command_return *rbb_ret;
+ int len = sizeof(*rbb) + sizeof(*rbb_ret);
+ int ret;
+
+ ratp_queue_console_tx(ctx);
+
+ buf = xzalloc(len);
+ rbb = buf;
+ rbb_ret = buf + sizeof(*rbb);
+
+ rbb->type = cpu_to_be16(BB_RATP_TYPE_COMMAND_RETURN);
+ rbb_ret->errno = cpu_to_be32(errno);
+
+ ret = ratp_send(&ctx->ratp, buf, len);
+
+ free(buf);
+
+ return ret;
+}
+
+static int ratp_bb_send_pong(struct ratp_ctx *ctx)
+{
+ void *buf;
+ struct ratp_bb *rbb;
+ int len = sizeof(*rbb);
+ int ret;
+
+ buf = xzalloc(len);
+ rbb = buf;
+
+ rbb->type = cpu_to_be16(BB_RATP_TYPE_PONG);
+
+ ret = ratp_send(&ctx->ratp, buf, len);
+
+ free(buf);
+
+ return ret;
+}
+
+static int ratp_bb_send_getenv_return(struct ratp_ctx *ctx, const char *val)
+{
+ void *buf;
+ struct ratp_bb *rbb;
+ int len, ret;
+
+ if (!val)
+ val = "";
+
+ len = sizeof(*rbb) + strlen(val);
+ buf = xzalloc(len);
+ rbb = buf;
+ strcpy(rbb->data, val);
+
+ rbb->type = cpu_to_be16(BB_RATP_TYPE_GETENV_RETURN);
+
+ ret = ratp_send(&ctx->ratp, buf, len);
+
+ free(buf);
+
+ return ret;
+}
+
+static char *ratp_command;
+static struct ratp_ctx *ratp_command_ctx;
+
+static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len)
+{
+ const struct ratp_bb *rbb = buf;
+ struct ratp_bb_pkt *pkt;
+ int dlen = len - sizeof(struct ratp_bb);
+ char *varname;
+ int ret = 0;
+
+ switch (be16_to_cpu(rbb->type)) {
+ case BB_RATP_TYPE_COMMAND:
+ if (ratp_command)
+ return 0;
+
+ ratp_command = xmemdup_add_zero(&rbb->data, dlen);
+ ratp_command_ctx = ctx;
+ pr_debug("got command: %s\n", ratp_command);
+
+ break;
+
+ case BB_RATP_TYPE_COMMAND_RETURN:
+ case BB_RATP_TYPE_PONG:
+ break;
+
+ case BB_RATP_TYPE_CONSOLEMSG:
+
+ kfifo_put(ctx->console_recv_fifo, rbb->data, dlen);
+ break;
+
+ case BB_RATP_TYPE_PING:
+ ret = ratp_bb_send_pong(ctx);
+ break;
+
+ case BB_RATP_TYPE_GETENV:
+ varname = xmemdup_add_zero(&rbb->data, dlen);
+
+ ret = ratp_bb_send_getenv_return(ctx, getenv(varname));
+ break;
+
+ case BB_RATP_TYPE_FS_RETURN:
+ pkt = xzalloc(sizeof(*pkt) + dlen);
+ pkt->len = dlen;
+ memcpy(pkt->data, &rbb->data, dlen);
+ ctx->fs_rx = pkt;
+ break;
+ default:
+ printf("%s: unhandled packet type 0x%04x\n", __func__, be16_to_cpu(rbb->type));
+ break;
+ }
+
+ return ret;
+}
+
+static int ratp_console_getc(struct console_device *cdev)
+{
+ struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
+ unsigned char c;
+
+ if (!kfifo_len(ctx->console_recv_fifo))
+ return -1;
+
+ kfifo_getc(ctx->console_recv_fifo, &c);
+
+ return c;
+}
+
+static int ratp_console_tstc(struct console_device *cdev)
+{
+ struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
+
+ return kfifo_len(ctx->console_recv_fifo) ? 1 : 0;
+}
+
+static int ratp_console_puts(struct console_device *cdev, const char *s)
+{
+ struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
+ int len = 0;
+
+ len = strlen(s);
+
+ if (ratp_busy(&ctx->ratp))
+ return len;
+
+ kfifo_put(ctx->console_transmit_fifo, s, len);
+
+ return len;
+}
+
+static void ratp_console_putc(struct console_device *cdev, char c)
+{
+ struct ratp_ctx *ctx = container_of(cdev, struct ratp_ctx, ratp_console);
+
+ if (ratp_busy(&ctx->ratp))
+ return;
+
+ kfifo_putc(ctx->console_transmit_fifo, c);
+}
+
+static int ratp_console_register(struct ratp_ctx *ctx)
+{
+ int ret;
+
+ ctx->ratp_console.tstc = ratp_console_tstc;
+ ctx->ratp_console.puts = ratp_console_puts;
+ ctx->ratp_console.putc = ratp_console_putc;
+ ctx->ratp_console.getc = ratp_console_getc;
+ ctx->ratp_console.devname = "ratpconsole";
+ ctx->ratp_console.devid = DEVICE_ID_SINGLE;
+
+ ret = console_register(&ctx->ratp_console);
+ if (ret) {
+ pr_err("registering failed with %s\n", strerror(-ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+void ratp_run_command(void)
+{
+ int ret;
+
+ if (!ratp_command)
+ return;
+
+ pr_debug("running command: %s\n", ratp_command);
+
+ ret = run_command(ratp_command);
+
+ free(ratp_command);
+ ratp_command = NULL;
+
+ ratp_bb_send_command_return(ratp_command_ctx, ret);
+}
+
+static const char *ratpfs_mount_path;
+
+int barebox_ratp_fs_mount(const char *path)
+{
+ if (path && ratpfs_mount_path)
+ return -EBUSY;
+
+ ratpfs_mount_path = path;
+
+ return 0;
+}
+
+static void ratp_console_unregister(struct ratp_ctx *ctx)
+{
+ int ret;
+
+ console_set_active(&ctx->ratp_console, 0);
+ poller_unregister(&ctx->poller);
+ ratp_close(&ctx->ratp);
+ console_set_active(ctx->cdev, ctx->old_active);
+ ctx->cdev = NULL;
+
+ if (ratpfs_mount_path) {
+ ret = umount(ratpfs_mount_path);
+ if (!ret)
+ ratpfs_mount_path = NULL;
+ }
+}
+
+static void ratp_poller(struct poller_struct *poller)
+{
+ struct ratp_ctx *ctx = container_of(poller, struct ratp_ctx, poller);
+ int ret;
+ size_t len;
+ void *buf;
+
+ ratp_queue_console_tx(ctx);
+
+ ret = ratp_poll(&ctx->ratp);
+ if (ret == -EINTR)
+ goto out;
+ if (ratp_closed(&ctx->ratp))
+ goto out;
+
+ ret = ratp_recv(&ctx->ratp, &buf, &len);
+ if (ret < 0)
+ return;
+
+ ratp_bb_dispatch(ctx, buf, len);
+
+ free(buf);
+
+ return;
+
+out:
+ ratp_console_unregister(ctx);
+}
+
+static int do_ratp_close(int argc, char *argv[])
+{
+ if (ratp_command_ctx && ratp_command_ctx->cdev)
+ ratp_console_unregister(ratp_command_ctx);
+ else
+ printf("ratp is not active\n");
+
+ return 0;
+}
+
+BAREBOX_CMD_START(ratp_close)
+ .cmd = do_ratp_close,
+};
+
+int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx)
+{
+ struct ratp_ctx *ctx = ratp_command_ctx;
+ struct ratp_bb *rbb;
+ int len;
+ u64 start;
+
+ if (!ctx)
+ return -EINVAL;
+
+ ctx->fs_rx = NULL;
+
+ len = sizeof(*rbb) + tx->len;
+ rbb = xzalloc(len);
+ rbb->type = cpu_to_be16(BB_RATP_TYPE_FS);
+ memcpy(rbb->data, tx->data, tx->len);
+
+ if (ratp_send(&ctx->ratp, rbb, len) != 0)
+ pr_debug("failed to send port pkt\n");
+
+ free(rbb);
+
+ start = get_time_ns();
+
+ while (!ctx->fs_rx) {
+ poller_call();
+ if (ratp_closed(&ctx->ratp))
+ return -EIO;
+ if (is_timeout(start, 10 * SECOND))
+ return -ETIMEDOUT;
+ }
+
+ *rx = ctx->fs_rx;
+
+ pr_debug("%s: len %i\n", __func__, ctx->fs_rx->len);
+
+ return 0;
+}
+
+int barebox_ratp(struct console_device *cdev)
+{
+ int ret;
+ struct ratp_ctx *ctx;
+ struct ratp *ratp;
+
+ if (ratp_command_ctx) {
+ ctx = ratp_command_ctx;
+ } else {
+ ctx = xzalloc(sizeof(*ctx));
+ ratp_command_ctx = ctx;
+ ctx->ratp.send = console_send;
+ ctx->ratp.recv = console_recv;
+ ctx->console_recv_fifo = kfifo_alloc(512);
+ ctx->console_transmit_fifo = kfifo_alloc(SZ_128K);
+ ctx->poller.func = ratp_poller;
+ ratp_console_register(ctx);
+ }
+
+ if (ctx->cdev)
+ return -EBUSY;
+
+ ratp = &ctx->ratp;
+
+ ctx->old_active = console_get_active(cdev);
+ console_set_active(cdev, 0);
+
+ ctx->cdev = cdev;
+ ctx->have_synch = 1;
+
+ ret = ratp_establish(ratp, false, 100);
+ if (ret < 0)
+ goto out;
+
+ ret = poller_register(&ctx->poller);
+ if (ret)
+ goto out1;
+
+ console_set_active(&ctx->ratp_console, CONSOLE_STDOUT | CONSOLE_STDERR |
+ CONSOLE_STDIN);
+
+ return 0;
+
+out1:
+ ratp_close(ratp);
+out:
+ console_set_active(ctx->cdev, ctx->old_active);
+ ctx->cdev = NULL;
+
+ return ret;
+}
+
+static void barebox_ratp_close(void)
+{
+ if (ratp_command_ctx && ratp_command_ctx->cdev)
+ ratp_console_unregister(ratp_command_ctx);
+}
+predevshutdown_exitcall(barebox_ratp_close); \ No newline at end of file