|
|
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: #include "ureg.h"
11:
12: typedef struct Incon Incon;
13: typedef struct Device Device;
14:
15: #define NOW (MACHP(0)->ticks*MS2HZ)
16:
17: #define MICROSECOND USED(NOW)
18:
19: #define DPRINT if(0)
20:
21: enum {
22: Minstation= 2, /* lowest station # to poll */
23: Maxstation= 15, /* highest station # to poll */
24: Nincon= 1, /* number of incons */
25: Nin= 32, /* Blocks in the input ring */
26: Bsize= 128, /* size of an input ring block */
27: Mfifo= 0xff, /* a mask, must be 2^n-1, must be > Nin */
28:
29: Qstats= 1, /* qid of the statistics file */
30: };
31:
32: /*
33: * incon datakit board
34: */
35: struct Device {
36: uchar cdata;
37: #define cpolln cdata
38: uchar u0;
39: uchar cstatus;
40: uchar u1;
41: uchar creset;
42: uchar u2;
43: uchar csend;
44: uchar u3;
45: ushort data_cntl; /* data is high byte, cntl is low byte */
46: uchar status;
47: #define cmd status
48: uchar u5;
49: uchar reset;
50: uchar u6;
51: uchar send;
52: uchar u7;
53: };
54: #define INCON ((Device *)0x40700000)
55:
56: struct Incon {
57: QLock;
58:
59: QLock xmit; /* transmit lock */
60: QLock reslock; /* reset lock */
61: Device *dev;
62: int station; /* station number */
63: int state; /* chip state */
64: Rendez r; /* output process */
65: Rendez kr; /* input kernel process */
66: ushort chan; /* current input channel */
67: Queue *rq; /* read queue */
68: int kstarted; /* true if kernel process started */
69:
70: /* input blocks */
71:
72: Block *inb[Nin];
73: ushort wi;
74: ushort ri;
75:
76: /* statistics */
77:
78: ulong overflow; /* overflow errors */
79: ulong pack0; /* channel 0 */
80: ulong crc; /* crc errors */
81: ulong in; /* bytes in */
82: ulong out; /* bytes out */
83: ulong wait; /* wait time in milliseconds */
84: };
85:
86: Incon incon[Nincon];
87:
88: /*
89: * chip state
90: */
91: enum {
92: Selecting,
93: Selected,
94: Notliving,
95: };
96:
97: /*
98: * internal chip registers
99: */
100: #define sel_polln 0
101: #define sel_station 1
102: #define sel_poll0 2
103: #define sel_rcv_cnt 3
104: #define sel_rcv_tim 4
105: #define sel_tx_cnt 5
106:
107: /*
108: * CSR bits
109: */
110: #define INCON_RUN 0x80
111: #define INCON_STOP 0x00
112: #define ENABLE_IRQ 0x40
113: #define ENABLE_TX_IRQ 0x20
114: #define INCON_ALIVE 0x80
115: #define TX_FULL 0x10
116: #define TX_EMPTY 0x08
117: #define RCV_EMPTY 0x04
118: #define OVERFLOW 0x02
119: #define CRC_ERROR 0x01
120:
121: /*
122: * polling constants
123: */
124: #define HT_GNOT 0x30
125: #define ST_UNIX 0x04
126: #define NCHAN 16
127:
128: static void inconkproc(void*);
129:
130: /*
131: * incon stream module definition
132: */
133: static void inconoput(Queue*, Block*);
134: static void inconstopen(Queue*, Stream*);
135: static void inconstclose(Queue*);
136: Qinfo inconinfo =
137: {
138: nullput,
139: inconoput,
140: inconstopen,
141: inconstclose,
142: "incon"
143: };
144:
145: int incondebug;
146:
147: Dirtab incondir[]={
148: "stats", {Qstats}, 0, 0444,
149: };
150:
151: /*
152: * set the incon parameters
153: */
154: void
155: inconset(Incon *ip, int cnt, int del)
156: {
157: Device *dev;
158:
159: if (cnt<1 || cnt>14 || del<1 || del>15)
160: error(Ebadarg);
161:
162: dev = ip->dev;
163: dev->cmd = sel_rcv_cnt | INCON_RUN;
164: MICROSECOND;
165: *(uchar *)&dev->data_cntl = cnt;
166: MICROSECOND;
167: dev->cmd = sel_rcv_tim | INCON_RUN;
168: MICROSECOND;
169: *(uchar *)&dev->data_cntl = del;
170: MICROSECOND;
171: dev->cmd = INCON_RUN | ENABLE_IRQ;
172: }
173:
174: /*
175: * parse a set request
176: */
177: void
178: inconsetctl(Incon *ip, Block *bp)
179: {
180: char *field[3];
181: int n;
182: int del;
183: int cnt;
184:
185: del = 15;
186: n = getfields((char *)bp->rptr, field, 3, " ");
187: switch(n){
188: default:
189: freeb(bp);
190: error(Ebadarg);
191: case 2:
192: del = strtol(field[1], 0, 0);
193: if(del<0 || del>15){
194: freeb(bp);
195: error(Ebadarg);
196: }
197: /* fall through */
198: case 1:
199: cnt = strtol(field[0], 0, 0);
200: if(cnt<0 || cnt>15){
201: freeb(bp);
202: error(Ebadarg);
203: }
204: }
205: inconset(ip, cnt, del);
206: freeb(bp);
207: }
208:
209: static void
210: nop(void)
211: {
212: }
213:
214: /*
215: * poll for a station number
216: */
217: void
218: inconpoll(Incon *ip, int station)
219: {
220: ulong timer;
221: Device *dev;
222:
223: dev = ip->dev;
224:
225: /*
226: * get us to a known state
227: */
228: ip->state = Notliving;
229: dev->cmd = INCON_STOP;
230:
231: /*
232: * try a station number
233: */
234: dev->cmd = sel_station;
235: *(uchar *)&dev->data_cntl = station;
236: dev->cmd = sel_poll0;
237: *(uchar *)&dev->data_cntl = HT_GNOT;
238: dev->cmd = sel_rcv_cnt;
239: *(uchar *)&dev->data_cntl = 3;
240: dev->cmd = sel_rcv_tim;
241: *(uchar *)&dev->data_cntl = 15;
242: dev->cmd = sel_tx_cnt;
243: *(uchar *)&dev->data_cntl = 1;
244: dev->cmd = sel_polln;
245: *(uchar *)&dev->data_cntl = 0x00;
246: *(uchar *)&dev->data_cntl = ST_UNIX;
247: *(uchar *)&dev->data_cntl = NCHAN;
248: *(uchar *)&dev->data_cntl = 'g';
249: *(uchar *)&dev->data_cntl = 'n';
250: *(uchar *)&dev->data_cntl = 'o';
251: *(uchar *)&dev->data_cntl = 't';
252: dev->cpolln = 0;
253:
254: /*
255: * poll and wait for ready (or 1/4 second)
256: */
257: ip->state = Selecting;
258: dev->cmd = INCON_RUN | ENABLE_IRQ;
259: timer = NOW + 250;
260: while (NOW < timer) {
261: nop();
262: if(dev->status & INCON_ALIVE){
263: ip->station = station;
264: ip->state = Selected;
265: break;
266: }
267: }
268: }
269:
270: /*
271: * reset the chip and find a new staion number
272: */
273: void
274: inconrestart(Incon *ip)
275: {
276: int i;
277:
278: if(!canqlock(&ip->reslock))
279: return;
280:
281: /*
282: * poll for incon station numbers
283: */
284: for(i = Minstation; i <= Maxstation; i++){
285: inconpoll(ip, i);
286: if(ip->state == Selected)
287: break;
288: }
289: switch(ip->state) {
290: case Selecting:
291: print("incon[%d] not polled\n", ip-incon);
292: break;
293: case Selected:
294: print("incon[%d] station %d\n", ip-incon, ip->station);
295: inconset(ip, 3, 15);
296: break;
297: default:
298: print("incon[%d] bollixed\n", ip-incon);
299: break;
300: }
301: qunlock(&ip->reslock);
302: }
303:
304: /*
305: * reset all incon chips.
306: */
307: void
308: inconreset(void)
309: {
310: int i;
311:
312: incon[0].dev = INCON;
313: incon[0].state = Selected;
314: incon[0].ri = incon[0].wi = 0;
315: /* inconset(&incon[0], 3, 15); /**/
316: for(i=1; i<Nincon; i++){
317: incon[i].dev = INCON+i;
318: incon[i].state = Notliving;
319: incon[i].dev->cmd = INCON_STOP;
320: incon[i].ri = incon[i].wi = 0;
321: }
322: }
323:
324: void
325: inconinit(void)
326: {
327: }
328:
329: /*
330: * enable the device for interrupts, spec is the device number
331: */
332: Chan*
333: inconattach(char *spec)
334: {
335: Incon *ip;
336: int i;
337: Chan *c;
338:
339: i = strtoul(spec, 0, 0);
340: if(i >= Nincon)
341: error(Ebadarg);
342: ip = &incon[i];
343: if(ip->state != Selected)
344: inconrestart(ip);
345:
346: c = devattach('i', spec);
347: c->dev = i;
348: c->qid.path = CHDIR;
349: c->qid.vers = 0;
350: return c;
351: }
352:
353: Chan*
354: inconclone(Chan *c, Chan *nc)
355: {
356: return devclone(c, nc);
357: }
358:
359: int
360: inconwalk(Chan *c, char *name)
361: {
362: return devwalk(c, name, incondir, 1, streamgen);
363: }
364:
365: void
366: inconstat(Chan *c, char *dp)
367: {
368: devstat(c, dp, incondir, 1, streamgen);
369: }
370:
371: Chan*
372: inconopen(Chan *c, int omode)
373: {
374: if(c->qid.path == CHDIR || c->qid.path == Qstats){
375: if(omode != OREAD)
376: error(Eperm);
377: }else
378: streamopen(c, &inconinfo);
379: c->mode = openmode(omode);
380: c->flag |= COPEN;
381: c->offset = 0;
382: return c;
383: }
384:
385: void
386: inconcreate(Chan *c, char *name, int omode, ulong perm)
387: {
388: USED(c, name, omode, perm);
389: error(Eperm);
390: }
391:
392: void
393: inconclose(Chan *c)
394: {
395: if(c->qid.path != CHDIR)
396: streamclose(c);
397: }
398:
399: long
400: inconread(Chan *c, void *buf, long n, ulong offset)
401: {
402: char b[256];
403: Incon *i;
404:
405: if(c->qid.path == CHDIR)
406: return devdirread(c, buf, n, incondir, 1, streamgen);
407: else if(c->qid.path == Qstats){
408: i = &incon[c->dev];
409: sprint(b, "in: %d\nout: %d\noverflow: %d\ncrc: %d\nwait: %d\n", i->in,
410: i->out, i->overflow, i->crc, i->wait);
411: return readstr(offset, buf, n, b);
412: } else
413: return streamread(c, buf, n);
414: }
415:
416: long
417: inconwrite(Chan *c, void *buf, long n, ulong offset)
418: {
419: USED(offset);
420: return streamwrite(c, buf, n, 0);
421: }
422:
423: void
424: inconremove(Chan *c)
425: {
426: USED(c);
427: error(Eperm);
428: }
429:
430: void
431: inconwstat(Chan *c, char *dp)
432: {
433: USED(c, dp);
434: error(Eperm);
435: }
436:
437: /*
438: * the stream routines
439: */
440:
441: /*
442: * for sleeping while kproc dies
443: */
444: static int
445: kNotliving(void *arg)
446: {
447: Incon *ip;
448:
449: ip = (Incon *)arg;
450: return ip->kstarted == 0;
451: }
452:
453: /*
454: * create the kernel process for input
455: * first wait for any old ones to die
456: */
457: static void
458: inconstopen(Queue *q, Stream *s)
459: {
460: Incon *ip;
461: char name[32];
462:
463: ip = &incon[s->dev];
464: sprint(name, "incon%d", s->dev);
465: q->ptr = q->other->ptr = ip;
466: wakeup(&ip->kr);
467: sleep(&ip->r, kNotliving, ip);
468: ip->rq = q;
469: kproc(name, inconkproc, ip);
470: }
471:
472: /*
473: * kill off the kernel process
474: */
475: static void
476: inconstclose(Queue * q)
477: {
478: Incon *ip;
479:
480: ip = (Incon *)q->ptr;
481: qlock(ip);
482: ip->rq = 0;
483: qunlock(ip);
484: wakeup(&ip->kr);
485: sleep(&ip->r, kNotliving, ip);
486: }
487:
488: /*
489: * free all blocks of a message in `q', `bp' is the first block
490: * of the message
491: */
492: static void
493: freemsg(Queue *q, Block *bp)
494: {
495: for(; bp; bp = getq(q)){
496: if(bp->flags & S_DELIM){
497: freeb(bp);
498: return;
499: }
500: freeb(bp);
501: }
502: }
503:
504: /*
505: * output a block
506: *
507: * the first 2 bytes of every message are the channel number,
508: * low order byte first. the third is a possible trailing control
509: * character.
510: */
511: void
512: inconoput(Queue *q, Block *bp)
513: {
514: Device *dev;
515: Incon *ip;
516: ulong start, end;
517: int chan;
518: int ctl;
519: int n, size;
520:
521: ip = (Incon *)q->ptr;
522:
523: if(bp->type != M_DATA){
524: if(streamparse("inconset", bp))
525: inconsetctl(ip, bp);
526: else
527: freeb(bp);
528: return;
529: }
530: if(BLEN(bp) < 3){
531: bp = pullup(bp, 3);
532: if(bp == 0){
533: print("inconoput pullup failed\n");
534: return;
535: }
536: }
537:
538: /*
539: * get a whole message before handing bytes to the device
540: */
541: if(!putq(q, bp))
542: return;
543:
544: /*
545: * one transmitter at a time
546: */
547: qlock(&ip->xmit);
548: dev = ip->dev;
549:
550: /*
551: * parse message
552: */
553: bp = getq(q);
554: chan = bp->rptr[0] | (bp->rptr[1]<<8);
555: ctl = bp->rptr[2];
556: bp->rptr += 3;
557: if(chan<=0)
558: print("bad channel %d\n", chan);
559:
560: if(incondebug)
561: print("->(%d)%uo %d\n", chan, ctl, bp->wptr - bp->rptr);
562:
563: /*
564: * make sure there's an incon out there
565: */
566: if(!(dev->status&INCON_ALIVE) || ip->state==Notliving){
567: inconrestart(ip);
568: freemsg(q, bp);
569: qunlock(&ip->xmit);
570: return;
571: }
572:
573: /*
574: * send the 8 bit data
575: */
576: for(;;){
577: /*
578: * spin till there is room
579: */
580: start = NOW;
581: for(n = 0, end = start+1000; dev->status & TX_FULL; n++){
582: nop(); /* make sure we don't optimize too much */
583: if(NOW > end){
584: print("incon output stuck\n");
585: freemsg(q, bp);
586: qunlock(&ip->xmit);
587: return;
588: }
589: }
590: ip->wait = (n + ip->wait)>>1;
591:
592: /*
593: * put in next packet
594: */
595: n = bp->wptr - bp->rptr;
596: if(n > 16)
597: n = 16;
598: size = n;
599: dev->cdata = chan;
600: ip->out += n;
601: while(n--){
602: *(uchar *)&dev->data_cntl = *bp->rptr++;
603: }
604:
605: /*
606: * get next block
607: */
608: if(bp->rptr >= bp->wptr){
609: if(bp->flags & S_DELIM){
610: freeb(bp);
611: break;
612: }
613: freeb(bp);
614: bp = getq(q);
615: if(bp==0)
616: break;
617: }
618:
619: /*
620: * end packet
621: */
622: dev->cdata = 0;
623: }
624:
625: /*
626: * send the control byte if there is one
627: */
628: if(ctl){
629: if(size >= 16){
630: dev->cdata = 0;
631: MICROSECOND;
632: for(end = NOW+1000; dev->status & TX_FULL;){
633: nop(); /* make sure we don't optimize too much */
634: if(NOW > end){
635: print("incon output stuck\n");
636: freemsg(q, bp);
637: qunlock(&ip->xmit);
638: return;
639: }
640: }
641: dev->cdata = chan;
642: MICROSECOND;
643: }
644: if(dev->status & TX_FULL)
645: print("inconfull\n");
646: dev->cdata = ctl;
647: }
648: MICROSECOND;
649: dev->cdata = 0;
650:
651: qunlock(&ip->xmit);
652: return;
653: }
654:
655: /*
656: * return true if the raw fifo is non-empty
657: */
658: static int
659: notempty(void *arg)
660: {
661: Incon *ip;
662:
663: ip = (Incon *)arg;
664: return ip->ri!=ip->wi;
665: }
666:
667: /*
668: * Read bytes from the raw input circular buffer.
669: */
670: static void
671: inconkproc(void *arg)
672: {
673: Incon *ip;
674: Block *bp;
675: int i;
676: int locked;
677:
678: ip = (Incon *)arg;
679: ip->kstarted = 1;
680:
681: /*
682: * create a number of blocks for input
683: */
684: for(i = 0; i < Nin; i++){
685: bp = ip->inb[i] = allocb(Bsize);
686: bp->wptr += 3;
687: }
688:
689: locked = 0;
690: if(waserror()){
691: if(locked)
692: qunlock(ip);
693: ip->kstarted = 0;
694: wakeup(&ip->r);
695: return;
696: }
697:
698: for(;;){
699: /*
700: * sleep if input fifo empty
701: */
702: sleep(&ip->kr, notempty, ip);
703:
704: /*
705: * die if the device is closed
706: */
707: USED(locked);
708: qlock(ip);
709: locked = 1;
710: if(ip->rq == 0){
711: qunlock(ip);
712: ip->kstarted = 0;
713: wakeup(&ip->r);
714: poperror();
715: return;
716: }
717:
718: /*
719: * send blocks upstream and stage new blocks. if the block is small
720: * (< 64 bytes) copy into a smaller buffer.
721: */
722: while(ip->ri != ip->wi){
723: bp = ip->inb[ip->ri];
724: ip->in += BLEN(bp);
725: PUTNEXT(ip->rq, bp);
726: bp = ip->inb[ip->ri] = allocb(Bsize);
727: bp->wptr += 3;
728: ip->ri = (ip->ri+1)%Nin;
729: }
730: USED(locked);
731: qunlock(ip);
732: locked = 0;
733: }
734: }
735:
736: /*
737: * drop a single packet
738: */
739: static void
740: droppacket(Device *dev)
741: {
742: int i;
743: int c;
744:
745: for(i = 0; i < 17; i++){
746: c = dev->data_cntl;
747: if(c==0)
748: break;
749: }
750: }
751:
752: /*
753: * flush the input fifo
754: */
755: static void
756: flushfifo(Device *dev)
757: {
758: while(!(dev->status & RCV_EMPTY))
759: droppacket(dev);
760: }
761:
762: /*
763: * advance the queue. if we've run out of staged input blocks,
764: * drop the packet and return 0. otherwise return the next input
765: * block to fill.
766: */
767: static Block *
768: nextin(Incon *ip, unsigned int c)
769: {
770: Block *bp;
771: int next;
772:
773: bp = ip->inb[ip->wi];
774: bp->rptr[0] = ip->chan;
775: bp->rptr[1] = ip->chan>>8;
776: bp->rptr[2] = c;
777: if(incondebug)
778: print("<-(%d)%uo %d\n", ip->chan, c, bp->wptr-bp->rptr);
779:
780: next = (ip->wi+1)%Nin;
781: if(next == ip->ri){
782: bp->wptr = bp->rptr+3;
783: return bp;
784: }
785: ip->wi = next;
786:
787: return ip->inb[ip->wi];
788: }
789:
790: /*
791: * read the packets from the device into the staged input blocks.
792: * we have to do this at interrupt tevel to turn off the interrupts.
793: */
794: static void
795: rdpackets(Incon *ip)
796: {
797: Block *bp;
798: unsigned int c;
799: Device *dev;
800: uchar *p;
801: int first = ip->wi;
802:
803: dev = ip->dev;
804: bp = ip->inb[ip->wi];
805: if(bp==0){
806: flushfifo(ip->dev);
807: return;
808: }
809: p = bp->wptr;
810: while(!(dev->status & RCV_EMPTY)){
811: /*
812: * get channel number
813: */
814: c = (dev->data_cntl)>>8;
815: if(c == 0){
816: droppacket(dev);
817: continue;
818: }
819: if(ip->chan != c){
820: if(p - bp->rptr > 3){
821: bp->wptr = p;
822: bp = nextin(ip, 0);
823: if(bp==0){
824: flushfifo(ip->dev);
825: return;
826: }
827: p = bp->wptr;
828: }
829: ip->chan = c;
830: }
831:
832: /*
833: * null byte marks end of packet
834: */
835: for(;;){
836: if((c=dev->data_cntl)&1) {
837: /*
838: * data byte, put in local buffer
839: */
840: *p++ = c>>8;
841: } else if (c>>=8) {
842: /*
843: * control byte ends block
844: */
845: bp->wptr = p;
846: bp = nextin(ip, c);
847: if(bp==0){
848: flushfifo(ip->dev);
849: return;
850: }
851: p = bp->wptr;
852: } else {
853: /* end of packet */
854: break;
855: }
856: }
857:
858: /*
859: * pass a block on if it doesn't have room for one more
860: * packet. this way we don't have to check per byte.
861: */
862: if(p + 16 > bp->lim){
863: bp->wptr = p;
864: bp = nextin(ip, 0);
865: p = bp->wptr;
866: }
867: }
868: bp->wptr = p;
869: if(bp->wptr != bp->rptr+3)
870: nextin(ip, 0);
871:
872: if(first != ip->wi)/**/
873: wakeup(&ip->kr);
874: }
875:
876: /*
877: * Receive an incon interrupt. One entry point
878: * for all types of interrupt. Until we figure out
879: * how to use more than one incon, this routine only
880: * is for incon[0].
881: */
882: void
883: inconintr(Ureg *ur)
884: {
885: uchar status;
886: Incon *ip;
887:
888: USED(ur);
889: ip = &incon[0];
890:
891: status = ip->dev->status;
892: if(!(status & RCV_EMPTY))
893: rdpackets(ip);
894:
895: /* check for exceptional conditions */
896: if(status&(OVERFLOW|CRC_ERROR)){
897: if(status&OVERFLOW)
898: ip->overflow++;
899: if(status&CRC_ERROR)
900: ip->crc++;
901: }
902:
903: /* see if it died underneath us */
904: if(!(status&INCON_ALIVE)){
905: switch(ip->state){
906: case Selected:
907: ip->dev->cmd = INCON_STOP;
908: print("Incon died\n");
909: break;
910: case Selecting:
911: print("rejected\n");
912: break;
913: default:
914: ip->dev->cmd = INCON_STOP;
915: break;
916: }
917: ip->state = Notliving;
918: }
919: }
920:
921: void
922: incontoggle(void)
923: {
924: incondebug ^= 1;
925: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.