Use readstr() for #device text buffers
[akaros.git] / kern / drivers / dev / regress.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 // regression device.
11 // Currently, has only one file, monitor, which is used to send
12 // commands to the monitor.
13 // TODO: read them back :-)
14
15 #include <slab.h>
16 #include <kmalloc.h>
17 #include <kref.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <assert.h>
21 #include <error.h>
22 #include <cpio.h>
23 #include <pmap.h>
24 #include <smp.h>
25 #include <net/ip.h>
26 #include <monitor.h>
27 #include <ktest.h>
28
29 struct dev regressdevtab;
30
31 static char *devname(void)
32 {
33         return regressdevtab.name;
34 }
35
36 struct regress
37 {
38         spinlock_t lock;
39         struct queue *monitor;
40 };
41 struct regress regress;
42
43 enum{
44         Monitordirqid = 0,
45         Monitordataqid,
46         Monitorctlqid,
47 };
48
49 struct dirtab regresstab[]={
50         {".",           {Monitordirqid, 0, QTDIR},0,    DMDIR|0550},
51         {"mondata",     {Monitordataqid},               0,      0600},
52         {"monctl",      {Monitorctlqid},                0,      0600},
53 };
54
55 static char *ctlcommands = "ktest";
56
57 static struct chan*
58 regressattach(char *spec)
59 {
60         uint32_t n;
61
62         regress.monitor = qopen(2 << 20, 0, 0, 0);
63         if (! regress.monitor) {
64                 printk("monitor allocate failed. No monitor output\n");
65         }
66         return devattach(devname(), spec);
67 }
68
69 static void
70 regressinit(void)
71 {
72 }
73
74 static struct walkqid *regresswalk(struct chan *c, struct chan *nc, char **name,
75                                    unsigned int nname)
76 {
77         return devwalk(c, nc, name, nname, regresstab, ARRAY_SIZE(regresstab),
78                        devgen);
79 }
80
81 static size_t regressstat(struct chan *c, uint8_t *db, size_t n)
82 {
83         if (regress.monitor)
84                 regresstab[Monitordataqid].length = qlen(regress.monitor);
85         else
86                 regresstab[Monitordataqid].length = 0;
87
88         return devstat(c, db, n, regresstab, ARRAY_SIZE(regresstab), devgen);
89 }
90
91 static struct chan*
92 regressopen(struct chan *c, int omode)
93 {
94         if(c->qid.type & QTDIR){
95                 if(openmode(omode) != O_READ)
96                         error(EPERM, ERROR_FIXME);
97         }
98         c->mode = openmode(omode);
99         c->flag |= COPEN;
100         c->offset = 0;
101         return c;
102 }
103
104 static void
105 regressclose(struct chan*unused)
106 {
107 }
108
109 static size_t regressread(struct chan *c, void *va, size_t n, off64_t off)
110 {
111         uint64_t w, *bp;
112         char *a, *ea;
113         uintptr_t offset = off;
114         uint64_t pc;
115         int snp_ret, ret = 0;
116
117         switch((int)c->qid.path){
118         case Monitordirqid:
119                 n = devdirread(c, va, n, regresstab, ARRAY_SIZE(regresstab), devgen);
120                 break;
121
122         case Monitorctlqid:
123                 n = readstr(off, va, n, ctlcommands);
124                 break;
125
126         case Monitordataqid:
127                 if (regress.monitor) {
128                         printd("monitordataqid: regress.monitor %p len %p\n", regress.monitor, qlen(kprof.monitor));
129                         if (qlen(regress.monitor) > 0)
130                                 n = qread(regress.monitor, va, n);
131                         else
132                                 n = 0;
133                 } else
134                         error(EFAIL, "no monitor queue");
135                 break;
136         default:
137                 n = 0;
138                 break;
139         }
140         return n;
141 }
142
143 static size_t regresswrite(struct chan *c, void *a, size_t n, off64_t unused)
144 {
145         ERRSTACK(1);
146         uintptr_t pc;
147         struct cmdbuf *cb;
148         cb = parsecmd(a, n);
149
150         if (waserror()) {
151                 kfree(cb);
152                 nexterror();
153         }
154
155         switch((int)(c->qid.path)){
156         case Monitorctlqid:
157                 if(strncmp(a, "ktest", 5) == 0){
158                         run_registered_ktest_suites();
159                 } else {
160                         error(EFAIL, "regresswrite: only commands are %s", ctlcommands);
161                 }
162                 break;
163
164         case Monitordataqid:
165                 if (onecmd(cb->nf, cb->f, NULL) < 0)
166                         n = -1;
167                 break;
168         default:
169                 error(EBADFD, ERROR_FIXME);
170         }
171         kfree(cb);
172         poperror();
173         return n;
174 }
175
176 struct dev regressdevtab __devtab = {
177         .name = "regress",
178
179         .reset = devreset,
180         .init = regressinit,
181         .shutdown = devshutdown,
182         .attach = regressattach,
183         .walk = regresswalk,
184         .stat = regressstat,
185         .open = regressopen,
186         .create = devcreate,
187         .close = regressclose,
188         .read = regressread,
189         .bread = devbread,
190         .write = regresswrite,
191         .bwrite = devbwrite,
192         .remove = devremove,
193         .wstat = devwstat,
194 };