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