123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- #include <u.h>
- #include <libc.h>
- #include "compat.h"
- #include "kbd.h"
- #include "error.h"
- typedef struct Queue Queue;
- struct Queue
- {
- QLock qwait;
- Rendez rwait;
- Lock lock;
- int notempty;
- char buf[1024];
- char *w;
- char *r;
- char *e;
- };
- Queue* kbdq; /* unprocessed console input */
- Queue* lineq; /* processed console input */
- Snarf snarf = {
- .vers = 1
- };
- static struct
- {
- QLock;
- int raw; /* true if we shouldn't process input */
- int ctl; /* number of opens to the control file */
- int x; /* index into line */
- char line[1024]; /* current input line */
- } kbd;
- /*
- * cheapo fixed-length queues
- */
- static void
- qwrite(Queue *q, void *v, int n)
- {
- char *buf, *next;
- int i;
- buf = v;
- lock(&q->lock);
- for(i = 0; i < n; i++){
- next = q->w+1;
- if(next >= q->e)
- next = q->buf;
- if(next == q->r)
- break;
- *q->w = buf[i];
- q->w = next;
- }
- q->notempty = 1;
- unlock(&q->lock);
- rendwakeup(&q->rwait);
- }
- static int
- qcanread(void *vq)
- {
- Queue *q;
- int ne;
- q = vq;
- lock(&q->lock);
- ne = q->notempty;
- unlock(&q->lock);
- return ne;
- }
- static int
- qread(Queue *q, void *v, int n)
- {
- char *a;
- int nn, notempty;
- if(n == 0)
- return 0;
- a = v;
- nn = 0;
- for(;;){
- lock(&q->lock);
- while(nn < n && q->r != q->w){
- a[nn++] = *q->r++;
- if(q->r >= q->e)
- q->r = q->buf;
- }
- notempty = q->notempty;
- q->notempty = q->r != q->w;
- unlock(&q->lock);
- if(notempty)
- break;
- /*
- * wait for something to show up in the kbd buffer.
- */
- qlock(&q->qwait);
- if(waserror()){
- qunlock(&q->qwait);
- nexterror();
- }
- rendsleep(&q->rwait, qcanread, q);
- qunlock(&q->qwait);
- poperror();
- }
- return nn;
- }
- static Queue *
- mkqueue(void)
- {
- Queue *q;
- q = smalloc(sizeof(Queue));
- q->r = q->buf;
- q->w = q->r;
- q->e = &q->buf[sizeof q->buf];
- q->notempty = 0;
- return q;
- }
- static void
- echoscreen(char *buf, int n)
- {
- char *e, *p;
- char ebuf[128];
- int x;
- p = ebuf;
- e = ebuf + sizeof(ebuf) - 4;
- while(n-- > 0){
- if(p >= e){
- screenputs(ebuf, p - ebuf);
- p = ebuf;
- }
- x = *buf++;
- if(x == 0x15){
- *p++ = '^';
- *p++ = 'U';
- *p++ = '\n';
- } else
- *p++ = x;
- }
- if(p != ebuf)
- screenputs(ebuf, p - ebuf);
- }
- /*
- * Put character, possibly a rune, into read queue at interrupt time.
- * Called at interrupt time to process a character.
- */
- void
- kbdputc(int ch)
- {
- int n;
- char buf[3];
- Rune r;
- r = ch;
- n = runetochar(buf, &r);
- qwrite(kbdq, buf, n);
- if(!kbd.raw)
- echoscreen(buf, n);
- }
- static void
- kbdputcinit(void)
- {
- kbdq = mkqueue();
- lineq = mkqueue();
- kbd.raw = 0;
- kbd.ctl = 0;
- kbd.x = 0;
- }
- enum{
- Qdir,
- Qcons,
- Qconsctl,
- Qsnarf,
- Qwinname,
- };
- static Dirtab consdir[]={
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "cons", {Qcons}, 0, 0660,
- "consctl", {Qconsctl}, 0, 0220,
- "snarf", {Qsnarf}, 0, 0600,
- "winname", {Qwinname}, 0, 0000,
- };
- static void
- consinit(void)
- {
- kbdputcinit();
- }
- static Chan*
- consattach(char *spec)
- {
- return devattach('c', spec);
- }
- static Walkqid*
- conswalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
- }
- static int
- consstat(Chan *c, uchar *dp, int n)
- {
- return devstat(c, dp, n, consdir, nelem(consdir), devgen);
- }
- static Chan*
- consopen(Chan *c, int omode)
- {
- c->aux = nil;
- c = devopen(c, omode, consdir, nelem(consdir), devgen);
- switch((ulong)c->qid.path){
- case Qconsctl:
- qlock(&kbd);
- kbd.ctl++;
- qunlock(&kbd);
- break;
- case Qsnarf:
- if((c->mode&3) == OWRITE || (c->mode&3) == ORDWR)
- c->aux = smalloc(sizeof(Snarf));
- break;
- }
- return c;
- }
- void
- setsnarf(char *buf, int n, int *vers)
- {
- int i;
- qlock(&snarf);
- snarf.vers++;
- if(vers)
- *vers = snarf.vers;
- for(i = 0; i < nelem(consdir); i++){
- if(consdir[i].qid.type == Qsnarf){
- consdir[i].qid.vers = snarf.vers;
- break;
- }
- }
- free(snarf.buf);
- snarf.n = n;
- snarf.buf = buf;
- qunlock(&snarf);
- }
- static void
- consclose(Chan *c)
- {
- Snarf *t;
- switch((ulong)c->qid.path){
- /* last close of control file turns off raw */
- case Qconsctl:
- if(c->flag&COPEN){
- qlock(&kbd);
- if(--kbd.ctl == 0)
- kbd.raw = 0;
- qunlock(&kbd);
- }
- break;
- /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
- case Qsnarf:
- t = c->aux;
- if(t == nil)
- break;
- setsnarf(t->buf, t->n, 0);
- t->buf = nil; /* setsnarf took it */
- free(t);
- c->aux = nil;
- break;
- }
- }
- static long
- consread(Chan *c, void *buf, long n, vlong off)
- {
- char ch;
- int send;
- if(n <= 0)
- return n;
- switch((ulong)c->qid.path){
- case Qsnarf:
- qlock(&snarf);
- if(off < snarf.n){
- if(off + n > snarf.n)
- n = snarf.n - off;
- memmove(buf, snarf.buf+off, n);
- }else
- n = 0;
- qunlock(&snarf);
- return n;
- case Qdir:
- return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
- case Qcons:
- qlock(&kbd);
- if(waserror()){
- qunlock(&kbd);
- nexterror();
- }
- while(!qcanread(lineq)){
- qread(kbdq, &ch, 1);
- send = 0;
- if(ch == 0){
- /* flush output on rawoff -> rawon */
- if(kbd.x > 0)
- send = !qcanread(kbdq);
- }else if(kbd.raw){
- kbd.line[kbd.x++] = ch;
- send = !qcanread(kbdq);
- }else{
- switch(ch){
- case '\b':
- if(kbd.x > 0)
- kbd.x--;
- break;
- case 0x15: /* ^U */
- kbd.x = 0;
- break;
- case '\n':
- case 0x04: /* ^D */
- send = 1;
- default:
- if(ch != 0x04)
- kbd.line[kbd.x++] = ch;
- break;
- }
- }
- if(send || kbd.x == sizeof kbd.line){
- qwrite(lineq, kbd.line, kbd.x);
- kbd.x = 0;
- }
- }
- n = qread(lineq, buf, n);
- qunlock(&kbd);
- poperror();
- return n;
- default:
- print("consread 0x%llux\n", c->qid.path);
- error(Egreg);
- }
- return -1; /* never reached */
- }
- static long
- conswrite(Chan *c, void *va, long n, vlong)
- {
- Snarf *t;
- char buf[256], *a;
- char ch;
- switch((ulong)c->qid.path){
- case Qcons:
- screenputs(va, n);
- break;
- case Qconsctl:
- if(n >= sizeof(buf))
- n = sizeof(buf)-1;
- strncpy(buf, va, n);
- buf[n] = 0;
- for(a = buf; a;){
- if(strncmp(a, "rawon", 5) == 0){
- kbd.raw = 1;
- /* clumsy hack - wake up reader */
- ch = 0;
- qwrite(kbdq, &ch, 1);
- } else if(strncmp(a, "rawoff", 6) == 0){
- kbd.raw = 0;
- }
- if(a = strchr(a, ' '))
- a++;
- }
- break;
- case Qsnarf:
- t = c->aux;
- /* always append only */
- if(t->n > MAXSNARF) /* avoid thrashing when people cut huge text */
- error("snarf buffer too big");
- a = realloc(t->buf, t->n + n + 1);
- if(a == nil)
- error("snarf buffer too big");
- t->buf = a;
- memmove(t->buf+t->n, va, n);
- t->n += n;
- t->buf[t->n] = '\0';
- break;
- default:
- print("conswrite: 0x%llux\n", c->qid.path);
- error(Egreg);
- }
- return n;
- }
- Dev consdevtab = {
- 'c',
- "cons",
- devreset,
- consinit,
- consattach,
- conswalk,
- consstat,
- consopen,
- devcreate,
- consclose,
- consread,
- devbread,
- conswrite,
- devbwrite,
- devremove,
- devwstat,
- };
|