156817Sralph /*-
263207Sbostic * Copyright (c) 1992, 1993
363207Sbostic * The Regents of the University of California. All rights reserved.
456817Sralph *
556817Sralph * This code is derived from software contributed to Berkeley by
656817Sralph * Ralph Campbell and Rick Macklem.
756817Sralph *
856817Sralph * %sccs.include.redist.c%
956817Sralph *
10*69799Sralph * @(#)scc.c 8.3 (Berkeley) 06/02/95
1156817Sralph */
1256817Sralph
1356817Sralph /*
1456817Sralph * Mach Operating System
1556817Sralph * Copyright (c) 1991,1990,1989 Carnegie Mellon University
1656817Sralph * All Rights Reserved.
1756817Sralph *
1856817Sralph * Permission to use, copy, modify and distribute this software and its
1956817Sralph * documentation is hereby granted, provided that both the copyright
2056817Sralph * notice and this permission notice appear in all copies of the
2156817Sralph * software, derivative works or modified versions, and any portions
2256817Sralph * thereof, and that both notices appear in supporting documentation.
2356817Sralph *
2456817Sralph * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
2556817Sralph * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
2656817Sralph * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
2756817Sralph *
2856817Sralph * Carnegie Mellon requests users of this software to return to
2956817Sralph *
3056817Sralph * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
3156817Sralph * School of Computer Science
3256817Sralph * Carnegie Mellon University
3356817Sralph * Pittsburgh PA 15213-3890
3456817Sralph *
3556817Sralph * any improvements or extensions that they make and grant Carnegie the
3656817Sralph * rights to redistribute these changes.
3756817Sralph */
3856817Sralph
3956817Sralph #include <scc.h>
4056817Sralph #if NSCC > 0
4156817Sralph /*
4256817Sralph * Intel 82530 dual usart chip driver. Supports the serial port(s) on the
4356817Sralph * Personal DECstation 5000/xx and DECstation 5000/1xx, plus the keyboard
4456817Sralph * and mouse on the 5000/1xx. (Don't ask me where the A channel signals
4556817Sralph * are on the 5000/xx.)
4656817Sralph *
4756817Sralph * See: Intel MicroCommunications Handbook, Section 2, pg. 155-173, 1992.
4856817Sralph */
4956817Sralph #include <sys/param.h>
5056817Sralph #include <sys/systm.h>
5156817Sralph #include <sys/ioctl.h>
5256817Sralph #include <sys/tty.h>
5356817Sralph #include <sys/proc.h>
5456817Sralph #include <sys/map.h>
5556817Sralph #include <sys/buf.h>
5656817Sralph #include <sys/conf.h>
5756817Sralph #include <sys/file.h>
5856817Sralph #include <sys/uio.h>
5956817Sralph #include <sys/kernel.h>
6056817Sralph #include <sys/syslog.h>
6156817Sralph
6256817Sralph #include <machine/pmioctl.h>
6356817Sralph
6456817Sralph #include <pmax/dev/device.h>
6556817Sralph #include <pmax/dev/pdma.h>
6656817Sralph #include <pmax/dev/sccreg.h>
6756817Sralph #include <pmax/dev/fbreg.h>
6856817Sralph
6956817Sralph #include <pmax/pmax/cons.h>
7056817Sralph #include <pmax/pmax/pmaxtype.h>
7156817Sralph
7256817Sralph extern int pmax_boardtype;
7356817Sralph extern struct consdev cn_tab;
7456817Sralph extern void ttrstrt __P((void *));
7556817Sralph extern void KBDReset __P((dev_t, void (*)()));
7656817Sralph extern void MouseInit __P((dev_t, void (*)(), int (*)()));
7756817Sralph
7856817Sralph /*
7956817Sralph * Driver information for auto-configuration stuff.
8056817Sralph */
8156817Sralph int sccprobe(), sccopen(), sccparam(), sccGetc();
8256817Sralph void sccintr(), sccstart(), sccPutc();
8356817Sralph struct driver sccdriver = {
8456817Sralph "scc", sccprobe, 0, 0, sccintr,
8556817Sralph };
8656817Sralph
8756817Sralph #define NSCCLINE (NSCC*2)
8856817Sralph #define SCCUNIT(dev) (minor(dev) >> 1)
8956817Sralph #define SCCLINE(dev) (minor(dev) & 0x1)
9056817Sralph
9156817Sralph struct tty scc_tty[NSCCLINE];
9256817Sralph void (*sccDivertXInput)(); /* X windows keyboard input routine */
9356817Sralph void (*sccMouseEvent)(); /* X windows mouse motion event routine */
9456817Sralph void (*sccMouseButtons)(); /* X windows mouse buttons event routine */
9556817Sralph #ifdef DEBUG
9656817Sralph int debugChar;
9756817Sralph #endif
9856817Sralph static void scc_modem_intr(), sccreset();
9956817Sralph
10056817Sralph struct scc_softc {
10156817Sralph struct pdma scc_pdma[2];
10256817Sralph struct {
10356817Sralph u_char wr1;
10456817Sralph u_char wr3;
10556817Sralph u_char wr4;
10656817Sralph u_char wr5;
10756817Sralph u_char wr14;
10856817Sralph } scc_wreg[2];
10956817Sralph int scc_softCAR;
11056817Sralph } scc_softc[NSCC];
11156817Sralph
11256817Sralph struct speedtab sccspeedtab[] = {
11356817Sralph 0, 0,
11456817Sralph 50, 4606,
11556817Sralph 75, 3070,
11656817Sralph 110, 2093,
11756817Sralph 134, 1711,
11856817Sralph 150, 1534,
11956817Sralph 300, 766,
12056817Sralph 600, 382,
12156817Sralph 1200, 190,
12256817Sralph 1800, 126,
12356817Sralph 2400, 94,
12456817Sralph 4800, 46,
12556817Sralph 9600, 22,
12656817Sralph 19200, 10,
12756817Sralph 38400, 4,
12856817Sralph -1, -1
12956817Sralph };
13056817Sralph
13156817Sralph #ifndef PORTSELECTOR
13256817Sralph #define ISPEED TTYDEF_SPEED
13356817Sralph #define LFLAG TTYDEF_LFLAG
13456817Sralph #else
13556817Sralph #define ISPEED B4800
13656817Sralph #define LFLAG (TTYDEF_LFLAG & ~ECHO)
13756817Sralph #endif
13856817Sralph
13956817Sralph /*
14056817Sralph * Test to see if device is present.
14156817Sralph * Return true if found and initialized ok.
14256817Sralph */
sccprobe(cp)14356817Sralph sccprobe(cp)
14456817Sralph register struct pmax_ctlr *cp;
14556817Sralph {
14656817Sralph register struct scc_softc *sc;
14756817Sralph register struct pdma *pdp;
14856817Sralph register struct tty *tp;
14956817Sralph register int cntr;
15056817Sralph struct tty ctty;
15156817Sralph struct termios cterm;
15256817Sralph int s;
15356817Sralph
15456817Sralph if (cp->pmax_unit >= NSCC)
15556817Sralph return (0);
15656817Sralph if (badaddr(cp->pmax_addr, 2))
15756817Sralph return (0);
15856817Sralph
15957234Sralph /*
16057234Sralph * For a remote console, wait a while for previous output to
16157234Sralph * complete.
16257234Sralph */
16357234Sralph if (major(cn_tab.cn_dev) == SCCDEV && cn_tab.cn_screen == 0 &&
16457234Sralph SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit)
16557234Sralph DELAY(10000);
16657234Sralph
16756817Sralph sc = &scc_softc[cp->pmax_unit];
16856817Sralph pdp = &sc->scc_pdma[0];
16956817Sralph
17056817Sralph /* init pseudo DMA structures */
17156817Sralph tp = &scc_tty[cp->pmax_unit * 2];
17256817Sralph for (cntr = 0; cntr < 2; cntr++) {
17356817Sralph pdp->p_addr = (void *)cp->pmax_addr;
17456817Sralph pdp->p_arg = (int)tp;
17556817Sralph pdp->p_fcn = (void (*)())0;
17656817Sralph tp->t_dev = (dev_t)((cp->pmax_unit << 1) | cntr);
17756817Sralph pdp++, tp++;
17856817Sralph }
17956817Sralph sc->scc_softCAR = cp->pmax_flags | 0x2;
18056817Sralph
18156817Sralph /* reset chip */
18256817Sralph sccreset(sc);
18356817Sralph
18456817Sralph /*
18556817Sralph * Special handling for consoles.
18656817Sralph */
18756817Sralph if (cn_tab.cn_screen) {
18856817Sralph if (cn_tab.cn_kbdgetc == sccGetc) {
18958793Sralph if (cp->pmax_unit == 1) {
19056817Sralph s = spltty();
19156817Sralph ctty.t_dev = makedev(SCCDEV, SCCKBD_PORT);
19256817Sralph cterm.c_cflag = CS8;
19356817Sralph cterm.c_ospeed = cterm.c_ispeed = 4800;
19456817Sralph (void) sccparam(&ctty, &cterm);
19558793Sralph DELAY(10000);
19658793Sralph #ifdef notyet
19758793Sralph /*
19858793Sralph * For some reason doing this hangs the 3min
19958793Sralph * during booting. Fortunately the keyboard
20058793Sralph * works ok without it.
20158793Sralph */
20256817Sralph KBDReset(ctty.t_dev, sccPutc);
20358793Sralph #endif
20458793Sralph DELAY(10000);
20556817Sralph splx(s);
20658793Sralph } else if (cp->pmax_unit == 0) {
20756817Sralph s = spltty();
20856817Sralph ctty.t_dev = makedev(SCCDEV, SCCMOUSE_PORT);
20956817Sralph cterm.c_cflag = CS8 | PARENB | PARODD;
21056817Sralph cterm.c_ospeed = cterm.c_ispeed = 4800;
21156817Sralph (void) sccparam(&ctty, &cterm);
21258793Sralph DELAY(10000);
21356817Sralph MouseInit(ctty.t_dev, sccPutc, sccGetc);
21458793Sralph DELAY(10000);
21556817Sralph splx(s);
21656817Sralph }
21756817Sralph }
21856817Sralph } else if (SCCUNIT(cn_tab.cn_dev) == cp->pmax_unit) {
21956817Sralph s = spltty();
22056817Sralph ctty.t_dev = cn_tab.cn_dev;
22156817Sralph cterm.c_cflag = CS8;
22256817Sralph cterm.c_ospeed = cterm.c_ispeed = 9600;
22356817Sralph (void) sccparam(&ctty, &cterm);
22457234Sralph DELAY(1000);
22556817Sralph cn_tab.cn_disabled = 0;
22656817Sralph splx(s);
22756817Sralph }
22857234Sralph printf("scc%d at nexus0 csr 0x%x priority %d\n",
22957234Sralph cp->pmax_unit, cp->pmax_addr, cp->pmax_pri);
23056817Sralph return (1);
23156817Sralph }
23256817Sralph
23356817Sralph /*
23456817Sralph * Reset the chip.
23556817Sralph */
23656817Sralph static void
sccreset(sc)23756817Sralph sccreset(sc)
23856817Sralph register struct scc_softc *sc;
23956817Sralph {
24056817Sralph register scc_regmap_t *regs;
24156817Sralph register u_char val;
24256817Sralph
24356817Sralph regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
24456817Sralph /*
24556817Sralph * Chip once-only initialization
24656817Sralph *
24756817Sralph * NOTE: The wiring we assume is the one on the 3min:
24856817Sralph *
24956817Sralph * out A-TxD --> TxD keybd or mouse
25056817Sralph * in A-RxD --> RxD keybd or mouse
25156817Sralph * out A-DTR~ --> DTR comm
25256817Sralph * out A-RTS~ --> RTS comm
25356817Sralph * in A-CTS~ --> SI comm
25456817Sralph * in A-DCD~ --> RI comm
25556817Sralph * in A-SYNCH~--> DSR comm
25656817Sralph * out B-TxD --> TxD comm
25756817Sralph * in B-RxD --> RxD comm
25856817Sralph * in B-RxC --> TRxCB comm
25956817Sralph * in B-TxC --> RTxCB comm
26056817Sralph * out B-RTS~ --> SS comm
26156817Sralph * in B-CTS~ --> CTS comm
26256817Sralph * in B-DCD~ --> CD comm
26356817Sralph */
26456817Sralph SCC_INIT_REG(regs, SCC_CHANNEL_A);
26556817Sralph SCC_INIT_REG(regs, SCC_CHANNEL_B);
26656817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET);
26756817Sralph DELAY(50000); /*enough ? */
26856817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, 0);
26956817Sralph
27056817Sralph /* program the interrupt vector */
27156817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0);
27256817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0);
27356817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS);
27456817Sralph
27556817Sralph /* timing base defaults */
27656817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16;
27756817Sralph sc->scc_wreg[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16;
27856817Sralph
27956817Sralph /* enable DTR, RTS and SS */
28056817Sralph sc->scc_wreg[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS;
28156817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR;
28256817Sralph
28356817Sralph /* baud rates */
28456817Sralph val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC;
28556817Sralph sc->scc_wreg[SCC_CHANNEL_B].wr14 = val;
28656817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr14 = val;
28756817Sralph
28856817Sralph /* interrupt conditions */
28956817Sralph val = SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE |
29057234Sralph SCC_WR1_EXT_IE;
29156817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr1 = val;
29256817Sralph sc->scc_wreg[SCC_CHANNEL_B].wr1 = val;
29356817Sralph }
29456817Sralph
sccopen(dev,flag,mode,p)29556817Sralph sccopen(dev, flag, mode, p)
29656817Sralph dev_t dev;
29756817Sralph int flag, mode;
29856817Sralph struct proc *p;
29956817Sralph {
30056817Sralph register struct scc_softc *sc;
30156817Sralph register struct tty *tp;
30256817Sralph register int unit, line;
30356817Sralph int s, error = 0;
30456817Sralph
30556817Sralph unit = SCCUNIT(dev);
30656817Sralph if (unit >= NSCC)
30756817Sralph return (ENXIO);
30856817Sralph line = SCCLINE(dev);
30956817Sralph sc = &scc_softc[unit];
31056817Sralph if (sc->scc_pdma[line].p_addr == (void *)0)
31156817Sralph return (ENXIO);
31256817Sralph tp = &scc_tty[minor(dev)];
31356817Sralph tp->t_oproc = sccstart;
31456817Sralph tp->t_param = sccparam;
31556817Sralph tp->t_dev = dev;
31656817Sralph if ((tp->t_state & TS_ISOPEN) == 0) {
31756817Sralph tp->t_state |= TS_WOPEN;
31856817Sralph ttychars(tp);
31956817Sralph #ifndef PORTSELECTOR
32056817Sralph if (tp->t_ispeed == 0) {
32156817Sralph #endif
32256817Sralph tp->t_iflag = TTYDEF_IFLAG;
32356817Sralph tp->t_oflag = TTYDEF_OFLAG;
32456817Sralph tp->t_cflag = TTYDEF_CFLAG;
32556817Sralph tp->t_lflag = LFLAG;
32656817Sralph tp->t_ispeed = tp->t_ospeed = ISPEED;
32756817Sralph #ifdef PORTSELECTOR
32856817Sralph tp->t_cflag |= HUPCL;
32956817Sralph #else
33056817Sralph }
33156817Sralph #endif
33256817Sralph (void) sccparam(tp, &tp->t_termios);
33356817Sralph ttsetwater(tp);
33456817Sralph } else if ((tp->t_state & TS_XCLUDE) && curproc->p_ucred->cr_uid != 0)
33556817Sralph return (EBUSY);
33656817Sralph (void) sccmctl(dev, DML_DTR, DMSET);
33756817Sralph s = spltty();
33856817Sralph while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
33956817Sralph !(tp->t_state & TS_CARR_ON)) {
34056817Sralph tp->t_state |= TS_WOPEN;
34156817Sralph if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
34256817Sralph ttopen, 0))
34356817Sralph break;
34456817Sralph }
34556817Sralph splx(s);
34656817Sralph if (error)
34756817Sralph return (error);
34856817Sralph return ((*linesw[tp->t_line].l_open)(dev, tp));
34956817Sralph }
35056817Sralph
35156817Sralph /*ARGSUSED*/
sccclose(dev,flag,mode,p)35256817Sralph sccclose(dev, flag, mode, p)
35356817Sralph dev_t dev;
35456817Sralph int flag, mode;
35556817Sralph struct proc *p;
35656817Sralph {
35756817Sralph register struct scc_softc *sc = &scc_softc[SCCUNIT(dev)];
35856817Sralph register struct tty *tp;
35956817Sralph register int bit, line;
36056817Sralph
36156817Sralph tp = &scc_tty[minor(dev)];
36256817Sralph line = SCCLINE(dev);
36356817Sralph if (sc->scc_wreg[line].wr5 & SCC_WR5_SEND_BREAK) {
36456817Sralph sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
36556817Sralph ttyoutput(0, tp);
36656817Sralph }
36756817Sralph (*linesw[tp->t_line].l_close)(tp, flag);
36856817Sralph if ((tp->t_cflag & HUPCL) || (tp->t_state & TS_WOPEN) ||
36956817Sralph !(tp->t_state & TS_ISOPEN))
37056817Sralph (void) sccmctl(dev, 0, DMSET);
37156817Sralph return (ttyclose(tp));
37256817Sralph }
37356817Sralph
sccread(dev,uio,flag)37456817Sralph sccread(dev, uio, flag)
37556817Sralph dev_t dev;
37656817Sralph struct uio *uio;
37756817Sralph {
37856817Sralph register struct tty *tp;
37956817Sralph
38056817Sralph tp = &scc_tty[minor(dev)];
38156817Sralph return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
38256817Sralph }
38356817Sralph
sccwrite(dev,uio,flag)38456817Sralph sccwrite(dev, uio, flag)
38556817Sralph dev_t dev;
38656817Sralph struct uio *uio;
38756817Sralph {
38856817Sralph register struct tty *tp;
38956817Sralph
39056817Sralph tp = &scc_tty[minor(dev)];
39156817Sralph return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
39256817Sralph }
39356817Sralph
39456817Sralph /*ARGSUSED*/
sccioctl(dev,cmd,data,flag,p)39556817Sralph sccioctl(dev, cmd, data, flag, p)
39656817Sralph dev_t dev;
397*69799Sralph u_long cmd;
39856817Sralph caddr_t data;
39956817Sralph int flag;
40056817Sralph struct proc *p;
40156817Sralph {
40256817Sralph register struct scc_softc *sc;
40356817Sralph register struct tty *tp;
40456817Sralph int error, line;
40556817Sralph
40656817Sralph tp = &scc_tty[minor(dev)];
40756817Sralph error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
40856817Sralph if (error >= 0)
40956817Sralph return (error);
41056817Sralph error = ttioctl(tp, cmd, data, flag);
41156817Sralph if (error >= 0)
41256817Sralph return (error);
41356817Sralph
41456817Sralph line = SCCLINE(dev);
41556817Sralph sc = &scc_softc[SCCUNIT(dev)];
41656817Sralph switch (cmd) {
41756817Sralph
41856817Sralph case TIOCSBRK:
41956817Sralph sc->scc_wreg[line].wr5 |= SCC_WR5_SEND_BREAK;
42056817Sralph ttyoutput(0, tp);
42156817Sralph break;
42256817Sralph
42356817Sralph case TIOCCBRK:
42456817Sralph sc->scc_wreg[line].wr5 &= ~SCC_WR5_SEND_BREAK;
42556817Sralph ttyoutput(0, tp);
42656817Sralph break;
42756817Sralph
42856817Sralph case TIOCSDTR:
42956817Sralph (void) sccmctl(dev, DML_DTR|DML_RTS, DMBIS);
43056817Sralph break;
43156817Sralph
43256817Sralph case TIOCCDTR:
43356817Sralph (void) sccmctl(dev, DML_DTR|DML_RTS, DMBIC);
43456817Sralph break;
43556817Sralph
43656817Sralph case TIOCMSET:
43756817Sralph (void) sccmctl(dev, *(int *)data, DMSET);
43856817Sralph break;
43956817Sralph
44056817Sralph case TIOCMBIS:
44156817Sralph (void) sccmctl(dev, *(int *)data, DMBIS);
44256817Sralph break;
44356817Sralph
44456817Sralph case TIOCMBIC:
44556817Sralph (void) sccmctl(dev, *(int *)data, DMBIC);
44656817Sralph break;
44756817Sralph
44856817Sralph case TIOCMGET:
44956817Sralph *(int *)data = sccmctl(dev, 0, DMGET);
45056817Sralph break;
45156817Sralph
45256817Sralph default:
45356817Sralph return (ENOTTY);
45456817Sralph }
45556817Sralph return (0);
45656817Sralph }
45756817Sralph
sccparam(tp,t)45856817Sralph sccparam(tp, t)
45956817Sralph register struct tty *tp;
46056817Sralph register struct termios *t;
46156817Sralph {
46256817Sralph register struct scc_softc *sc;
46356817Sralph register scc_regmap_t *regs;
46456817Sralph register int line;
46556817Sralph register u_char value, wvalue;
46656817Sralph register int cflag = t->c_cflag;
46756817Sralph int ospeed;
46856817Sralph
46956817Sralph if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
47056817Sralph return (EINVAL);
47156817Sralph sc = &scc_softc[SCCUNIT(tp->t_dev)];
47256817Sralph line = SCCLINE(tp->t_dev);
47356817Sralph regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
47456817Sralph ospeed = ttspeedtab(t->c_ospeed, sccspeedtab);
47556817Sralph if (ospeed < 0)
47656817Sralph return (EINVAL);
47756817Sralph /* and copy to tty */
47856817Sralph tp->t_ispeed = t->c_ispeed;
47956817Sralph tp->t_ospeed = t->c_ospeed;
48056817Sralph tp->t_cflag = cflag;
48156817Sralph
48256817Sralph /*
48356817Sralph * Handle console specially.
48456817Sralph */
48556817Sralph if (cn_tab.cn_screen) {
48656817Sralph if (minor(tp->t_dev) == SCCKBD_PORT) {
48756817Sralph cflag = CS8;
48856817Sralph ospeed = ttspeedtab(4800, sccspeedtab);
48956817Sralph } else if (minor(tp->t_dev) == SCCMOUSE_PORT) {
49056817Sralph cflag = CS8 | PARENB | PARODD;
49156817Sralph ospeed = ttspeedtab(4800, sccspeedtab);
49256817Sralph }
49356817Sralph } else if (tp->t_dev == cn_tab.cn_dev) {
49456817Sralph cflag = CS8;
49556817Sralph ospeed = ttspeedtab(9600, sccspeedtab);
49656817Sralph }
49756817Sralph if (ospeed == 0) {
49856817Sralph (void) sccmctl(tp->t_dev, 0, DMSET); /* hang up line */
49956817Sralph return (0);
50056817Sralph }
50156817Sralph
50256817Sralph /* reset line */
50356817Sralph if (line == SCC_CHANNEL_A)
50456817Sralph value = SCC_WR9_RESET_CHA_A;
50556817Sralph else
50656817Sralph value = SCC_WR9_RESET_CHA_B;
50756817Sralph SCC_WRITE_REG(regs, line, SCC_WR9, value);
50856817Sralph DELAY(25);
50956817Sralph
51056817Sralph /* stop bits, normally 1 */
51156817Sralph value = sc->scc_wreg[line].wr4 & 0xf0;
51256817Sralph if (cflag & CSTOPB)
51356817Sralph value |= SCC_WR4_2_STOP;
51456817Sralph else
51556817Sralph value |= SCC_WR4_1_STOP;
51656817Sralph if ((cflag & PARODD) == 0)
51756817Sralph value |= SCC_WR4_EVEN_PARITY;
51856817Sralph if (cflag & PARENB)
51956817Sralph value |= SCC_WR4_PARITY_ENABLE;
52056817Sralph
52156817Sralph /* set it now, remember it must be first after reset */
52256817Sralph sc->scc_wreg[line].wr4 = value;
52356817Sralph SCC_WRITE_REG(regs, line, SCC_WR4, value);
52456817Sralph
52556817Sralph /* vector again */
52656817Sralph SCC_WRITE_REG(regs, line, SCC_WR2, 0xf0);
52756817Sralph
52856817Sralph /* clear break, keep rts dtr */
52956817Sralph wvalue = sc->scc_wreg[line].wr5 & (SCC_WR5_DTR|SCC_WR5_RTS);
53056817Sralph switch (cflag & CSIZE) {
53156817Sralph case CS5:
53256817Sralph value = SCC_WR3_RX_5_BITS;
53356817Sralph wvalue |= SCC_WR5_TX_5_BITS;
53456817Sralph break;
53556817Sralph case CS6:
53656817Sralph value = SCC_WR3_RX_6_BITS;
53756817Sralph wvalue |= SCC_WR5_TX_6_BITS;
53856817Sralph break;
53956817Sralph case CS7:
54056817Sralph value = SCC_WR3_RX_7_BITS;
54156817Sralph wvalue |= SCC_WR5_TX_7_BITS;
54256817Sralph break;
54356817Sralph case CS8:
54456817Sralph default:
54556817Sralph value = SCC_WR3_RX_8_BITS;
54656817Sralph wvalue |= SCC_WR5_TX_8_BITS;
54756817Sralph };
54856817Sralph sc->scc_wreg[line].wr3 = value;
54956817Sralph SCC_WRITE_REG(regs, line, SCC_WR3, value);
55056817Sralph sc->scc_wreg[line].wr5 = wvalue;
55156817Sralph SCC_WRITE_REG(regs, line, SCC_WR5, wvalue);
55256817Sralph SCC_WRITE_REG(regs, line, SCC_WR6, 0);
55356817Sralph SCC_WRITE_REG(regs, line, SCC_WR7, 0);
55456817Sralph SCC_WRITE_REG(regs, line, SCC_WR9, SCC_WR9_VIS);
55556817Sralph SCC_WRITE_REG(regs, line, SCC_WR10, 0);
55656817Sralph value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR |
55756817Sralph SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR;
55856817Sralph SCC_WRITE_REG(regs, line, SCC_WR11, value);
55956817Sralph SCC_SET_TIMING_BASE(regs, line, ospeed);
56056817Sralph value = sc->scc_wreg[line].wr14;
56156817Sralph SCC_WRITE_REG(regs, line, SCC_WR14, value);
56256817Sralph value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE;
56356817Sralph SCC_WRITE_REG(regs, line, SCC_WR15, value);
56456817Sralph
56556817Sralph /* and now the enables */
56656817Sralph value = sc->scc_wreg[line].wr3 | SCC_WR3_RX_ENABLE;
56756817Sralph SCC_WRITE_REG(regs, line, SCC_WR3, value);
56856817Sralph value = sc->scc_wreg[line].wr5 | SCC_WR5_TX_ENABLE;
56956817Sralph sc->scc_wreg[line].wr5 = value;
57056817Sralph SCC_WRITE_REG(regs, line, SCC_WR5, value);
57156817Sralph
57256817Sralph /* master inter enable */
57356817Sralph value = SCC_WR9_MASTER_IE | SCC_WR9_VIS;
57456817Sralph SCC_WRITE_REG(regs, line, SCC_WR9, value);
57556817Sralph SCC_WRITE_REG(regs, line, SCC_WR1, sc->scc_wreg[line].wr1);
57656817Sralph MachEmptyWriteBuffer();
57756817Sralph return (0);
57856817Sralph }
57956817Sralph
58056817Sralph /*
58156817Sralph * Check for interrupts from all devices.
58256817Sralph */
58356817Sralph void
sccintr(unit)58456817Sralph sccintr(unit)
58556817Sralph register int unit;
58656817Sralph {
58756817Sralph register scc_regmap_t *regs;
58856817Sralph register struct tty *tp;
58956817Sralph register struct pdma *dp;
59056817Sralph register struct scc_softc *sc;
59156817Sralph register int cc, chan, rr1, rr2, rr3;
59256817Sralph int overrun = 0;
59356817Sralph
59456817Sralph sc = &scc_softc[unit];
59556817Sralph regs = (scc_regmap_t *)sc->scc_pdma[0].p_addr;
59656817Sralph unit <<= 1;
59756817Sralph for (;;) {
59856817Sralph SCC_READ_REG(regs, SCC_CHANNEL_B, SCC_RR2, rr2);
59956817Sralph rr2 = SCC_RR2_STATUS(rr2);
60056817Sralph /* are we done yet ? */
60156817Sralph if (rr2 == 6) { /* strange, distinguished value */
60256817Sralph SCC_READ_REG(regs, SCC_CHANNEL_A, SCC_RR3, rr3);
60356817Sralph if (rr3 == 0)
60456817Sralph return;
60556817Sralph }
60656817Sralph
60756817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS);
60856817Sralph if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) {
60956817Sralph chan = (rr2 == SCC_RR2_A_XMIT_DONE) ?
61056817Sralph SCC_CHANNEL_A : SCC_CHANNEL_B;
61156817Sralph tp = &scc_tty[unit | chan];
61264979Smckusick dp = &sc->scc_pdma[chan];
61356817Sralph if (dp->p_mem < dp->p_end) {
61456817Sralph SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
61556817Sralph MachEmptyWriteBuffer();
61656817Sralph } else {
61756817Sralph tp->t_state &= ~TS_BUSY;
61856817Sralph if (tp->t_state & TS_FLUSH)
61956817Sralph tp->t_state &= ~TS_FLUSH;
62056817Sralph else {
62156817Sralph ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
62256817Sralph dp->p_end = dp->p_mem = tp->t_outq.c_cf;
62356817Sralph }
62456817Sralph if (tp->t_line)
62556817Sralph (*linesw[tp->t_line].l_start)(tp);
62656817Sralph else
62756817Sralph sccstart(tp);
62856817Sralph if (tp->t_outq.c_cc == 0 || !(tp->t_state & TS_BUSY)) {
62956817Sralph SCC_READ_REG(regs, chan, SCC_RR15, cc);
63056817Sralph cc &= ~SCC_WR15_TX_UNDERRUN_IE;
63156817Sralph SCC_WRITE_REG(regs, chan, SCC_WR15, cc);
63256817Sralph cc = sc->scc_wreg[chan].wr1 & ~SCC_WR1_TX_IE;
63356817Sralph SCC_WRITE_REG(regs, chan, SCC_WR1, cc);
63456817Sralph sc->scc_wreg[chan].wr1 = cc;
63556817Sralph MachEmptyWriteBuffer();
63656817Sralph }
63756817Sralph }
63857234Sralph } else if (rr2 == SCC_RR2_A_RECV_DONE ||
63957234Sralph rr2 == SCC_RR2_B_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL ||
64057234Sralph rr2 == SCC_RR2_B_RECV_SPECIAL) {
64157234Sralph if (rr2 == SCC_RR2_A_RECV_DONE || rr2 == SCC_RR2_A_RECV_SPECIAL)
64257234Sralph chan = SCC_CHANNEL_A;
64357234Sralph else
64457234Sralph chan = SCC_CHANNEL_B;
64557234Sralph tp = &scc_tty[unit | chan];
64657234Sralph SCC_READ_DATA(regs, chan, cc);
64757234Sralph if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
64857234Sralph rr2 == SCC_RR2_B_RECV_SPECIAL) {
64957234Sralph SCC_READ_REG(regs, chan, SCC_RR1, rr1);
65057234Sralph SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_ERROR);
65157234Sralph if ((rr1 & SCC_RR1_RX_OVERRUN) && overrun == 0) {
65257234Sralph log(LOG_WARNING, "scc%d,%d: silo overflow\n",
65357234Sralph unit >> 1, chan);
65457234Sralph overrun = 1;
65557234Sralph }
65657234Sralph }
65756817Sralph
65856817Sralph /*
65956817Sralph * Keyboard needs special treatment.
66056817Sralph */
66156817Sralph if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
66256817Sralph #ifdef KADB
66356817Sralph if (cc == LK_DO) {
66456817Sralph spl0();
66556817Sralph kdbpanic();
66656817Sralph return;
66756817Sralph }
66856817Sralph #endif
66956817Sralph #ifdef DEBUG
67056817Sralph debugChar = cc;
67156817Sralph #endif
67256817Sralph if (sccDivertXInput) {
67356817Sralph (*sccDivertXInput)(cc);
67456817Sralph continue;
67556817Sralph }
67656817Sralph if ((cc = kbdMapChar(cc)) < 0)
67756817Sralph continue;
67856817Sralph /*
67956817Sralph * Now for mousey
68056817Sralph */
68156817Sralph } else if (tp == &scc_tty[SCCMOUSE_PORT] && sccMouseButtons) {
68256817Sralph register MouseReport *mrp;
68356817Sralph static MouseReport currentRep;
68456817Sralph
68556817Sralph mrp = ¤tRep;
68656817Sralph mrp->byteCount++;
68756817Sralph if (cc & MOUSE_START_FRAME) {
68856817Sralph /*
68956817Sralph * The first mouse report byte (button state).
69056817Sralph */
69156817Sralph mrp->state = cc;
69256817Sralph if (mrp->byteCount > 1)
69356817Sralph mrp->byteCount = 1;
69456817Sralph } else if (mrp->byteCount == 2) {
69556817Sralph /*
69656817Sralph * The second mouse report byte (delta x).
69756817Sralph */
69856817Sralph mrp->dx = cc;
69956817Sralph } else if (mrp->byteCount == 3) {
70056817Sralph /*
70156817Sralph * The final mouse report byte (delta y).
70256817Sralph */
70356817Sralph mrp->dy = cc;
70456817Sralph mrp->byteCount = 0;
70556817Sralph if (mrp->dx != 0 || mrp->dy != 0) {
70656817Sralph /*
70756817Sralph * If the mouse moved,
70856817Sralph * post a motion event.
70956817Sralph */
71056817Sralph (*sccMouseEvent)(mrp);
71156817Sralph }
71256817Sralph (*sccMouseButtons)(mrp);
71356817Sralph }
71456817Sralph continue;
71556817Sralph }
71656817Sralph if (!(tp->t_state & TS_ISOPEN)) {
71756817Sralph wakeup((caddr_t)&tp->t_rawq);
71856817Sralph #ifdef PORTSELECTOR
71956817Sralph if (!(tp->t_state & TS_WOPEN))
72056817Sralph #endif
72156817Sralph continue;
72256817Sralph }
72357234Sralph if (rr2 == SCC_RR2_A_RECV_SPECIAL ||
72457234Sralph rr2 == SCC_RR2_B_RECV_SPECIAL) {
72557234Sralph if (rr1 & SCC_RR1_PARITY_ERR)
72657234Sralph cc |= TTY_PE;
72757234Sralph if (rr1 & SCC_RR1_FRAME_ERR)
72857234Sralph cc |= TTY_FE;
72956817Sralph }
73056817Sralph (*linesw[tp->t_line].l_rint)(cc, tp);
73156817Sralph } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) {
73256817Sralph chan = (rr2 == SCC_RR2_A_EXT_STATUS) ?
73356817Sralph SCC_CHANNEL_A : SCC_CHANNEL_B;
73456817Sralph SCC_WRITE_REG(regs, chan, SCC_RR0, SCC_RESET_EXT_IP);
73556817Sralph scc_modem_intr(unit | chan);
73656817Sralph }
73756817Sralph }
73856817Sralph }
73956817Sralph
74056817Sralph void
sccstart(tp)74156817Sralph sccstart(tp)
74256817Sralph register struct tty *tp;
74356817Sralph {
74456817Sralph register struct pdma *dp;
74556817Sralph register scc_regmap_t *regs;
74656817Sralph register struct scc_softc *sc;
74756817Sralph register int cc, chan;
74856817Sralph u_char temp;
74957234Sralph int s, sendone;
75056817Sralph
75164979Smckusick sc = &scc_softc[SCCUNIT(tp->t_dev)];
75264979Smckusick dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];
75356817Sralph regs = (scc_regmap_t *)dp->p_addr;
75456817Sralph s = spltty();
75556817Sralph if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
75656817Sralph goto out;
75756817Sralph if (tp->t_outq.c_cc <= tp->t_lowat) {
75856817Sralph if (tp->t_state & TS_ASLEEP) {
75956817Sralph tp->t_state &= ~TS_ASLEEP;
76056817Sralph wakeup((caddr_t)&tp->t_outq);
76156817Sralph }
76256817Sralph selwakeup(&tp->t_wsel);
76356817Sralph }
76456817Sralph if (tp->t_outq.c_cc == 0)
76556817Sralph goto out;
76656817Sralph /* handle console specially */
76756817Sralph if (tp == &scc_tty[SCCKBD_PORT] && cn_tab.cn_screen) {
76856817Sralph while (tp->t_outq.c_cc > 0) {
76956817Sralph cc = getc(&tp->t_outq) & 0x7f;
77056817Sralph cnputc(cc);
77156817Sralph }
77256817Sralph /*
77356817Sralph * After we flush the output queue we may need to wake
77456817Sralph * up the process that made the output.
77556817Sralph */
77656817Sralph if (tp->t_outq.c_cc <= tp->t_lowat) {
77756817Sralph if (tp->t_state & TS_ASLEEP) {
77856817Sralph tp->t_state &= ~TS_ASLEEP;
77956817Sralph wakeup((caddr_t)&tp->t_outq);
78056817Sralph }
78156817Sralph selwakeup(&tp->t_wsel);
78256817Sralph }
78356817Sralph goto out;
78456817Sralph }
78556817Sralph if (tp->t_flags & (RAW|LITOUT))
78656817Sralph cc = ndqb(&tp->t_outq, 0);
78756817Sralph else {
78856817Sralph cc = ndqb(&tp->t_outq, 0200);
78956817Sralph if (cc == 0) {
79056817Sralph cc = getc(&tp->t_outq);
79156817Sralph timeout(ttrstrt, (void *)tp, (cc & 0x7f) + 6);
79256817Sralph tp->t_state |= TS_TIMEOUT;
79356817Sralph goto out;
79456817Sralph }
79556817Sralph }
79656817Sralph tp->t_state |= TS_BUSY;
79756817Sralph dp->p_end = dp->p_mem = tp->t_outq.c_cf;
79856817Sralph dp->p_end += cc;
79956817Sralph
80056817Sralph /*
80156817Sralph * Enable transmission and send the first char, as required.
80256817Sralph */
80356817Sralph chan = SCCLINE(tp->t_dev);
80457234Sralph SCC_READ_REG(regs, chan, SCC_RR0, temp);
80557234Sralph sendone = (temp & SCC_RR0_TX_EMPTY);
80656817Sralph SCC_READ_REG(regs, chan, SCC_RR15, temp);
80756817Sralph temp |= SCC_WR15_TX_UNDERRUN_IE;
80856817Sralph SCC_WRITE_REG(regs, chan, SCC_WR15, temp);
80956817Sralph temp = sc->scc_wreg[chan].wr1 | SCC_WR1_TX_IE;
81056817Sralph SCC_WRITE_REG(regs, chan, SCC_WR1, temp);
81156817Sralph sc->scc_wreg[chan].wr1 = temp;
81257234Sralph if (sendone) {
81356817Sralph #ifdef DIAGNOSTIC
81456817Sralph if (cc == 0)
81556817Sralph panic("sccstart: No chars");
81656817Sralph #endif
81756817Sralph SCC_WRITE_DATA(regs, chan, *dp->p_mem++);
81856817Sralph }
81956817Sralph MachEmptyWriteBuffer();
82056817Sralph out:
82156817Sralph splx(s);
82256817Sralph }
82356817Sralph
82456817Sralph /*
82556817Sralph * Stop output on a line.
82656817Sralph */
82756817Sralph /*ARGSUSED*/
sccstop(tp,flag)82856817Sralph sccstop(tp, flag)
82956817Sralph register struct tty *tp;
83056817Sralph {
83156817Sralph register struct pdma *dp;
83264979Smckusick register struct scc_softc *sc;
83356817Sralph register int s;
83456817Sralph
83564979Smckusick sc = &scc_softc[SCCUNIT(tp->t_dev)];
83664979Smckusick dp = &sc->scc_pdma[SCCLINE(tp->t_dev)];
83756817Sralph s = spltty();
83856817Sralph if (tp->t_state & TS_BUSY) {
83956817Sralph dp->p_end = dp->p_mem;
84056817Sralph if (!(tp->t_state & TS_TTSTOP))
84156817Sralph tp->t_state |= TS_FLUSH;
84256817Sralph }
84356817Sralph splx(s);
84456817Sralph }
84556817Sralph
sccmctl(dev,bits,how)84656817Sralph sccmctl(dev, bits, how)
84756817Sralph dev_t dev;
84856817Sralph int bits, how;
84956817Sralph {
85056817Sralph register struct scc_softc *sc;
85156817Sralph register scc_regmap_t *regs;
85256817Sralph register int line, mbits;
85356817Sralph register u_char value;
85456817Sralph int s;
85556817Sralph
85656817Sralph sc = &scc_softc[SCCUNIT(dev)];
85756817Sralph line = SCCLINE(dev);
85856817Sralph regs = (scc_regmap_t *)sc->scc_pdma[line].p_addr;
85956817Sralph s = spltty();
86056817Sralph /*
86156817Sralph * only channel B has modem control, however the DTR and RTS
86256817Sralph * pins on the comm port are wired to the DTR and RTS A channel
86356817Sralph * signals.
86456817Sralph */
86556817Sralph mbits = DML_DTR | DML_DSR | DML_CAR;
86656817Sralph if (line == SCC_CHANNEL_B) {
86756817Sralph if (sc->scc_wreg[SCC_CHANNEL_A].wr5 & SCC_WR5_DTR)
86856817Sralph mbits = DML_DTR | DML_DSR;
86956817Sralph else
87056817Sralph mbits = 0;
87156817Sralph SCC_READ_REG_ZERO(regs, SCC_CHANNEL_B, value);
87256817Sralph if (value & SCC_RR0_DCD)
87356817Sralph mbits |= DML_CAR;
87456817Sralph }
87556817Sralph switch (how) {
87656817Sralph case DMSET:
87756817Sralph mbits = bits;
87856817Sralph break;
87956817Sralph
88056817Sralph case DMBIS:
88156817Sralph mbits |= bits;
88256817Sralph break;
88356817Sralph
88456817Sralph case DMBIC:
88556817Sralph mbits &= ~bits;
88656817Sralph break;
88756817Sralph
88856817Sralph case DMGET:
88956817Sralph (void) splx(s);
89056817Sralph return (mbits);
89156817Sralph }
89256817Sralph if (line == SCC_CHANNEL_B) {
89356817Sralph if (mbits & DML_DTR)
89456817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr5 |= SCC_WR5_DTR;
89556817Sralph else
89656817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr5 &= ~SCC_WR5_DTR;
89756817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR5,
89856817Sralph sc->scc_wreg[SCC_CHANNEL_A].wr5);
89956817Sralph }
90056817Sralph if ((mbits & DML_DTR) && (sc->scc_softCAR & (1 << line)))
90156817Sralph scc_tty[minor(dev)].t_state |= TS_CARR_ON;
90256817Sralph (void) splx(s);
90356817Sralph return (mbits);
90456817Sralph }
90556817Sralph
90656817Sralph /*
90756817Sralph * Check for carrier transition.
90856817Sralph */
90956817Sralph static void
scc_modem_intr(dev)91056817Sralph scc_modem_intr(dev)
91156817Sralph dev_t dev;
91256817Sralph {
91356817Sralph register scc_regmap_t *regs;
91456817Sralph register struct scc_softc *sc;
91556817Sralph register struct tty *tp;
91656817Sralph register int car, chan;
91756817Sralph register u_char value;
91856817Sralph int s;
91956817Sralph
92056817Sralph sc = &scc_softc[SCCUNIT(dev)];
92156817Sralph tp = &scc_tty[minor(dev)];
92256817Sralph chan = SCCLINE(dev);
92364979Smckusick regs = (scc_regmap_t *)sc->scc_pdma[chan].p_addr;
92456817Sralph if (chan == SCC_CHANNEL_A)
92556817Sralph return;
92656817Sralph s = spltty();
92756817Sralph if (sc->scc_softCAR & (1 << chan))
92856817Sralph car = 1;
92956817Sralph else {
93056817Sralph SCC_READ_REG_ZERO(regs, chan, value);
93156817Sralph car = value & SCC_RR0_DCD;
93256817Sralph }
93356817Sralph if (car) {
93456817Sralph /* carrier present */
93556817Sralph if (!(tp->t_state & TS_CARR_ON))
93656817Sralph (void)(*linesw[tp->t_line].l_modem)(tp, 1);
93756817Sralph } else if (tp->t_state & TS_CARR_ON)
93856817Sralph (void)(*linesw[tp->t_line].l_modem)(tp, 0);
93956817Sralph splx(s);
94056817Sralph }
94156817Sralph
94256817Sralph /*
94356817Sralph * Get a char off the appropriate line via. a busy wait loop.
94456817Sralph */
94556817Sralph int
sccGetc(dev)94656817Sralph sccGetc(dev)
94756817Sralph dev_t dev;
94856817Sralph {
94956817Sralph register scc_regmap_t *regs;
95056817Sralph register int c, line;
95156817Sralph register u_char value;
95256817Sralph int s;
95356817Sralph
95456817Sralph line = SCCLINE(dev);
95556817Sralph regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;
95656817Sralph if (!regs)
95756817Sralph return (0);
95856817Sralph s = spltty();
95956817Sralph for (;;) {
96056817Sralph SCC_READ_REG(regs, line, SCC_RR0, value);
96156817Sralph if (value & SCC_RR0_RX_AVAIL) {
96256817Sralph SCC_READ_REG(regs, line, SCC_RR1, value);
96358793Sralph SCC_READ_DATA(regs, line, c);
96456817Sralph if (value & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN |
96556817Sralph SCC_RR1_FRAME_ERR)) {
96656817Sralph SCC_WRITE_REG(regs, line, SCC_WR0, SCC_RESET_ERROR);
96756817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
96856817Sralph SCC_RESET_HIGHEST_IUS);
96956817Sralph } else {
97056817Sralph SCC_WRITE_REG(regs, SCC_CHANNEL_A, SCC_WR0,
97156817Sralph SCC_RESET_HIGHEST_IUS);
97256817Sralph splx(s);
97356817Sralph return (c & 0xff);
97456817Sralph }
97556817Sralph } else
97656817Sralph DELAY(10);
97756817Sralph }
97856817Sralph }
97956817Sralph
98056817Sralph /*
98156817Sralph * Send a char on a port, via a busy wait loop.
98256817Sralph */
98356817Sralph void
sccPutc(dev,c)98456817Sralph sccPutc(dev, c)
98556817Sralph dev_t dev;
98656817Sralph int c;
98756817Sralph {
98856817Sralph register scc_regmap_t *regs;
98957234Sralph register int line;
99056817Sralph register u_char value;
99156817Sralph int s;
99256817Sralph
99356817Sralph s = spltty();
99456817Sralph line = SCCLINE(dev);
99556817Sralph regs = (scc_regmap_t *)scc_softc[SCCUNIT(dev)].scc_pdma[line].p_addr;
99657234Sralph
99756817Sralph /*
99856817Sralph * Wait for transmitter to be not busy.
99956817Sralph */
100056817Sralph do {
100156817Sralph SCC_READ_REG(regs, line, SCC_RR0, value);
100257234Sralph if (value & SCC_RR0_TX_EMPTY)
100357234Sralph break;
100457234Sralph DELAY(100);
100557234Sralph } while (1);
100657234Sralph
100757234Sralph /*
100857234Sralph * Send the char.
100957234Sralph */
101057234Sralph SCC_WRITE_DATA(regs, line, c);
101157234Sralph MachEmptyWriteBuffer();
101256817Sralph splx(s);
101356817Sralph }
101456817Sralph #endif /* NSCC */
1015