xref: /inferno-os/os/ks32/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 #include	"../port/netif.h"
9*74a4d8c2SCharles.Forsyth 
10*74a4d8c2SCharles.Forsyth /*
11*74a4d8c2SCharles.Forsyth  * currently no DMA or flow control (hardware or software)
12*74a4d8c2SCharles.Forsyth  */
13*74a4d8c2SCharles.Forsyth 
14*74a4d8c2SCharles.Forsyth /*
15*74a4d8c2SCharles.Forsyth  * problems fixed from previous vsn:
16*74a4d8c2SCharles.Forsyth  *
17*74a4d8c2SCharles.Forsyth  *	- no kick on queue's, so redirections weren't getting
18*74a4d8c2SCharles.Forsyth  *	  started until the clock tick
19*74a4d8c2SCharles.Forsyth  *
20*74a4d8c2SCharles.Forsyth  *	- lots of unnecessary overhead
21*74a4d8c2SCharles.Forsyth  *
22*74a4d8c2SCharles.Forsyth  *	- initialization sequencing
23*74a4d8c2SCharles.Forsyth  *
24*74a4d8c2SCharles.Forsyth  *	- uart[n] no longer indexed before calling uartinstall()
25*74a4d8c2SCharles.Forsyth  */
26*74a4d8c2SCharles.Forsyth #define DEBUG	if(0)iprint
27*74a4d8c2SCharles.Forsyth 
28*74a4d8c2SCharles.Forsyth static void uartintr(Ureg*, void*);
29*74a4d8c2SCharles.Forsyth 
30*74a4d8c2SCharles.Forsyth enum
31*74a4d8c2SCharles.Forsyth {
32*74a4d8c2SCharles.Forsyth 	Stagesize= 1024,
33*74a4d8c2SCharles.Forsyth 	Dmabufsize=Stagesize/2,
34*74a4d8c2SCharles.Forsyth 	Nuart=7,		/* max per machine */
35*74a4d8c2SCharles.Forsyth };
36*74a4d8c2SCharles.Forsyth 
37*74a4d8c2SCharles.Forsyth typedef struct Uart Uart;
38*74a4d8c2SCharles.Forsyth struct Uart
39*74a4d8c2SCharles.Forsyth {
40*74a4d8c2SCharles.Forsyth 	QLock;
41*74a4d8c2SCharles.Forsyth 
42*74a4d8c2SCharles.Forsyth 	int	opens;
43*74a4d8c2SCharles.Forsyth 
44*74a4d8c2SCharles.Forsyth 	int	enabled;
45*74a4d8c2SCharles.Forsyth 
46*74a4d8c2SCharles.Forsyth 	int	port;			/* 0 or 1 */
47*74a4d8c2SCharles.Forsyth 	int	kickme;		/* for kick */
48*74a4d8c2SCharles.Forsyth 	int	frame;		/* framing errors */
49*74a4d8c2SCharles.Forsyth 	int	overrun;	/* rcvr overruns */
50*74a4d8c2SCharles.Forsyth 	int	perror;		/* parity error */
51*74a4d8c2SCharles.Forsyth 	int	bps;		/* baud rate */
52*74a4d8c2SCharles.Forsyth 	uchar	bits;
53*74a4d8c2SCharles.Forsyth 	char	parity;
54*74a4d8c2SCharles.Forsyth 	uchar	stop;
55*74a4d8c2SCharles.Forsyth 
56*74a4d8c2SCharles.Forsyth 	int	inters;		/* total interrupt count */
57*74a4d8c2SCharles.Forsyth 	int	rinters;	/* interrupts due to read */
58*74a4d8c2SCharles.Forsyth 	int	winters;	/* interrupts due to write */
59*74a4d8c2SCharles.Forsyth 
60*74a4d8c2SCharles.Forsyth 	int	rcount;		/* total read count */
61*74a4d8c2SCharles.Forsyth 	int	wcount;		/* total output count */
62*74a4d8c2SCharles.Forsyth 
63*74a4d8c2SCharles.Forsyth 	/* buffers */
64*74a4d8c2SCharles.Forsyth 	int	(*putc)(Queue*, int);
65*74a4d8c2SCharles.Forsyth 	Queue	*iq;
66*74a4d8c2SCharles.Forsyth 	Queue	*oq;
67*74a4d8c2SCharles.Forsyth 
68*74a4d8c2SCharles.Forsyth 	UartReg	*reg;
69*74a4d8c2SCharles.Forsyth 
70*74a4d8c2SCharles.Forsyth 	/* staging areas to avoid some of the per character costs */
71*74a4d8c2SCharles.Forsyth 	uchar	*ip;
72*74a4d8c2SCharles.Forsyth 	uchar	*ie;
73*74a4d8c2SCharles.Forsyth 	uchar	*op;
74*74a4d8c2SCharles.Forsyth 	uchar	*oe;
75*74a4d8c2SCharles.Forsyth 
76*74a4d8c2SCharles.Forsyth 	/* put large buffers last to aid register-offset optimizations: */
77*74a4d8c2SCharles.Forsyth 	char	name[KNAMELEN];
78*74a4d8c2SCharles.Forsyth 	uchar	istage[Stagesize];
79*74a4d8c2SCharles.Forsyth 	uchar	ostage[Stagesize];
80*74a4d8c2SCharles.Forsyth };
81*74a4d8c2SCharles.Forsyth 
82*74a4d8c2SCharles.Forsyth #define UCON_ENABLEMASK (UCON_RXMDMASK | UCON_TXMDMASK | UCON_SINTMASK)
83*74a4d8c2SCharles.Forsyth #define UCON_ENABLESET (UCON_RXMDINT | UCON_TXMDINT | UCON_SINTON)
84*74a4d8c2SCharles.Forsyth #define UCON_DISABLESET (UCON_RXMDOFF | UCON_TXMDOFF | UCON_SINTOFF)
85*74a4d8c2SCharles.Forsyth 
86*74a4d8c2SCharles.Forsyth static Uart *uart[Nuart];
87*74a4d8c2SCharles.Forsyth static int nuart;
88*74a4d8c2SCharles.Forsyth 
89*74a4d8c2SCharles.Forsyth static uchar
readstatus(Uart * p)90*74a4d8c2SCharles.Forsyth readstatus(Uart *p)
91*74a4d8c2SCharles.Forsyth {
92*74a4d8c2SCharles.Forsyth 	UartReg *reg = p->reg;
93*74a4d8c2SCharles.Forsyth 	uchar stat = reg->stat;
94*74a4d8c2SCharles.Forsyth 	if (stat & USTAT_OV)
95*74a4d8c2SCharles.Forsyth 		p->overrun++;
96*74a4d8c2SCharles.Forsyth 	if (stat & USTAT_PE)
97*74a4d8c2SCharles.Forsyth 		p->perror++;
98*74a4d8c2SCharles.Forsyth 	if (stat & USTAT_FE)
99*74a4d8c2SCharles.Forsyth 		p->frame++;
100*74a4d8c2SCharles.Forsyth 	return stat;
101*74a4d8c2SCharles.Forsyth }
102*74a4d8c2SCharles.Forsyth 
103*74a4d8c2SCharles.Forsyth static void
uartset(Uart * p)104*74a4d8c2SCharles.Forsyth uartset(Uart *p)
105*74a4d8c2SCharles.Forsyth {
106*74a4d8c2SCharles.Forsyth 	UartReg *reg = p->reg;
107*74a4d8c2SCharles.Forsyth 	ulong denom;
108*74a4d8c2SCharles.Forsyth 	ulong brdiv;
109*74a4d8c2SCharles.Forsyth 	int n;
110*74a4d8c2SCharles.Forsyth 	uchar lcon;
111*74a4d8c2SCharles.Forsyth 
112*74a4d8c2SCharles.Forsyth 	lcon= ULCON_CLOCKMCLK | ULCON_IROFF;
113*74a4d8c2SCharles.Forsyth 	lcon |= ULCON_WL5 + (p->bits - 5);
114*74a4d8c2SCharles.Forsyth 	lcon |= p->stop == 1 ? ULCON_STOP1 : ULCON_STOP2;
115*74a4d8c2SCharles.Forsyth 	switch (p->parity) {
116*74a4d8c2SCharles.Forsyth 	default:
117*74a4d8c2SCharles.Forsyth 	case 'n':
118*74a4d8c2SCharles.Forsyth 		lcon |= ULCON_PMDNONE;
119*74a4d8c2SCharles.Forsyth 		break;
120*74a4d8c2SCharles.Forsyth 	case 'o':
121*74a4d8c2SCharles.Forsyth 		lcon |= ULCON_PMDODD;
122*74a4d8c2SCharles.Forsyth 		break;
123*74a4d8c2SCharles.Forsyth 	case 'e':
124*74a4d8c2SCharles.Forsyth 		lcon |= ULCON_PMDEVEN;
125*74a4d8c2SCharles.Forsyth 		break;
126*74a4d8c2SCharles.Forsyth 	}
127*74a4d8c2SCharles.Forsyth 	reg->lcon = lcon;
128*74a4d8c2SCharles.Forsyth 
129*74a4d8c2SCharles.Forsyth 	/* clear the break and loopback bits; leave everything else alone */
130*74a4d8c2SCharles.Forsyth 	reg->con = (reg->con & ~(UCON_BRKMASK | UCON_LOOPMASK)) | UCON_BRKOFF | UCON_LOOPOFF;
131*74a4d8c2SCharles.Forsyth 
132*74a4d8c2SCharles.Forsyth 	denom = 2 * 16 * p->bps;
133*74a4d8c2SCharles.Forsyth 	brdiv = (TIMER_HZ + denom / 2) / denom - 1;
134*74a4d8c2SCharles.Forsyth 	reg->brdiv = brdiv << 4;
135*74a4d8c2SCharles.Forsyth 
136*74a4d8c2SCharles.Forsyth 	/* set buffer length according to speed, to allow
137*74a4d8c2SCharles.Forsyth 	 * at most a 200ms delay before dumping the staging buffer
138*74a4d8c2SCharles.Forsyth 	 * into the input queue
139*74a4d8c2SCharles.Forsyth 	 */
140*74a4d8c2SCharles.Forsyth 	n = p->bps/(10*1000/200);
141*74a4d8c2SCharles.Forsyth 	p->ie = &p->istage[n < Stagesize ? n : Stagesize];
142*74a4d8c2SCharles.Forsyth }
143*74a4d8c2SCharles.Forsyth 
144*74a4d8c2SCharles.Forsyth /*
145*74a4d8c2SCharles.Forsyth  *  send break
146*74a4d8c2SCharles.Forsyth  */
147*74a4d8c2SCharles.Forsyth static void
uartbreak(Uart * p,int ms)148*74a4d8c2SCharles.Forsyth uartbreak(Uart *p, int ms)
149*74a4d8c2SCharles.Forsyth {
150*74a4d8c2SCharles.Forsyth 	UartReg *reg = p->reg;
151*74a4d8c2SCharles.Forsyth 	if(ms == 0)
152*74a4d8c2SCharles.Forsyth 		ms = 200;
153*74a4d8c2SCharles.Forsyth 	reg->con |= UCON_BRKON;
154*74a4d8c2SCharles.Forsyth 	tsleep(&up->sleep, return0, 0, ms);
155*74a4d8c2SCharles.Forsyth 	reg->con &= ~UCON_BRKON;
156*74a4d8c2SCharles.Forsyth }
157*74a4d8c2SCharles.Forsyth 
158*74a4d8c2SCharles.Forsyth /*
159*74a4d8c2SCharles.Forsyth  *  turn on a port
160*74a4d8c2SCharles.Forsyth  */
161*74a4d8c2SCharles.Forsyth static void
uartenable(Uart * p)162*74a4d8c2SCharles.Forsyth uartenable(Uart *p)
163*74a4d8c2SCharles.Forsyth {
164*74a4d8c2SCharles.Forsyth 	UartReg *reg = p->reg;
165*74a4d8c2SCharles.Forsyth 
166*74a4d8c2SCharles.Forsyth 	if(p->enabled)
167*74a4d8c2SCharles.Forsyth 		return;
168*74a4d8c2SCharles.Forsyth 
169*74a4d8c2SCharles.Forsyth 	uartset(p);
170*74a4d8c2SCharles.Forsyth 	// enable receive, transmit, and receive interrupt:
171*74a4d8c2SCharles.Forsyth 	reg->con = (reg->con & UCON_ENABLEMASK) | UCON_ENABLESET;
172*74a4d8c2SCharles.Forsyth 	p->enabled = 1;
173*74a4d8c2SCharles.Forsyth }
174*74a4d8c2SCharles.Forsyth 
175*74a4d8c2SCharles.Forsyth /*
176*74a4d8c2SCharles.Forsyth  *  turn off a port
177*74a4d8c2SCharles.Forsyth  */
178*74a4d8c2SCharles.Forsyth static void
uartdisable(Uart * p)179*74a4d8c2SCharles.Forsyth uartdisable(Uart *p)
180*74a4d8c2SCharles.Forsyth {
181*74a4d8c2SCharles.Forsyth 	p->reg->con = (p->reg->con & UCON_ENABLEMASK) | UCON_DISABLESET;
182*74a4d8c2SCharles.Forsyth 	p->enabled = 0;
183*74a4d8c2SCharles.Forsyth }
184*74a4d8c2SCharles.Forsyth 
185*74a4d8c2SCharles.Forsyth /*
186*74a4d8c2SCharles.Forsyth  *  put some bytes into the local queue to avoid calling
187*74a4d8c2SCharles.Forsyth  *  qconsume for every character
188*74a4d8c2SCharles.Forsyth  */
189*74a4d8c2SCharles.Forsyth static int
stageoutput(Uart * p)190*74a4d8c2SCharles.Forsyth stageoutput(Uart *p)
191*74a4d8c2SCharles.Forsyth {
192*74a4d8c2SCharles.Forsyth 	int n;
193*74a4d8c2SCharles.Forsyth 	Queue *q = p->oq;
194*74a4d8c2SCharles.Forsyth 
195*74a4d8c2SCharles.Forsyth 	if(!q)
196*74a4d8c2SCharles.Forsyth 		return 0;
197*74a4d8c2SCharles.Forsyth 	n = qconsume(q, p->ostage, Stagesize);
198*74a4d8c2SCharles.Forsyth 	if(n <= 0)
199*74a4d8c2SCharles.Forsyth 		return 0;
200*74a4d8c2SCharles.Forsyth 	p->op = p->ostage;
201*74a4d8c2SCharles.Forsyth 	p->oe = p->ostage + n;
202*74a4d8c2SCharles.Forsyth 	return n;
203*74a4d8c2SCharles.Forsyth }
204*74a4d8c2SCharles.Forsyth 
205*74a4d8c2SCharles.Forsyth static void
uartxmit(Uart * p)206*74a4d8c2SCharles.Forsyth uartxmit(Uart *p)
207*74a4d8c2SCharles.Forsyth {
208*74a4d8c2SCharles.Forsyth 	UartReg *reg = p->reg;
209*74a4d8c2SCharles.Forsyth 	ulong gag = 1;
210*74a4d8c2SCharles.Forsyth 	while(p->op < p->oe || stageoutput(p)) {
211*74a4d8c2SCharles.Forsyth 		if(readstatus(p) & USTAT_TBE) {
212*74a4d8c2SCharles.Forsyth 			DEBUG("T");
213*74a4d8c2SCharles.Forsyth 			reg->txbuf = *(p->op++);
214*74a4d8c2SCharles.Forsyth 			p->wcount++;
215*74a4d8c2SCharles.Forsyth 		} else {
216*74a4d8c2SCharles.Forsyth 			DEBUG("F");
217*74a4d8c2SCharles.Forsyth 			gag = 0;
218*74a4d8c2SCharles.Forsyth 			break;
219*74a4d8c2SCharles.Forsyth 		}
220*74a4d8c2SCharles.Forsyth 	}
221*74a4d8c2SCharles.Forsyth 	if (gag) {
222*74a4d8c2SCharles.Forsyth 		DEBUG("G");
223*74a4d8c2SCharles.Forsyth 		p->kickme = 1;
224*74a4d8c2SCharles.Forsyth 		intrmask(UARTTXbit(p->port), 0);
225*74a4d8c2SCharles.Forsyth 	}
226*74a4d8c2SCharles.Forsyth }
227*74a4d8c2SCharles.Forsyth 
228*74a4d8c2SCharles.Forsyth static void
uartrecvq(Uart * p)229*74a4d8c2SCharles.Forsyth uartrecvq(Uart *p)
230*74a4d8c2SCharles.Forsyth {
231*74a4d8c2SCharles.Forsyth 	uchar *cp = p->istage;
232*74a4d8c2SCharles.Forsyth 	int n = p->ip - cp;
233*74a4d8c2SCharles.Forsyth 
234*74a4d8c2SCharles.Forsyth 	if(n == 0)
235*74a4d8c2SCharles.Forsyth 		return;
236*74a4d8c2SCharles.Forsyth 	if(p->putc)
237*74a4d8c2SCharles.Forsyth 		while(n-- > 0)
238*74a4d8c2SCharles.Forsyth 			p->putc(p->iq, *cp++);
239*74a4d8c2SCharles.Forsyth 	else if(p->iq)
240*74a4d8c2SCharles.Forsyth 		if(qproduce(p->iq, p->istage, n) < n)
241*74a4d8c2SCharles.Forsyth 			print("qproduce flow control");
242*74a4d8c2SCharles.Forsyth 	p->ip = p->istage;
243*74a4d8c2SCharles.Forsyth }
244*74a4d8c2SCharles.Forsyth 
245*74a4d8c2SCharles.Forsyth static void
uartrecv(Uart * p)246*74a4d8c2SCharles.Forsyth uartrecv(Uart *p)
247*74a4d8c2SCharles.Forsyth {
248*74a4d8c2SCharles.Forsyth 	UartReg *reg = p->reg;
249*74a4d8c2SCharles.Forsyth 	uchar stat = readstatus(p);
250*74a4d8c2SCharles.Forsyth 
251*74a4d8c2SCharles.Forsyth DEBUG("R");
252*74a4d8c2SCharles.Forsyth 	if (stat & USTAT_RDR) {
253*74a4d8c2SCharles.Forsyth 		int c;
254*74a4d8c2SCharles.Forsyth 		c = reg->rxbuf;
255*74a4d8c2SCharles.Forsyth 		if (c == '?') {
256*74a4d8c2SCharles.Forsyth 			DEBUG("mod 0x%.8lx\n", INTREG->mod);
257*74a4d8c2SCharles.Forsyth 			DEBUG("msk 0x%.8lx\n", INTREG->msk);
258*74a4d8c2SCharles.Forsyth 			DEBUG("pnd 0x%.8lx\n", INTREG->pnd);
259*74a4d8c2SCharles.Forsyth 		}
260*74a4d8c2SCharles.Forsyth 		*p->ip++ = c;
261*74a4d8c2SCharles.Forsyth /*		if(p->ip >= p->ie) */
262*74a4d8c2SCharles.Forsyth 			uartrecvq(p);
263*74a4d8c2SCharles.Forsyth 		p->rcount++;
264*74a4d8c2SCharles.Forsyth 	}
265*74a4d8c2SCharles.Forsyth }
266*74a4d8c2SCharles.Forsyth 
267*74a4d8c2SCharles.Forsyth static void
uartkick(void * a)268*74a4d8c2SCharles.Forsyth uartkick(void *a)
269*74a4d8c2SCharles.Forsyth {
270*74a4d8c2SCharles.Forsyth 	Uart *p = a;
271*74a4d8c2SCharles.Forsyth 	int x = splhi();
272*74a4d8c2SCharles.Forsyth 	DEBUG("k");
273*74a4d8c2SCharles.Forsyth 	if (p->kickme) {
274*74a4d8c2SCharles.Forsyth 		p->kickme = 0;
275*74a4d8c2SCharles.Forsyth 		DEBUG("K");
276*74a4d8c2SCharles.Forsyth 		intrunmask(UARTTXbit(p->port), 0);
277*74a4d8c2SCharles.Forsyth 	}
278*74a4d8c2SCharles.Forsyth 	splx(x);
279*74a4d8c2SCharles.Forsyth }
280*74a4d8c2SCharles.Forsyth 
281*74a4d8c2SCharles.Forsyth /*
282*74a4d8c2SCharles.Forsyth  *  UART Interrupt Handler
283*74a4d8c2SCharles.Forsyth  */
284*74a4d8c2SCharles.Forsyth static void
uarttxintr(Ureg *,void * arg)285*74a4d8c2SCharles.Forsyth uarttxintr(Ureg*, void* arg)
286*74a4d8c2SCharles.Forsyth {
287*74a4d8c2SCharles.Forsyth 	Uart *p = arg;
288*74a4d8c2SCharles.Forsyth 	intrclear(UARTTXbit(p->port), 0);
289*74a4d8c2SCharles.Forsyth 	p->inters++;
290*74a4d8c2SCharles.Forsyth 	p->winters++;
291*74a4d8c2SCharles.Forsyth 	uartxmit(p);
292*74a4d8c2SCharles.Forsyth }
293*74a4d8c2SCharles.Forsyth 
294*74a4d8c2SCharles.Forsyth static void
uartrxintr(Ureg *,void * arg)295*74a4d8c2SCharles.Forsyth uartrxintr(Ureg*, void* arg)
296*74a4d8c2SCharles.Forsyth {
297*74a4d8c2SCharles.Forsyth 	Uart *p = arg;
298*74a4d8c2SCharles.Forsyth 	intrclear(UARTRXbit(p->port), 0);
299*74a4d8c2SCharles.Forsyth 	p->inters++;
300*74a4d8c2SCharles.Forsyth 	p->rinters++;
301*74a4d8c2SCharles.Forsyth 	uartrecv(p);
302*74a4d8c2SCharles.Forsyth }
303*74a4d8c2SCharles.Forsyth 
304*74a4d8c2SCharles.Forsyth 
305*74a4d8c2SCharles.Forsyth static void
uartsetup(ulong port,char * name)306*74a4d8c2SCharles.Forsyth uartsetup(ulong port, char *name)
307*74a4d8c2SCharles.Forsyth {
308*74a4d8c2SCharles.Forsyth 	Uart *p;
309*74a4d8c2SCharles.Forsyth 
310*74a4d8c2SCharles.Forsyth 	if(nuart >= Nuart)
311*74a4d8c2SCharles.Forsyth 		return;
312*74a4d8c2SCharles.Forsyth 
313*74a4d8c2SCharles.Forsyth 	p = xalloc(sizeof(Uart));
314*74a4d8c2SCharles.Forsyth 	uart[nuart++] = p;
315*74a4d8c2SCharles.Forsyth 	strcpy(p->name, name);
316*74a4d8c2SCharles.Forsyth 
317*74a4d8c2SCharles.Forsyth 	p->reg = &UARTREG[port];
318*74a4d8c2SCharles.Forsyth 	p->bps = 9600;
319*74a4d8c2SCharles.Forsyth 	p->bits = 8;
320*74a4d8c2SCharles.Forsyth 	p->parity = 'n';
321*74a4d8c2SCharles.Forsyth 	p->stop = 1;
322*74a4d8c2SCharles.Forsyth 	p->kickme = 0;
323*74a4d8c2SCharles.Forsyth 	p->port = port;
324*74a4d8c2SCharles.Forsyth 
325*74a4d8c2SCharles.Forsyth 	p->iq = qopen(4*1024, 0, 0 , p);
326*74a4d8c2SCharles.Forsyth 	p->oq = qopen(4*1024, 0, uartkick, p);
327*74a4d8c2SCharles.Forsyth 
328*74a4d8c2SCharles.Forsyth 	p->ip = p->istage;
329*74a4d8c2SCharles.Forsyth 	p->ie = &p->istage[Stagesize];
330*74a4d8c2SCharles.Forsyth 	p->op = p->ostage;
331*74a4d8c2SCharles.Forsyth 	p->oe = p->ostage;
332*74a4d8c2SCharles.Forsyth 
333*74a4d8c2SCharles.Forsyth 	intrenable(UARTTXbit(port), uarttxintr, p, 0);
334*74a4d8c2SCharles.Forsyth 	intrenable(UARTRXbit(port), uartrxintr, p, 0);
335*74a4d8c2SCharles.Forsyth }
336*74a4d8c2SCharles.Forsyth 
337*74a4d8c2SCharles.Forsyth static void
uartinstall(void)338*74a4d8c2SCharles.Forsyth uartinstall(void)
339*74a4d8c2SCharles.Forsyth {
340*74a4d8c2SCharles.Forsyth 	static int already;
341*74a4d8c2SCharles.Forsyth 
342*74a4d8c2SCharles.Forsyth 	if(already)
343*74a4d8c2SCharles.Forsyth 		return;
344*74a4d8c2SCharles.Forsyth 	already = 1;
345*74a4d8c2SCharles.Forsyth 
346*74a4d8c2SCharles.Forsyth 	uartsetup(0, "eia0");
347*74a4d8c2SCharles.Forsyth //	uartsetup(1, "eia1");
348*74a4d8c2SCharles.Forsyth }
349*74a4d8c2SCharles.Forsyth 
350*74a4d8c2SCharles.Forsyth /*
351*74a4d8c2SCharles.Forsyth  *  called by main() to configure a duart port as a console or a mouse
352*74a4d8c2SCharles.Forsyth  */
353*74a4d8c2SCharles.Forsyth void
uartspecial(int port,int bps,char parity,Queue ** in,Queue ** out,int (* putc)(Queue *,int))354*74a4d8c2SCharles.Forsyth uartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int))
355*74a4d8c2SCharles.Forsyth {
356*74a4d8c2SCharles.Forsyth 	Uart *p;
357*74a4d8c2SCharles.Forsyth 
358*74a4d8c2SCharles.Forsyth 	uartinstall();
359*74a4d8c2SCharles.Forsyth 	if(port >= nuart)
360*74a4d8c2SCharles.Forsyth 		return;
361*74a4d8c2SCharles.Forsyth 	p = uart[port];
362*74a4d8c2SCharles.Forsyth 	if(bps)
363*74a4d8c2SCharles.Forsyth 		p->bps = bps;
364*74a4d8c2SCharles.Forsyth 	if(parity)
365*74a4d8c2SCharles.Forsyth 		p->parity = parity;
366*74a4d8c2SCharles.Forsyth 	uartenable(p);
367*74a4d8c2SCharles.Forsyth 	p->putc = putc;
368*74a4d8c2SCharles.Forsyth 	if(in)
369*74a4d8c2SCharles.Forsyth 		*in = p->iq;
370*74a4d8c2SCharles.Forsyth 	if(out)
371*74a4d8c2SCharles.Forsyth 		*out = p->oq;
372*74a4d8c2SCharles.Forsyth 	p->opens++;
373*74a4d8c2SCharles.Forsyth }
374*74a4d8c2SCharles.Forsyth 
375*74a4d8c2SCharles.Forsyth Dirtab *uartdir;
376*74a4d8c2SCharles.Forsyth int ndir;
377*74a4d8c2SCharles.Forsyth 
378*74a4d8c2SCharles.Forsyth static void
setlength(int i)379*74a4d8c2SCharles.Forsyth setlength(int i)
380*74a4d8c2SCharles.Forsyth {
381*74a4d8c2SCharles.Forsyth 	Uart *p;
382*74a4d8c2SCharles.Forsyth 
383*74a4d8c2SCharles.Forsyth 	if(i > 0){
384*74a4d8c2SCharles.Forsyth 		p = uart[i];
385*74a4d8c2SCharles.Forsyth 		if(p && p->opens && p->iq)
386*74a4d8c2SCharles.Forsyth 			uartdir[1+3*i].length = qlen(p->iq);
387*74a4d8c2SCharles.Forsyth 	} else for(i = 0; i < nuart; i++){
388*74a4d8c2SCharles.Forsyth 		p = uart[i];
389*74a4d8c2SCharles.Forsyth 		if(p && p->opens && p->iq)
390*74a4d8c2SCharles.Forsyth 			uartdir[1+3*i].length = qlen(p->iq);
391*74a4d8c2SCharles.Forsyth 	}
392*74a4d8c2SCharles.Forsyth }
393*74a4d8c2SCharles.Forsyth 
394*74a4d8c2SCharles.Forsyth /*
395*74a4d8c2SCharles.Forsyth  *  all uarts must be uartsetup() by this point or inside of uartinstall()
396*74a4d8c2SCharles.Forsyth  */
397*74a4d8c2SCharles.Forsyth static void
uartreset(void)398*74a4d8c2SCharles.Forsyth uartreset(void)
399*74a4d8c2SCharles.Forsyth {
400*74a4d8c2SCharles.Forsyth 	int i;
401*74a4d8c2SCharles.Forsyth 	Dirtab *dp;
402*74a4d8c2SCharles.Forsyth 
403*74a4d8c2SCharles.Forsyth 	uartinstall();
404*74a4d8c2SCharles.Forsyth 
405*74a4d8c2SCharles.Forsyth 	ndir = 1+3*nuart;
406*74a4d8c2SCharles.Forsyth 	uartdir = xalloc(ndir * sizeof(Dirtab));
407*74a4d8c2SCharles.Forsyth 	dp = uartdir;
408*74a4d8c2SCharles.Forsyth 	strcpy(dp->name, ".");
409*74a4d8c2SCharles.Forsyth 	mkqid(&dp->qid, 0, 0, QTDIR);
410*74a4d8c2SCharles.Forsyth 	dp->length = 0;
411*74a4d8c2SCharles.Forsyth 	dp->perm = DMDIR|0555;
412*74a4d8c2SCharles.Forsyth 	dp++;
413*74a4d8c2SCharles.Forsyth 	for(i = 0; i < nuart; i++){
414*74a4d8c2SCharles.Forsyth 		/* 3 directory entries per port */
415*74a4d8c2SCharles.Forsyth 		strcpy(dp->name, uart[i]->name);
416*74a4d8c2SCharles.Forsyth 		dp->qid.path = NETQID(i, Ndataqid);
417*74a4d8c2SCharles.Forsyth 		dp->perm = 0660;
418*74a4d8c2SCharles.Forsyth 		dp++;
419*74a4d8c2SCharles.Forsyth 		sprint(dp->name, "%sctl", uart[i]->name);
420*74a4d8c2SCharles.Forsyth 		dp->qid.path = NETQID(i, Nctlqid);
421*74a4d8c2SCharles.Forsyth 		dp->perm = 0660;
422*74a4d8c2SCharles.Forsyth 		dp++;
423*74a4d8c2SCharles.Forsyth 		sprint(dp->name, "%sstatus", uart[i]->name);
424*74a4d8c2SCharles.Forsyth 		dp->qid.path = NETQID(i, Nstatqid);
425*74a4d8c2SCharles.Forsyth 		dp->perm = 0444;
426*74a4d8c2SCharles.Forsyth 		dp++;
427*74a4d8c2SCharles.Forsyth 	}
428*74a4d8c2SCharles.Forsyth }
429*74a4d8c2SCharles.Forsyth 
430*74a4d8c2SCharles.Forsyth static Chan*
uartattach(char * spec)431*74a4d8c2SCharles.Forsyth uartattach(char *spec)
432*74a4d8c2SCharles.Forsyth {
433*74a4d8c2SCharles.Forsyth 	return devattach('t', spec);
434*74a4d8c2SCharles.Forsyth }
435*74a4d8c2SCharles.Forsyth 
436*74a4d8c2SCharles.Forsyth static Walkqid*
uartwalk(Chan * c,Chan * nc,char ** name,int nname)437*74a4d8c2SCharles.Forsyth uartwalk(Chan *c, Chan *nc, char **name, int nname)
438*74a4d8c2SCharles.Forsyth {
439*74a4d8c2SCharles.Forsyth 	return devwalk(c, nc, name, nname, uartdir, ndir, devgen);
440*74a4d8c2SCharles.Forsyth }
441*74a4d8c2SCharles.Forsyth 
442*74a4d8c2SCharles.Forsyth static int
uartstat(Chan * c,uchar * dp,int n)443*74a4d8c2SCharles.Forsyth uartstat(Chan *c, uchar *dp, int n)
444*74a4d8c2SCharles.Forsyth {
445*74a4d8c2SCharles.Forsyth 	if(NETTYPE(c->qid.path) == Ndataqid)
446*74a4d8c2SCharles.Forsyth 		setlength(NETID(c->qid.path));
447*74a4d8c2SCharles.Forsyth 	return devstat(c, dp, n, uartdir, ndir, devgen);
448*74a4d8c2SCharles.Forsyth }
449*74a4d8c2SCharles.Forsyth 
450*74a4d8c2SCharles.Forsyth static Chan*
uartopen(Chan * c,int omode)451*74a4d8c2SCharles.Forsyth uartopen(Chan *c, int omode)
452*74a4d8c2SCharles.Forsyth {
453*74a4d8c2SCharles.Forsyth 	Uart *p;
454*74a4d8c2SCharles.Forsyth 
455*74a4d8c2SCharles.Forsyth 	c = devopen(c, omode, uartdir, ndir, devgen);
456*74a4d8c2SCharles.Forsyth 
457*74a4d8c2SCharles.Forsyth 	switch(NETTYPE(c->qid.path)){
458*74a4d8c2SCharles.Forsyth 	case Nctlqid:
459*74a4d8c2SCharles.Forsyth 	case Ndataqid:
460*74a4d8c2SCharles.Forsyth 		p = uart[NETID(c->qid.path)];
461*74a4d8c2SCharles.Forsyth 		qlock(p);
462*74a4d8c2SCharles.Forsyth 		if(p->opens++ == 0){
463*74a4d8c2SCharles.Forsyth 			uartenable(p);
464*74a4d8c2SCharles.Forsyth 			qreopen(p->iq);
465*74a4d8c2SCharles.Forsyth 			qreopen(p->oq);
466*74a4d8c2SCharles.Forsyth 		}
467*74a4d8c2SCharles.Forsyth 		qunlock(p);
468*74a4d8c2SCharles.Forsyth 		break;
469*74a4d8c2SCharles.Forsyth 	}
470*74a4d8c2SCharles.Forsyth 
471*74a4d8c2SCharles.Forsyth 	return c;
472*74a4d8c2SCharles.Forsyth }
473*74a4d8c2SCharles.Forsyth 
474*74a4d8c2SCharles.Forsyth static void
uartclose(Chan * c)475*74a4d8c2SCharles.Forsyth uartclose(Chan *c)
476*74a4d8c2SCharles.Forsyth {
477*74a4d8c2SCharles.Forsyth 	Uart *p;
478*74a4d8c2SCharles.Forsyth 
479*74a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
480*74a4d8c2SCharles.Forsyth 		return;
481*74a4d8c2SCharles.Forsyth 	if((c->flag & COPEN) == 0)
482*74a4d8c2SCharles.Forsyth 		return;
483*74a4d8c2SCharles.Forsyth 	switch(NETTYPE(c->qid.path)){
484*74a4d8c2SCharles.Forsyth 	case Ndataqid:
485*74a4d8c2SCharles.Forsyth 	case Nctlqid:
486*74a4d8c2SCharles.Forsyth 		p = uart[NETID(c->qid.path)];
487*74a4d8c2SCharles.Forsyth 		qlock(p);
488*74a4d8c2SCharles.Forsyth 		if(--(p->opens) == 0){
489*74a4d8c2SCharles.Forsyth 			uartdisable(p);
490*74a4d8c2SCharles.Forsyth 			qclose(p->iq);
491*74a4d8c2SCharles.Forsyth 			qclose(p->oq);
492*74a4d8c2SCharles.Forsyth 			p->ip = p->istage;
493*74a4d8c2SCharles.Forsyth 		}
494*74a4d8c2SCharles.Forsyth 		qunlock(p);
495*74a4d8c2SCharles.Forsyth 		break;
496*74a4d8c2SCharles.Forsyth 	}
497*74a4d8c2SCharles.Forsyth }
498*74a4d8c2SCharles.Forsyth 
499*74a4d8c2SCharles.Forsyth static long
uartstatus(Chan * c,Uart * p,void * buf,long n,long offset)500*74a4d8c2SCharles.Forsyth uartstatus(Chan *c, Uart *p, void *buf, long n, long offset)
501*74a4d8c2SCharles.Forsyth {
502*74a4d8c2SCharles.Forsyth 	char str[256];
503*74a4d8c2SCharles.Forsyth 	USED(c);
504*74a4d8c2SCharles.Forsyth 
505*74a4d8c2SCharles.Forsyth 	str[0] = 0;
506*74a4d8c2SCharles.Forsyth 	sprint(str, "opens %d ferr %d oerr %d perr %d baud %d parity %c"
507*74a4d8c2SCharles.Forsyth 			" intr %d rintr %d wintr %d"
508*74a4d8c2SCharles.Forsyth 			" rcount %d wcount %d",
509*74a4d8c2SCharles.Forsyth 		p->opens, p->frame, p->overrun, p->perror, p->bps, p->parity,
510*74a4d8c2SCharles.Forsyth 		p->inters, p->rinters, p->winters,
511*74a4d8c2SCharles.Forsyth 		p->rcount, p->wcount);
512*74a4d8c2SCharles.Forsyth 
513*74a4d8c2SCharles.Forsyth 	strcat(str, "\n");
514*74a4d8c2SCharles.Forsyth 	return readstr(offset, buf, n, str);
515*74a4d8c2SCharles.Forsyth }
516*74a4d8c2SCharles.Forsyth 
517*74a4d8c2SCharles.Forsyth static long
uartread(Chan * c,void * buf,long n,vlong offset)518*74a4d8c2SCharles.Forsyth uartread(Chan *c, void *buf, long n, vlong offset)
519*74a4d8c2SCharles.Forsyth {
520*74a4d8c2SCharles.Forsyth 	Uart *p;
521*74a4d8c2SCharles.Forsyth 
522*74a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR){
523*74a4d8c2SCharles.Forsyth 		setlength(-1);
524*74a4d8c2SCharles.Forsyth 		return devdirread(c, buf, n, uartdir, ndir, devgen);
525*74a4d8c2SCharles.Forsyth 	}
526*74a4d8c2SCharles.Forsyth 
527*74a4d8c2SCharles.Forsyth 	p = uart[NETID(c->qid.path)];
528*74a4d8c2SCharles.Forsyth 	switch(NETTYPE(c->qid.path)){
529*74a4d8c2SCharles.Forsyth 	case Ndataqid:
530*74a4d8c2SCharles.Forsyth 		return qread(p->iq, buf, n);
531*74a4d8c2SCharles.Forsyth 	case Nctlqid:
532*74a4d8c2SCharles.Forsyth 		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
533*74a4d8c2SCharles.Forsyth 	case Nstatqid:
534*74a4d8c2SCharles.Forsyth 		return uartstatus(c, p, buf, n, offset);
535*74a4d8c2SCharles.Forsyth 	}
536*74a4d8c2SCharles.Forsyth 
537*74a4d8c2SCharles.Forsyth 	return 0;
538*74a4d8c2SCharles.Forsyth }
539*74a4d8c2SCharles.Forsyth 
540*74a4d8c2SCharles.Forsyth static void
uartctl(Uart * p,char * cmd)541*74a4d8c2SCharles.Forsyth uartctl(Uart *p, char *cmd)
542*74a4d8c2SCharles.Forsyth {
543*74a4d8c2SCharles.Forsyth 	int i, n;
544*74a4d8c2SCharles.Forsyth 
545*74a4d8c2SCharles.Forsyth 	/* let output drain for a while (up to 4 secs) */
546*74a4d8c2SCharles.Forsyth 	for(i = 0; i < 200 && (qlen(p->oq) || (readstatus(p) & USTAT_TC) == 0); i++)
547*74a4d8c2SCharles.Forsyth 		tsleep(&up->sleep, return0, 0, 20);
548*74a4d8c2SCharles.Forsyth 
549*74a4d8c2SCharles.Forsyth 	if(strncmp(cmd, "break", 5) == 0){
550*74a4d8c2SCharles.Forsyth 		uartbreak(p, 0);
551*74a4d8c2SCharles.Forsyth 		return;
552*74a4d8c2SCharles.Forsyth 	}
553*74a4d8c2SCharles.Forsyth 
554*74a4d8c2SCharles.Forsyth 	n = atoi(cmd+1);
555*74a4d8c2SCharles.Forsyth 	switch(*cmd){
556*74a4d8c2SCharles.Forsyth 	case 'B':
557*74a4d8c2SCharles.Forsyth 	case 'b':
558*74a4d8c2SCharles.Forsyth 		if(n <= 0)
559*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
560*74a4d8c2SCharles.Forsyth 		p->bps = n;
561*74a4d8c2SCharles.Forsyth 		uartset(p);
562*74a4d8c2SCharles.Forsyth 		break;
563*74a4d8c2SCharles.Forsyth 	case 'f':
564*74a4d8c2SCharles.Forsyth 	case 'F':
565*74a4d8c2SCharles.Forsyth 		qflush(p->oq);
566*74a4d8c2SCharles.Forsyth 		break;
567*74a4d8c2SCharles.Forsyth 	case 'H':
568*74a4d8c2SCharles.Forsyth 	case 'h':
569*74a4d8c2SCharles.Forsyth 		qhangup(p->iq, 0);
570*74a4d8c2SCharles.Forsyth 		qhangup(p->oq, 0);
571*74a4d8c2SCharles.Forsyth 		break;
572*74a4d8c2SCharles.Forsyth 	case 'L':
573*74a4d8c2SCharles.Forsyth 	case 'l':
574*74a4d8c2SCharles.Forsyth 		if(n < 7 || n > 8)
575*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
576*74a4d8c2SCharles.Forsyth 		p->bits = n;
577*74a4d8c2SCharles.Forsyth 		uartset(p);
578*74a4d8c2SCharles.Forsyth 		break;
579*74a4d8c2SCharles.Forsyth 	case 'n':
580*74a4d8c2SCharles.Forsyth 	case 'N':
581*74a4d8c2SCharles.Forsyth 		qnoblock(p->oq, n);
582*74a4d8c2SCharles.Forsyth 		break;
583*74a4d8c2SCharles.Forsyth 	case 'P':
584*74a4d8c2SCharles.Forsyth 	case 'p':
585*74a4d8c2SCharles.Forsyth 		p->parity = *(cmd+1);
586*74a4d8c2SCharles.Forsyth 		uartset(p);
587*74a4d8c2SCharles.Forsyth 		break;
588*74a4d8c2SCharles.Forsyth 	case 'K':
589*74a4d8c2SCharles.Forsyth 	case 'k':
590*74a4d8c2SCharles.Forsyth 		uartbreak(p, n);
591*74a4d8c2SCharles.Forsyth 		break;
592*74a4d8c2SCharles.Forsyth 	case 'Q':
593*74a4d8c2SCharles.Forsyth 	case 'q':
594*74a4d8c2SCharles.Forsyth 		qsetlimit(p->iq, n);
595*74a4d8c2SCharles.Forsyth 		qsetlimit(p->oq, n);
596*74a4d8c2SCharles.Forsyth 		break;
597*74a4d8c2SCharles.Forsyth 	case 's':
598*74a4d8c2SCharles.Forsyth 	case 'S':
599*74a4d8c2SCharles.Forsyth 		if(n < 1 || n > 2)
600*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
601*74a4d8c2SCharles.Forsyth 		p->stop = n;
602*74a4d8c2SCharles.Forsyth 		uartset(p);
603*74a4d8c2SCharles.Forsyth 		break;
604*74a4d8c2SCharles.Forsyth 	}
605*74a4d8c2SCharles.Forsyth }
606*74a4d8c2SCharles.Forsyth 
607*74a4d8c2SCharles.Forsyth static long
uartwrite(Chan * c,void * buf,long n,vlong offset)608*74a4d8c2SCharles.Forsyth uartwrite(Chan *c, void *buf, long n, vlong offset)
609*74a4d8c2SCharles.Forsyth {
610*74a4d8c2SCharles.Forsyth 	Uart *p;
611*74a4d8c2SCharles.Forsyth 	char cmd[32];
612*74a4d8c2SCharles.Forsyth 
613*74a4d8c2SCharles.Forsyth 	USED(offset);
614*74a4d8c2SCharles.Forsyth 
615*74a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
616*74a4d8c2SCharles.Forsyth 		error(Eperm);
617*74a4d8c2SCharles.Forsyth 
618*74a4d8c2SCharles.Forsyth 	p = uart[NETID(c->qid.path)];
619*74a4d8c2SCharles.Forsyth 
620*74a4d8c2SCharles.Forsyth 	switch(NETTYPE(c->qid.path)){
621*74a4d8c2SCharles.Forsyth 	case Ndataqid:
622*74a4d8c2SCharles.Forsyth 		return qwrite(p->oq, buf, n);
623*74a4d8c2SCharles.Forsyth 	case Nctlqid:
624*74a4d8c2SCharles.Forsyth 
625*74a4d8c2SCharles.Forsyth 		if(n >= sizeof(cmd))
626*74a4d8c2SCharles.Forsyth 			n = sizeof(cmd)-1;
627*74a4d8c2SCharles.Forsyth 		memmove(cmd, buf, n);
628*74a4d8c2SCharles.Forsyth 		cmd[n] = 0;
629*74a4d8c2SCharles.Forsyth 		uartctl(p, cmd);
630*74a4d8c2SCharles.Forsyth 		return n;
631*74a4d8c2SCharles.Forsyth 	}
632*74a4d8c2SCharles.Forsyth }
633*74a4d8c2SCharles.Forsyth 
634*74a4d8c2SCharles.Forsyth static int
uartwstat(Chan * c,uchar * dp,int n)635*74a4d8c2SCharles.Forsyth uartwstat(Chan *c, uchar *dp, int n)
636*74a4d8c2SCharles.Forsyth {
637*74a4d8c2SCharles.Forsyth 	error(Eperm);
638*74a4d8c2SCharles.Forsyth 	return 0;
639*74a4d8c2SCharles.Forsyth #ifdef xxx
640*74a4d8c2SCharles.Forsyth 	Dir d;
641*74a4d8c2SCharles.Forsyth 	Dirtab *dt;
642*74a4d8c2SCharles.Forsyth 
643*74a4d8c2SCharles.Forsyth 	if(!iseve())
644*74a4d8c2SCharles.Forsyth 		error(Eperm);
645*74a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
646*74a4d8c2SCharles.Forsyth 		error(Eperm);
647*74a4d8c2SCharles.Forsyth 	if(NETTYPE(c->qid.path) == Nstatqid)
648*74a4d8c2SCharles.Forsyth 		error(Eperm);
649*74a4d8c2SCharles.Forsyth 
650*74a4d8c2SCharles.Forsyth 	dt = &uartdir[3 * NETID(c->qid.path)];
651*74a4d8c2SCharles.Forsyth 	convM2D(dp, &d);
652*74a4d8c2SCharles.Forsyth 	d.mode &= 0666;
653*74a4d8c2SCharles.Forsyth 	dt[0].perm = dt[1].perm = d.mode;
654*74a4d8c2SCharles.Forsyth #endif
655*74a4d8c2SCharles.Forsyth }
656*74a4d8c2SCharles.Forsyth 
657*74a4d8c2SCharles.Forsyth Dev uartdevtab = {
658*74a4d8c2SCharles.Forsyth 	't',
659*74a4d8c2SCharles.Forsyth 	"uart",
660*74a4d8c2SCharles.Forsyth 
661*74a4d8c2SCharles.Forsyth 	uartreset,
662*74a4d8c2SCharles.Forsyth 	devinit,
663*74a4d8c2SCharles.Forsyth 	devshutdown,
664*74a4d8c2SCharles.Forsyth 	uartattach,
665*74a4d8c2SCharles.Forsyth 	uartwalk,
666*74a4d8c2SCharles.Forsyth 	uartstat,
667*74a4d8c2SCharles.Forsyth 	uartopen,
668*74a4d8c2SCharles.Forsyth 	devcreate,
669*74a4d8c2SCharles.Forsyth 	uartclose,
670*74a4d8c2SCharles.Forsyth 	uartread,
671*74a4d8c2SCharles.Forsyth 	devbread,
672*74a4d8c2SCharles.Forsyth 	uartwrite,
673*74a4d8c2SCharles.Forsyth 	devbwrite,
674*74a4d8c2SCharles.Forsyth 	devremove,
675*74a4d8c2SCharles.Forsyth 	uartwstat,
676*74a4d8c2SCharles.Forsyth };
677*74a4d8c2SCharles.Forsyth 
678*74a4d8c2SCharles.Forsyth void
uartputc(int c)679*74a4d8c2SCharles.Forsyth uartputc(int c)
680*74a4d8c2SCharles.Forsyth {
681*74a4d8c2SCharles.Forsyth 	UartReg *u;
682*74a4d8c2SCharles.Forsyth 
683*74a4d8c2SCharles.Forsyth 	if (!c)
684*74a4d8c2SCharles.Forsyth 		return;
685*74a4d8c2SCharles.Forsyth 	u = &UARTREG[1];
686*74a4d8c2SCharles.Forsyth 	while ((u->stat & USTAT_TBE) == 0)
687*74a4d8c2SCharles.Forsyth 		;
688*74a4d8c2SCharles.Forsyth 	u->txbuf = c;
689*74a4d8c2SCharles.Forsyth 	if (c == '\n')
690*74a4d8c2SCharles.Forsyth 		while((u->stat & USTAT_TC) == 0)	/* flush xmit fifo */
691*74a4d8c2SCharles.Forsyth 			;
692*74a4d8c2SCharles.Forsyth }
693*74a4d8c2SCharles.Forsyth 
694*74a4d8c2SCharles.Forsyth void
uartputs(char * data,int len)695*74a4d8c2SCharles.Forsyth uartputs(char *data, int len)
696*74a4d8c2SCharles.Forsyth {
697*74a4d8c2SCharles.Forsyth 	int x;
698*74a4d8c2SCharles.Forsyth 
699*74a4d8c2SCharles.Forsyth 	clockpoll();
700*74a4d8c2SCharles.Forsyth 	x = splfhi();
701*74a4d8c2SCharles.Forsyth 	while (len--){
702*74a4d8c2SCharles.Forsyth 		if(*data == '\n')
703*74a4d8c2SCharles.Forsyth 			uartputc('\r');
704*74a4d8c2SCharles.Forsyth 		uartputc(*data++);
705*74a4d8c2SCharles.Forsyth 	}
706*74a4d8c2SCharles.Forsyth 	splx(x);
707*74a4d8c2SCharles.Forsyth }
708*74a4d8c2SCharles.Forsyth 
709*74a4d8c2SCharles.Forsyth int
uartgetc(void)710*74a4d8c2SCharles.Forsyth uartgetc(void)
711*74a4d8c2SCharles.Forsyth {
712*74a4d8c2SCharles.Forsyth 	UartReg *u;
713*74a4d8c2SCharles.Forsyth 
714*74a4d8c2SCharles.Forsyth 	clockcheck();
715*74a4d8c2SCharles.Forsyth 	u = &UARTREG[1];
716*74a4d8c2SCharles.Forsyth 	while((u->stat & USTAT_RDR) == 0)
717*74a4d8c2SCharles.Forsyth 		clockcheck();
718*74a4d8c2SCharles.Forsyth 	return u->rxbuf;
719*74a4d8c2SCharles.Forsyth }
720