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