19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include "compat.h"
49a747e4fSDavid du Colombier #include "kbd.h"
59a747e4fSDavid du Colombier #include "error.h"
69a747e4fSDavid du Colombier
79a747e4fSDavid du Colombier typedef struct Queue Queue;
89a747e4fSDavid du Colombier struct Queue
99a747e4fSDavid du Colombier {
109a747e4fSDavid du Colombier QLock qwait;
119a747e4fSDavid du Colombier Rendez rwait;
129a747e4fSDavid du Colombier
139a747e4fSDavid du Colombier Lock lock;
149a747e4fSDavid du Colombier int notempty;
159a747e4fSDavid du Colombier char buf[1024];
169a747e4fSDavid du Colombier char *w;
179a747e4fSDavid du Colombier char *r;
189a747e4fSDavid du Colombier char *e;
199a747e4fSDavid du Colombier };
209a747e4fSDavid du Colombier
219a747e4fSDavid du Colombier Queue* kbdq; /* unprocessed console input */
229a747e4fSDavid du Colombier Queue* lineq; /* processed console input */
239a747e4fSDavid du Colombier Snarf snarf = {
249a747e4fSDavid du Colombier .vers = 1
259a747e4fSDavid du Colombier };
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier static struct
289a747e4fSDavid du Colombier {
299a747e4fSDavid du Colombier QLock;
309a747e4fSDavid du Colombier int raw; /* true if we shouldn't process input */
319a747e4fSDavid du Colombier int ctl; /* number of opens to the control file */
329a747e4fSDavid du Colombier int x; /* index into line */
339a747e4fSDavid du Colombier char line[1024]; /* current input line */
349a747e4fSDavid du Colombier } kbd;
359a747e4fSDavid du Colombier
369a747e4fSDavid du Colombier /*
379a747e4fSDavid du Colombier * cheapo fixed-length queues
389a747e4fSDavid du Colombier */
399a747e4fSDavid du Colombier static void
qwrite(Queue * q,void * v,int n)409a747e4fSDavid du Colombier qwrite(Queue *q, void *v, int n)
419a747e4fSDavid du Colombier {
429a747e4fSDavid du Colombier char *buf, *next;
439a747e4fSDavid du Colombier int i;
449a747e4fSDavid du Colombier
459a747e4fSDavid du Colombier buf = v;
469a747e4fSDavid du Colombier lock(&q->lock);
479a747e4fSDavid du Colombier for(i = 0; i < n; i++){
489a747e4fSDavid du Colombier next = q->w+1;
499a747e4fSDavid du Colombier if(next >= q->e)
509a747e4fSDavid du Colombier next = q->buf;
519a747e4fSDavid du Colombier if(next == q->r)
529a747e4fSDavid du Colombier break;
539a747e4fSDavid du Colombier *q->w = buf[i];
549a747e4fSDavid du Colombier q->w = next;
559a747e4fSDavid du Colombier }
569a747e4fSDavid du Colombier q->notempty = 1;
579a747e4fSDavid du Colombier unlock(&q->lock);
589a747e4fSDavid du Colombier rendwakeup(&q->rwait);
599a747e4fSDavid du Colombier }
609a747e4fSDavid du Colombier
619a747e4fSDavid du Colombier static int
qcanread(void * vq)629a747e4fSDavid du Colombier qcanread(void *vq)
639a747e4fSDavid du Colombier {
649a747e4fSDavid du Colombier Queue *q;
659a747e4fSDavid du Colombier int ne;
669a747e4fSDavid du Colombier
679a747e4fSDavid du Colombier q = vq;
689a747e4fSDavid du Colombier lock(&q->lock);
699a747e4fSDavid du Colombier ne = q->notempty;
709a747e4fSDavid du Colombier unlock(&q->lock);
719a747e4fSDavid du Colombier return ne;
729a747e4fSDavid du Colombier }
739a747e4fSDavid du Colombier
749a747e4fSDavid du Colombier static int
qread(Queue * q,void * v,int n)759a747e4fSDavid du Colombier qread(Queue *q, void *v, int n)
769a747e4fSDavid du Colombier {
779a747e4fSDavid du Colombier char *a;
789a747e4fSDavid du Colombier int nn, notempty;
799a747e4fSDavid du Colombier
809a747e4fSDavid du Colombier if(n == 0)
819a747e4fSDavid du Colombier return 0;
829a747e4fSDavid du Colombier a = v;
839a747e4fSDavid du Colombier nn = 0;
849a747e4fSDavid du Colombier for(;;){
859a747e4fSDavid du Colombier lock(&q->lock);
869a747e4fSDavid du Colombier
879a747e4fSDavid du Colombier while(nn < n && q->r != q->w){
889a747e4fSDavid du Colombier a[nn++] = *q->r++;
899a747e4fSDavid du Colombier if(q->r >= q->e)
909a747e4fSDavid du Colombier q->r = q->buf;
919a747e4fSDavid du Colombier }
929a747e4fSDavid du Colombier
939a747e4fSDavid du Colombier notempty = q->notempty;
949a747e4fSDavid du Colombier q->notempty = q->r != q->w;
959a747e4fSDavid du Colombier unlock(&q->lock);
969a747e4fSDavid du Colombier if(notempty)
979a747e4fSDavid du Colombier break;
989a747e4fSDavid du Colombier
999a747e4fSDavid du Colombier /*
1009a747e4fSDavid du Colombier * wait for something to show up in the kbd buffer.
1019a747e4fSDavid du Colombier */
1029a747e4fSDavid du Colombier qlock(&q->qwait);
1039a747e4fSDavid du Colombier if(waserror()){
1049a747e4fSDavid du Colombier qunlock(&q->qwait);
1059a747e4fSDavid du Colombier nexterror();
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier rendsleep(&q->rwait, qcanread, q);
1089a747e4fSDavid du Colombier qunlock(&q->qwait);
1099a747e4fSDavid du Colombier poperror();
1109a747e4fSDavid du Colombier }
1119a747e4fSDavid du Colombier return nn;
1129a747e4fSDavid du Colombier }
1139a747e4fSDavid du Colombier
1149a747e4fSDavid du Colombier static Queue *
mkqueue(void)1159a747e4fSDavid du Colombier mkqueue(void)
1169a747e4fSDavid du Colombier {
1179a747e4fSDavid du Colombier Queue *q;
1189a747e4fSDavid du Colombier
1199a747e4fSDavid du Colombier q = smalloc(sizeof(Queue));
1209a747e4fSDavid du Colombier q->r = q->buf;
1219a747e4fSDavid du Colombier q->w = q->r;
1229a747e4fSDavid du Colombier q->e = &q->buf[sizeof q->buf];
1239a747e4fSDavid du Colombier q->notempty = 0;
1249a747e4fSDavid du Colombier return q;
1259a747e4fSDavid du Colombier }
1269a747e4fSDavid du Colombier
1279a747e4fSDavid du Colombier static void
echoscreen(char * buf,int n)1289a747e4fSDavid du Colombier echoscreen(char *buf, int n)
1299a747e4fSDavid du Colombier {
1309a747e4fSDavid du Colombier char *e, *p;
1319a747e4fSDavid du Colombier char ebuf[128];
1329a747e4fSDavid du Colombier int x;
1339a747e4fSDavid du Colombier
1349a747e4fSDavid du Colombier p = ebuf;
1359a747e4fSDavid du Colombier e = ebuf + sizeof(ebuf) - 4;
1369a747e4fSDavid du Colombier while(n-- > 0){
1379a747e4fSDavid du Colombier if(p >= e){
1389a747e4fSDavid du Colombier screenputs(ebuf, p - ebuf);
1399a747e4fSDavid du Colombier p = ebuf;
1409a747e4fSDavid du Colombier }
1419a747e4fSDavid du Colombier x = *buf++;
1429a747e4fSDavid du Colombier if(x == 0x15){
1439a747e4fSDavid du Colombier *p++ = '^';
1449a747e4fSDavid du Colombier *p++ = 'U';
1459a747e4fSDavid du Colombier *p++ = '\n';
1469a747e4fSDavid du Colombier } else
1479a747e4fSDavid du Colombier *p++ = x;
1489a747e4fSDavid du Colombier }
1499a747e4fSDavid du Colombier if(p != ebuf)
1509a747e4fSDavid du Colombier screenputs(ebuf, p - ebuf);
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier
1539a747e4fSDavid du Colombier /*
1549a747e4fSDavid du Colombier * Put character, possibly a rune, into read queue at interrupt time.
1559a747e4fSDavid du Colombier * Called at interrupt time to process a character.
1569a747e4fSDavid du Colombier */
1579a747e4fSDavid du Colombier void
kbdputc(int ch)1589a747e4fSDavid du Colombier kbdputc(int ch)
1599a747e4fSDavid du Colombier {
1609a747e4fSDavid du Colombier int n;
161*82726826SDavid du Colombier char buf[UTFmax];
1629a747e4fSDavid du Colombier Rune r;
1639a747e4fSDavid du Colombier
1649a747e4fSDavid du Colombier r = ch;
1659a747e4fSDavid du Colombier n = runetochar(buf, &r);
1669a747e4fSDavid du Colombier qwrite(kbdq, buf, n);
1679a747e4fSDavid du Colombier if(!kbd.raw)
1689a747e4fSDavid du Colombier echoscreen(buf, n);
1699a747e4fSDavid du Colombier }
1709a747e4fSDavid du Colombier
1719a747e4fSDavid du Colombier static void
kbdputcinit(void)1729a747e4fSDavid du Colombier kbdputcinit(void)
1739a747e4fSDavid du Colombier {
1749a747e4fSDavid du Colombier kbdq = mkqueue();
1759a747e4fSDavid du Colombier lineq = mkqueue();
1769a747e4fSDavid du Colombier kbd.raw = 0;
1779a747e4fSDavid du Colombier kbd.ctl = 0;
1789a747e4fSDavid du Colombier kbd.x = 0;
1799a747e4fSDavid du Colombier }
1809a747e4fSDavid du Colombier
1819a747e4fSDavid du Colombier enum{
1829a747e4fSDavid du Colombier Qdir,
1839a747e4fSDavid du Colombier Qcons,
1849a747e4fSDavid du Colombier Qconsctl,
1859a747e4fSDavid du Colombier Qsnarf,
1869a747e4fSDavid du Colombier Qwinname,
1879a747e4fSDavid du Colombier };
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier static Dirtab consdir[]={
1909a747e4fSDavid du Colombier ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
1919a747e4fSDavid du Colombier "cons", {Qcons}, 0, 0660,
1929a747e4fSDavid du Colombier "consctl", {Qconsctl}, 0, 0220,
1939a747e4fSDavid du Colombier "snarf", {Qsnarf}, 0, 0600,
1949a747e4fSDavid du Colombier "winname", {Qwinname}, 0, 0000,
1959a747e4fSDavid du Colombier };
1969a747e4fSDavid du Colombier
1979a747e4fSDavid du Colombier static void
consinit(void)1989a747e4fSDavid du Colombier consinit(void)
1999a747e4fSDavid du Colombier {
2009a747e4fSDavid du Colombier kbdputcinit();
2019a747e4fSDavid du Colombier }
2029a747e4fSDavid du Colombier
2039a747e4fSDavid du Colombier static Chan*
consattach(char * spec)2049a747e4fSDavid du Colombier consattach(char *spec)
2059a747e4fSDavid du Colombier {
2069a747e4fSDavid du Colombier return devattach('c', spec);
2079a747e4fSDavid du Colombier }
2089a747e4fSDavid du Colombier
2099a747e4fSDavid du Colombier static Walkqid*
conswalk(Chan * c,Chan * nc,char ** name,int nname)2109a747e4fSDavid du Colombier conswalk(Chan *c, Chan *nc, char **name, int nname)
2119a747e4fSDavid du Colombier {
2129a747e4fSDavid du Colombier return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
2139a747e4fSDavid du Colombier }
2149a747e4fSDavid du Colombier
2159a747e4fSDavid du Colombier static int
consstat(Chan * c,uchar * dp,int n)2169a747e4fSDavid du Colombier consstat(Chan *c, uchar *dp, int n)
2179a747e4fSDavid du Colombier {
2189a747e4fSDavid du Colombier return devstat(c, dp, n, consdir, nelem(consdir), devgen);
2199a747e4fSDavid du Colombier }
2209a747e4fSDavid du Colombier
2219a747e4fSDavid du Colombier static Chan*
consopen(Chan * c,int omode)2229a747e4fSDavid du Colombier consopen(Chan *c, int omode)
2239a747e4fSDavid du Colombier {
2249a747e4fSDavid du Colombier c->aux = nil;
2259a747e4fSDavid du Colombier c = devopen(c, omode, consdir, nelem(consdir), devgen);
2269a747e4fSDavid du Colombier switch((ulong)c->qid.path){
2279a747e4fSDavid du Colombier case Qconsctl:
2289a747e4fSDavid du Colombier qlock(&kbd);
2299a747e4fSDavid du Colombier kbd.ctl++;
2309a747e4fSDavid du Colombier qunlock(&kbd);
2319a747e4fSDavid du Colombier break;
2329a747e4fSDavid du Colombier case Qsnarf:
2338aafde0cSDavid du Colombier if((c->mode&3) == OWRITE || (c->mode&3) == ORDWR)
2349a747e4fSDavid du Colombier c->aux = smalloc(sizeof(Snarf));
2359a747e4fSDavid du Colombier break;
2369a747e4fSDavid du Colombier }
2379a747e4fSDavid du Colombier return c;
2389a747e4fSDavid du Colombier }
2399a747e4fSDavid du Colombier
2409a747e4fSDavid du Colombier void
setsnarf(char * buf,int n,int * vers)241d9306527SDavid du Colombier setsnarf(char *buf, int n, int *vers)
2429a747e4fSDavid du Colombier {
2439a747e4fSDavid du Colombier int i;
2449a747e4fSDavid du Colombier
2459a747e4fSDavid du Colombier qlock(&snarf);
2469a747e4fSDavid du Colombier snarf.vers++;
247d9306527SDavid du Colombier if(vers)
248d9306527SDavid du Colombier *vers = snarf.vers;
2499a747e4fSDavid du Colombier for(i = 0; i < nelem(consdir); i++){
2509a747e4fSDavid du Colombier if(consdir[i].qid.type == Qsnarf){
2519a747e4fSDavid du Colombier consdir[i].qid.vers = snarf.vers;
2529a747e4fSDavid du Colombier break;
2539a747e4fSDavid du Colombier }
2549a747e4fSDavid du Colombier }
2559a747e4fSDavid du Colombier free(snarf.buf);
2569a747e4fSDavid du Colombier snarf.n = n;
2579a747e4fSDavid du Colombier snarf.buf = buf;
2589a747e4fSDavid du Colombier qunlock(&snarf);
2599a747e4fSDavid du Colombier }
2609a747e4fSDavid du Colombier
2619a747e4fSDavid du Colombier static void
consclose(Chan * c)2629a747e4fSDavid du Colombier consclose(Chan *c)
2639a747e4fSDavid du Colombier {
2649a747e4fSDavid du Colombier Snarf *t;
2659a747e4fSDavid du Colombier
2669a747e4fSDavid du Colombier switch((ulong)c->qid.path){
2679a747e4fSDavid du Colombier /* last close of control file turns off raw */
2689a747e4fSDavid du Colombier case Qconsctl:
2699a747e4fSDavid du Colombier if(c->flag&COPEN){
2709a747e4fSDavid du Colombier qlock(&kbd);
2719a747e4fSDavid du Colombier if(--kbd.ctl == 0)
2729a747e4fSDavid du Colombier kbd.raw = 0;
2739a747e4fSDavid du Colombier qunlock(&kbd);
2749a747e4fSDavid du Colombier }
2759a747e4fSDavid du Colombier break;
2769a747e4fSDavid du Colombier /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
2779a747e4fSDavid du Colombier case Qsnarf:
2789a747e4fSDavid du Colombier t = c->aux;
2799a747e4fSDavid du Colombier if(t == nil)
2809a747e4fSDavid du Colombier break;
281d9306527SDavid du Colombier setsnarf(t->buf, t->n, 0);
282e6c6b7f8SDavid du Colombier t->buf = nil; /* setsnarf took it */
283f8e525acSDavid du Colombier free(t);
284f8e525acSDavid du Colombier c->aux = nil;
2859a747e4fSDavid du Colombier break;
2869a747e4fSDavid du Colombier }
2879a747e4fSDavid du Colombier }
2889a747e4fSDavid du Colombier
2899a747e4fSDavid du Colombier static long
consread(Chan * c,void * buf,long n,vlong off)2909a747e4fSDavid du Colombier consread(Chan *c, void *buf, long n, vlong off)
2919a747e4fSDavid du Colombier {
29273e742d7SDavid du Colombier char ch;
2938aafde0cSDavid du Colombier int send;
2949a747e4fSDavid du Colombier
2959a747e4fSDavid du Colombier if(n <= 0)
2969a747e4fSDavid du Colombier return n;
2979a747e4fSDavid du Colombier switch((ulong)c->qid.path){
2989a747e4fSDavid du Colombier case Qsnarf:
2999a747e4fSDavid du Colombier qlock(&snarf);
3009a747e4fSDavid du Colombier if(off < snarf.n){
3019a747e4fSDavid du Colombier if(off + n > snarf.n)
3029a747e4fSDavid du Colombier n = snarf.n - off;
3039a747e4fSDavid du Colombier memmove(buf, snarf.buf+off, n);
3049a747e4fSDavid du Colombier }else
3059a747e4fSDavid du Colombier n = 0;
3069a747e4fSDavid du Colombier qunlock(&snarf);
3079a747e4fSDavid du Colombier return n;
3089a747e4fSDavid du Colombier
3099a747e4fSDavid du Colombier case Qdir:
3109a747e4fSDavid du Colombier return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
3119a747e4fSDavid du Colombier
3129a747e4fSDavid du Colombier case Qcons:
3139a747e4fSDavid du Colombier qlock(&kbd);
3149a747e4fSDavid du Colombier if(waserror()){
3159a747e4fSDavid du Colombier qunlock(&kbd);
3169a747e4fSDavid du Colombier nexterror();
3179a747e4fSDavid du Colombier }
3189a747e4fSDavid du Colombier while(!qcanread(lineq)){
3198aafde0cSDavid du Colombier qread(kbdq, &ch, 1);
3208aafde0cSDavid du Colombier send = 0;
3218aafde0cSDavid du Colombier if(ch == 0){
3228aafde0cSDavid du Colombier /* flush output on rawoff -> rawon */
3238aafde0cSDavid du Colombier if(kbd.x > 0)
3248aafde0cSDavid du Colombier send = !qcanread(kbdq);
3258aafde0cSDavid du Colombier }else if(kbd.raw){
3268aafde0cSDavid du Colombier kbd.line[kbd.x++] = ch;
3278aafde0cSDavid du Colombier send = !qcanread(kbdq);
3288aafde0cSDavid du Colombier }else{
3299a747e4fSDavid du Colombier switch(ch){
3309a747e4fSDavid du Colombier case '\b':
3318aafde0cSDavid du Colombier if(kbd.x > 0)
3329a747e4fSDavid du Colombier kbd.x--;
3339a747e4fSDavid du Colombier break;
3348aafde0cSDavid du Colombier case 0x15: /* ^U */
3359a747e4fSDavid du Colombier kbd.x = 0;
3369a747e4fSDavid du Colombier break;
3379a747e4fSDavid du Colombier case '\n':
3388aafde0cSDavid du Colombier case 0x04: /* ^D */
3398aafde0cSDavid du Colombier send = 1;
3409a747e4fSDavid du Colombier default:
3418aafde0cSDavid du Colombier if(ch != 0x04)
3429a747e4fSDavid du Colombier kbd.line[kbd.x++] = ch;
3439a747e4fSDavid du Colombier break;
3449a747e4fSDavid du Colombier }
3458aafde0cSDavid du Colombier }
3468aafde0cSDavid du Colombier if(send || kbd.x == sizeof kbd.line){
3479a747e4fSDavid du Colombier qwrite(lineq, kbd.line, kbd.x);
3489a747e4fSDavid du Colombier kbd.x = 0;
3499a747e4fSDavid du Colombier }
3509a747e4fSDavid du Colombier }
3519a747e4fSDavid du Colombier n = qread(lineq, buf, n);
3529a747e4fSDavid du Colombier qunlock(&kbd);
3539a747e4fSDavid du Colombier poperror();
3549a747e4fSDavid du Colombier return n;
3559a747e4fSDavid du Colombier
3569a747e4fSDavid du Colombier default:
3579a747e4fSDavid du Colombier print("consread 0x%llux\n", c->qid.path);
3589a747e4fSDavid du Colombier error(Egreg);
3599a747e4fSDavid du Colombier }
3609a747e4fSDavid du Colombier return -1; /* never reached */
3619a747e4fSDavid du Colombier }
3629a747e4fSDavid du Colombier
3639a747e4fSDavid du Colombier static long
conswrite(Chan * c,void * va,long n,vlong)3649a747e4fSDavid du Colombier conswrite(Chan *c, void *va, long n, vlong)
3659a747e4fSDavid du Colombier {
3669a747e4fSDavid du Colombier Snarf *t;
3679a747e4fSDavid du Colombier char buf[256], *a;
3688aafde0cSDavid du Colombier char ch;
3699a747e4fSDavid du Colombier
3709a747e4fSDavid du Colombier switch((ulong)c->qid.path){
3719a747e4fSDavid du Colombier case Qcons:
3729a747e4fSDavid du Colombier screenputs(va, n);
3739a747e4fSDavid du Colombier break;
3749a747e4fSDavid du Colombier
3759a747e4fSDavid du Colombier case Qconsctl:
3769a747e4fSDavid du Colombier if(n >= sizeof(buf))
3779a747e4fSDavid du Colombier n = sizeof(buf)-1;
3789a747e4fSDavid du Colombier strncpy(buf, va, n);
3799a747e4fSDavid du Colombier buf[n] = 0;
3809a747e4fSDavid du Colombier for(a = buf; a;){
3819a747e4fSDavid du Colombier if(strncmp(a, "rawon", 5) == 0){
3829a747e4fSDavid du Colombier kbd.raw = 1;
3838aafde0cSDavid du Colombier /* clumsy hack - wake up reader */
3848aafde0cSDavid du Colombier ch = 0;
3858aafde0cSDavid du Colombier qwrite(kbdq, &ch, 1);
3869a747e4fSDavid du Colombier } else if(strncmp(a, "rawoff", 6) == 0){
3879a747e4fSDavid du Colombier kbd.raw = 0;
3889a747e4fSDavid du Colombier }
3899a747e4fSDavid du Colombier if(a = strchr(a, ' '))
3909a747e4fSDavid du Colombier a++;
3919a747e4fSDavid du Colombier }
3929a747e4fSDavid du Colombier break;
3939a747e4fSDavid du Colombier
3949a747e4fSDavid du Colombier case Qsnarf:
3959a747e4fSDavid du Colombier t = c->aux;
3969a747e4fSDavid du Colombier /* always append only */
3979a747e4fSDavid du Colombier if(t->n > MAXSNARF) /* avoid thrashing when people cut huge text */
3989a747e4fSDavid du Colombier error("snarf buffer too big");
3999a747e4fSDavid du Colombier a = realloc(t->buf, t->n + n + 1);
4009a747e4fSDavid du Colombier if(a == nil)
4019a747e4fSDavid du Colombier error("snarf buffer too big");
4029a747e4fSDavid du Colombier t->buf = a;
4039a747e4fSDavid du Colombier memmove(t->buf+t->n, va, n);
4049a747e4fSDavid du Colombier t->n += n;
4059a747e4fSDavid du Colombier t->buf[t->n] = '\0';
4069a747e4fSDavid du Colombier break;
4079a747e4fSDavid du Colombier default:
4089a747e4fSDavid du Colombier print("conswrite: 0x%llux\n", c->qid.path);
4099a747e4fSDavid du Colombier error(Egreg);
4109a747e4fSDavid du Colombier }
4119a747e4fSDavid du Colombier return n;
4129a747e4fSDavid du Colombier }
4139a747e4fSDavid du Colombier
4149a747e4fSDavid du Colombier Dev consdevtab = {
4159a747e4fSDavid du Colombier 'c',
4169a747e4fSDavid du Colombier "cons",
4179a747e4fSDavid du Colombier
4189a747e4fSDavid du Colombier devreset,
4199a747e4fSDavid du Colombier consinit,
4209a747e4fSDavid du Colombier consattach,
4219a747e4fSDavid du Colombier conswalk,
4229a747e4fSDavid du Colombier consstat,
4239a747e4fSDavid du Colombier consopen,
4249a747e4fSDavid du Colombier devcreate,
4259a747e4fSDavid du Colombier consclose,
4269a747e4fSDavid du Colombier consread,
4279a747e4fSDavid du Colombier devbread,
4289a747e4fSDavid du Colombier conswrite,
4299a747e4fSDavid du Colombier devbwrite,
4309a747e4fSDavid du Colombier devremove,
4319a747e4fSDavid du Colombier devwstat,
4329a747e4fSDavid du Colombier };
433