/* * Mach Operating System * Copyright (c) 1993-1989 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie Mellon * the rights to redistribute these changes. */ /* * HISTORY * $Log: scc_8530_hdw.c,v $ * Revision 1.1.1.1 1993/09/29 06:09:28 briggs * The current MacBSD architecture sub-directory for NetBSD-0.9--more or * less. It needs some help to get to be -current. Support for minimal * hardware on the SE/30, II, IIx, and IIcx exists. * * Revision 2.9 93/03/26 17:58:01 mrt * No minor()s, no dev_t. * [93/03/18 af] * * Revision 2.8 93/03/09 10:52:21 danner * GCC quiet. * [93/03/07 13:29:58 af] * * Post-debugging lint. * [93/03/05 af] * * Revision 2.7 93/02/05 08:05:17 danner * Flamingo, full_modem and isa_console per-line. * [93/02/04 af] * * Revision 2.6 93/01/14 17:21:44 danner * static/extern cleanups. * [93/01/14 danner] * * Proper spl typing. * [92/11/30 af] * * Revision 2.5 92/05/05 10:04:59 danner * Fixed how the interrupt routine plays with priorities. * Ask for buffering on all lines. * [92/05/04 11:15:43 af] * * Fixed for more than just rconsole-ing. Two bugs: the chip * needs one char out to generate the xmit-empty (so it really * is a xmit-done) interrupt, and the t_addr game was not played * properly. * Tested both on maxine and the two serial lines kmin has. * [92/04/14 11:47:26 af] * * Revision 2.4 92/02/19 16:46:10 elf * Uhmm, lotsa changes. Basically, got channel B working * and made it possible to use it as rconsole line. * Missing modem bitsies only. * A joint Terri&Sandro feature presentation. * [92/02/10 17:03:08 af] * * Revision 2.3 91/08/28 11:09:53 jsb * Fixed scc_scan to actually check the tp->state each time, * we are not notified when the MI code brutally zeroes it * on close and so we cannot update our software CARrier. * [91/08/27 16:18:05 af] * * Revision 2.2 91/08/24 11:52:54 af * Created, from the Zilog specs: * "Z8530 SCC Serial Communications Controller, Product Specification" * in the "1983/84 Components Data Book" pp 409-429, September 1983 * Zilog, Campbell, CA 95008 * [91/06/28 af] * */ #ident "$Id: scc_8530_hdw.c,v 1.1.1.1 1993/09/29 06:09:28 briggs Exp $" /* * File: scc_8530_hdw.c * Author: Alessandro Forin, Carnegie Mellon University * Date: 6/91 * * Hardware-level operations for the SCC Serial Line Driver */ #include #if NSCC > 0 #include #include #include #include /* spl definitions */ #include #include #include #include #include #include #include /* Alignment and padding */ #if defined(DECSTATION) /* * 3min's padding */ typedef struct { char pad0; volatile unsigned char datum; char pad1[2]; } scc_padded1_register_t; #define scc_register_t scc_padded1_register_t #endif #if defined(FLAMINGO) typedef struct { volatile unsigned int datum; unsigned int pad1; } scc_padded1_register_t; #define scc_register_t scc_padded1_register_t #define scc_set_datum(d,v) (d) = (volatile unsigned int) (v) << 8, wbflush() #define scc_get_datum(d,v) (v) = ((d) >> 8) & 0xff #endif #include /* needs the above defs */ /* * On the 3min keyboard and mouse come in on channels A * of the two units. The MI code expects them at 'lines' * 0 and 1, respectively. So we map here back and forth. * Note also the MI code believes unit 0 has four lines. */ #define SCC_KBDUNIT 1 #define SCC_PTRUNIT 0 mi_to_scc(unitp, linep) int *unitp, *linep; { /* only play games on MI 'unit' 0 */ if (*unitp) { /* e.g. by mapping the first four lines specially */ *unitp++; return; } /* always get unit=0 (console) and line = 0|1 */ if (*linep == SCREEN_LINE_KEYBOARD) { *unitp = SCC_KBDUNIT; *linep = SCC_CHANNEL_A; } else if (*linep == SCREEN_LINE_POINTER) { *unitp = SCC_PTRUNIT; *linep = SCC_CHANNEL_A; } else { *unitp = (*linep & 1); *linep = SCC_CHANNEL_B; } /* line 0 is channel B, line 1 is channel A */ } #define NSCC_LINE 2 /* 2 ttys per chip */ /* only care for mapping to ttyno */ scc_to_mi(sccunit, sccline) { if (sccunit > 1) return (sccunit * NSCC_LINE + sccline); /* only for console (first pair of SCCs): */ if (sccline == SCC_CHANNEL_A) return ((!sccunit) & 1); return 2+sccunit; } /* * Driver status */ struct scc_softc { scc_regmap_t *regs; /* software copy of some write regs, for reg |= */ struct softreg { unsigned char wr1; unsigned char wr4; unsigned char wr5; unsigned char wr14; } softr[2]; /* per channel */ unsigned short breaks; unsigned short fake; /* missing rs232 bits, channel A */ char polling_mode; char softCAR, osoftCAR; char probed_once; boolean_t full_modem; boolean_t isa_console; } scc_softc_data[NSCC]; typedef struct scc_softc *scc_softc_t; scc_softc_t scc_softc[NSCC]; scc_softCAR(unit, line, on) { mi_to_scc(&unit, &line); if (on) scc_softc[unit]->softCAR |= 1<softCAR &= ~(1 << line); } /* * BRG formula is: * ClockFrequency * BRGconstant = --------------------------- - 2 * 2 * BaudRate * ClockDivider */ /* Speed selections with Pclk=7.3728Mhz, clock x16 */ static short scc_speeds[] = /* 0 50 75 110 134.5 150 200 300 600 1200 1800 2400 */ { 0, 4606, 3070, 2093, 1711, 1534, 1150, 766, 382, 190, 126, 94, /* 4800 9600 19.2k 38.4k */ 46, 22, 10, 4}; /* * Definition of the driver for the auto-configuration program. */ int scc_probe(), scc_attach(), scc_intr(); caddr_t scc_std[NSCC] = { 0 }; struct bus_device *scc_info[NSCC]; struct bus_driver scc_driver = { scc_probe, 0, scc_attach, 0, scc_std, "scc", scc_info,}; /* * Adapt/Probe/Attach functions */ boolean_t scc_uses_modem_control = FALSE;/* patch this with adb */ set_scc_address( sccunit, regs, has_modem, isa_console) caddr_t regs; boolean_t has_modem; boolean_t isa_console; { extern int scc_probe(), scc_param(), scc_start(), scc_putc(), scc_getc(), scc_pollc(), scc_mctl(), scc_softCAR(); scc_std[sccunit] = regs; scc_softc_data[sccunit].full_modem = has_modem & scc_uses_modem_control; scc_softc_data[sccunit].isa_console = isa_console; /* Do this here */ console_probe = scc_probe; console_param = scc_param; console_start = scc_start; console_putc = scc_putc; console_getc = scc_getc; console_pollc = scc_pollc; console_mctl = scc_mctl; console_softCAR = scc_softCAR; } scc_probe( xxx, ui) struct bus_device *ui; { int sccunit = ui->unit; scc_softc_t scc; register int val; register scc_regmap_t *regs; regs = (scc_regmap_t *)scc_std[sccunit]; if (regs == 0) return 0; /* * See if we are here */ if (check_memory(regs, 0)) { /* no rides today */ return 0; } scc = &scc_softc_data[sccunit]; if (scc->probed_once++){ return 1; } /* * Chip once-only initialization * * NOTE: The wiring we assume is the one on the 3min: * * out A-TxD --> TxD keybd or mouse * in A-RxD --> RxD keybd or mouse * out A-DTR~ --> DTR comm * out A-RTS~ --> RTS comm * in A-CTS~ --> SI comm * in A-DCD~ --> RI comm * in A-SYNCH~--> DSR comm * out B-TxD --> TxD comm * in B-RxD --> RxD comm * in B-RxC --> TRxCB comm * in B-TxC --> RTxCB comm * out B-RTS~ --> SS comm * in B-CTS~ --> CTS comm * in B-DCD~ --> CD comm */ scc_softc[sccunit] = scc; scc->regs = regs; scc->fake = 1<t_addr = (char*)(0x80000000L + (sccunit<<1) + (i&1)); /* do min buffering */ tp->t_state |= TS_MIN; } } /* make sure reg pointer is in known state */ scc_init_reg(regs, SCC_CHANNEL_A); scc_init_reg(regs, SCC_CHANNEL_B); /* reset chip, fully */ scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET); delay(50000);/*enough ? */ scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, 0); /* program the interrupt vector */ scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0); scc_write_reg(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0); scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS); /* most of the init is in scc_param() */ /* timing base defaults */ scc->softr[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16; scc->softr[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16; /* enable DTR, RTS and SS */ scc->softr[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS; scc->softr[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR; /* baud rates */ val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC; scc->softr[SCC_CHANNEL_B].wr14 = val; scc->softr[SCC_CHANNEL_A].wr14 = val; /* interrupt conditions */ val = SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE | SCC_WR1_EXT_IE | SCC_WR1_TX_IE; scc->softr[SCC_CHANNEL_A].wr1 = val; scc->softr[SCC_CHANNEL_B].wr1 = val; /* * After probing, any line that should be active * (keybd,mouse,rcline) is activated via scc_param(). */ scc_set_modem_control(scc, scc->full_modem); #if defined(KMIN) || defined (FLAMINGO) /* * Crock: MI code knows of unit 0 as console, we need * unit 1 as well since the keyboard is there * This is acceptable on maxine, which has to call its * only one chip unit 1 so that rconsole is happy. */ if (sccunit == 0) { struct bus_device d; d = *ui; d.unit = 1; scc_probe( xxx, &d); } #endif return 1; } boolean_t scc_timer_started = FALSE; scc_attach(ui) register struct bus_device *ui; { int sccunit = ui->unit; extern scc_scan(); extern int tty_inq_size; int i; /* We only have 4 ttys, but always at 9600 * Give em a lot of room (plus dma..) */ tty_inq_size = 4096; if (!scc_timer_started) { /* do all of them, before we call scc_scan() */ /* harmless if done already */ for (i = 0; i < NSCC*NSCC_LINE; i++) ttychars(console_tty[i]); scc_timer_started = TRUE; scc_scan(); } #if NBM > 0 if (SCREEN_ISA_CONSOLE() && scc_softc[sccunit]->isa_console) { printf("\n sl0: "); if (sccunit && rcline == 3) printf("( rconsole )"); if (sccunit == SCC_KBDUNIT) { printf("\n sl1: "); lk201_attach(0, sccunit >> 1); } else if (sccunit == SCC_PTRUNIT) { printf("\n sl1: "); mouse_attach(0, sccunit >> 1); } } else #endif /*NBM > 0*/ { printf("%s", (sccunit == 1) ? "\n sl0: ( alternate console )\n sl1:" : "\n sl0:\n sl1:"); } } /* * Would you like to make a phone call ? */ scc_set_modem_control(scc, on) scc_softc_t scc; boolean_t on; { if (on) /* your problem if the hardware then is broke */ scc->fake = 0; else scc->fake = 3; scc->full_modem = on; /* user should do an scc_param() ifchanged */ } /* * Polled I/O (debugger) */ scc_pollc(unit, on) boolean_t on; { scc_softc_t scc; int line = SCREEN_LINE_KEYBOARD, sccunit = unit; mi_to_scc(&sccunit, &line); scc = scc_softc[sccunit]; if (on) { scc->polling_mode++; #if NBM > 0 screen_on_off(unit, TRUE); #endif NBM > 0 } else scc->polling_mode--; } /* * Interrupt routine */ int scc_intr_count; scc_intr(unit,spllevel) spl_t spllevel; { scc_softc_t scc = scc_softc[unit]; register scc_regmap_t *regs = scc->regs; register int rr1, rr2; register int c; scc_intr_count++; #if mips splx(spllevel); /* lower priority */ #endif next_intr: scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR2, rr2); rr2 = SCC_RR2_STATUS(rr2); /* are we done yet ? */ if (rr2 == 6) { /* strange, distinguished value */ register int rr3; scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR3, rr3); if (rr3 == 0) return; } if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) { register chan = (rr2 == SCC_RR2_A_XMIT_DONE) ? SCC_CHANNEL_A : SCC_CHANNEL_B; scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); c = cons_simple_tint(scc_to_mi(unit,chan), FALSE); if (c == -1) { /* no more data for this line */ scc_read_reg(regs, chan, SCC_RR15, c); c &= ~SCC_WR15_TX_UNDERRUN_IE; scc_write_reg(regs, chan, SCC_WR15, c); c = scc->softr[chan].wr1 & ~SCC_WR1_TX_IE; scc_write_reg(regs, chan, SCC_WR1, c); scc->softr[chan].wr1 = c; c = cons_simple_tint(scc_to_mi(unit,chan), TRUE); if (c != -1) /* funny race, scc_start has been called already */ scc_write_data(regs, chan, c); } else { scc_write_data(regs, chan, c); /* and leave it enabled */ } } else if (rr2 == SCC_RR2_A_RECV_DONE) { int err = 0; scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); if (scc->polling_mode) goto next_intr; scc_read_data(regs, SCC_CHANNEL_A, c); rr1 = scc_to_mi(unit,SCC_CHANNEL_A); cons_simple_rint (rr1, rr1, c, 0); } else if (rr2 == SCC_RR2_B_RECV_DONE) { int err = 0; scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); if (scc->polling_mode) goto next_intr; scc_read_data(regs, SCC_CHANNEL_B, c); rr1 = scc_to_mi(unit,SCC_CHANNEL_B); cons_simple_rint (rr1, rr1, c, 0); } else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) { int chan = (rr2 == SCC_RR2_A_EXT_STATUS) ? SCC_CHANNEL_A : SCC_CHANNEL_B; scc_write_reg(regs, chan, SCC_RR0, SCC_RESET_EXT_IP); scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); scc_modem_intr(scc, chan); } else if ((rr2 == SCC_RR2_A_RECV_SPECIAL) || (rr2 == SCC_RR2_B_RECV_SPECIAL)) { register int chan = (rr2 == SCC_RR2_A_RECV_SPECIAL) ? SCC_CHANNEL_A : SCC_CHANNEL_B; scc_read_reg(regs, chan, SCC_RR1, rr1); if (rr1 & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { int err; /* map to CONS_ERR_xxx MI error codes */ err = ((rr1 & SCC_RR1_PARITY_ERR)<<8) | ((rr1 & SCC_RR1_RX_OVERRUN)<<9) | ((rr1 & SCC_RR1_FRAME_ERR)<<7); scc_write_reg(regs, chan, SCC_RR0, SCC_RESET_ERROR); rr1 = scc_to_mi(unit,chan); cons_simple_rint(rr1, rr1, 0, err); } scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); } goto next_intr; } boolean_t scc_start(tp) struct tty *tp; { register scc_regmap_t *regs; register int chan, temp; register struct softreg *sr; temp = (natural_t)tp->t_addr; chan = (temp & 1); /* channel */ temp = (temp >> 1)&0xff;/* sccunit */ regs = scc_softc[temp]->regs; sr = &scc_softc[temp]->softr[chan]; scc_read_reg(regs, chan, SCC_RR15, temp); temp |= SCC_WR15_TX_UNDERRUN_IE; scc_write_reg(regs, chan, SCC_WR15, temp); temp = sr->wr1 | SCC_WR1_TX_IE; scc_write_reg(regs, chan, SCC_WR1, temp); sr->wr1 = temp; /* but we need a first char out or no cookie */ scc_read_reg(regs, chan, SCC_RR0, temp); if (temp & SCC_RR0_TX_EMPTY) { register char c; c = getc(&tp->t_outq); scc_write_data(regs, chan, c); } } /* * Get a char from a specific SCC line * [this is only used for console&screen purposes] */ scc_getc( unit, line, wait, raw ) boolean_t wait; boolean_t raw; { scc_softc_t scc; register scc_regmap_t *regs; unsigned char c; int value, mi_line, rcvalue, from_line; mi_line = line; mi_to_scc(&unit, &line); scc = scc_softc[unit]; regs = scc->regs; /* * wait till something available * * NOTE: we know! that rcline==3 */ if (rcline) rcline = 3; again: rcvalue = 0; while (1) { scc_read_reg_zero(regs, line, value); if (rcline && (mi_line == SCREEN_LINE_KEYBOARD)) { scc_read_reg_zero(regs, SCC_CHANNEL_B, rcvalue); value |= rcvalue; } if (((value & SCC_RR0_RX_AVAIL) == 0) && wait) delay(10); else break; } /* * if nothing found return -1 */ from_line = (rcvalue & SCC_RR0_RX_AVAIL) ? SCC_CHANNEL_B : line; if (value & SCC_RR0_RX_AVAIL) { scc_read_reg(regs, from_line, SCC_RR1, value); scc_read_data(regs, from_line, c); } else { /* splx(s);*/ return -1; } /* * bad chars not ok */ if (value&(SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { /* scc_state(unit,from_line); */ scc_write_reg(regs, from_line, SCC_RR0, SCC_RESET_ERROR); if (wait) { scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); goto again; } } scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); /* splx(s);*/ #if NBM > 0 if ((mi_line == SCREEN_LINE_KEYBOARD) && (from_line == SCC_CHANNEL_A) && !raw && SCREEN_ISA_CONSOLE() && scc->isa_console) return lk201_rint(SCREEN_CONS_UNIT(), c, wait, scc->polling_mode); else #endif NBM > 0 return c; } /* * Put a char on a specific SCC line */ scc_putc( unit, line, c ) { scc_softc_t scc; register scc_regmap_t *regs; spl_t s = spltty(); register int value; mi_to_scc(&unit, &line); scc = scc_softc[unit]; regs = scc->regs; do { scc_read_reg(regs, line, SCC_RR0, value); if (value & SCC_RR0_TX_EMPTY) break; delay(100); } while (1); scc_write_data(regs, line, c); /* wait for it to swallow the char ? */ splx(s); } scc_param(tp, line) struct tty *tp; { scc_regmap_t *regs; int value, sccline, unit; struct softreg *sr; scc_softc_t scc; line = tp->t_dev; /* MI code wants us to handle 4 lines on unit 0 */ unit = (line < 4) ? 0 : (line / NSCC_LINE); sccline = line; mi_to_scc(&unit, &sccline); if ((scc = scc_softc[unit]) == 0) return; /* sanity */ regs = scc->regs; sr = &scc->softr[sccline]; /* * Do not let user fool around with kbd&mouse */ #if NBM > 0 if (screen_captures(line)) { tp->t_ispeed = tp->t_ospeed = B4800; tp->t_flags |= TF_LITOUT; } #endif NBM > 0 if (tp->t_ispeed == 0) { (void) scc_mctl(tp->t_dev, TM_HUP, DMSET); /* hang up line */ return; } /* reset line */ value = (sccline == SCC_CHANNEL_A) ? SCC_WR9_RESET_CHA_A : SCC_WR9_RESET_CHA_B; scc_write_reg(regs, sccline, SCC_WR9, value); delay(25); /* stop bits, normally 1 */ value = sr->wr4 & 0xf0; value |= (tp->t_ispeed == B110) ? SCC_WR4_2_STOP : SCC_WR4_1_STOP; /* .. and parity */ #if 0 if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_EVENP) value |= SCC_WR4_EVEN_PARITY; value |= SCC_WR4_PARITY_ENABLE; #else if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_ODDP) value |= SCC_WR4_PARITY_ENABLE; #endif /* set it now, remember it must be first after reset */ sr->wr4 = value; scc_write_reg(regs, sccline, SCC_WR4, value); /* vector again */ scc_write_reg(regs, sccline, SCC_WR2, 0xf0); /* we only do 8 bits per char */ value = SCC_WR3_RX_8_BITS; scc_write_reg(regs, sccline, SCC_WR3, value); /* clear break, keep rts dtr */ value = sr->wr5 & (SCC_WR5_DTR|SCC_WR5_RTS); value |= SCC_WR5_TX_8_BITS; sr->wr5 = value; scc_write_reg(regs, sccline, SCC_WR5, value); scc_write_reg(regs, sccline, SCC_WR6, 0); scc_write_reg(regs, sccline, SCC_WR7, 0); scc_write_reg(regs, sccline, SCC_WR9, SCC_WR9_VIS); scc_write_reg(regs, sccline, SCC_WR10, 0); /* clock config */ value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR | SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR; scc_write_reg(regs, sccline, SCC_WR11, value); value = scc_speeds[tp->t_ispeed]; scc_set_timing_base(regs,sccline,value); value = sr->wr14; scc_write_reg(regs, sccline, SCC_WR14, value); value = (scc->full_modem) ? SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE : SCC_WR15_BREAK_IE; scc_write_reg(regs, sccline, SCC_WR15, value); /* and now the enables */ value = SCC_WR3_RX_8_BITS | SCC_WR3_RX_ENABLE; scc_write_reg(regs, sccline, SCC_WR3, value); value = sr->wr5 | SCC_WR5_TX_ENABLE; sr->wr5 = value; scc_write_reg(regs, sccline, SCC_WR5, value); /* master inter enable */ scc_write_reg(regs,sccline,SCC_WR9,SCC_WR9_MASTER_IE|SCC_WR9_VIS); scc_write_reg(regs, sccline, SCC_WR1, sr->wr1); } /* * Modem control functions */ scc_mctl(dev, bits, how) int dev; int bits, how; { return 0; #if 0 register scc_regmap_t *regs; int unit, sccline; register int tcr, msr, brk, n_tcr, n_brk; int b; spl_t s; scc_softc_t sc; unit = dev; sccline = unit & 3; unit >>= 2; mi_to_scc(&unit, &sccline); /* no modem support on channel A */ /* XXX break on 0&1 */ if (sccline == SCC_CHANNEL_A) return TM_LE | TM_DTR | TM_CTS | TM_CAR | TM_DSR; scc = scc_softc[unit]; regs = scc->regs; s = spltty(); ....some other day.. tcr = ((regs->scc_tcr | (scc->fake>>4)) & 0xf00) >> (8 + b*2); brk = (scc->breaks >> (8 + (unit&3))) & 1; /* THE break bit */ n_tcr = (bits & (TM_RTS | TM_DTR)) >> 1; n_brk = (bits & TM_BRK) >> 9; /* break transitions, must 'send' a char out */ bits = (brk ^ n_brk) & 1; switch (how) { case DMSET: tcr = n_tcr; brk = n_brk; break; case DMBIS: tcr |= n_tcr; brk |= n_brk; break; case DMBIC: tcr &= ~n_tcr; brk = 0; break; case DMGET: msr = ((regs->scc_msr | scc->fake) & 0xf0f) >> (b*8); (void) splx(s); return (tcr<<1)|/* DTR, RTS */ ((msr&1)<<5)|/* CTS */ ((msr&2)<<7)|/* DSR */ ((msr&0xc)<<4)|/* CD, RNG */ (brk << 9)|/* BRK */ TM_LE; } n_tcr = (regs->scc_tcr & ~(3 << (8 + b*2))) | (tcr << (8 + b*2)); regs->scc_tcr = n_tcr; scc->fake = (scc->fake & 0xf0f) | (n_tcr<<4&0xf000); scc->breaks = (scc->breaks & ~(1 << (8 + (unit&3)))) | (brk << (8 + (unit&3))); if(bits) scc_putc( unit>>2, unit&3, 0);/* force break, now */ (void) splx(s); return 0;/* useless to compute it */ #endif } scc_modem_intr(scc, chan) { /* nothing yet */ } static check_car( register struct tty *tp, boolean_t car) { if (car) { #if notyet /* cancel modem timeout if need to */ if (car & (SCC_MSR_CD2 | SCC_MSR_CD3)) untimeout(scc_hup, (caddr_t)tp); #endif /* I think this belongs in the MI code */ if (tp->t_state & TS_WOPEN) tp->t_state |= TS_ISOPEN; /* carrier present */ if ((tp->t_state & TS_CARR_ON) == 0) (void)ttymodem(tp, 1); } else if ((tp->t_state&TS_CARR_ON) && ttymodem(tp, 0) == 0) scc_mctl( tp->t_dev, TM_DTR, DMBIC); } /* * Periodically look at the CD signals: * they do generate interrupts but we * must fake them on channel A. We might * also fake them on channel B. */ scc_scan() { register i; spl_t s = spltty(); for (i = 0; i < NSCC; i++) { register scc_softc_t scc; register int car; register struct tty **tpp; scc = scc_softc[i]; if (scc == 0) continue; car = scc->softCAR | scc->fake; tpp = &console_tty[i * NSCC_LINE]; while (car) { if (car & 1) check_car(*tpp, 1); tpp++; car = car>>1; } } splx(s); timeout(scc_scan, (caddr_t)0, 5*hz); } #if 0 /* debug */ scc_rreg(unit,chan,n) { int val; scc_read_reg(scc_softc[unit]->regs, chan, n, val); return val; } scc_wreg(unit,chan,n,val) { scc_write_reg(scc_softc[unit]->regs, chan, n, val); } scc_state(unit,soft) { printf("{%d intr, A: R0 %x R1 %x R3 %x baudr %x R15 %x}\n", scc_intr_count, scc_rreg(unit, 1, SCC_RR0), scc_rreg(unit, 1, SCC_RR1), scc_rreg(unit, 1, SCC_RR3), (scc_rreg(unit, 1, SCC_RR13) << 8) | scc_rreg(unit, 1, SCC_RR12), scc_rreg(unit, 1, SCC_RR15)); printf("{B: R0 %x R1 %x R2 %x baudr %x R15 %x}\n", scc_rreg(unit, 1, SCC_RR0), scc_rreg(unit, 1, SCC_RR1), scc_rreg(unit, 1, SCC_RR2), (scc_rreg(unit, 1, SCC_RR13) << 8) | scc_rreg(unit, 1, SCC_RR12), scc_rreg(unit, 1, SCC_RR15)); if (soft) { struct softreg *sr; sr = scc_softc[unit]->softr; printf("{B: W1 %x W4 %x W5 %x W14 %x}", sr->wr1, sr->wr4, sr->wr5, sr->wr14); sr++; printf("{A: W1 %x W4 %x W5 %x W14 %x}\n", sr->wr1, sr->wr4, sr->wr5, sr->wr14); } } #endif #endif NSCC > 0