|
|
1.1 root 1: /*
2: * VAX 8[578]00 console driver
3: */
4: #include "sys/param.h"
5: #include "sys/stream.h"
6: #include "sys/ttyio.h"
7: #include "sys/cons.h"
8: #include "sys/mtpr.h"
9: #include "sys/conf.h"
10:
11: #define NCONS 16 /* possible console IDs */
12:
13: #define DATA 0xff
14: #define IDMASK 0xff
15: #define IDSHIFT 8
16:
17: #define CONPRI (PZERO+5) /* something interruptible */
18:
19: /*
20: * state bits
21: */
22: #define TTSTOP 01
23: #define TIMEOUT 04
24:
25: /*
26: * cnbusy bits
27: */
28: #define TXBUSY 01
29: #define IOBUSY 02 /* cninc/cnoutc busy */
30:
31: static char cnbusy;
32: static char cnonext;
33: static char cnstate[NCONS];
34: static struct queue *cnrq[NCONS];
35: static struct queue *cnwq[NCONS];
36:
37: /*
38: * for internal io without device open
39: */
40: struct cnbuf {
41: int count;
42: char *buf;
43: };
44: static struct cnbuf cnibuf[NCONS];
45: static struct cnbuf cnobuf[NCONS];
46: static short cnlastin; /* debugging */
47:
48: long cnopen();
49: int cnclose(), cnoput();
50:
51: static struct qinit cnrinit = { nulldev, NULL, cnopen, cnclose, 0, 0 };
52: static struct qinit cnwinit = { cnoput, NULL, cnopen, cnclose, 200, 100 };
53: struct streamtab cnstream = { &cnrinit, &cnwinit };
54: struct cdevsw cncdev = cstrinit(&cnstream);
55:
56: long
57: cnopen(qp, dev)
58: struct queue *qp;
59: dev_t dev;
60: {
61: register int i;
62:
63: i = minor(dev);
64: if (i >= NCONS)
65: return (1);
66: cnrq[i] = qp;
67: cnwq[i] = WR(qp);
68: qp->ptr = (caddr_t)i;
69: mtpr(RXCS, mfpr(RXCS)|RXCS_IE);
70: return(1);
71: }
72:
73: cnclose(qp)
74: struct queue *qp;
75: {
76: register int i;
77:
78: i = (int)qp->ptr;
79: cnrq[i] = NULL;
80: cnwq[i] = NULL;
81: }
82:
83: /*
84: * Console write put routine
85: */
86: cnoput(q, bp)
87: register struct queue *q;
88: register struct block *bp;
89: {
90: register struct ttydevb *sp;
91: register int dev;
92:
93: dev = (int)OTHERQ(q)->ptr;
94: switch(bp->type) {
95: case M_IOCTL: /* just acknowledge */
96: sp = (struct ttydevb *)stiodata(bp);
97: switch (stiocom(bp)) {
98: case TIOCGDEV:
99: sp->ispeed = sp->ospeed = B9600;
100: bp->wptr = bp->rptr + sizeof(struct ttydevb) + STIOCHDR;
101: bp->type = M_IOCACK;
102: qreply(q, bp);
103: return;
104:
105: case TIOCSDEV:
106: bp->wptr = bp->rptr;
107: bp->type = M_IOCACK;
108: qreply(q, bp);
109: return;
110:
111: default:
112: bp->type = M_IOCNAK;
113: bp->wptr = bp->rptr;
114: qreply(q, bp);
115: return;
116: }
117:
118: case M_STOP:
119: cnstate[dev] |= TTSTOP;
120: break;
121:
122: case M_START:
123: cnstate[dev] &= ~TTSTOP;
124: cnstart();
125: break;
126:
127: case M_FLUSH:
128: flushq(q, 0);
129: break;
130:
131: case M_DELAY:
132: case M_DATA:
133: if (bp->rptr >= bp->wptr)
134: break;
135: putq(q, bp);
136: cnstart();
137: return;
138:
139: default: /* not handled; just toss */
140: break;
141: }
142: freeb(bp);
143: }
144:
145: /*
146: * Console receive interrupt
147: */
148:
149: cnrint()
150: {
151: register int c, dev;
152: register struct queue *qp;
153: register struct cnbuf *cp;
154:
155: c = mfpr(RXDB);
156: dev = (c >> IDSHIFT) & IDMASK;
157: cp = &cnibuf[dev];
158: if (cp->count) {
159: *cp->buf++ = c;
160: if (--cp->count == 0)
161: wakeup((caddr_t)&cp->count);
162: return;
163: }
164: if ((qp = cnrq[dev])!=NULL) {
165: if ((qp->next->flag & QFULL) == 0)
166: putd(qp->next->qinfo->putp, qp->next, c);
167: return;
168: }
169: cnlastin = c; /* for debugging */
170: }
171:
172: /*
173: * Transmitter interrupt
174: */
175: cnxint()
176: {
177: cnbusy &=~ TXBUSY;
178: mtpr(TXCS, mfpr(TXCS)&~TXCS_IE);
179: cnstart();
180: }
181:
182: cntime(dev)
183: caddr_t dev;
184: {
185: cnstate[(int)dev] &= ~TIMEOUT;
186: cnstart();
187: }
188:
189: #define NEXT(i) (((i)+1)%NCONS)
190:
191: cnstart()
192: {
193: register struct block *bp;
194: register int i;
195: register struct queue *q;
196: register struct cnbuf *cp;
197: register s, j;
198:
199: s = spl6();
200: if (cnbusy & TXBUSY) {
201: splx(s);
202: return;
203: }
204: i = cnonext;
205: for (j = 0; j < NCONS && (cnbusy & TXBUSY) == 0; i = NEXT(i), j++) {
206: cp = &cnobuf[i];
207: if (cp->count) {
208: mtpr(TXDB, (*cp->buf++&0377) | (i<<IDSHIFT));
209: mtpr(TXCS, mfpr(TXCS)|TXCS_IE);
210: cnbusy |= TXBUSY;
211: if (--cp->count == 0)
212: wakeup((caddr_t)&cp->count);
213: continue;
214: }
215: if ((q = cnwq[i]) == NULL)
216: continue;
217: if ((cnstate[i] & (TIMEOUT|TTSTOP)) || q->count == 0)
218: continue;
219: bp = getq(q);
220: switch (bp->type) {
221: case M_DATA:
222: mtpr(TXDB, (i<<IDSHIFT)|*bp->rptr++);
223: mtpr(TXCS, mfpr(TXCS)|TXCS_IE);
224: cnbusy |= TXBUSY;
225: if (bp->rptr >= bp->wptr)
226: freeb(bp);
227: else
228: putbq(q, bp);
229: break;
230:
231: case M_DELAY:
232: timeout(cntime, (caddr_t)i, (int)*bp->rptr);
233: cnstate[i] |= TIMEOUT;
234: default: /* flow through */
235: freeb(bp);
236: break;
237: }
238: }
239: cnonext = i;
240: splx(s);
241: }
242:
243: /*
244: * Print a character on console; for printf.
245: * try to preserve things; wait a bit for console to come ready.
246: * all fairly hopeless.
247: */
248: cnputc(c)
249: register c;
250: {
251: register s, timo;
252:
253: timo = 3000000;
254: while((mfpr(TXCS)&TXCS_RDY) == 0)
255: if(--timo == 0)
256: return;
257: if(c == 0)
258: return;
259: s = mfpr(TXCS);
260: mtpr(TXCS, 0);
261: mtpr(TXDB, c&DATA);
262: if(c == '\n')
263: cnputc('\r');
264: cnputc(0);
265: mtpr(TXCS, s);
266: }
267:
268: /*
269: * primitives for internal console I/O
270: * p = cniwrite(id, buf, count)
271: * p = cniread(id, buf, count)
272: * p is a pointer to an integer.
273: * when the count is satisfied, *p will be zero and p will be awakened
274: * *p = 0 aborts the I/O
275: * cniwait(p, s) waits for at most s seconds, then aborts
276: *
277: * only one I/O may be outstanding per id;
278: * a new one aborts the previous one, quietly
279: *
280: * buf had best be static; stacks move, and the process waiting for io
281: * will almost certainly go out of context.
282: * hence the KSTART checks.
283: */
284:
285: int *
286: cniread(id, buf, count)
287: int id, count;
288: char *buf;
289: {
290: register struct cnbuf *cp;
291:
292: if (id < 0 || id >= NCONS || (int)buf < KSTART)
293: panic("cniread");
294: cp = &cnibuf[id];
295: cp->buf = buf;
296: cp->count = count;
297: mtpr(RXCS, mfpr(RXCS)|RXCS_IE);
298: return (&cp->count);
299: }
300:
301: int *
302: cniwrite(id, buf, count)
303: int id, count;
304: char *buf;
305: {
306: register struct cnbuf *cp;
307:
308: if (id < 0 || id >= NCONS || (int)buf < KSTART)
309: panic("cniwrite");
310: cp = &cnobuf[id];
311: cp->buf = buf;
312: cp->count = count;
313: cnstart();
314: return (&cp->count);
315: }
316:
317: cniwait(p, t)
318: register int *p;
319: int t;
320: {
321: register int s;
322: register int sh;
323:
324: s = spl6();
325: while (*p)
326: if (tsleep((caddr_t)p, CONPRI, t) != TS_OK) {
327: sh = *p;
328: *p = 0;
329: splx(s);
330: return (sh);
331: }
332: splx(s);
333: return (0);
334: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.