|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)dca.c 7.7 (Berkeley) 6/30/90
21: */
22:
23: #include "dca.h"
24: #if NDCA > 0
25: /*
26: * 98626/98644/internal serial interface
27: */
28: #include "param.h"
29: #include "systm.h"
30: #include "ioctl.h"
31: #include "tty.h"
32: #include "user.h"
33: #include "conf.h"
34: #include "file.h"
35: #include "uio.h"
36: #include "kernel.h"
37: #include "syslog.h"
38:
39: #include "device.h"
40: #include "dcareg.h"
41: #include "machine/cpu.h"
42: #include "machine/isr.h"
43:
44: int dcaprobe();
45: struct driver dcadriver = {
46: dcaprobe, "dca",
47: };
48:
49: int dcastart(), dcaparam(), dcaintr();
50: int dcasoftCAR;
51: int dca_active;
52: int ndca = NDCA;
53: int dcaconsole = -1;
54: int dcadefaultrate = TTYDEF_SPEED;
55: struct dcadevice *dca_addr[NDCA];
56: struct tty dca_tty[NDCA];
57: struct isr dcaisr[NDCA];
58:
59: struct speedtab dcaspeedtab[] = {
60: 0, 0,
61: 50, DCABRD(50),
62: 75, DCABRD(75),
63: 110, DCABRD(110),
64: 134, DCABRD(134),
65: 150, DCABRD(150),
66: 200, DCABRD(200),
67: 300, DCABRD(300),
68: 600, DCABRD(600),
69: 1200, DCABRD(1200),
70: 1800, DCABRD(1800),
71: 2400, DCABRD(2400),
72: 4800, DCABRD(4800),
73: 9600, DCABRD(9600),
74: 19200, DCABRD(19200),
75: 38400, DCABRD(38400),
76: -1, -1
77: };
78:
79: extern struct tty *constty;
80: #ifdef KGDB
81: extern int kgdb_dev;
82: extern int kgdb_rate;
83: extern int kgdb_debug_init;
84: #endif
85:
86: #define UNIT(x) minor(x)
87:
88: dcaprobe(hd)
89: register struct hp_device *hd;
90: {
91: register struct dcadevice *dca;
92: register int unit;
93:
94: dca = (struct dcadevice *)hd->hp_addr;
95: if (dca->dca_irid != DCAID0 &&
96: dca->dca_irid != DCAREMID0 &&
97: dca->dca_irid != DCAID1 &&
98: dca->dca_irid != DCAREMID1)
99: return (0);
100: unit = hd->hp_unit;
101: if (unit == dcaconsole)
102: DELAY(100000);
103: dca->dca_irid = 0xFF;
104: DELAY(100);
105:
106: hd->hp_ipl = DCAIPL(dca->dca_ic);
107: dcaisr[unit].isr_ipl = hd->hp_ipl;
108: dcaisr[unit].isr_arg = unit;
109: dcaisr[unit].isr_intr = dcaintr;
110: dca_addr[unit] = dca;
111: dca_active |= 1 << unit;
112: dcasoftCAR = hd->hp_flags;
113: isrlink(&dcaisr[unit]);
114: #ifdef KGDB
115: if (kgdb_dev == makedev(1, unit)) {
116: if (dcaconsole == unit)
117: kgdb_dev = -1; /* can't debug over console port */
118: else {
119: (void) dcainit(unit);
120: dcaconsole = -2; /* XXX */
121: if (kgdb_debug_init) {
122: printf("dca%d: kgdb waiting...", unit);
123: /* trap into kgdb */
124: asm("trap #15;");
125: printf("connected.\n");
126: } else
127: printf("dca%d: kgdb enabled\n", unit);
128: }
129: }
130: #endif
131: dca->dca_ic = IC_IE;
132: /*
133: * Need to reset baud rate, etc. of next print so reset dcaconsole.
134: * Also make sure console is always "hardwired"
135: */
136: if (unit == dcaconsole) {
137: dcaconsole = -1;
138: dcasoftCAR |= (1 << unit);
139: }
140: return (1);
141: }
142:
143: dcaopen(dev, flag)
144: dev_t dev;
145: {
146: register struct tty *tp;
147: register int unit;
148: int error = 0;
149:
150: unit = UNIT(dev);
151: if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
152: return (ENXIO);
153: tp = &dca_tty[unit];
154: tp->t_oproc = dcastart;
155: tp->t_param = dcaparam;
156: tp->t_dev = dev;
157: if ((tp->t_state & TS_ISOPEN) == 0) {
158: tp->t_state |= TS_WOPEN;
159: ttychars(tp);
160: tp->t_iflag = TTYDEF_IFLAG;
161: tp->t_oflag = TTYDEF_OFLAG;
162: tp->t_cflag = TTYDEF_CFLAG;
163: tp->t_lflag = TTYDEF_LFLAG;
164: tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
165: dcaparam(tp, &tp->t_termios);
166: ttsetwater(tp);
167: } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
168: return (EBUSY);
169: (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
170: if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
171: tp->t_state |= TS_CARR_ON;
172: (void) spltty();
173: while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
174: (tp->t_state & TS_CARR_ON) == 0) {
175: tp->t_state |= TS_WOPEN;
176: if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
177: ttopen, 0))
178: break;
179: }
180: (void) spl0();
181: if (error == 0)
182: error = (*linesw[tp->t_line].l_open)(dev, tp);
183: return (error);
184: }
185:
186: /*ARGSUSED*/
187: dcaclose(dev, flag)
188: dev_t dev;
189: {
190: register struct tty *tp;
191: register struct dcadevice *dca;
192: register int unit;
193:
194: unit = UNIT(dev);
195: dca = dca_addr[unit];
196: tp = &dca_tty[unit];
197: (*linesw[tp->t_line].l_close)(tp);
198: dca->dca_cfcr &= ~CFCR_SBREAK;
199: #ifdef KGDB
200: /* do not disable interrupts if debugging */
201: if (kgdb_dev != makedev(1, unit))
202: #endif
203: dca->dca_ier = 0;
204: if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
205: (tp->t_state&TS_ISOPEN) == 0)
206: (void) dcamctl(dev, 0, DMSET);
207: ttyclose(tp);
208: return(0);
209: }
210:
211: dcaread(dev, uio, flag)
212: dev_t dev;
213: struct uio *uio;
214: {
215: register struct tty *tp = &dca_tty[UNIT(dev)];
216:
217: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
218: }
219:
220: dcawrite(dev, uio, flag)
221: dev_t dev;
222: struct uio *uio;
223: {
224: int unit = UNIT(dev);
225: register struct tty *tp = &dca_tty[unit];
226:
227: /*
228: * (XXX) We disallow virtual consoles if the physical console is
229: * a serial port. This is in case there is a display attached that
230: * is not the console. In that situation we don't need/want the X
231: * server taking over the console.
232: */
233: if (constty && unit == dcaconsole)
234: constty = NULL;
235: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
236: }
237:
238: dcaintr(unit)
239: register int unit;
240: {
241: register struct dcadevice *dca;
242: register u_char code;
243: register struct tty *tp;
244:
245: dca = dca_addr[unit];
246: if ((dca->dca_ic & IC_IR) == 0)
247: return(0);
248: while (1) {
249: code = dca->dca_iir;
250: switch (code) {
251: case IIR_NOPEND:
252: return (1);
253: case IIR_RXRDY:
254: /* do time-critical read in-line */
255: tp = &dca_tty[unit];
256: code = dca->dca_data;
257: if ((tp->t_state & TS_ISOPEN) == 0) {
258: #ifdef KGDB
259: if (kgdb_dev == makedev(1, unit) &&
260: code == '!') {
261: printf("kgdb trap from dca%d\n", unit);
262: /* trap into kgdb */
263: asm("trap #15;");
264: }
265: #endif
266: } else
267: (*linesw[tp->t_line].l_rint)(code, tp);
268: break;
269: case IIR_TXRDY:
270: tp = &dca_tty[unit];
271: tp->t_state &=~ (TS_BUSY|TS_FLUSH);
272: if (tp->t_line)
273: (*linesw[tp->t_line].l_start)(tp);
274: else
275: dcastart(tp);
276: break;
277: case IIR_RLS:
278: dcaeint(unit, dca);
279: break;
280: default:
281: if (code & IIR_NOPEND)
282: return (1);
283: log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
284: unit, code);
285: /* fall through */
286: case IIR_MLSC:
287: dcamint(unit, dca);
288: break;
289: }
290: }
291: }
292:
293: dcaeint(unit, dca)
294: register int unit;
295: register struct dcadevice *dca;
296: {
297: register struct tty *tp;
298: register int stat, c;
299:
300: tp = &dca_tty[unit];
301: stat = dca->dca_lsr;
302: c = dca->dca_data;
303: if ((tp->t_state & TS_ISOPEN) == 0) {
304: #ifdef KGDB
305: /* we don't care about parity errors */
306: if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
307: kgdb_dev == makedev(1, unit) && c == '!') {
308: printf("kgdb trap from dca%d\n", unit);
309: /* trap into kgdb */
310: asm("trap #15;");
311: }
312: #endif
313: return;
314: }
315: if (stat & (LSR_BI | LSR_FE))
316: c |= TTY_FE;
317: else if (stat & LSR_PE)
318: c |= TTY_PE;
319: else if (stat & LSR_OE)
320: log(LOG_WARNING, "dca%d: silo overflow\n", unit);
321: (*linesw[tp->t_line].l_rint)(c, tp);
322: }
323:
324: dcamint(unit, dca)
325: register int unit;
326: register struct dcadevice *dca;
327: {
328: register struct tty *tp;
329: register int stat;
330:
331: tp = &dca_tty[unit];
332: stat = dca->dca_msr;
333: if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
334: if (stat & MSR_DCD)
335: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
336: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
337: dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
338: } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
339: (tp->t_flags & CRTSCTS)) {
340: /* the line is up and we want to do rts/cts flow control */
341: if (stat & MSR_CTS) {
342: tp->t_state &=~ TS_TTSTOP;
343: ttstart(tp);
344: } else
345: tp->t_state |= TS_TTSTOP;
346: }
347: }
348:
349: dcaioctl(dev, cmd, data, flag)
350: dev_t dev;
351: caddr_t data;
352: {
353: register struct tty *tp;
354: register int unit = UNIT(dev);
355: register struct dcadevice *dca;
356: register int error;
357:
358: tp = &dca_tty[unit];
359: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
360: if (error >= 0)
361: return (error);
362: error = ttioctl(tp, cmd, data, flag);
363: if (error >= 0)
364: return (error);
365:
366: dca = dca_addr[unit];
367: switch (cmd) {
368:
369: case TIOCSBRK:
370: dca->dca_cfcr |= CFCR_SBREAK;
371: break;
372:
373: case TIOCCBRK:
374: dca->dca_cfcr &= ~CFCR_SBREAK;
375: break;
376:
377: case TIOCSDTR:
378: (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
379: break;
380:
381: case TIOCCDTR:
382: (void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
383: break;
384:
385: case TIOCMSET:
386: (void) dcamctl(dev, *(int *)data, DMSET);
387: break;
388:
389: case TIOCMBIS:
390: (void) dcamctl(dev, *(int *)data, DMBIS);
391: break;
392:
393: case TIOCMBIC:
394: (void) dcamctl(dev, *(int *)data, DMBIC);
395: break;
396:
397: case TIOCMGET:
398: *(int *)data = dcamctl(dev, 0, DMGET);
399: break;
400:
401: default:
402: return (ENOTTY);
403: }
404: return (0);
405: }
406:
407: dcaparam(tp, t)
408: register struct tty *tp;
409: register struct termios *t;
410: {
411: register struct dcadevice *dca;
412: register int cfcr, cflag = t->c_cflag;
413: int unit = UNIT(tp->t_dev);
414: int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
415:
416: /* check requested parameters */
417: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
418: return(EINVAL);
419: /* and copy to tty */
420: tp->t_ispeed = t->c_ispeed;
421: tp->t_ospeed = t->c_ospeed;
422: tp->t_cflag = cflag;
423:
424: dca = dca_addr[unit];
425: dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
426: if (ospeed == 0) {
427: (void) dcamctl(unit, 0, DMSET); /* hang up line */
428: return(0);
429: }
430: dca->dca_cfcr |= CFCR_DLAB;
431: dca->dca_data = ospeed & 0xFF;
432: dca->dca_ier = ospeed >> 8;
433: switch (cflag&CSIZE) {
434: case CS5:
435: cfcr = CFCR_5BITS; break;
436: case CS6:
437: cfcr = CFCR_6BITS; break;
438: case CS7:
439: cfcr = CFCR_7BITS; break;
440: case CS8:
441: cfcr = CFCR_8BITS; break;
442: }
443: if (cflag&PARENB) {
444: cfcr |= CFCR_PENAB;
445: if ((cflag&PARODD) == 0)
446: cfcr |= CFCR_PEVEN;
447: }
448: if (cflag&CSTOPB)
449: cfcr |= CFCR_STOPB;
450: dca->dca_cfcr = cfcr;
451: return(0);
452: }
453:
454: dcastart(tp)
455: register struct tty *tp;
456: {
457: register struct dcadevice *dca;
458: int s, unit, c;
459:
460: unit = UNIT(tp->t_dev);
461: dca = dca_addr[unit];
462: s = spltty();
463: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
464: goto out;
465: if (tp->t_outq.c_cc <= tp->t_lowat) {
466: if (tp->t_state&TS_ASLEEP) {
467: tp->t_state &= ~TS_ASLEEP;
468: wakeup((caddr_t)&tp->t_outq);
469: }
470: if (tp->t_wsel) {
471: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
472: tp->t_wsel = 0;
473: tp->t_state &= ~TS_WCOLL;
474: }
475: }
476: if (tp->t_outq.c_cc == 0)
477: goto out;
478: if (dca->dca_lsr & LSR_TXRDY) {
479: c = getc(&tp->t_outq);
480: tp->t_state |= TS_BUSY;
481: dca->dca_data = c;
482: }
483: out:
484: splx(s);
485: }
486:
487: /*
488: * Stop output on a line.
489: */
490: /*ARGSUSED*/
491: dcastop(tp, flag)
492: register struct tty *tp;
493: {
494: register int s;
495:
496: s = spltty();
497: if (tp->t_state & TS_BUSY) {
498: if ((tp->t_state&TS_TTSTOP)==0)
499: tp->t_state |= TS_FLUSH;
500: }
501: splx(s);
502: }
503:
504: dcamctl(dev, bits, how)
505: dev_t dev;
506: int bits, how;
507: {
508: register struct dcadevice *dca;
509: register int unit;
510: int s;
511:
512: unit = UNIT(dev);
513: dca = dca_addr[unit];
514: s = spltty();
515: switch (how) {
516:
517: case DMSET:
518: dca->dca_mcr = bits;
519: break;
520:
521: case DMBIS:
522: dca->dca_mcr |= bits;
523: break;
524:
525: case DMBIC:
526: dca->dca_mcr &= ~bits;
527: break;
528:
529: case DMGET:
530: bits = dca->dca_msr;
531: break;
532: }
533: (void) splx(s);
534: return(bits);
535: }
536:
537: /*
538: * Following are all routines needed for DCA to act as console
539: */
540: #include "machine/cons.h"
541:
542: dcacnprobe(cp)
543: struct consdev *cp;
544: {
545: int unit, i;
546: extern int dcaopen();
547:
548: /* XXX: ick */
549: unit = CONUNIT;
550: dca_addr[CONUNIT] = CONADDR;
551:
552: /* make sure hardware exists */
553: if (badaddr((short *)dca_addr[unit])) {
554: cp->cn_pri = CN_DEAD;
555: return;
556: }
557:
558: /* locate the major number */
559: for (i = 0; i < nchrdev; i++)
560: if (cdevsw[i].d_open == dcaopen)
561: break;
562:
563: /* initialize required fields */
564: cp->cn_dev = makedev(i, unit);
565: cp->cn_tp = &dca_tty[unit];
566: switch (dca_addr[unit]->dca_irid) {
567: case DCAID0:
568: case DCAID1:
569: cp->cn_pri = CN_NORMAL;
570: break;
571: case DCAREMID0:
572: case DCAREMID1:
573: cp->cn_pri = CN_REMOTE;
574: break;
575: default:
576: cp->cn_pri = CN_DEAD;
577: break;
578: }
579: }
580:
581: dcacninit(cp)
582: struct consdev *cp;
583: {
584: int unit = UNIT(cp->cn_dev);
585:
586: dcainit(unit);
587: dcaconsole = unit;
588: }
589:
590: dcainit(unit)
591: int unit;
592: {
593: register struct dcadevice *dca;
594: int s, rate;
595: short stat;
596:
597: #ifdef lint
598: stat = unit; if (stat) return;
599: #endif
600: dca = dca_addr[unit];
601: s = splhigh();
602: dca->dca_irid = 0xFF;
603: DELAY(100);
604: dca->dca_ic = IC_IE;
605: dca->dca_cfcr = CFCR_DLAB;
606: rate = ttspeedtab(dcadefaultrate, dcaspeedtab);
607: dca->dca_data = rate & 0xFF;
608: dca->dca_ier = rate >> 8;
609: dca->dca_cfcr = CFCR_8BITS;
610: dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
611: stat = dca->dca_iir;
612: splx(s);
613: }
614:
615: dcacngetc(dev)
616: {
617: register struct dcadevice *dca = dca_addr[UNIT(dev)];
618: short stat;
619: int c, s;
620:
621: #ifdef lint
622: stat = dev; if (stat) return(0);
623: #endif
624: s = splhigh();
625: while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
626: ;
627: c = dca->dca_data;
628: stat = dca->dca_iir;
629: splx(s);
630: return(c);
631: }
632:
633: /*
634: * Console kernel output character routine.
635: */
636: dcacnputc(dev, c)
637: dev_t dev;
638: register int c;
639: {
640: register struct dcadevice *dca = dca_addr[UNIT(dev)];
641: register int timo;
642: short stat;
643: int s = splhigh();
644:
645: #ifdef lint
646: stat = dev; if (stat) return;
647: #endif
648: if (dcaconsole == -1) {
649: (void) dcainit(UNIT(dev));
650: dcaconsole = UNIT(dev);
651: }
652: /* wait for any pending transmission to finish */
653: timo = 50000;
654: while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
655: ;
656: dca->dca_data = c;
657: /* wait for this transmission to complete */
658: timo = 1500000;
659: while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
660: ;
661: /* clear any interrupts generated by this transmission */
662: stat = dca->dca_iir;
663: splx(s);
664: }
665: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.