xref: /inferno-os/os/mpc/devuart.c (revision 4eb166cf184c1f102fb79e31b1465ea3e2021c39)
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