|  | /* Copyright (c) 2020 Google Inc | 
|  | * Barret Rhoden <brho@cs.berkeley.edu> | 
|  | * See LICENSE for details. | 
|  | * | 
|  | * #template.  Dummy device with a devdir table. | 
|  | */ | 
|  |  | 
|  | #include <ns.h> | 
|  | #include <kmalloc.h> | 
|  | #include <string.h> | 
|  | #include <stdio.h> | 
|  | #include <assert.h> | 
|  | #include <error.h> | 
|  |  | 
|  | struct dev template_devtab; | 
|  |  | 
|  | static char *devname(void) | 
|  | { | 
|  | return template_devtab.name; | 
|  | } | 
|  |  | 
|  | enum { | 
|  | Qdir, | 
|  | Qctl, | 
|  | }; | 
|  |  | 
|  | static struct dirtab XXX_dir[] = { | 
|  | {".", {Qdir, 0, QTDIR}, 0, DMDIR | 0555}, | 
|  | {"ctl", {Qctl, 0, QTFILE}, 0, 0666}, | 
|  | }; | 
|  |  | 
|  | static struct chan *XXX_attach(char *spec) | 
|  | { | 
|  | return devattach(devname(), spec); | 
|  | } | 
|  |  | 
|  | static struct walkqid *XXX_walk(struct chan *c, struct chan *nc, char **name, | 
|  | unsigned int nname) | 
|  | { | 
|  | return devwalk(c, nc, name, nname, XXX_dir, ARRAY_SIZE(XXX_dir), | 
|  | devgen); | 
|  | } | 
|  |  | 
|  | static size_t XXX_stat(struct chan *c, uint8_t *db, size_t n) | 
|  | { | 
|  | return devstat(c, db, n, XXX_dir, ARRAY_SIZE(XXX_dir), devgen); | 
|  | } | 
|  |  | 
|  | static struct chan *XXX_open(struct chan *c, int omode) | 
|  | { | 
|  | return devopen(c, omode, XXX_dir, ARRAY_SIZE(XXX_dir), devgen); | 
|  | } | 
|  |  | 
|  | static void XXX_close(struct chan *c) | 
|  | { | 
|  | /* If you do anything after open, only undo it for COPEN chans */ | 
|  | if (!(c->flag & COPEN)) | 
|  | return; | 
|  | } | 
|  |  | 
|  | static size_t XXX_read(struct chan *c, void *ubuf, size_t n, off64_t offset) | 
|  | { | 
|  | switch (c->qid.path) { | 
|  | case Qdir: | 
|  | return devdirread(c, ubuf, n, XXX_dir, ARRAY_SIZE(XXX_dir), | 
|  | devgen); | 
|  | case Qctl: | 
|  | return readstr(offset, ubuf, n, "XXX"); | 
|  | default: | 
|  | panic("Bad Qid %p!", c->qid.path); | 
|  | } | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | #define XXX_CTL_USAGE "start|stop|print|reset" | 
|  |  | 
|  | static void XXX_ctl_cmd(struct chan *c, struct cmdbuf *cb) | 
|  | { | 
|  | ERRSTACK(1); | 
|  |  | 
|  | if (cb->nf < 1) | 
|  | error(EFAIL, XXX_CTL_USAGE); | 
|  |  | 
|  | if (waserror()) { | 
|  | nexterror(); | 
|  | } | 
|  | if (!strcmp(cb->f[0], "start")) { | 
|  | ; | 
|  | } else if (!strcmp(cb->f[0], "stop")) { | 
|  | ; | 
|  | } else if (!strcmp(cb->f[0], "print")) { | 
|  | ; | 
|  | } else if (!strcmp(cb->f[0], "reset")) { | 
|  | ; | 
|  | } else { | 
|  | error(EFAIL, XXX_CTL_USAGE); | 
|  | } | 
|  | poperror(); | 
|  | } | 
|  |  | 
|  | static size_t XXX_write(struct chan *c, void *ubuf, size_t n, off64_t unused) | 
|  | { | 
|  | ERRSTACK(1); | 
|  | struct cmdbuf *cb = parsecmd(ubuf, n); | 
|  |  | 
|  | if (waserror()) { | 
|  | kfree(cb); | 
|  | nexterror(); | 
|  | } | 
|  | switch (c->qid.path) { | 
|  | case Qctl: | 
|  | XXX_ctl_cmd(c, cb); | 
|  | break; | 
|  | default: | 
|  | error(EFAIL, "Unable to write to %s", devname()); | 
|  | } | 
|  | kfree(cb); | 
|  | poperror(); | 
|  | return n; | 
|  | } | 
|  |  | 
|  | struct dev template_devtab __devtab = { | 
|  | .name = "template", | 
|  | .reset = devreset, | 
|  | .init = devinit, | 
|  | .shutdown = devshutdown, | 
|  | .attach = XXX_attach, | 
|  | .walk = XXX_walk, | 
|  | .stat = XXX_stat, | 
|  | .open = XXX_open, | 
|  | .create = devcreate, | 
|  | .close = XXX_close, | 
|  | .read = XXX_read, | 
|  | .bread = devbread, | 
|  | .write = XXX_write, | 
|  | .bwrite = devbwrite, | 
|  | .remove = devremove, | 
|  | .wstat = devwstat, | 
|  | .power = devpower, | 
|  | .chaninfo = devchaninfo, | 
|  | }; |