Removes extra print funcs from devcons
[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 /*
200  * mainly for libmp
201  */
202 void
203 sysfatal(char *fmt, ...)
204 {
205         va_list arg;
206         char buf[64];
207
208         va_start(arg, fmt);
209         vsnprintf(buf, sizeof(buf), fmt, arg);
210         va_end(arg);
211         error(buf);
212 }
213
214 int
215 pprint(char *fmt, ...)
216 {
217         ERRSTACK(1);
218         int n;
219         struct chan *c;
220         Osenv *o;
221         va_list arg;
222         char buf[2*PRINTSIZE];
223
224         n = sprint(buf, "%s %ld: ", up->text, up->pid);
225         va_start(arg, fmt);
226         n = vseprintf(buf+n, buf+sizeof(buf), fmt, arg) - buf;
227         va_end(arg);
228
229         o = up->env;
230         if(o->fgrp == 0) {
231                 printd("%s", buf);
232                 return 0;
233         }
234         /* TODO: this is probably wrong (VFS hack) */
235         c = o->fgrp->fd[2];
236         if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) {
237                 printd("%s", buf);
238                 return 0;
239         }
240
241         if(waserror()) {
242                 printd("%s", buf);
243                 poperror();
244                 return 0;
245         }
246         devtab[c->type].write(c, buf, n, c->offset);
247         poperror();
248
249         spin_lock(&c->lock);
250         c->offset += n;
251         spin_unlock(&c->lock);
252
253         return n;
254 }
255
256 void
257 echo(Rune r, char *buf, int n)
258 {
259         if(kbd.raw)
260                 return;
261
262         if(r == '\n'){
263                 if(printq)
264                         qiwrite(printq, "\r", 1);
265         } else if(r == 0x15){
266                 buf = "^U\n";
267                 n = 3;
268         }
269         if(consoleprint && screenputs != NULL)
270                 screenputs(buf, n);
271         if(printq)
272                 qiwrite(printq, buf, n);
273 }
274 #endif
275 #if 0
276 /*
277  *      Debug key support.  Allows other parts of the kernel to register debug
278  *      key handlers, instead of devcons.c having to know whatever's out there.
279  *      A kproc is used to invoke most handlers, rather than tying up the CPU at
280  *      splhi, which can choke some device drivers (eg softmodem).
281  */
282 typedef struct {
283         Rune    r;
284         char    *m;
285         void    (*f)(Rune);
286         int     i;      /* function called at interrupt time */
287 } Dbgkey;
288
289 static struct {
290         Rendez;
291         Dbgkey  *work;
292         Dbgkey  keys[50];
293         int     nkeys;
294         int     on;
295 } dbg;
296
297 static Dbgkey *
298 finddbgkey(Rune r)
299 {
300         int i;
301         Dbgkey *dp;
302
303         for(dp = dbg.keys, i = 0; i < dbg.nkeys; i++, dp++)
304                 if(dp->r == r)
305                         return dp;
306         return NULL;
307 }
308
309 static int
310 dbgwork(void *)
311 {
312         return dbg.work != 0;
313 }
314
315 static void
316 dbgproc(void *)
317 {
318         Dbgkey *dp;
319
320         setpri(PriRealtime);
321         for(;;) {
322                 do {
323                         rendez_sleep(&dbg, dbgwork, 0);
324                         dp = dbg.work;
325                 } while(dp == NULL);
326                 dp->f(dp->r);
327                 dbg.work = NULL;
328         }
329 }
330
331 void
332 debugkey(Rune r, char *msg, void (*fcn)(), int iflag)
333 {
334         Dbgkey *dp;
335
336         if(dbg.nkeys >= ARRAY_SIZE(dbg.keys))
337                 return;
338         if(finddbgkey(r) != NULL)
339                 return;
340         for(dp = &dbg.keys[dbg.nkeys++] - 1; dp >= dbg.keys; dp--) {
341                 if(strcmp(dp->m, msg) < 0)
342                         break;
343                 dp[1] = dp[0];
344         }
345         dp++;
346         dp->r = r;
347         dp->m = msg;
348         dp->f = fcn;
349         dp->i = iflag;
350 }
351
352 static int
353 isdbgkey(Rune r)
354 {
355         static int ctrlt;
356         Dbgkey *dp;
357         int echoctrlt = ctrlt;
358
359         /*
360          * ^t hack BUG
361          */
362         if(dbg.on || (ctrlt >= 2)) {
363                 if(r == 0x14 || r == 0x05) {
364                         ctrlt++;
365                         return 0;
366                 }
367                 if(dp = finddbgkey(r)) {
368                         if(dp->i || ctrlt > 2)
369                                 dp->f(r);
370                         else {
371                                 dbg.work = dp;
372                                 rendez_wakeup(&dbg);
373                         }
374                         ctrlt = 0;
375                         return 1;
376                 }
377                 ctrlt = 0;
378         }
379         else if(r == 0x14){
380                 ctrlt++;
381                 return 1;
382         }
383         else
384                 ctrlt = 0;
385         if(echoctrlt){
386                 char buf[3];
387
388                 buf[0] = 0x14;
389                 while(--echoctrlt >= 0){
390                         echo(buf[0], buf, 1);
391                         qproduce(kbdq, buf, 1);
392                 }
393         }
394         return 0;
395 }
396
397 static void
398 dbgtoggle(Rune)
399 {
400         dbg.on = !dbg.on;
401         printd("Debug keys %s\n", dbg.on ? "HOT" : "COLD");
402 }
403
404 static void
405 dbghelp(void)
406 {
407         int i;
408         Dbgkey *dp;
409         Dbgkey *dp2;
410         static char fmt[] = "%c: %-22s";
411
412         dp = dbg.keys;
413         dp2 = dp + (dbg.nkeys + 1)/2;
414         for(i = dbg.nkeys; i > 1; i -= 2, dp++, dp2++) {
415                 printd(fmt, dp->r, dp->m);
416                 printd(fmt, dp2->r, dp2->m);
417                 printd("\n");
418         }
419         if(i)
420                 printd(fmt, dp->r, dp->m);
421         printd("\n");
422 }
423
424 static void
425 debuginit(void)
426 {
427         ktask("consdbg", dbgproc, NULL);
428         debugkey('|', "HOT|COLD keys", dbgtoggle, 0);
429         debugkey('?', "help", dbghelp, 0);
430 }
431 #endif
432 #if 0
433 /*
434  *  Called by a uart interrupt for console input.
435  *
436  *  turn '\r' into '\n' before putting it into the queue.
437  */
438 int
439 kbdcr2nl(struct queue *q, int ch)
440 {
441         if(ch == '\r')
442                 ch = '\n';
443         return kbdputc(q, ch);
444 }
445
446 /*
447  *  Put character, possibly a rune, into read queue at interrupt time.
448  *  Performs translation for compose sequences
449  *  Called at interrupt time to process a character.
450  */
451 int
452 kbdputc(struct queue *q, int ch)
453 {
454         int n;
455         char buf[3];
456         Rune r;
457         static Rune kc[15];
458         static int nk, collecting = 0;
459
460         r = ch;
461         if(r == Latin) {
462                 collecting = 1;
463                 nk = 0;
464                 return 0;
465         }
466         if(collecting) {
467                 int c;
468                 nk += runetochar(( char *unused_char_p_t)&kc[nk], &r);
469                 c = latin1(kc, nk);
470                 if(c < -1)      /* need more keystrokes */
471                         return 0;
472                 collecting = 0;
473                 if(c == -1) {   /* invalid sequence */
474                         echo(kc[0], ( char *unused_char_p_t)kc, nk);
475                         qproduce(q, kc, nk);
476                         return 0;
477                 }
478                 r = (Rune)c;
479         }
480         kbd.c = r;
481         n = runetochar(buf, &r);
482         if(n == 0)
483                 return 0;
484         if(!isdbgkey(r)) {
485                 echo(r, buf, n);
486                 qproduce(q, buf, n);
487         }
488         return 0;
489 }
490
491 void
492 kbdrepeat(int rep)
493 {
494         kbd.repeat = rep;
495         kbd.count = 0;
496 }
497
498 void
499 kbdclock(void)
500 {
501         if(kbd.repeat == 0)
502                 return;
503         if(kbd.repeat==1 && ++kbd.count>HZ){
504                 kbd.repeat = 2;
505                 kbd.count = 0;
506                 return;
507         }
508         if(++kbd.count&1)
509                 kbdputc(kbdq, kbd.c);
510 }
511 #endif
512
513 enum{
514         Qdir,
515         Qcons,
516         Qsysctl,
517         Qconsctl,
518         Qdrivers,
519         Qhostowner,
520         Qkeyboard,
521         Qklog,
522         Qkprint,
523         Qscancode,
524         Qmemory,
525         Qmsec,
526         Qnull,
527         Qrandom,
528         Qnotquiterandom,
529         Qsysname,
530         Qtime,
531         Quser,
532         Qjit,
533 };
534
535 static struct dirtab consdir[]=
536 {
537         {".",   {Qdir, 0, QTDIR},       0,              DMDIR|0555},
538         {"cons",                {Qcons},        0,              0660},
539         {"consctl",     {Qconsctl},     0,              0220},
540         {"sysctl",      {Qsysctl},      0,              0644},
541         {"drivers",     {Qdrivers},     0,              0444},
542         {"hostowner",   {Qhostowner},   0,      0644},
543         {"keyboard",    {Qkeyboard},    0,              0666},
544         {"klog",                {Qklog},        0,              0444},
545         {"kprint",              {Qkprint},      0,              0444},
546         {"scancode",    {Qscancode},    0,              0444},
547         {"memory",      {Qmemory},      0,              0444},
548         {"msec",                {Qmsec},        NUMSIZE,        0444},
549         {"null",                {Qnull},        0,              0666},
550         {"random",      {Qrandom},      0,              0444},
551         {"notquiterandom", {Qnotquiterandom}, 0,        0444},
552         {"sysname",     {Qsysname},     0,              0664},
553         {"time",                {Qtime},        0,              0664},
554         {"user",                {Quser},        0,      0644},
555         {"jit",         {Qjit}, 0,      0666},
556 };
557
558 uint32_t        boottime;               /* seconds since epoch at boot */
559
560 #if 0
561 void
562 fddump()
563 {
564         struct proc *p;
565         Osenv *o;
566         int i;
567         struct chan *c;
568
569         p = proctab(6);
570         o = p->env;
571         for(i = 0; i <= o->fgrp->maxfd; i++) {
572                 if((c = o->fgrp->fd[i]) == NULL)
573                         continue;
574                 printd("%d: %s\n", i, c->name == NULL? "???": c->name->s);
575         }
576 }
577 #endif
578
579 static void
580 consinit(void)
581 {
582         randominit();
583 #if 0
584         debuginit();
585         debugkey('f', "files/6", fddump, 0);
586         debugkey('q', "panic", qpanic, 1);
587         debugkey('r', "exit", rexit, 1);
588         klogq = qopen(128*1024, 0, 0, 0);
589 #endif
590 }
591
592 static struct chan*
593 consattach(char *spec)
594 {
595         return devattach('c', spec);
596 }
597
598 static struct walkqid*
599 conswalk(struct chan *c, struct chan *nc, char **name, int nname)
600 {
601         return devwalk(c, nc, name, nname, consdir, ARRAY_SIZE(consdir), devgen);
602 }
603
604 static int
605 consstat(struct chan *c, uint8_t *dp, int n)
606 {
607         return devstat(c, dp, n, consdir, ARRAY_SIZE(consdir), devgen);
608 }
609
610 #if 0
611 static void
612 flushkbdline(struct queue *q)
613 {
614         if(kbd.x){
615                 qwrite(q, kbd.line, kbd.x);
616                 kbd.x = 0;
617         }
618 }
619 #endif
620
621 static struct chan*
622 consopen(struct chan *c, int omode)
623 {
624         c->aux = 0;
625 #if 0
626         switch((uint32_t)c->qid.path){
627         case Qconsctl:
628                 if(!iseve())
629                         error(Eperm);
630                 qlock(&(&kbd)->qlock);
631                 kbd.ctl++;
632                 qunlock(&(&kbd)->qlock);
633                 break;
634
635         case Qkeyboard:
636                 if((omode & 3) != OWRITE) {
637                         qlock(&(&kbd)->qlock);
638                         kbd.kbdr++;
639                         flushkbdline(kbdq);
640                         kbd.raw = 1;
641                         qunlock(&(&kbd)->qlock);
642                 }
643                 break;
644
645         case Qscancode:
646                 qlock(&(&kbd)->qlock);
647                 if(kscanq || !kscanid) {
648                         qunlock(&(&kbd)->qlock);
649                         c->flag &= ~COPEN;
650                         if(kscanq)
651                                 error(Einuse);
652                         else
653                                 error(Ebadarg);
654                 }
655                 kscanq = qopen(256, 0, NULL, NULL);
656                 qunlock(&(&kbd)->qlock);
657                 break;
658
659         case Qkprint:
660                 if((omode & 3) != OWRITE) {
661                         wlock(&(&kprintq)->rwlock);
662                         if(kprintq.q != NULL){
663                                 wunlock(&(&kprintq)->rwlock);
664                                 error(Einuse);
665                         }
666                         kprintq.q = qopen(32*1024, Qcoalesce, NULL, NULL);
667                         if(kprintq.q == NULL){
668                                 wunlock(&(&kprintq)->rwlock);
669                                 error(Enomem);
670                         }
671                         qnoblock(kprintq.q, 1);
672                         wunlock(&(&kprintq)->rwlock);
673                         c->iounit = qiomaxatomic;
674                 }
675                 break;
676         }
677 #endif
678         return devopen(c, omode, consdir, ARRAY_SIZE(consdir), devgen);
679 }
680
681 static void
682 consclose(struct chan *c)
683 {
684         if((c->flag&COPEN) == 0)
685                 return;
686
687         switch((uint32_t)c->qid.path){
688 #if 0
689         case Qconsctl:
690                 /* last close of control file turns off raw */
691                 qlock(&(&kbd)->qlock);
692                 if(--kbd.ctl == 0)
693                         kbd.raw = 0;
694                 qunlock(&(&kbd)->qlock);
695                 break;
696
697         case Qkeyboard:
698                 if(c->mode != OWRITE) {
699                         qlock(&(&kbd)->qlock);
700                         --kbd.kbdr;
701                         qunlock(&(&kbd)->qlock);
702                 }
703                 break;
704
705         case Qscancode:
706                 qlock(&(&kbd)->qlock);
707                 if(kscanq) {
708                         qfree(kscanq);
709                         kscanq = 0;
710                 }
711                 qunlock(&(&kbd)->qlock);
712                 break;
713
714         case Qkprint:
715                 wlock(&(&kprintq)->rwlock);
716                 qfree(kprintq.q);
717                 kprintq.q = NULL;
718                 wunlock(&(&kprintq)->rwlock);
719                 break;
720 #endif
721         default: 
722                 break;
723         }
724 }
725
726 /* we do it this way to avoid the many fun deadlock opportunities
727  * we keep hitting. And, if you don't suck it
728  * out soon enough, you lost it. No real effort to ensure goodness
729  * here as it can get called anywhere. Barret will fix it.
730  */
731 static uint8_t logbuffer[1<<20];
732 static int index = 0;
733 static struct queue *logqueue = NULL;
734 static int reading_kmesg = 0;
735 void logbuf(int c)
736 {
737         if (reading_kmesg)
738                 return;
739         if (index > 1<<20)
740                 return;
741         logbuffer[index++] = c;
742 }
743
744 static long
745 consread(struct chan *c, void *buf, long n, int64_t offset)
746 {
747         ERRSTACK(1);
748         int l;
749
750         int ch, eol, i;
751         char *p, tmp[128];
752         char *cbuf = buf;
753
754         if(n <= 0)
755                 return n;
756
757         switch((uint32_t)c->qid.path){
758         case Qdir:
759                 return devdirread(c, buf, n, consdir, ARRAY_SIZE(consdir), devgen);
760         case Qsysctl:
761                 return readstr(offset, buf, n, "akaros");
762 #if 0
763         case Qcons:
764         case Qkeyboard:
765                 qlock(&(&kbd)->qlock);
766                 if(waserror()) {
767                         qunlock(&(&kbd)->qlock);
768                         nexterror();
769                 }
770                 if(kbd.raw || kbd.kbdr) {
771                         if(qcanread(lineq))
772                                 n = qread(lineq, buf, n);
773                         else {
774                                 /* read as much as possible */
775                                 do {
776                                         i = qread(kbdq, cbuf, n);
777                                         cbuf += i;
778                                         n -= i;
779                                 } while(n>0 && qcanread(kbdq));
780                                 n = cbuf - ( char *unused_char_p_t)buf;
781                         }
782                 } else {
783                         while(!qcanread(lineq)) {
784                                 qread(kbdq, &kbd.line[kbd.x], 1);
785                                 ch = kbd.line[kbd.x];
786                                 eol = 0;
787                                 switch(ch){
788                                 case '\b':
789                                         if(kbd.x)
790                                                 kbd.x--;
791                                         break;
792                                 case 0x15:
793                                         kbd.x = 0;
794                                         break;
795                                 case '\n':
796                                 case 0x04:
797                                         eol = 1;
798                                 default:
799                                         kbd.line[kbd.x++] = ch;
800                                         break;
801                                 }
802                                 if(kbd.x == sizeof(kbd.line) || eol) {
803                                         if(ch == 0x04)
804                                                 kbd.x--;
805                                         qwrite(lineq, kbd.line, kbd.x);
806                                         kbd.x = 0;
807                                 }
808                         }
809                         n = qread(lineq, buf, n);
810                 }
811                 qunlock(&(&kbd)->qlock);
812                 poperror();
813                 return n;
814
815         case Qscancode:
816                 if(offset == 0)
817                         return readstr(0, buf, n, kscanid);
818                 else
819                         return qread(kscanq, buf, n);
820
821         case Qtime:
822                 snprintf(tmp, sizeof(tmp), "%.lld", (int64_t)mseconds()*1000);
823                 return readstr(offset, buf, n, tmp);
824
825         case Qhostowner:
826                 return readstr(offset, buf, n, eve);
827
828         case Quser:
829                 return readstr(offset, buf, n, o->user);
830
831         case Qjit:
832                 snprintf(tmp, sizeof(tmp), "%d", cflag);
833                 return readstr(offset, buf, n, tmp);
834 #endif
835         case Qnull:
836                 return 0;
837 #if 0
838         case Qmsec:
839                 return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
840 #endif
841         case Qsysname:
842                 if(sysname == NULL)
843                         return 0;
844                 return readstr(offset, buf, n, "Windows 95");
845
846 /* not in akaros, inferno was a special case. 
847         case Qnotquiterandom:
848                 genrandom(buf, n);
849                 return n;
850 */
851
852         case Qrandom:
853                 return randomread(buf, n);
854 #if 0
855         case Qmemory:
856                 return poolread(buf, n, offset);
857 #endif
858         case Qdrivers:
859                 p = kzmalloc(READSTR, 0);
860                 if(p == NULL)
861                         error(Enomem);
862                 l = 0;
863                 for(i = 0; &devtab[i] < __devtabend; i++)
864                         l += snprintf(p+l, READSTR-l, "#%c %s\n", devtab[i].dc,  devtab[i].name);
865                 if(waserror()){
866                         kfree(p);
867                         nexterror();
868                 }
869                 n = readstr(offset, buf, n, p);
870                 kfree(p);
871                 poperror();
872                 return n;
873         case Qklog:
874                 //return qread(klogq, buf, n);  
875                 /* the queue gives us some elasticity for log reading. */
876                 if (! logqueue)
877                         logqueue = qopen(1<<20, 0, 0, 0);
878                 if (logqueue){
879                         int ret;
880                         /* atomic sets/gets are not that important in this case. */
881                         reading_kmesg = 1;
882                         qwrite(logqueue, logbuffer, index);
883                         index = 0;
884                         ret = qread(logqueue, buf, n);
885                         reading_kmesg = 0;
886                         return ret;
887                 }
888                 break;
889 #if 0
890         case Qkprint:
891                 rlock(&(&kprintq)->rwlock);
892                 if(waserror()){
893                         runlock(&(&kprintq)->rwlock);
894                         nexterror();
895                 }
896                 n = qread(kprintq.q, buf, n);
897                 poperror();
898                 runlock(&(&kprintq)->rwlock);
899                 return n;
900 #endif
901         default:
902                 printd("consread %llu\n", c->qid.path);
903                 error(Egreg);
904         }
905         return -1;              /* never reached */
906 }
907
908 static long
909 conswrite(struct chan *c, void *va, long n, int64_t offset)
910 {
911         ERRSTACK(1);
912         int64_t t;
913         long l, bp;
914         char *a = va;
915         struct cmdbuf *cb;
916         struct cmdtab *ct;
917         char buf[256];
918         int x;
919
920         switch((uint32_t)c->qid.path){
921 #if 0
922         case Qcons:
923                 /*
924                  * Can't page fault in putstrn, so copy the data locally.
925                  */
926                 l = n;
927                 while(l > 0){
928                         bp = l;
929                         if(bp > sizeof buf)
930                                 bp = sizeof buf;
931                         memmove(buf, a, bp);
932                         putstrn0(a, bp, 1);
933                         a += bp;
934                         l -= bp;
935                 }
936                 break;
937
938         case Qconsctl:
939                 if(n >= sizeof(buf))
940                         n = sizeof(buf)-1;
941                 strncpy(buf, a, n);
942                 buf[n] = 0;
943                 for(a = buf; a;){
944                         if(strncmp(a, "rawon", 5) == 0){
945                                 qlock(&(&kbd)->qlock);
946                                 flushkbdline(kbdq);
947                                 kbd.raw = 1;
948                                 qunlock(&(&kbd)->qlock);
949                         } else if(strncmp(a, "rawoff", 6) == 0){
950                                 qlock(&(&kbd)->qlock);
951                                 kbd.raw = 0;
952                                 kbd.x = 0;
953                                 qunlock(&(&kbd)->qlock);
954                         }
955                         if(a = strchr(a, ' '))
956                                 a++;
957                 }
958                 break;
959
960         case Qkeyboard:
961                 for(x=0; x<n; ) {
962                         Rune r;
963                         x += chartorune(&r, &a[x]);
964                         kbdputc(kbdq, r);
965                 }
966                 break;
967         
968         case Qtime:
969                 if(n >= sizeof(buf))
970                         n = sizeof(buf)-1;
971                 strncpy(buf, a, n);
972                 buf[n] = 0;
973                 t = strtoll(buf, 0, 0)/1000000;
974                 boottime = t - TK2SEC(MACHP(0)->ticks);
975                 break;
976
977         case Qhostowner:
978                 if(!iseve())
979                         error(Eperm);
980                 if(offset != 0 || n >= sizeof(buf))
981                         error(Ebadarg);
982                 memmove(buf, a, n);
983                 buf[n] = '\0';
984                 if(n > 0 && buf[n-1] == '\n')
985                         buf[--n] = 0;
986                 if(n <= 0)
987                         error(Ebadarg);
988                 renameuser(eve, buf);
989                 renameproguser(eve, buf);
990                 kstrdup(&eve, buf);
991                 kstrdup(&up->env->user, buf);
992                 break;
993
994         case Quser:
995                 if(!iseve())
996                         error(Eperm);
997                 if(offset != 0)
998                         error(Ebadarg);
999                 if(n <= 0 || n >= sizeof(buf))
1000                         error(Ebadarg);
1001                 strncpy(buf, a, n);
1002                 buf[n] = 0;
1003                 if(buf[n-1] == '\n')
1004                         buf[n-1] = 0;
1005                 kstrdup(&up->env->user, buf);
1006                 break;
1007
1008         case Qjit:
1009                 if(n >= sizeof(buf))
1010                         n = sizeof(buf)-1;
1011                 strncpy(buf, va, n);
1012                 buf[n] = '\0';
1013                 x = atoi(buf);
1014                 if(x < 0 || x > 9)
1015                         error(Ebadarg);
1016                 cflag = x;
1017                 return n;
1018
1019         case Qnull:
1020                 break;
1021
1022         case Qsysname:
1023                 if(offset != 0)
1024                         error(Ebadarg);
1025                 if(n <= 0 || n >= sizeof(buf))
1026                         error(Ebadarg);
1027                 strncpy(buf, a, n);
1028                 buf[n] = 0;
1029                 if(buf[n-1] == '\n')
1030                         buf[n-1] = 0;
1031                 kstrdup(&sysname, buf);
1032                 break;
1033
1034         case Qsysctl:
1035                 if(!iseve())
1036                         error(Eperm);
1037                 cb = parsecmd(a, n);
1038                 if(waserror()){
1039                         kfree(cb);
1040                         nexterror();
1041                 }
1042                 ct = lookupcmd(cb, sysctlcmd, ARRAY_SIZE(sysctlcmd));
1043                 switch(ct->index){
1044                 case CMreboot:
1045                         reboot();
1046                         break;
1047                 case CMhalt:
1048                         halt();
1049                         break;
1050                 case CMpanic:
1051                         panic("sysctl");
1052                 case CMconsole:
1053                         consoleprint = strcmp(cb->f[1], "off") != 0;
1054                         break;
1055                 case CMbroken:
1056                         keepbroken = 1;
1057                         break;
1058                 case CMnobroken:
1059                         keepbroken = 0;
1060                         break;
1061                 }
1062                 poperror();
1063                 kfree(cb);
1064                 break;
1065 #endif
1066         default:
1067                 printd("conswrite: %llu\n", c->qid.path);
1068                 error(Egreg);
1069         }
1070         return n;
1071 }
1072
1073 struct dev consdevtab __devtab = {
1074         'c',
1075         "cons",
1076
1077         devreset,
1078         consinit,
1079         devshutdown,
1080         consattach,
1081         conswalk,
1082         consstat,
1083         consopen,
1084         devcreate,
1085         consclose,
1086         consread,
1087         devbread,
1088         conswrite,
1089         devbwrite,
1090         devremove,
1091         devwstat,
1092 };
1093
1094 static  uint32_t        randn;
1095
1096 static void
1097 seedrand(void)
1098 {
1099         randomread((void*)&randn, sizeof(randn));
1100 }
1101
1102 int
1103 nrand(int n)
1104 {
1105         if(randn == 0)
1106                 seedrand();
1107         randn = randn*1103515245 + 12345 + read_tsc();
1108         return (randn>>16) % n;
1109 }
1110
1111 int
1112 rand(void)
1113 {
1114         nrand(1);
1115         return randn;
1116 }
1117
1118 uint32_t
1119 truerand(void)
1120 {
1121         uint32_t x;
1122
1123         randomread(&x, sizeof(x));
1124         return x;
1125 }
1126
1127 /* TODO: qlock_init this, if you ever use this */
1128 qlock_t grandomlk;
1129
1130 void
1131 _genrandomqlock(void)
1132 {
1133         qlock(&grandomlk);
1134 }
1135
1136
1137 void
1138 _genrandomqunlock(void)
1139 {
1140         qunlock(&grandomlk);
1141 }