|
|
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 "io.h"
7: #include "../port/error.h"
8:
9: #include "devtab.h"
10: #define nelem(x) (sizeof(x)/sizeof(x[0]))
11: /*
12: * Driver for an NS16450 serial port
13: */
14: enum
15: {
16: /*
17: * register numbers
18: */
19: Data= 0, /* xmit/rcv buffer */
20: Iena= 1, /* interrupt enable */
21: Ircv= (1<<0), /* for char rcv'd */
22: Ixmt= (1<<1), /* for xmit buffer empty */
23: Irstat=(1<<2), /* for change in rcv'er status */
24: Imstat=(1<<3), /* for change in modem status */
25: Istat= 2, /* interrupt flag (read) */
26: Fenabd=(3<<6), /* on if fifo's enabled */
27: Fifoctl=2, /* fifo control (write) */
28: Fenab= (1<<0), /* enable xmit/rcv fifos */
29: Ftrig= (1<<6), /* trigger after 4 input characters */
30: Fclear=(3<<1), /* clear xmit & rcv fifos */
31: Format= 3, /* byte format */
32: Bits8= (3<<0), /* 8 bits/byte */
33: Stop2= (1<<2), /* 2 stop bits */
34: Pena= (1<<3), /* generate parity */
35: Peven= (1<<4), /* even parity */
36: Pforce=(1<<5), /* force parity */
37: Break= (1<<6), /* generate a break */
38: Dra= (1<<7), /* address the divisor */
39: Mctl= 4, /* modem control */
40: Dtr= (1<<0), /* data terminal ready */
41: Rts= (1<<1), /* request to send */
42: Ri= (1<<2), /* ring */
43: Inton= (1<<3), /* turn on interrupts */
44: Loop= (1<<4), /* loop back */
45: Lstat= 5, /* line status */
46: Inready=(1<<0), /* receive buffer full */
47: Oerror=(1<<1), /* receiver overrun */
48: Perror=(1<<2), /* receiver parity error */
49: Ferror=(1<<3), /* rcv framing error */
50: Outready=(1<<5), /* output buffer full */
51: Mstat= 6, /* modem status */
52: Ctsc= (1<<0), /* clear to send changed */
53: Dsrc= (1<<1), /* data set ready changed */
54: Rire= (1<<2), /* rising edge of ring indicator */
55: Dcdc= (1<<3), /* data carrier detect changed */
56: Cts= (1<<4), /* complement of clear to send line */
57: Dsr= (1<<5), /* complement of data set ready line */
58: Ring= (1<<6), /* complement of ring indicator line */
59: Dcd= (1<<7), /* complement of data carrier detect line */
60: Scratch=7, /* scratchpad */
61: Dlsb= 0, /* divisor lsb */
62: Dmsb= 1, /* divisor msb */
63:
64: Serial= 0,
65: Modem= 1,
66: };
67:
68: typedef struct Uart Uart;
69: struct Uart
70: {
71: QLock;
72: int port;
73: uchar sticky[8]; /* sticky write register values */
74: int printing; /* true if printing */
75: int enabled;
76: int cts;
77:
78: /* fifo control */
79: int fifoon;
80: int nofifo;
81: int istat;
82:
83: /* console interface */
84: int special; /* can't use the stream interface */
85: IOQ *iq; /* input character queue */
86: IOQ *oq; /* output character queue */
87:
88: /* stream interface */
89: Queue *wq; /* write queue */
90: Rendez r; /* kproc waiting for input */
91: int kstarted; /* kproc started */
92:
93: /* error statistics */
94: ulong frame;
95: ulong overrun;
96: };
97:
98: typedef struct Scard
99: {
100: ISAConf; /* card configuration */
101: int first; /* number of first port */
102: } Scard;
103:
104:
105: Uart uart[34];
106: int Nuart; /* total no of uarts in the machine */
107: int Nscard; /* number of serial cards */
108: Scard scard[5]; /* configs for the serial card */
109:
110: #define UartFREQ 1843200
111:
112: #define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v))
113: #define uartrdreg(u,r) inb((u)->port + r)
114:
115: void uartintr(Ureg*, void*);
116: void mp008intr(Ureg*, void*);
117:
118: /*
119: * set the baud rate by calculating and setting the baudrate
120: * generator constant. This will work with fairly non-standard
121: * baud rates.
122: */
123: void
124: uartsetbaud(Uart *up, int rate)
125: {
126: ulong brconst;
127:
128: brconst = (UartFREQ+8*rate-1)/(16*rate);
129:
130: uartwrreg(up, Format, Dra);
131: outb(up->port+Dmsb, (brconst>>8) & 0xff);
132: outb(up->port+Dlsb, brconst & 0xff);
133: uartwrreg(up, Format, 0);
134: }
135:
136: /*
137: * toggle DTR
138: */
139: void
140: uartdtr(Uart *up, int n)
141: {
142: if(n)
143: up->sticky[Mctl] |= Dtr;
144: else
145: up->sticky[Mctl] &= ~Dtr;
146: uartwrreg(up, Mctl, 0);
147: }
148:
149: /*
150: * toggle RTS
151: */
152: void
153: uartrts(Uart *up, int n)
154: {
155: if(n)
156: up->sticky[Mctl] |= Rts;
157: else
158: up->sticky[Mctl] &= ~Rts;
159: uartwrreg(up, Mctl, 0);
160: }
161:
162: /*
163: * send break
164: */
165: void
166: uartbreak(Uart *up, int ms)
167: {
168: if(ms == 0)
169: ms = 200;
170: uartwrreg(up, Format, Break);
171: tsleep(&u->p->sleep, return0, 0, ms);
172: uartwrreg(up, Format, 0);
173: }
174:
175: /*
176: * set bits/char
177: */
178: void
179: uartbits(Uart *up, int bits)
180: {
181: if(bits < 5 || bits > 8)
182: error(Ebadarg);
183: up->sticky[Format] &= ~3;
184: up->sticky[Format] |= bits-5;
185: uartwrreg(up, Format, 0);
186: }
187:
188: /*
189: * set parity
190: */
191: void
192: uartparity(Uart *up, int c)
193: {
194: switch(c&0xff){
195: case 'e':
196: up->sticky[Format] |= Pena|Peven;
197: break;
198: case 'o':
199: up->sticky[Format] &= ~Peven;
200: up->sticky[Format] |= Pena;
201: break;
202: default:
203: up->sticky[Format] &= ~(Pena|Peven);
204: break;
205: }
206: uartwrreg(up, Format, 0);
207: }
208:
209: /*
210: * set stop bits
211: */
212: void
213: uartstop(Uart *up, int n)
214: {
215: switch(n){
216: case 1:
217: up->sticky[Format] &= ~Stop2;
218: break;
219: case 2:
220: default:
221: up->sticky[Format] |= Stop2;
222: break;
223: }
224: uartwrreg(up, Format, 0);
225: }
226:
227:
228: void
229: uartfifoon(Uart *p)
230: {
231: ulong i, x;
232:
233: if(p->nofifo)
234: return;
235:
236: x = splhi();
237:
238: /* empty buffer */
239: for(i = 0; i < 16; i++)
240: uartrdreg(p, Data);
241: uartintr(0, p);
242:
243: /* turn on fifo */
244: p->fifoon = 1;
245: uartwrreg(p, Fifoctl, Fenab|Ftrig);
246:
247: uartintr(0, p);
248: if((p->istat & Fenabd) == 0){
249: /* didn't work, must be an earlier chip type */
250: p->nofifo = 1;
251: }
252:
253: splx(x);
254: }
255:
256: /*
257: * modem flow control on/off (rts/cts)
258: */
259: void
260: uartmflow(Uart *up, int n)
261: {
262: if(n){
263: up->sticky[Iena] |= Imstat;
264: uartwrreg(up, Iena, 0);
265: up->cts = uartrdreg(up, Mstat) & Cts;
266:
267: /* turn on fifo's */
268: uartfifoon(up);
269: } else {
270: up->sticky[Iena] &= ~Imstat;
271: uartwrreg(up, Iena, 0);
272: up->cts = 1;
273:
274: /* turn off fifo's */
275: if(up->fifoon){
276: up->fifoon = 0;
277: uartwrreg(up, Fifoctl, 0);
278: }
279: }
280: }
281:
282:
283: /*
284: * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
285: * transmit and receive enabled, interrupts disabled.
286: */
287: void
288: uartsetup(void)
289: {
290: Uart *up;
291: Scard *sc;
292: int i, j, baddr;
293: static int already;
294:
295: if(already)
296: return;
297: already = 1;
298:
299: /*
300: * set port addresses
301: */
302: uart[0].port = 0x3F8;
303: uart[1].port = 0x2F8;
304: setvec(Uart0vec, uartintr, &uart[0]);
305: setvec(Uart1vec, uartintr, &uart[1]);
306: Nuart = 2;
307: for(i = 0; isaconfig("serial", i, &scard[i]) && i < nelem(scard); i++) {
308: sc = &scard[i];
309: if(strcmp(sc->type, "mp008") == 0 || strcmp(sc->type, "MP008") == 0){
310: /*
311: * port gives base port address for uarts
312: * irq is interrupt
313: * mem is the polling port
314: * size is the number of serial ports on the same polling port
315: */
316: sc->first = Nuart;
317: if(sc->size == 0)
318: sc->size = 8;
319: setvec(Int0vec + sc->irq, mp008intr, &scard[i]);
320: baddr = sc->port;
321: for(j=0, up = &uart[Nuart]; j < sc->size; baddr += 8, j++, up++){
322: up->port = baddr;
323: Nuart++;
324: }
325: } else {
326: /*
327: * port gives base port address for uarts
328: * irq is interrupt
329: * size is the number of serial ports on the same polling port
330: */
331: if(sc->size == 0)
332: sc->size = 1;
333: baddr = sc->port;
334: for(j=0, up = &uart[Nuart]; j < sc->size; baddr += 8, j++, up++){
335: setvec(Int0vec + sc->irq, uartintr, &uart[Nuart]);
336: up->port = baddr;
337: Nuart++;
338: }
339: }
340: }
341: Nscard = i;
342: for(up = uart; up < &uart[Nuart]; up++){
343: memset(up->sticky, 0, sizeof(up->sticky));
344: /*
345: * set rate to 9600 baud.
346: * 8 bits/character.
347: * 1 stop bit.
348: * interrupts enabled.
349: */
350: uartsetbaud(up, 9600);
351: up->sticky[Format] = Bits8;
352: uartwrreg(up, Format, 0);
353: up->sticky[Mctl] |= Inton;
354: uartwrreg(up, Mctl, 0x0);
355: }
356: }
357:
358: /*
359: * Queue n characters for output; if queue is full, we lose characters.
360: * Get the output going if it isn't already.
361: */
362: void
363: uartputs(IOQ *cq, char *s, int n)
364: {
365: Uart *up = cq->ptr;
366: int ch, x, multiprocessor;
367: int tries;
368:
369: multiprocessor = active.machs > 1;
370: x = splhi();
371: if(multiprocessor)
372: lock(cq);
373: puts(cq, s, n);
374: if(up->printing == 0){
375: ch = getc(cq);
376: if(ch >= 0){
377: up->printing = 1;
378: for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready);
379: tries++)
380: ;
381: outb(up->port + Data, ch);
382: }
383: }
384: if(multiprocessor)
385: unlock(cq);
386: splx(x);
387: }
388:
389: /*
390: * a uart interrupt (a damn lot of work for one character)
391: */
392: void
393: uartintr(Ureg *ur, void *a)
394: {
395: int ch;
396: IOQ *cq;
397: int s, l, multiprocessor;
398: Uart *up = a;
399:
400: USED(ur, a);
401:
402: multiprocessor = active.machs > 1;
403: for(;;){
404: s = uartrdreg(up, Istat);
405: switch(s & 0x3F){
406: case 6: /* receiver line status */
407: l = uartrdreg(up, Lstat);
408: if(l & Ferror)
409: up->frame++;
410: if(l & Oerror)
411: up->overrun++;
412: break;
413:
414: case 4: /* received data available */
415: case 12:
416: ch = uartrdreg(up, Data) & 0xff;
417: cq = up->iq;
418: if(cq == 0)
419: break;
420: if(cq->putc)
421: (*cq->putc)(cq, ch);
422: else
423: putc(cq, ch);
424: break;
425:
426: case 2: /* transmitter empty */
427: cq = up->oq;
428: if(cq == 0)
429: break;
430: if(multiprocessor)
431: lock(cq);
432: if(up->cts == 0)
433: up->printing = 0;
434: else {
435: ch = getc(cq);
436: if(ch < 0){
437: up->printing = 0;
438: wakeup(&cq->r);
439: }else
440: outb(up->port + Data, ch);
441: }
442: if(multiprocessor)
443: unlock(cq);
444: break;
445:
446: case 0: /* modem status */
447: ch = uartrdreg(up, Mstat);
448: if(ch & Ctsc){
449: up->cts = ch & Cts;
450: cq = up->oq;
451: if(cq == 0)
452: break;
453: if(multiprocessor)
454: lock(cq);
455: if(up->cts && up->printing == 0){
456: ch = getc(cq);
457: if(ch >= 0){
458: up->printing = 1;
459: outb(up->port + Data, ch);
460: } else
461: wakeup(&cq->r);
462: }
463: if(multiprocessor)
464: unlock(cq);
465: }
466: break;
467:
468: default:
469: if(s&1)
470: return;
471: print("weird modem interrupt #%2.2ux\n", s);
472: break;
473: }
474: }
475: }
476:
477: void
478: mp008intr(Ureg *ur, void *a)
479: {
480: uchar i, n;
481: Scard *sc = a;
482:
483: USED(ur);
484:
485: n = ~inb(sc->mem);
486: for(i = 0; n; i++){
487: if(n & 1)
488: uartintr(ur, &uart[sc->first + i]);
489: n >>= 1;
490: }
491: }
492:
493: void
494: uartclock(void)
495: {
496: Uart *up;
497: IOQ *cq;
498:
499: for(up = uart; up < &uart[Nuart]; up++){
500: cq = up->iq;
501: if(up->wq && cangetc(cq))
502: wakeup(&cq->r);
503: }
504: }
505:
506:
507: /*
508: * turn on a port's interrupts. set DTR and RTS
509: */
510: void
511: uartenable(Uart *up)
512: {
513: /*
514: * turn on power to the port
515: */
516: if(up == &uart[Modem]){
517: if(modem(1) < 0)
518: print("can't turn on modem speaker\n");
519: } else {
520: if(serial(1) < 0)
521: print("can't turn on serial port power\n");
522: }
523:
524: /*
525: * set up i/o routines
526: */
527: if(up->oq){
528: up->oq->puts = uartputs;
529: up->oq->ptr = up;
530: }
531: if(up->iq){
532: up->iq->ptr = up;
533: }
534: up->enabled = 1;
535:
536: /*
537: * turn on interrupts
538: */
539: up->sticky[Iena] = Ircv | Ixmt | Irstat;
540: uartwrreg(up, Iena, 0);
541:
542: /*
543: * turn on DTR and RTS
544: */
545: uartdtr(up, 1);
546: uartrts(up, 1);
547:
548: /*
549: * assume we can send
550: */
551: up->cts = 1;
552: }
553:
554: /*
555: * turn off the uart
556: */
557: void
558: uartdisable(Uart *up)
559: {
560:
561: /*
562: * turn off interrupts
563: */
564: up->sticky[Iena] = 0;
565: uartwrreg(up, Iena, 0);
566:
567: /*
568: * revert to default settings
569: */
570: up->sticky[Format] = Bits8;
571: uartwrreg(up, Format, 0);
572:
573: /*
574: * turn off DTR and RTS
575: */
576: uartdtr(up, 0);
577: uartrts(up, 0);
578: up->enabled = 0;
579:
580: /*
581: * turn off power
582: */
583: if(up == &uart[Modem]){
584: if(modem(0) < 0)
585: print("can't turn off modem speaker\n");
586: } else {
587: if(serial(0) < 0)
588: print("can't turn off serial power\n");
589: }
590: }
591:
592: /*
593: * set up an uart port as something other than a stream
594: */
595: void
596: uartspecial(int port, IOQ *oq, IOQ *iq, int baud)
597: {
598: Uart *up = &uart[port];
599:
600: uartsetup();
601: up->special = 1;
602: up->oq = oq;
603: up->iq = iq;
604: uartenable(up);
605: if(baud)
606: uartsetbaud(up, baud);
607:
608: if(iq){
609: /*
610: * Stupid HACK to undo a stupid hack
611: */
612: if(iq == &kbdq)
613: kbdq.putc = kbdcr2nl;
614: }
615: }
616:
617: static int uartputc(IOQ *, int);
618: static void uartstopen(Queue*, Stream*);
619: static void uartstclose(Queue*);
620: static void uartoput(Queue*, Block*);
621: static void uartkproc(void *);
622: Qinfo uartinfo =
623: {
624: nullput,
625: uartoput,
626: uartstopen,
627: uartstclose,
628: "uart"
629: };
630:
631: static void
632: uartstopen(Queue *q, Stream *s)
633: {
634: Uart *up;
635: char name[NAMELEN];
636:
637: up = &uart[s->id];
638: up->iq->putc = 0;
639: uartenable(up);
640:
641: qlock(up);
642: up->wq = WR(q);
643: WR(q)->ptr = up;
644: RD(q)->ptr = up;
645: qunlock(up);
646:
647: if(up->kstarted == 0){
648: up->kstarted = 1;
649: sprint(name, "uart%d", s->id);
650: kproc(name, uartkproc, up);
651: }
652: }
653:
654: static void
655: uartstclose(Queue *q)
656: {
657: Uart *up = q->ptr;
658:
659: if(up->special)
660: return;
661:
662: uartdisable(up);
663:
664: qlock(up);
665: kprint("uartstclose: q=0x%ux, id=%d\n", q, up-uart);
666: up->wq = 0;
667: up->iq->putc = 0;
668: WR(q)->ptr = 0;
669: RD(q)->ptr = 0;
670: qunlock(up);
671: }
672:
673: static int
674: xmtempty(void *arg)
675: {
676: IOQ *q=arg;
677:
678: return !cangetc(q);
679: }
680:
681: static void
682: uartoput(Queue *q, Block *bp)
683: {
684: Uart *up = q->ptr;
685: IOQ *cq;
686: int n, m;
687:
688: if(up == 0){
689: freeb(bp);
690: return;
691: }
692: cq = up->oq;
693: if(waserror()){
694: freeb(bp);
695: nexterror();
696: }
697: if(bp->type == M_CTL){
698: if(cangetc(cq)) /* let output drain */
699: sleep(&cq->r, xmtempty, cq);
700: n = strtoul((char *)(bp->rptr+1), 0, 0);
701: switch(*bp->rptr){
702: case 'B':
703: case 'b':
704: if(n <= 0)
705: error(Ebadctl);
706: uartsetbaud(up, n);
707: break;
708: case 'D':
709: case 'd':
710: uartdtr(up, n);
711: break;
712: case 'K':
713: case 'k':
714: uartbreak(up, n);
715: break;
716: case 'L':
717: case 'l':
718: uartbits(up, n);
719: break;
720: case 'm':
721: case 'M':
722: uartmflow(up, n);
723: break;
724: case 'P':
725: case 'p':
726: uartparity(up, *(bp->rptr+1));
727: break;
728: case 'R':
729: case 'r':
730: uartrts(up, n);
731: break;
732: case 'S':
733: case 's':
734: uartstop(up, n);
735: break;
736: }
737: }else while((m = BLEN(bp)) > 0){
738: while ((n = canputc(cq)) == 0){
739: sleep(&cq->r, canputc, cq);
740: }
741: if(n > m)
742: n = m;
743: (*cq->puts)(cq, bp->rptr, n);
744: bp->rptr += n;
745: }
746: freeb(bp);
747: poperror();
748: }
749:
750: /*
751: * process to send bytes upstream for a port
752: */
753: static void
754: uartkproc(void *a)
755: {
756: Uart *up = a;
757: IOQ *cq = up->iq;
758: Block *bp;
759: int n;
760: ulong frame, overrun;
761: static ulong ints;
762:
763: frame = 0;
764: overrun = 0;
765:
766: if(waserror())
767: print("uartkproc got an error\n");
768:
769: for(;;){
770: sleep(&cq->r, cangetc, cq);
771: if((ints++ & 0x1f) == 0)
772: lights((ints>>5)&1);
773: qlock(up);
774: if(up->wq == 0){
775: cq->out = cq->in;
776: }else{
777: n = cangetc(cq);
778: bp = allocb(n);
779: bp->flags |= S_DELIM;
780: bp->wptr += gets(cq, bp->wptr, n);
781: PUTNEXT(RD(up->wq), bp);
782: }
783: qunlock(up);
784: if(up->frame != frame){
785: kprint("uart%d: %d framing\n", up-uart, up->frame);
786: frame = up->frame;
787: }
788: if(up->overrun != overrun){
789: kprint("uart%d: %d overruns\n", up-uart, up->overrun);
790: overrun = up->overrun;
791: }
792: }
793: }
794:
795: enum{
796: Qdir= 0,
797: };
798:
799: Dirtab uartdir[2*nelem(uart)];
800:
801: /*
802: * allocate the queues if no one else has
803: */
804: void
805: uartreset(void)
806: {
807: Uart *up;
808:
809: uartsetup();
810: for(up = uart; up < &uart[Nuart]; up++){
811: if(up->special)
812: continue;
813: up->iq = xalloc(sizeof(IOQ));
814: initq(up->iq);
815: up->oq = xalloc(sizeof(IOQ));
816: initq(up->oq);
817: }
818: }
819:
820: void
821: uartinit(void)
822: {
823: int i;
824:
825: for(i=0; i < 2*Nuart; ++i) {
826: if(i & 1) {
827: sprint(uartdir[i].name, "eia%dctl", i/2);
828: uartdir[i].qid.path = STREAMQID(i/2, Sctlqid);
829: } else {
830: sprint(uartdir[i].name, "eia%d", i/2);
831: uartdir[i].qid.path = STREAMQID(i/2, Sdataqid);
832: }
833: uartdir[i].length = 0;
834: uartdir[i].perm = 0660;
835: }
836: }
837:
838: Chan*
839: uartattach(char *upec)
840: {
841: return devattach('t', upec);
842: }
843:
844: Chan*
845: uartclone(Chan *c, Chan *nc)
846: {
847: return devclone(c, nc);
848: }
849:
850: int
851: uartwalk(Chan *c, char *name)
852: {
853: return devwalk(c, name, uartdir, Nuart * 2, devgen);
854: }
855:
856: void
857: uartstat(Chan *c, char *dp)
858: {
859: int i;
860:
861: for(i=0; i < 2*Nuart; i += 2)
862: if(c->qid.path == uartdir[i].qid.path) {
863: streamstat(c, dp, uartdir[i].name, uartdir[i].perm);
864: return;
865: }
866: devstat(c, dp, uartdir, Nuart * 2, devgen);
867: }
868:
869: Chan*
870: uartopen(Chan *c, int omode)
871: {
872: Uart *up;
873: int i;
874:
875: up = 0;
876: for(i=0; i < 2*Nuart; ++i)
877: if(c->qid.path == uartdir[i].qid.path) {
878: up = &uart[i/2];
879: break;
880: }
881:
882: if(up && up->special)
883: error(Einuse);
884: if((c->qid.path & CHDIR) == 0)
885: streamopen(c, &uartinfo);
886: return devopen(c, omode, uartdir, Nuart * 2, devgen);
887: }
888:
889: void
890: uartcreate(Chan *c, char *name, int omode, ulong perm)
891: {
892: USED(c, name, omode, perm);
893: error(Eperm);
894: }
895:
896: void
897: uartclose(Chan *c)
898: {
899: if(c->stream)
900: streamclose(c);
901: }
902:
903: long
904: uartstatus(Uart *up, void *buf, long n, ulong offset)
905: {
906: uchar mstat;
907: uchar tstat;
908: char str[128];
909:
910: str[0] = 0;
911: tstat = up->sticky[Mctl];
912: mstat = uartrdreg(up, Mstat);
913: if(mstat & Cts)
914: strcat(str, " cts");
915: if(mstat & Dsr)
916: strcat(str, " dsr");
917: if(mstat & Ring)
918: strcat(str, " ring");
919: if(mstat & Dcd)
920: strcat(str, " dcd");
921: if(tstat & Dtr)
922: strcat(str, " dtr");
923: if(tstat & Rts)
924: strcat(str, " rts");
925: return readstr(offset, buf, n, str);
926: }
927:
928: long
929: uartread(Chan *c, void *buf, long n, ulong offset)
930: {
931: int i;
932: long qpath;
933:
934: USED(offset);
935: qpath = c->qid.path & ~CHDIR;
936: if(qpath == Qdir)
937: return devdirread(c, buf, n, uartdir, Nuart * 2, devgen);
938: for(i=1; i < 2*Nuart; i += 2)
939: if(qpath == uartdir[i].qid.path)
940: return uartstatus(&uart[i/2], buf, n, offset);
941: return streamread(c, buf, n);
942: }
943:
944: long
945: uartwrite(Chan *c, void *va, long n, ulong offset)
946: {
947: USED(offset);
948: return streamwrite(c, va, n, 0);
949: }
950:
951: void
952: uartremove(Chan *c)
953: {
954: USED(c);
955: error(Eperm);
956: }
957:
958: void
959: uartwstat(Chan *c, char *dp)
960: {
961: USED(c, dp);
962: error(Eperm);
963: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.