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	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"io.h"
7
#include	"../port/error.h"
8
 
9
#include	"../port/netif.h"
10
 
11
enum
12
{
13
	/* soft flow control chars */
14
	CTLS= 023,
15
	CTLQ= 021,
16
};
17
 
18
extern Dev uartdevtab;
19
extern PhysUart* physuart[];
20
 
21
static Uart* uartlist;
22
static Uart** uart;
23
static int uartnuart;
24
static Dirtab *uartdir;
25
static int uartndir;
26
static Timer *uarttimer;
27
 
28
struct Uartalloc {
29
	Lock;
30
	Uart *elist;	/* list of enabled interfaces */
31
} uartalloc;
32
 
33
static void	uartclock(void);
34
static void	uartflow(void*);
35
 
36
/*
37
 *  enable/disable uart and add/remove to list of enabled uarts
38
 */
39
//static
40
Uart*
41
uartenable(Uart *p)
42
{
43
	Uart **l;
44
 
45
	if (up == nil)
46
		return p;		/* too soon; try again later */
47
//		return nil;
48
 
49
	if(p->iq == nil){
50
		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
51
			return nil;
52
	}
53
	else
54
		qreopen(p->iq);
55
	if(p->oq == nil){
56
		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
57
			qfree(p->iq);
58
			p->iq = nil;
59
			return nil;
60
		}
61
	}
62
	else
63
		qreopen(p->oq);
64
 
65
	p->ir = p->istage;
66
	p->iw = p->istage;
67
	p->ie = &p->istage[Stagesize];
68
	p->op = p->ostage;
69
	p->oe = p->ostage;
70
 
71
	p->hup_dsr = p->hup_dcd = 0;
72
	p->dsr = p->dcd = 0;
73
 
74
	/* assume we can send */
75
	p->cts = 1;
76
	p->ctsbackoff = 0;
77
 
78
	if (up) {
79
		if(p->bits == 0)
80
			uartctl(p, "l8");
81
		if(p->stop == 0)
82
			uartctl(p, "s1");
83
		if(p->parity == 0)
84
			uartctl(p, "pn");
85
		if(p->baud == 0)
86
			uartctl(p, "b9600");
87
		(*p->phys->enable)(p, 1);
88
	}
89
 
90
	/*
91
	 * use ilock because uartclock can otherwise interrupt here
92
	 * and would hang on an attempt to lock uartalloc.
93
	 */
94
	ilock(&uartalloc);
95
	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
96
		if(*l == p)
97
			break;
98
	}
99
	if(*l == 0){
100
		p->elist = uartalloc.elist;
101
		uartalloc.elist = p;
102
	}
103
	p->enabled = 1;
104
	iunlock(&uartalloc);
105
 
106
	return p;
107
}
108
 
109
static void
110
uartdisable(Uart *p)
111
{
112
	Uart **l;
113
 
114
	(*p->phys->disable)(p);
115
 
116
	ilock(&uartalloc);
117
	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
118
		if(*l == p){
119
			*l = p->elist;
120
			break;
121
		}
122
	}
123
	p->enabled = 0;
124
	iunlock(&uartalloc);
125
}
126
 
127
void
128
uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
129
{
130
	qlock(p);
131
	if(p->opens++ == 0 && uartenable(p) == nil){
132
		qunlock(p);
133
		error(Enodev);
134
	}
135
	if(setb1200)
136
		uartctl(p, "b1200");
137
	p->putc = putc;
138
	p->special = 1;
139
	qunlock(p);
140
}
141
 
142
void
143
uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
144
{
145
	qlock(p);
146
	if(p->opens == 0 || p->special == 0){
147
		qunlock(p);
148
		error(Enodev);
149
	}
150
	p->putc = putc;
151
	qunlock(p);
152
}
153
 
154
static void
155
setlength(int i)
156
{
157
	Uart *p;
158
 
159
	if(i > 0){
160
		p = uart[i];
161
		if(p && p->opens && p->iq)
162
			uartdir[1+3*i].length = qlen(p->iq);
163
	} else for(i = 0; i < uartnuart; i++){
164
		p = uart[i];
165
		if(p && p->opens && p->iq)
166
			uartdir[1+3*i].length = qlen(p->iq);
167
	}
168
}
169
 
170
/*
171
 *  set up the '#t' directory
172
 */
173
static void
174
uartreset(void)
175
{
176
	int i;
177
	Dirtab *dp;
178
	Uart *p, *tail;
179
 
180
	tail = nil;
181
	for(i = 0; physuart[i] != nil; i++){
182
		if(physuart[i]->pnp == nil)
183
			continue;
184
		if((p = physuart[i]->pnp()) == nil)
185
			continue;
186
		if(uartlist != nil)
187
			tail->next = p;
188
		else
189
			uartlist = p;
190
		for(tail = p; tail->next != nil; tail = tail->next)
191
			uartnuart++;
192
		uartnuart++;
193
	}
194
 
195
	if(uartnuart)
196
		uart = xalloc(uartnuart*sizeof(Uart*));
197
 
198
	uartndir = 1 + 3*uartnuart;
199
	uartdir = xalloc(uartndir * sizeof(Dirtab));
200
	if (uart == nil || uartdir == nil)
201
		panic("uartreset: no memory");
202
	dp = uartdir;
203
	strcpy(dp->name, ".");
204
	mkqid(&dp->qid, 0, 0, QTDIR);
205
	dp->length = 0;
206
	dp->perm = DMDIR|0555;
207
	dp++;
208
	p = uartlist;
209
	for(i = 0; i < uartnuart; i++){
210
		/* 3 directory entries per port */
211
		snprint(dp->name, sizeof dp->name, "eia%d", i);
212
		dp->qid.path = NETQID(i, Ndataqid);
213
		dp->perm = 0660;
214
		dp++;
215
		snprint(dp->name, sizeof dp->name, "eia%dctl", i);
216
		dp->qid.path = NETQID(i, Nctlqid);
217
		dp->perm = 0660;
218
		dp++;
219
		snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
220
		dp->qid.path = NETQID(i, Nstatqid);
221
		dp->perm = 0444;
222
		dp++;
223
 
224
		uart[i] = p;
225
		p->dev = i;
226
		if(p->console || p->special){
227
			if(uartenable(p) != nil){
228
				if(p->console && up){
229
					kbdq = p->iq;
230
					serialoq = p->oq;
231
					p->putc = kbdcr2nl;
232
				}
233
				p->opens++;
234
			}
235
		}
236
		p = p->next;
237
	}
238
 
239
	if(uartnuart){
240
		/*
241
		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
242
		 * processing it every 22 ms should be fine.
243
		 */
244
		uarttimer = addclock0link(uartclock, 22);
245
	}
246
}
247
 
248
 
249
static Chan*
250
uartattach(char *spec)
251
{
252
	return devattach('t', spec);
253
}
254
 
255
static Walkqid*
256
uartwalk(Chan *c, Chan *nc, char **name, int nname)
257
{
258
	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
259
}
260
 
261
static int
262
uartstat(Chan *c, uchar *dp, int n)
263
{
264
	if(NETTYPE(c->qid.path) == Ndataqid)
265
		setlength(NETID(c->qid.path));
266
	return devstat(c, dp, n, uartdir, uartndir, devgen);
267
}
268
 
269
static Chan*
270
uartopen(Chan *c, int omode)
271
{
272
	Uart *p;
273
 
274
	c = devopen(c, omode, uartdir, uartndir, devgen);
275
 
276
	switch(NETTYPE(c->qid.path)){
277
	case Nctlqid:
278
	case Ndataqid:
279
		p = uart[NETID(c->qid.path)];
280
		qlock(p);
281
		if(p->opens++ == 0 && uartenable(p) == nil){
282
			qunlock(p);
283
			c->flag &= ~COPEN;
284
			error(Enodev);
285
		}
286
		qunlock(p);
287
		break;
288
	}
289
 
290
	c->iounit = qiomaxatomic;
291
	return c;
292
}
293
 
294
static int
295
uartdrained(void* arg)
296
{
297
	Uart *p;
298
 
299
	p = arg;
300
	return qlen(p->oq) == 0 && p->op == p->oe;
301
}
302
 
303
static void
304
uartdrainoutput(Uart *p)
305
{
306
	if(!p->enabled || up == nil)
307
		return;
308
 
309
	p->drain = 1;
310
	if(waserror()){
311
		p->drain = 0;
312
		nexterror();
313
	}
314
	sleep(&p->r, uartdrained, p);
315
	poperror();
316
}
317
 
318
static void
319
uartclose(Chan *c)
320
{
321
	Uart *p;
322
 
323
	if(c->qid.type & QTDIR)
324
		return;
325
	if((c->flag & COPEN) == 0)
326
		return;
327
	switch(NETTYPE(c->qid.path)){
328
	case Ndataqid:
329
	case Nctlqid:
330
		p = uart[NETID(c->qid.path)];
331
		qlock(p);
332
		if(--(p->opens) == 0){
333
			qclose(p->iq);
334
			ilock(&p->rlock);
335
			p->ir = p->iw = p->istage;
336
			iunlock(&p->rlock);
337
 
338
			/*
339
			 */
340
			qhangup(p->oq, nil);
341
			if(!waserror()){
342
				uartdrainoutput(p);
343
				poperror();
344
			}
345
			qclose(p->oq);
346
			uartdisable(p);
347
			p->dcd = p->dsr = p->dohup = 0;
348
		}
349
		qunlock(p);
350
		break;
351
	}
352
}
353
 
354
static long
355
uartread(Chan *c, void *buf, long n, vlong off)
356
{
357
	Uart *p;
358
	ulong offset = off;
359
 
360
	if(c->qid.type & QTDIR){
361
		setlength(-1);
362
		return devdirread(c, buf, n, uartdir, uartndir, devgen);
363
	}
364
 
365
	p = uart[NETID(c->qid.path)];
366
	switch(NETTYPE(c->qid.path)){
367
	case Ndataqid:
368
		return qread(p->iq, buf, n);
369
	case Nctlqid:
370
		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
371
	case Nstatqid:
372
		return (*p->phys->status)(p, buf, n, offset);
373
	}
374
 
375
	return 0;
376
}
377
 
378
int
379
uartctl(Uart *p, char *cmd)
380
{
381
	char *f[16];
382
	int i, n, nf;
383
 
384
	nf = tokenize(cmd, f, nelem(f));
385
	for(i = 0; i < nf; i++){
386
		if(strncmp(f[i], "break", 5) == 0){
387
			(*p->phys->dobreak)(p, 0);
388
			continue;
389
		}
390
 
391
		n = atoi(f[i]+1);
392
		switch(*f[i]){
393
		case 'B':
394
		case 'b':
395
			uartdrainoutput(p);
396
			if((*p->phys->baud)(p, n) < 0)
397
				return -1;
398
			break;
399
		case 'C':
400
		case 'c':
401
			p->hup_dcd = n;
402
			break;
403
		case 'D':
404
		case 'd':
405
			uartdrainoutput(p);
406
			(*p->phys->dtr)(p, n);
407
			break;
408
		case 'E':
409
		case 'e':
410
			p->hup_dsr = n;
411
			break;
412
		case 'f':
413
		case 'F':
414
			if(p->oq != nil)
415
				qflush(p->oq);
416
			break;
417
		case 'H':
418
		case 'h':
419
			if(p->iq != nil)
420
				qhangup(p->iq, 0);
421
			if(p->oq != nil)
422
				qhangup(p->oq, 0);
423
			break;
424
		case 'i':
425
		case 'I':
426
			uartdrainoutput(p);
427
			(*p->phys->fifo)(p, n);
428
			break;
429
		case 'K':
430
		case 'k':
431
			uartdrainoutput(p);
432
			(*p->phys->dobreak)(p, n);
433
			break;
434
		case 'L':
435
		case 'l':
436
			uartdrainoutput(p);
437
			if((*p->phys->bits)(p, n) < 0)
438
				return -1;
439
			break;
440
		case 'm':
441
		case 'M':
442
			uartdrainoutput(p);
443
			(*p->phys->modemctl)(p, n);
444
			break;
445
		case 'n':
446
		case 'N':
447
			if(p->oq != nil)
448
				qnoblock(p->oq, n);
449
			break;
450
		case 'P':
451
		case 'p':
452
			uartdrainoutput(p);
453
			if((*p->phys->parity)(p, *(f[i]+1)) < 0)
454
				return -1;
455
			break;
456
		case 'Q':
457
		case 'q':
458
			if(p->iq != nil)
459
				qsetlimit(p->iq, n);
460
			if(p->oq != nil)
461
				qsetlimit(p->oq, n);
462
			break;
463
		case 'R':
464
		case 'r':
465
			uartdrainoutput(p);
466
			(*p->phys->rts)(p, n);
467
			break;
468
		case 'S':
469
		case 's':
470
			uartdrainoutput(p);
471
			if((*p->phys->stop)(p, n) < 0)
472
				return -1;
473
			break;
474
		case 'W':
475
		case 'w':
476
			if(uarttimer == nil || n < 1)
477
				return -1;
478
			uarttimer->tns = (vlong)n * 100000LL;
479
			break;
480
		case 'X':
481
		case 'x':
482
			if(p->enabled){
483
				ilock(&p->tlock);
484
				p->xonoff = n;
485
				iunlock(&p->tlock);
486
			}
487
			break;
488
		}
489
	}
490
	return 0;
491
}
492
 
493
static long
494
uartwrite(Chan *c, void *buf, long n, vlong)
495
{
496
	Uart *p;
497
	char *cmd;
498
 
499
	if(c->qid.type & QTDIR)
500
		error(Eperm);
501
 
502
	p = uart[NETID(c->qid.path)];
503
 
504
	switch(NETTYPE(c->qid.path)){
505
	case Ndataqid:
506
		qlock(p);
507
		if(waserror()){
508
			qunlock(p);
509
			nexterror();
510
		}
511
 
512
		n = qwrite(p->oq, buf, n);
513
 
514
		qunlock(p);
515
		poperror();
516
		break;
517
	case Nctlqid:
518
		cmd = malloc(n+1);
519
		memmove(cmd, buf, n);
520
		cmd[n] = 0;
521
		qlock(p);
522
		if(waserror()){
523
			qunlock(p);
524
			free(cmd);
525
			nexterror();
526
		}
527
 
528
		/* let output drain */
529
		if(uartctl(p, cmd) < 0)
530
			error(Ebadarg);
531
 
532
		qunlock(p);
533
		poperror();
534
		free(cmd);
535
		break;
536
	}
537
 
538
	return n;
539
}
540
 
541
static int
542
uartwstat(Chan *c, uchar *dp, int n)
543
{
544
	Dir d;
545
	Dirtab *dt;
546
 
547
	if(!iseve())
548
		error(Eperm);
549
	if(QTDIR & c->qid.type)
550
		error(Eperm);
551
	if(NETTYPE(c->qid.path) == Nstatqid)
552
		error(Eperm);
553
 
554
	dt = &uartdir[1 + 3 * NETID(c->qid.path)];
555
	n = convM2D(dp, n, &d, nil);
556
	if(n == 0)
557
		error(Eshortstat);
558
	if(d.mode != ~0UL)
559
		dt[0].perm = dt[1].perm = d.mode;
560
	return n;
561
}
562
 
563
void
564
uartpower(int on)
565
{
566
	Uart *p;
567
 
568
	for(p = uartlist; p != nil; p = p->next) {
569
		if(p->phys->power)
570
			(*p->phys->power)(p, on);
571
	}
572
}
573
 
574
Dev uartdevtab = {
575
	't',
576
	"uart",
577
 
578
	uartreset,
579
	devinit,
580
	devshutdown,
581
	uartattach,
582
	uartwalk,
583
	uartstat,
584
	uartopen,
585
	devcreate,
586
	uartclose,
587
	uartread,
588
	devbread,
589
	uartwrite,
590
	devbwrite,
591
	devremove,
592
	uartwstat,
593
	uartpower,
594
};
595
 
596
/*
597
 *  restart input if it's off
598
 */
599
static void
600
uartflow(void *v)
601
{
602
	Uart *p;
603
 
604
	p = v;
605
	if(p->modem)
606
		(*p->phys->rts)(p, 1);
607
}
608
 
609
/*
610
 *  put some bytes into the local queue to avoid calling
611
 *  qconsume for every character
612
 */
613
int
614
uartstageoutput(Uart *p)
615
{
616
	int n;
617
 
618
	n = qconsume(p->oq, p->ostage, Stagesize);
619
	if(n <= 0)
620
//		n = 0;			/* experiment */
621
		return 0;
622
	p->op = p->ostage;
623
	p->oe = p->ostage + n;
624
	return n;
625
}
626
 
627
/*
628
 *  restart output
629
 */
630
void
631
uartkick(void *v)
632
{
633
	Uart *p = v;
634
 
635
	if(p->blocked)
636
		return;
637
 
638
	ilock(&p->tlock);
639
	(*p->phys->kick)(p);
640
	iunlock(&p->tlock);
641
 
642
	if(p->drain && uartdrained(p)){
643
		p->drain = 0;
644
		wakeup(&p->r);
645
	}
646
}
647
 
648
/*
649
 * Move data from the interrupt staging area to
650
 * the input Queue.
651
 */
652
static void
653
uartstageinput(Uart *p)
654
{
655
	int n;
656
	uchar *ir, *iw;
657
 
658
	while(p->ir != p->iw){
659
		ir = p->ir;
660
		if(p->ir > p->iw){
661
			iw = p->ie;
662
			p->ir = p->istage;
663
		}
664
		else{
665
			iw = p->iw;
666
			p->ir = p->iw;
667
		}
668
		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
669
			p->serr++;
670
			(*p->phys->rts)(p, 0);
671
		}
672
		else if(n == 0)
673
			p->berr++;
674
	}
675
}
676
 
677
/*
678
 *  receive a character at interrupt time
679
 */
680
void
681
uartrecv(Uart *p,  char ch)
682
{
683
	uchar *next;
684
 
685
	/* software flow control */
686
	if(p->xonoff){
687
		if(ch == CTLS){
688
			p->blocked = 1;
689
		}else if(ch == CTLQ){
690
			p->blocked = 0;
691
			p->ctsbackoff = 2; /* clock gets output going again */
692
		}
693
	}
694
 
695
	/* receive the character */
696
	if(p->putc)
697
		p->putc(p->iq, ch);
698
	else if (p->iw) {		/* maybe the line isn't enabled yet */
699
		ilock(&p->rlock);
700
		next = p->iw + 1;
701
		if(next == p->ie)
702
			next = p->istage;
703
		if(next == p->ir)
704
			uartstageinput(p);
705
		if(next != p->ir){
706
			*p->iw = ch;
707
			p->iw = next;
708
		}
709
		iunlock(&p->rlock);
710
	}
711
}
712
 
713
/*
714
 *  we save up input characters till clock time to reduce
715
 *  per character interrupt overhead.
716
 */
717
static void
718
uartclock(void)
719
{
720
	Uart *p;
721
 
722
	ilock(&uartalloc);
723
	for(p = uartalloc.elist; p; p = p->elist){
724
 
725
		/* this hopefully amortizes cost of qproduce to many chars */
726
		if(p->iw != p->ir){
727
			ilock(&p->rlock);
728
			uartstageinput(p);
729
			iunlock(&p->rlock);
730
		}
731
 
732
		/* hang up if requested */
733
		if(p->dohup){
734
			qhangup(p->iq, 0);
735
			qhangup(p->oq, 0);
736
			p->dohup = 0;
737
		}
738
 
739
		/* this adds hysteresis to hardware/software flow control */
740
		if(p->ctsbackoff){
741
			ilock(&p->tlock);
742
			if(p->ctsbackoff){
743
				if(--(p->ctsbackoff) == 0)
744
					(*p->phys->kick)(p);
745
			}
746
			iunlock(&p->tlock);
747
		}
748
		uartkick(p);		/* keep it moving */
749
	}
750
	iunlock(&uartalloc);
751
}
752
 
753
/*
754
 * polling console input, output
755
 */
756
 
757
Uart* consuart;
758
 
759
int
760
uartgetc(void)
761
{
762
	if(consuart == nil || consuart->phys->getc == nil)
763
		return -1;
764
	return consuart->phys->getc(consuart);
765
}
766
 
767
void
768
uartputc(int c)
769
{
770
	char c2;
771
 
772
	if(consuart == nil || consuart->phys->putc == nil) {
773
		c2 = c;
774
		if (lprint)
775
			(*lprint)(&c2, 1);
776
		return;
777
	}
778
	consuart->phys->putc(consuart, c);
779
}
780
 
781
void
782
uartputs(char *s, int n)
783
{
784
	char *e;
785
 
786
	if(consuart == nil || consuart->phys->putc == nil) {
787
		if (lprint)
788
			(*lprint)(s, n);
789
		return;
790
	}
791
 
792
	e = s+n;
793
	for(; s<e; s++){
794
		if(*s == '\n')
795
			consuart->phys->putc(consuart, '\r');
796
		consuart->phys->putc(consuart, *s);
797
	}
798
}