All qlocks are initialized
[akaros.git] / kern / drivers / dev / cons.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 extern char *eve;
17 /* much stuff not ready yet. */
18 #if 0
19 extern int cflag;
20 extern int keepbroken;
21
22 void    (*serwrite)(char *, int);
23
24 struct queue*   kscanq;                 /* keyboard raw scancodes (when needed) */
25 char*   kscanid;                /* name of raw scan format (if defined) */
26 struct queue*   kbdq;                   /* unprocessed console input */
27 struct queue*   lineq;                  /* processed console input */
28 struct queue*   printq;                 /* console output */
29 struct queue*   klogq;                  /* kernel print (log) output */
30 int     iprintscreenputs;
31
32 static struct
33 {
34         rwlock_t rwlock;
35         Queue*  q;
36 } kprintq;
37
38 static struct
39 {
40         qlock_t qlock;
41
42         int     raw;            /* true if we shouldn't process input */
43         int     ctl;            /* number of opens to the control file */
44         int     kbdr;           /* number of open reads to the keyboard */
45         int     scan;           /* true if reading raw scancodes */
46         int     x;              /* index into line */
47         char    line[1024];     /* current input line */
48
49         char    c;
50         int     count;
51         int     repeat;
52 } kbd;
53
54 #endif
55 char*   sysname = "Your machine";
56 char*   eve = "eve";
57
58 enum
59 {
60         CMreboot,
61         CMhalt,
62         CMpanic,
63         CMbroken,
64         CMnobroken,
65         CMconsole,
66 };
67
68 static struct cmdtab sysctlcmd[] =
69 {
70         {CMreboot,      "reboot",       0},
71         {CMhalt,        "halt", 0},
72         {CMpanic,       "panic", 0},
73         {CMconsole,     "console", 1},
74         {CMbroken,      "broken", 0},
75         {CMnobroken,    "nobroken", 0},
76 };
77
78 void
79 printinit(void)
80 {
81 #if 0
82         lineq = qopen(2*1024, 0, NULL, NULL);
83         if(lineq == NULL)
84                 panic("printinit");
85         qnoblock(lineq, 1);
86 #endif
87 }
88
89 /*
90  *  return true if current user is eve
91  */
92 int
93 iseve(void)
94 {
95 #if 0
96         Osenv *o;
97
98         o = up->env;
99         return strcmp(eve, o->user) == 0;
100 #endif
101         return 1;
102 }
103
104 #if 0
105 static int
106 consactive(void)
107 {
108         if(printq)
109                 return qlen(printq) > 0;
110         return 0;
111 }
112
113 static void
114 prflush(void)
115 {
116         uint32_t now;
117
118         now = m->ticks;
119         while(serwrite==NULL && consactive())
120                 if(m->ticks - now >= HZ)
121                         break;
122 }
123
124 /*
125  *   Print a string on the console.  Convert \n to \r\n for serial
126  *   line consoles.  Locking of the queues is left up to the screen
127  *   or uart code.  Multi-line messages to serial consoles may get
128  *   interspersed with other messages.
129  */
130 static void
131 putstrn0(char *str, int n, int usewrite)
132 {
133         int m;
134         char *t;
135         char buf[PRINTSIZE+2];
136         ERRSTACK(1);
137
138         /*
139          *  if kprint is open, put the message there, otherwise
140          *  if there's an attached bit mapped display,
141          *  put the message there.
142          */
143         m = consoleprint;
144         if(canrlock(&(&kprintq)->rwlock)){
145                 if(kprintq.q != NULL){
146                         if(waserror()){
147                                 runlock(&(&kprintq)->rwlock);
148                                 nexterror();
149                         }
150                         if(usewrite)
151                                 qwrite(kprintq.q, str, n);
152                         else
153                                 qiwrite(kprintq.q, str, n);
154                         poperror();
155                         m = 0;
156                 }
157                 runlock(&(&kprintq)->rwlock);
158         }
159         if(m && screenputs != NULL)
160                 screenputs(str, n);
161
162         /*
163          *  if there's a serial line being used as a console,
164          *  put the message there.
165          */
166         if(serwrite != NULL) {
167                 serwrite(str, n);
168                 return;
169         }
170
171         if(printq == 0)
172                 return;
173
174         while(n > 0) {
175                 t = memchr(str, '\n', n);
176                 if(t && !kbd.raw) {
177                         m = t - str;
178                         if(m > sizeof(buf)-2)
179                                 m = sizeof(buf)-2;
180                         memmove(buf, str, m);
181                         buf[m] = '\r';
182                         buf[m+1] = '\n';
183                         if(usewrite)
184                                 qwrite(printq, buf, m+2);
185                         else
186                                 qiwrite(printq, buf, m+2);
187                         str = t + 1;
188                         n -= m + 1;
189                 } else {
190                         if(usewrite)
191                                 qwrite(printq, str, n);
192                         else 
193                                 qiwrite(printq, str, n);
194                         break;
195                 }
196         }
197 }
198
199 void
200 putstrn(char *str, int n)
201 {
202         putstrn0(str, n, 0);
203 }
204
205 int
206 snprintf(char *s, int n, char *fmt, ...)
207 {
208         va_list arg;
209
210         va_start(arg, fmt);
211         n = vseprintf(s, s+n, fmt, arg) - s;
212         va_end(arg);
213
214         return n;
215 }
216
217 int
218 sprint(char *s, char *fmt, ...)
219 {
220         int n;
221         va_list arg;
222
223         va_start(arg, fmt);
224         n = vseprintf(s, s+PRINTSIZE, fmt, arg) - s;
225         va_end(arg);
226
227         return n;
228 }
229
230 int
231 print(char *fmt, ...)
232 {
233         int n;
234         va_list arg;
235         char buf[PRINTSIZE];
236
237         va_start(arg, fmt);
238         n = vseprintf(buf, buf+sizeof(buf), fmt, arg) - buf;
239         va_end(arg);
240         putstrn(buf, n);
241
242         return n;
243 }
244
245 int
246 fprint(int fd, char *fmt, ...)
247 {
248         int n;
249         va_list arg;
250         char buf[PRINTSIZE];
251
252         va_start(arg, fmt);
253         n = vseprintf(buf, buf+sizeof(buf), fmt, arg) - buf;
254         va_end(arg);
255         putstrn(buf, n);
256
257         return n;
258 }
259
260 int
261 kprint(char *fmt, ...)
262 {
263         va_list arg;
264         char buf[PRINTSIZE];
265         int n;
266
267         va_start(arg, fmt);
268         n = vseprintf(buf, buf+sizeof(buf), fmt, arg) - buf;
269         va_end(arg);
270         if(qfull(klogq))
271                 qflush(klogq);
272         return qproduce(klogq, buf, n);
273 }
274
275 int
276 iprint(char *fmt, ...)
277 {
278         int n, s;
279         va_list arg;
280         char buf[PRINTSIZE];
281
282         s = splhi();
283         va_start(arg, fmt);
284         n = vseprintf(buf, buf+sizeof(buf), fmt, arg) - buf;
285         va_end(arg);
286         if(screenputs != NULL && iprintscreenputs)
287                 screenputs(buf, n);
288         uartputs(buf, n);
289         splx(s);
290
291         return n;
292 }
293
294 void
295 panic(char *fmt, ...)
296 {
297         int n;
298         va_list arg;
299         char buf[PRINTSIZE];
300
301         setpanic();
302         kprintq.q = NULL;
303         strncpy(buf,  "panic: ", sizeof(buf));
304         va_start(arg, fmt);
305         n = vseprintf(buf+strlen(buf), buf+sizeof(buf)-1, fmt, arg) - buf;
306         va_end(arg);
307         buf[n] = '\n';
308         putstrn(buf, n+1);
309         spllo();
310         dumpstack();
311
312         exit(1);
313 }
314
315 void
316 _assert(char *fmt)
317 {
318         panic("assert failed: %s", fmt);
319 }
320
321 /*
322  * mainly for libmp
323  */
324 void
325 sysfatal(char *fmt, ...)
326 {
327         va_list arg;
328         char buf[64];
329
330         va_start(arg, fmt);
331         vsnprintf(buf, sizeof(buf), fmt, arg);
332         va_end(arg);
333         error(buf);
334 }
335
336 int
337 pprint(char *fmt, ...)
338 {
339         ERRSTACK(1);
340         int n;
341         struct chan *c;
342         Osenv *o;
343         va_list arg;
344         char buf[2*PRINTSIZE];
345
346         n = sprint(buf, "%s %ld: ", up->text, up->pid);
347         va_start(arg, fmt);
348         n = vseprintf(buf+n, buf+sizeof(buf), fmt, arg) - buf;
349         va_end(arg);
350
351         o = up->env;
352         if(o->fgrp == 0) {
353                 printd("%s", buf);
354                 return 0;
355         }
356         /* TODO: this is probably wrong (VFS hack) */
357         c = o->fgrp->fd[2];
358         if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) {
359                 printd("%s", buf);
360                 return 0;
361         }
362
363         if(waserror()) {
364                 printd("%s", buf);
365                 poperror();
366                 return 0;
367         }
368         devtab[c->type]->write(c, buf, n, c->offset);
369         poperror();
370
371         spin_lock(&c->lock);
372         c->offset += n;
373         spin_unlock(&c->lock);
374
375         return n;
376 }
377
378 void
379 echo(Rune r, char *buf, int n)
380 {
381         if(kbd.raw)
382                 return;
383
384         if(r == '\n'){
385                 if(printq)
386                         qiwrite(printq, "\r", 1);
387         } else if(r == 0x15){
388                 buf = "^U\n";
389                 n = 3;
390         }
391         if(consoleprint && screenputs != NULL)
392                 screenputs(buf, n);
393         if(printq)
394                 qiwrite(printq, buf, n);
395 }
396 #endif
397 #if 0
398 /*
399  *      Debug key support.  Allows other parts of the kernel to register debug
400  *      key handlers, instead of devcons.c having to know whatever's out there.
401  *      A kproc is used to invoke most handlers, rather than tying up the CPU at
402  *      splhi, which can choke some device drivers (eg softmodem).
403  */
404 typedef struct {
405         Rune    r;
406         char    *m;
407         void    (*f)(Rune);
408         int     i;      /* function called at interrupt time */
409 } Dbgkey;
410
411 static struct {
412         Rendez;
413         Dbgkey  *work;
414         Dbgkey  keys[50];
415         int     nkeys;
416         int     on;
417 } dbg;
418
419 static Dbgkey *
420 finddbgkey(Rune r)
421 {
422         int i;
423         Dbgkey *dp;
424
425         for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
426                 if(dp->r == r)
427                         return dp;
428         return NULL;
429 }
430
431 static int
432 dbgwork(void *)
433 {
434         return dbg.work != 0;
435 }
436
437 static void
438 dbgproc(void *)
439 {
440         Dbgkey *dp;
441
442         setpri(PriRealtime);
443         for(;;) {
444                 do {
445                         rendez_sleep(&dbg, dbgwork, 0);
446                         dp = dbg.work;
447                 } while(dp == NULL);
448                 dp->f(dp->r);
449                 dbg.work = NULL;
450         }
451 }
452
453 void
454 debugkey(Rune r, char *msg, void (*fcn)(), int iflag)
455 {
456         Dbgkey *dp;
457
458         if(dbg.nkeys >= ARRAY_SIZE(dbg.keys))
459                 return;
460         if(finddbgkey(r) != NULL)
461                 return;
462         for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
463                 if(strcmp(dp->m, msg) < 0)
464                         break;
465                 dp[1] = dp[0];
466         }
467         dp++;
468         dp->r = r;
469         dp->m = msg;
470         dp->f = fcn;
471         dp->i = iflag;
472 }
473
474 static int
475 isdbgkey(Rune r)
476 {
477         static int ctrlt;
478         Dbgkey *dp;
479         int echoctrlt = ctrlt;
480
481         /*
482          * ^t hack BUG
483          */
484         if(dbg.on || (ctrlt >= 2)) {
485                 if(r == 0x14 || r == 0x05) {
486                         ctrlt++;
487                         return 0;
488                 }
489                 if(dp = finddbgkey(r)) {
490                         if(dp->i || ctrlt > 2)
491                                 dp->f(r);
492                         else {
493                                 dbg.work = dp;
494                                 rendez_wakeup(&dbg);
495                         }
496                         ctrlt = 0;
497                         return 1;
498                 }
499                 ctrlt = 0;
500         }
501         else if(r == 0x14){
502                 ctrlt++;
503                 return 1;
504         }
505         else
506                 ctrlt = 0;
507         if(echoctrlt){
508                 char buf[3];
509
510                 buf[0] = 0x14;
511                 while(--echoctrlt >= 0){
512                         echo(buf[0], buf, 1);
513                         qproduce(kbdq, buf, 1);
514                 }
515         }
516         return 0;
517 }
518
519 static void
520 dbgtoggle(Rune)
521 {
522         dbg.on = !dbg.on;
523         printd("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
524 }
525
526 static void
527 dbghelp(void)
528 {
529         int i;
530         Dbgkey *dp;
531         Dbgkey *dp2;
532         static char fmt[] = "%c: %-22s";
533
534         dp = dbg.keys;
535         dp2 = dp + (dbg.nkeys + 1)/2;
536         for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
537                 printd(fmt, dp->r, dp->m);
538                 printd(fmt, dp2->r, dp2->m);
539                 printd("\n");
540         }
541         if(i)
542                 printd(fmt, dp->r, dp->m);
543         printd("\n");
544 }
545
546 static void
547 debuginit(void)
548 {
549         ktask("consdbg", dbgproc, NULL);
550         debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
551         debugkey('?', "help", dbghelp, 0);
552 }
553 #endif
554 #if 0
555 /*
556  *  Called by a uart interrupt for console input.
557  *
558  *  turn '\r' into '\n' before putting it into the queue.
559  */
560 int
561 kbdcr2nl(struct queue *q, int ch)
562 {
563         if(ch == '\r')
564                 ch = '\n';
565         return kbdputc(q, ch);
566 }
567
568 /*
569  *  Put character, possibly a rune, into read queue at interrupt time.
570  *  Performs translation for compose sequences
571  *  Called at interrupt time to process a character.
572  */
573 int
574 kbdputc(struct queue *q, int ch)
575 {
576         int n;
577         char buf[3];
578         Rune r;
579         static Rune kc[15];
580         static int nk, collecting = 0;
581
582         r = ch;
583         if(r == Latin) {
584                 collecting = 1;
585                 nk = 0;
586                 return 0;
587         }
588         if(collecting) {
589                 int c;
590                 nk += runetochar(( char *unused_char_p_t)&kc[nk], &r);
591                 c = latin1(kc, nk);
592                 if(c < -1)      /* need more keystrokes */
593                         return 0;
594                 collecting = 0;
595                 if(c == -1) {   /* invalid sequence */
596                         echo(kc[0], ( char *unused_char_p_t)kc, nk);
597                         qproduce(q, kc, nk);
598                         return 0;
599                 }
600                 r = (Rune)c;
601         }
602         kbd.c = r;
603         n = runetochar(buf, &r);
604         if(n == 0)
605                 return 0;
606         if(!isdbgkey(r)) {
607                 echo(r, buf, n);
608                 qproduce(q, buf, n);
609         }
610         return 0;
611 }
612
613 void
614 kbdrepeat(int rep)
615 {
616         kbd.repeat = rep;
617         kbd.count = 0;
618 }
619
620 void
621 kbdclock(void)
622 {
623         if(kbd.repeat == 0)
624                 return;
625         if(kbd.repeat==1 && ++kbd.count>HZ){
626                 kbd.repeat = 2;
627                 kbd.count = 0;
628                 return;
629         }
630         if(++kbd.count&1)
631                 kbdputc(kbdq, kbd.c);
632 }
633 #endif
634
635 enum{
636         Qdir,
637         Qcons,
638         Qsysctl,
639         Qconsctl,
640         Qdrivers,
641         Qhostowner,
642         Qkeyboard,
643         Qklog,
644         Qkprint,
645         Qscancode,
646         Qmemory,
647         Qmsec,
648         Qnull,
649         Qrandom,
650         Qnotquiterandom,
651         Qsysname,
652         Qtime,
653         Quser,
654         Qjit,
655 };
656
657 static struct dirtab consdir[]=
658 {
659         {".",   {Qdir, 0, QTDIR},       0,              DMDIR|0555},
660         {"cons",                {Qcons},        0,              0660},
661         {"consctl",     {Qconsctl},     0,              0220},
662         {"sysctl",      {Qsysctl},      0,              0644},
663         {"drivers",     {Qdrivers},     0,              0444},
664         {"hostowner",   {Qhostowner},   0,      0644},
665         {"keyboard",    {Qkeyboard},    0,              0666},
666         {"klog",                {Qklog},        0,              0444},
667         {"kprint",              {Qkprint},      0,              0444},
668         {"scancode",    {Qscancode},    0,              0444},
669         {"memory",      {Qmemory},      0,              0444},
670         {"msec",                {Qmsec},        NUMSIZE,        0444},
671         {"null",                {Qnull},        0,              0666},
672         {"random",      {Qrandom},      0,              0444},
673         {"notquiterandom", {Qnotquiterandom}, 0,        0444},
674         {"sysname",     {Qsysname},     0,              0664},
675         {"time",                {Qtime},        0,              0664},
676         {"user",                {Quser},        0,      0644},
677         {"jit",         {Qjit}, 0,      0666},
678 };
679
680 uint32_t        boottime;               /* seconds since epoch at boot */
681
682 #if 0
683 void
684 fddump()
685 {
686         struct proc *p;
687         Osenv *o;
688         int i;
689         struct chan *c;
690
691         p = proctab(6);
692         o = p->env;
693         for(i = 0; i <= o->fgrp->maxfd; i++) {
694                 if((c = o->fgrp->fd[i]) == NULL)
695                         continue;
696                 printd("%d: %s\n", i, c->name == NULL? "???": c->name->s);
697         }
698 }
699 #endif
700
701 static void
702 consinit(void)
703 {
704         randominit();
705 #if 0
706         debuginit();
707         debugkey('f', "files/6", fddump, 0);
708         debugkey('q', "panic", qpanic, 1);
709         debugkey('r', "exit", rexit, 1);
710         klogq = qopen(128*1024, 0, 0, 0);
711 #endif
712 }
713
714 static struct chan*
715 consattach(char *spec)
716 {
717         return devattach('c', spec);
718 }
719
720 static struct walkqid*
721 conswalk(struct chan *c, struct chan *nc, char **name, int nname)
722 {
723         return devwalk(c, nc, name, nname, consdir, ARRAY_SIZE(consdir), devgen);
724 }
725
726 static int
727 consstat(struct chan *c, uint8_t *dp, int n)
728 {
729         return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
730 }
731
732 #if 0
733 static void
734 flushkbdline(struct queue *q)
735 {
736         if(kbd.x){
737                 qwrite(q, kbd.line, kbd.x);
738                 kbd.x = 0;
739         }
740 }
741 #endif
742
743 static struct chan*
744 consopen(struct chan *c, int omode)
745 {
746         c->aux = 0;
747 #if 0
748         switch((uint32_t)c->qid.path){
749         case Qconsctl:
750                 if(!iseve())
751                         error(Eperm);
752                 qlock(&(&kbd)->qlock);
753                 kbd.ctl++;
754                 qunlock(&(&kbd)->qlock);
755                 break;
756
757         case Qkeyboard:
758                 if((omode & 3) != OWRITE) {
759                         qlock(&(&kbd)->qlock);
760                         kbd.kbdr++;
761                         flushkbdline(kbdq);
762                         kbd.raw = 1;
763                         qunlock(&(&kbd)->qlock);
764                 }
765                 break;
766
767         case Qscancode:
768                 qlock(&(&kbd)->qlock);
769                 if(kscanq || !kscanid) {
770                         qunlock(&(&kbd)->qlock);
771                         c->flag &= ~COPEN;
772                         if(kscanq)
773                                 error(Einuse);
774                         else
775                                 error(Ebadarg);
776                 }
777                 kscanq = qopen(256, 0, NULL, NULL);
778                 qunlock(&(&kbd)->qlock);
779                 break;
780
781         case Qkprint:
782                 if((omode & 3) != OWRITE) {
783                         wlock(&(&kprintq)->rwlock);
784                         if(kprintq.q != NULL){
785                                 wunlock(&(&kprintq)->rwlock);
786                                 error(Einuse);
787                         }
788                         kprintq.q = qopen(32*1024, Qcoalesce, NULL, NULL);
789                         if(kprintq.q == NULL){
790                                 wunlock(&(&kprintq)->rwlock);
791                                 error(Enomem);
792                         }
793                         qnoblock(kprintq.q, 1);
794                         wunlock(&(&kprintq)->rwlock);
795                         c->iounit = qiomaxatomic;
796                 }
797                 break;
798         }
799 #endif
800         return devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
801 }
802
803 static void
804 consclose(struct chan *c)
805 {
806         if((c->flag&COPEN) == 0)
807                 return;
808
809         switch((uint32_t)c->qid.path){
810 #if 0
811         case Qconsctl:
812                 /* last close of control file turns off raw */
813                 qlock(&(&kbd)->qlock);
814                 if(--kbd.ctl == 0)
815                         kbd.raw = 0;
816                 qunlock(&(&kbd)->qlock);
817                 break;
818
819         case Qkeyboard:
820                 if(c->mode != OWRITE) {
821                         qlock(&(&kbd)->qlock);
822                         --kbd.kbdr;
823                         qunlock(&(&kbd)->qlock);
824                 }
825                 break;
826
827         case Qscancode:
828                 qlock(&(&kbd)->qlock);
829                 if(kscanq) {
830                         qfree(kscanq);
831                         kscanq = 0;
832                 }
833                 qunlock(&(&kbd)->qlock);
834                 break;
835
836         case Qkprint:
837                 wlock(&(&kprintq)->rwlock);
838                 qfree(kprintq.q);
839                 kprintq.q = NULL;
840                 wunlock(&(&kprintq)->rwlock);
841                 break;
842 #endif
843         default: 
844                 break;
845         }
846 }
847
848 /* we do it this way to avoid the many fun deadlock opportunities
849  * we keep hitting. And, if you don't suck it
850  * out soon enough, you lost it. No real effort to ensure goodness
851  * here as it can get called anywhere. Barret will fix it.
852  */
853 static uint8_t logbuffer[1<<20];
854 static int index = 0;
855 static struct queue *logqueue = NULL;
856 static int reading_kmesg = 0;
857 void logbuf(int c)
858 {
859         if (reading_kmesg)
860                 return;
861         if (index > 1<<20)
862                 return;
863         logbuffer[index++] = c;
864 }
865
866 static long
867 consread(struct chan *c, void *buf, long n, int64_t offset)
868 {
869         ERRSTACK(1);
870         int l;
871
872         int ch, eol, i;
873         char *p, tmp[128];
874         char *cbuf = buf;
875
876         if(n <= 0)
877                 return n;
878
879         switch((uint32_t)c->qid.path){
880         case Qdir:
881                 return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
882         case Qsysctl:
883                 return readstr(offset, buf, n, "akaros");
884 #if 0
885         case Qcons:
886         case Qkeyboard:
887                 qlock(&(&kbd)->qlock);
888                 if(waserror()) {
889                         qunlock(&(&kbd)->qlock);
890                         nexterror();
891                 }
892                 if(kbd.raw || kbd.kbdr) {
893                         if(qcanread(lineq))
894                                 n = qread(lineq, buf, n);
895                         else {
896                                 /* read as much as possible */
897                                 do {
898                                         i = qread(kbdq, cbuf, n);
899                                         cbuf += i;
900                                         n -= i;
901                                 } while(n>0 && qcanread(kbdq));
902                                 n = cbuf - ( char *unused_char_p_t)buf;
903                         }
904                 } else {
905                         while(!qcanread(lineq)) {
906                                 qread(kbdq, &kbd.line[kbd.x], 1);
907                                 ch = kbd.line[kbd.x];
908                                 eol = 0;
909                                 switch(ch){
910                                 case '\b':
911                                         if(kbd.x)
912                                                 kbd.x--;
913                                         break;
914                                 case 0x15:
915                                         kbd.x = 0;
916                                         break;
917                                 case '\n':
918                                 case 0x04:
919                                         eol = 1;
920                                 default:
921                                         kbd.line[kbd.x++] = ch;
922                                         break;
923                                 }
924                                 if(kbd.x == sizeof(kbd.line) || eol) {
925                                         if(ch == 0x04)
926                                                 kbd.x--;
927                                         qwrite(lineq, kbd.line, kbd.x);
928                                         kbd.x = 0;
929                                 }
930                         }
931                         n = qread(lineq, buf, n);
932                 }
933                 qunlock(&(&kbd)->qlock);
934                 poperror();
935                 return n;
936
937         case Qscancode:
938                 if(offset == 0)
939                         return readstr(0, buf, n, kscanid);
940                 else
941                         return qread(kscanq, buf, n);
942
943         case Qtime:
944                 snprintf(tmp, sizeof(tmp), "%.lld", (int64_t)mseconds()*1000);
945                 return readstr(offset, buf, n, tmp);
946
947         case Qhostowner:
948                 return readstr(offset, buf, n, eve);
949
950         case Quser:
951                 return readstr(offset, buf, n, o->user);
952
953         case Qjit:
954                 snprintf(tmp, sizeof(tmp), "%d", cflag);
955                 return readstr(offset, buf, n, tmp);
956 #endif
957         case Qnull:
958                 return 0;
959 #if 0
960         case Qmsec:
961                 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
962 #endif
963         case Qsysname:
964                 if(sysname == NULL)
965                         return 0;
966                 return readstr(offset, buf, n, "Windows 95");
967
968 /* not in akaros, inferno was a special case. 
969         case Qnotquiterandom:
970                 genrandom(buf, n);
971                 return n;
972 */
973
974         case Qrandom:
975                 return randomread(buf, n);
976 #if 0
977         case Qmemory:
978                 return poolread(buf, n, offset);
979 #endif
980         case Qdrivers:
981                 p = kzmalloc(READSTR, 0);
982                 if(p == NULL)
983                         error(Enomem);
984                 l = 0;
985                 for(i = 0; devtab[i] != NULL; i++)
986                         l += snprintf(p+l, READSTR-l, "#%c %s\n", devtab[i]->dc,  devtab[i]->name);
987                 if(waserror()){
988                         kfree(p);
989                         nexterror();
990                 }
991                 n = readstr(offset, buf, n, p);
992                 kfree(p);
993                 poperror();
994                 return n;
995         case Qklog:
996                 //return qread(klogq, buf, n);  
997                 /* the queue gives us some elasticity for log reading. */
998                 if (! logqueue)
999                         logqueue = qopen(1<<20, 0, 0, 0);
1000                 if (logqueue){
1001                         int ret;
1002                         /* atomic sets/gets are not that important in this case. */
1003                         reading_kmesg = 1;
1004                         qwrite(logqueue, logbuffer, index);
1005                         index = 0;
1006                         ret = qread(logqueue, buf, n);
1007                         reading_kmesg = 0;
1008                         return ret;
1009                 }
1010                 break;
1011 #if 0
1012         case Qkprint:
1013                 rlock(&(&kprintq)->rwlock);
1014                 if(waserror()){
1015                         runlock(&(&kprintq)->rwlock);
1016                         nexterror();
1017                 }
1018                 n = qread(kprintq.q, buf, n);
1019                 poperror();
1020                 runlock(&(&kprintq)->rwlock);
1021                 return n;
1022 #endif
1023         default:
1024                 printd("consread %llud\n", c->qid.path);
1025                 error(Egreg);
1026         }
1027         return -1;              /* never reached */
1028 }
1029
1030 static long
1031 conswrite(struct chan *c, void *va, long n, int64_t offset)
1032 {
1033         ERRSTACK(1);
1034         int64_t t;
1035         long l, bp;
1036         char *a = va;
1037         struct cmdbuf *cb;
1038         struct cmdtab *ct;
1039         char buf[256];
1040         int x;
1041
1042         switch((uint32_t)c->qid.path){
1043 #if 0
1044         case Qcons:
1045                 /*
1046                  * Can't page fault in putstrn, so copy the data locally.
1047                  */
1048                 l = n;
1049                 while(l > 0){
1050                         bp = l;
1051                         if(bp > sizeof buf)
1052                                 bp = sizeof buf;
1053                         memmove(buf, a, bp);
1054                         putstrn0(a, bp, 1);
1055                         a += bp;
1056                         l -= bp;
1057                 }
1058                 break;
1059
1060         case Qconsctl:
1061                 if(n >= sizeof(buf))
1062                         n = sizeof(buf)-1;
1063                 strncpy(buf, a, n);
1064                 buf[n] = 0;
1065                 for(a = buf; a;){
1066                         if(strncmp(a, "rawon", 5) == 0){
1067                                 qlock(&(&kbd)->qlock);
1068                                 flushkbdline(kbdq);
1069                                 kbd.raw = 1;
1070                                 qunlock(&(&kbd)->qlock);
1071                         } else if(strncmp(a, "rawoff", 6) == 0){
1072                                 qlock(&(&kbd)->qlock);
1073                                 kbd.raw = 0;
1074                                 kbd.x = 0;
1075                                 qunlock(&(&kbd)->qlock);
1076                         }
1077                         if(a = strchr(a, ' '))
1078                                 a++;
1079                 }
1080                 break;
1081
1082         case Qkeyboard:
1083                 for(x=0; x<n; ) {
1084                         Rune r;
1085                         x += chartorune(&r, &a[x]);
1086                         kbdputc(kbdq, r);
1087                 }
1088                 break;
1089         
1090         case Qtime:
1091                 if(n >= sizeof(buf))
1092                         n = sizeof(buf)-1;
1093                 strncpy(buf, a, n);
1094                 buf[n] = 0;
1095                 t = strtoll(buf, 0, 0)/1000000;
1096                 boottime = t - TK2SEC(MACHP(0)->ticks);
1097                 break;
1098
1099         case Qhostowner:
1100                 if(!iseve())
1101                         error(Eperm);
1102                 if(offset != 0 || n >= sizeof(buf))
1103                         error(Ebadarg);
1104                 memmove(buf, a, n);
1105                 buf[n] = '\0';
1106                 if(n > 0 && buf[n-1] == '\n')
1107                         buf[--n] = 0;
1108                 if(n <= 0)
1109                         error(Ebadarg);
1110                 renameuser(eve, buf);
1111                 renameproguser(eve, buf);
1112                 kstrdup(&eve, buf);
1113                 kstrdup(&up->env->user, buf);
1114                 break;
1115
1116         case Quser:
1117                 if(!iseve())
1118                         error(Eperm);
1119                 if(offset != 0)
1120                         error(Ebadarg);
1121                 if(n <= 0 || n >= sizeof(buf))
1122                         error(Ebadarg);
1123                 strncpy(buf, a, n);
1124                 buf[n] = 0;
1125                 if(buf[n-1] == '\n')
1126                         buf[n-1] = 0;
1127                 kstrdup(&up->env->user, buf);
1128                 break;
1129
1130         case Qjit:
1131                 if(n >= sizeof(buf))
1132                         n = sizeof(buf)-1;
1133                 strncpy(buf, va, n);
1134                 buf[n] = '\0';
1135                 x = atoi(buf);
1136                 if(x < 0 || x > 9)
1137                         error(Ebadarg);
1138                 cflag = x;
1139                 return n;
1140
1141         case Qnull:
1142                 break;
1143
1144         case Qsysname:
1145                 if(offset != 0)
1146                         error(Ebadarg);
1147                 if(n <= 0 || n >= sizeof(buf))
1148                         error(Ebadarg);
1149                 strncpy(buf, a, n);
1150                 buf[n] = 0;
1151                 if(buf[n-1] == '\n')
1152                         buf[n-1] = 0;
1153                 kstrdup(&sysname, buf);
1154                 break;
1155
1156         case Qsysctl:
1157                 if(!iseve())
1158                         error(Eperm);
1159                 cb = parsecmd(a, n);
1160                 if(waserror()){
1161                         kfree(cb);
1162                         nexterror();
1163                 }
1164                 ct = lookupcmd(cb, sysctlcmd, ARRAY_SIZE(sysctlcmd));
1165                 switch(ct->index){
1166                 case CMreboot:
1167                         reboot();
1168                         break;
1169                 case CMhalt:
1170                         halt();
1171                         break;
1172                 case CMpanic:
1173                         panic("sysctl");
1174                 case CMconsole:
1175                         consoleprint = strcmp(cb->f[1], "off") != 0;
1176                         break;
1177                 case CMbroken:
1178                         keepbroken = 1;
1179                         break;
1180                 case CMnobroken:
1181                         keepbroken = 0;
1182                         break;
1183                 }
1184                 poperror();
1185                 kfree(cb);
1186                 break;
1187 #endif
1188         default:
1189                 printd("conswrite: %llud\n", c->qid.path);
1190                 error(Egreg);
1191         }
1192         return n;
1193 }
1194
1195 struct dev consdevtab = {
1196         'c',
1197         "cons",
1198
1199         devreset,
1200         consinit,
1201         devshutdown,
1202         consattach,
1203         conswalk,
1204         consstat,
1205         consopen,
1206         devcreate,
1207         consclose,
1208         consread,
1209         devbread,
1210         conswrite,
1211         devbwrite,
1212         devremove,
1213         devwstat,
1214 };
1215
1216 static  uint32_t        randn;
1217
1218 static void
1219 seedrand(void)
1220 {
1221         randomread((void*)&randn, sizeof(randn));
1222 }
1223
1224 int
1225 nrand(int n)
1226 {
1227         if(randn == 0)
1228                 seedrand();
1229         randn = randn*1103515245 + 12345 + read_tsc();
1230         return (randn>>16) % n;
1231 }
1232
1233 int
1234 rand(void)
1235 {
1236         nrand(1);
1237         return randn;
1238 }
1239
1240 uint32_t
1241 truerand(void)
1242 {
1243         uint32_t x;
1244
1245         randomread(&x, sizeof(x));
1246         return x;
1247 }
1248
1249 /* TODO: qlock_init this, if you ever use this */
1250 qlock_t grandomlk;
1251
1252 void
1253 _genrandomqlock(void)
1254 {
1255         qlock(&grandomlk);
1256 }
1257
1258
1259 void
1260 _genrandomqunlock(void)
1261 {
1262         qunlock(&grandomlk);
1263 }