]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/kbdfs/kbdfs.c
merge
[plan9front.git] / sys / src / cmd / aux / kbdfs / kbdfs.c
1 #include <u.h>
2 #include <libc.h>
3 #include <auth.h>
4 #include <fcall.h>
5 #include <thread.h>
6 #include <keyboard.h>
7 #include <9p.h>
8
9 enum {
10         Nscan=  128,
11
12         Qroot=  0,
13         Qkbd,
14         Qkbin,
15         Qkbmap,
16         Qcons,
17         Qconsctl,
18         Nqid,
19
20         Rawon=  0,
21         Rawoff,
22         Kbdflush,
23
24         STACK = 8*1024,
25 };
26
27 typedef struct Key Key;
28 typedef struct Scan Scan;
29
30 struct Key {
31         int     down;
32         int     c;
33         Rune    r;
34         Rune    b;
35 };
36
37 struct Scan {
38         int     esc1;
39         int     esc2;
40         int     caps;
41         int     num;
42         int     shift;
43         int     ctl;
44         int     alt;
45         int     altgr;
46         int     leds;
47 };
48
49 struct Qtab {
50         char *name;
51         int mode;
52         int type;
53 } qtab[Nqid] = {
54         "/",
55                 DMDIR|0500,
56                 QTDIR,
57
58         "kbd",
59                 0600,
60                 0,
61
62         "kbin",
63                 0200,   
64                 0,
65
66         "kbmap",
67                 0600,   
68                 0,
69
70         "cons",
71                 0600,   
72                 0,
73
74         "consctl",
75                 0600,
76                 0,
77 };
78
79 char Eshort[] = "read count too small";
80 char Ebadarg[] = "invalid argument";
81 char Eperm[] = "permission denied";
82 char Einuse[] = "file in use";
83 char Enonexist[] = "file does not exist";
84 char Ebadspec[] = "bad attach specifier";
85 char Ewalk[] = "walk in non directory";
86 char Efront[] = "the front fell off";
87
88 int scanfd;
89 int ledsfd;
90 int consfd;
91
92 int kbdopen;
93 int consopen;
94 int consctlopen;
95
96 int debug;
97
98 Channel *keychan;       /* Key */
99
100 Channel *reqchan;       /* Req* */
101 Channel *ctlchan;       /* int */
102
103 Channel *rawchan;       /* Rune */
104 Channel *runechan;      /* Rune */
105 Channel *linechan;      /* char * */
106 Channel *kbdchan;       /* char* */
107
108 /*
109  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
110  * A 'standard' keyboard doesn't produce anything above 0x58.
111  */
112 Rune kbtab[Nscan] = 
113 {
114 [0x00]  0,      0x1b,   '1',    '2',    '3',    '4',    '5',    '6',
115 [0x08]  '7',    '8',    '9',    '0',    '-',    '=',    '\b',   '\t',
116 [0x10]  'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
117 [0x18]  'o',    'p',    '[',    ']',    '\n',   Kctl,   'a',    's',
118 [0x20]  'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
119 [0x28]  '\'',   '`',    Kshift, '\\',   'z',    'x',    'c',    'v',
120 [0x30]  'b',    'n',    'm',    ',',    '.',    '/',    Kshift, '*',
121 [0x38]  Kalt,   ' ',    Kctl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
122 [0x40]  KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,        '7',
123 [0x48]  '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
124 [0x50]  '2',    '3',    '0',    '.',    0,      0,      0,      KF|11,
125 [0x58]  KF|12,  0,      0,      0,      0,      0,      0,      0,
126 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
127 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
128 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
129 [0x78]  0,      Kdown,  0,      Kup,    0,      0,      0,      0,
130 };
131
132 Rune kbtabshift[Nscan] =
133 {
134 [0x00]  0,      0x1b,   '!',    '@',    '#',    '$',    '%',    '^',
135 [0x08]  '&',    '*',    '(',    ')',    '_',    '+',    '\b',   '\t',
136 [0x10]  'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
137 [0x18]  'O',    'P',    '{',    '}',    '\n',   Kctl,   'A',    'S',
138 [0x20]  'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
139 [0x28]  '"',    '~',    Kshift, '|',    'Z',    'X',    'C',    'V',
140 [0x30]  'B',    'N',    'M',    '<',    '>',    '?',    Kshift, '*',
141 [0x38]  Kalt,   ' ',    Kctl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
142 [0x40]  KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,        '7',
143 [0x48]  '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
144 [0x50]  '2',    '3',    '0',    '.',    0,      0,      0,      KF|11,
145 [0x58]  KF|12,  0,      0,      0,      0,      0,      0,      0,
146 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
147 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
148 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
149 [0x78]  0,      Kup,    0,      Kup,    0,      0,      0,      0,
150 };
151
152 Rune kbtabesc1[Nscan] =
153 {
154 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
155 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
156 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
157 [0x18]  0,      0,      0,      0,      '\n',   Kctl,   0,      0,
158 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
159 [0x28]  0,      0,      Kshift, 0,      0,      0,      0,      0,
160 [0x30]  0,      0,      0,      0,      0,      '/',    0,      Kprint,
161 [0x38]  Kaltgr, 0,      0,      0,      0,      0,      0,      0,
162 [0x40]  0,      0,      0,      0,      0,      0,      Kbreak, Khome,
163 [0x48]  Kup,    Kpgup,  0,      Kleft,  0,      Kright, 0,      Kend,
164 [0x50]  Kdown,  Kpgdown,        Kins,   Kdel,   0,      0,      0,      0,
165 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
166 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
167 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
168 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
169 [0x78]  0,      Kup,    0,      0,      0,      0,      0,      0,
170 };
171
172 Rune kbtabaltgr[Nscan] =
173 {
174 [0x00]  0,      0,      0,      0,      0,      0,      0,      0,
175 [0x08]  0,      0,      0,      0,      0,      0,      0,      0,
176 [0x10]  0,      0,      0,      0,      0,      0,      0,      0,
177 [0x18]  0,      0,      0,      0,      '\n',   Kctl,   0,      0,
178 [0x20]  0,      0,      0,      0,      0,      0,      0,      0,
179 [0x28]  0,      0,      Kshift, 0,      0,      0,      0,      0,
180 [0x30]  0,      0,      0,      0,      0,      '/',    0,      Kprint,
181 [0x38]  Kaltgr, 0,      0,      0,      0,      0,      0,      0,
182 [0x40]  0,      0,      0,      0,      0,      0,      Kbreak, Khome,
183 [0x48]  Kup,    Kpgup,  0,      Kleft,  0,      Kright, 0,      Kend,
184 [0x50]  Kdown,  Kpgdown,        Kins,   Kdel,   0,      0,      0,      0,
185 [0x58]  0,      0,      0,      0,      0,      0,      0,      0,
186 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
187 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
188 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
189 [0x78]  0,      Kup,    0,      0,      0,      0,      0,      0,
190 };
191
192 Rune kbtabctl[Nscan] =
193 {
194 [0x00]  0,      '\e',    '\11',    '\12',    '\13',    '\14',    '\15',    '\16', 
195 [0x08]  '\17',    '\18',    '\19',    '\10',    '\r',    '\1d',    '\b',   '\t',
196 [0x10]  '\11',    '\17',    '\ 5',    '\12',    '\14',    '\19',    '\15',    '\t',
197 [0x18]  '\ f',    '\10',    '\e',    '\1d',    '\n',   Kctl,   '\ 1',    '\13', 
198 [0x20]  '\ 4',    '\ 6',    '\a',    '\b',   '\n',   '\v',    '\f',    '\e', 
199 [0x28]  '\a',    0,      Kshift, '\1c',    '\1a',    '\18',    '\ 3',    '\16', 
200 [0x30]  '\ 2',    '\ e',    '\r',    '\f',    '\ e',    '\ f',    Kshift, '\n',
201 [0x38]  Kalt,   0,      Kctl,   '\ 5',    '\ 6',    '\a',    '\ 4',    '\ 5', 
202 [0x40]  '\ 6',    '\a',    '\f',    '\r',    '\ e',    '\ 5',    '\ 6',    '\17', 
203 [0x48]  '\18',    '\19',    '\r',    '\14',    '\15',    '\16',    '\v',    '\11', 
204 [0x50]  '\12',    '\13',    '\10',    '\ e',    0,      0,      0,      '\ f', 
205 [0x58]  '\f',    0,      0,      0,      0,      0,      0,      0,
206 [0x60]  0,      0,      0,      0,      0,      0,      0,      0,
207 [0x68]  0,      0,      0,      0,      0,      0,      0,      0,
208 [0x70]  0,      0,      0,      0,      0,      0,      0,      0,
209 [0x78]  0,      '\a',    0,      '\b',   0,      0,      0,      0,
210 };
211
212 void reboot(void);
213
214 /*
215  * Scan code processing
216  */
217 void
218 kbdputsc(Scan *scan, int c)
219 {
220         Key key;
221
222         /*
223          *  e0's is the first of a 2 character sequence, e1 the first
224          *  of a 3 character sequence (on the safari)
225          */
226         if(c == 0xe0){
227                 scan->esc1 = 1;
228                 return;
229         } else if(c == 0xe1){
230                 scan->esc2 = 2;
231                 return;
232         }
233
234         key.down = (c & 0x80) == 0;
235         key.c = c & 0x7f;
236
237         if(key.c >= Nscan)
238                 return;
239
240         if(scan->esc1)
241                 key.r = kbtabesc1[key.c];
242         else if(scan->shift)
243                 key.r = kbtabshift[key.c];
244         else if(scan->altgr)
245                 key.r = kbtabaltgr[key.c];
246         else if(scan->ctl)
247                 key.r = kbtabctl[key.c];
248         else
249                 key.r = kbtab[key.c];
250
251         switch(key.r){
252         case Spec|0x60:
253                 key.r = Kshift;
254                 break;
255         case Spec|0x62:
256                 key.r = Kctl;
257                 break;
258         case Spec|0x63:
259                 key.r = Kalt;
260                 break;
261         }
262
263         if(scan->esc1)
264                 key.b = key.r;
265         else
266                 key.b = kbtab[key.c];
267
268         if(scan->caps && key.r<='z' && key.r>='a')
269                 key.r += 'A' - 'a';
270
271         if(scan->ctl && scan->alt && key.r == Kdel)
272                 reboot();
273
274         send(keychan, &key);
275
276         if(scan->esc1)
277                 scan->esc1 = 0;
278         else if(scan->esc2)
279                 scan->esc2--;
280
281         switch(key.r){
282         case Kshift:
283                 scan->shift = key.down;
284                 break;
285         case Kctl:
286                 scan->ctl = key.down;
287                 break;
288         case Kaltgr:
289                 scan->altgr = key.down;
290                 break;
291         case Kalt:
292                 scan->alt = key.down;
293                 break;
294         case Knum:
295                 scan->num ^= key.down;
296                 break;
297         case Kcaps:
298                 scan->caps ^= key.down;
299                 break;
300         }
301 }
302
303 void
304 setleds(Scan *scan, int leds)
305 {
306         char buf[8];
307
308         if(ledsfd < 0 || scan->leds == leds)
309                 return;
310         leds &= 7;
311         snprint(buf, sizeof(buf), "%d", leds);
312         pwrite(ledsfd, buf, strlen(buf), 0);
313         scan->leds = leds;
314 }
315
316 /*
317  * Read scan codes from scanfd
318  */ 
319 void
320 scanproc(void *)
321 {
322         uchar buf[64];
323         Scan scan;
324         int i, n;
325
326         threadsetname("scanproc");
327
328         memset(&scan, 0, sizeof scan);
329         while((n = read(scanfd, buf, sizeof buf)) > 0){
330                 for(i=0; i<n; i++)
331                         kbdputsc(&scan, buf[i]);
332                 setleds(&scan, (scan.num<<1) | (scan.caps<<2));
333         }
334 }
335
336 char*
337 utfconv(Rune *r, int n)
338 {
339         char *s, *p;
340         int l;
341
342         l = runenlen(r, n) + 1;
343         s = emalloc9p(l);
344         for(p = s; n > 0; r++, n--)
345                 p += runetochar(p, r);
346         *p = 0;
347         return s;
348 }
349
350 /*
351  * Read key events from keychan and produce characters to
352  * rawchan and keystate in kbdchan. this way here is only
353  * one global keystate even if multiple keyboards are used.
354  */
355 void
356 keyproc(void *)
357 {
358         Rune rb[Nscan*2+1];
359         int cb[Nscan];
360         Key key;
361         int i, nb;
362         char *s;
363
364         threadsetname("keyproc");
365
366         nb = 0;
367         while(recv(keychan, &key) > 0){
368                 if(key.down && key.r)
369                         nbsend(rawchan, &key.r);
370
371                 rb[0] = 0;
372                 for(i=0; i<nb && cb[i] != key.c; i++)
373                         ;
374                 if(!key.down){
375                         while(i < nb && cb[i] == key.c){
376                                 memmove(cb+i, cb+i+1, (nb-i+1) * sizeof(cb[0]));
377                                 memmove(rb+i+1, rb+i+2, (nb-i+1) * sizeof(rb[0]));
378                                 nb--;
379                                 rb[0] = 'K';
380                         }
381                 } else if(i == nb && nb < nelem(cb) && key.b){
382                         cb[nb] = key.c;
383                         rb[nb+1] = key.b;
384                         nb++;
385                         if(nb < nelem(cb) && key.r && key.b != key.r){
386                                 cb[nb] = key.c;
387                                 rb[nb+1] = key.r;
388                                 nb++;
389                         }
390                         rb[0] = 'k';
391                 }
392                 if(rb[0]){
393                         s = utfconv(rb, nb+1);
394                         if(nbsendp(kbdchan, s) <= 0)
395                                 free(s);
396                 }
397         }
398 }
399
400 /*
401  * Read characters from consfd (serial console)
402  */ 
403 void
404 consproc(void *)
405 {
406         char *p, *e, *x, buf[64];
407         int n, cr;
408         Rune r;
409
410         threadsetname("consproc");
411
412         cr = 0;
413         p = buf;
414         e = buf + sizeof(buf);
415         while((n = read(consfd, p, e - p)) > 0){
416                 x = buf + n;
417                 while(p < x && fullrune(p, x - p)){
418                         p += chartorune(&r, p);
419                         if(r){
420                                 if(r == '\n' && cr){
421                                         cr = 0;
422                                         continue;
423                                 }
424                                 if(cr = (r == '\r'))
425                                         r = '\n';
426                                 send(runechan, &r);
427                         }
428                 }
429                 n = x - p;
430                 memmove(buf, p, n);
431                 p = buf + n;
432         }
433 }
434
435 static int
436 nextrune(Channel *ch, Rune *r)
437 {
438         while(recv(ch, r) > 0){
439                 switch(*r){
440                 case 0:
441                 case Kcaps:
442                 case Knum:
443                 case Kshift:
444                 case Kaltgr:
445                         /* ignore modifiers */
446                         continue;
447
448                 case Kctl:
449                 case Kalt:
450                         /* composing escapes */
451                         return 1;
452                 }
453                 return 0;
454         }
455         return -1;
456 }
457
458 /*
459  * Read runes from rawchan, possibly compose special characters
460  * and output the new runes to runechan
461  */
462 void
463 runeproc(void *)
464 {
465         static struct {
466                 char    *ld;    /* must be seen before using this conversion */
467                 char    *si;    /* options for last input characters */
468                 Rune    *so;    /* the corresponding Rune for each si entry */
469         } tab[] = {
470 #include "latin1.h"
471         };
472         Rune r, rr;
473         int i, j;
474         int ctl;
475
476         threadsetname("runeproc");
477
478         ctl = 0;
479         while((i = nextrune(rawchan, &r)) >= 0){
480                 if(i == 0){
481                         ctl = 0;
482 Forward:
483                         send(runechan, &r);
484                         continue;
485                 }
486
487                 if(r == Kctl){
488                         ctl = 1;
489                         continue;
490                 }
491
492                 /*
493                  * emulators like qemu and vmware use Ctrl+Alt to lock
494                  * keyboard input so dont confuse them for a compose
495                  * sequence.
496                  */
497                 if(r != Kalt || ctl)
498                         continue;
499
500                 if(nextrune(rawchan, &r))
501                         continue;
502
503                 if(r == 'X'){
504                         r = 0;
505                         for(i = 0; i<4; i++){
506                                 if(nextrune(rawchan, &rr))
507                                         break;
508                                 r <<= 4;
509                                 if(rr >= '0' && rr <= '9')
510                                         r |= (rr - '0');
511                                 else if(rr >= 'a' && rr <= 'f')
512                                         r |= 10 + (rr - 'a');
513                                 else if(rr >= 'A' && rr <= 'F')
514                                         r |= 10 + (rr - 'A');
515                                 else
516                                         break;
517                         }
518                         if(i == 4 && r)
519                                 goto Forward;
520                 } else {
521                         if(nextrune(rawchan, &rr))
522                                 continue;
523                         for(i = 0; i<nelem(tab); i++){
524                                 if(tab[i].ld[0] != r)
525                                         continue;
526                                 if(tab[i].ld[1] == 0)
527                                         break;  
528                                 if(tab[i].ld[1] == rr){
529                                         nextrune(rawchan, &rr);
530                                         break;
531                                 }
532                         }
533                         if(i == nelem(tab) || rr == 0)
534                                 continue;
535                         for(j = 0; tab[i].si[j]; j++){
536                                 if(tab[i].si[j] != rr)
537                                         continue;
538                                 r = tab[i].so[j];
539                                 goto Forward;
540                         }
541                 }
542         }
543 }
544
545 /*
546  * Cook lines for cons
547  */
548 void
549 lineproc(void *aux)
550 {
551         Rune rb[256], r;
552         Channel *cook;
553         int nr, done;
554         
555         cook = aux;
556
557         threadsetname("lineproc");
558
559         for(;;){
560                 nr = 0;
561                 done = 0;
562                 do {
563                         recv(cook, &r);
564                         switch(r){
565                         case '\0':      /* flush */
566                                 nr = 0;
567                                 continue;
568                         case '\b':      /* backspace */
569                         case Knack:     /* ^U */
570                                 while(nr > 0){
571                                         nr--;
572                                         fprint(1, "\b");
573                                         if(r == '\b')
574                                                 break;
575                                 }
576                                 continue;
577                         case Keof:      /* ^D */
578                                 done = 1;
579                                 break;
580                         case '\n':
581                                 done = 1;
582                                 /* no break */
583                         default:
584                                 rb[nr++] = r;
585                                 fprint(1, "%C", r);
586                         }
587                 } while(!done && nr < nelem(rb));
588                 sendp(linechan, utfconv(rb, nr));
589         }
590 }
591
592 /*
593  * Queue reads to cons and kbd, flushing and
594  * relay data between 9p and rawchan / kbdchan.
595  */
596 void
597 ctlproc(void *)
598 {
599         struct {
600                 Req *h;
601                 Req **t;
602         } qcons, qkbd, *q;
603         enum { Areq, Actl, Arune, Aline, Akbd, Aend };
604         Alt a[Aend+1];
605         Req *req;
606         Fid *fid;
607         Rune r;
608         char *s, *b, *p, *e;
609         int c, n, raw;
610         Channel *cook;
611
612         threadsetname("ctlproc");
613
614         cook = chancreate(sizeof(Rune), 0);
615
616         if(scanfd >= 0)
617                 proccreate(scanproc, nil, STACK);       /* scanfd -> keychan */
618         if(consfd >= 0)
619                 proccreate(consproc, nil, STACK);       /* consfd -> runechan */
620
621         threadcreate(keyproc, nil, STACK);              /* keychan -> rawchan, kbdchan */
622         threadcreate(runeproc, nil, STACK);             /* rawchan -> runechan */
623         threadcreate(lineproc, cook, STACK);            /* cook -> linechan */
624
625         raw = 0;
626
627         b = p = e = nil;
628
629         qcons.h = nil;
630         qcons.t = &qcons.h;
631         qkbd.h = nil;
632         qkbd.t = &qkbd.h;
633
634         memset(a, 0, sizeof a);
635
636         a[Areq].c = reqchan;
637         a[Areq].v = &req;
638         a[Areq].op = CHANRCV;
639
640         a[Actl].c = ctlchan;
641         a[Actl].v = &c;
642         a[Actl].op = CHANRCV;
643
644         a[Arune].c = runechan;
645         a[Arune].v = &r;
646         a[Arune].op = CHANRCV;
647
648         a[Aline].c = linechan;
649         a[Aline].v = &s;
650         a[Aline].op = CHANRCV;
651
652         a[Akbd].c = kbdchan;
653         a[Akbd].v = &s;
654         a[Akbd].op = CHANRCV;
655
656         a[Aend].op = CHANEND;
657
658         for(;;){
659                 s = nil;
660
661                 if(kbdopen){
662                         a[Arune].op = qkbd.h ? CHANRCV : CHANNOP;
663                         a[Akbd].op = qkbd.h ? CHANRCV : CHANNOP;
664                         a[Aline].op = CHANNOP;
665                 }else{
666                         a[Arune].op = (b == nil) ? CHANRCV : CHANNOP;
667                         a[Akbd].op = CHANRCV;
668                         a[Aline].op = (b == nil) ? CHANRCV : CHANNOP;
669                 }
670
671                 switch(alt(a)){
672                 case Areq:
673                         fid = req->fid;
674                         if(req->ifcall.type == Tflush){
675                                 Req **rr;
676
677                                 fid = req->oldreq->fid;
678                                 q = fid->qid.path == Qcons ? &qcons : &qkbd;
679                                 for(rr = &q->h; *rr && *rr != req->oldreq; rr = &((*rr)->aux))
680                                         ;
681                                 if(*rr == req->oldreq){
682                                         if((*rr = req->oldreq->aux) == nil)
683                                                 q->t = rr;
684                                         req->oldreq->aux = nil;
685                                         respond(req->oldreq, "interrupted");
686                                 }
687                                 respond(req, nil);
688                         } else if(req->ifcall.type == Tread){
689                                 q = fid->qid.path == Qcons ? &qcons : &qkbd;
690                                 req->aux = nil;
691                                 *q->t = req;
692                                 q->t = &req->aux;
693                                 goto Havereq;
694                         } else
695                                 respond(req, Efront);
696                         break;
697
698                 case Actl:
699                         switch(c){
700                         case Rawoff:
701                         case Rawon:
702                                 if(raw = (c == Rawon)){
703                                         while(s = nbrecvp(linechan))
704                                                 free(s);
705                                         r = '\0';
706                                         send(cook, &r);
707                                         free(b);
708                                         b = nil;
709                                 }
710                                 break;
711                         case Kbdflush:
712                                 while(s = nbrecvp(kbdchan))
713                                         free(s);
714                                 break;
715                         }
716                         break;
717
718                 case Arune:
719                         if(kbdopen){
720                                 s = emalloc9p(UTFmax+2);
721                                 s[0] = 'c';
722                                 s[1+runetochar(s+1, &r)] = 0;
723                                 goto Havekbd;
724                         }
725
726                         if(raw){
727                                 s = emalloc9p(UTFmax+1);
728                                 s[runetochar(s, &r)] = 0;
729                         } else {
730                                 nbsend(cook, &r);
731                                 break;
732                         }
733                         /* no break */
734
735                 case Aline:
736                         b = s;
737                         p = s;
738                         e = s + strlen(s);
739
740                 Havereq:
741                         while(b && (req = qcons.h)){
742                                 if((qcons.h = req->aux) == nil)
743                                         qcons.t = &qcons.h;
744                                 n = e - p;
745                                 if(req->ifcall.count < n)
746                                         n = req->ifcall.count;
747                                 req->ofcall.count = n;
748                                 memmove(req->ofcall.data, p, n);
749                                 respond(req, nil);
750                                 p += n;
751                                 if(p >= e){
752                                         free(b);
753                                         b = nil;
754                                 }
755                         }
756                         break;
757
758                 case Akbd:
759                 Havekbd:
760                         if(req = qkbd.h){
761                                 if((qkbd.h = req->aux) == nil)
762                                         qkbd.t = &qkbd.h;
763                                 n = strlen(s) + 1;
764                                 if(n > req->ifcall.count)
765                                         respond(req, Eshort);
766                                 else {
767                                         req->ofcall.count = n;
768                                         memmove(req->ofcall.data, s, n);
769                                         respond(req, nil);
770                                 }
771                         }
772                         free(s);
773                         break;
774                 }
775         }
776 }
777
778 /*
779  * Keyboard layout maps
780  */
781
782 Rune*
783 kbmapent(int t, int sc)
784 {
785         if(sc < 0 || sc >= Nscan)
786                 return nil;
787         switch(t){
788         default:
789                 return nil;
790         case 0:
791                 return &kbtab[sc];
792         case 1:
793                 return &kbtabshift[sc];
794         case 2:
795                 return &kbtabesc1[sc];
796         case 3:
797                 return &kbtabaltgr[sc];
798         case 4:
799                 return &kbtabctl[sc];
800         }
801 }
802
803 void
804 kbmapread(Req *req)
805 {
806         char tmp[3*12+1];
807         int t, sc, off, n;
808         Rune *rp;
809
810         off = req->ifcall.offset/(sizeof(tmp)-1);
811         t = off/Nscan;
812         sc = off%Nscan;
813         if(rp = kbmapent(t, sc))
814                 sprint(tmp, "%11d %11d %11d\n", t, sc, *rp);
815         else
816                 *tmp = 0;
817         n = strlen(tmp);
818         if(req->ifcall.count < n)
819                 n = req->ifcall.count;
820         req->ofcall.count = n;
821         memmove(req->ofcall.data, tmp, n);
822         respond(req, nil);
823 }
824
825 void
826 kbmapwrite(Req *req)
827 {
828         char line[100], *lp, *b;
829         Rune r, *rp;
830         int sc, t, l;
831         Fid *f;
832
833         f = req->fid;
834         b = req->ifcall.data;
835         l = req->ifcall.count;
836         lp = line;
837         if(f->aux){
838                 strcpy(line, f->aux);
839                 lp = line+strlen(line);
840                 free(f->aux);
841                 f->aux = nil;
842         }
843         while(--l >= 0) {
844                 *lp++  = *b++;
845                 if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
846                         *lp = 0;
847                         if(*line == 0){
848                         Badarg:
849                                 respond(req, Ebadarg);
850                                 return;
851                         }
852                         if(*line == '\n' || *line == '#'){
853                                 lp = line;
854                                 continue;
855                         }
856                         lp = line;
857                         while(*lp == ' ' || *lp == '\t')
858                                 lp++;
859                         t = strtoul(line, &lp, 0);
860                         sc = strtoul(lp, &lp, 0);
861                         while(*lp == ' ' || *lp == '\t')
862                                 lp++;
863                         if((rp = kbmapent(t, sc)) == nil)
864                                 goto Badarg;
865                         r = 0;
866                         if(*lp == '\'' && lp[1])
867                                 chartorune(&r, lp+1);
868                         else if(*lp == '^' && lp[1]){
869                                 chartorune(&r, lp+1);
870                                 if(0x40 <= r && r < 0x60)
871                                         r -= 0x40;
872                                 else
873                                         goto Badarg;
874                         }else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
875                                 r = 0xF900+lp[1]-'0';
876                         else if(*lp>='0' && *lp<='9') /* includes 0x... */
877                                 r = strtoul(lp, &lp, 0);
878                         else
879                                 goto Badarg;
880                         *rp = r;
881                         lp = line;
882                 }
883         }
884         if(lp != line){
885                 l = lp-line;
886                 f->aux = lp = emalloc9p(l+1);
887                 memmove(lp, line, l);
888                 lp[l] = 0;
889         }
890         req->ofcall.count = req->ifcall.count;
891         respond(req, nil);
892 }
893
894 /*
895  * Filesystem
896  */
897
898 static char*
899 getauser(void)
900 {
901         static char user[64];
902         int fd;
903         int n;
904
905         if(*user)
906                 return user;
907         if((fd = open("/dev/user", OREAD)) < 0)
908                 strcpy(user, "none");
909         else {
910                 n = read(fd, user, (sizeof user)-1);
911                 close(fd);
912                 if(n < 0)
913                         strcpy(user, "none");
914                 else
915                         user[n] = 0;
916         }
917         return user;
918 }
919
920 static int
921 fillstat(ulong qid, Dir *d)
922 {
923         struct Qtab *t;
924
925         memset(d, 0, sizeof *d);
926         d->uid = getauser();
927         d->gid = getauser();
928         d->muid = "";
929         d->qid = (Qid){qid, 0, 0};
930         d->atime = time(0);
931         t = qtab + qid;
932         d->name = t->name;
933         d->qid.type = t->type;
934         d->mode = t->mode;
935         return 1;
936 }
937
938 static void
939 fsattach(Req *r)
940 {
941         char *spec;
942
943         spec = r->ifcall.aname;
944         if(spec && spec[0]){
945                 respond(r, Ebadspec);
946                 return;
947         }
948         r->fid->qid = (Qid){Qroot, 0, QTDIR};
949         r->ofcall.qid = r->fid->qid;
950         respond(r, nil);
951 }
952
953 static void
954 fsstat(Req *r)
955 {
956         fillstat((ulong)r->fid->qid.path, &r->d);
957         r->d.name = estrdup9p(r->d.name);
958         r->d.uid = estrdup9p(r->d.uid);
959         r->d.gid = estrdup9p(r->d.gid);
960         r->d.muid = estrdup9p(r->d.muid);
961         respond(r, nil);
962 }
963
964 static char*
965 fswalk1(Fid *fid, char *name, Qid *qid)
966 {
967         int i;
968         ulong path;
969
970         path = fid->qid.path;
971         switch(path){
972         case Qroot:
973                 if (strcmp(name, "..") == 0) {
974                         *qid = (Qid){Qroot, 0, QTDIR};
975                         fid->qid = *qid;
976                         return nil;
977                 }
978                 for(i = fid->qid.path; i<Nqid; i++){
979                         if(strcmp(name, qtab[i].name) != 0)
980                                 continue;
981                         *qid = (Qid){i, 0, 0};
982                         fid->qid = *qid;
983                         return nil;
984                 }
985                 return Enonexist;
986                 
987         default:
988                 return Ewalk;
989         }
990 }
991
992 static void
993 fsopen(Req *r)
994 {
995         Fid *f;
996         static int need[4] = { 4, 2, 6, 1 };
997         struct Qtab *t;
998         int n;
999
1000         f = r->fid;
1001         t = qtab + f->qid.path;
1002         n = need[r->ifcall.mode & 3]<<6;
1003         if((n & t->mode) != n)
1004                 respond(r, Eperm);
1005         else{
1006                 f->aux = nil;
1007                 switch((ulong)f->qid.path){
1008                 case Qkbd:
1009                         if(kbdopen){
1010                                 respond(r, Einuse);
1011                                 return;
1012                         }
1013                         kbdopen++;
1014                         sendul(ctlchan, Kbdflush);
1015                         break;
1016                 case Qcons:
1017                         consopen++;
1018                         break;
1019                 case Qconsctl:
1020                         consctlopen++;
1021                         break;
1022                 }
1023                 respond(r, nil);
1024         }
1025 }
1026
1027 static int
1028 readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
1029 {
1030         int i, m, n;
1031         long pos;
1032         Dir d;
1033
1034         n = 0;
1035         pos = 0;
1036         for (i = 1; i < Nqid; i++){
1037                 fillstat(i, &d);
1038                 m = convD2M(&d, &buf[n], blen-n);
1039                 if(off <= pos){
1040                         if(m <= BIT16SZ || m > cnt)
1041                                 break;
1042                         n += m;
1043                         cnt -= m;
1044                 }
1045                 pos += m;
1046         }
1047         return n;
1048 }
1049
1050 static void
1051 fsread(Req *r)
1052 {
1053         Fid *f;
1054
1055         f = r->fid;
1056         switch((ulong)f->qid.path){
1057         default:
1058                 respond(r, Efront);
1059                 return;
1060
1061         case Qroot:
1062                 r->ofcall.count = readtopdir(f, (void*)r->ofcall.data, r->ifcall.offset,
1063                         r->ifcall.count, r->ifcall.count);
1064                 break;
1065
1066         case Qkbd:
1067         case Qcons:
1068                 sendp(reqchan, r);
1069                 return;
1070
1071         case Qkbmap:
1072                 kbmapread(r);
1073                 return;
1074         }
1075         respond(r, nil);
1076 }
1077
1078 static void
1079 fswrite(Req *r)
1080 {
1081         Fid *f;
1082         char *p;
1083         int n, i;
1084
1085         f = r->fid;
1086         switch((ulong)f->qid.path){
1087         default:
1088                 respond(r, Efront);
1089                 return;
1090
1091         case Qcons:
1092                 n = r->ifcall.count;
1093                 if(write(1, r->ifcall.data, n) != n){
1094                         responderror(r);
1095                         return;
1096                 }
1097                 r->ofcall.count = n;
1098                 break;
1099
1100         case Qconsctl:
1101                 p = r->ifcall.data;
1102                 n = r->ifcall.count;
1103                 if(n >= 5 && memcmp(p, "rawon", 5) == 0)
1104                         sendul(ctlchan, Rawon);
1105                 else if(n >= 6 && memcmp(p, "rawoff", 6) == 0)
1106                         sendul(ctlchan, Rawoff);
1107                 else {
1108                         respond(r, Ebadarg);
1109                         return;
1110                 }
1111                 r->ofcall.count = n;
1112                 break;
1113
1114         case Qkbin:
1115                 if(f->aux == nil){
1116                         f->aux = emalloc9p(sizeof(Scan));
1117                         memset(f->aux, 0, sizeof(Scan));
1118                 }
1119                 for(i=0; i<r->ifcall.count; i++)
1120                         kbdputsc((Scan*)f->aux, (uchar)r->ifcall.data[i]);
1121                 r->ofcall.count = i;
1122                 break;
1123
1124         case Qkbmap:
1125                 kbmapwrite(r);
1126                 return;
1127
1128         }
1129         respond(r, nil);
1130 }
1131
1132 static void
1133 fsflush(Req *r)
1134 {
1135         switch((ulong)r->oldreq->fid->qid.path) {
1136         case Qkbd:
1137         case Qcons:
1138                 sendp(reqchan, r);
1139                 return;
1140         }
1141         respond(r, nil);
1142 }
1143
1144 static void
1145 fsdestroyfid(Fid *f)
1146 {
1147         void *p;
1148
1149         if(f->omode != -1)
1150                 switch((ulong)f->qid.path){
1151                 case Qkbin:
1152                 case Qkbmap:
1153                         if(p = f->aux){
1154                                 f->aux = nil;
1155                                 free(p);
1156                         }
1157                         break;
1158                 case Qkbd:
1159                         kbdopen--;
1160                         break;
1161                 case Qcons:
1162                         consopen--;
1163                         break;
1164                 case Qconsctl:
1165                         if(--consctlopen == 0)
1166                                 sendul(ctlchan, Rawoff);
1167                         break;
1168                 }
1169 }
1170
1171 static void
1172 fsend(Srv*)
1173 {
1174         threadexitsall(nil);
1175 }
1176
1177 Srv fs = {
1178         .attach=                        fsattach,
1179         .walk1=                 fswalk1,
1180         .open=                  fsopen,
1181         .read=                  fsread,
1182         .write=                 fswrite,
1183         .stat=                  fsstat,
1184         .flush=                 fsflush,
1185         .destroyfid=            fsdestroyfid,
1186         .end=                   fsend,
1187 };
1188
1189 void
1190 reboot(void)
1191 {
1192         int fd;
1193
1194         if(debug)
1195                 return;
1196
1197         if((fd = open("/dev/reboot", OWRITE)) < 0){
1198                 fprint(2, "can't open /dev/reboot: %r\n");
1199                 return;
1200         }
1201         fprint(fd, "reboot\n");
1202         close(fd);
1203 }
1204
1205 void
1206 elevate(void)
1207 {
1208         char buf[128];
1209         Dir *d, nd;
1210         int fd;
1211
1212         if(debug)
1213                 return;
1214
1215         snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
1216         if((fd = open(buf, OWRITE)) < 0){
1217                 fprint(2, "can't open %s: %r\n", buf);
1218                 return;
1219         }
1220
1221         /* get higher than normal priority */
1222         fprint(fd, "pri 16\n");
1223
1224         /* always present in physical memory */
1225         fprint(fd, "noswap\n");
1226
1227         /* dont let anybody kill us */
1228         if(d = dirfstat(fd)){
1229                 nulldir(&nd);
1230                 nd.mode = d->mode & ~0222;
1231                 dirfwstat(fd, &nd);
1232                 free(d);
1233         }
1234
1235         close(fd);
1236         
1237 }
1238
1239 void
1240 usage(void)
1241 {
1242         fprint(2, "usage: %s [ -dD ] [ -s srv ] [ -m mntpnt ] [ file ]\n", argv0);
1243         exits("usage");
1244 }
1245
1246 void
1247 threadmain(int argc, char** argv)
1248 {
1249         char *mtpt = "/dev";
1250         char *srv = nil;
1251
1252         consfd = -1;
1253
1254         ARGBEGIN{
1255         case 'd':
1256                 debug++;
1257                 break;
1258         case 'D':
1259                 chatty9p++;
1260                 break;
1261         case 's':
1262                 srv = EARGF(usage());
1263                 break;
1264         case 'm':
1265                 mtpt = EARGF(usage());
1266                 break;
1267         default:
1268                 usage();
1269         }ARGEND
1270
1271         if((scanfd = open("/dev/scancode", OREAD)) < 0)
1272                 fprint(2, "%s: warning: can't open /dev/scancode: %r\n", argv0);
1273         if((ledsfd = open("/dev/leds", OWRITE)) < 0)
1274                 fprint(2, "%s: warning: can't open /dev/leds: %r\n", argv0);
1275
1276         if(*argv)
1277                 if((consfd = open(*argv, OREAD)) < 0)
1278                         fprint(2, "%s: warning: can't open %s: %r\n", argv0, *argv);
1279
1280         keychan = chancreate(sizeof(Key), 8);
1281         reqchan = chancreate(sizeof(Req*), 0);
1282         ctlchan = chancreate(sizeof(int), 0);
1283         rawchan = chancreate(sizeof(Rune), 16);
1284         runechan = chancreate(sizeof(Rune), 32);
1285         linechan = chancreate(sizeof(char*), 16);
1286         kbdchan = chancreate(sizeof(char*), 16);
1287
1288         if(!(keychan && reqchan && ctlchan && rawchan && runechan && linechan && kbdchan))
1289                 sysfatal("allocating chans");
1290
1291         elevate();
1292         procrfork(ctlproc, nil, STACK, RFNAMEG|RFNOTEG);
1293         threadpostmountsrv(&fs, srv, mtpt, MBEFORE);
1294 }