xref: /inferno-os/os/mpc/devuart.c (revision b43c1ca5eb5fc65b93ae935a568432712797b049)
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 	Nbuf=	2,	/* double buffered */
13 	Rbufsize=	512,
14 	Bufsize=	(Rbufsize+CACHELINESZ-1)&~(CACHELINESZ-1),
15 	Nuart=	2+4,	/* max in any 8xx architecture (2xSMC, 4xSCC) */
16 	CTLS=	's'&037,
17 	CTLQ=	'q'&037,
18 };
19 
20 enum {
21 	/* status bits in SCC receive buffer descriptors */
22 	RxBRK=	1<<7,	/* break ended frame (async hdlc) */
23 	RxDE=	1<<7,	/* DPLL error (hdlc) */
24 	RxBOF=	1<<6,	/* BOF ended frame (async hdlc) */
25 	RxLG=	1<<5,	/* frame too large (hdlc) */
26 	RxNO=	1<<4,	/* bad bit alignment (hdlc) */
27 	RxBR=	1<<5,	/* break received during frame (uart) */
28 	RxFR=	1<<4,	/* framing error (uart) */
29 	RxPR=	1<<3,	/* parity error (uart) */
30 	RxAB=	1<<3,	/* frame aborted (hdlc, async hdlc) */
31 	RxCR=	1<<2,	/* bad CRC (hdlc, async hdlc) */
32 	RxOV=	1<<1,	/* receiver overrun (all) */
33 	RxCD=	1<<0,	/* CD lost (all) */
34 
35 	/* hdlc-specific Rx/Tx BDs */
36 	TxTC=	1<<10,
37 };
38 
39 /*
40  *  SMC in UART mode
41  */
42 
43 typedef struct Uartsmc Uartsmc;
44 struct Uartsmc {
45 	IOCparam;
46 	ushort	maxidl;
47 	ushort	idlc;
48 	ushort	brkln;
49 	ushort	brkec;
50 	ushort	brkcr;
51 	ushort	rmask;
52 };
53 
54 /*
55  * SCC2 UART parameters
56  */
57 enum {
58 	/* special mode bits */
59 	SccAHDLC = 1<<0,
60 	SccHDLC = 1<<1,
61 	SccIR = 1<<2,
62 	SccPPP = 1<<3,
63 };
64 
65 typedef struct Uartscc Uartscc;
66 struct Uartscc {
67 	SCCparam;
68 	uchar	rsvd[8];
69 	ushort	max_idl;
70 	ushort	idlc;
71 	ushort	brkcr;
72 	ushort	parec;
73 	ushort	frmec;
74 	ushort	nosec;
75 	ushort	brkec;
76 	ushort	brkln;
77 	ushort	uaddr1;
78 	ushort	uaddr2;
79 	ushort	rtemp;
80 	ushort	toseq;
81 	ushort	character[8];
82 	ushort	rccm;
83 	ushort	rccrp;
84 	ushort	rlbc;
85 };
86 
87 typedef struct UartAHDLC UartAHDLC;
88 struct UartAHDLC {
89 	SCCparam;
90 	ulong	rsvd1;
91 	ulong	c_mask;
92 	ulong	c_pres;
93 	ushort	bof;
94 	ushort	eof;
95 	ushort	esc;
96 	ushort	rsvd2[2];
97 	ushort	zero;
98 	ushort	rsvd3;
99 	ushort	rfthr;
100 	ushort	resvd4[2];
101 	ulong	txctl_tbl;
102 	ulong	rxctl_tbl;
103 	ushort	nof;
104 	ushort	rsvd5;
105 };
106 
107 typedef struct UartHDLC UartHDLC;
108 struct UartHDLC {
109 	SCCparam;
110 	ulong	rsvd1;
111 	ulong	c_mask;
112 	ulong	c_pres;
113 	ushort	disfc;
114 	ushort	crcec;
115 	ushort	abtsc;
116 	ushort	nmarc;
117 	ushort	retrc;
118 	ushort	mflr;
119 	ushort	max_cnt;
120 	ushort	rfthr;
121 	ushort	rfcnt;
122 	ushort	hmask;
123 	ushort	haddr[4];
124 	ushort	tmp;
125 	ushort	tmp_mb;
126 };
127 
128 enum {
129 	/* SCC events of possible interest here eventually */
130 	AB=	1<<9,	/* autobaud detected */
131 	GRA= 1<<7,	/* graceful stop completed */
132 	CCR= 1<<3,	/* control character detected */
133 
134 	/* SCC, SMC common interrupt events */
135 	BSY=	1<<2,	/* receive buffer was busy (overrun) */
136 	TXB= 1<<1,	/* block sent */
137 	RXB= 1<<0,	/* block received */
138 
139 	/* SCC events */
140 	TXE = 1<<4,	/* transmission error */
141 	RXF = 1<<3,	/* final block received */
142 
143 	/* gsmr_l */
144 	ENR = 1<<5,	/* enable receiver */
145 	ENT = 1<<4,	/* enable transmitter */
146 
147 	/* port A */
148 	RXD1=	SIBIT(15),
149 	TXD1=	SIBIT(14),
150 
151 	/* port B */
152 	RTS1B=	IBIT(19),
153 
154 	/* port C */
155 	RTS1C=	SIBIT(15),
156 	CTS1=	SIBIT(11),
157 	CD1=	SIBIT(10),
158 };
159 
160 typedef struct Uart Uart;
161 struct Uart
162 {
163 	QLock;
164 
165 	Uart	*elist;		/* next enabled interface */
166 	char	name[KNAMELEN];
167 
168 	int	x;		/* index: x in SMCx or SCCx */
169 	int	cpmid;		/* eg, SCC1ID, SMC1ID */
170 	CPMdev*	cpm;
171 	int	opens;
172 	uchar	bpc;	/* bits/char */
173 	uchar	parity;
174 	uchar	stopb;
175 	uchar	setup;
176 	uchar	enabled;
177 	int	dev;
178 
179 	ulong	frame;		/* framing errors */
180 	ulong	perror;
181 	ulong	overrun;	/* rcvr overruns */
182 	ulong	crcerr;
183 	ulong	interrupts;
184 	int	baud;		/* baud rate */
185 
186 	/* flow control */
187 	int	xonoff;		/* software flow control on */
188 	int	blocked;
189 	int	modem;		/* hardware flow control on */
190 	int	cts;		/* ... cts state */
191 	int	rts;		/* ... rts state */
192 	Rendez	r;
193 
194 	/* buffers */
195 	int	(*putc)(Queue*, int);
196 	Queue	*iq;
197 	Queue	*oq;
198 
199 	/* staging areas to avoid some of the per character costs */
200 	/* TO DO: should probably use usual Ring */
201 	Block*	istage[Nbuf];	/* double buffered */
202 	int	rdrx;	/* last buffer read */
203 
204 	Lock	plock;		/* for output variables */
205 	Block*	outb;	/* currently transmitting Block */
206 
207 	BD*	rxb;
208 	BD*	txb;
209 
210 	SMC*	smc;
211 	SCC*	scc;
212 	IOCparam*	param;
213 	ushort*	brkcr;	/* brkcr location in appropriate block */
214 	int	brgc;
215 	int	mode;
216 	Block*	partial;
217 	int	loopback;
218 };
219 
220 static Uart *uart[Nuart];
221 static int nuart;
222 
223 struct Uartalloc {
224 	Lock;
225 	Uart *elist;	/* list of enabled interfaces */
226 } uartalloc;
227 
228 static void uartintr(Uart*, int);
229 static void smcuintr(Ureg*, void*);
230 static void sccuintr(Ureg*, void*);
231 
232 static void
233 uartsetbuf(Uart *up)
234 {
235 	IOCparam *p;
236 	BD *bd;
237 	int i;
238 	Block *bp;
239 
240 	p = up->param;
241 	p->rfcr = 0x18;
242 	p->tfcr = 0x18;
243 	p->mrblr = Rbufsize;
244 
245 	if((bd = up->rxb) == nil){
246 		bd = bdalloc(Nbuf);
247 		up->rxb = bd;
248 	}
249 	p->rbase = (ushort)bd;
250 	for(i=0; i<Nbuf; i++){
251 		bd->status = BDEmpty|BDInt;
252 		bd->length = 0;
253 		if((bp = up->istage[i]) == nil)
254 			up->istage[i] = bp = allocb(Bufsize);
255 		bd->addr = PADDR(bp->wp);
256 		dcflush(bp->wp, Bufsize);
257 		bd++;
258 	}
259 	(bd-1)->status |= BDWrap;
260 	up->rdrx = 0;
261 
262 	if((bd = up->txb) == nil){
263 		bd = bdalloc(1);
264 		up->txb = bd;
265 	}
266 	p->tbase = (ushort)bd;
267 	bd->status = BDWrap|BDInt;
268 	bd->length = 0;
269 	bd->addr = 0;
270 }
271 
272 static void
273 smcsetup(Uart *up)
274 {
275 	IMM *io;
276 	Uartsmc *p;
277 	SMC *smc;
278 	ulong txrx;
279 
280 	archdisableuart(up->cpmid);
281 	up->brgc = brgalloc();
282 	if(up->brgc < 0)
283 		error(Eio);
284 	m->iomem->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;
285 	smcnmsi(up->x, up->brgc);
286 
287 	archenableuart(up->cpmid, 0);
288 
289 	if(up->x == 1)
290 		txrx = IBIT(24)|IBIT(25);	/* SMC1 RX/TX */
291 	else
292 		txrx = IBIT(20)|IBIT(21);	/* SMC2 */
293 	io = ioplock();
294 	io->pbpar |= txrx;
295 	io->pbdir &= ~txrx;
296 	iopunlock();
297 
298 	up->param = up->cpm->param;
299 	uartsetbuf(up);
300 
301 	cpmop(up->cpm, InitRxTx, 0);
302 
303 	/* SMC protocol parameters */
304 	p = (Uartsmc*)up->param;
305 	up->brkcr = &p->brkcr;
306 	p->maxidl = 1;	/* non-zero so buffer closes when idle before mrblr reached */
307 	p->brkln = 0;
308 	p->brkec = 0;
309 	p->brkcr = 1;
310 	smc = up->cpm->regs;
311 	smc->smce = 0xff;	/* clear events */
312 	smc->smcm = BSY|RXB|TXB;	/* enable all possible interrupts */
313 	up->smc = smc;
314 	smc->smcmr = ((1+8+1-1)<<11)|(2<<4);	/* 8-bit, 1 stop, no parity; UART mode */
315 	intrenable(VectorCPIC+up->cpm->irq, smcuintr, up, BUSUNKNOWN, up->name);
316 	/* enable when device opened */
317 }
318 
319 static void
320 smcuintr(Ureg*, void *a)
321 {
322 	Uart *up;
323 	int events;
324 
325 	up = a;
326 	events = up->smc->smce;
327 	eieio();
328 	up->smc->smce = events;
329 	uartintr(up, events&(BSY|RXB|TXB));
330 }
331 
332 /*
333  * set the IO ports to enable the control signals for SCCx
334  */
335 static void
336 sccuartpins(int x, int mode)
337 {
338 	IMM *io;
339 	int i, w;
340 
341 	x--;
342 	io = ioplock();
343 	i = 2*x;
344 	w = (TXD1|RXD1)<<i;	/* TXDn and RXDn in port A */
345 	io->papar |= w;	/* enable TXDn and RXDn pins */
346 	io->padir &= ~w;
347 	if((mode & SccIR) == 0)
348 		io->paodr |= TXD1<<i;
349 	else
350 		io->paodr &= ~w;	/* not open drain */
351 
352 	w = (CD1|CTS1)<<i;	/* CDn and CTSn in port C */
353 	io->pcpar &= ~w;
354 	io->pcdir &= ~w;
355 	if(conf.nocts2 || mode)
356 		io->pcso &= ~w;	/* force CTS and CD on */
357 	else
358 		io->pcso |= w;
359 
360 	w = RTS1B<<x;
361 	io->pbpar &= ~w;
362 	io->pbdir &= ~w;
363 
364 	w = RTS1C<<x;	/* RTSn~ */
365 	if((mode & SccIR) == 0)
366 		io->pcpar |= w;
367 	else
368 		io->pcpar &= ~w;	/* don't use for IR */
369 	iopunlock();
370 }
371 
372 static void
373 sccsetup(Uart *up)
374 {
375 	SCC *scc;
376 	int i;
377 
378 	scc = up->cpm->regs;
379 	up->scc = scc;
380 	up->param = up->cpm->param;
381 	sccxstop(up->cpm);
382 	archdisableuart(up->cpmid);
383 	if(up->brgc < 0){
384 		up->brgc = brgalloc();
385 		if(up->brgc < 0)
386 			error(Eio);
387 	}
388 	m->iomem->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;
389 	sccnmsi(up->x, up->brgc, up->brgc);
390 	sccuartpins(up->x, up->mode);
391 
392 	uartsetbuf(up);
393 
394 	cpmop(up->cpm, InitRxTx, 0);
395 
396 	/* SCC protocol parameters */
397 	if((up->mode & (SccAHDLC|SccHDLC)) == 0){
398 		Uartscc *sp;
399 		sp = (Uartscc*)up->param;
400 		sp->max_idl = 1;
401 		sp->brkcr = 1;
402 		sp->parec = 0;
403 		sp->frmec = 0;
404 		sp->nosec = 0;
405 		sp->brkec = 0;
406 		sp->brkln = 0;
407 		sp->brkec = 0;
408 		sp->uaddr1 = 0;
409 		sp->uaddr2 = 0;
410 		sp->toseq = 0;
411 		for(i=0; i<8; i++)
412 			sp->character[i] = 0x8000;
413 		sp->rccm = 0xC0FF;
414 		up->brkcr = &sp->brkcr;
415 		scc->irmode = 0;
416 		scc->dsr = ~0;
417 		scc->gsmrh = 1<<5;	/* 8-bit oriented receive fifo */
418 		scc->gsmrl = 0x28004;	/* UART mode */
419 	}else{
420 		UartAHDLC *hp;
421 		hp = (UartAHDLC*)up->param;
422 		hp->c_mask = 0x0000F0B8;
423 		hp->c_pres = 0x0000FFFF;
424 		if(up->mode & SccIR){
425 			hp->bof = 0xC0;
426 			hp->eof = 0xC1;
427 			//scc->dsr = 0xC0C0;
428 			scc->dsr = 0x7E7E;
429 		}else{
430 			hp->bof = 0x7E;
431 			hp->eof = 0x7E;
432 			scc->dsr = 0x7E7E;
433 		}
434 		hp->esc = 0x7D;
435 		hp->zero = 0;
436 		if(up->mode & SccHDLC)
437 			hp->rfthr = 1;
438 		else
439 			hp->rfthr = 0;	/* receive threshold of 1 doesn't work properly for Async HDLC */
440 		hp->txctl_tbl = 0;
441 		hp->rxctl_tbl = 0;
442 		if(up->mode & SccIR){
443 			/* low-speed infrared */
444 			hp->nof = 12-1;	/* 12 flags */
445 			scc->irsip = 0;
446 			scc->irmode = (2<<8) | 1;
447 			archsetirxcvr(0);
448 			if(up->loopback)
449 				scc->irmode = (3<<4)|1;	/* loopback */
450 		}else{
451 			scc->irmode = 0;
452 			hp->txctl_tbl = ~0;
453 			hp->rxctl_tbl = ~0;
454 			hp->nof = 1-1;	/* one opening flag */
455 		}
456 		up->brkcr = nil;
457 		scc->gsmrh = 1<<5;	/* 8-bit oriented receive fifo */
458 		if(up->mode & SccHDLC)
459 			scc->gsmrl = 0x28000;	/* HDLC */
460 		else
461 			scc->gsmrl = 0x28006;	/* async HDLC/IrDA */
462 	}
463 	archenableuart(up->cpmid, (up->mode&SccIR)!=0);
464 	scc->scce = ~0;	/* clear events */
465 	scc->sccm = TXE|BSY|RXF|TXB|RXB;	/* enable all interesting interrupts */
466 	intrenable(VectorCPIC+up->cpm->irq, sccuintr, up, BUSUNKNOWN, up->name);
467 	scc->psmr = 3<<12;	/* 8-bit, 1 stop, no parity; UART mode */
468 	if(up->loopback && (up->mode & SccIR) == 0)
469 		scc->gsmrl |= 1<<6;	/* internal loop back */
470 	scc->gsmrl |= ENT|ENR;	/* enable rx/tx */
471 	if(0){
472 		print("gsmrl=%8.8lux gsmrh=%8.8lux dsr=%4.4ux irmode=%4.4ux\n", scc->gsmrl, scc->gsmrh, scc->dsr, scc->irmode);
473 		for(i=0; i<sizeof(Uartscc); i+=4)
474 			print("%2.2ux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));
475 	}
476 }
477 
478 static void
479 sccuintr(Ureg*, void *a)
480 {
481 	Uart *up;
482 	int events;
483 
484 	up = a;
485 	if(up->scc == nil)
486 		return;
487 	events = up->scc->scce;
488 	eieio();
489 	up->scc->scce = events;
490 	if(up->enabled){
491 		if(0)
492 			print("#%ux|", events);
493 		uartintr(up, events);
494 	}
495 }
496 
497 static void
498 uartsetbaud(Uart *p, int rate)
499 {
500 	if(rate <= 0 || p->brgc < 0)
501 		return;
502 	p->baud = rate;
503 	m->iomem->brgc[p->brgc] = baudgen(rate, 16) | BaudEnable;
504 }
505 
506 static void
507 uartsetmode(Uart *p)
508 {
509 	int r, clen;
510 
511 	ilock(&p->plock);
512 	clen = p->bpc;
513 	if(p->parity == 'e' || p->parity == 'o')
514 		clen++;
515 	clen++;	/* stop bit */
516 	if(p->stopb == 2)
517 		clen++;
518 	if(p->smc){
519 		r = p->smc->smcmr & 0x3F;	/* keep mode, enable bits */
520 		r |= (clen<<11);
521 		if(p->parity == 'e')
522 			r |= 3<<8;
523 		else if(p->parity == 'o')
524 			r |= 2<<8;
525 		if(p->stopb == 2)
526 			r |= 1<<10;
527 		eieio();
528 		p->smc->smcmr = r;
529 	}else if(p->scc && p->mode == 0){
530 		r = p->scc->psmr & 0x8FE0;	/* keep mode bits */
531 		r |= ((p->bpc-5)&3)<<12;
532 		if(p->parity == 'e')
533 			r |= (6<<2)|2;
534 		else if(p->parity == 'o')
535 			r |= (4<<2)|0;
536 		if(p->stopb == 2)
537 			r |= 1<<14;
538 		eieio();
539 		p->scc->psmr = r;
540 	}
541 	iunlock(&p->plock);
542 }
543 
544 static void
545 uartparity(Uart *p, char type)
546 {
547 	ilock(&p->plock);
548 	p->parity = type;
549 	iunlock(&p->plock);
550 	uartsetmode(p);
551 }
552 
553 /*
554  *  set bits/character
555  */
556 static void
557 uartbits(Uart *p, int bits)
558 {
559 	if(bits < 5 || bits > 14 || bits > 8 && p->scc)
560 		error(Ebadarg);
561 
562 	ilock(&p->plock);
563 	p->bpc = bits;
564 	iunlock(&p->plock);
565 	uartsetmode(p);
566 }
567 
568 
569 /*
570  *  toggle DTR
571  */
572 static void
573 uartdtr(Uart *p, int n)
574 {
575 	if(p->scc == nil)
576 		return;	/* not possible */
577 	USED(n);	/* not possible on FADS */
578 }
579 
580 /*
581  *  toggle RTS
582  */
583 static void
584 uartrts(Uart *p, int n)
585 {
586 	p->rts = n;
587 	if(p->scc == nil)
588 		return;	/* not possible */
589 	USED(n);	/* not possible on FADS */
590 }
591 
592 /*
593  *  send break
594  */
595 static void
596 uartbreak(Uart *p, int ms)
597 {
598 	if(p->brkcr == nil)
599 		return;
600 
601 	if(ms <= 0)
602 		ms = 200;
603 
604 	if(waserror()){
605 		ilock(&p->plock);
606 		*p->brkcr = 1;
607 		cpmop(p->cpm, RestartTx, 0);
608 		iunlock(&p->plock);
609 		nexterror();
610 	}
611 	ilock(&p->plock);
612 	*p->brkcr = ((p->baud/(p->bpc+2))*ms+500)/1000;
613 	cpmop(p->cpm, StopTx, 0);
614 	iunlock(&p->plock);
615 
616 	tsleep(&up->sleep, return0, 0, ms);
617 
618 	poperror();
619 	ilock(&p->plock);
620 	*p->brkcr = 1;
621 	cpmop(p->cpm, RestartTx, 0);
622 	iunlock(&p->plock);
623 }
624 
625 /*
626  *  modem flow control on/off (rts/cts)
627  */
628 static void
629 uartmflow(Uart *p, int n)
630 {
631 	if(p->scc == nil)
632 		return;	/* not possible */
633 	if(n){
634 		p->modem = 1;
635 		/* enable status interrupts ... */
636 		p->scc->psmr |= 1<<15;	/* enable async flow control */
637 		p->cts = 1;
638 		/* could change maxidl */
639 	}else{
640 		p->modem = 0;
641 		/* stop status interrupts ... */
642 		p->scc->psmr &= ~(1<<15);
643 		p->cts = 1;
644 	}
645 }
646 
647 /*
648  *  turn on a port's interrupts.  set DTR and RTS
649  */
650 void
651 uartenable(Uart *p)
652 {
653 	Uart **l;
654 
655 	if(p->enabled)
656 		return;
657 
658 	if(p->setup == 0){
659 		if(p->cpmid == CPsmc1 || p->cpmid == CPsmc2)
660 			smcsetup(p);
661 		else
662 			sccsetup(p);
663 		p->setup = 1;
664 	}
665 
666 	/*
667  	 *  turn on interrupts
668 	 */
669 	if(p->smc){
670 		cpmop(p->cpm, RestartTx, 0);
671 		p->smc->smcmr |= 3;
672 		p->smc->smcm = BSY|TXB|RXB;
673 		eieio();
674 	}else if(p->scc){
675 		cpmop(p->cpm, RestartTx, 0);
676 		p->scc->gsmrl |= ENT|ENR;
677 		p->scc->sccm = BSY|TXB|RXB;
678 		eieio();
679 	}
680 
681 	/*
682 	 *  turn on DTR and RTS
683 	 */
684 	uartdtr(p, 1);
685 	uartrts(p, 1);
686 
687 	/*
688 	 *  assume we can send
689 	 */
690 	p->cts = 1;
691 	p->blocked = 0;
692 
693 	/*
694 	 *  set baud rate to the last used
695 	 */
696 	uartsetbaud(p, p->baud);
697 
698 	lock(&uartalloc);
699 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
700 		if(*l == p)
701 			break;
702 	}
703 	if(*l == 0){
704 		p->elist = uartalloc.elist;
705 		uartalloc.elist = p;
706 	}
707 	p->enabled = 1;
708 	unlock(&uartalloc);
709 	p->cts = 1;
710 	p->blocked = 0;
711 	p->xonoff = 0;
712 	p->enabled = 1;
713 }
714 
715 /*
716  *  turn off a port's interrupts.  reset DTR and RTS
717  */
718 void
719 uartdisable(Uart *p)
720 {
721 	Uart **l;
722 
723 	/*
724  	 *  turn off interrpts
725 	 */
726 	if(p->smc)
727 		smcxstop(p->cpm);
728 	else if(p->scc)
729 		sccxstop(p->cpm);
730 
731 	/*
732 	 *  revert to default settings
733 	 */
734 	p->bpc = 8;
735 	p->parity = 0;
736 	p->stopb = 0;
737 
738 	/*
739 	 *  turn off DTR, RTS, hardware flow control & fifo's
740 	 */
741 	uartdtr(p, 0);
742 	uartrts(p, 0);
743 	uartmflow(p, 0);
744 	p->xonoff = p->blocked = 0;
745 
746 	lock(&uartalloc);
747 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
748 		if(*l == p){
749 			*l = p->elist;
750 			break;
751 		}
752 	}
753 	p->enabled = 0;
754 	unlock(&uartalloc);
755 }
756 
757 /*
758  *  set the next output buffer going
759  */
760 static void
761 txstart(Uart *p)
762 {
763 	Block *b;
764 	int n, flags;
765 
766 	if(!p->cts || p->blocked || p->txb->status & BDReady)
767 		return;
768 	if((b = p->outb) == nil){
769 		if((b = qget(p->oq)) == nil)
770 			return;
771 		if(p->mode & SccPPP &&
772 		   p->mode & SccAHDLC &&
773 		   BLEN(b) >= 8){	/* strip framing data */
774 			UartAHDLC *hp;
775 			hp = (UartAHDLC*)p->param;
776 			if(hp != nil && (p->mode & SccIR) == 0){
777 				hp->txctl_tbl = nhgetl(b->rp);
778 				hp->rxctl_tbl = nhgetl(b->rp+4);
779 			}
780 			b->rp += 8;
781 			if(0)
782 				print("tx #%lux rx #%lux\n", hp->txctl_tbl, hp->rxctl_tbl);
783 		}
784 	}
785 	n = BLEN(b);
786 	if(n <= 0)
787 		print("txstart: 0\n");
788 	if(p->bpc > 8){
789 		/* half-word alignment and length if chars are long */
790 		if(PADDR(b->rp)&1){	/* must be even if chars are long */
791 			memmove(b->base, b->rp, n);
792 			b->rp = b->base;
793 			b->wp = b->rp+n;
794 		}
795 		if(n & 1)
796 			n++;
797 	}
798 	dcflush(b->rp, n);
799 	p->outb = b;
800 	if(n > 0xFFFF)
801 		n = 0xFFFE;
802 	if(p->mode & SccHDLC)
803 		flags = BDLast | TxTC;
804 	else if(p->mode)
805 		flags = BDLast;
806 	else
807 		flags = 0;
808 	p->txb->addr = PADDR(b->rp);
809 	p->txb->length = n;
810 	eieio();
811 	p->txb->status = (p->txb->status & BDWrap) | flags | BDReady|BDInt;
812 	eieio();
813 }
814 
815 /*
816  *  (re)start output
817  */
818 static void
819 uartkick(void *v)
820 {
821 	Uart *p;
822 
823 	p = v;
824 	ilock(&p->plock);
825 	if(p->outb == nil)
826 		txstart(p);
827 	iunlock(&p->plock);
828 }
829 
830 /*
831  *  restart input if it's off
832  */
833 static void
834 uartflow(void *v)
835 {
836 	Uart *p;
837 
838 	p = v;
839 	if(p->modem)
840 		uartrts(p, 1);
841 }
842 
843 static void
844 uartsetup(int x, int lid, char *name)
845 {
846 	Uart *p;
847 
848 	if(nuart >= Nuart)
849 		return;
850 
851 	p = xalloc(sizeof(Uart));
852 	uart[nuart] = p;
853 	strcpy(p->name, name);
854 	p->dev = nuart;
855 	nuart++;
856 	p->x = x;
857 	p->cpmid = lid;
858 	p->cpm = cpmdev(lid);
859 	p->brgc = -1;
860 	p->mode = 0;
861 
862 	/*
863 	 *  set rate to 9600 baud.
864 	 *  8 bits/character.
865 	 *  1 stop bit.
866 	 *  interrupts enabled.
867 	 */
868 	p->bpc = 8;
869 	p->parity = 0;
870 	p->baud = 9600;
871 
872 	p->iq = qopen(4*1024, Qcoalesce, uartflow, p);
873 	p->oq = qopen(4*1024, 0, uartkick, p);
874 }
875 
876 /*
877  *  called by main() to configure a duart port as a console or a mouse
878  */
879 void
880 uartspecial(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int))
881 {
882 	Uart *p;
883 
884 	if(port < 0 || port >= nuart || (p = uart[port]) == nil)
885 		return;	/* specified port not implemented */
886 	uartenable(p);
887 	if(baud)
888 		uartsetbaud(p, baud);
889 	p->putc = putc;
890 	if(in)
891 		*in = p->iq;
892 	if(out)
893 		*out = p->oq;
894 	p->opens++;
895 }
896 
897 static int
898 uartinput(Uart *p, BD *bd)
899 {
900 	int ch, dokick, i, l;
901 	uchar *bp;
902 
903 	dokick = 0;
904 	if(bd->status & RxFR)
905 		p->frame++;
906 	if(bd->status & RxOV)
907 		p->overrun++;
908 	l = bd->length;
909 	if(bd->status & RxPR){
910 		p->perror++;
911 		l--;	/* it's the last character */
912 	}
913 	bp = KADDR(bd->addr);
914 	if(p->xonoff || p->putc && p->opens==1){
915 		for(i=0; i<l; i++){
916 			ch = bp[i];
917 			if(p->xonoff){
918 				if(ch == CTLS){
919 					p->blocked = 1;
920 					cpmop(p->cpm, StopTx, 0);
921 				}else if (ch == CTLQ){
922 					p->blocked = 0;
923 					dokick = 1;
924 				}
925 				/* BUG? should discard on/off char? */
926 			}
927 			if(p->putc)
928 				(*p->putc)(p->iq, ch);
929 		}
930 	}
931 	if(l > 0 && (p->putc == nil || p->opens>1))
932 		qproduce(p->iq, bp, l);
933 	return dokick;
934 }
935 
936 static void
937 framedinput(Uart *p, BD *bd)
938 {
939 	Block *pkt;
940 	int l;
941 
942 	pkt = p->partial;
943 	p->partial = nil;
944 	if(bd->status & RxOV){
945 		p->overrun++;
946 		goto Discard;
947 	}
948 	if(bd->status & (RxAB|RxCR|RxCD|RxLG|RxNO|RxDE|RxBOF|RxBRK)){
949 		if(bd->status & RxCR)
950 			p->crcerr++;
951 		else
952 			p->frame++;
953 		goto Discard;
954 	}
955 	if(pkt == nil){
956 		pkt = iallocb(1500);	/* TO DO: allocate less if possible */
957 		if(pkt == nil)
958 			return;
959 	}
960 	l = bd->length;
961 	if(bd->status & BDLast)
962 		l -= BLEN(pkt);	/* last one gives size of entire frame */
963 	if(l > 0){
964 		if(pkt->wp+l > pkt->lim)
965 			goto Discard;
966 		memmove(pkt->wp, KADDR(bd->addr), l);
967 		pkt->wp += l;
968 	}
969 	if(0)
970 		print("#%ux|", bd->status);
971 	if(bd->status & BDLast){
972 		if(p->mode & (SccHDLC|SccAHDLC)){
973 			if(BLEN(pkt) <= 2){
974 				p->frame++;
975 				goto Discard;
976 			}
977 			pkt->wp -= 2;	/* strip CRC */
978 		}
979 		qpass(p->iq, pkt);
980 	}else
981 		p->partial = pkt;
982 	return;
983 
984 Discard:
985 	if(pkt != nil)
986 		freeb(pkt);
987 }
988 
989 /*
990  *  handle an interrupt to a single uart
991  */
992 static void
993 uartintr(Uart *p, int events)
994 {
995 	int dokick;
996 	BD *bd;
997 	Block *b;
998 
999 	if(events & BSY)
1000 		p->overrun++;
1001 	p->interrupts++;
1002 	dokick = 0;
1003 	while(p->rxb != nil && ((bd = &p->rxb[p->rdrx])->status & BDEmpty) == 0){
1004 		dcinval(KADDR(bd->addr), bd->length);
1005 		if(p->mode)
1006 			framedinput(p, bd);
1007 		else if(uartinput(p, bd))
1008 			dokick = 1;
1009 		bd->status = (bd->status & BDWrap) | BDEmpty|BDInt;
1010 		eieio();
1011 		if(++p->rdrx >= Nbuf)
1012 			p->rdrx = 0;
1013 	}
1014 	if((bd = p->txb) != nil){
1015 		if((bd->status & BDReady) == 0){
1016 			ilock(&p->plock);
1017 			if((b = p->outb) != nil){
1018 				b->rp += bd->length;
1019 				if(b->rp >= b->wp){
1020 					p->outb = nil;
1021 					freeb(b);
1022 				}
1023 			}
1024 			txstart(p);
1025 			iunlock(&p->plock);
1026 		}
1027 	}
1028 	eieio();
1029 	/* TO DO: modem status isn't available on 82xFADS */
1030 	if(dokick && p->cts && !p->blocked){
1031 		if(p->outb == nil){
1032 			ilock(&p->plock);
1033 			txstart(p);
1034 			iunlock(&p->plock);
1035 		}
1036 		cpmop(p->cpm, RestartTx, 0);
1037 	} else if (events & TXE)
1038 		cpmop(p->cpm, RestartTx, 0);
1039 }
1040 
1041 /*
1042  * used to ensure uart console output when debugging
1043  */
1044 void
1045 uartwait(void)
1046 {
1047 	Uart *p = uart[0];
1048 	int s;
1049 
1050 	while(p && (p->outb||qlen(p->oq))){
1051 		if(islo())
1052 			continue;
1053 		s = splhi();
1054 		if((p->txb->status & BDReady) == 0){
1055 			p->blocked = 0;
1056 			p->cts = 1;
1057 			if(p->scc == nil)
1058 				smcuintr(nil, p);
1059 			else
1060 				sccuintr(nil, p);
1061 		}
1062 		splx(s);
1063 	}
1064 }
1065 
1066 static Dirtab *uartdir;
1067 static int ndir;
1068 
1069 static void
1070 setlength(int i)
1071 {
1072 	Uart *p;
1073 
1074 	if(i >= 0){
1075 		p = uart[i];
1076 		if(p && p->opens && p->iq)
1077 			uartdir[1+4*i].length = qlen(p->iq);
1078 	} else for(i = 0; i < nuart; i++){
1079 		p = uart[i];
1080 		if(p && p->opens && p->iq)
1081 			uartdir[1+4*i].length = qlen(p->iq);
1082 	}
1083 
1084 }
1085 
1086 void
1087 uartinstall(void)
1088 {
1089 	static int already;
1090 	int i, n;
1091 	char name[2*KNAMELEN];
1092 	if(already)
1093 		return;
1094 	already = 1;
1095 	n = 0;
1096 	for(i=0; i<2; i++)
1097 		if(conf.smcuarts & (1<<i)){
1098 			snprint(name, sizeof(name), "eia%d", n++);
1099 			uartsetup(i+1, CPsmc1+i, name);
1100 		}
1101 	n = 2;
1102 	for(i=0; i<conf.nscc; i++)
1103 		if(conf.sccuarts & (1<<i)){
1104 			snprint(name, sizeof(name), "eia%d", n++);
1105 			uartsetup(i+1, CPscc1+i, name);
1106 		}
1107 }
1108 
1109 /*
1110  *  all uarts must be uartsetup() by this point or inside of uartinstall()
1111  */
1112 static void
1113 uartreset(void)
1114 {
1115 	int i;
1116 	Dirtab *dp;
1117 
1118 	uartinstall();	/* architecture specific */
1119 
1120 	ndir = 1+4*nuart;
1121 	uartdir = xalloc(ndir * sizeof(Dirtab));
1122 	dp = uartdir;
1123 	strcpy(dp->name, ".");
1124 	mkqid(&dp->qid, 0, 0, QTDIR);
1125 	dp->length = 0;
1126 	dp->perm = DMDIR|0555;
1127 	dp++;
1128 	for(i = 0; i < nuart; i++){
1129 		/* 4 directory entries per port */
1130 		strcpy(dp->name, uart[i]->name);
1131 		dp->qid.path = NETQID(i, Ndataqid);
1132 		dp->perm = 0660;
1133 		dp++;
1134 		sprint(dp->name, "%sctl", uart[i]->name);
1135 		dp->qid.path = NETQID(i, Nctlqid);
1136 		dp->perm = 0660;
1137 		dp++;
1138 		sprint(dp->name, "%sstatus", uart[i]->name);
1139 		dp->qid.path = NETQID(i, Nstatqid);
1140 		dp->perm = 0444;
1141 		dp++;
1142 		sprint(dp->name, "%smode", uart[i]->name);
1143 		dp->qid.path = NETQID(i, Ntypeqid);
1144 		dp->perm = 0660;
1145 		dp++;
1146 	}
1147 }
1148 
1149 static Chan*
1150 uartattach(char *spec)
1151 {
1152 	return devattach('t', spec);
1153 }
1154 
1155 static Walkqid*
1156 uartwalk(Chan *c, Chan *nc, char **name, int nname)
1157 {
1158 	return devwalk(c, nc, name, nname, uartdir, ndir, devgen);
1159 }
1160 
1161 static int
1162 uartstat(Chan *c, uchar *dp, int n)
1163 {
1164 	if(NETTYPE(c->qid.path) == Ndataqid)
1165 		setlength(NETID(c->qid.path));
1166 	return devstat(c, dp, n, uartdir, ndir, devgen);
1167 }
1168 
1169 static Chan*
1170 uartopen(Chan *c, int omode)
1171 {
1172 	Uart *p;
1173 
1174 	c = devopen(c, omode, uartdir, ndir, devgen);
1175 
1176 	switch(NETTYPE(c->qid.path)){
1177 	case Nctlqid:
1178 	case Ndataqid:
1179 		p = uart[NETID(c->qid.path)];
1180 		qlock(p);
1181 		if(p->opens++ == 0){
1182 			uartenable(p);
1183 			qreopen(p->iq);
1184 			qreopen(p->oq);
1185 		}
1186 		qunlock(p);
1187 		break;
1188 	}
1189 
1190 	return c;
1191 }
1192 
1193 static void
1194 uartclose(Chan *c)
1195 {
1196 	Uart *p;
1197 
1198 	if(c->qid.type & QTDIR)
1199 		return;
1200 	if((c->flag & COPEN) == 0)
1201 		return;
1202 	switch(NETTYPE(c->qid.path)){
1203 	case Ndataqid:
1204 	case Nctlqid:
1205 		p = uart[NETID(c->qid.path)];
1206 		qlock(p);
1207 		if(--(p->opens) == 0){
1208 			uartdisable(p);
1209 			qclose(p->iq);
1210 			qclose(p->oq);
1211 		}
1212 		qunlock(p);
1213 		break;
1214 	}
1215 }
1216 
1217 static long
1218 uartstatus(Chan*, Uart *p, void *buf, long n, long offset)
1219 {
1220 	IMM *io;
1221 	char str[256];
1222 
1223 // TO DO: change to standard format for first line:
1224 //"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
1225 	sprint(str, "opens %d ferr %lud oerr %lud crcerr %lud baud %ud perr %lud intr %lud", p->opens,
1226 		p->frame, p->overrun, p->crcerr, p->baud, p->perror, p->interrupts);
1227 	/* TO DO: cts, dsr, ring, dcd, dtr, rts aren't all available on 82xFADS */
1228 	io = m->iomem;
1229 	if(p->scc){
1230 		if((io->pcdat & SIBIT(9)) == 0)
1231 			strcat(str, " cts");
1232 		if((io->pcdat & SIBIT(8)) == 0)
1233 			strcat(str, " dcd");
1234 		if((io->pbdat & IBIT(22)) == 0)
1235 			strcat(str, " dtr");
1236 	}else if(p->smc){
1237 		if((io->pbdat & IBIT(23)) == 0)
1238 			strcat(str, " dtr");
1239 	}
1240 	strcat(str, "\n");
1241 	return readstr(offset, buf, n, str);
1242 }
1243 
1244 static long
1245 uartread(Chan *c, void *buf, long n, vlong offset)
1246 {
1247 	Uart *p;
1248 
1249 	if(c->qid.type & QTDIR){
1250 		setlength(-1);
1251 		return devdirread(c, buf, n, uartdir, ndir, devgen);
1252 	}
1253 
1254 	p = uart[NETID(c->qid.path)];
1255 	switch(NETTYPE(c->qid.path)){
1256 	case Ndataqid:
1257 		return qread(p->iq, buf, n);
1258 	case Nctlqid:
1259 		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
1260 	case Nstatqid:
1261 		return uartstatus(c, p, buf, n, offset);
1262 	case Ntypeqid:
1263 		return readnum(offset, buf, n, p->mode, NUMSIZE);
1264 	}
1265 
1266 	return 0;
1267 }
1268 
1269 static Block*
1270 uartbread(Chan *c, long n, ulong offset)
1271 {
1272 	if(c->qid.type & QTDIR || NETTYPE(c->qid.path) != Ndataqid)
1273 		return devbread(c, n, offset);
1274 	return qbread(uart[NETID(c->qid.path)]->iq, n);
1275 }
1276 
1277 static void
1278 uartctl(Uart *p, char *cmd)
1279 {
1280 	int i, n;
1281 
1282 	/* let output drain for a while */
1283 	for(i = 0; i < 16 && qlen(p->oq); i++)
1284 		tsleep(&p->r, (int(*)(void*))qlen, p->oq, 125);
1285 
1286 	if(strncmp(cmd, "break", 5) == 0){
1287 		uartbreak(p, 0);
1288 		return;
1289 	}
1290 
1291 	n = atoi(cmd+1);
1292 	switch(*cmd){
1293 	case 'B':
1294 	case 'b':
1295 		uartsetbaud(p, n);
1296 		break;
1297 	case 'D':
1298 	case 'd':
1299 		uartdtr(p, n);
1300 		break;
1301 	case 'f':
1302 	case 'F':
1303 		qflush(p->oq);
1304 		break;
1305 	case 'H':
1306 	case 'h':
1307 		qhangup(p->iq, 0);
1308 		qhangup(p->oq, 0);
1309 		break;
1310 	case 'L':
1311 	case 'l':
1312 		uartbits(p, n);
1313 		break;
1314 	case 'm':
1315 	case 'M':
1316 		uartmflow(p, n);
1317 		break;
1318 	case 'n':
1319 	case 'N':
1320 		qnoblock(p->oq, n);
1321 		break;
1322 	case 'P':
1323 	case 'p':
1324 		uartparity(p, *(cmd+1));
1325 		break;
1326 	case 'K':
1327 	case 'k':
1328 		uartbreak(p, n);
1329 		break;
1330 	case 'R':
1331 	case 'r':
1332 		uartrts(p, n);
1333 		break;
1334 	case 'Q':
1335 	case 'q':
1336 		qsetlimit(p->iq, n);
1337 		qsetlimit(p->oq, n);
1338 		break;
1339 	case 'W':
1340 	case 'w':
1341 		/* obsolete */
1342 		break;
1343 	case 'X':
1344 	case 'x':
1345 		p->xonoff = n;
1346 		break;
1347 	case 'Z':
1348 	case 'z':
1349 		p->loopback = n;
1350 		break;
1351 	}
1352 }
1353 
1354 static long
1355 uartwrite(Chan *c, void *buf, long n, vlong offset)
1356 {
1357 	Uart *p;
1358 	char cmd[32];
1359 	int m, inuse;
1360 
1361 	USED(offset);
1362 
1363 	if(c->qid.type & QTDIR)
1364 		error(Eperm);
1365 
1366 	p = uart[NETID(c->qid.path)];
1367 
1368 	switch(NETTYPE(c->qid.path)){
1369 	case Ndataqid:
1370 		return qwrite(p->oq, buf, n);
1371 	case Nctlqid:
1372 		if(n >= sizeof(cmd))
1373 			n = sizeof(cmd)-1;
1374 		memmove(cmd, buf, n);
1375 		cmd[n] = 0;
1376 		uartctl(p, cmd);
1377 		return n;
1378 	case Ntypeqid:
1379 		if(p->smc || p->putc)
1380 			error(Ebadarg);
1381 		if(n >= sizeof(cmd))
1382 			n = sizeof(cmd)-1;
1383 		memmove(cmd, buf, n);
1384 		cmd[n] = 0;
1385 		m = strtoul(cmd, nil, 0);
1386 		inuse = 0;
1387 		qlock(p);
1388 		if(p->opens == 0){
1389 			p->mode = m & 0x7F;
1390 			p->loopback = (m&0x80)!=0;
1391 			p->setup = 0;
1392 		}else
1393 			inuse = 1;
1394 		qunlock(p);
1395 		if(inuse)
1396 			error(Einuse);
1397 		return n;
1398 	}
1399 }
1400 
1401 static long
1402 uartbwrite(Chan *c, Block *bp, ulong offset)
1403 {
1404 	if(c->qid.type & QTDIR || NETTYPE(c->qid.path) != Ndataqid)
1405 		return devbwrite(c, bp, offset);
1406 	return qbwrite(uart[NETID(c->qid.path)]->oq, bp);
1407 }
1408 
1409 static int
1410 uartwstat(Chan *c, uchar *dp, int n)
1411 {
1412 	Dir d;
1413 	Dirtab *dt;
1414 
1415 	if(!iseve())
1416 		error(Eperm);
1417 	if(c->qid.type & QTDIR)
1418 		error(Eperm);
1419 	if(NETTYPE(c->qid.path) == Nstatqid)
1420 		error(Eperm);
1421 
1422 	dt = &uartdir[1+4 * NETID(c->qid.path)];
1423 	n = convM2D(dp, n, &d, nil);
1424 	if(d.mode != ~0UL){
1425 		d.mode &= 0666;
1426 		dt[0].perm = dt[1].perm = d.mode;
1427 	}
1428 	return n;
1429 }
1430 
1431 Dev uartdevtab = {
1432 	't',
1433 	"uart",
1434 
1435 	uartreset,
1436 	devinit,
1437 	devshutdown,
1438 	uartattach,
1439 	uartwalk,
1440 	uartstat,
1441 	uartopen,
1442 	devcreate,
1443 	uartclose,
1444 	uartread,
1445 	uartbread,
1446 	uartwrite,
1447 	uartbwrite,
1448 	devremove,
1449 	uartwstat,
1450 };
1451