|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "../port/error.h"
7: #include "devtab.h"
8:
9: #include "io.h"
10:
11: /* Centronix parallel (printer) port */
12:
13: typedef struct Lptinfo Lptinfo;
14:
15: struct Lptinfo
16: {
17: int base; /* port number */
18: int ivec; /* interrupt number */
19: };
20:
21: static Lptinfo lptinfo[] = {
22: 0x3bc, Parallelvec, /* lpt1 (safari) */
23: 0x378, Parallelvec, /* lpt1 (`official') */
24: 0x278, Int0vec+5, /* lpt2 (`official') */
25: };
26: #define NDEV (sizeof lptinfo/sizeof lptinfo[0])
27:
28: extern int incondev; /* from config */
29:
30: /* offsets, and bits in the registers */
31: enum
32: {
33: /* data latch register */
34: Qdlr= 0x0,
35: /* printer status register */
36: Qpsr= 0x1,
37: Fbusy= 0x80,
38: Fintbar= 0x40,
39: /* printer control register */
40: Qpcr= 0x2,
41: Fie= 0x10,
42: Fsi= 0x08,
43: Finitbar= 0x04,
44: Faf= 0x02,
45: Fstrobe= 0x01,
46:
47: /* other `registers' */
48: Qstats= 0x03,
49: Qdebug= 0x04
50: };
51:
52: /*
53: * af si dlr<7:0>
54: * 0 x xxxxxxxx wr ctl/data char (si is dcto)
55: * 1 0 xxxxxxxx wr cmd
56: * 1 1 xxxxxx00 rd ctl/data char
57: * 1 1 xxxxxx01 rd status
58: * 1 1 xxxxxx11 nop (multiplexer to normal state)
59: *
60: * psr<7:3> multiplexed as follows:
61: *
62: * bc7 bc6 bc5 bc4 bc3
63: * rd, st- low bsy d8 d7 d6 d5
64: * rd, st- high d4 d3 d2 d1 d0
65: * other bsy int-
66: */
67:
68: typedef struct Incon Incon;
69:
70: #define NOW (MACHP(0)->ticks*MS2HZ)
71:
72: #define DPRINT if(incondebug)kprint
73:
74: static void inconintr(Ureg *ur, void *a);
75:
76: enum {
77: Minstation= 2, /* lowest station # to poll */
78: Maxstation= 15, /* highest station # to poll */
79: Nincon= 1, /* number of incons */
80: Nin= 32, /* Blocks in the input ring */
81: Bsize= 128, /* size of an input ring block */
82: Mfifo= 0xff /* a mask, must be 2^n-1, must be > Nin */
83: };
84:
85: struct Incon {
86: QLock;
87:
88: QLock xmit; /* transmit lock */
89: QLock reslock; /* reset lock */
90: int dev; /* base address of port */
91: int station; /* station number */
92: int state; /* chip state */
93: Rendez r; /* output process */
94: Rendez kr; /* input kernel process */
95: ushort chan; /* current input channel */
96: Queue *rq; /* read queue */
97: int kstarted; /* true if kernel process started */
98:
99: /* input blocks */
100:
101: Block *inb[Nin];
102: ushort wi;
103: ushort ri;
104:
105: /* statistics */
106:
107: ulong overflow; /* overflow errors */
108: ulong pack0; /* channel 0 */
109: ulong crc; /* crc errors */
110: ulong in; /* bytes in */
111: ulong out; /* bytes out */
112: ulong wait; /* wait time in milliseconds */
113: };
114:
115: Incon incon[Nincon];
116:
117: /*
118: * chip state
119: */
120: enum {
121: Selecting,
122: Selected,
123: Notliving,
124: };
125:
126: /*
127: * internal chip registers
128: */
129: #define sel_polln 0
130: #define sel_station 1
131: #define sel_poll0 2
132: #define sel_rcv_cnt 3
133: #define sel_rcv_tim 4
134: #define sel_tx_cnt 5
135:
136: /*
137: * CSR bits
138: */
139: #define INCON_RUN 0x80
140: #define INCON_STOP 0x00
141: #define ENABLE_IRQ 0x40
142: #define ENABLE_TX_IRQ 0x20
143: #define INCON_ALIVE 0x80
144: #define TX_FULL 0x10
145: #define TX_EMPTY 0x08
146: #define RCV_EMPTY 0x04
147: #define OVERFLOW 0x02
148: #define CRC_ERROR 0x01
149:
150: /*
151: * polling constants
152: */
153: #define HT_GNOT 0x30
154: #define HT_UNIX 0x31
155: #define ST_UNIX 0x04
156: #define NCHAN 64
157:
158: static void inconkproc(void*);
159:
160: /*
161: * incon stream module definition
162: */
163: static void inconoput(Queue*, Block*);
164: static void inconstopen(Queue*, Stream*);
165: static void inconstclose(Queue*);
166: Qinfo inconinfo =
167: {
168: nullput,
169: inconoput,
170: inconstopen,
171: inconstclose,
172: "incon"
173: };
174:
175: int incondebug = 0;
176:
177: Dirtab incondir[]={
178: "dlr", {Qdlr}, 1, 0666,
179: "psr", {Qpsr}, 5, 0444,
180: "pcr", {Qpcr}, 0, 0666,
181: "stats", {Qstats}, 0, 0444,
182: "debug", {Qdebug}, 0, 0666,
183: };
184: #define NINCON (sizeof incondir/sizeof incondir[0])
185:
186: static void
187: nop(void)
188: {
189: }
190:
191: static int
192: slowinb(int x)
193: {
194: nop();
195: nop();
196: return inb(x);
197: }
198:
199: static void
200: reset(int dev) /* hardware reset */
201: {
202: outb(dev+Qpcr, Finitbar);
203: outb(dev+Qpcr, 0);
204: outb(dev+Qpcr, Finitbar);
205: }
206:
207: static void
208: wrctl(int dev, int data) /* write control character */
209: {
210: outb(dev+Qpcr, Finitbar); /* no interrupts, please */
211: outb(dev+Qdlr, data);
212: outb(dev+Qpcr, Finitbar|Fstrobe);
213: outb(dev+Qpcr, Finitbar|Fie);
214: }
215:
216: static void
217: wrdata(int dev, int data) /* write data character */
218: {
219: outb(dev+Qpcr, Finitbar|Fsi);
220: outb(dev+Qdlr, data);
221: outb(dev+Qpcr, Finitbar|Fsi|Fstrobe);
222: outb(dev+Qpcr, Finitbar|Fsi|Fie);
223: }
224:
225: static void
226: wrcmd(int dev, int data) /* write command */
227: {
228: outb(dev+Qpcr, Finitbar|Faf);
229: outb(dev+Qdlr, data);
230: outb(dev+Qpcr, Finitbar|Faf|Fstrobe);
231: outb(dev+Qpcr, Finitbar|Faf|Fie);
232: }
233:
234: static int
235: rdstatus(Incon *ip) /* read status */
236: {
237: int dev, data;
238:
239: dev = ip->dev;
240:
241: outb(dev+Qpcr, Finitbar|Faf|Fsi);
242: outb(dev+Qdlr, 0x01);
243: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
244: data = (inb(dev+Qpsr)&0xf8)<<2;
245: outb(dev+Qpcr, Finitbar|Faf|Fsi);
246: data |= inb(dev+Qpsr)>>3;
247: if(data&(OVERFLOW|CRC_ERROR)){
248: if(data&OVERFLOW)
249: ip->overflow++;
250: if(data&CRC_ERROR)
251: ip->crc++;
252: }
253: outb(dev+Qdlr, 0x03);
254: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
255: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fie);
256:
257: return data;
258: }
259:
260: static void
261: iwrcmd(int dev, int data) /* write command at interrupt level */
262: {
263: outb(dev+Qdlr, data);
264: outb(dev+Qpcr, Finitbar|Faf|Fstrobe);
265: outb(dev+Qpcr, Finitbar|Faf);
266: }
267:
268: static int
269: irdstatus(Incon *ip) /* read status at interrupt level */
270: {
271: int dev, data;
272:
273: dev = ip->dev;
274:
275: outb(dev+Qdlr, 0x01);
276: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
277: data = (slowinb(dev+Qpsr)&0xf8)<<2;
278: outb(dev+Qpcr, Finitbar|Faf|Fsi);
279: data |= slowinb(dev+Qpsr)>>3;
280: if(data&(OVERFLOW|CRC_ERROR)){
281: if(data&OVERFLOW)
282: ip->overflow++;
283: if(data&CRC_ERROR)
284: ip->crc++;
285: }
286:
287: return data;
288: }
289:
290: static int
291: irddata(int dev) /* read data at interrupt level */
292: {
293: int data;
294:
295: outb(dev+Qdlr, 0x00);
296: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
297: data = (slowinb(dev+Qpsr)&0xf8)<<2;
298: outb(dev+Qpcr, Finitbar|Faf|Fsi);
299: data |= slowinb(dev+Qpsr)>>3;
300:
301: return data;
302: }
303:
304: static int
305: irdnext(int dev) /* read next data at interrupt level */
306: {
307: int data;
308:
309: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
310: data = (inb(dev+Qpsr)&0xf8)<<2;
311: outb(dev+Qpcr, Finitbar|Faf|Fsi);
312: data |= inb(dev+Qpsr)>>3;
313:
314: return data;
315: }
316:
317: static void
318: irdnop(int dev, int pcr) /* read nop (mux reset) */
319: {
320: outb(dev+Qdlr, 0x03);
321: outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
322: outb(dev+Qpcr, pcr);
323: }
324:
325: int Irdnext(int);
326: #define irdnext Irdnext
327: /**/
328:
329: /*
330: * set the incon parameters
331: */
332: void
333: inconset(Incon *ip, int cnt, int del)
334: {
335: int dev;
336:
337: if (cnt<1 || cnt>14 || del<1 || del>15)
338: error(Ebadarg);
339:
340: dev = ip->dev;
341: wrcmd(dev, sel_rcv_cnt | INCON_RUN);
342: wrdata(dev, cnt);
343: wrcmd(dev, sel_rcv_tim | INCON_RUN);
344: wrdata(dev, del);
345: wrcmd(dev, INCON_RUN | ENABLE_IRQ);
346: }
347:
348: /*
349: * parse a set request
350: */
351: void
352: inconsetctl(Incon *ip, Block *bp)
353: {
354: char *field[3];
355: int n;
356: int del;
357: int cnt;
358:
359: del = 15;
360: n = getfields((char *)bp->rptr, field, 3, " ");
361: switch(n){
362: default:
363: freeb(bp);
364: error(Ebadarg);
365: case 2:
366: del = strtol(field[1], 0, 0);
367: if(del<0 || del>15){
368: freeb(bp);
369: error(Ebadarg);
370: }
371: /* fall through */
372: case 1:
373: cnt = strtol(field[0], 0, 0);
374: if(cnt<0 || cnt>15){
375: freeb(bp);
376: error(Ebadarg);
377: }
378: }
379: inconset(ip, cnt, del);
380: freeb(bp);
381: }
382:
383: /*
384: * poll for a station number
385: */
386: void
387: inconpoll(Incon *ip, int station)
388: {
389: ulong timer;
390: int dev;
391: char *p;
392:
393: dev = ip->dev;
394:
395: /*
396: * get us to a known state
397: */
398: ip->state = Notliving;
399: wrcmd(dev, INCON_STOP);
400:
401: /*
402: * try a station number
403: */
404: wrcmd(dev, sel_station);
405: wrdata(dev, station);
406: wrcmd(dev, sel_poll0);
407: wrdata(dev, HT_GNOT);
408: wrcmd(dev, sel_rcv_cnt);
409: wrdata(dev, 3);
410: wrcmd(dev, sel_rcv_tim);
411: wrdata(dev, 15);
412: wrcmd(dev, sel_tx_cnt);
413: wrdata(dev, 1);
414: wrcmd(dev, sel_polln);
415: wrdata(dev, 0x00);
416: wrdata(dev, ST_UNIX);
417: wrdata(dev, NCHAN);
418: for(p = "gnot"; *p; p++)
419: wrdata(dev, *p);
420: wrctl(dev, 0);
421:
422: /*
423: * poll and wait for ready (or 1/4 second)
424: */
425: ip->state = Selecting;
426: wrcmd(dev, INCON_RUN | ENABLE_IRQ);
427: timer = NOW + 250;
428: while (NOW < timer) {
429: nop();
430: if(rdstatus(ip) & INCON_ALIVE){
431: ip->station = station;
432: ip->state = Selected;
433: break;
434: }
435: }
436: }
437:
438: /*
439: * reset the chip and find a new station number
440: */
441: void
442: inconrestart(Incon *ip)
443: {
444: int i;
445:
446: if(!canqlock(&ip->reslock))
447: return;
448:
449: /*
450: * poll for incon station numbers
451: */
452: DPRINT("inconrestart\n");
453: for(i = Minstation; i <= Maxstation; i++){
454: inconpoll(ip, i);
455: if(ip->state == Selected)
456: break;
457: }
458: switch(ip->state) {
459: case Selecting:
460: DPRINT("incon[%d] not polled\n", ip-incon);
461: print("incon[%d] not polled\n", ip-incon);
462: break;
463: case Selected:
464: DPRINT("incon[%d] station %d\n", ip-incon, ip->station);
465: print("incon[%d] station %d\n", ip-incon, ip->station);
466: inconset(ip, 3, 15);
467: break;
468: default:
469: DPRINT("incon[%d] bollixed\n", ip-incon);
470: print("incon[%d] bollixed\n", ip-incon);
471: break;
472: }
473: qunlock(&ip->reslock);
474: }
475:
476: /*
477: * reset all incon chips.
478: */
479:
480: void
481: inconreset(void)
482: {
483: int i;
484: char *p;
485:
486: /*
487: * get incondev from p9rc
488: */
489: p = getconf("incondev");
490: if(p)
491: incondev = atoi(p);
492:
493: /*
494: * state is Selected if we used incon as the boot device
495: * i.e. we've already got a station number.
496: * state is Selecting if this is a first-time open.
497: */
498: /* inconset(&incon[0], 3, 15); /**/
499: for(i=0; i<Nincon; i++){
500: incon[i].dev = lptinfo[incondev].base;
501: incon[i].state = Notliving;
502: reset(incon[i].dev);
503: incon[i].ri = incon[i].wi = 0;
504: }
505: incon[0].state = Selecting;
506: wrcmd(incon[0].dev, INCON_STOP);
507: }
508:
509: void
510: inconinit(void)
511: {
512: wrcmd(incon[0].dev, INCON_STOP);
513: }
514:
515: /*
516: * enable the device for interrupts, spec is the device number
517: */
518: Chan*
519: inconattach(char *spec)
520: {
521: Incon *ip;
522: int i;
523: Chan *c;
524:
525: setvec(lptinfo[incondev].ivec, inconintr, 0);
526: i = strtoul(spec, 0, 0);
527: if(i >= Nincon)
528: error(Ebadarg);
529: ip = &incon[i];
530: rdstatus(ip);
531: if(ip->state != Selected)
532: inconrestart(ip);
533:
534: c = devattach('i', spec);
535: c->dev = i;
536: c->qid.path = CHDIR;
537: c->qid.vers = 0;
538: return c;
539: }
540:
541: Chan*
542: inconclone(Chan *c, Chan *nc)
543: {
544: return devclone(c, nc);
545: }
546:
547: int
548: inconwalk(Chan *c, char *name)
549: {
550: return devwalk(c, name, incondir, NINCON, streamgen);
551: }
552:
553: void
554: inconstat(Chan *c, char *dp)
555: {
556: devstat(c, dp, incondir, NINCON, streamgen);
557: }
558:
559: Chan*
560: inconopen(Chan *c, int omode)
561: {
562: if(c->qid.path != CHDIR && c->qid.path >= Slowqid)
563: streamopen(c, &inconinfo);
564: c->mode = openmode(omode);
565: c->flag |= COPEN;
566: c->offset = 0;
567: return c;
568: }
569:
570: void
571: inconcreate(Chan *c, char *name, int omode, ulong perm)
572: {
573: USED(c, name, omode, perm);
574: error(Eperm);
575: }
576:
577: void
578: inconclose(Chan *c)
579: {
580: if(c->qid.path != CHDIR && c->qid.path >= Slowqid)
581: streamclose(c);
582: }
583:
584: long
585: inconread(Chan *c, void *buf, long n, ulong offset)
586: {
587: char b[256];
588: Incon *ip;
589:
590: if(c->qid.path == CHDIR)
591: return devdirread(c, buf, n, incondir, NINCON, streamgen);
592: ip = &incon[c->dev];
593: switch(c->qid.path){
594: default:
595: return streamread(c, buf, n);
596: case Qdlr:
597: case Qpsr:
598: case Qpcr:
599: sprint(b, "0x%2.2ux\n", inb(ip->dev + c->qid.path));
600: break;
601: case Qstats:
602: sprint(b, "state: %d\nstation: %d\nin: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n",
603: ip->state, ip->station, ip->in, ip->out, ip->overflow, ip->crc, ip->wait);
604: break;
605: case Qdebug:
606: sprint(b, "%d\n", incondebug);
607: break;
608: }
609: return readstr(offset, buf, n, b);
610: }
611:
612: long
613: inconwrite(Chan *c, void *buf, long n, ulong offset)
614: {
615: char b[8];
616: Incon *ip;
617: int data;
618:
619: USED(offset);
620: switch(c->qid.path){
621: default:
622: return streamwrite(c, buf, n, 0);
623: case Qdlr:
624: case Qpcr:
625: case Qdebug:
626: break;
627: }
628: if(n > sizeof b-1)
629: n = sizeof b-1;
630: memmove(b, buf, n);
631: b[n] = 0;
632: data = strtoul(b, 0, 0);
633: switch(c->qid.path){
634: default:
635: ip = &incon[c->dev];
636: outb(ip->dev + c->qid.path, data);
637: break;
638: case Qdebug:
639: incondebug = data;
640: break;
641: }
642: return n;
643: }
644:
645: void
646: inconremove(Chan *c)
647: {
648: USED(c);
649: error(Eperm);
650: }
651:
652: void
653: inconwstat(Chan *c, char *dp)
654: {
655: USED(c, dp);
656: error(Eperm);
657: }
658:
659: /*
660: * the stream routines
661: */
662:
663: /*
664: * kill off the kernel process
665: */
666: static int
667: kNotliving(void *arg)
668: {
669: Incon *ip;
670:
671: ip = (Incon *)arg;
672: return ip->kstarted == 0;
673: }
674:
675: static void
676: inconstclose(Queue * q)
677: {
678: Incon *ip;
679:
680: ip = (Incon *)q->ptr;
681: qlock(ip);
682: ip->rq = 0;
683: qunlock(ip);
684: wakeup(&ip->kr);
685: sleep(&ip->r, kNotliving, ip);
686: }
687:
688: /*
689: * create the kernel process for input
690: * first wait for any old ones to die
691: */
692: static void
693: inconstopen(Queue *q, Stream *s)
694: {
695: Incon *ip;
696: char name[32];
697:
698: ip = &incon[s->dev];
699: sprint(name, "incon%d", s->dev);
700: q->ptr = q->other->ptr = ip;
701: wakeup(&ip->kr);
702: sleep(&ip->r, kNotliving, ip);
703: ip->rq = q;
704: kproc(name, inconkproc, ip);
705: }
706:
707: /*
708: * free all blocks of a message in `q', `bp' is the first block
709: * of the message
710: */
711: static void
712: freemsg(Queue *q, Block *bp)
713: {
714: for(; bp; bp = getq(q)){
715: if(bp->flags & S_DELIM){
716: freeb(bp);
717: return;
718: }
719: freeb(bp);
720: }
721: }
722:
723: static void
724: showpkt(char *str, int chan, int ctl, Block *bp, int i)
725: {
726: int n;
727:
728: n = bp->wptr - bp->rptr;
729: kprint("%s(%d)%uo %d", str, chan, ctl, n);
730: if(n > 8)
731: n = 8;
732: for(; i<n; i++)
733: kprint(" %2.2ux", bp->rptr[i]);
734: kprint("\n");
735: }
736:
737: /*
738: * output a block
739: *
740: * the first 2 bytes of every message are the channel number,
741: * low order byte first. the third is a possible trailing control
742: * character.
743: */
744: void
745: inconoput(Queue *q, Block *bp)
746: {
747: int dev;
748: Incon *ip;
749: ulong end;
750: int status, chan, ctl;
751: int n, size;
752:
753: ip = (Incon *)q->ptr;
754:
755: if(bp->type != M_DATA){
756: if(streamparse("inconset", bp))
757: inconsetctl(ip, bp);
758: else
759: freeb(bp);
760: return;
761: }
762: if(BLEN(bp) < 3){
763: bp = pullup(bp, 3);
764: if(bp == 0){
765: print("inconoput pullup failed\n");
766: return;
767: }
768: }
769:
770: /*
771: * get a whole message before handing bytes to the device
772: */
773: if(!putq(q, bp))
774: return;
775:
776: /*
777: * one transmitter at a time
778: */
779: qlock(&ip->xmit);
780: dev = ip->dev;
781:
782: /*
783: * parse message
784: */
785: bp = getq(q);
786: chan = bp->rptr[0] | (bp->rptr[1]<<8);
787: ctl = bp->rptr[2];
788: bp->rptr += 3;
789: if(chan<=0)
790: print("bad channel %d\n", chan);
791:
792: if(incondebug){
793: kprint("0x%.2ux ", rdstatus(ip));
794: showpkt("->", chan, ctl, bp, 0);
795: }
796:
797: /*
798: * make sure there's an incon out there
799: */
800: if(!(rdstatus(ip)&INCON_ALIVE) || ip->state==Notliving){
801: DPRINT("inconoput: not ready");
802: inconrestart(ip);
803: freemsg(q, bp);
804: qunlock(&ip->xmit);
805: return;
806: }
807:
808: /*
809: * send the 8 bit data
810: */
811: for(;;){
812: /*
813: * spin till there is room
814: */
815: for(n=0, end = NOW+1000; (status=rdstatus(ip)) & TX_FULL; n++){
816: nop(); /* make sure we don't optimize too much */
817: if(NOW > end){
818: print("incon output stuck 0 %.2ux\n", status);
819: freemsg(q, bp);
820: qunlock(&ip->xmit);
821: return;
822: }
823: }
824: ip->wait = (n + ip->wait)>>1;
825:
826: /*
827: * put in next packet
828: */
829: n = bp->wptr - bp->rptr;
830: if(n > 16)
831: n = 16;
832: size = n;
833: wrctl(dev, chan);
834: ip->out += n;
835: while(n--){
836: wrdata(dev, *bp->rptr++);
837: }
838:
839: /*
840: * get next block
841: */
842: if(bp->rptr >= bp->wptr){
843: if(bp->flags & S_DELIM){
844: freeb(bp);
845: break;
846: }
847: freeb(bp);
848: bp = getq(q);
849: if(bp==0)
850: break;
851: }
852:
853: /*
854: * end packet
855: */
856: wrctl(dev, 0);
857: }
858:
859: /*
860: * send the control byte if there is one
861: */
862: if(ctl){
863: if(size >= 16){
864: wrctl(dev, 0);
865: for(end = NOW+1000; rdstatus(ip) & TX_FULL;){
866: nop(); /* make sure we don't optimize too much */
867: if(NOW > end){
868: print("incon output stuck 1\n");
869: freemsg(q, bp);
870: qunlock(&ip->xmit);
871: return;
872: }
873: }
874: wrctl(dev, chan);
875: }
876: if(rdstatus(ip) & TX_FULL)
877: print("inconfull\n");
878: ip->out += 1;
879: wrctl(dev, ctl);
880: }
881: wrctl(dev, 0);
882:
883: qunlock(&ip->xmit);
884: return;
885: }
886:
887: /*
888: * return true if the raw fifo is non-empty
889: */
890: static int
891: notempty(void *arg)
892: {
893: Incon *ip;
894:
895: ip = (Incon *)arg;
896: return ip->ri!=ip->wi;
897: }
898:
899: /*
900: * Read bytes from the raw input circular buffer.
901: */
902: static void
903: inconkproc(void *arg)
904: {
905: Incon *ip;
906: Block *bp;
907: int i;
908: int locked;
909:
910: ip = (Incon *)arg;
911: ip->kstarted = 1;
912:
913: /*
914: * create a number of blocks for input
915: */
916: for(i = 0; i < Nin; i++){
917: bp = ip->inb[i] = allocb(Bsize);
918: bp->wptr += 3;
919: }
920:
921: locked = 0;
922: if(waserror()){
923: if(locked)
924: qunlock(ip);
925: ip->kstarted = 0;
926: wakeup(&ip->r);
927: return;
928: }
929:
930: for(;;){
931: /*
932: * sleep if input fifo empty
933: */
934: sleep(&ip->kr, notempty, ip);
935:
936: /*
937: * die if the device is closed
938: */
939: USED(locked);
940: qlock(ip);
941: locked = 1;
942: if(ip->rq == 0){
943: qunlock(ip);
944: ip->kstarted = 0;
945: wakeup(&ip->r);
946: poperror();
947: return;
948: }
949:
950: /*
951: * send blocks upstream and stage new blocks.
952: */
953: while(ip->ri != ip->wi){
954: bp = ip->inb[ip->ri];
955: bp->flags |= S_DELIM;
956: ip->in += BLEN(bp);
957: PUTNEXT(ip->rq, bp);
958: bp = ip->inb[ip->ri] = allocb(Bsize);
959: bp->wptr += 3;
960: ip->ri = (ip->ri+1)%Nin;
961: }
962: USED(locked);
963: qunlock(ip);
964: locked = 0;
965: }
966: }
967:
968: /*
969: * drop a single packet
970: */
971: static void
972: droppacket(int dev)
973: {
974: if(irddata(dev) == 0)
975: return;
976: while(irdnext(dev))
977: ;
978: }
979:
980: /*
981: * flush the input fifo
982: */
983: static void
984: flushfifo(Incon *ip)
985: {
986: while(!(irdstatus(ip) & RCV_EMPTY))
987: droppacket(ip->dev);
988: }
989:
990: /*
991: * advance the queue. if we've run out of staged input blocks,
992: * drop the packet and return 0. otherwise return the next input
993: * block to fill.
994: */
995: static Block *
996: nextin(Incon *ip, unsigned int c)
997: {
998: Block *bp;
999: int next;
1000:
1001: bp = ip->inb[ip->wi];
1002: bp->rptr[0] = ip->chan;
1003: bp->rptr[1] = ip->chan>>8;
1004: bp->rptr[2] = c;
1005: if(incondebug)
1006: showpkt("<-", ip->chan, c, bp, 3);
1007:
1008: next = (ip->wi+1)%Nin;
1009: if(next == ip->ri){
1010: bp->wptr = bp->rptr+3;
1011: return bp;
1012: }
1013: ip->wi = next;
1014:
1015: return ip->inb[ip->wi];
1016: }
1017:
1018: /*
1019: * read the packets from the device into the staged input blocks.
1020: * we have to do this at interrupt tevel to turn off the interrupts.
1021: */
1022: static void
1023: rdpackets(Incon *ip)
1024: {
1025: Block *bp;
1026: unsigned int c;
1027: int dev;
1028: uchar *p;
1029: int first = ip->wi;
1030:
1031: dev = ip->dev;
1032: bp = ip->inb[ip->wi];
1033: if(bp==0){
1034: flushfifo(ip);
1035: return;
1036: }
1037: p = bp->wptr;
1038: while(!(irdstatus(ip) & RCV_EMPTY)){
1039: /*
1040: * get channel number
1041: */
1042: c = irddata(dev);
1043: if(c == 0){
1044: droppacket(dev);
1045: continue;
1046: }
1047: if(ip->chan != c){
1048: if(p - bp->rptr > 3){
1049: bp->wptr = p;
1050: bp = nextin(ip, 0);
1051: p = bp->wptr;
1052: }
1053: ip->chan = c;
1054: }
1055:
1056: /*
1057: * null byte marks end of packet
1058: */
1059: while(c = irdnext(dev)){ /* assign = */
1060: if((c & 0x100) == 0){
1061: /*
1062: * control byte ends block
1063: */
1064: bp->wptr = p;
1065: bp = nextin(ip, c);
1066: p = bp->wptr;
1067: }else{
1068: /*
1069: * data byte, put in local buffer
1070: */
1071: *p++ = c;
1072: }
1073: }
1074:
1075: /*
1076: * pass a block on if it doesn't have room for one more
1077: * packet. this way we don't have to check per byte.
1078: */
1079: if(p + 16 > bp->lim){
1080: bp->wptr = p;
1081: bp = nextin(ip, 0);
1082: p = bp->wptr;
1083: }
1084: }
1085: bp->wptr = p;
1086: if(bp->wptr != bp->rptr+3)
1087: nextin(ip, 0);
1088:
1089: if(first != ip->wi)/**/
1090: wakeup(&ip->kr);
1091: }
1092:
1093: /*
1094: * Receive an incon interrupt. One entry point
1095: * for all types of interrupt. Until we figure out
1096: * how to use more than one incon, this routine only
1097: * is for incon[0].
1098: */
1099: static void
1100: inconintr(Ureg *ur, void *a)
1101: {
1102: uchar status;
1103: int pcr;
1104: Incon *ip;
1105:
1106: USED(ur, a);
1107: ip = &incon[0];
1108: pcr = inb(ip->dev+Qpcr);
1109: if(!(pcr & Fie))
1110: return;
1111: status = irdstatus(ip);
1112: if(incondebug){
1113: kprint("pcr=%2.2x status=%2.2x\n", pcr, status);
1114: if(pcr & Fstrobe)
1115: kprint("YIKES!!\n");
1116: }
1117: if(!(status & RCV_EMPTY))
1118: rdpackets(ip);
1119:
1120: /* see if it died underneath us */
1121: if(!(status&INCON_ALIVE)){
1122: switch(ip->state){
1123: case Selected:
1124: iwrcmd(ip->dev, INCON_STOP);
1125: DPRINT("Incon died\n");
1126: print("Incon died\n");
1127: break;
1128: case Selecting:
1129: DPRINT("rejected\n");
1130: print("rejected\n");
1131: break;
1132: default:
1133: iwrcmd(ip->dev, INCON_STOP);
1134: DPRINT("state was %d\n", ip->state);
1135: break;
1136: }
1137: ip->state = Notliving;
1138: }
1139: irdnop(ip->dev, pcr);
1140: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.