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