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