]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vnc/devcons.c
kernel: keep segment locked for data2txt
[plan9front.git] / sys / src / cmd / vnc / devcons.c
1 #include        <u.h>
2 #include        <libc.h>
3 #include        "compat.h"
4 #include        "kbd.h"
5 #include        "error.h"
6
7 typedef struct Queue    Queue;
8 struct Queue
9 {
10         QLock   qwait;
11         Rendez  rwait;
12
13         Lock    lock;
14         int     notempty;
15         char    buf[1024];
16         char    *w;
17         char    *r;
18         char    *e;
19 };
20
21 Queue*  kbdq;                   /* unprocessed console input */
22 Queue*  lineq;                  /* processed console input */
23 Snarf   snarf = {
24         .vers = 1
25 };
26
27 static struct
28 {
29         QLock;
30         int     raw;            /* true if we shouldn't process input */
31         int     ctl;            /* number of opens to the control file */
32         int     x;              /* index into line */
33         char    line[1024];     /* current input line */
34 } kbd;
35
36 /*
37  * cheapo fixed-length queues
38  */
39 static void
40 qwrite(Queue *q, void *v, int n)
41 {
42         char *buf, *next;
43         int i;
44
45         buf = v;
46         lock(&q->lock);
47         for(i = 0; i < n; i++){
48                 next = q->w+1;
49                 if(next >= q->e)
50                         next = q->buf;
51                 if(next == q->r)
52                         break;
53                 *q->w = buf[i];
54                 q->w = next;
55         }
56         q->notempty = 1;
57         unlock(&q->lock);
58         rendwakeup(&q->rwait);
59 }
60
61 static int
62 qcanread(void *vq)
63 {
64         Queue *q;
65         int ne;
66
67         q = vq;
68         lock(&q->lock);
69         ne = q->notempty;
70         unlock(&q->lock);
71         return ne;
72 }
73
74 static int
75 qread(Queue *q, void *v, int n)
76 {
77         char *a;
78         int nn, notempty;
79
80         if(n == 0)
81                 return 0;
82         a = v;
83         nn = 0;
84         for(;;){
85                 lock(&q->lock);
86
87                 while(nn < n && q->r != q->w){
88                         a[nn++] = *q->r++;
89                         if(q->r >= q->e)
90                                 q->r = q->buf;
91                 }
92
93                 notempty = q->notempty;
94                 q->notempty = q->r != q->w;
95                 unlock(&q->lock);
96                 if(notempty)
97                         break;
98
99                 /*
100                  * wait for something to show up in the kbd buffer.
101                  */
102                 qlock(&q->qwait);
103                 if(waserror()){
104                         qunlock(&q->qwait);
105                         nexterror();
106                 }
107                 rendsleep(&q->rwait, qcanread, q);
108                 qunlock(&q->qwait);
109                 poperror();
110         }
111         return nn;
112 }
113
114 static Queue *
115 mkqueue(void)
116 {
117         Queue *q;
118
119         q = smalloc(sizeof(Queue));
120         q->r = q->buf;
121         q->w = q->r;
122         q->e = &q->buf[sizeof q->buf];
123         q->notempty = 0;
124         return q;
125 }
126
127 static void
128 echoscreen(char *buf, int n)
129 {
130         char *e, *p;
131         char ebuf[128];
132         int x;
133
134         p = ebuf;
135         e = ebuf + sizeof(ebuf) - 4;
136         while(n-- > 0){
137                 if(p >= e){
138                         screenputs(ebuf, p - ebuf);
139                         p = ebuf;
140                 }
141                 x = *buf++;
142                 if(x == 0x15){
143                         *p++ = '^';
144                         *p++ = 'U';
145                         *p++ = '\n';
146                 } else
147                         *p++ = x;
148         }
149         if(p != ebuf)
150                 screenputs(ebuf, p - ebuf);
151 }
152
153 /*
154  *  Put character, possibly a rune, into read queue at interrupt time.
155  *  Called at interrupt time to process a character.
156  */
157 void
158 kbdputc(int ch)
159 {
160         int n;
161         char buf[3];
162         Rune r;
163
164         r = ch;
165         n = runetochar(buf, &r);
166         qwrite(kbdq, buf, n);
167         if(!kbd.raw)
168                 echoscreen(buf, n);
169 }
170
171 static void
172 kbdputcinit(void)
173 {
174         kbdq = mkqueue();
175         lineq = mkqueue();
176         kbd.raw = 0;
177         kbd.ctl = 0;
178         kbd.x = 0;
179 }
180
181 enum{
182         Qdir,
183         Qcons,
184         Qconsctl,
185         Qsnarf,
186         Qwinname,
187 };
188
189 static Dirtab consdir[]={
190         ".",            {Qdir, 0, QTDIR},       0,              DMDIR|0555,
191         "cons",         {Qcons},        0,              0660,
192         "consctl",      {Qconsctl},     0,              0220,
193         "snarf",        {Qsnarf},       0,              0600,
194         "winname",      {Qwinname},     0,              0000,
195 };
196
197 static void
198 consinit(void)
199 {
200         kbdputcinit();
201 }
202
203 static Chan*
204 consattach(char *spec)
205 {
206         return devattach('c', spec);
207 }
208
209 static Walkqid*
210 conswalk(Chan *c, Chan *nc, char **name, int nname)
211 {
212         return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);
213 }
214
215 static int
216 consstat(Chan *c, uchar *dp, int n)
217 {
218         return devstat(c, dp, n, consdir, nelem(consdir), devgen);
219 }
220
221 static Chan*
222 consopen(Chan *c, int omode)
223 {
224         c->aux = nil;
225         c = devopen(c, omode, consdir, nelem(consdir), devgen);
226         switch((ulong)c->qid.path){
227         case Qconsctl:
228                 qlock(&kbd);
229                 kbd.ctl++;
230                 qunlock(&kbd);
231                 break;
232         case Qsnarf:
233                 if((c->mode&3) == OWRITE || (c->mode&3) == ORDWR)
234                         c->aux = smalloc(sizeof(Snarf));
235                 break;
236         }
237         return c;
238 }
239
240 void
241 setsnarf(char *buf, int n, int *vers)
242 {
243         int i;
244
245         qlock(&snarf);
246         snarf.vers++;
247         if(vers)
248                 *vers = snarf.vers;     
249         for(i = 0; i < nelem(consdir); i++){
250                 if(consdir[i].qid.type == Qsnarf){
251                         consdir[i].qid.vers = snarf.vers;
252                         break;
253                 }
254         }
255         free(snarf.buf);
256         snarf.n = n;
257         snarf.buf = buf;
258         qunlock(&snarf);
259 }
260
261 static void
262 consclose(Chan *c)
263 {
264         Snarf *t;
265
266         switch((ulong)c->qid.path){
267         /* last close of control file turns off raw */
268         case Qconsctl:
269                 if(c->flag&COPEN){
270                         qlock(&kbd);
271                         if(--kbd.ctl == 0)
272                                 kbd.raw = 0;
273                         qunlock(&kbd);
274                 }
275                 break;
276         /* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
277         case Qsnarf:
278                 t = c->aux;
279                 if(t == nil)
280                         break;
281                 setsnarf(t->buf, t->n, 0);
282                 t->buf = nil;   /* setsnarf took it */
283                 free(t);
284                 c->aux = nil;
285                 break;
286         }
287 }
288
289 static long
290 consread(Chan *c, void *buf, long n, vlong off)
291 {
292         char ch;
293         int     send;
294
295         if(n <= 0)
296                 return n;
297         switch((ulong)c->qid.path){
298         case Qsnarf:
299                 qlock(&snarf);
300                 if(off < snarf.n){
301                         if(off + n > snarf.n)
302                                 n = snarf.n - off;
303                         memmove(buf, snarf.buf+off, n);
304                 }else
305                         n = 0;
306                 qunlock(&snarf);
307                 return n;
308
309         case Qdir:
310                 return devdirread(c, buf, n, consdir, nelem(consdir), devgen);
311
312         case Qcons:
313                 qlock(&kbd);
314                 if(waserror()){
315                         qunlock(&kbd);
316                         nexterror();
317                 }
318                 while(!qcanread(lineq)){
319                         qread(kbdq, &ch, 1);
320                         send = 0;
321                         if(ch == 0){
322                                 /* flush output on rawoff -> rawon */
323                                 if(kbd.x > 0)
324                                         send = !qcanread(kbdq);
325                         }else if(kbd.raw){
326                                 kbd.line[kbd.x++] = ch;
327                                 send = !qcanread(kbdq);
328                         }else{
329                                 switch(ch){
330                                 case '\b':
331                                         if(kbd.x > 0)
332                                                 kbd.x--;
333                                         break;
334                                 case 0x15:      /* ^U */
335                                         kbd.x = 0;
336                                         break;
337                                 case '\n':
338                                 case 0x04:      /* ^D */
339                                         send = 1;
340                                 default:
341                                         if(ch != 0x04)
342                                                 kbd.line[kbd.x++] = ch;
343                                         break;
344                                 }
345                         }
346                         if(send || kbd.x == sizeof kbd.line){
347                                 qwrite(lineq, kbd.line, kbd.x);
348                                 kbd.x = 0;
349                         }
350                 }
351                 n = qread(lineq, buf, n);
352                 qunlock(&kbd);
353                 poperror();
354                 return n;
355
356         default:
357                 print("consread 0x%llux\n", c->qid.path);
358                 error(Egreg);
359         }
360         return -1;              /* never reached */
361 }
362
363 static long
364 conswrite(Chan *c, void *va, long n, vlong)
365 {
366         Snarf *t;
367         char buf[256], *a;
368         char ch;
369
370         switch((ulong)c->qid.path){
371         case Qcons:
372                 screenputs(va, n);
373                 break;
374
375         case Qconsctl:
376                 if(n >= sizeof(buf))
377                         n = sizeof(buf)-1;
378                 strncpy(buf, va, n);
379                 buf[n] = 0;
380                 for(a = buf; a;){
381                         if(strncmp(a, "rawon", 5) == 0){
382                                 kbd.raw = 1;
383                                 /* clumsy hack - wake up reader */
384                                 ch = 0;
385                                 qwrite(kbdq, &ch, 1);                   
386                         } else if(strncmp(a, "rawoff", 6) == 0){
387                                 kbd.raw = 0;
388                         }
389                         if(a = strchr(a, ' '))
390                                 a++;
391                 }
392                 break;
393
394         case Qsnarf:
395                 t = c->aux;
396                 /* always append only */
397                 if(t->n > MAXSNARF)     /* avoid thrashing when people cut huge text */
398                         error("snarf buffer too big");
399                 a = realloc(t->buf, t->n + n + 1);
400                 if(a == nil)
401                         error("snarf buffer too big");
402                 t->buf = a;
403                 memmove(t->buf+t->n, va, n);
404                 t->n += n;
405                 t->buf[t->n] = '\0';
406                 break;
407         default:
408                 print("conswrite: 0x%llux\n", c->qid.path);
409                 error(Egreg);
410         }
411         return n;
412 }
413
414 Dev consdevtab = {
415         'c',
416         "cons",
417
418         devreset,
419         consinit,
420         consattach,
421         conswalk,
422         consstat,
423         consopen,
424         devcreate,
425         consclose,
426         consread,
427         devbread,
428         conswrite,
429         devbwrite,
430         devremove,
431         devwstat,
432 };