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 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 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 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 * 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 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 1589a747e4fSDavid du Colombier kbdputc(int ch) 1599a747e4fSDavid du Colombier { 1609a747e4fSDavid du Colombier int n; 1619a747e4fSDavid du Colombier char buf[3]; 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 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 1989a747e4fSDavid du Colombier consinit(void) 1999a747e4fSDavid du Colombier { 2009a747e4fSDavid du Colombier kbdputcinit(); 2019a747e4fSDavid du Colombier } 2029a747e4fSDavid du Colombier 2039a747e4fSDavid du Colombier static Chan* 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* 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 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* 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: 2339a747e4fSDavid du Colombier if(c->mode == OWRITE || c->mode == 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 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 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); 282*e6c6b7f8SDavid 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 2909a747e4fSDavid du Colombier consread(Chan *c, void *buf, long n, vlong off) 2919a747e4fSDavid du Colombier { 2929a747e4fSDavid du Colombier char *cbuf; 2939a747e4fSDavid du Colombier int i, ch, eol; 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 if(kbd.raw){ 3199a747e4fSDavid du Colombier cbuf = buf; 3209a747e4fSDavid du Colombier if(qcanread(lineq)) 3219a747e4fSDavid du Colombier n = qread(lineq, buf, n); 3229a747e4fSDavid du Colombier else { 3239a747e4fSDavid du Colombier /* read as much as possible */ 3249a747e4fSDavid du Colombier do { 3259a747e4fSDavid du Colombier i = qread(kbdq, cbuf, n); 3269a747e4fSDavid du Colombier cbuf += i; 3279a747e4fSDavid du Colombier n -= i; 3289a747e4fSDavid du Colombier } while (n>0 && qcanread(kbdq)); 3299a747e4fSDavid du Colombier n = cbuf - (char*)buf; 3309a747e4fSDavid du Colombier } 3319a747e4fSDavid du Colombier } else { 3329a747e4fSDavid du Colombier while(!qcanread(lineq)){ 3339a747e4fSDavid du Colombier qread(kbdq, &kbd.line[kbd.x], 1); 3349a747e4fSDavid du Colombier ch = kbd.line[kbd.x]; 3359a747e4fSDavid du Colombier eol = 0; 3369a747e4fSDavid du Colombier switch(ch){ 3379a747e4fSDavid du Colombier case '\b': 3389a747e4fSDavid du Colombier if(kbd.x) 3399a747e4fSDavid du Colombier kbd.x--; 3409a747e4fSDavid du Colombier break; 3419a747e4fSDavid du Colombier case 0x15: 3429a747e4fSDavid du Colombier kbd.x = 0; 3439a747e4fSDavid du Colombier break; 3449a747e4fSDavid du Colombier case '\n': 3459a747e4fSDavid du Colombier case 0x04: 3469a747e4fSDavid du Colombier eol = 1; 3479a747e4fSDavid du Colombier default: 3489a747e4fSDavid du Colombier kbd.line[kbd.x++] = ch; 3499a747e4fSDavid du Colombier break; 3509a747e4fSDavid du Colombier } 3519a747e4fSDavid du Colombier if(kbd.x == sizeof(kbd.line) || eol){ 3529a747e4fSDavid du Colombier if(ch == 0x04) 3539a747e4fSDavid du Colombier kbd.x--; 3549a747e4fSDavid du Colombier qwrite(lineq, kbd.line, kbd.x); 3559a747e4fSDavid du Colombier kbd.x = 0; 3569a747e4fSDavid du Colombier } 3579a747e4fSDavid du Colombier } 3589a747e4fSDavid du Colombier n = qread(lineq, buf, n); 3599a747e4fSDavid du Colombier } 3609a747e4fSDavid du Colombier qunlock(&kbd); 3619a747e4fSDavid du Colombier poperror(); 3629a747e4fSDavid du Colombier return n; 3639a747e4fSDavid du Colombier 3649a747e4fSDavid du Colombier default: 3659a747e4fSDavid du Colombier print("consread 0x%llux\n", c->qid.path); 3669a747e4fSDavid du Colombier error(Egreg); 3679a747e4fSDavid du Colombier } 3689a747e4fSDavid du Colombier return -1; /* never reached */ 3699a747e4fSDavid du Colombier } 3709a747e4fSDavid du Colombier 3719a747e4fSDavid du Colombier static long 3729a747e4fSDavid du Colombier conswrite(Chan *c, void *va, long n, vlong) 3739a747e4fSDavid du Colombier { 3749a747e4fSDavid du Colombier Snarf *t; 3759a747e4fSDavid du Colombier char buf[256], *a; 3769a747e4fSDavid du Colombier 3779a747e4fSDavid du Colombier switch((ulong)c->qid.path){ 3789a747e4fSDavid du Colombier case Qcons: 3799a747e4fSDavid du Colombier screenputs(va, n); 3809a747e4fSDavid du Colombier break; 3819a747e4fSDavid du Colombier 3829a747e4fSDavid du Colombier case Qconsctl: 3839a747e4fSDavid du Colombier if(n >= sizeof(buf)) 3849a747e4fSDavid du Colombier n = sizeof(buf)-1; 3859a747e4fSDavid du Colombier strncpy(buf, va, n); 3869a747e4fSDavid du Colombier buf[n] = 0; 3879a747e4fSDavid du Colombier for(a = buf; a;){ 3889a747e4fSDavid du Colombier if(strncmp(a, "rawon", 5) == 0){ 3899a747e4fSDavid du Colombier qlock(&kbd); 3909a747e4fSDavid du Colombier if(kbd.x){ 3919a747e4fSDavid du Colombier qwrite(kbdq, kbd.line, kbd.x); 3929a747e4fSDavid du Colombier kbd.x = 0; 3939a747e4fSDavid du Colombier } 3949a747e4fSDavid du Colombier kbd.raw = 1; 3959a747e4fSDavid du Colombier qunlock(&kbd); 3969a747e4fSDavid du Colombier } else if(strncmp(a, "rawoff", 6) == 0){ 3979a747e4fSDavid du Colombier qlock(&kbd); 3989a747e4fSDavid du Colombier kbd.raw = 0; 3999a747e4fSDavid du Colombier kbd.x = 0; 4009a747e4fSDavid du Colombier qunlock(&kbd); 4019a747e4fSDavid du Colombier } 4029a747e4fSDavid du Colombier if(a = strchr(a, ' ')) 4039a747e4fSDavid du Colombier a++; 4049a747e4fSDavid du Colombier } 4059a747e4fSDavid du Colombier break; 4069a747e4fSDavid du Colombier 4079a747e4fSDavid du Colombier case Qsnarf: 4089a747e4fSDavid du Colombier t = c->aux; 4099a747e4fSDavid du Colombier /* always append only */ 4109a747e4fSDavid du Colombier if(t->n > MAXSNARF) /* avoid thrashing when people cut huge text */ 4119a747e4fSDavid du Colombier error("snarf buffer too big"); 4129a747e4fSDavid du Colombier a = realloc(t->buf, t->n + n + 1); 4139a747e4fSDavid du Colombier if(a == nil) 4149a747e4fSDavid du Colombier error("snarf buffer too big"); 4159a747e4fSDavid du Colombier t->buf = a; 4169a747e4fSDavid du Colombier memmove(t->buf+t->n, va, n); 4179a747e4fSDavid du Colombier t->n += n; 4189a747e4fSDavid du Colombier t->buf[t->n] = '\0'; 4199a747e4fSDavid du Colombier break; 4209a747e4fSDavid du Colombier default: 4219a747e4fSDavid du Colombier print("conswrite: 0x%llux\n", c->qid.path); 4229a747e4fSDavid du Colombier error(Egreg); 4239a747e4fSDavid du Colombier } 4249a747e4fSDavid du Colombier return n; 4259a747e4fSDavid du Colombier } 4269a747e4fSDavid du Colombier 4279a747e4fSDavid du Colombier Dev consdevtab = { 4289a747e4fSDavid du Colombier 'c', 4299a747e4fSDavid du Colombier "cons", 4309a747e4fSDavid du Colombier 4319a747e4fSDavid du Colombier devreset, 4329a747e4fSDavid du Colombier consinit, 4339a747e4fSDavid du Colombier consattach, 4349a747e4fSDavid du Colombier conswalk, 4359a747e4fSDavid du Colombier consstat, 4369a747e4fSDavid du Colombier consopen, 4379a747e4fSDavid du Colombier devcreate, 4389a747e4fSDavid du Colombier consclose, 4399a747e4fSDavid du Colombier consread, 4409a747e4fSDavid du Colombier devbread, 4419a747e4fSDavid du Colombier conswrite, 4429a747e4fSDavid du Colombier devbwrite, 4439a747e4fSDavid du Colombier devremove, 4449a747e4fSDavid du Colombier devwstat, 4459a747e4fSDavid du Colombier }; 446