1*74a4d8c2SCharles.Forsyth #include "boot.h"
2*74a4d8c2SCharles.Forsyth
3*74a4d8c2SCharles.Forsyth /*
4*74a4d8c2SCharles.Forsyth * basic read/write interface to mpc8xx I2C bus (master mode)
5*74a4d8c2SCharles.Forsyth */
6*74a4d8c2SCharles.Forsyth
7*74a4d8c2SCharles.Forsyth typedef struct I2C I2C;
8*74a4d8c2SCharles.Forsyth
9*74a4d8c2SCharles.Forsyth struct I2C {
10*74a4d8c2SCharles.Forsyth uchar i2mod;
11*74a4d8c2SCharles.Forsyth uchar rsv12a[3];
12*74a4d8c2SCharles.Forsyth uchar i2add;
13*74a4d8c2SCharles.Forsyth uchar rsv12b[3];
14*74a4d8c2SCharles.Forsyth uchar i2brg;
15*74a4d8c2SCharles.Forsyth uchar rsv12c[3];
16*74a4d8c2SCharles.Forsyth uchar i2com;
17*74a4d8c2SCharles.Forsyth uchar rsv12d[3];
18*74a4d8c2SCharles.Forsyth uchar i2cer;
19*74a4d8c2SCharles.Forsyth uchar rsv12e[3];
20*74a4d8c2SCharles.Forsyth uchar i2cmr;
21*74a4d8c2SCharles.Forsyth };
22*74a4d8c2SCharles.Forsyth
23*74a4d8c2SCharles.Forsyth enum {
24*74a4d8c2SCharles.Forsyth /* i2c-specific BD flags */
25*74a4d8c2SCharles.Forsyth RxeOV= 1<<1, /* overrun */
26*74a4d8c2SCharles.Forsyth TxS= 1<<10, /* transmit start condition */
27*74a4d8c2SCharles.Forsyth TxeNAK= 1<<2, /* last transmitted byte not acknowledged */
28*74a4d8c2SCharles.Forsyth TxeUN= 1<<1, /* underflow */
29*74a4d8c2SCharles.Forsyth TxeCL= 1<<0, /* collision */
30*74a4d8c2SCharles.Forsyth TxERR= (TxeNAK|TxeUN|TxeCL),
31*74a4d8c2SCharles.Forsyth
32*74a4d8c2SCharles.Forsyth /* i2cmod */
33*74a4d8c2SCharles.Forsyth REVD= 1<<5, /* =1, LSB first */
34*74a4d8c2SCharles.Forsyth GCD= 1<<4, /* =1, general call address disabled */
35*74a4d8c2SCharles.Forsyth FLT= 1<<3, /* =0, not filtered; =1, filtered */
36*74a4d8c2SCharles.Forsyth PDIV= 3<<1, /* predivisor field */
37*74a4d8c2SCharles.Forsyth EN= 1<<0, /* enable */
38*74a4d8c2SCharles.Forsyth
39*74a4d8c2SCharles.Forsyth /* i2com */
40*74a4d8c2SCharles.Forsyth STR= 1<<7, /* start transmit */
41*74a4d8c2SCharles.Forsyth I2CM= 1<<0, /* master */
42*74a4d8c2SCharles.Forsyth I2CS= 0<<0, /* slave */
43*74a4d8c2SCharles.Forsyth
44*74a4d8c2SCharles.Forsyth /* i2cer */
45*74a4d8c2SCharles.Forsyth TXE = 1<<4,
46*74a4d8c2SCharles.Forsyth BSY = 1<<2,
47*74a4d8c2SCharles.Forsyth TXB = 1<<1,
48*74a4d8c2SCharles.Forsyth RXB = 1<<0,
49*74a4d8c2SCharles.Forsyth
50*74a4d8c2SCharles.Forsyth /* port B bits */
51*74a4d8c2SCharles.Forsyth I2CSDA = IBIT(27),
52*74a4d8c2SCharles.Forsyth I2CSCL = IBIT(26),
53*74a4d8c2SCharles.Forsyth
54*74a4d8c2SCharles.Forsyth Rbit = 1<<0, /* bit in address byte denoting read */
55*74a4d8c2SCharles.Forsyth
56*74a4d8c2SCharles.Forsyth /* maximum I2C I/O (can change) */
57*74a4d8c2SCharles.Forsyth Bufsize = 64,
58*74a4d8c2SCharles.Forsyth Tbuflen= Bufsize+4, /* extra address bytes and alignment */
59*74a4d8c2SCharles.Forsyth Freq = 100000,
60*74a4d8c2SCharles.Forsyth I2CTimeout = 250, /* msec */
61*74a4d8c2SCharles.Forsyth };
62*74a4d8c2SCharles.Forsyth
63*74a4d8c2SCharles.Forsyth /* data cache needn't be flushed if buffers allocated in uncached INTMEM */
64*74a4d8c2SCharles.Forsyth #define DCFLUSH(a,n)
65*74a4d8c2SCharles.Forsyth
66*74a4d8c2SCharles.Forsyth /*
67*74a4d8c2SCharles.Forsyth * I2C software structures
68*74a4d8c2SCharles.Forsyth */
69*74a4d8c2SCharles.Forsyth
70*74a4d8c2SCharles.Forsyth struct Ctlr {
71*74a4d8c2SCharles.Forsyth Lock;
72*74a4d8c2SCharles.Forsyth QLock io;
73*74a4d8c2SCharles.Forsyth int init;
74*74a4d8c2SCharles.Forsyth I2C* i2c;
75*74a4d8c2SCharles.Forsyth IOCparam* sp;
76*74a4d8c2SCharles.Forsyth
77*74a4d8c2SCharles.Forsyth BD* rd;
78*74a4d8c2SCharles.Forsyth BD* td;
79*74a4d8c2SCharles.Forsyth int phase;
80*74a4d8c2SCharles.Forsyth char* addr;
81*74a4d8c2SCharles.Forsyth char* txbuf;
82*74a4d8c2SCharles.Forsyth char* rxbuf;
83*74a4d8c2SCharles.Forsyth };
84*74a4d8c2SCharles.Forsyth typedef struct Ctlr Ctlr;
85*74a4d8c2SCharles.Forsyth
86*74a4d8c2SCharles.Forsyth static Ctlr i2ctlr[1];
87*74a4d8c2SCharles.Forsyth extern int predawn;
88*74a4d8c2SCharles.Forsyth
89*74a4d8c2SCharles.Forsyth static void interrupt(Ureg*, void*);
90*74a4d8c2SCharles.Forsyth
91*74a4d8c2SCharles.Forsyth static void
enable(void)92*74a4d8c2SCharles.Forsyth enable(void)
93*74a4d8c2SCharles.Forsyth {
94*74a4d8c2SCharles.Forsyth I2C *i2c;
95*74a4d8c2SCharles.Forsyth
96*74a4d8c2SCharles.Forsyth i2c = i2ctlr->i2c;
97*74a4d8c2SCharles.Forsyth i2c->i2cer = ~0; /* clear events */
98*74a4d8c2SCharles.Forsyth eieio();
99*74a4d8c2SCharles.Forsyth i2c->i2mod |= EN;
100*74a4d8c2SCharles.Forsyth eieio();
101*74a4d8c2SCharles.Forsyth i2c->i2cmr = TXE|BSY|TXB|RXB; /* enable all interrupts */
102*74a4d8c2SCharles.Forsyth eieio();
103*74a4d8c2SCharles.Forsyth }
104*74a4d8c2SCharles.Forsyth
105*74a4d8c2SCharles.Forsyth static void
disable(void)106*74a4d8c2SCharles.Forsyth disable(void)
107*74a4d8c2SCharles.Forsyth {
108*74a4d8c2SCharles.Forsyth I2C *i2c;
109*74a4d8c2SCharles.Forsyth
110*74a4d8c2SCharles.Forsyth i2c = i2ctlr->i2c;
111*74a4d8c2SCharles.Forsyth i2c->i2cmr = 0; /* mask all interrupts */
112*74a4d8c2SCharles.Forsyth i2c->i2mod &= ~EN;
113*74a4d8c2SCharles.Forsyth }
114*74a4d8c2SCharles.Forsyth
115*74a4d8c2SCharles.Forsyth /*
116*74a4d8c2SCharles.Forsyth * called by the reset routine of any driver using the I2C
117*74a4d8c2SCharles.Forsyth */
118*74a4d8c2SCharles.Forsyth void
i2csetup(void)119*74a4d8c2SCharles.Forsyth i2csetup(void)
120*74a4d8c2SCharles.Forsyth {
121*74a4d8c2SCharles.Forsyth IMM *io;
122*74a4d8c2SCharles.Forsyth I2C *i2c;
123*74a4d8c2SCharles.Forsyth IOCparam *sp;
124*74a4d8c2SCharles.Forsyth Ctlr *ctlr;
125*74a4d8c2SCharles.Forsyth long f, e, emin;
126*74a4d8c2SCharles.Forsyth int p, d, dmax;
127*74a4d8c2SCharles.Forsyth
128*74a4d8c2SCharles.Forsyth ctlr = i2ctlr;
129*74a4d8c2SCharles.Forsyth if(ctlr->init)
130*74a4d8c2SCharles.Forsyth return;
131*74a4d8c2SCharles.Forsyth print("i2c setup...\n");
132*74a4d8c2SCharles.Forsyth ctlr->init = 1;
133*74a4d8c2SCharles.Forsyth i2c = KADDR(INTMEM+0x860);
134*74a4d8c2SCharles.Forsyth ctlr->i2c = i2c;
135*74a4d8c2SCharles.Forsyth sp = KADDR(INTMEM+0x3c80);
136*74a4d8c2SCharles.Forsyth ctlr->sp = sp;
137*74a4d8c2SCharles.Forsyth disable();
138*74a4d8c2SCharles.Forsyth
139*74a4d8c2SCharles.Forsyth if(ctlr->txbuf == nil){
140*74a4d8c2SCharles.Forsyth ctlr->txbuf = ialloc(Tbuflen, 2);
141*74a4d8c2SCharles.Forsyth ctlr->addr = ctlr->txbuf+Bufsize;
142*74a4d8c2SCharles.Forsyth }
143*74a4d8c2SCharles.Forsyth if(ctlr->rxbuf == nil)
144*74a4d8c2SCharles.Forsyth ctlr->rxbuf = ialloc(Bufsize, 2);
145*74a4d8c2SCharles.Forsyth if(ctlr->rd == nil){
146*74a4d8c2SCharles.Forsyth ctlr->rd = bdalloc(1);
147*74a4d8c2SCharles.Forsyth ctlr->rd->addr = PADDR(ctlr->rxbuf);
148*74a4d8c2SCharles.Forsyth ctlr->rd->length = 0;
149*74a4d8c2SCharles.Forsyth ctlr->rd->status = BDWrap;
150*74a4d8c2SCharles.Forsyth }
151*74a4d8c2SCharles.Forsyth if(ctlr->td == nil){
152*74a4d8c2SCharles.Forsyth ctlr->td = bdalloc(2);
153*74a4d8c2SCharles.Forsyth ctlr->td->addr = PADDR(ctlr->txbuf);
154*74a4d8c2SCharles.Forsyth ctlr->td->length = 0;
155*74a4d8c2SCharles.Forsyth ctlr->td->status = BDWrap|BDLast;
156*74a4d8c2SCharles.Forsyth }
157*74a4d8c2SCharles.Forsyth
158*74a4d8c2SCharles.Forsyth /* select port pins */
159*74a4d8c2SCharles.Forsyth io = ioplock();
160*74a4d8c2SCharles.Forsyth io->pbdir |= I2CSDA | I2CSCL;
161*74a4d8c2SCharles.Forsyth io->pbodr |= I2CSDA | I2CSCL;
162*74a4d8c2SCharles.Forsyth io->pbpar |= I2CSDA | I2CSCL;
163*74a4d8c2SCharles.Forsyth iopunlock();
164*74a4d8c2SCharles.Forsyth
165*74a4d8c2SCharles.Forsyth /* explicitly initialise parameters, because InitRxTx can't be used (see i2c/spi relocation errata) */
166*74a4d8c2SCharles.Forsyth sp = ctlr->sp;
167*74a4d8c2SCharles.Forsyth sp->rbase = PADDR(ctlr->rd);
168*74a4d8c2SCharles.Forsyth sp->tbase = PADDR(ctlr->td);
169*74a4d8c2SCharles.Forsyth sp->rfcr = 0x18;
170*74a4d8c2SCharles.Forsyth sp->tfcr = 0x18;
171*74a4d8c2SCharles.Forsyth sp->mrblr = Bufsize;
172*74a4d8c2SCharles.Forsyth sp->rstate = 0;
173*74a4d8c2SCharles.Forsyth sp->rptr = 0;
174*74a4d8c2SCharles.Forsyth sp->rbptr = sp->rbase;
175*74a4d8c2SCharles.Forsyth sp->rcnt = 0;
176*74a4d8c2SCharles.Forsyth sp->tstate = 0;
177*74a4d8c2SCharles.Forsyth sp->tbptr = sp->tbase;
178*74a4d8c2SCharles.Forsyth sp->tptr = 0;
179*74a4d8c2SCharles.Forsyth sp->tcnt = 0;
180*74a4d8c2SCharles.Forsyth eieio();
181*74a4d8c2SCharles.Forsyth
182*74a4d8c2SCharles.Forsyth i2c->i2com = I2CM;
183*74a4d8c2SCharles.Forsyth i2c->i2mod = 0; /* normal mode */
184*74a4d8c2SCharles.Forsyth i2c->i2add = 0;
185*74a4d8c2SCharles.Forsyth
186*74a4d8c2SCharles.Forsyth emin = Freq;
187*74a4d8c2SCharles.Forsyth dmax = (m->cpuhz/Freq)/2-3;
188*74a4d8c2SCharles.Forsyth for(d=0; d < dmax; d++){
189*74a4d8c2SCharles.Forsyth for(p=3; p>=0; p--){
190*74a4d8c2SCharles.Forsyth f = (m->cpuhz>>(p+2))/(2*(d+3));
191*74a4d8c2SCharles.Forsyth e = Freq - f;
192*74a4d8c2SCharles.Forsyth if(e < 0)
193*74a4d8c2SCharles.Forsyth e = -e;
194*74a4d8c2SCharles.Forsyth if(e < emin){
195*74a4d8c2SCharles.Forsyth emin = e;
196*74a4d8c2SCharles.Forsyth i2c->i2brg = d;
197*74a4d8c2SCharles.Forsyth i2c->i2mod = (i2c->i2mod&~PDIV)|((3-p)<<1); /* set PDIV */
198*74a4d8c2SCharles.Forsyth }
199*74a4d8c2SCharles.Forsyth }
200*74a4d8c2SCharles.Forsyth }
201*74a4d8c2SCharles.Forsyth //print("i2brg=%d i2mod=#%2.2ux\n", i2c->i2brg, i2c->i2mod);
202*74a4d8c2SCharles.Forsyth setvec(VectorCPIC+0x10, interrupt, i2ctlr);
203*74a4d8c2SCharles.Forsyth }
204*74a4d8c2SCharles.Forsyth
205*74a4d8c2SCharles.Forsyth enum {
206*74a4d8c2SCharles.Forsyth Idling,
207*74a4d8c2SCharles.Forsyth Done,
208*74a4d8c2SCharles.Forsyth Busy,
209*74a4d8c2SCharles.Forsyth Sending,
210*74a4d8c2SCharles.Forsyth Recving,
211*74a4d8c2SCharles.Forsyth };
212*74a4d8c2SCharles.Forsyth
213*74a4d8c2SCharles.Forsyth static void
interrupt(Ureg *,void * arg)214*74a4d8c2SCharles.Forsyth interrupt(Ureg*, void *arg)
215*74a4d8c2SCharles.Forsyth {
216*74a4d8c2SCharles.Forsyth int events;
217*74a4d8c2SCharles.Forsyth Ctlr *ctlr;
218*74a4d8c2SCharles.Forsyth I2C *i2c;
219*74a4d8c2SCharles.Forsyth
220*74a4d8c2SCharles.Forsyth ctlr = arg;
221*74a4d8c2SCharles.Forsyth i2c = ctlr->i2c;
222*74a4d8c2SCharles.Forsyth events = i2c->i2cer;
223*74a4d8c2SCharles.Forsyth eieio();
224*74a4d8c2SCharles.Forsyth i2c->i2cer = events;
225*74a4d8c2SCharles.Forsyth if(events & (BSY|TXE)){
226*74a4d8c2SCharles.Forsyth //print("I2C#%x\n", events);
227*74a4d8c2SCharles.Forsyth if(ctlr->phase != Idling){
228*74a4d8c2SCharles.Forsyth ctlr->phase = Idling;
229*74a4d8c2SCharles.Forsyth }
230*74a4d8c2SCharles.Forsyth }else{
231*74a4d8c2SCharles.Forsyth if(events & TXB){
232*74a4d8c2SCharles.Forsyth //print("i2c: xmt %d %4.4ux %4.4ux\n", ctlr->phase, ctlr->td->status, ctlr->td[1].status);
233*74a4d8c2SCharles.Forsyth if(ctlr->phase == Sending){
234*74a4d8c2SCharles.Forsyth ctlr->phase = Done;
235*74a4d8c2SCharles.Forsyth }
236*74a4d8c2SCharles.Forsyth }
237*74a4d8c2SCharles.Forsyth if(events & RXB){
238*74a4d8c2SCharles.Forsyth //print("i2c: rcv %d %4.4ux %d\n", ctlr->phase, ctlr->rd->status, ctlr->rd->length);
239*74a4d8c2SCharles.Forsyth if(ctlr->phase == Recving){
240*74a4d8c2SCharles.Forsyth ctlr->phase = Done;
241*74a4d8c2SCharles.Forsyth }
242*74a4d8c2SCharles.Forsyth }
243*74a4d8c2SCharles.Forsyth }
244*74a4d8c2SCharles.Forsyth }
245*74a4d8c2SCharles.Forsyth
246*74a4d8c2SCharles.Forsyth static int
done(void * a)247*74a4d8c2SCharles.Forsyth done(void *a)
248*74a4d8c2SCharles.Forsyth {
249*74a4d8c2SCharles.Forsyth return ((Ctlr*)a)->phase < Busy;
250*74a4d8c2SCharles.Forsyth }
251*74a4d8c2SCharles.Forsyth
252*74a4d8c2SCharles.Forsyth static void
i2cwait(Ctlr * ctlr)253*74a4d8c2SCharles.Forsyth i2cwait(Ctlr *ctlr)
254*74a4d8c2SCharles.Forsyth {
255*74a4d8c2SCharles.Forsyth /* TO DO: timeout */
256*74a4d8c2SCharles.Forsyth while(!done(ctlr)){
257*74a4d8c2SCharles.Forsyth if(predawn)
258*74a4d8c2SCharles.Forsyth interrupt(nil, ctlr);
259*74a4d8c2SCharles.Forsyth }
260*74a4d8c2SCharles.Forsyth }
261*74a4d8c2SCharles.Forsyth
262*74a4d8c2SCharles.Forsyth long
i2csend(int addr,void * buf,long n)263*74a4d8c2SCharles.Forsyth i2csend(int addr, void *buf, long n)
264*74a4d8c2SCharles.Forsyth {
265*74a4d8c2SCharles.Forsyth Ctlr *ctlr;
266*74a4d8c2SCharles.Forsyth int i, p, s;
267*74a4d8c2SCharles.Forsyth
268*74a4d8c2SCharles.Forsyth ctlr = i2ctlr;
269*74a4d8c2SCharles.Forsyth if(n > Bufsize)
270*74a4d8c2SCharles.Forsyth return -1;
271*74a4d8c2SCharles.Forsyth i = 1;
272*74a4d8c2SCharles.Forsyth ctlr->txbuf[0] = addr & ~1;
273*74a4d8c2SCharles.Forsyth if(addr & 1){
274*74a4d8c2SCharles.Forsyth ctlr->txbuf[1] = addr>>8;
275*74a4d8c2SCharles.Forsyth i++;
276*74a4d8c2SCharles.Forsyth }
277*74a4d8c2SCharles.Forsyth memmove(ctlr->txbuf+i, buf, n);
278*74a4d8c2SCharles.Forsyth DCFLUSH(ctlr->txbuf, Tbuflen);
279*74a4d8c2SCharles.Forsyth ctlr->phase = Sending;
280*74a4d8c2SCharles.Forsyth ctlr->rd->status = BDEmpty|BDWrap|BDInt;
281*74a4d8c2SCharles.Forsyth ctlr->td->addr = PADDR(ctlr->txbuf);
282*74a4d8c2SCharles.Forsyth ctlr->td->length = n+i;
283*74a4d8c2SCharles.Forsyth ctlr->td->status = BDReady|BDWrap|BDLast|BDInt;
284*74a4d8c2SCharles.Forsyth enable();
285*74a4d8c2SCharles.Forsyth ctlr->i2c->i2com = STR|I2CM;
286*74a4d8c2SCharles.Forsyth eieio();
287*74a4d8c2SCharles.Forsyth i2cwait(ctlr);
288*74a4d8c2SCharles.Forsyth disable();
289*74a4d8c2SCharles.Forsyth p = ctlr->phase;
290*74a4d8c2SCharles.Forsyth s = ctlr->td->status;
291*74a4d8c2SCharles.Forsyth if(s & BDReady || s & TxERR || p != Done)
292*74a4d8c2SCharles.Forsyth return -1;
293*74a4d8c2SCharles.Forsyth return n;
294*74a4d8c2SCharles.Forsyth }
295*74a4d8c2SCharles.Forsyth
296*74a4d8c2SCharles.Forsyth long
i2crecv(int addr,void * buf,long n)297*74a4d8c2SCharles.Forsyth i2crecv(int addr, void *buf, long n)
298*74a4d8c2SCharles.Forsyth {
299*74a4d8c2SCharles.Forsyth Ctlr *ctlr;
300*74a4d8c2SCharles.Forsyth int p, s, flag;
301*74a4d8c2SCharles.Forsyth BD *td;
302*74a4d8c2SCharles.Forsyth long nr;
303*74a4d8c2SCharles.Forsyth
304*74a4d8c2SCharles.Forsyth ctlr = i2ctlr;
305*74a4d8c2SCharles.Forsyth if(n > Bufsize)
306*74a4d8c2SCharles.Forsyth return -1;
307*74a4d8c2SCharles.Forsyth ctlr->txbuf[0] = addr|Rbit;
308*74a4d8c2SCharles.Forsyth if(addr & 1){ /* special select sequence */
309*74a4d8c2SCharles.Forsyth ctlr->addr[0] = addr &~ 1;
310*74a4d8c2SCharles.Forsyth ctlr->addr[1] = addr>>8;
311*74a4d8c2SCharles.Forsyth }
312*74a4d8c2SCharles.Forsyth DCFLUSH(ctlr->txbuf, Tbuflen);
313*74a4d8c2SCharles.Forsyth DCFLUSH(ctlr->rxbuf, Bufsize);
314*74a4d8c2SCharles.Forsyth ctlr->phase = Recving;
315*74a4d8c2SCharles.Forsyth ctlr->rd->addr = PADDR(ctlr->rxbuf);
316*74a4d8c2SCharles.Forsyth ctlr->rd->status = BDEmpty|BDWrap|BDInt;
317*74a4d8c2SCharles.Forsyth flag = 0;
318*74a4d8c2SCharles.Forsyth td = ctlr->td;
319*74a4d8c2SCharles.Forsyth td[1].status = 0;
320*74a4d8c2SCharles.Forsyth if(addr & 1){
321*74a4d8c2SCharles.Forsyth /* special select sequence */
322*74a4d8c2SCharles.Forsyth td->addr = PADDR(ctlr->addr);
323*74a4d8c2SCharles.Forsyth td->length = 2;
324*74a4d8c2SCharles.Forsyth /* td->status made BDReady below */
325*74a4d8c2SCharles.Forsyth td++;
326*74a4d8c2SCharles.Forsyth flag = TxS;
327*74a4d8c2SCharles.Forsyth }
328*74a4d8c2SCharles.Forsyth td->addr = PADDR(ctlr->txbuf);
329*74a4d8c2SCharles.Forsyth td->length = n+1;
330*74a4d8c2SCharles.Forsyth td->status = BDReady|BDWrap|BDLast | flag; /* not BDInt: leave that to receive */
331*74a4d8c2SCharles.Forsyth if(flag)
332*74a4d8c2SCharles.Forsyth ctlr->td->status = BDReady;
333*74a4d8c2SCharles.Forsyth enable();
334*74a4d8c2SCharles.Forsyth ctlr->i2c->i2com = STR|I2CM;
335*74a4d8c2SCharles.Forsyth eieio();
336*74a4d8c2SCharles.Forsyth i2cwait(ctlr);
337*74a4d8c2SCharles.Forsyth disable();
338*74a4d8c2SCharles.Forsyth p = ctlr->phase;
339*74a4d8c2SCharles.Forsyth s = ctlr->td->status;
340*74a4d8c2SCharles.Forsyth if(flag)
341*74a4d8c2SCharles.Forsyth s |= ctlr->td[1].status;
342*74a4d8c2SCharles.Forsyth nr = ctlr->rd->length;
343*74a4d8c2SCharles.Forsyth if(nr > n)
344*74a4d8c2SCharles.Forsyth nr = n; /* shouldn't happen */
345*74a4d8c2SCharles.Forsyth if(s & TxERR || s & BDReady || ctlr->rd->status & BDEmpty)
346*74a4d8c2SCharles.Forsyth return -1;
347*74a4d8c2SCharles.Forsyth if(p != Done)
348*74a4d8c2SCharles.Forsyth return -1;
349*74a4d8c2SCharles.Forsyth memmove(buf, ctlr->rxbuf, nr);
350*74a4d8c2SCharles.Forsyth return nr;
351*74a4d8c2SCharles.Forsyth }
352