xref: /plan9/sys/src/cmd/vnc/devcons.c (revision e6c6b7f8757fefe4f788e3998e8ae256bca21dc3)
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