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