|
|
1.1 root 1: /*-
2: * Copyright (c) 1991 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)com.c 7.5 (Berkeley) 5/16/91
34: */
35:
36: #include "com.h"
37: #if NCOM > 0
38: /*
39: * COM driver, based on HP dca driver
40: * uses National Semiconductor NS16450/NS16550AF UART
41: */
42: #include "param.h"
43: #include "systm.h"
44: #include "ioctl.h"
45: #include "tty.h"
46: #include "proc.h"
47: #include "user.h"
48: #include "conf.h"
49: #include "file.h"
50: #include "uio.h"
51: #include "kernel.h"
52: #include "syslog.h"
53:
54: #include "i386/isa/isa_device.h"
55: #include "i386/isa/comreg.h"
56: #include "i386/isa/ic/ns16550.h"
57:
58: int comprobe(), comattach(), comintr(), comstart(), comparam();
59:
60: struct isa_driver comdriver = {
61: comprobe, comattach, "com"
62: };
63:
64: int comsoftCAR;
65: int com_active;
66: int com_hasfifo;
67: int ncom = NCOM;
68: #ifdef COMCONSOLE
69: int comconsole = COMCONSOLE;
70: #else
71: int comconsole = -1;
72: #endif
73: int comconsinit;
74: int comdefaultrate = TTYDEF_SPEED;
75: int commajor;
76: short com_addr[NCOM];
77: struct tty com_tty[NCOM];
78:
79: struct speedtab comspeedtab[] = {
80: 0, 0,
81: 50, COMBRD(50),
82: 75, COMBRD(75),
83: 110, COMBRD(110),
84: 134, COMBRD(134),
85: 150, COMBRD(150),
86: 200, COMBRD(200),
87: 300, COMBRD(300),
88: 600, COMBRD(600),
89: 1200, COMBRD(1200),
90: 1800, COMBRD(1800),
91: 2400, COMBRD(2400),
92: 4800, COMBRD(4800),
93: 9600, COMBRD(9600),
94: 19200, COMBRD(19200),
95: 38400, COMBRD(38400),
96: 57600, COMBRD(57600),
97: -1, -1
98: };
99:
100: extern struct tty *constty;
101: #ifdef KGDB
102: #include "machine/remote-sl.h"
103:
104: extern int kgdb_dev;
105: extern int kgdb_rate;
106: extern int kgdb_debug_init;
107: #endif
108:
109: #define UNIT(x) minor(x)
110:
111: comprobe(dev)
112: struct isa_device *dev;
113: {
114: /* force access to id reg */
115: outb(dev->id_iobase+com_cfcr, 0);
116: outb(dev->id_iobase+com_iir, 0);
117: if ((inb(dev->id_iobase+com_iir) & 0x38) == 0)
118: return(1);
119: return(1);
120:
121: }
122:
123:
124: int
125: comattach(isdp)
126: struct isa_device *isdp;
127: {
128: struct tty *tp;
129: u_char unit;
130: int port = isdp->id_iobase;
131:
132: unit = isdp->id_unit;
133: if (unit == comconsole)
134: DELAY(100000);
135: com_addr[unit] = port;
136: com_active |= 1 << unit;
137: comsoftCAR |= 1 << unit; /* XXX */
138:
139: /* look for a NS 16550AF UART with FIFOs */
140: outb(port+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
141: DELAY(100);
142: if ((inb(port+com_iir) & IIR_FIFO_MASK) == IIR_FIFO_MASK)
143: com_hasfifo |= 1 << unit;
144:
145: outb(port+com_ier, 0);
146: outb(port+com_mcr, 0 | MCR_IENABLE);
147: #ifdef KGDB
148: if (kgdb_dev == makedev(commajor, unit)) {
149: if (comconsole == unit)
150: kgdb_dev = -1; /* can't debug over console port */
151: else {
152: (void) cominit(unit, kgdb_rate);
153: if (kgdb_debug_init) {
154: /*
155: * Print prefix of device name,
156: * let kgdb_connect print the rest.
157: */
158: printf("com%d: ", unit);
159: kgdb_connect(1);
160: } else
161: printf("com%d: kgdb enabled\n", unit);
162: }
163: }
164: #endif
165: /*
166: * Need to reset baud rate, etc. of next print so reset comconsinit.
167: * Also make sure console is always "hardwired"
168: */
169: if (unit == comconsole) {
170: comconsinit = 0;
171: comsoftCAR |= (1 << unit);
172: }
173: return (1);
174: }
175:
176: /* ARGSUSED */
177: #ifdef __STDC__
178: comopen(dev_t dev, int flag, int mode, struct proc *p)
179: #else
180: comopen(dev, flag, mode, p)
181: dev_t dev;
182: int flag, mode;
183: struct proc *p;
184: #endif
185: {
186: register struct tty *tp;
187: register int unit;
188: int error = 0;
189:
190: unit = UNIT(dev);
191: if (unit >= NCOM || (com_active & (1 << unit)) == 0)
192: return (ENXIO);
193: tp = &com_tty[unit];
194: tp->t_oproc = comstart;
195: tp->t_param = comparam;
196: tp->t_dev = dev;
197: if ((tp->t_state & TS_ISOPEN) == 0) {
198: tp->t_state |= TS_WOPEN;
199: ttychars(tp);
200: if (tp->t_ispeed == 0) {
201: tp->t_iflag = TTYDEF_IFLAG;
202: tp->t_oflag = TTYDEF_OFLAG;
203: tp->t_cflag = TTYDEF_CFLAG;
204: tp->t_lflag = TTYDEF_LFLAG;
205: tp->t_ispeed = tp->t_ospeed = comdefaultrate;
206: }
207: comparam(tp, &tp->t_termios);
208: ttsetwater(tp);
209: } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
210: return (EBUSY);
211: (void) spltty();
212: (void) commctl(dev, MCR_DTR | MCR_RTS, DMSET);
213: if ((comsoftCAR & (1 << unit)) || (commctl(dev, 0, DMGET) & MSR_DCD))
214: tp->t_state |= TS_CARR_ON;
215: while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
216: (tp->t_state & TS_CARR_ON) == 0) {
217: tp->t_state |= TS_WOPEN;
218: if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
219: ttopen, 0))
220: break;
221: }
222: (void) spl0();
223: if (error == 0)
224: error = (*linesw[tp->t_line].l_open)(dev, tp);
225: return (error);
226: }
227:
228: /*ARGSUSED*/
229: comclose(dev, flag, mode, p)
230: dev_t dev;
231: int flag, mode;
232: struct proc *p;
233: {
234: register struct tty *tp;
235: register com;
236: register int unit;
237:
238: unit = UNIT(dev);
239: com = com_addr[unit];
240: tp = &com_tty[unit];
241: (*linesw[tp->t_line].l_close)(tp, flag);
242: outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
243: #ifdef KGDB
244: /* do not disable interrupts if debugging */
245: if (kgdb_dev != makedev(commajor, unit))
246: #endif
247: outb(com+com_ier, 0);
248: if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
249: (tp->t_state&TS_ISOPEN) == 0)
250: (void) commctl(dev, 0, DMSET);
251: ttyclose(tp);
252: return(0);
253: }
254:
255: comread(dev, uio, flag)
256: dev_t dev;
257: struct uio *uio;
258: {
259: register struct tty *tp = &com_tty[UNIT(dev)];
260:
261: return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
262: }
263:
264: comwrite(dev, uio, flag)
265: dev_t dev;
266: struct uio *uio;
267: {
268: int unit = UNIT(dev);
269: register struct tty *tp = &com_tty[unit];
270:
271: /*
272: * (XXX) We disallow virtual consoles if the physical console is
273: * a serial port. This is in case there is a display attached that
274: * is not the console. In that situation we don't need/want the X
275: * server taking over the console.
276: */
277: if (constty && unit == comconsole)
278: constty = NULL;
279: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
280: }
281:
282: comintr(unit)
283: register int unit;
284: {
285: register com;
286: register u_char code;
287: register struct tty *tp;
288:
289: com = com_addr[unit];
290: while (1) {
291: code = inb(com+com_iir);
292: switch (code & IIR_IMASK) {
293: case IIR_NOPEND:
294: return (1);
295: case IIR_RXTOUT:
296: case IIR_RXRDY:
297: tp = &com_tty[unit];
298: /*
299: * Process received bytes. Inline for speed...
300: */
301: #ifdef KGDB
302: #define RCVBYTE() \
303: code = inb(com+com_data); \
304: if ((tp->t_state & TS_ISOPEN) == 0) { \
305: if (kgdb_dev == makedev(commajor, unit) && \
306: code == FRAME_END) \
307: kgdb_connect(0); /* trap into kgdb */ \
308: } else \
309: (*linesw[tp->t_line].l_rint)(code, tp)
310: #else
311: #define RCVBYTE() \
312: code = inb(com+com_data); \
313: if (tp->t_state & TS_ISOPEN) \
314: (*linesw[tp->t_line].l_rint)(code, tp)
315: #endif
316:
317: RCVBYTE();
318:
319: if (com_hasfifo & (1 << unit))
320: while ((code = inb(com+com_lsr)) & LSR_RCV_MASK) {
321: if (code == LSR_RXRDY) {
322: RCVBYTE();
323: } else
324: comeint(unit, code, com);
325: }
326: break;
327: case IIR_TXRDY:
328: tp = &com_tty[unit];
329: tp->t_state &=~ (TS_BUSY|TS_FLUSH);
330: if (tp->t_line)
331: (*linesw[tp->t_line].l_start)(tp);
332: else
333: comstart(tp);
334: break;
335: case IIR_RLS:
336: comeint(unit, inb(com+com_lsr), com);
337: break;
338: default:
339: if (code & IIR_NOPEND)
340: return (1);
341: log(LOG_WARNING, "com%d: weird interrupt: 0x%x\n",
342: unit, code);
343: /* fall through */
344: case IIR_MLSC:
345: commint(unit, com);
346: break;
347: }
348: }
349: }
350:
351: comeint(unit, stat, com)
352: register int unit, stat;
353: register com;
354: {
355: register struct tty *tp;
356: register int c;
357:
358: tp = &com_tty[unit];
359: c = inb(com+com_data);
360: if ((tp->t_state & TS_ISOPEN) == 0) {
361: #ifdef KGDB
362: /* we don't care about parity errors */
363: if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
364: kgdb_dev == makedev(commajor, unit) && c == FRAME_END)
365: kgdb_connect(0); /* trap into kgdb */
366: #endif
367: return;
368: }
369: if (stat & (LSR_BI | LSR_FE))
370: c |= TTY_FE;
371: else if (stat & LSR_PE)
372: c |= TTY_PE;
373: else if (stat & LSR_OE)
374: log(LOG_WARNING, "com%d: silo overflow\n", unit);
375: (*linesw[tp->t_line].l_rint)(c, tp);
376: }
377:
378: commint(unit, com)
379: register int unit;
380: register com;
381: {
382: register struct tty *tp;
383: register int stat;
384:
385: tp = &com_tty[unit];
386: stat = inb(com+com_msr);
387: if ((stat & MSR_DDCD) && (comsoftCAR & (1 << unit)) == 0) {
388: if (stat & MSR_DCD)
389: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
390: else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
391: outb(com+com_mcr,
392: inb(com+com_mcr) & ~(MCR_DTR | MCR_RTS) | MCR_IENABLE);
393: } else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
394: (tp->t_flags & CRTSCTS)) {
395: /* the line is up and we want to do rts/cts flow control */
396: if (stat & MSR_CTS) {
397: tp->t_state &=~ TS_TTSTOP;
398: ttstart(tp);
399: } else
400: tp->t_state |= TS_TTSTOP;
401: }
402: }
403:
404: comioctl(dev, cmd, data, flag)
405: dev_t dev;
406: caddr_t data;
407: {
408: register struct tty *tp;
409: register int unit = UNIT(dev);
410: register com;
411: register int error;
412:
413: tp = &com_tty[unit];
414: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
415: if (error >= 0)
416: return (error);
417: error = ttioctl(tp, cmd, data, flag);
418: if (error >= 0)
419: return (error);
420:
421: com = com_addr[unit];
422: switch (cmd) {
423:
424: case TIOCSBRK:
425: outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_SBREAK);
426: break;
427:
428: case TIOCCBRK:
429: outb(com+com_cfcr, inb(com+com_cfcr) & ~CFCR_SBREAK);
430: break;
431:
432: case TIOCSDTR:
433: (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIS);
434: break;
435:
436: case TIOCCDTR:
437: (void) commctl(dev, MCR_DTR | MCR_RTS, DMBIC);
438: break;
439:
440: case TIOCMSET:
441: (void) commctl(dev, *(int *)data, DMSET);
442: break;
443:
444: case TIOCMBIS:
445: (void) commctl(dev, *(int *)data, DMBIS);
446: break;
447:
448: case TIOCMBIC:
449: (void) commctl(dev, *(int *)data, DMBIC);
450: break;
451:
452: case TIOCMGET:
453: *(int *)data = commctl(dev, 0, DMGET);
454: break;
455:
456: default:
457: return (ENOTTY);
458: }
459: return (0);
460: }
461:
462: comparam(tp, t)
463: register struct tty *tp;
464: register struct termios *t;
465: {
466: register com;
467: register int cfcr, cflag = t->c_cflag;
468: int unit = UNIT(tp->t_dev);
469: int ospeed = ttspeedtab(t->c_ospeed, comspeedtab);
470:
471: /* check requested parameters */
472: if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
473: return(EINVAL);
474: /* and copy to tty */
475: tp->t_ispeed = t->c_ispeed;
476: tp->t_ospeed = t->c_ospeed;
477: tp->t_cflag = cflag;
478:
479: com = com_addr[unit];
480: outb(com+com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS /*| IER_EMSC*/);
481: if (ospeed == 0) {
482: (void) commctl(unit, 0, DMSET); /* hang up line */
483: return(0);
484: }
485: outb(com+com_cfcr, inb(com+com_cfcr) | CFCR_DLAB);
486: outb(com+com_data, ospeed & 0xFF);
487: outb(com+com_ier, ospeed >> 8);
488: switch (cflag&CSIZE) {
489: case CS5:
490: cfcr = CFCR_5BITS; break;
491: case CS6:
492: cfcr = CFCR_6BITS; break;
493: case CS7:
494: cfcr = CFCR_7BITS; break;
495: case CS8:
496: cfcr = CFCR_8BITS; break;
497: }
498: if (cflag&PARENB) {
499: cfcr |= CFCR_PENAB;
500: if ((cflag&PARODD) == 0)
501: cfcr |= CFCR_PEVEN;
502: }
503: if (cflag&CSTOPB)
504: cfcr |= CFCR_STOPB;
505: outb(com+com_cfcr, cfcr);
506:
507: if (com_hasfifo & (1 << unit))
508: outb(com+com_fifo, FIFO_ENABLE | FIFO_TRIGGER_14);
509:
510: return(0);
511: }
512:
513: comstart(tp)
514: register struct tty *tp;
515: {
516: register com;
517: int s, unit, c;
518:
519: unit = UNIT(tp->t_dev);
520: com = com_addr[unit];
521: s = spltty();
522: if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
523: goto out;
524: if (tp->t_outq.c_cc <= tp->t_lowat) {
525: if (tp->t_state&TS_ASLEEP) {
526: tp->t_state &= ~TS_ASLEEP;
527: wakeup((caddr_t)&tp->t_outq);
528: }
529: if (tp->t_wsel) {
530: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
531: tp->t_wsel = 0;
532: tp->t_state &= ~TS_WCOLL;
533: }
534: }
535: if (tp->t_outq.c_cc == 0)
536: goto out;
537: if (inb(com+com_lsr) & LSR_TXRDY) {
538: c = getc(&tp->t_outq);
539: tp->t_state |= TS_BUSY;
540: outb(com+com_data, c);
541: if (com_hasfifo & (1 << unit))
542: for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
543: outb(com+com_data, getc(&tp->t_outq));
544: }
545: out:
546: splx(s);
547: }
548:
549: /*
550: * Stop output on a line.
551: */
552: /*ARGSUSED*/
553: comstop(tp, flag)
554: register struct tty *tp;
555: {
556: register int s;
557:
558: s = spltty();
559: if (tp->t_state & TS_BUSY) {
560: if ((tp->t_state&TS_TTSTOP)==0)
561: tp->t_state |= TS_FLUSH;
562: }
563: splx(s);
564: }
565:
566: commctl(dev, bits, how)
567: dev_t dev;
568: int bits, how;
569: {
570: register com;
571: register int unit;
572: int s;
573:
574: unit = UNIT(dev);
575: com = com_addr[unit];
576: s = spltty();
577: switch (how) {
578:
579: case DMSET:
580: outb(com+com_mcr, bits | MCR_IENABLE);
581: break;
582:
583: case DMBIS:
584: outb(com+com_mcr, inb(com+com_mcr) | bits | MCR_IENABLE);
585: break;
586:
587: case DMBIC:
588: outb(com+com_mcr, inb(com+com_mcr) & ~bits | MCR_IENABLE);
589: break;
590:
591: case DMGET:
592: bits = inb(com+com_msr);
593: break;
594: }
595: (void) splx(s);
596: return(bits);
597: }
598:
599: /*
600: * Following are all routines needed for COM to act as console
601: */
602: #include "i386/i386/cons.h"
603:
604: comcnprobe(cp)
605: struct consdev *cp;
606: {
607: int unit;
608:
609: /* locate the major number */
610: for (commajor = 0; commajor < nchrdev; commajor++)
611: if (cdevsw[commajor].d_open == comopen)
612: break;
613:
614: /* XXX: ick */
615: unit = CONUNIT;
616: com_addr[CONUNIT] = CONADDR;
617:
618: /* make sure hardware exists? XXX */
619:
620: /* initialize required fields */
621: cp->cn_dev = makedev(commajor, unit);
622: cp->cn_tp = &com_tty[unit];
623: #ifdef COMCONSOLE
624: cp->cn_pri = CN_REMOTE; /* Force a serial port console */
625: #else
626: cp->cn_pri = CN_NORMAL;
627: #endif
628: }
629:
630: comcninit(cp)
631: struct consdev *cp;
632: {
633: int unit = UNIT(cp->cn_dev);
634:
635: cominit(unit, comdefaultrate);
636: comconsole = unit;
637: comconsinit = 1;
638: }
639:
640: cominit(unit, rate)
641: int unit, rate;
642: {
643: register int com;
644: int s;
645: short stat;
646:
647: #ifdef lint
648: stat = unit; if (stat) return;
649: #endif
650: com = com_addr[unit];
651: s = splhigh();
652: outb(com+com_cfcr, CFCR_DLAB);
653: rate = ttspeedtab(comdefaultrate, comspeedtab);
654: outb(com+com_data, rate & 0xFF);
655: outb(com+com_ier, rate >> 8);
656: outb(com+com_cfcr, CFCR_8BITS);
657: outb(com+com_ier, IER_ERXRDY | IER_ETXRDY);
658: outb(com+com_fifo, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14);
659: stat = inb(com+com_iir);
660: splx(s);
661: }
662:
663: comcngetc(dev)
664: {
665: register com = com_addr[UNIT(dev)];
666: short stat;
667: int c, s;
668:
669: #ifdef lint
670: stat = dev; if (stat) return(0);
671: #endif
672: s = splhigh();
673: while (((stat = inb(com+com_lsr)) & LSR_RXRDY) == 0)
674: ;
675: c = inb(com+com_data);
676: stat = inb(com+com_iir);
677: splx(s);
678: return(c);
679: }
680:
681: /*
682: * Console kernel output character routine.
683: */
684: comcnputc(dev, c)
685: dev_t dev;
686: register int c;
687: {
688: register com = com_addr[UNIT(dev)];
689: register int timo;
690: short stat;
691: int s = splhigh();
692:
693: #ifdef lint
694: stat = dev; if (stat) return;
695: #endif
696: #ifdef KGDB
697: if (dev != kgdb_dev)
698: #endif
699: if (comconsinit == 0) {
700: (void) cominit(UNIT(dev), comdefaultrate);
701: comconsinit = 1;
702: }
703: /* wait for any pending transmission to finish */
704: timo = 50000;
705: while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
706: ;
707: outb(com+com_data, c);
708: /* wait for this transmission to complete */
709: timo = 1500000;
710: while (((stat = inb(com+com_lsr)) & LSR_TXRDY) == 0 && --timo)
711: ;
712: /* clear any interrupts generated by this transmission */
713: stat = inb(com+com_iir);
714: splx(s);
715: }
716: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.