27 typedef struct Key Key;
28 typedef struct Scan Scan;
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";
98 Channel *keychan; /* Key */
100 Channel *reqchan; /* Req* */
101 Channel *ctlchan; /* int */
103 Channel *rawchan; /* Rune */
104 Channel *linechan; /* char * */
105 Channel *kbdchan; /* char* */
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.
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,
131 Rune kbtabshift[Nscan] =
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,
151 Rune kbtabesc1[Nscan] =
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,
171 Rune kbtabaltgr[Nscan] =
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,
191 Rune kbtabctl[Nscan] =
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,
214 * Scan code processing
217 kbdputsc(Scan *scan, int c)
222 * e0's is the first of a 2 character sequence, e1 the first
223 * of a 3 character sequence (on the safari)
228 } else if(c == 0xe1){
233 key.down = (c & 0x80) == 0;
240 key.r = kbtabesc1[key.c];
242 key.r = kbtabshift[key.c];
244 key.r = kbtabaltgr[key.c];
246 key.r = kbtabctl[key.c];
248 key.r = kbtab[key.c];
265 key.b = kbtab[key.c];
267 if(scan->caps && key.r<='z' && key.r>='a')
270 if(scan->ctl && scan->alt && key.r == Kdel)
282 scan->shift = key.down;
285 scan->ctl = key.down;
288 scan->altgr = key.down;
291 scan->alt = key.down;
294 scan->num ^= key.down;
297 scan->caps ^= key.down;
303 setleds(Scan *scan, int leds)
307 if(ledsfd < 0 || scan->leds == leds)
310 snprint(buf, sizeof(buf), "%d", leds);
311 pwrite(ledsfd, buf, strlen(buf), 0);
316 * Read scan codes from scanfd
325 threadsetname("scanproc");
327 memset(&scan, 0, sizeof scan);
328 while((n = read(scanfd, buf, sizeof buf)) > 0){
330 kbdputsc(&scan, buf[i]);
331 setleds(&scan, (scan.num<<1) | (scan.caps<<2));
336 utfconv(Rune *r, int n)
341 l = runenlen(r, n) + 1;
343 for(p = s; n > 0; r++, n--)
344 p += runetochar(p, r);
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.
363 threadsetname("keyproc");
366 while(recv(keychan, &key) > 0){
378 nbsend(rawchan, &key.r);
382 for(i=0; i<nb && cb[i] != key.c; i++)
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]));
390 } else if(i == nb && nb < nelem(cb) && key.b){
394 if(nb < nelem(cb) && key.r && key.b != key.r){
401 if(nbsendp(kbdchan, s) <= 0)
407 * Read characters from consfd (serial console)
412 char *p, *e, *x, buf[64];
416 threadsetname("consproc");
420 e = buf + sizeof(buf);
421 while((n = read(consfd, p, e - p)) > 0){
423 while(p < x && fullrune(p, x - p)){
424 p += chartorune(&r, p);
442 * Cook lines for cons
453 threadsetname("lineproc");
461 case '\0': /* flush */
464 case '\b': /* backspace */
483 } while(!done && nr < nelem(rb));
484 sendp(linechan, utfconv(rb, nr));
489 * Queue reads to cons and kbd, flushing and
490 * relay data between 9p and rawchan / kbdchan.
499 enum { Areq, Actl, Araw, Aline, Akbd, Aend };
508 threadsetname("ctlproc");
510 cook = chancreate(sizeof(Rune), 0);
513 proccreate(scanproc, nil, STACK);
515 proccreate(consproc, nil, STACK);
517 threadcreate(keyproc, nil, STACK);
518 threadcreate(lineproc, cook, STACK);
529 memset(a, 0, sizeof a);
533 a[Areq].op = CHANRCV;
537 a[Actl].op = CHANRCV;
541 a[Araw].op = CHANRCV;
543 a[Aline].c = linechan;
545 a[Aline].op = CHANRCV;
549 a[Akbd].op = CHANRCV;
551 a[Aend].op = CHANEND;
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;
563 if(req->ifcall.type == Tflush){
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))
570 if(*rr == req->oldreq){
571 if((*rr = req->oldreq->aux) == nil)
573 req->oldreq->aux = nil;
574 respond(req->oldreq, "interrupted");
577 } else if(req->ifcall.type == Tread){
578 q = fid->qid.path == Qcons ? &qcons : &qkbd;
584 respond(req, Efront);
591 if(raw = (c == Rawon)){
592 while(s = nbrecvp(linechan))
601 while(s = nbrecvp(kbdchan))
609 s = emalloc9p(UTFmax+1);
610 s[runetochar(s, &r)] = 0;
623 while(b && (req = qcons.h)){
624 if((qcons.h = req->aux) == nil)
627 if(req->ifcall.count < n)
628 n = req->ifcall.count;
629 req->ofcall.count = n;
630 memmove(req->ofcall.data, p, n);
642 if((qkbd.h = req->aux) == nil)
645 if(n > req->ifcall.count)
646 respond(req, Eshort);
648 req->ofcall.count = n;
649 memmove(req->ofcall.data, s, n);
660 * Keyboard layout maps
664 kbmapent(int t, int sc)
666 if(sc < 0 || sc >= Nscan)
674 return &kbtabshift[sc];
676 return &kbtabesc1[sc];
678 return &kbtabaltgr[sc];
680 return &kbtabctl[sc];
691 off = req->ifcall.offset/(sizeof(tmp)-1);
694 if(rp = kbmapent(t, sc))
695 sprint(tmp, "%11d %11d %11d\n", t, sc, *rp);
699 if(req->ifcall.count < n)
700 n = req->ifcall.count;
701 req->ofcall.count = n;
702 memmove(req->ofcall.data, tmp, n);
709 char line[100], *lp, *b;
715 b = req->ifcall.data;
716 l = req->ifcall.count;
719 strcpy(line, f->aux);
720 lp = line+strlen(line);
726 if(lp[-1] == '\n' || lp == &line[sizeof(line)-1]) {
730 respond(req, Ebadarg);
733 if(*line == '\n' || *line == '#'){
738 while(*lp == ' ' || *lp == '\t')
740 t = strtoul(line, &lp, 0);
741 sc = strtoul(lp, &lp, 0);
742 while(*lp == ' ' || *lp == '\t')
744 if((rp = kbmapent(t, sc)) == nil)
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)
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);
767 f->aux = lp = emalloc9p(l+1);
768 memmove(lp, line, l);
771 req->ofcall.count = req->ifcall.count;
782 static char user[64];
788 if((fd = open("/dev/user", OREAD)) < 0)
789 strcpy(user, "none");
791 n = read(fd, user, (sizeof user)-1);
794 strcpy(user, "none");
802 fillstat(ulong qid, Dir *d)
806 memset(d, 0, sizeof *d);
810 d->qid = (Qid){qid, 0, 0};
814 d->qid.type = t->type;
824 spec = r->ifcall.aname;
826 respond(r, Ebadspec);
829 r->fid->qid = (Qid){Qroot, 0, QTDIR};
830 r->ofcall.qid = r->fid->qid;
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);
846 fswalk1(Fid *fid, char *name, Qid *qid)
851 path = fid->qid.path;
854 if (strcmp(name, "..") == 0) {
855 *qid = (Qid){Qroot, 0, QTDIR};
859 for(i = fid->qid.path; i<Nqid; i++){
860 if(strcmp(name, qtab[i].name) != 0)
862 *qid = (Qid){i, 0, 0};
877 static int need[4] = { 4, 2, 6, 1 };
882 t = qtab + f->qid.path;
883 n = need[r->ifcall.mode & 3]<<6;
884 if((n & t->mode) != n)
888 switch((ulong)f->qid.path){
895 sendul(ctlchan, Kbdflush);
909 readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
917 for (i = 1; i < Nqid; i++){
919 m = convD2M(&d, &buf[n], blen-n);
921 if(m <= BIT16SZ || m > cnt)
937 switch((ulong)f->qid.path){
943 r->ofcall.count = readtopdir(f, (void*)r->ofcall.data, r->ifcall.offset,
944 r->ifcall.count, r->ifcall.count);
967 switch((ulong)f->qid.path){
974 if(write(1, r->ifcall.data, n) != n){
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);
997 f->aux = emalloc9p(sizeof(Scan));
998 memset(f->aux, 0, sizeof(Scan));
1000 for(i=0; i<r->ifcall.count; i++)
1001 kbdputsc((Scan*)f->aux, (uchar)r->ifcall.data[i]);
1002 r->ofcall.count = i;
1016 switch((ulong)r->oldreq->fid->qid.path) {
1026 fsdestroyfid(Fid *f)
1031 switch((ulong)f->qid.path){
1046 if(--consctlopen == 0)
1047 sendul(ctlchan, Rawoff);
1055 threadexitsall(nil);
1066 .destroyfid= fsdestroyfid,
1078 if((fd = open("/dev/reboot", OWRITE)) < 0){
1079 fprint(2, "can't open /dev/reboot: %r\n");
1082 fprint(fd, "reboot\n");
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);
1102 /* get higher than normal priority */
1103 fprint(fd, "pri 16\n");
1105 /* always present in physical memory */
1106 fprint(fd, "noswap\n");
1108 /* dont let anybody kill us */
1109 if(d = dirfstat(fd)){
1111 nd.mode = d->mode & ~0222;
1123 fprint(2, "usage: %s [ -dD ] [ -s srv ] [ -m mntpnt ] [ file ]\n", argv0);
1128 threadmain(int argc, char** argv)
1130 char *mtpt = "/dev";
1143 srv = EARGF(usage());
1146 mtpt = EARGF(usage());
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);
1158 if((consfd = open(*argv, OREAD)) < 0)
1159 fprint(2, "%s: warning: can't open %s: %r\n", argv0, *argv);
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);
1168 if(!(keychan && reqchan && ctlchan && rawchan && linechan && kbdchan))
1169 sysfatal("allocating chans");
1172 procrfork(ctlproc, nil, STACK, RFNAMEG|RFNOTEG);
1173 threadpostmountsrv(&fs, srv, mtpt, MBEFORE);