xref: /plan9/sys/src/9/omap/devcons.c (revision 047f1f95aa802225c557b6f2f4b096acb12ebb86)
18e32b400SDavid du Colombier #include	"u.h"
28e32b400SDavid du Colombier #include	"../port/lib.h"
38e32b400SDavid du Colombier #include	"mem.h"
48e32b400SDavid du Colombier #include	"dat.h"
58e32b400SDavid du Colombier #include	"fns.h"
68e32b400SDavid du Colombier #include	"../port/error.h"
78e32b400SDavid du Colombier #include	"pool.h"
88e32b400SDavid du Colombier 
98e32b400SDavid du Colombier #include	<authsrv.h>
108e32b400SDavid du Colombier 
118e32b400SDavid du Colombier void	(*consdebug)(void) = nil;
128e32b400SDavid du Colombier void	(*screenputs)(char*, int) = nil;
138e32b400SDavid du Colombier 
148e32b400SDavid du Colombier Queue*	kbdq;			/* unprocessed console input */
158e32b400SDavid du Colombier Queue*	lineq;			/* processed console input */
168e32b400SDavid du Colombier Queue*	serialoq;		/* serial console output */
178e32b400SDavid du Colombier Queue*	kprintoq;		/* console output, for /dev/kprint */
188e32b400SDavid du Colombier ulong	kprintinuse;		/* test and set whether /dev/kprint is open */
198e32b400SDavid du Colombier int	iprintscreenputs = 1;
208e32b400SDavid du Colombier 
218e32b400SDavid du Colombier int	panicking;
228e32b400SDavid du Colombier 
238e32b400SDavid du Colombier static struct
248e32b400SDavid du Colombier {
258e32b400SDavid du Colombier 	QLock;
268e32b400SDavid du Colombier 
278e32b400SDavid du Colombier 	int	raw;		/* true if we shouldn't process input */
288e32b400SDavid du Colombier 	Ref	ctl;		/* number of opens to the control file */
298e32b400SDavid du Colombier 	int	x;		/* index into line */
308e32b400SDavid du Colombier 	char	line[1024];	/* current input line */
318e32b400SDavid du Colombier 
328e32b400SDavid du Colombier 	int	count;
338e32b400SDavid du Colombier 	int	ctlpoff;
348e32b400SDavid du Colombier 
358e32b400SDavid du Colombier 	/* a place to save up characters at interrupt time before dumping them in the queue */
368e32b400SDavid du Colombier 	Lock	lockputc;
378e32b400SDavid du Colombier 	char	istage[1024];
388e32b400SDavid du Colombier 	char	*iw;
398e32b400SDavid du Colombier 	char	*ir;
408e32b400SDavid du Colombier 	char	*ie;
418e32b400SDavid du Colombier } kbd = {
428e32b400SDavid du Colombier 	.iw	= kbd.istage,
438e32b400SDavid du Colombier 	.ir	= kbd.istage,
448e32b400SDavid du Colombier 	.ie	= kbd.istage + sizeof(kbd.istage),
458e32b400SDavid du Colombier };
468e32b400SDavid du Colombier 
478e32b400SDavid du Colombier char	*sysname;
488e32b400SDavid du Colombier vlong	fasthz;
498e32b400SDavid du Colombier 
508e32b400SDavid du Colombier static void	seedrand(void);
518e32b400SDavid du Colombier static int	readtime(ulong, char*, int);
528e32b400SDavid du Colombier static int	readbintime(char*, int);
538e32b400SDavid du Colombier static int	writetime(char*, int);
548e32b400SDavid du Colombier static int	writebintime(char*, int);
558e32b400SDavid du Colombier 
568e32b400SDavid du Colombier enum
578e32b400SDavid du Colombier {
588e32b400SDavid du Colombier 	CMhalt,
598e32b400SDavid du Colombier 	CMreboot,
608e32b400SDavid du Colombier 	CMpanic,
618e32b400SDavid du Colombier };
628e32b400SDavid du Colombier 
638e32b400SDavid du Colombier Cmdtab rebootmsg[] =
648e32b400SDavid du Colombier {
658e32b400SDavid du Colombier 	CMhalt,		"halt",		1,
668e32b400SDavid du Colombier 	CMreboot,	"reboot",	0,
678e32b400SDavid du Colombier 	CMpanic,	"panic",	0,
688e32b400SDavid du Colombier };
698e32b400SDavid du Colombier 
708e32b400SDavid du Colombier void
718e32b400SDavid du Colombier printinit(void)
728e32b400SDavid du Colombier {
738e32b400SDavid du Colombier 	lineq = qopen(2*1024, 0, nil, nil);
748e32b400SDavid du Colombier 	if(lineq == nil)
758e32b400SDavid du Colombier 		panic("printinit");
768e32b400SDavid du Colombier 	qnoblock(lineq, 1);
778e32b400SDavid du Colombier }
788e32b400SDavid du Colombier 
798e32b400SDavid du Colombier int
808e32b400SDavid du Colombier consactive(void)
818e32b400SDavid du Colombier {
828e32b400SDavid du Colombier 	if(serialoq)
838e32b400SDavid du Colombier 		return qlen(serialoq) > 0;
848e32b400SDavid du Colombier 	return 0;
858e32b400SDavid du Colombier }
868e32b400SDavid du Colombier 
878e32b400SDavid du Colombier void
888e32b400SDavid du Colombier prflush(void)
898e32b400SDavid du Colombier {
908e32b400SDavid du Colombier 	ulong now;
918e32b400SDavid du Colombier 
928e32b400SDavid du Colombier 	now = m->ticks;
938e32b400SDavid du Colombier 	while(consactive())
948e32b400SDavid du Colombier 		if(m->ticks - now >= HZ)
958e32b400SDavid du Colombier 			break;
968e32b400SDavid du Colombier }
978e32b400SDavid du Colombier 
988e32b400SDavid du Colombier /*
998e32b400SDavid du Colombier  * Log console output so it can be retrieved via /dev/kmesg.
1008e32b400SDavid du Colombier  * This is good for catching boot-time messages after the fact.
1018e32b400SDavid du Colombier  */
1028e32b400SDavid du Colombier struct {
1038e32b400SDavid du Colombier 	Lock lk;
1048e32b400SDavid du Colombier //	char buf[16384];		/* normal */
1058e32b400SDavid du Colombier 	char buf[256*1024];		/* for acpi debugging */
1068e32b400SDavid du Colombier 	uint n;
1078e32b400SDavid du Colombier } kmesg;
1088e32b400SDavid du Colombier 
1098e32b400SDavid du Colombier static void
1108e32b400SDavid du Colombier kmesgputs(char *str, int n)
1118e32b400SDavid du Colombier {
1128e32b400SDavid du Colombier 	uint nn, d;
1138e32b400SDavid du Colombier 
1148e32b400SDavid du Colombier 	ilock(&kmesg.lk);
1158e32b400SDavid du Colombier 	/* take the tail of huge writes */
1168e32b400SDavid du Colombier 	if(n > sizeof kmesg.buf){
1178e32b400SDavid du Colombier 		d = n - sizeof kmesg.buf;
1188e32b400SDavid du Colombier 		str += d;
1198e32b400SDavid du Colombier 		n -= d;
1208e32b400SDavid du Colombier 	}
1218e32b400SDavid du Colombier 
1228e32b400SDavid du Colombier 	/* slide the buffer down to make room */
1238e32b400SDavid du Colombier 	nn = kmesg.n;
1248e32b400SDavid du Colombier 	if(nn + n >= sizeof kmesg.buf){
1258e32b400SDavid du Colombier 		d = nn + n - sizeof kmesg.buf;
1268e32b400SDavid du Colombier 		if(d)
1278e32b400SDavid du Colombier 			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);
1288e32b400SDavid du Colombier 		nn -= d;
1298e32b400SDavid du Colombier 	}
1308e32b400SDavid du Colombier 
1318e32b400SDavid du Colombier 	/* copy the data in */
1328e32b400SDavid du Colombier 	memmove(kmesg.buf+nn, str, n);
1338e32b400SDavid du Colombier 	nn += n;
1348e32b400SDavid du Colombier 	kmesg.n = nn;
1358e32b400SDavid du Colombier 	iunlock(&kmesg.lk);
1368e32b400SDavid du Colombier }
1378e32b400SDavid du Colombier 
1388e32b400SDavid du Colombier /*
1398e32b400SDavid du Colombier  *   Print a string on the console.  Convert \n to \r\n for serial
1408e32b400SDavid du Colombier  *   line consoles.  Locking of the queues is left up to the screen
1418e32b400SDavid du Colombier  *   or uart code.  Multi-line messages to serial consoles may get
1428e32b400SDavid du Colombier  *   interspersed with other messages.
1438e32b400SDavid du Colombier  */
1448e32b400SDavid du Colombier static void
1458e32b400SDavid du Colombier putstrn0(char *str, int n, int usewrite)
1468e32b400SDavid du Colombier {
1478e32b400SDavid du Colombier #ifdef CRUDEPRINT
1488e32b400SDavid du Colombier 	CRUDEPRINT(str, n);
1498e32b400SDavid du Colombier 	USED(usewrite);
1508e32b400SDavid du Colombier #else
1518e32b400SDavid du Colombier 	int m;
1528e32b400SDavid du Colombier 	char *t;
1538e32b400SDavid du Colombier 
1548e32b400SDavid du Colombier 	if(!islo())
1558e32b400SDavid du Colombier 		usewrite = 0;
1568e32b400SDavid du Colombier 
1578e32b400SDavid du Colombier 	/*
1588e32b400SDavid du Colombier 	 *  how many different output devices do we need?
1598e32b400SDavid du Colombier 	 */
1608e32b400SDavid du Colombier 	kmesgputs(str, n);
1618e32b400SDavid du Colombier 
1628e32b400SDavid du Colombier 	/*
1638e32b400SDavid du Colombier 	 *  if someone is reading /dev/kprint,
1648e32b400SDavid du Colombier 	 *  put the message there.
1658e32b400SDavid du Colombier 	 *  if not and there's an attached bit mapped display,
1668e32b400SDavid du Colombier 	 *  put the message there.
1678e32b400SDavid du Colombier 	 *
1688e32b400SDavid du Colombier 	 *  if there's a serial line being used as a console,
1698e32b400SDavid du Colombier 	 *  put the message there.
1708e32b400SDavid du Colombier 	 */
1718e32b400SDavid du Colombier 	if(kprintoq != nil && !qisclosed(kprintoq)){
1728e32b400SDavid du Colombier 		if(usewrite)
1738e32b400SDavid du Colombier 			qwrite(kprintoq, str, n);
1748e32b400SDavid du Colombier 		else
1758e32b400SDavid du Colombier 			qiwrite(kprintoq, str, n);
1768e32b400SDavid du Colombier 	}else if(screenputs != nil)
1778e32b400SDavid du Colombier 		screenputs(str, n);
1788e32b400SDavid du Colombier 
1798e32b400SDavid du Colombier 	if(serialoq == nil){
1808e32b400SDavid du Colombier 		uartputs(str, n);
1818e32b400SDavid du Colombier 		return;
1828e32b400SDavid du Colombier 	}
1838e32b400SDavid du Colombier 
1848e32b400SDavid du Colombier 	while(n > 0) {
1858e32b400SDavid du Colombier 		t = memchr(str, '\n', n);
1868e32b400SDavid du Colombier 		if(t && !kbd.raw) {
1878e32b400SDavid du Colombier 			m = t-str;
1888e32b400SDavid du Colombier 			if(usewrite){
1898e32b400SDavid du Colombier 				qwrite(serialoq, str, m);
1908e32b400SDavid du Colombier 				qwrite(serialoq, "\r\n", 2);
1918e32b400SDavid du Colombier 			} else {
1928e32b400SDavid du Colombier 				qiwrite(serialoq, str, m);
1938e32b400SDavid du Colombier 				qiwrite(serialoq, "\r\n", 2);
1948e32b400SDavid du Colombier 			}
1958e32b400SDavid du Colombier 			n -= m+1;
1968e32b400SDavid du Colombier 			str = t+1;
1978e32b400SDavid du Colombier 		} else {
1988e32b400SDavid du Colombier 			if(usewrite)
1998e32b400SDavid du Colombier 				qwrite(serialoq, str, n);
2008e32b400SDavid du Colombier 			else
2018e32b400SDavid du Colombier 				qiwrite(serialoq, str, n);
2028e32b400SDavid du Colombier 			break;
2038e32b400SDavid du Colombier 		}
2048e32b400SDavid du Colombier 	}
2058e32b400SDavid du Colombier #endif
2068e32b400SDavid du Colombier }
2078e32b400SDavid du Colombier 
2088e32b400SDavid du Colombier void
2098e32b400SDavid du Colombier putstrn(char *str, int n)
2108e32b400SDavid du Colombier {
2118e32b400SDavid du Colombier 	putstrn0(str, n, 0);
2128e32b400SDavid du Colombier }
2138e32b400SDavid du Colombier 
2148e32b400SDavid du Colombier int noprint;
2158e32b400SDavid du Colombier 
2168e32b400SDavid du Colombier int
2178e32b400SDavid du Colombier print(char *fmt, ...)
2188e32b400SDavid du Colombier {
2198e32b400SDavid du Colombier 	int n;
2208e32b400SDavid du Colombier 	va_list arg;
2218e32b400SDavid du Colombier 	char buf[PRINTSIZE];
2228e32b400SDavid du Colombier 
2238e32b400SDavid du Colombier 	if(noprint)
2248e32b400SDavid du Colombier 		return -1;
2258e32b400SDavid du Colombier 
2268e32b400SDavid du Colombier 	va_start(arg, fmt);
2278e32b400SDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
2288e32b400SDavid du Colombier 	va_end(arg);
2298e32b400SDavid du Colombier 	putstrn(buf, n);
2308e32b400SDavid du Colombier 
2318e32b400SDavid du Colombier 	return n;
2328e32b400SDavid du Colombier }
2338e32b400SDavid du Colombier 
2348e32b400SDavid du Colombier /*
2358e32b400SDavid du Colombier  * Want to interlock iprints to avoid interlaced output on
2368e32b400SDavid du Colombier  * multiprocessor, but don't want to deadlock if one processor
2378e32b400SDavid du Colombier  * dies during print and another has something important to say.
2388e32b400SDavid du Colombier  * Make a good faith effort.
2398e32b400SDavid du Colombier  */
2408e32b400SDavid du Colombier static Lock iprintlock;
2418e32b400SDavid du Colombier static int
2428e32b400SDavid du Colombier iprintcanlock(Lock *l)
2438e32b400SDavid du Colombier {
2448e32b400SDavid du Colombier 	int i;
2458e32b400SDavid du Colombier 
2468e32b400SDavid du Colombier 	for(i=0; i<1000; i++){
2478e32b400SDavid du Colombier 		if(canlock(l))
2488e32b400SDavid du Colombier 			return 1;
2498e32b400SDavid du Colombier 		if(l->m == MACHP(m->machno))
2508e32b400SDavid du Colombier 			return 0;
2518e32b400SDavid du Colombier 		microdelay(100);
2528e32b400SDavid du Colombier 	}
2538e32b400SDavid du Colombier 	return 0;
2548e32b400SDavid du Colombier }
2558e32b400SDavid du Colombier 
2568e32b400SDavid du Colombier int
2578e32b400SDavid du Colombier iprint(char *fmt, ...)
2588e32b400SDavid du Colombier {
2598e32b400SDavid du Colombier 	int n, s, locked;
2608e32b400SDavid du Colombier 	va_list arg;
2618e32b400SDavid du Colombier 	char buf[PRINTSIZE];
2628e32b400SDavid du Colombier 
2638e32b400SDavid du Colombier 	s = splhi();
2648e32b400SDavid du Colombier 	va_start(arg, fmt);
2658e32b400SDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
2668e32b400SDavid du Colombier 	va_end(arg);
2678e32b400SDavid du Colombier 	locked = iprintcanlock(&iprintlock);
2688e32b400SDavid du Colombier 	if(screenputs != nil && iprintscreenputs)
2698e32b400SDavid du Colombier 		screenputs(buf, n);
2708e32b400SDavid du Colombier #ifdef CRUDEPRINT
2718e32b400SDavid du Colombier 	CRUDEPRINT(buf, n);
2728e32b400SDavid du Colombier #else
2738e32b400SDavid du Colombier 	uartputs(buf, n);
2748e32b400SDavid du Colombier #endif
2758e32b400SDavid du Colombier 	if(locked)
2768e32b400SDavid du Colombier 		unlock(&iprintlock);
2778e32b400SDavid du Colombier 	splx(s);
2788e32b400SDavid du Colombier 
2798e32b400SDavid du Colombier 	return n;
2808e32b400SDavid du Colombier }
2818e32b400SDavid du Colombier 
2828e32b400SDavid du Colombier void
2838e32b400SDavid du Colombier panic(char *fmt, ...)
2848e32b400SDavid du Colombier {
2858e32b400SDavid du Colombier 	int n, s;
2868e32b400SDavid du Colombier 	va_list arg;
2878e32b400SDavid du Colombier 	char buf[PRINTSIZE];
2888e32b400SDavid du Colombier 
2898e32b400SDavid du Colombier 	kprintoq = nil;	/* don't try to write to /dev/kprint */
2908e32b400SDavid du Colombier 
2918e32b400SDavid du Colombier 	if(panicking)
2928e32b400SDavid du Colombier 		for(;;);
2938e32b400SDavid du Colombier 	panicking = 1;
2948e32b400SDavid du Colombier 
2958e32b400SDavid du Colombier 	delay(20);
2968e32b400SDavid du Colombier 	s = splhi();
2978e32b400SDavid du Colombier 	strcpy(buf, "panic: ");
2988e32b400SDavid du Colombier 	va_start(arg, fmt);
2998e32b400SDavid du Colombier 	n = vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf;
3008e32b400SDavid du Colombier 	va_end(arg);
3018e32b400SDavid du Colombier 	iprint("%s\n", buf);
3028e32b400SDavid du Colombier 	if(consdebug)
3038e32b400SDavid du Colombier 		(*consdebug)();
3048e32b400SDavid du Colombier 	splx(s);
3058e32b400SDavid du Colombier 	prflush();
3068e32b400SDavid du Colombier 	buf[n] = '\n';
307*047f1f95SDavid du Colombier //	putstrn(buf, n+1);
308*047f1f95SDavid du Colombier //	dumpstack();
3098e32b400SDavid du Colombier 
3108e32b400SDavid du Colombier 	exit(1);
3118e32b400SDavid du Colombier }
3128e32b400SDavid du Colombier 
3138e32b400SDavid du Colombier /* libmp at least contains a few calls to sysfatal; simulate with panic */
3148e32b400SDavid du Colombier void
3158e32b400SDavid du Colombier sysfatal(char *fmt, ...)
3168e32b400SDavid du Colombier {
3178e32b400SDavid du Colombier 	char err[256];
3188e32b400SDavid du Colombier 	va_list arg;
3198e32b400SDavid du Colombier 
3208e32b400SDavid du Colombier 	va_start(arg, fmt);
3218e32b400SDavid du Colombier 	vseprint(err, err + sizeof err, fmt, arg);
3228e32b400SDavid du Colombier 	va_end(arg);
3238e32b400SDavid du Colombier 	panic("sysfatal: %s", err);
3248e32b400SDavid du Colombier }
3258e32b400SDavid du Colombier 
3268e32b400SDavid du Colombier void
3278e32b400SDavid du Colombier _assert(char *fmt)
3288e32b400SDavid du Colombier {
3298e32b400SDavid du Colombier 	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);
3308e32b400SDavid du Colombier }
3318e32b400SDavid du Colombier 
3328e32b400SDavid du Colombier int
3338e32b400SDavid du Colombier pprint(char *fmt, ...)
3348e32b400SDavid du Colombier {
3358e32b400SDavid du Colombier 	int n;
3368e32b400SDavid du Colombier 	Chan *c;
3378e32b400SDavid du Colombier 	va_list arg;
3388e32b400SDavid du Colombier 	char buf[2*PRINTSIZE];
3398e32b400SDavid du Colombier 
3408e32b400SDavid du Colombier 	if(up == nil || up->fgrp == nil)
3418e32b400SDavid du Colombier 		return 0;
3428e32b400SDavid du Colombier 
3438e32b400SDavid du Colombier 	c = up->fgrp->fd[2];
3448e32b400SDavid du Colombier 	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
3458e32b400SDavid du Colombier 		return 0;
3468e32b400SDavid du Colombier 	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);
3478e32b400SDavid du Colombier 	va_start(arg, fmt);
3488e32b400SDavid du Colombier 	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;
3498e32b400SDavid du Colombier 	va_end(arg);
3508e32b400SDavid du Colombier 
3518e32b400SDavid du Colombier 	if(waserror())
3528e32b400SDavid du Colombier 		return 0;
3538e32b400SDavid du Colombier 	devtab[c->type]->write(c, buf, n, c->offset);
3548e32b400SDavid du Colombier 	poperror();
3558e32b400SDavid du Colombier 
3568e32b400SDavid du Colombier 	lock(c);
3578e32b400SDavid du Colombier 	c->offset += n;
3588e32b400SDavid du Colombier 	unlock(c);
3598e32b400SDavid du Colombier 
3608e32b400SDavid du Colombier 	return n;
3618e32b400SDavid du Colombier }
3628e32b400SDavid du Colombier 
3638e32b400SDavid du Colombier static void
3648e32b400SDavid du Colombier echoscreen(char *buf, int n)
3658e32b400SDavid du Colombier {
3668e32b400SDavid du Colombier 	char *e, *p;
3678e32b400SDavid du Colombier 	char ebuf[128];
3688e32b400SDavid du Colombier 	int x;
3698e32b400SDavid du Colombier 
3708e32b400SDavid du Colombier iprint("echoscreen: wrong for beagle\n");
3718e32b400SDavid du Colombier 	p = ebuf;
3728e32b400SDavid du Colombier 	e = ebuf + sizeof(ebuf) - 4;
3738e32b400SDavid du Colombier 	while(n-- > 0){
3748e32b400SDavid du Colombier 		if(p >= e){
3758e32b400SDavid du Colombier 			screenputs(ebuf, p - ebuf);
3768e32b400SDavid du Colombier 			p = ebuf;
3778e32b400SDavid du Colombier 		}
3788e32b400SDavid du Colombier 		x = *buf++;
3798e32b400SDavid du Colombier 		if(x == 0x15){
3808e32b400SDavid du Colombier 			*p++ = '^';
3818e32b400SDavid du Colombier 			*p++ = 'U';
3828e32b400SDavid du Colombier 			*p++ = '\n';
3838e32b400SDavid du Colombier 		} else
3848e32b400SDavid du Colombier 			*p++ = x;
3858e32b400SDavid du Colombier 	}
3868e32b400SDavid du Colombier 	if(p != ebuf)
3878e32b400SDavid du Colombier 		screenputs(ebuf, p - ebuf);
3888e32b400SDavid du Colombier }
3898e32b400SDavid du Colombier 
3908e32b400SDavid du Colombier static void
3918e32b400SDavid du Colombier echoserialoq(char *buf, int n)
3928e32b400SDavid du Colombier {
3938e32b400SDavid du Colombier #ifdef ECHO_WORKS
3948e32b400SDavid du Colombier 	int x;
3958e32b400SDavid du Colombier 	char *e, *p;
3968e32b400SDavid du Colombier 	char ebuf[128];
3978e32b400SDavid du Colombier 
3988e32b400SDavid du Colombier 	p = ebuf;
3998e32b400SDavid du Colombier 	e = ebuf + sizeof(ebuf) - 4;
4008e32b400SDavid du Colombier 	while(n-- > 0){
4018e32b400SDavid du Colombier 		if(p >= e){
4028e32b400SDavid du Colombier 			qiwrite(serialoq, ebuf, p - ebuf);
4038e32b400SDavid du Colombier 			p = ebuf;
4048e32b400SDavid du Colombier 		}
4058e32b400SDavid du Colombier 		x = *buf++;
4068e32b400SDavid du Colombier 		if(x == '\n'){
4078e32b400SDavid du Colombier 			*p++ = '\r';
4088e32b400SDavid du Colombier 			*p++ = '\n';
4098e32b400SDavid du Colombier 		} else if(x == 0x15){
4108e32b400SDavid du Colombier 			*p++ = '^';
4118e32b400SDavid du Colombier 			*p++ = 'U';
4128e32b400SDavid du Colombier 			*p++ = '\n';
4138e32b400SDavid du Colombier 		} else
4148e32b400SDavid du Colombier 			*p++ = x;
4158e32b400SDavid du Colombier 	}
4168e32b400SDavid du Colombier 	if(p != ebuf)
4178e32b400SDavid du Colombier 		qiwrite(serialoq, ebuf, p - ebuf);
4188e32b400SDavid du Colombier #else
4198e32b400SDavid du Colombier 	/*
4208e32b400SDavid du Colombier 	 * TODO: something is broken about the above and echoed characters
4218e32b400SDavid du Colombier 	 * don't appear.  until we figure it out, just brute force it.
4228e32b400SDavid du Colombier 	 */
4238e32b400SDavid du Colombier 	while(n-- > 0){
4248e32b400SDavid du Colombier 		if(*buf == ('u' & 037))
4258e32b400SDavid du Colombier 			CRUDEPRINT("^U\r\n", 4);
4268e32b400SDavid du Colombier 		else
4278e32b400SDavid du Colombier 			CRUDEPRINT(buf, 1);
4288e32b400SDavid du Colombier 		buf++;
4298e32b400SDavid du Colombier 	}
4308e32b400SDavid du Colombier #endif
4318e32b400SDavid du Colombier }
4328e32b400SDavid du Colombier 
4338e32b400SDavid du Colombier static void
4348e32b400SDavid du Colombier echo(char *buf, int n)
4358e32b400SDavid du Colombier {
4368e32b400SDavid du Colombier 	static int ctrlt, pid;
4378e32b400SDavid du Colombier 	int x;
4388e32b400SDavid du Colombier 	char *e, *p;
4398e32b400SDavid du Colombier 
4408e32b400SDavid du Colombier 	if(n == 0)
4418e32b400SDavid du Colombier 		return;
4428e32b400SDavid du Colombier 
4438e32b400SDavid du Colombier 	e = buf+n;
4448e32b400SDavid du Colombier 	for(p = buf; p < e; p++){
4458e32b400SDavid du Colombier 		switch(*p){
4468e32b400SDavid du Colombier 		case 0x10:	/* ^P */
4478e32b400SDavid du Colombier 			if(cpuserver && !kbd.ctlpoff){
4488e32b400SDavid du Colombier 				active.exiting = 1;
4498e32b400SDavid du Colombier 				return;
4508e32b400SDavid du Colombier 			}
4518e32b400SDavid du Colombier 			break;
4528e32b400SDavid du Colombier 		case 0x14:	/* ^T */
4538e32b400SDavid du Colombier 			ctrlt++;
4548e32b400SDavid du Colombier 			if(ctrlt > 2)
4558e32b400SDavid du Colombier 				ctrlt = 2;
4568e32b400SDavid du Colombier 			continue;
4578e32b400SDavid du Colombier 		}
4588e32b400SDavid du Colombier 
4598e32b400SDavid du Colombier 		if(ctrlt != 2)
4608e32b400SDavid du Colombier 			continue;
4618e32b400SDavid du Colombier 
4628e32b400SDavid du Colombier 		/* ^T escapes */
4638e32b400SDavid du Colombier 		ctrlt = 0;
4648e32b400SDavid du Colombier 		switch(*p){
4658e32b400SDavid du Colombier 		case 'S':
4668e32b400SDavid du Colombier 			x = splhi();
4678e32b400SDavid du Colombier 			dumpstack();
4688e32b400SDavid du Colombier 			procdump();
4698e32b400SDavid du Colombier 			splx(x);
4708e32b400SDavid du Colombier 			return;
4718e32b400SDavid du Colombier 		case 's':
4728e32b400SDavid du Colombier 			dumpstack();
4738e32b400SDavid du Colombier 			return;
4748e32b400SDavid du Colombier 		case 'x':
4758e32b400SDavid du Colombier 			xsummary();
4768e32b400SDavid du Colombier 			ixsummary();
4778e32b400SDavid du Colombier 			mallocsummary();
4788e32b400SDavid du Colombier 		//	memorysummary();
4798e32b400SDavid du Colombier 			pagersummary();
4808e32b400SDavid du Colombier 			return;
4818e32b400SDavid du Colombier 		case 'd':
4828e32b400SDavid du Colombier 			if(consdebug == nil)
4838e32b400SDavid du Colombier 				consdebug = rdb;
4848e32b400SDavid du Colombier 			else
4858e32b400SDavid du Colombier 				consdebug = nil;
4868e32b400SDavid du Colombier 			print("consdebug now %#p\n", consdebug);
4878e32b400SDavid du Colombier 			return;
4888e32b400SDavid du Colombier 		case 'D':
4898e32b400SDavid du Colombier 			if(consdebug == nil)
4908e32b400SDavid du Colombier 				consdebug = rdb;
4918e32b400SDavid du Colombier 			consdebug();
4928e32b400SDavid du Colombier 			return;
4938e32b400SDavid du Colombier 		case 'p':
4948e32b400SDavid du Colombier 			x = spllo();
4958e32b400SDavid du Colombier 			procdump();
4968e32b400SDavid du Colombier 			splx(x);
4978e32b400SDavid du Colombier 			return;
4988e32b400SDavid du Colombier 		case 'q':
4998e32b400SDavid du Colombier 			scheddump();
5008e32b400SDavid du Colombier 			return;
5018e32b400SDavid du Colombier 		case 'k':
5028e32b400SDavid du Colombier 			killbig("^t ^t k");
5038e32b400SDavid du Colombier 			return;
5048e32b400SDavid du Colombier 		case 'r':
5058e32b400SDavid du Colombier 			exit(0);
5068e32b400SDavid du Colombier 			return;
5078e32b400SDavid du Colombier 		}
5088e32b400SDavid du Colombier 	}
5098e32b400SDavid du Colombier 
5108e32b400SDavid du Colombier 	qproduce(kbdq, buf, n);
5118e32b400SDavid du Colombier 	if(kbd.raw)
5128e32b400SDavid du Colombier 		return;
5138e32b400SDavid du Colombier 	kmesgputs(buf, n);
5148e32b400SDavid du Colombier 	if(screenputs != nil)
5158e32b400SDavid du Colombier 		echoscreen(buf, n);
5168e32b400SDavid du Colombier 	if(serialoq)
5178e32b400SDavid du Colombier 		echoserialoq(buf, n);
5188e32b400SDavid du Colombier }
5198e32b400SDavid du Colombier 
5208e32b400SDavid du Colombier /*
5218e32b400SDavid du Colombier  *  Called by a uart interrupt for console input.
5228e32b400SDavid du Colombier  *
5238e32b400SDavid du Colombier  *  turn '\r' into '\n' before putting it into the queue.
5248e32b400SDavid du Colombier  */
5258e32b400SDavid du Colombier int
5268e32b400SDavid du Colombier kbdcr2nl(Queue*, int ch)
5278e32b400SDavid du Colombier {
5288e32b400SDavid du Colombier 	char *next;
5298e32b400SDavid du Colombier 
5308e32b400SDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
5318e32b400SDavid du Colombier 	if(ch == '\r' && !kbd.raw)
5328e32b400SDavid du Colombier 		ch = '\n';
5338e32b400SDavid du Colombier 	next = kbd.iw+1;
5348e32b400SDavid du Colombier 	if(next >= kbd.ie)
5358e32b400SDavid du Colombier 		next = kbd.istage;
5368e32b400SDavid du Colombier 	if(next != kbd.ir){
5378e32b400SDavid du Colombier 		*kbd.iw = ch;
5388e32b400SDavid du Colombier 		kbd.iw = next;
5398e32b400SDavid du Colombier 	}
5408e32b400SDavid du Colombier 	iunlock(&kbd.lockputc);
5418e32b400SDavid du Colombier 	return 0;
5428e32b400SDavid du Colombier }
5438e32b400SDavid du Colombier 
5448e32b400SDavid du Colombier /*
5458e32b400SDavid du Colombier  *  Put character, possibly a rune, into read queue at interrupt time.
5468e32b400SDavid du Colombier  *  Called at interrupt time to process a character.
5478e32b400SDavid du Colombier  */
5488e32b400SDavid du Colombier int
5498e32b400SDavid du Colombier kbdputc(Queue*, int ch)
5508e32b400SDavid du Colombier {
5518e32b400SDavid du Colombier 	int i, n;
5528e32b400SDavid du Colombier 	char buf[3];
5538e32b400SDavid du Colombier 	Rune r;
5548e32b400SDavid du Colombier 	char *next;
5558e32b400SDavid du Colombier 
5568e32b400SDavid du Colombier 	if(kbd.ir == nil)
5578e32b400SDavid du Colombier 		return 0;		/* in case we're not inited yet */
5588e32b400SDavid du Colombier 
5598e32b400SDavid du Colombier 	ilock(&kbd.lockputc);		/* just a mutex */
5608e32b400SDavid du Colombier 	r = ch;
5618e32b400SDavid du Colombier 	n = runetochar(buf, &r);
5628e32b400SDavid du Colombier 	for(i = 0; i < n; i++){
5638e32b400SDavid du Colombier 		next = kbd.iw+1;
5648e32b400SDavid du Colombier 		if(next >= kbd.ie)
5658e32b400SDavid du Colombier 			next = kbd.istage;
5668e32b400SDavid du Colombier 		if(next == kbd.ir)
5678e32b400SDavid du Colombier 			break;
5688e32b400SDavid du Colombier 		*kbd.iw = buf[i];
5698e32b400SDavid du Colombier 		kbd.iw = next;
5708e32b400SDavid du Colombier 	}
5718e32b400SDavid du Colombier 	iunlock(&kbd.lockputc);
5728e32b400SDavid du Colombier 	return 0;
5738e32b400SDavid du Colombier }
5748e32b400SDavid du Colombier 
5758e32b400SDavid du Colombier /*
5768e32b400SDavid du Colombier  *  we save up input characters till clock time to reduce
5778e32b400SDavid du Colombier  *  per character interrupt overhead.
5788e32b400SDavid du Colombier  */
5798e32b400SDavid du Colombier static void
5808e32b400SDavid du Colombier kbdputcclock(void)
5818e32b400SDavid du Colombier {
5828e32b400SDavid du Colombier 	char *iw;
5838e32b400SDavid du Colombier 
5848e32b400SDavid du Colombier 	/* this amortizes cost of qproduce */
5858e32b400SDavid du Colombier 	if(kbd.iw != kbd.ir){
5868e32b400SDavid du Colombier 		iw = kbd.iw;
5878e32b400SDavid du Colombier 		if(iw < kbd.ir){
5888e32b400SDavid du Colombier 			echo(kbd.ir, kbd.ie-kbd.ir);
5898e32b400SDavid du Colombier 			kbd.ir = kbd.istage;
5908e32b400SDavid du Colombier 		}
5918e32b400SDavid du Colombier 		if(kbd.ir != iw){
5928e32b400SDavid du Colombier 			echo(kbd.ir, iw-kbd.ir);
5938e32b400SDavid du Colombier 			kbd.ir = iw;
5948e32b400SDavid du Colombier 		}
5958e32b400SDavid du Colombier 	}
5968e32b400SDavid du Colombier }
5978e32b400SDavid du Colombier 
5988e32b400SDavid du Colombier enum{
5998e32b400SDavid du Colombier 	Qdir,
6008e32b400SDavid du Colombier 	Qbintime,
6018e32b400SDavid du Colombier 	Qcons,
6028e32b400SDavid du Colombier 	Qconsctl,
6038e32b400SDavid du Colombier 	Qcputime,
6048e32b400SDavid du Colombier 	Qdrivers,
6058e32b400SDavid du Colombier 	Qkmesg,
6068e32b400SDavid du Colombier 	Qkprint,
6078e32b400SDavid du Colombier 	Qhostdomain,
6088e32b400SDavid du Colombier 	Qhostowner,
6098e32b400SDavid du Colombier 	Qnull,
6108e32b400SDavid du Colombier 	Qosversion,
6118e32b400SDavid du Colombier 	Qpgrpid,
6128e32b400SDavid du Colombier 	Qpid,
6138e32b400SDavid du Colombier 	Qppid,
6148e32b400SDavid du Colombier 	Qrandom,
6158e32b400SDavid du Colombier 	Qreboot,
6168e32b400SDavid du Colombier 	Qswap,
6178e32b400SDavid du Colombier 	Qsysname,
6188e32b400SDavid du Colombier 	Qsysstat,
6198e32b400SDavid du Colombier 	Qtime,
6208e32b400SDavid du Colombier 	Quser,
6218e32b400SDavid du Colombier 	Qzero,
6228e32b400SDavid du Colombier };
6238e32b400SDavid du Colombier 
6248e32b400SDavid du Colombier enum
6258e32b400SDavid du Colombier {
6268e32b400SDavid du Colombier 	VLNUMSIZE=	22,
6278e32b400SDavid du Colombier };
6288e32b400SDavid du Colombier 
6298e32b400SDavid du Colombier static Dirtab consdir[]={
6308e32b400SDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,
6318e32b400SDavid du Colombier 	"bintime",	{Qbintime},	24,		0664,
6328e32b400SDavid du Colombier 	"cons",		{Qcons},	0,		0660,
6338e32b400SDavid du Colombier 	"consctl",	{Qconsctl},	0,		0220,
6348e32b400SDavid du Colombier 	"cputime",	{Qcputime},	6*NUMSIZE,	0444,
6358e32b400SDavid du Colombier 	"drivers",	{Qdrivers},	0,		0444,
6368e32b400SDavid du Colombier 	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,
6378e32b400SDavid du Colombier 	"hostowner",	{Qhostowner},	0,		0664,
6388e32b400SDavid du Colombier 	"kmesg",	{Qkmesg},	0,		0440,
6398e32b400SDavid du Colombier 	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,
6408e32b400SDavid du Colombier 	"null",		{Qnull},	0,		0666,
6418e32b400SDavid du Colombier 	"osversion",	{Qosversion},	0,		0444,
6428e32b400SDavid du Colombier 	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,
6438e32b400SDavid du Colombier 	"pid",		{Qpid},		NUMSIZE,	0444,
6448e32b400SDavid du Colombier 	"ppid",		{Qppid},	NUMSIZE,	0444,
6458e32b400SDavid du Colombier 	"random",	{Qrandom},	0,		0444,
6468e32b400SDavid du Colombier 	"reboot",	{Qreboot},	0,		0664,
6478e32b400SDavid du Colombier 	"swap",		{Qswap},	0,		0664,
6488e32b400SDavid du Colombier 	"sysname",	{Qsysname},	0,		0664,
6498e32b400SDavid du Colombier 	"sysstat",	{Qsysstat},	0,		0666,
6508e32b400SDavid du Colombier 	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,
6518e32b400SDavid du Colombier 	"user",		{Quser},	0,		0666,
6528e32b400SDavid du Colombier 	"zero",		{Qzero},	0,		0444,
6538e32b400SDavid du Colombier };
6548e32b400SDavid du Colombier 
6558e32b400SDavid du Colombier int
6568e32b400SDavid du Colombier readnum(ulong off, char *buf, ulong n, ulong val, int size)
6578e32b400SDavid du Colombier {
6588e32b400SDavid du Colombier 	char tmp[64];
6598e32b400SDavid du Colombier 
6608e32b400SDavid du Colombier 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);
6618e32b400SDavid du Colombier 	tmp[size-1] = ' ';
6628e32b400SDavid du Colombier 	if(off >= size)
6638e32b400SDavid du Colombier 		return 0;
6648e32b400SDavid du Colombier 	if(off+n > size)
6658e32b400SDavid du Colombier 		n = size-off;
6668e32b400SDavid du Colombier 	memmove(buf, tmp+off, n);
6678e32b400SDavid du Colombier 	return n;
6688e32b400SDavid du Colombier }
6698e32b400SDavid du Colombier 
6708e32b400SDavid du Colombier int
6718e32b400SDavid du Colombier readstr(ulong off, char *buf, ulong n, char *str)
6728e32b400SDavid du Colombier {
6738e32b400SDavid du Colombier 	int size;
6748e32b400SDavid du Colombier 
6758e32b400SDavid du Colombier 	size = strlen(str);
6768e32b400SDavid du Colombier 	if(off >= size)
6778e32b400SDavid du Colombier 		return 0;
6788e32b400SDavid du Colombier 	if(off+n > size)
6798e32b400SDavid du Colombier 		n = size-off;
6808e32b400SDavid du Colombier 	memmove(buf, str+off, n);
6818e32b400SDavid du Colombier 	return n;
6828e32b400SDavid du Colombier }
6838e32b400SDavid du Colombier 
6848e32b400SDavid du Colombier static void
6858e32b400SDavid du Colombier consinit(void)
6868e32b400SDavid du Colombier {
6878e32b400SDavid du Colombier 	todinit();
6888e32b400SDavid du Colombier 	randominit();
6898e32b400SDavid du Colombier 	/*
6908e32b400SDavid du Colombier 	 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
6918e32b400SDavid du Colombier 	 * processing it every 22 ms should be fine
6928e32b400SDavid du Colombier 	 */
6938e32b400SDavid du Colombier 	addclock0link(kbdputcclock, 22);
6948e32b400SDavid du Colombier }
6958e32b400SDavid du Colombier 
6968e32b400SDavid du Colombier static Chan*
6978e32b400SDavid du Colombier consattach(char *spec)
6988e32b400SDavid du Colombier {
6998e32b400SDavid du Colombier 	return devattach('c', spec);
7008e32b400SDavid du Colombier }
7018e32b400SDavid du Colombier 
7028e32b400SDavid du Colombier static Walkqid*
7038e32b400SDavid du Colombier conswalk(Chan *c, Chan *nc, char **name, int nname)
7048e32b400SDavid du Colombier {
7058e32b400SDavid du Colombier 	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
7068e32b400SDavid du Colombier }
7078e32b400SDavid du Colombier 
7088e32b400SDavid du Colombier static int
7098e32b400SDavid du Colombier consstat(Chan *c, uchar *dp, int n)
7108e32b400SDavid du Colombier {
7118e32b400SDavid du Colombier 	return devstat(c, dp, n, consdir, nelem(consdir), devgen);
7128e32b400SDavid du Colombier }
7138e32b400SDavid du Colombier 
7148e32b400SDavid du Colombier static Chan*
7158e32b400SDavid du Colombier consopen(Chan *c, int omode)
7168e32b400SDavid du Colombier {
7178e32b400SDavid du Colombier 	c->aux = nil;
7188e32b400SDavid du Colombier 	c = devopen(c, omode, consdir, nelem(consdir), devgen);
7198e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
7208e32b400SDavid du Colombier 	case Qconsctl:
7218e32b400SDavid du Colombier 		incref(&kbd.ctl);
7228e32b400SDavid du Colombier 		break;
7238e32b400SDavid du Colombier 
7248e32b400SDavid du Colombier 	case Qkprint:
7258e32b400SDavid du Colombier 		if(tas(&kprintinuse) != 0){
7268e32b400SDavid du Colombier 			c->flag &= ~COPEN;
7278e32b400SDavid du Colombier 			error(Einuse);
7288e32b400SDavid du Colombier 		}
7298e32b400SDavid du Colombier 		if(kprintoq == nil){
7308e32b400SDavid du Colombier 			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);
7318e32b400SDavid du Colombier 			if(kprintoq == nil){
7328e32b400SDavid du Colombier 				c->flag &= ~COPEN;
7338e32b400SDavid du Colombier 				error(Enomem);
7348e32b400SDavid du Colombier 			}
7358e32b400SDavid du Colombier 			qnoblock(kprintoq, 1);
7368e32b400SDavid du Colombier 		}else
7378e32b400SDavid du Colombier 			qreopen(kprintoq);
7388e32b400SDavid du Colombier 		c->iounit = qiomaxatomic;
7398e32b400SDavid du Colombier 		break;
7408e32b400SDavid du Colombier 	}
7418e32b400SDavid du Colombier 	return c;
7428e32b400SDavid du Colombier }
7438e32b400SDavid du Colombier 
7448e32b400SDavid du Colombier static void
7458e32b400SDavid du Colombier consclose(Chan *c)
7468e32b400SDavid du Colombier {
7478e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
7488e32b400SDavid du Colombier 	/* last close of control file turns off raw */
7498e32b400SDavid du Colombier 	case Qconsctl:
7508e32b400SDavid du Colombier 		if(c->flag&COPEN){
7518e32b400SDavid du Colombier 			if(decref(&kbd.ctl) == 0)
7528e32b400SDavid du Colombier 				kbd.raw = 0;
7538e32b400SDavid du Colombier 		}
7548e32b400SDavid du Colombier 		break;
7558e32b400SDavid du Colombier 
7568e32b400SDavid du Colombier 	/* close of kprint allows other opens */
7578e32b400SDavid du Colombier 	case Qkprint:
7588e32b400SDavid du Colombier 		if(c->flag & COPEN){
7598e32b400SDavid du Colombier 			kprintinuse = 0;
7608e32b400SDavid du Colombier 			qhangup(kprintoq, nil);
7618e32b400SDavid du Colombier 		}
7628e32b400SDavid du Colombier 		break;
7638e32b400SDavid du Colombier 	}
7648e32b400SDavid du Colombier }
7658e32b400SDavid du Colombier 
7668e32b400SDavid du Colombier static long
7678e32b400SDavid du Colombier consread(Chan *c, void *buf, long n, vlong off)
7688e32b400SDavid du Colombier {
7698e32b400SDavid du Colombier 	ulong l;
7708e32b400SDavid du Colombier 	Mach *mp;
7718e32b400SDavid du Colombier 	char *b, *bp, ch;
7728e32b400SDavid du Colombier 	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */
7738e32b400SDavid du Colombier 	int i, k, id, send;
7748e32b400SDavid du Colombier 	vlong offset = off;
7758e32b400SDavid du Colombier 
7768e32b400SDavid du Colombier 	if(n <= 0)
7778e32b400SDavid du Colombier 		return n;
7788e32b400SDavid du Colombier 
7798e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
7808e32b400SDavid du Colombier 	case Qdir:
7818e32b400SDavid du Colombier 		return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
7828e32b400SDavid du Colombier 
7838e32b400SDavid du Colombier 	case Qcons:
7848e32b400SDavid du Colombier 		qlock(&kbd);
7858e32b400SDavid du Colombier 		if(waserror()) {
7868e32b400SDavid du Colombier 			qunlock(&kbd);
7878e32b400SDavid du Colombier 			nexterror();
7888e32b400SDavid du Colombier 		}
7898e32b400SDavid du Colombier 		while(!qcanread(lineq)){
7908e32b400SDavid du Colombier 			if(qread(kbdq, &ch, 1) == 0)
7918e32b400SDavid du Colombier 				continue;
7928e32b400SDavid du Colombier 			send = 0;
7938e32b400SDavid du Colombier 			if(ch == 0){
7948e32b400SDavid du Colombier 				/* flush output on rawoff -> rawon */
7958e32b400SDavid du Colombier 				if(kbd.x > 0)
7968e32b400SDavid du Colombier 					send = !qcanread(kbdq);
7978e32b400SDavid du Colombier 			}else if(kbd.raw){
7988e32b400SDavid du Colombier 				kbd.line[kbd.x++] = ch;
7998e32b400SDavid du Colombier 				send = !qcanread(kbdq);
8008e32b400SDavid du Colombier 			}else{
8018e32b400SDavid du Colombier 				switch(ch){
8028e32b400SDavid du Colombier 				case '\b':
8038e32b400SDavid du Colombier 					if(kbd.x > 0)
8048e32b400SDavid du Colombier 						kbd.x--;
8058e32b400SDavid du Colombier 					break;
8068e32b400SDavid du Colombier 				case 0x15:	/* ^U */
8078e32b400SDavid du Colombier 					kbd.x = 0;
8088e32b400SDavid du Colombier 					break;
8098e32b400SDavid du Colombier 				case '\n':
8108e32b400SDavid du Colombier 				case 0x04:	/* ^D */
8118e32b400SDavid du Colombier 					send = 1;
8128e32b400SDavid du Colombier 				default:
8138e32b400SDavid du Colombier 					if(ch != 0x04)
8148e32b400SDavid du Colombier 						kbd.line[kbd.x++] = ch;
8158e32b400SDavid du Colombier 					break;
8168e32b400SDavid du Colombier 				}
8178e32b400SDavid du Colombier 			}
8188e32b400SDavid du Colombier 			if(send || kbd.x == sizeof kbd.line){
8198e32b400SDavid du Colombier 				qwrite(lineq, kbd.line, kbd.x);
8208e32b400SDavid du Colombier 				kbd.x = 0;
8218e32b400SDavid du Colombier 			}
8228e32b400SDavid du Colombier 		}
8238e32b400SDavid du Colombier 		n = qread(lineq, buf, n);
8248e32b400SDavid du Colombier 		qunlock(&kbd);
8258e32b400SDavid du Colombier 		poperror();
8268e32b400SDavid du Colombier 		return n;
8278e32b400SDavid du Colombier 
8288e32b400SDavid du Colombier 	case Qcputime:
8298e32b400SDavid du Colombier 		k = offset;
8308e32b400SDavid du Colombier 		if(k >= 6*NUMSIZE)
8318e32b400SDavid du Colombier 			return 0;
8328e32b400SDavid du Colombier 		if(k+n > 6*NUMSIZE)
8338e32b400SDavid du Colombier 			n = 6*NUMSIZE - k;
8348e32b400SDavid du Colombier 		/* easiest to format in a separate buffer and copy out */
8358e32b400SDavid du Colombier 		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
8368e32b400SDavid du Colombier 			l = up->time[i];
8378e32b400SDavid du Colombier 			if(i == TReal)
8388e32b400SDavid du Colombier 				l = MACHP(0)->ticks - l;
8398e32b400SDavid du Colombier 			l = TK2MS(l);
8408e32b400SDavid du Colombier 			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
8418e32b400SDavid du Colombier 		}
8428e32b400SDavid du Colombier 		memmove(buf, tmp+k, n);
8438e32b400SDavid du Colombier 		return n;
8448e32b400SDavid du Colombier 
8458e32b400SDavid du Colombier 	case Qkmesg:
8468e32b400SDavid du Colombier 		/*
8478e32b400SDavid du Colombier 		 * This is unlocked to avoid tying up a process
8488e32b400SDavid du Colombier 		 * that's writing to the buffer.  kmesg.n never
8498e32b400SDavid du Colombier 		 * gets smaller, so worst case the reader will
8508e32b400SDavid du Colombier 		 * see a slurred buffer.
8518e32b400SDavid du Colombier 		 */
8528e32b400SDavid du Colombier 		if(off >= kmesg.n)
8538e32b400SDavid du Colombier 			n = 0;
8548e32b400SDavid du Colombier 		else{
8558e32b400SDavid du Colombier 			if(off+n > kmesg.n)
8568e32b400SDavid du Colombier 				n = kmesg.n - off;
8578e32b400SDavid du Colombier 			memmove(buf, kmesg.buf+off, n);
8588e32b400SDavid du Colombier 		}
8598e32b400SDavid du Colombier 		return n;
8608e32b400SDavid du Colombier 
8618e32b400SDavid du Colombier 	case Qkprint:
8628e32b400SDavid du Colombier 		return qread(kprintoq, buf, n);
8638e32b400SDavid du Colombier 
8648e32b400SDavid du Colombier 	case Qpgrpid:
8658e32b400SDavid du Colombier 		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE);
8668e32b400SDavid du Colombier 
8678e32b400SDavid du Colombier 	case Qpid:
8688e32b400SDavid du Colombier 		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE);
8698e32b400SDavid du Colombier 
8708e32b400SDavid du Colombier 	case Qppid:
8718e32b400SDavid du Colombier 		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE);
8728e32b400SDavid du Colombier 
8738e32b400SDavid du Colombier 	case Qtime:
8748e32b400SDavid du Colombier 		return readtime((ulong)offset, buf, n);
8758e32b400SDavid du Colombier 
8768e32b400SDavid du Colombier 	case Qbintime:
8778e32b400SDavid du Colombier 		return readbintime(buf, n);
8788e32b400SDavid du Colombier 
8798e32b400SDavid du Colombier 	case Qhostowner:
8808e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, eve);
8818e32b400SDavid du Colombier 
8828e32b400SDavid du Colombier 	case Qhostdomain:
8838e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, hostdomain);
8848e32b400SDavid du Colombier 
8858e32b400SDavid du Colombier 	case Quser:
8868e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, up->user);
8878e32b400SDavid du Colombier 
8888e32b400SDavid du Colombier 	case Qnull:
8898e32b400SDavid du Colombier 		return 0;
8908e32b400SDavid du Colombier 
8918e32b400SDavid du Colombier 	case Qsysstat:
8928e32b400SDavid du Colombier 		b = smalloc(conf.nmach*(NUMSIZE*11+1) + 1);	/* +1 for NUL */
8938e32b400SDavid du Colombier 		bp = b;
8948e32b400SDavid du Colombier 		for(id = 0; id < 32; id++) {
8958e32b400SDavid du Colombier 			if(active.machs & (1<<id)) {
8968e32b400SDavid du Colombier 				mp = MACHP(id);
8978e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, id, NUMSIZE);
8988e32b400SDavid du Colombier 				bp += NUMSIZE;
8998e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE);
9008e32b400SDavid du Colombier 				bp += NUMSIZE;
9018e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE);
9028e32b400SDavid du Colombier 				bp += NUMSIZE;
9038e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE);
9048e32b400SDavid du Colombier 				bp += NUMSIZE;
9058e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE);
9068e32b400SDavid du Colombier 				bp += NUMSIZE;
9078e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE);
9088e32b400SDavid du Colombier 				bp += NUMSIZE;
9098e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE);
9108e32b400SDavid du Colombier 				bp += NUMSIZE;
9118e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE);
9128e32b400SDavid du Colombier 				bp += NUMSIZE;
9138e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE,
9148e32b400SDavid du Colombier 					(mp->perf.avg_inidle*100)/mp->perf.period,
9158e32b400SDavid du Colombier 					NUMSIZE);
9168e32b400SDavid du Colombier 				bp += NUMSIZE;
9178e32b400SDavid du Colombier 				readnum(0, bp, NUMSIZE,
9188e32b400SDavid du Colombier 					(mp->perf.avg_inintr*100)/mp->perf.period,
9198e32b400SDavid du Colombier 					NUMSIZE);
9208e32b400SDavid du Colombier 				bp += NUMSIZE;
9218e32b400SDavid du Colombier 				*bp++ = '\n';
9228e32b400SDavid du Colombier 			}
9238e32b400SDavid du Colombier 		}
9248e32b400SDavid du Colombier 		if(waserror()){
9258e32b400SDavid du Colombier 			free(b);
9268e32b400SDavid du Colombier 			nexterror();
9278e32b400SDavid du Colombier 		}
9288e32b400SDavid du Colombier 		n = readstr((ulong)offset, buf, n, b);
9298e32b400SDavid du Colombier 		free(b);
9308e32b400SDavid du Colombier 		poperror();
9318e32b400SDavid du Colombier 		return n;
9328e32b400SDavid du Colombier 
9338e32b400SDavid du Colombier 	case Qswap:
9348e32b400SDavid du Colombier 		snprint(tmp, sizeof tmp,
9358e32b400SDavid du Colombier 			"%lud memory\n"
9368e32b400SDavid du Colombier 			"%d pagesize\n"
9378e32b400SDavid du Colombier 			"%lud kernel\n"
9388e32b400SDavid du Colombier 			"%lud/%lud user\n"
9398e32b400SDavid du Colombier 			"%lud/%lud swap\n"
9408e32b400SDavid du Colombier 			"%lud/%lud kernel malloc\n"
9418e32b400SDavid du Colombier 			"%lud/%lud kernel draw\n",
9428e32b400SDavid du Colombier 			conf.npage*BY2PG,
9438e32b400SDavid du Colombier 			BY2PG,
9448e32b400SDavid du Colombier 			conf.npage-conf.upages,
9458e32b400SDavid du Colombier 			palloc.user-palloc.freecount, palloc.user,
9468e32b400SDavid du Colombier 			conf.nswap-swapalloc.free, conf.nswap,
9478e32b400SDavid du Colombier 			mainmem->cursize, mainmem->maxsize,
9488e32b400SDavid du Colombier 			imagmem->cursize, imagmem->maxsize);
9498e32b400SDavid du Colombier 
9508e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, tmp);
9518e32b400SDavid du Colombier 
9528e32b400SDavid du Colombier 	case Qsysname:
9538e32b400SDavid du Colombier 		if(sysname == nil)
9548e32b400SDavid du Colombier 			return 0;
9558e32b400SDavid du Colombier 		return readstr((ulong)offset, buf, n, sysname);
9568e32b400SDavid du Colombier 
9578e32b400SDavid du Colombier 	case Qrandom:
9588e32b400SDavid du Colombier 		return randomread(buf, n);
9598e32b400SDavid du Colombier 
9608e32b400SDavid du Colombier 	case Qdrivers:
9618e32b400SDavid du Colombier 		b = malloc(READSTR);
9628e32b400SDavid du Colombier 		if(b == nil)
9638e32b400SDavid du Colombier 			error(Enomem);
9648e32b400SDavid du Colombier 		n = 0;
9658e32b400SDavid du Colombier 		for(i = 0; devtab[i] != nil; i++)
9668e32b400SDavid du Colombier 			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name);
9678e32b400SDavid du Colombier 		if(waserror()){
9688e32b400SDavid du Colombier 			free(b);
9698e32b400SDavid du Colombier 			nexterror();
9708e32b400SDavid du Colombier 		}
9718e32b400SDavid du Colombier 		n = readstr((ulong)offset, buf, n, b);
9728e32b400SDavid du Colombier 		free(b);
9738e32b400SDavid du Colombier 		poperror();
9748e32b400SDavid du Colombier 		return n;
9758e32b400SDavid du Colombier 
9768e32b400SDavid du Colombier 	case Qzero:
9778e32b400SDavid du Colombier 		memset(buf, 0, n);
9788e32b400SDavid du Colombier 		return n;
9798e32b400SDavid du Colombier 
9808e32b400SDavid du Colombier 	case Qosversion:
9818e32b400SDavid du Colombier 		snprint(tmp, sizeof tmp, "2000");
9828e32b400SDavid du Colombier 		n = readstr((ulong)offset, buf, n, tmp);
9838e32b400SDavid du Colombier 		return n;
9848e32b400SDavid du Colombier 
9858e32b400SDavid du Colombier 	default:
9868e32b400SDavid du Colombier 		print("consread %#llux\n", c->qid.path);
9878e32b400SDavid du Colombier 		error(Egreg);
9888e32b400SDavid du Colombier 	}
9898e32b400SDavid du Colombier 	return -1;		/* never reached */
9908e32b400SDavid du Colombier }
9918e32b400SDavid du Colombier 
9928e32b400SDavid du Colombier static long
9938e32b400SDavid du Colombier conswrite(Chan *c, void *va, long n, vlong off)
9948e32b400SDavid du Colombier {
9958e32b400SDavid du Colombier 	char buf[256], ch;
9968e32b400SDavid du Colombier 	long l, bp;
9978e32b400SDavid du Colombier 	char *a;
9988e32b400SDavid du Colombier 	Mach *mp;
9998e32b400SDavid du Colombier 	int id, fd;
10008e32b400SDavid du Colombier 	Chan *swc;
10018e32b400SDavid du Colombier 	ulong offset;
10028e32b400SDavid du Colombier 	Cmdbuf *cb;
10038e32b400SDavid du Colombier 	Cmdtab *ct;
10048e32b400SDavid du Colombier 
10058e32b400SDavid du Colombier 	a = va;
10068e32b400SDavid du Colombier 	offset = off;
10078e32b400SDavid du Colombier 
10088e32b400SDavid du Colombier 	switch((ulong)c->qid.path){
10098e32b400SDavid du Colombier 	case Qcons:
10108e32b400SDavid du Colombier 		/*
10118e32b400SDavid du Colombier 		 * Can't page fault in putstrn, so copy the data locally.
10128e32b400SDavid du Colombier 		 */
10138e32b400SDavid du Colombier 		l = n;
10148e32b400SDavid du Colombier 		while(l > 0){
10158e32b400SDavid du Colombier 			bp = l;
10168e32b400SDavid du Colombier 			if(bp > sizeof buf)
10178e32b400SDavid du Colombier 				bp = sizeof buf;
10188e32b400SDavid du Colombier 			memmove(buf, a, bp);
10198e32b400SDavid du Colombier 			putstrn0(buf, bp, 1);
10208e32b400SDavid du Colombier 			a += bp;
10218e32b400SDavid du Colombier 			l -= bp;
10228e32b400SDavid du Colombier 		}
10238e32b400SDavid du Colombier 		break;
10248e32b400SDavid du Colombier 
10258e32b400SDavid du Colombier 	case Qconsctl:
10268e32b400SDavid du Colombier 		if(n >= sizeof(buf))
10278e32b400SDavid du Colombier 			n = sizeof(buf)-1;
10288e32b400SDavid du Colombier 		strncpy(buf, a, n);
10298e32b400SDavid du Colombier 		buf[n] = 0;
10308e32b400SDavid du Colombier 		for(a = buf; a;){
10318e32b400SDavid du Colombier 			if(strncmp(a, "rawon", 5) == 0){
10328e32b400SDavid du Colombier 				kbd.raw = 1;
10338e32b400SDavid du Colombier 				/* clumsy hack - wake up reader */
10348e32b400SDavid du Colombier 				ch = 0;
10358e32b400SDavid du Colombier 				qwrite(kbdq, &ch, 1);
10368e32b400SDavid du Colombier 			} else if(strncmp(a, "rawoff", 6) == 0){
10378e32b400SDavid du Colombier 				kbd.raw = 0;
10388e32b400SDavid du Colombier 			} else if(strncmp(a, "ctlpon", 6) == 0){
10398e32b400SDavid du Colombier 				kbd.ctlpoff = 0;
10408e32b400SDavid du Colombier 			} else if(strncmp(a, "ctlpoff", 7) == 0){
10418e32b400SDavid du Colombier 				kbd.ctlpoff = 1;
10428e32b400SDavid du Colombier 			}
10438e32b400SDavid du Colombier 			if(a = strchr(a, ' '))
10448e32b400SDavid du Colombier 				a++;
10458e32b400SDavid du Colombier 		}
10468e32b400SDavid du Colombier 		break;
10478e32b400SDavid du Colombier 
10488e32b400SDavid du Colombier 	case Qtime:
10498e32b400SDavid du Colombier 		if(!iseve())
10508e32b400SDavid du Colombier 			error(Eperm);
10518e32b400SDavid du Colombier 		return writetime(a, n);
10528e32b400SDavid du Colombier 
10538e32b400SDavid du Colombier 	case Qbintime:
10548e32b400SDavid du Colombier 		if(!iseve())
10558e32b400SDavid du Colombier 			error(Eperm);
10568e32b400SDavid du Colombier 		return writebintime(a, n);
10578e32b400SDavid du Colombier 
10588e32b400SDavid du Colombier 	case Qhostowner:
10598e32b400SDavid du Colombier 		return hostownerwrite(a, n);
10608e32b400SDavid du Colombier 
10618e32b400SDavid du Colombier 	case Qhostdomain:
10628e32b400SDavid du Colombier 		return hostdomainwrite(a, n);
10638e32b400SDavid du Colombier 
10648e32b400SDavid du Colombier 	case Quser:
10658e32b400SDavid du Colombier 		return userwrite(a, n);
10668e32b400SDavid du Colombier 
10678e32b400SDavid du Colombier 	case Qnull:
10688e32b400SDavid du Colombier 		break;
10698e32b400SDavid du Colombier 
10708e32b400SDavid du Colombier 	case Qreboot:
10718e32b400SDavid du Colombier 		if(!iseve())
10728e32b400SDavid du Colombier 			error(Eperm);
10738e32b400SDavid du Colombier 		cb = parsecmd(a, n);
10748e32b400SDavid du Colombier 
10758e32b400SDavid du Colombier 		if(waserror()) {
10768e32b400SDavid du Colombier 			free(cb);
10778e32b400SDavid du Colombier 			nexterror();
10788e32b400SDavid du Colombier 		}
10798e32b400SDavid du Colombier 		ct = lookupcmd(cb, rebootmsg, nelem(rebootmsg));
10808e32b400SDavid du Colombier 		switch(ct->index) {
10818e32b400SDavid du Colombier 		case CMhalt:
10828e32b400SDavid du Colombier 			reboot(nil, 0, 0);
10838e32b400SDavid du Colombier 			break;
10848e32b400SDavid du Colombier 		case CMreboot:
10858e32b400SDavid du Colombier 			rebootcmd(cb->nf-1, cb->f+1);
10868e32b400SDavid du Colombier 			break;
10878e32b400SDavid du Colombier 		case CMpanic:
10888e32b400SDavid du Colombier 			*(ulong*)0=0;
10898e32b400SDavid du Colombier 			panic("/dev/reboot");
10908e32b400SDavid du Colombier 		}
10918e32b400SDavid du Colombier 		poperror();
10928e32b400SDavid du Colombier 		free(cb);
10938e32b400SDavid du Colombier 		break;
10948e32b400SDavid du Colombier 
10958e32b400SDavid du Colombier 	case Qsysstat:
10968e32b400SDavid du Colombier 		for(id = 0; id < 32; id++) {
10978e32b400SDavid du Colombier 			if(active.machs & (1<<id)) {
10988e32b400SDavid du Colombier 				mp = MACHP(id);
10998e32b400SDavid du Colombier 				mp->cs = 0;
11008e32b400SDavid du Colombier 				mp->intr = 0;
11018e32b400SDavid du Colombier 				mp->syscall = 0;
11028e32b400SDavid du Colombier 				mp->pfault = 0;
11038e32b400SDavid du Colombier 				mp->tlbfault = 0;
11048e32b400SDavid du Colombier 				mp->tlbpurge = 0;
11058e32b400SDavid du Colombier 			}
11068e32b400SDavid du Colombier 		}
11078e32b400SDavid du Colombier 		break;
11088e32b400SDavid du Colombier 
11098e32b400SDavid du Colombier 	case Qswap:
11108e32b400SDavid du Colombier 		if(n >= sizeof buf)
11118e32b400SDavid du Colombier 			error(Egreg);
11128e32b400SDavid du Colombier 		memmove(buf, va, n);	/* so we can NUL-terminate */
11138e32b400SDavid du Colombier 		buf[n] = 0;
11148e32b400SDavid du Colombier 		/* start a pager if not already started */
11158e32b400SDavid du Colombier 		if(strncmp(buf, "start", 5) == 0){
11168e32b400SDavid du Colombier 			kickpager();
11178e32b400SDavid du Colombier 			break;
11188e32b400SDavid du Colombier 		}
11198e32b400SDavid du Colombier 		if(!iseve())
11208e32b400SDavid du Colombier 			error(Eperm);
11218e32b400SDavid du Colombier 		if(buf[0]<'0' || '9'<buf[0])
11228e32b400SDavid du Colombier 			error(Ebadarg);
11238e32b400SDavid du Colombier 		fd = strtoul(buf, 0, 0);
11248e32b400SDavid du Colombier 		swc = fdtochan(fd, -1, 1, 1);
11258e32b400SDavid du Colombier 		setswapchan(swc);
11268e32b400SDavid du Colombier 		break;
11278e32b400SDavid du Colombier 
11288e32b400SDavid du Colombier 	case Qsysname:
11298e32b400SDavid du Colombier 		if(offset != 0)
11308e32b400SDavid du Colombier 			error(Ebadarg);
11318e32b400SDavid du Colombier 		if(n <= 0 || n >= sizeof buf)
11328e32b400SDavid du Colombier 			error(Ebadarg);
11338e32b400SDavid du Colombier 		strncpy(buf, a, n);
11348e32b400SDavid du Colombier 		buf[n] = 0;
11358e32b400SDavid du Colombier 		if(buf[n-1] == '\n')
11368e32b400SDavid du Colombier 			buf[n-1] = 0;
11378e32b400SDavid du Colombier 		kstrdup(&sysname, buf);
11388e32b400SDavid du Colombier 		break;
11398e32b400SDavid du Colombier 
11408e32b400SDavid du Colombier 	default:
11418e32b400SDavid du Colombier 		print("conswrite: %#llux\n", c->qid.path);
11428e32b400SDavid du Colombier 		error(Egreg);
11438e32b400SDavid du Colombier 	}
11448e32b400SDavid du Colombier 	return n;
11458e32b400SDavid du Colombier }
11468e32b400SDavid du Colombier 
11478e32b400SDavid du Colombier Dev consdevtab = {
11488e32b400SDavid du Colombier 	'c',
11498e32b400SDavid du Colombier 	"cons",
11508e32b400SDavid du Colombier 
11518e32b400SDavid du Colombier 	devreset,
11528e32b400SDavid du Colombier 	consinit,
11538e32b400SDavid du Colombier 	devshutdown,
11548e32b400SDavid du Colombier 	consattach,
11558e32b400SDavid du Colombier 	conswalk,
11568e32b400SDavid du Colombier 	consstat,
11578e32b400SDavid du Colombier 	consopen,
11588e32b400SDavid du Colombier 	devcreate,
11598e32b400SDavid du Colombier 	consclose,
11608e32b400SDavid du Colombier 	consread,
11618e32b400SDavid du Colombier 	devbread,
11628e32b400SDavid du Colombier 	conswrite,
11638e32b400SDavid du Colombier 	devbwrite,
11648e32b400SDavid du Colombier 	devremove,
11658e32b400SDavid du Colombier 	devwstat,
11668e32b400SDavid du Colombier };
11678e32b400SDavid du Colombier 
11688e32b400SDavid du Colombier static	ulong	randn;
11698e32b400SDavid du Colombier 
11708e32b400SDavid du Colombier static void
11718e32b400SDavid du Colombier seedrand(void)
11728e32b400SDavid du Colombier {
11738e32b400SDavid du Colombier 	if(!waserror()){
11748e32b400SDavid du Colombier 		randomread((void*)&randn, sizeof(randn));
11758e32b400SDavid du Colombier 		poperror();
11768e32b400SDavid du Colombier 	}
11778e32b400SDavid du Colombier }
11788e32b400SDavid du Colombier 
11798e32b400SDavid du Colombier int
11808e32b400SDavid du Colombier nrand(int n)
11818e32b400SDavid du Colombier {
11828e32b400SDavid du Colombier 	if(randn == 0)
11838e32b400SDavid du Colombier 		seedrand();
11848e32b400SDavid du Colombier 	randn = randn*1103515245 + 12345 + MACHP(0)->ticks;
11858e32b400SDavid du Colombier 	return (randn>>16) % n;
11868e32b400SDavid du Colombier }
11878e32b400SDavid du Colombier 
11888e32b400SDavid du Colombier int
11898e32b400SDavid du Colombier rand(void)
11908e32b400SDavid du Colombier {
11918e32b400SDavid du Colombier 	nrand(1);
11928e32b400SDavid du Colombier 	return randn;
11938e32b400SDavid du Colombier }
11948e32b400SDavid du Colombier 
11958e32b400SDavid du Colombier static uvlong uvorder = 0x0001020304050607ULL;
11968e32b400SDavid du Colombier 
11978e32b400SDavid du Colombier static uchar*
11988e32b400SDavid du Colombier le2vlong(vlong *to, uchar *f)
11998e32b400SDavid du Colombier {
12008e32b400SDavid du Colombier 	uchar *t, *o;
12018e32b400SDavid du Colombier 	int i;
12028e32b400SDavid du Colombier 
12038e32b400SDavid du Colombier 	t = (uchar*)to;
12048e32b400SDavid du Colombier 	o = (uchar*)&uvorder;
12058e32b400SDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
12068e32b400SDavid du Colombier 		t[o[i]] = f[i];
12078e32b400SDavid du Colombier 	return f+sizeof(vlong);
12088e32b400SDavid du Colombier }
12098e32b400SDavid du Colombier 
12108e32b400SDavid du Colombier static uchar*
12118e32b400SDavid du Colombier vlong2le(uchar *t, vlong from)
12128e32b400SDavid du Colombier {
12138e32b400SDavid du Colombier 	uchar *f, *o;
12148e32b400SDavid du Colombier 	int i;
12158e32b400SDavid du Colombier 
12168e32b400SDavid du Colombier 	f = (uchar*)&from;
12178e32b400SDavid du Colombier 	o = (uchar*)&uvorder;
12188e32b400SDavid du Colombier 	for(i = 0; i < sizeof(vlong); i++)
12198e32b400SDavid du Colombier 		t[i] = f[o[i]];
12208e32b400SDavid du Colombier 	return t+sizeof(vlong);
12218e32b400SDavid du Colombier }
12228e32b400SDavid du Colombier 
12238e32b400SDavid du Colombier static long order = 0x00010203;
12248e32b400SDavid du Colombier 
12258e32b400SDavid du Colombier static uchar*
12268e32b400SDavid du Colombier le2long(long *to, uchar *f)
12278e32b400SDavid du Colombier {
12288e32b400SDavid du Colombier 	uchar *t, *o;
12298e32b400SDavid du Colombier 	int i;
12308e32b400SDavid du Colombier 
12318e32b400SDavid du Colombier 	t = (uchar*)to;
12328e32b400SDavid du Colombier 	o = (uchar*)&order;
12338e32b400SDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12348e32b400SDavid du Colombier 		t[o[i]] = f[i];
12358e32b400SDavid du Colombier 	return f+sizeof(long);
12368e32b400SDavid du Colombier }
12378e32b400SDavid du Colombier 
12388e32b400SDavid du Colombier static uchar*
12398e32b400SDavid du Colombier long2le(uchar *t, long from)
12408e32b400SDavid du Colombier {
12418e32b400SDavid du Colombier 	uchar *f, *o;
12428e32b400SDavid du Colombier 	int i;
12438e32b400SDavid du Colombier 
12448e32b400SDavid du Colombier 	f = (uchar*)&from;
12458e32b400SDavid du Colombier 	o = (uchar*)&order;
12468e32b400SDavid du Colombier 	for(i = 0; i < sizeof(long); i++)
12478e32b400SDavid du Colombier 		t[i] = f[o[i]];
12488e32b400SDavid du Colombier 	return t+sizeof(long);
12498e32b400SDavid du Colombier }
12508e32b400SDavid du Colombier 
12518e32b400SDavid du Colombier char *Ebadtimectl = "bad time control";
12528e32b400SDavid du Colombier 
12538e32b400SDavid du Colombier /*
12548e32b400SDavid du Colombier  *  like the old #c/time but with added info.  Return
12558e32b400SDavid du Colombier  *
12568e32b400SDavid du Colombier  *	secs	nanosecs	fastticks	fasthz
12578e32b400SDavid du Colombier  */
12588e32b400SDavid du Colombier static int
12598e32b400SDavid du Colombier readtime(ulong off, char *buf, int n)
12608e32b400SDavid du Colombier {
12618e32b400SDavid du Colombier 	vlong	nsec, ticks;
12628e32b400SDavid du Colombier 	long sec;
12638e32b400SDavid du Colombier 	char str[7*NUMSIZE];
12648e32b400SDavid du Colombier 
12658e32b400SDavid du Colombier 	nsec = todget(&ticks);
12668e32b400SDavid du Colombier 	if(fasthz == 0LL)
12678e32b400SDavid du Colombier 		fastticks((uvlong*)&fasthz);
12688e32b400SDavid du Colombier 	sec = nsec/1000000000ULL;
12698e32b400SDavid du Colombier 	snprint(str, sizeof(str), "%*lud %*llud %*llud %*llud ",
12708e32b400SDavid du Colombier 		NUMSIZE-1, sec,
12718e32b400SDavid du Colombier 		VLNUMSIZE-1, nsec,
12728e32b400SDavid du Colombier 		VLNUMSIZE-1, ticks,
12738e32b400SDavid du Colombier 		VLNUMSIZE-1, fasthz);
12748e32b400SDavid du Colombier 	return readstr(off, buf, n, str);
12758e32b400SDavid du Colombier }
12768e32b400SDavid du Colombier 
12778e32b400SDavid du Colombier /*
12788e32b400SDavid du Colombier  *  set the time in seconds
12798e32b400SDavid du Colombier  */
12808e32b400SDavid du Colombier static int
12818e32b400SDavid du Colombier writetime(char *buf, int n)
12828e32b400SDavid du Colombier {
12838e32b400SDavid du Colombier 	char b[13];
12848e32b400SDavid du Colombier 	long i;
12858e32b400SDavid du Colombier 	vlong now;
12868e32b400SDavid du Colombier 
12878e32b400SDavid du Colombier 	if(n >= sizeof(b))
12888e32b400SDavid du Colombier 		error(Ebadtimectl);
12898e32b400SDavid du Colombier 	strncpy(b, buf, n);
12908e32b400SDavid du Colombier 	b[n] = 0;
12918e32b400SDavid du Colombier 	i = strtol(b, 0, 0);
12928e32b400SDavid du Colombier 	if(i <= 0)
12938e32b400SDavid du Colombier 		error(Ebadtimectl);
12948e32b400SDavid du Colombier 	now = i*1000000000LL;
12958e32b400SDavid du Colombier 	todset(now, 0, 0);
12968e32b400SDavid du Colombier 	return n;
12978e32b400SDavid du Colombier }
12988e32b400SDavid du Colombier 
12998e32b400SDavid du Colombier /*
13008e32b400SDavid du Colombier  *  read binary time info.  all numbers are little endian.
13018e32b400SDavid du Colombier  *  ticks and nsec are syncronized.
13028e32b400SDavid du Colombier  */
13038e32b400SDavid du Colombier static int
13048e32b400SDavid du Colombier readbintime(char *buf, int n)
13058e32b400SDavid du Colombier {
13068e32b400SDavid du Colombier 	int i;
13078e32b400SDavid du Colombier 	vlong nsec, ticks;
13088e32b400SDavid du Colombier 	uchar *b = (uchar*)buf;
13098e32b400SDavid du Colombier 
13108e32b400SDavid du Colombier 	i = 0;
13118e32b400SDavid du Colombier 	if(fasthz == 0LL)
13128e32b400SDavid du Colombier 		fastticks((uvlong*)&fasthz);
13138e32b400SDavid du Colombier 	nsec = todget(&ticks);
13148e32b400SDavid du Colombier 	if(n >= 3*sizeof(uvlong)){
13158e32b400SDavid du Colombier 		vlong2le(b+2*sizeof(uvlong), fasthz);
13168e32b400SDavid du Colombier 		i += sizeof(uvlong);
13178e32b400SDavid du Colombier 	}
13188e32b400SDavid du Colombier 	if(n >= 2*sizeof(uvlong)){
13198e32b400SDavid du Colombier 		vlong2le(b+sizeof(uvlong), ticks);
13208e32b400SDavid du Colombier 		i += sizeof(uvlong);
13218e32b400SDavid du Colombier 	}
13228e32b400SDavid du Colombier 	if(n >= 8){
13238e32b400SDavid du Colombier 		vlong2le(b, nsec);
13248e32b400SDavid du Colombier 		i += sizeof(vlong);
13258e32b400SDavid du Colombier 	}
13268e32b400SDavid du Colombier 	return i;
13278e32b400SDavid du Colombier }
13288e32b400SDavid du Colombier 
13298e32b400SDavid du Colombier /*
13308e32b400SDavid du Colombier  *  set any of the following
13318e32b400SDavid du Colombier  *	- time in nsec
13328e32b400SDavid du Colombier  *	- nsec trim applied over some seconds
13338e32b400SDavid du Colombier  *	- clock frequency
13348e32b400SDavid du Colombier  */
13358e32b400SDavid du Colombier static int
13368e32b400SDavid du Colombier writebintime(char *buf, int n)
13378e32b400SDavid du Colombier {
13388e32b400SDavid du Colombier 	uchar *p;
13398e32b400SDavid du Colombier 	vlong delta;
13408e32b400SDavid du Colombier 	long period;
13418e32b400SDavid du Colombier 
13428e32b400SDavid du Colombier 	n--;
13438e32b400SDavid du Colombier 	p = (uchar*)buf + 1;
13448e32b400SDavid du Colombier 	switch(*buf){
13458e32b400SDavid du Colombier 	case 'n':
13468e32b400SDavid du Colombier 		if(n < sizeof(vlong))
13478e32b400SDavid du Colombier 			error(Ebadtimectl);
13488e32b400SDavid du Colombier 		le2vlong(&delta, p);
13498e32b400SDavid du Colombier 		todset(delta, 0, 0);
13508e32b400SDavid du Colombier 		break;
13518e32b400SDavid du Colombier 	case 'd':
13528e32b400SDavid du Colombier 		if(n < sizeof(vlong)+sizeof(long))
13538e32b400SDavid du Colombier 			error(Ebadtimectl);
13548e32b400SDavid du Colombier 		p = le2vlong(&delta, p);
13558e32b400SDavid du Colombier 		le2long(&period, p);
13568e32b400SDavid du Colombier 		todset(-1, delta, period);
13578e32b400SDavid du Colombier 		break;
13588e32b400SDavid du Colombier 	case 'f':
13598e32b400SDavid du Colombier 		if(n < sizeof(uvlong))
13608e32b400SDavid du Colombier 			error(Ebadtimectl);
13618e32b400SDavid du Colombier 		le2vlong(&fasthz, p);
13628e32b400SDavid du Colombier 		if(fasthz <= 0)
13638e32b400SDavid du Colombier 			error(Ebadtimectl);
13648e32b400SDavid du Colombier 		todsetfreq(fasthz);
13658e32b400SDavid du Colombier 		break;
13668e32b400SDavid du Colombier 	}
13678e32b400SDavid du Colombier 	return n;
13688e32b400SDavid du Colombier }
1369