commit 71c38bc3d65907d2997c23b62fdd13f193b62cee
parent 4eafb8af2fd2454170d0ee08467a2a37090943e8
Author: Ambroise Vincent <ambroise.vincent@arm.com>
Date: Wed, 3 Apr 2019 10:32:15 +0100
[dev] Add console driver
Allow to add and remove outputs from the file system.
Change-Id: Ifbde6cfe6c02c1ffad0cab5b47946b1343feb2bc
Signed-off-by: Ambroise Vincent <ambroise.vincent@arm.com>
Diffstat:
5 files changed, 254 insertions(+), 9 deletions(-)
diff --git a/drivers/dev.h b/drivers/dev.h
@@ -1,7 +1,8 @@
#include <stddef.h>
-#define NR_CHANS 20
+#define NR_CHANS 15
#define NR_UARTS 2
+#define NR_CONSS 1
#define NR_BINDS 4
#define NODEV 255
#define CHDIR (1 << 15)
diff --git a/drivers/devcons.c b/drivers/devcons.c
@@ -0,0 +1,213 @@
+#include <assert.h>
+#include <rcode/rcode.h>
+#include <rcode/9p.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libk.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rcode/dev.h>
+
+#define CONSOUT 2
+#define NAMESIZE 15
+#define CONSSTATUS 128
+
+enum Orootqid {
+ Qconsfs,
+ Qraw,
+ Qctl
+};
+
+static const Dirtab dirtab[] = {
+ {"raw", Qraw, 0, O_READ | O_WRITE},
+ {"ctl", Qctl, 0, O_READ | O_WRITE}
+};
+
+struct cons {
+ Chan *in;
+ char inname[NAMESIZE];
+ Chan *out[CONSOUT];
+ char outname[CONSOUT][NAMESIZE];
+};
+
+static struct cons *cons;
+
+static int
+conswalk(Chan *c, const char *name)
+{
+ return devwalk(c, name, dirtab, NELEM(dirtab), devgen);
+}
+
+static int
+consstatus(void *buf, Chan *c, int n)
+{
+ int i;
+ int len = 0;
+ char tmp[CONSSTATUS];
+
+ if (cons->in)
+ len += ksnprint(tmp, sizeof(tmp),
+ "addin %s\n",
+ cons->inname);
+
+ for (i = 0; i < CONSOUT; i++) {
+ if (cons->out[i])
+ len += ksnprint(tmp + len, sizeof(tmp) - len,
+ "addout %s\n",
+ cons->outname[i]);
+ }
+
+ if (len == sizeof(tmp))
+ panic("consstatus");
+
+ return buf2chan(c, buf, tmp, n, len);
+}
+
+static int
+consaddin(void *buf, int n)
+{
+ if (cons->in || n >= NAMESIZE)
+ return -1;
+
+ cons->in = namec(buf, O_READ);
+ memcpy(cons->inname, buf, n);
+ return 0;
+}
+
+static int
+consaddout(void *buf, int n)
+{
+ int i;
+
+ if (n >= NAMESIZE)
+ return -1;
+
+ for (i = 0; i < CONSOUT; i++) {
+ if (!cons->out[i]) {
+ cons->out[i] = namec(buf, O_WRITE);
+ memcpy(cons->outname[i], buf, n);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+consdelin(void *buf, int n)
+{
+ if (!cons->in || memcmp(buf, cons->inname, n))
+ return -1;
+
+ chanclose(cons->in);
+ cons->in = NULL;
+ cons->inname[0] = '\0';
+ return 0;
+}
+
+static int
+consdelout(void *buf, int n)
+{
+ int i;
+
+ for (i = 0; i < CONSOUT; i++) {
+ if (cons->out[i] && !memcmp(buf, cons->outname[i], n)) {
+ chanclose(cons->out[i]);
+ cons->out[i] = NULL;
+ cons->outname[i][0] = '\0';
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+conswrite(Chan *c, void *buf, int n)
+{
+ char *tokens[2];
+ int written, i;
+ Chan *p;
+ Chan **pp;
+ int (*func)(void *, int);
+
+ struct conscmds {
+ const char name[7];
+ int (*func)(void *, int);
+ };
+
+ const struct conscmds conscmds[] = {
+ {"addin", consaddin},
+ {"addout", consaddout},
+ {"delin", consdelin},
+ {"delout", consdelout}
+ };
+
+ switch (c->qid & ~CHDIR) {
+ case Qconsfs:
+ return -1;
+ case Qraw:
+ written = -1;
+ for (pp = cons->out; pp < &cons->out[CONSOUT]; pp++) {
+ if ((p = *pp) == NULL)
+ continue;
+ written = devtab[p->type]->write(p, buf, n);
+ }
+ return written;
+ case Qctl:
+ if (tokenize(buf, n, tokens, 2) != 2)
+ return -1;
+ for (i = 0; i < NELEM(conscmds); i++) {
+ if (!strcmp(tokens[0], conscmds[i].name)) {
+ func = conscmds[i].func;
+ return (*func)(tokens[1], strlen(tokens[1]));
+ }
+ }
+ return -1;
+ default:
+ panic("conswrite");
+ }
+}
+
+static int
+consread(Chan *c, void *buf, int n)
+{
+ switch (c->qid & ~CHDIR) {
+ case Qconsfs:
+ return dirread(c, buf, n, dirtab, NELEM(dirtab), devgen);
+ case Qraw: {
+ Chan *in = cons->in;
+ if (cons->in)
+ return devtab[in->type]->read(in, buf, n);
+ return -1;
+ }
+ case Qctl:
+ return consstatus(buf, c, n);
+ default:
+ panic("consread");
+ }
+}
+
+void
+conslink(Attr *attr)
+{
+ size_t siz;
+ Attr *a;
+ int index = 0;
+
+ siz = sizeof(struct cons);
+ cons = memset(alloc(siz), 0, siz);
+
+ for (a = attr; a->key; a++) {
+ if (!strcmp(a->key, "in"))
+ consaddin(a->value, strlen(a->value));
+ else if (!strcmp(a->key, "out") && index < CONSOUT)
+ consaddout(a->value, strlen(a->value));
+ }
+}
+
+const Dev consdevtab = {
+ .id = 's',
+ .walk = conswalk,
+ .read = consread,
+ .write = conswrite,
+};
diff --git a/drivers/devroot.c b/drivers/devroot.c
@@ -7,7 +7,10 @@
enum Orootqid {
Qroot,
Qdev,
- Qdevuart,
+ Qdevuart0,
+ Qdevuart1,
+ Qdevuart2,
+ Qdevuart3,
Qdevcons,
Qrealm,
Qarfs,
@@ -27,7 +30,10 @@ static const Dirtab dirtab[] = {
};
static const Dirtab devfstab[] = {
- {"uart", CHDIR | Qdevuart, 0, O_READ},
+ {"uart0", CHDIR | Qdevuart0, 0, O_READ},
+ {"uart1", CHDIR | Qdevuart1, 0, O_READ},
+ {"uart2", CHDIR | Qdevuart2, 0, O_READ},
+ {"uart3", CHDIR | Qdevuart3, 0, O_READ},
{"cons", CHDIR | Qdevcons, 0, O_READ},
};
diff --git a/target/native/rcode b/target/native/rcode
@@ -1,6 +1,7 @@
dev
root
uart
+ pl011 base=0x1C090000,clk=24000000,rate=115200
pl011 base=0x1c0c0000,clk=24000000,rate=115200
- pl011 base=0x1c0c0100,clk=24000000,rate=115200
+ cons
end
diff --git a/target/native/rom.c b/target/native/rom.c
@@ -93,20 +93,44 @@ info(Mach *mp)
mp->sp, mp->stacksiz);
}
+/*
+ * TODO: This should be in devc.c. The way the rcode file is parsed should be
+ * modified to allow that.
+ */
+typedef struct attr Attr;
+
+struct attr {
+ char *key;
+ char *value;
+};
+
+extern void conslink(Attr *attr);
+
static void
namespace(void)
{
- if (open("#t0/raw", O_READ) != 0)
+ if (open("#s0/raw", O_READ) != 0)
goto error;
- if (open("#t0/raw", O_WRITE) != 1)
+ if (open("#s0/raw", O_WRITE) != 1)
goto error;
- if (open("#t0/raw", O_WRITE) != 2)
+ if (open("#s0/raw", O_WRITE) != 2)
goto error;
- if (bind("#t0", "/dev/uart") < 0)
+ if (bind("#s0", "/dev/cons") < 0)
goto error;
- if (bind("#t0", "/dev/cons") < 0)
+
+ if (bind("#t0", "/dev/uart0") < 0)
goto error;
+ if (bind("#t1", "/dev/uart3") < 0)
+ goto error;
+
+ /*
+ * TODO: This should be in devc.c. The way the rcode file is parsed should be
+ * modified to allow that.
+ */
+ // Link required after bind
+ conslink((Attr []) {{"in", "/dev/uart0/raw"},{"out", "/dev/uart0/raw"},{0}});
+
return;
error: