Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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[UTFmax];
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
};