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