diff options
Diffstat (limited to 'common/ratp/ratp.c')
-rw-r--r-- | common/ratp/ratp.c | 182 |
1 files changed, 112 insertions, 70 deletions
diff --git a/common/ratp/ratp.c b/common/ratp/ratp.c index e84ad22167..fddb286e01 100644 --- a/common/ratp/ratp.c +++ b/common/ratp/ratp.c @@ -1,9 +1,6 @@ /* * 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. @@ -18,18 +15,18 @@ #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 <work.h> #include <linux/sizes.h> #include <ratp_bb.h> #include <fs.h> +#include <console_countdown.h> LIST_HEAD(ratp_command_list); EXPORT_SYMBOL(ratp_command_list); @@ -53,6 +50,11 @@ struct ratp_ctx { struct ratp_bb_pkt *fs_rx; struct poller_struct poller; + struct work_queue wq; + + bool console_registered; + bool poller_registered; + bool wq_registered; }; static int compare_ratp_command(struct list_head *a, struct list_head *b) @@ -100,11 +102,24 @@ static int init_ratp_command_list(void) late_initcall(init_ratp_command_list); +static bool console_exists(struct console_device *cdev) +{ + struct console_device *cs; + + list_for_each_entry(cs, &console_list, list) + if (cs == cdev) + return true; + return false; +} + 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 (!console_exists(cdev)) + return -ENODEV; + if (ctx->have_synch) { ctx->have_synch = 0; *data = 0x01; @@ -126,6 +141,9 @@ static int console_send(struct ratp *r, void *pkt, int len) const uint8_t *buf = pkt; int i; + if (!console_exists(cdev)) + return -ENODEV; + for (i = 0; i < len; i++) cdev->putc(cdev, buf[i]); @@ -178,9 +196,14 @@ static int ratp_bb_send_command_return(struct ratp_ctx *ctx, uint32_t errno) return ret; } -static char *ratp_command; static struct ratp_ctx *ratp_ctx; +struct ratp_work { + struct work_struct work; + struct ratp_ctx *ctx; + char *command; +}; + static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len) { const struct ratp_bb *rbb = buf; @@ -189,6 +212,7 @@ static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len) int ret = 0; uint16_t type = be16_to_cpu(rbb->type); struct ratp_command *cmd; + struct ratp_work *rw; /* See if there's a command registered to this type */ cmd = find_ratp_request(type); @@ -206,12 +230,16 @@ static int ratp_bb_dispatch(struct ratp_ctx *ctx, const void *buf, int len) switch (type) { case BB_RATP_TYPE_COMMAND: - if (!IS_ENABLED(CONFIG_CONSOLE_RATP) || ratp_command) + if (!IS_ENABLED(CONFIG_CONSOLE_RATP)) return 0; - ratp_command = xstrndup((const char *)rbb->data, dlen); - ratp_ctx = ctx; - pr_debug("got command: %s\n", ratp_command); + rw = xzalloc(sizeof(*rw)); + rw->ctx = ctx; + rw->command = xstrndup((const char *)rbb->data, dlen); + + wq_queue_work(&ctx->wq, &rw->work); + + pr_debug("got command: %s\n", rw->command); break; @@ -282,41 +310,20 @@ static void ratp_console_putc(struct console_device *cdev, char c) 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 barebox_ratp_command_run(void) +static void ratp_command_run(struct work_struct *w) { + struct ratp_work *rw = container_of(w, struct ratp_work, work); + struct ratp_ctx *ctx = rw->ctx; int ret; - if (!ratp_command) - return; - - pr_debug("running command: %s\n", ratp_command); + pr_debug("running command: %s\n", rw->command); - ret = run_command(ratp_command); + ret = run_command(rw->command); - free(ratp_command); - ratp_command = NULL; + free(rw->command); + free(rw); - ratp_bb_send_command_return(ratp_ctx, ret); + ratp_bb_send_command_return(ctx, ret); } static const char *ratpfs_mount_path; @@ -331,15 +338,30 @@ int barebox_ratp_fs_mount(const char *path) return 0; } -static void ratp_console_unregister(struct ratp_ctx *ctx) +static void ratp_unregister(struct ratp_ctx *ctx) { int ret; - console_set_active(&ctx->ratp_console, 0); - poller_unregister(&ctx->poller); + if (ctx->console_registered) + console_unregister(&ctx->ratp_console); + + if (ctx->poller_registered) + poller_unregister(&ctx->poller); + + if (ctx->wq_registered) + wq_unregister(&ctx->wq); + ratp_close(&ctx->ratp); console_set_active(ctx->cdev, ctx->old_active); - ctx->cdev = NULL; + + if (ctx->console_recv_fifo) + kfifo_free(ctx->console_recv_fifo); + + if (ctx->console_transmit_fifo) + kfifo_free(ctx->console_transmit_fifo); + + free(ctx); + ratp_ctx = NULL; if (ratpfs_mount_path) { ret = umount(ratpfs_mount_path); @@ -361,6 +383,7 @@ static void ratp_poller(struct poller_struct *poller) ret = ratp_poll(&ctx->ratp); if (ret == -EINTR) goto out; + if (ratp_closed(&ctx->ratp)) goto out; @@ -375,7 +398,7 @@ static void ratp_poller(struct poller_struct *poller) return; out: - ratp_console_unregister(ctx); + ratp_unregister(ctx); } int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx) @@ -403,7 +426,6 @@ int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx) start = get_time_ns(); while (!ctx->fs_rx) { - poller_call(); if (ratp_closed(&ctx->ratp)) return -EIO; if (is_timeout(start, 10 * SECOND)) @@ -417,32 +439,46 @@ int barebox_ratp_fs_call(struct ratp_bb_pkt *tx, struct ratp_bb_pkt **rx) return 0; } +static void ratp_work_cancel(struct work_struct *w) +{ + struct ratp_work *rw = container_of(w, struct ratp_work, work); + + free(rw->command); + free(rw); +} + int barebox_ratp(struct console_device *cdev) { int ret; struct ratp_ctx *ctx; - struct ratp *ratp; if (!cdev->getc || !cdev->putc) return -EINVAL; - if (ratp_ctx) { - ctx = ratp_ctx; - } else { - ctx = xzalloc(sizeof(*ctx)); - ratp_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) + if (ratp_ctx) return -EBUSY; - ratp = &ctx->ratp; + ctx = xzalloc(sizeof(*ctx)); + ratp_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; + 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 console failed with %s\n", strerror(-ret)); + return ret; + } + + ctx->console_registered = true; ctx->old_active = console_get_active(cdev); console_set_active(cdev, 0); @@ -450,31 +486,37 @@ int barebox_ratp(struct console_device *cdev) ctx->cdev = cdev; ctx->have_synch = 1; - ret = ratp_establish(ratp, false, 100); + ret = ratp_establish(&ctx->ratp, false, 1000); if (ret < 0) goto out; - ret = poller_register(&ctx->poller); + ctx->wq.fn = ratp_command_run; + ctx->wq.cancel = ratp_work_cancel; + wq_register(&ctx->wq); + ctx->wq_registered = true; + + ret = poller_register(&ctx->poller, "ratp"); if (ret) - goto out1; + goto out; + + ctx->poller_registered = true; + + console_countdown_abort(); 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; + ratp_unregister(ctx); return ret; } static void barebox_ratp_close(void) { - if (ratp_ctx && ratp_ctx->cdev) - ratp_console_unregister(ratp_ctx); + if (ratp_ctx) + ratp_unregister(ratp_ctx); } predevshutdown_exitcall(barebox_ratp_close); |