diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2001-08-21 21:42:31 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2001-08-21 21:42:31 +0000 |
commit | 32233cbea00059b62b2cb41171efdac6f6745e5a (patch) | |
tree | 37f2f466c5efcd89191559c7cae5fb7d17f6a868 /sys/arch | |
parent | b7839ed5b9eb410077a97b34afb12d65daa80169 (diff) |
zs and all it's associated stuff (all from NetBSD).. Works on my ultra1,
but still needs tweaks (wedging this into OpenBSD is worse than square
peg in round hole).
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/sparc64/conf/GENERIC | 5 | ||||
-rw-r--r-- | sys/arch/sparc64/conf/files.sparc64 | 10 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/z8530reg.h | 451 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/z8530sc.c | 357 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/z8530sc.h | 157 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/z8530tty.c | 1838 | ||||
-rw-r--r-- | sys/arch/sparc64/dev/zs.c | 26 | ||||
-rw-r--r-- | sys/arch/sparc64/include/z8530var.h | 4 |
8 files changed, 2831 insertions, 17 deletions
diff --git a/sys/arch/sparc64/conf/GENERIC b/sys/arch/sparc64/conf/GENERIC index 7afe28047e0..210fc659cff 100644 --- a/sys/arch/sparc64/conf/GENERIC +++ b/sys/arch/sparc64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.8 2001/08/21 16:21:47 jason Exp $ +# $OpenBSD: GENERIC,v 1.9 2001/08/21 21:42:30 jason Exp $ # $NetBSD: GENERIC32,v 1.18 2001/07/20 00:07:12 eeh Exp $ machine sparc64 @@ -24,6 +24,9 @@ sbus0 at mainbus0 # Ultra 1 #### Standard system devices -- all required for a given architecture +zs* at sbus? slot ? offset ? +zstty* at zs? channel ? + ## PROM console driver -- if all else fails pcons0 at mainbus0 # PROM console diff --git a/sys/arch/sparc64/conf/files.sparc64 b/sys/arch/sparc64/conf/files.sparc64 index 8cbef86eabe..27e97fa55b3 100644 --- a/sys/arch/sparc64/conf/files.sparc64 +++ b/sys/arch/sparc64/conf/files.sparc64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.sparc64,v 1.7 2001/08/21 16:21:27 jason Exp $ +# $OpenBSD: files.sparc64,v 1.8 2001/08/21 21:42:30 jason Exp $ # $NetBSD: files.sparc64,v 1.50 2001/08/10 20:53:50 eeh Exp $ # maxpartitions must be first item in files.${ARCH} @@ -49,18 +49,18 @@ file arch/sparc64/sparc64/cpu.c device zs {channel = -1} attach zs at mainbus, sbus file arch/sparc64/dev/zs.c zs needs-flag -file dev/ic/z8530sc.c zs +file arch/sparc64/dev/z8530sc.c zs define zstty {} device zstty: tty attach zstty at zs -file dev/ic/z8530tty.c zstty needs-flag +file arch/sparc64/dev/z8530tty.c zstty needs-flag device kbd attach kbd at zs with kbd_zs attach kbd at zstty -file dev/sun/kbd_zs.c kbd_zs -file dev/sun/kbd.c kbd needs-flag +file arch/sparc64/dev/kbd_zs.c kbd_zs +file arch/sparc64/dev/kbd.c kbd needs-flag file dev/sun/kbd_tables.c kbd file arch/sparc64/dev/kd.c kbd file dev/sun/sunkbd.c kbd needs-flag diff --git a/sys/arch/sparc64/dev/z8530reg.h b/sys/arch/sparc64/dev/z8530reg.h new file mode 100644 index 00000000000..1ba1faa9b95 --- /dev/null +++ b/sys/arch/sparc64/dev/z8530reg.h @@ -0,0 +1,451 @@ +/* $OpenBSD: z8530reg.h,v 1.1 2001/08/21 21:42:30 jason Exp $ */ +/* $NetBSD: z8530reg.h,v 1.9 1998/07/31 05:08:38 wrstuden Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)zsreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Zilog SCC registers, as implemented on the Sun-4c. + * + * Each Z8530 implements two channels (called `a' and `b'). + * + * The damnable chip was designed to fit on Z80 I/O ports, and thus + * has everything multiplexed out the wazoo. We have to select + * a register, then read or write the register, and so on. Worse, + * the parameter bits are scattered all over the register space. + * This thing is full of `miscellaneous' control registers. + * + * Worse yet, the registers have incompatible functions on read + * and write operations. We describe the registers below according + * to whether they are `read registers' (RR) or `write registers' (WR). + * As if this were not enough, some of the channel B status bits show + * up in channel A, and vice versa. The blasted thing shares write + * registers 2 and 9 across both channels, and reads registers 2 and 3 + * differently for the two channels. We can, however, ignore this much + * of the time. + * + * This file also includes flags for the Z85C30 and Z85230 enhanced scc. + * The CMOS 8530 includes extra SDLC functionality, and is used in a + * number of Macs (often in the Z85C80, an 85C30 combined w/ a SCSI + * controller). -wrs + * + * Some of the names in this files were chosen to make the hsis driver + * work unchanged (which means that they will match some in SunOS). + * + * `S.C.' stands for Special Condition, which is any of these: + * receiver overrun (aka silo overflow) + * framing error (missing stop bit, etc) + * end of frame (in synchronous modes) + * parity error (when `parity error is S.C.' is set) + * + * Registers with only a single `numeric value' get a name. + * Other registers hold bits and are only numbered; the bit + * definitions imply the register number (see below). + * + * We never use the receive and transmit data registers as + * indirects (choosing instead the zc_data register), so they + * are not defined here. + */ +#define ZSRR_IVEC 2 /* interrupt vector (channel 0) */ +#define ZSRR_IPEND 3 /* interrupt pending (ch. 0 only) */ +#define ZSRR_TXSYNC 6 /* sync transmit char (monosync mode) */ +#define ZSRR_RXSYNC 7 /* sync receive char (monosync mode) */ +#define ZSRR_SYNCLO 6 /* sync low byte (bisync mode) */ +#define ZSRR_SYNCHI 7 /* sync high byte (bisync mode) */ +#define ZSRR_SDLC_ADDR 6 /* SDLC address (SDLC mode) */ +#define ZSRR_SDLC_FLAG 7 /* SDLC flag 0x7E (SDLC mode) */ +#define ZSRR_BAUDLO 12 /* baud rate generator (low half) */ +#define ZSRR_BAUDHI 13 /* baud rate generator (high half) */ +#define ZSRR_ENHANCED 14 /* read address of WR7' - yes, it's not 7!*/ + +#define ZSWR_IVEC 2 /* interrupt vector (shared) */ +#define ZSWR_TXSYNC 6 /* sync transmit char (monosync mode) */ +#define ZSWR_RXSYNC 7 /* sync receive char (monosync mode) */ +#define ZSWR_SYNCLO 6 /* sync low byte (bisync mode) */ +#define ZSWR_SYNCHI 7 /* sync high byte (bisync mode) */ +#define ZSWR_SDLC_ADDR 6 /* SDLC address (SDLC mode) */ +#define ZSWR_SDLC_FLAG 7 /* SDLC flag 0x7E (SDLC mode) */ +#define ZSWR_BAUDLO 12 /* baud rate generator (low half) */ +#define ZSWR_BAUDHI 13 /* baud rate generator (high half) */ +#define ZSWR_ENHANCED 7 /* write address of WR7' */ + +/* + * Registers 0 through 7 may be written with any one of the 8 command + * modifiers, and/or any one of the 4 reset modifiers, defined below. + * To write registers 8 through 15, however, the command modifier must + * always be `point high'. Rather than track this bizzareness all over + * the driver, we try to avoid using any modifiers, ever (but they are + * defined here if you want them). + */ +#define ZSM_RESET_TXUEOM 0xc0 /* reset xmit underrun / eom latch */ +#define ZSM_RESET_TXCRC 0x80 /* reset xmit crc generator */ +#define ZSM_RESET_RXCRC 0x40 /* reset recv crc checker */ +#define ZSM_NULL 0x00 /* nothing special */ + +#define ZSM_RESET_IUS 0x38 /* reset interrupt under service */ +#define ZSM_RESET_ERR 0x30 /* reset error cond */ +#define ZSM_RESET_TXINT 0x28 /* reset xmit interrupt pending */ +#define ZSM_EI_NEXTRXC 0x20 /* enable int. on next rcvd char */ +#define ZSM_SEND_ABORT 0x18 /* send abort (SDLC) */ +#define ZSM_RESET_STINT 0x10 /* reset external/status interrupt */ +#define ZSM_POINTHIGH 0x08 /* `point high' (use r8-r15) */ +#define ZSM_NULL 0x00 /* nothing special */ + +/* + * Commands for Write Register 0 (`Command Register'). + * These are just the command modifiers or'ed with register number 0 + * (which of course equals the command modifier). + */ +#define ZSWR0_RESET_EOM ZSM_RESET_TXUEOM +#define ZSWR0_RESET_TXCRC ZSM_RESET_TXCRC +#define ZSWR0_RESET_RXCRC ZSM_RESET_RXCRC +#define ZSWR0_CLR_INTR ZSM_RESET_IUS +#define ZSWR0_RESET_ERRORS ZSM_RESET_ERR +#define ZSWR0_EI_NEXTRXC ZSM_EI_NEXTRXC +#define ZSWR0_SEND_ABORT ZSM_SEND_ABORT +#define ZSWR0_RESET_STATUS ZSM_RESET_STINT +#define ZSWR0_RESET_TXINT ZSM_RESET_TXINT + +/* + * Bits in Write Register 1 (`Transmit/Receive Interrupt and Data + * Transfer Mode Definition'). Note that bits 3 and 4 are taken together + * as a single unit, and bits 5 and 6 are useful only if bit 7 is set. + */ +#define ZSWR1_REQ_WAIT 0x80 /* WAIT*-REQ* pin gives WAIT* */ +#define ZSWR1_REQ_REQ 0xc0 /* WAIT*-REQ* pin gives REQ* */ +#define ZSWR1_REQ_TX 0x00 /* WAIT*-REQ* pin follows xmit buf */ +#define ZSWR1_REQ_RX 0x20 /* WAIT*-REQ* pin follows recv buf */ + +#define ZSWR1_RIE_NONE 0x00 /* disable rxint entirely */ +#define ZSWR1_RIE_FIRST 0x08 /* rxint on first char & on S.C. */ +#define ZSWR1_RIE 0x10 /* rxint per char & on S.C. */ +#define ZSWR1_RIE_SPECIAL_ONLY 0x18 /* rxint on S.C. only */ + +#define ZSWR1_PE_SC 0x04 /* parity error is special condition */ +#define ZSWR1_TIE 0x02 /* transmit interrupt enable */ +#define ZSWR1_SIE 0x01 /* external/status interrupt enable */ + +#define ZSWR1_IMASK 0x1F /* mask of all itr. enable bits. */ + +/* HSIS compat */ +#define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX) + +/* + * Bits in Write Register 3 (`Receive Parameters and Control'). + * Bits 7 and 6 are taken as a unit. Note that the receive bits + * per character ordering is insane. + * + * Here `hardware flow control' means CTS enables the transmitter + * and DCD enables the receiver. The latter is neither interesting + * nor useful, and gets in our way, making it almost unusable. + */ +#define ZSWR3_RX_5 0x00 /* receive 5 bits per char */ +#define ZSWR3_RX_7 0x40 /* receive 7 bits per char */ +#define ZSWR3_RX_6 0x80 /* receive 6 bits per char */ +#define ZSWR3_RX_8 0xc0 /* receive 8 bits per char */ +#define ZSWR3_RXSIZE 0xc0 /* receive char size mask */ + +#define ZSWR3_HFC 0x20 /* hardware flow control */ +#define ZSWR3_HUNT 0x10 /* enter hunt mode */ +#define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */ +#define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */ +#define ZSWR3_SDLC_SHORT_ADDR 0x02 /* short address mode (SDLC only) */ +#define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */ +#define ZSWR3_RX_ENABLE 0x01 /* receiver enable */ + +/* + * Bits in Write Register 4 (`Transmit/Receive Miscellaneous Parameters + * and Modes'). Bits 7&6, 5&4, and 3&2 are taken as units. + */ +#define ZSWR4_CLK_X1 0x00 /* clock divisor = 1 */ +#define ZSWR4_CLK_X16 0x40 /* clock divisor = 16 */ +#define ZSWR4_CLK_X32 0x80 /* clock divisor = 32 */ +#define ZSWR4_CLK_X64 0xc0 /* clock divisor = 64 */ +#define ZSWR4_CLK_MASK 0xc0 /* clock divisor mask */ + +#define ZSWR4_MONOSYNC 0x00 /* 8 bit sync char (sync only) */ +#define ZSWR4_BISYNC 0x10 /* 16 bit sync char (sync only) */ +#define ZSWR4_SDLC 0x20 /* SDLC mode */ +#define ZSWR4_EXTSYNC 0x30 /* external sync mode */ +#define ZSWR4_SYNC_MASK 0x30 /* sync mode bit mask */ + +#define ZSWR4_SYNCMODE 0x00 /* no stop bit (sync mode only) */ +#define ZSWR4_ONESB 0x04 /* 1 stop bit */ +#define ZSWR4_1P5SB 0x08 /* 1.5 stop bits (clk cannot be 1x) */ +#define ZSWR4_TWOSB 0x0c /* 2 stop bits */ +#define ZSWR4_SBMASK 0x0c /* mask of all stop bits */ + +#define ZSWR4_EVENP 0x02 /* check for even parity */ +#define ZSWR4_PARENB 0x01 /* enable parity checking */ +#define ZSWR4_PARMASK 0x03 /* mask of all parity bits */ + +/* + * Bits in Write Register 5 (`Transmit Parameter and Controls'). + * Bits 6 and 5 are taken as a unit; the ordering is, as with RX + * bits per char, not sensible. + */ +#define ZSWR5_DTR 0x80 /* assert (set to -12V) DTR */ + +#define ZSWR5_TX_5 0x00 /* transmit 5 or fewer bits */ +#define ZSWR5_TX_7 0x20 /* transmit 7 bits */ +#define ZSWR5_TX_6 0x40 /* transmit 6 bits */ +#define ZSWR5_TX_8 0x60 /* transmit 8 bits */ +#define ZSWR5_TXSIZE 0x60 /* transmit char size mask */ + +#define ZSWR5_BREAK 0x10 /* send break (continuous 0s) */ +#define ZSWR5_TX_ENABLE 0x08 /* enable transmitter */ +#define ZSWR5_CRC16 0x04 /* use CRC16 (off => use SDLC) */ +#define ZSWR5_RTS 0x02 /* assert RTS */ +#define ZSWR5_TXCRC_ENABLE 0x01 /* enable xmit crc calculation */ + +#ifdef not_done_here +/* + * Bits in Write Register 7 when the chip is in SDLC mode. + */ +#define ZSWR7_SDLCFLAG 0x7e /* this value makes SDLC mode work */ +#endif + +/* + * Bits in Write Register 7' (ZSWR_ENHANCED above). This register is + * only available on the 85230. Dispite the fact it contains flags + * and not a single value, the register was named as it is read + * via RR14. Weird. + */ + /* 0x80 unused */ +#define ZSWR7P_EXTEND_READ 0x40 /* modify read map; make most regs readable */ +#define ZSWR7P_TX_FIFO 0x20 /* change level for Tx FIFO empty int */ +#define ZSWR7P_DTR_TIME 0x10 /* modifies deact. speed of /DTR//REQ */ +#define ZSWR7P_RX_FIFO 0x08 /* Rx FIFO int on 1/2 full? */ +#define ZSWR7P_RTS_DEACT 0x04 /* automatically deassert RTS */ +#define ZSWR7P_AUTO_EOM_RESET 0x02 /* automatically reset EMO/Tx Underrun */ +#define ZSWR7P_AUTO_TX_FLAG 0x01 /* Auto send SDLC flag at transmit start */ + +/* + * Bits in Write Register 9 (`Master Interrupt Control'). Bits 7 & 6 + * are taken as a unit and indicate the type of reset; 00 means no reset + * (and is not defined here). + */ +#define ZSWR9_HARD_RESET 0xc0 /* force hardware reset */ +#define ZSWR9_A_RESET 0x80 /* reset channel A (0) */ +#define ZSWR9_B_RESET 0x40 /* reset channel B (1) */ +#define ZSWR9_SOFT_INTAC 0x20 /* Not in NMOS version */ + +#define ZSWR9_STATUS_HIGH 0x10 /* status in high bits of intr vec */ +#define ZSWR9_MASTER_IE 0x08 /* master interrupt enable */ +#define ZSWR9_DLC 0x04 /* disable lower chain */ +#define ZSWR9_NO_VECTOR 0x02 /* no vector */ +#define ZSWR9_VECTOR_INCL_STAT 0x01 /* vector includes status */ + +/* + * Bits in Write Register 10 (`Miscellaneous Transmitter/Receiver Control + * Bits'). Bits 6 & 5 are taken as a unit, and some of the bits are + * meaningful only in certain modes. Bleah. + */ +#define ZSWR10_PRESET_ONES 0x80 /* preset CRC to all 1 (else all 0) */ + +#define ZSWR10_NRZ 0x00 /* NRZ encoding */ +#define ZSWR10_NRZI 0x20 /* NRZI encoding */ +#define ZSWR10_FM1 0x40 /* FM1 encoding */ +#define ZSWR10_FM0 0x60 /* FM0 encoding */ + +#define ZSWR10_GA_ON_POLL 0x10 /* go active on poll (loop mode) */ +#define ZSWR10_MARK_IDLE 0x08 /* all 1s (vs flag) when idle (SDLC) */ +#define ZSWR10_ABORT_ON_UNDERRUN 0x4 /* abort on xmit underrun (SDLC) */ +#define ZSWR10_LOOP_MODE 0x02 /* loop mode (SDLC) */ +#define ZSWR10_6_BIT_SYNC 0x01 /* 6 bits per sync char (sync modes) */ + +/* + * Bits in Write Register 11 (`Clock Mode Control'). Bits 6&5, 4&3, and + * 1&0 are taken as units. Various bits depend on other bits in complex + * ways; see the Zilog manual. + */ +#define ZSWR11_XTAL 0x80 /* have xtal between RTxC* and SYNC* */ + /* (else have TTL oscil. on RTxC*) */ +#define ZSWR11_RXCLK_RTXC 0x00 /* recv clock taken from RTxC* pin */ +#define ZSWR11_RXCLK_TRXC 0x20 /* recv clock taken from TRxC* pin */ +#define ZSWR11_RXCLK_BAUD 0x40 /* recv clock taken from BRG */ +#define ZSWR11_RXCLK_DPLL 0x60 /* recv clock taken from DPLL */ + +#define ZSWR11_TXCLK_RTXC 0x00 /* xmit clock taken from RTxC* pin */ +#define ZSWR11_TXCLK_TRXC 0x08 /* xmit clock taken from TRxC* pin */ +#define ZSWR11_TXCLK_BAUD 0x10 /* xmit clock taken from BRG */ +#define ZSWR11_TXCLK_DPLL 0x18 /* xmit clock taken from DPLL */ + +#define ZSWR11_TRXC_OUT_ENA 0x04 /* TRxC* pin will be an output */ + /* (unless it is being used above) */ +#define ZSWR11_TRXC_XTAL 0x00 /* TRxC output from xtal oscillator */ +#define ZSWR11_TRXC_XMIT 0x01 /* TRxC output from xmit clock */ +#define ZSWR11_TRXC_BAUD 0x02 /* TRxC output from BRG */ +#define ZSWR11_TRXC_DPLL 0x03 /* TRxC output from DPLL */ + +/* + * Formula for Write Registers 12 and 13 (`Lower Byte of Baud Rate + * Generator Time Constant' and `Upper Byte of ...'). Inputs: + * + * f BRG input clock frequency (in Hz) AFTER division + * by 1, 16, 32, or 64 (per clock divisor in WR4) + * bps desired rate in bits per second (9600, etc) + * + * We want + * + * f + * ----- + 0.5 - 2 + * 2 bps + * + * rounded down to an integer. This can be computed entirely + * in integer arithemtic as: + * + * f + bps + * ------- - 2 + * 2 bps + */ +#define BPS_TO_TCONST(f, bps) ((((f) + (bps)) / (2 * (bps))) - 2) + +/* inverse of above: given a BRG Time Constant, return Bits Per Second */ +#define TCONST_TO_BPS(f, tc) ((f) / 2 / ((tc) + 2)) + +/* + * Bits in Write Register 14 (`Miscellaneous Control Bits'). + * Bits 7 through 5 are taken as a unit and make up a `DPLL command'. + */ +#define ZSWR14_DPLL_NOOP 0x00 /* leave DPLL alone */ +#define ZSWR14_DPLL_SEARCH 0x20 /* enter search mode */ +#define ZSWR14_DPLL_RESET_CM 0x40 /* reset `clock missing' in RR10 */ +#define ZSWR14_DPLL_DISABLE 0x60 /* disable DPLL (continuous search) */ +#define ZSWR14_DPLL_SRC_BAUD 0x80 /* set DPLL src = BRG */ +#define ZSWR14_DPLL_SRC_RTXC 0xa0 /* set DPLL src = RTxC* or xtal osc */ +#define ZSWR14_DPLL_FM 0xc0 /* operate in FM mode */ +#define ZSWR14_DPLL_NRZI 0xe0 /* operate in NRZI mode */ + +#define ZSWR14_LOCAL_LOOPBACK 0x10 /* set local loopback mode */ +#define ZSWR14_AUTO_ECHO 0x08 /* set auto echo mode */ +#define ZSWR14_DTR_REQ 0x04 /* DTR* / REQ* pin gives REQ* */ +#define ZSWR14_BAUD_FROM_PCLK 0x02 /* BRG clock taken from PCLK */ + /* (else from RTxC* pin or xtal osc) */ +#define ZSWR14_BAUD_ENA 0x01 /* enable BRG countdown */ + +/* + * Bits in Write Register 15 (`External/Status Interrupt Control'). + * Most of these cause status interrupts whenever the corresponding + * bit or pin changes state (i.e., any rising or falling edge). + * + * NOTE: ZSWR15_SDLC_FIFO & ZSWR15_ENABLE_ENHANCED should not be + * set on an NMOS 8530. Also, ZSWR15_ENABLE_ENHANCED is only + * available on the 85230. + */ +#define ZSWR15_BREAK_IE 0x80 /* enable break/abort status int */ +#define ZSWR15_TXUEOM_IE 0x40 /* enable TX underrun/EOM status int */ +#define ZSWR15_CTS_IE 0x20 /* enable CTS* pin status int */ +#define ZSWR15_SYNCHUNT_IE 0x10 /* enable SYNC* pin/hunt status int */ +#define ZSWR15_DCD_IE 0x08 /* enable DCD* pin status int */ +#define ZSWR15_SDLC_FIFO 0x04 /* enable SDLC FIFO enhancements */ +#define ZSWR15_ZERO_COUNT_IE 0x02 /* enable BRG-counter = 0 status int */ +#define ZSWR15_ENABLE_ENHANCED 0x01 /* enable writing WR7' at reg 7 */ + +/* + * Bits in Read Register 0 (`Transmit/Receive Buffer Status and External + * Status'). + */ +#define ZSRR0_BREAK 0x80 /* break/abort detected */ +#define ZSRR0_TXUNDER 0x40 /* transmit underrun/EOM (sync) */ +#define ZSRR0_CTS 0x20 /* clear to send */ +#define ZSRR0_SYNC_HUNT 0x10 /* sync/hunt (sync mode) */ +#define ZSRR0_DCD 0x08 /* data carrier detect */ +#define ZSRR0_TX_READY 0x04 /* transmit buffer empty */ +#define ZSRR0_ZERO_COUNT 0x02 /* zero count in baud clock */ +#define ZSRR0_RX_READY 0x01 /* received character ready */ + +/* + * Bits in Read Register 1 (the Zilog book does not name this one). + */ +#define ZSRR1_EOF 0x80 /* end of frame (SDLC mode) */ +#define ZSRR1_FE 0x40 /* CRC/framing error */ +#define ZSRR1_DO 0x20 /* data (receiver) overrun */ +#define ZSRR1_PE 0x10 /* parity error */ +#define ZSRR1_RC0 0x08 /* residue code 0 (SDLC mode) */ +#define ZSRR1_RC1 0x04 /* residue code 1 (SDLC mode) */ +#define ZSRR1_RC2 0x02 /* residue code 2 (SDLC mode) */ +#define ZSRR1_ALL_SENT 0x01 /* all chars out of xmitter (async) */ + +/* + * Read Register 2 in B channel contains status bits if VECTOR_INCL_STAT + * is set. + */ + +/* + * Bits in Read Register 3 (`Interrupt Pending'). Only channel A + * has an RR3. + */ + /* 0x80 unused, returned as 0 */ + /* 0x40 unused, returned as 0 */ +#define ZSRR3_IP_A_RX 0x20 /* channel A recv int pending */ +#define ZSRR3_IP_A_TX 0x10 /* channel A xmit int pending */ +#define ZSRR3_IP_A_STAT 0x08 /* channel A status int pending */ +#define ZSRR3_IP_B_RX 0x04 /* channel B recv int pending */ +#define ZSRR3_IP_B_TX 0x02 /* channel B xmit int pending */ +#define ZSRR3_IP_B_STAT 0x01 /* channel B status int pending */ + +/* + * Bits in Read Register 10 (`contains some miscellaneous status bits'). + */ +#define ZSRR10_1_CLOCK_MISSING 0x80 /* 1 clock edge missing (FM mode) */ +#define ZSRR10_2_CLOCKS_MISSING 0x40 /* 2 clock edges missing (FM mode) */ + /* 0x20 unused */ +#define ZSRR10_LOOP_SENDING 0x10 /* xmitter controls loop (SDLC loop) */ + /* 0x08 unused */ + /* 0x04 unused */ +#define ZSRR10_ON_LOOP 0x02 /* SCC is on loop (SDLC/X.21 modes) */ + +/* + * Bits in Read Register 15. This register is one of the few that + * simply reads back the corresponding Write Register. + */ +#define ZSRR15_BREAK_IE 0x80 /* break/abort status int enable */ +#define ZSRR15_TXUEOM_IE 0x40 /* TX underrun/EOM status int enable */ +#define ZSRR15_CTS_IE 0x20 /* CTS* pin status int enable */ +#define ZSRR15_SYNCHUNT_IE 0x10 /* SYNC* pin/hunt status int enable */ +#define ZSRR15_DCD_IE 0x08 /* DCD* pin status int enable */ + /* 0x04 unused, returned as zero */ +#define ZSRR15_ZERO_COUNT_IE 0x02 /* BRG-counter = 0 status int enable */ + /* 0x01 unused, returned as zero */ diff --git a/sys/arch/sparc64/dev/z8530sc.c b/sys/arch/sparc64/dev/z8530sc.c new file mode 100644 index 00000000000..fa631060e13 --- /dev/null +++ b/sys/arch/sparc64/dev/z8530sc.c @@ -0,0 +1,357 @@ +/* $OpenBSD: z8530sc.c,v 1.1 2001/08/21 21:42:30 jason Exp $ */ +/* $NetBSD: z8530sc.c,v 1.15 2001/07/07 15:53:22 thorpej Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (common part) + * + * This file contains the machine-independent parts of the + * driver common to tty and keyboard/mouse sub-drivers. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <sparc64/dev/z8530reg.h> +#include <machine/z8530var.h> + +void +zs_break(cs, set) + struct zs_chanstate *cs; + int set; +{ + + if (set) { + cs->cs_preg[5] |= ZSWR5_BREAK; + cs->cs_creg[5] |= ZSWR5_BREAK; + } else { + cs->cs_preg[5] &= ~ZSWR5_BREAK; + cs->cs_creg[5] &= ~ZSWR5_BREAK; + } + zs_write_reg(cs, 5, cs->cs_creg[5]); +} + + +/* + * drain on-chip fifo + */ +void +zs_iflush(cs) + struct zs_chanstate *cs; +{ + u_char c, rr0, rr1; + int i; + + /* + * Count how many times we loop. Some systems, such as some + * Apple PowerBooks, claim to have SCC's which they really don't. + */ + for (i = 0; i < 32; i++) { + /* Is there input available? */ + rr0 = zs_read_csr(cs); + if ((rr0 & ZSRR0_RX_READY) == 0) + break; + + /* + * First read the status, because reading the data + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + } +} + + +/* + * Write the given register set to the given zs channel in the proper order. + * The channel must not be transmitting at the time. The receiver will + * be disabled for the time it takes to write all the registers. + * Call this with interrupts disabled. + */ +void +zs_loadchannelregs(cs) + struct zs_chanstate *cs; +{ + u_char *reg; + + zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */ + +#if 1 + /* + * XXX: Is this really a good idea? + * XXX: Should go elsewhere! -gwr + */ + zs_iflush(cs); /* XXX */ +#endif + + if (memcmp((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16) == 0) + return; /* only change if values are different */ + + /* Copy "pending" regs to "current" */ + memcpy((caddr_t)cs->cs_creg, (caddr_t)cs->cs_preg, 16); + reg = cs->cs_creg; /* current regs */ + + /* disable interrupts */ + zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK); + + /* baud clock divisor, stop bits, parity */ + zs_write_reg(cs, 4, reg[4]); + + /* misc. TX/RX control bits */ + zs_write_reg(cs, 10, reg[10]); + + /* char size, enable (RX/TX) */ + zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); + zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); + + /* synchronous mode stuff */ + zs_write_reg(cs, 6, reg[6]); + zs_write_reg(cs, 7, reg[7]); + +#if 0 + /* + * Registers 2 and 9 are special because they are + * actually common to both channels, but must be + * programmed through channel A. The "zsc" attach + * function takes care of setting these registers + * and they should not be touched thereafter. + */ + /* interrupt vector */ + zs_write_reg(cs, 2, reg[2]); + /* master interrupt control */ + zs_write_reg(cs, 9, reg[9]); +#endif + + /* Shut down the BRG */ + zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA); + +#ifdef ZS_MD_SETCLK + /* Let the MD code setup any external clock. */ + ZS_MD_SETCLK(cs); +#endif /* ZS_MD_SETCLK */ + + /* clock mode control */ + zs_write_reg(cs, 11, reg[11]); + + /* baud rate (lo/hi) */ + zs_write_reg(cs, 12, reg[12]); + zs_write_reg(cs, 13, reg[13]); + + /* Misc. control bits */ + zs_write_reg(cs, 14, reg[14]); + + /* which lines cause status interrupts */ + zs_write_reg(cs, 15, reg[15]); + + /* + * Zilog docs recommend resetting external status twice at this + * point. Mainly as the status bits are latched, and the first + * interrupt clear might unlatch them to new values, generating + * a second interrupt request. + */ + zs_write_csr(cs, ZSM_RESET_STINT); + zs_write_csr(cs, ZSM_RESET_STINT); + + /* char size, enable (RX/TX)*/ + zs_write_reg(cs, 3, reg[3]); + zs_write_reg(cs, 5, reg[5]); + + /* interrupt enables: RX, TX, STATUS */ + zs_write_reg(cs, 1, reg[1]); +} + + +/* + * ZS hardware interrupt. Scan all ZS channels. NB: we know here that + * channels are kept in (A,B) pairs. + * + * Do just a little, then get out; set a software interrupt if more + * work is needed. + * + * We deliberately ignore the vectoring Zilog gives us, and match up + * only the number of `reset interrupt under service' operations, not + * the order. + */ +int +zsc_intr_hard(arg) + void *arg; +{ + struct zsc_softc *zsc = arg; + struct zs_chanstate *cs; + u_char rr3; + + /* First look at channel A. */ + cs = zsc->zsc_cs[0]; + /* Note: only channel A has an RR3 */ + rr3 = zs_read_reg(cs, 3); + + /* + * Clear interrupt first to avoid a race condition. + * If a new interrupt condition happens while we are + * servicing this one, we will get another interrupt + * shortly. We can NOT just sit here in a loop, or + * we will cause horrible latency for other devices + * on this interrupt level (i.e. sun3x floppy disk). + */ + if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) { + zs_write_csr(cs, ZSWR0_CLR_INTR); + if (rr3 & ZSRR3_IP_A_RX) + (*cs->cs_ops->zsop_rxint)(cs); + if (rr3 & ZSRR3_IP_A_STAT) + (*cs->cs_ops->zsop_stint)(cs, 0); + if (rr3 & ZSRR3_IP_A_TX) + (*cs->cs_ops->zsop_txint)(cs); + } + + /* Now look at channel B. */ + cs = zsc->zsc_cs[1]; + if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) { + zs_write_csr(cs, ZSWR0_CLR_INTR); + if (rr3 & ZSRR3_IP_B_RX) + (*cs->cs_ops->zsop_rxint)(cs); + if (rr3 & ZSRR3_IP_B_STAT) + (*cs->cs_ops->zsop_stint)(cs, 0); + if (rr3 & ZSRR3_IP_B_TX) + (*cs->cs_ops->zsop_txint)(cs); + } + + /* Note: caller will check cs_x->cs_softreq and DTRT. */ + return (rr3); +} + + +/* + * ZS software interrupt. Scan all channels for deferred interrupts. + */ +int +zsc_intr_soft(arg) + void *arg; +{ + struct zsc_softc *zsc = arg; + struct zs_chanstate *cs; + int rval, chan; + + rval = 0; + for (chan = 0; chan < 2; chan++) { + cs = zsc->zsc_cs[chan]; + + /* + * The softint flag can be safely cleared once + * we have decided to call the softint routine. + * (No need to do splzs() first.) + */ + if (cs->cs_softreq) { + cs->cs_softreq = 0; + (*cs->cs_ops->zsop_softint)(cs); + rval++; + } + } + return (rval); +} + +/* + * Provide a null zs "ops" vector. + */ + +static void zsnull_rxint __P((struct zs_chanstate *)); +static void zsnull_stint __P((struct zs_chanstate *, int)); +static void zsnull_txint __P((struct zs_chanstate *)); +static void zsnull_softint __P((struct zs_chanstate *)); + +static void +zsnull_rxint(cs) + struct zs_chanstate *cs; +{ + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +static void +zsnull_stint(cs, force) + struct zs_chanstate *cs; + int force; +{ + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +static void +zsnull_txint(cs) + struct zs_chanstate *cs; +{ + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +static void +zsnull_softint(cs) + struct zs_chanstate *cs; +{ + zs_write_reg(cs, 1, 0); + zs_write_reg(cs, 15, 0); +} + +struct zsops zsops_null = { + zsnull_rxint, /* receive char available */ + zsnull_stint, /* external/status */ + zsnull_txint, /* xmit buffer empty */ + zsnull_softint, /* process software interrupt */ +}; diff --git a/sys/arch/sparc64/dev/z8530sc.h b/sys/arch/sparc64/dev/z8530sc.h new file mode 100644 index 00000000000..fe7e5f9c096 --- /dev/null +++ b/sys/arch/sparc64/dev/z8530sc.h @@ -0,0 +1,157 @@ +/* $OpenBSD: z8530sc.h,v 1.1 2001/08/21 21:42:30 jason Exp $ */ +/* $NetBSD: z8530sc.h,v 1.15 2001/05/11 01:40:48 thorpej Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + + +/* + * Function vector - per channel + */ +struct zs_chanstate; +struct zsops { + void (*zsop_rxint) __P((struct zs_chanstate *)); + /* receive char available */ + void (*zsop_stint) __P((struct zs_chanstate *, int)); + /* external/status */ + void (*zsop_txint) __P((struct zs_chanstate *)); + /* xmit buffer empty */ + void (*zsop_softint) __P((struct zs_chanstate *)); + /* process software interrupt */ +}; + +extern struct zsops zsops_null; + + +/* + * Software state, per zs channel. + */ +struct zs_chanstate { + + /* Pointers to the device registers. */ + volatile u_char *cs_reg_csr; /* ctrl, status, and reg. number. */ + volatile u_char *cs_reg_data; /* data or numbered register */ + + int cs_channel; /* sub-unit number */ + void *cs_private; /* sub-driver data pointer */ + struct zsops *cs_ops; + + int cs_brg_clk; /* BAUD Rate Generator clock + * (usually PCLK / 16) */ + int cs_defspeed; /* default baud rate */ + int cs_defcflag; /* default cflag */ + + /* + * We must keep a copy of the write registers as they are + * mostly write-only and we sometimes need to set and clear + * individual bits (e.g., in WR3). Not all of these are + * needed but 16 bytes is cheap and this makes the addressing + * simpler. Unfortunately, we can only write to some registers + * when the chip is not actually transmitting, so whenever + * we are expecting a `transmit done' interrupt the preg array + * is allowed to `get ahead' of the current values. In a + * few places we must change the current value of a register, + * rather than (or in addition to) the pending value; for these + * cs_creg[] contains the current value. + */ + u_char cs_creg[16]; /* current values */ + u_char cs_preg[16]; /* pending values */ + int cs_heldchange; /* change pending (creg != preg) */ + + u_char cs_rr0; /* last rr0 processed */ + u_char cs_rr0_delta; /* rr0 changes at status intr. */ + u_char cs_rr0_mask; /* rr0 bits that stop output */ + u_char cs_rr0_dcd; /* which bit to read as DCD */ + u_char cs_rr0_cts; /* which bit to read as CTS */ + u_char cs_rr0_pps; /* which bit to use for PPS */ + /* the above is set only while CRTSCTS is enabled. */ + + u_char cs_wr5_dtr; /* which bit to write as DTR */ + u_char cs_wr5_rts; /* which bit to write as RTS */ + /* the above is set only while CRTSCTS is enabled. */ + + char cs_softreq; /* need soft interrupt call */ + char cs_spare1; /* (for skippy :) */ + + /* power management hooks */ + int (*enable) __P((struct zs_chanstate *)); + void (*disable) __P((struct zs_chanstate *)); + int enabled; + + /* MD code might define a larger variant of this. */ +}; + +struct consdev; +struct zsc_attach_args { + int channel; /* two serial channels per zsc */ + int hwflags; /* see definitions below */ + /* `consdev' is only valid if ZS_HWFLAG_USE_CONSDEV is set */ + struct consdev *consdev; +}; +/* In case of split console devices, use these: */ +#define ZS_HWFLAG_CONSOLE_INPUT 1 +#define ZS_HWFLAG_CONSOLE_OUTPUT 2 +#define ZS_HWFLAG_CONSOLE \ + (ZS_HWFLAG_CONSOLE_INPUT | ZS_HWFLAG_CONSOLE_OUTPUT) +#define ZS_HWFLAG_NO_DCD 4 /* Ignore the DCD bit */ +#define ZS_HWFLAG_NO_CTS 8 /* Ignore the CTS bit */ +#define ZS_HWFLAG_RAW 16 /* advise raw mode */ +#define ZS_HWFLAG_USE_CONSDEV 32 /* Use console ops from `consdev' */ +#define ZS_HWFLAG_NORESET 64 /* Don't reset at attach time */ + +int zsc_intr_soft __P((void *)); +int zsc_intr_hard __P((void *)); + +void zs_abort __P((struct zs_chanstate *)); +void zs_break __P((struct zs_chanstate *, int)); +void zs_iflush __P((struct zs_chanstate *)); +void zs_loadchannelregs __P((struct zs_chanstate *)); +int zs_set_speed __P((struct zs_chanstate *, int)); +int zs_set_modes __P((struct zs_chanstate *, int)); + +extern int zs_major; + +int zs_check_kgdb __P((struct zs_chanstate *, int)); + diff --git a/sys/arch/sparc64/dev/z8530tty.c b/sys/arch/sparc64/dev/z8530tty.c new file mode 100644 index 00000000000..94d55bc017e --- /dev/null +++ b/sys/arch/sparc64/dev/z8530tty.c @@ -0,0 +1,1838 @@ +/* $OpenBSD: z8530tty.c,v 1.1 2001/08/21 21:42:30 jason Exp $ */ +/* $NetBSD: z8530tty.c,v 1.77 2001/05/30 15:24:24 lukem Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999 + * Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (tty interface) + * + * This is the "slave" driver that will be attached to + * the "zsc" driver for plain "tty" async. serial lines. + * + * Credits, history: + * + * The original version of this code was the sparc/dev/zs.c driver + * as distributed with the Berkeley 4.4 Lite release. Since then, + * Gordon Ross reorganized the code into the current parent/child + * driver scheme, separating the Sun keyboard and mouse support + * into independent child drivers. + * + * RTS/CTS flow-control support was a collaboration of: + * Gordon Ross <gwr@netbsd.org>, + * Bill Studenmund <wrstuden@loki.stanford.edu> + * Ian Dall <Ian.Dall@dsto.defence.gov.au> + * + * The driver was massively overhauled in November 1997 by Charles Hannum, + * fixing *many* bugs, and substantially improving performance. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <sparc64/dev/z8530reg.h> +#include <machine/z8530var.h> + +#include <dev/cons.h> + +/* + * How many input characters we can buffer. + * The port-specific var.h may override this. + * Note: must be a power of two! + */ +#ifndef ZSTTY_RING_SIZE +#define ZSTTY_RING_SIZE 2048 +#endif + +#if 0 +static struct cnm_state zstty_cnm_state; +#endif + +struct cfdriver zstty_cd = { + NULL, "zstty", DV_TTY +}; + +/* + * Make this an option variable one can patch. + * But be warned: this must be a power of 2! + */ +u_int zstty_rbuf_size = ZSTTY_RING_SIZE; + +/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */ +u_int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE * 1) / 4; +u_int zstty_rbuf_lowat = (ZSTTY_RING_SIZE * 3) / 4; + +#if 0 /* JLW */ +static int zsppscap = + PPS_TSFMT_TSPEC | + PPS_CAPTUREASSERT | + PPS_CAPTURECLEAR | +#ifdef PPS_SYNC + PPS_HARDPPSONASSERT | PPS_HARDPPSONCLEAR | +#endif /* PPS_SYNC */ + PPS_OFFSETASSERT | PPS_OFFSETCLEAR; +#endif + +struct zstty_softc { + struct device zst_dev; /* required first: base device */ + struct tty *zst_tty; + struct zs_chanstate *zst_cs; + + struct timeout zst_diag_ch; + + u_int zst_overflows, + zst_floods, + zst_errors; + + int zst_hwflags, /* see z8530var.h */ + zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */ + + u_int zst_r_hiwat, + zst_r_lowat; + u_char *volatile zst_rbget, + *volatile zst_rbput; + volatile u_int zst_rbavail; + u_char *zst_rbuf, + *zst_ebuf; + + /* + * The transmit byte count and address are used for pseudo-DMA + * output in the hardware interrupt code. PDMA can be suspended + * to get pending changes done; heldtbc is used for this. It can + * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state. + */ + u_char *zst_tba; /* transmit buffer address */ + u_int zst_tbc, /* transmit byte count */ + zst_heldtbc; /* held tbc while xmission stopped */ + + /* Flags to communicate with zstty_softint() */ + volatile u_char zst_rx_flags, /* receiver blocked */ +#define RX_TTY_BLOCKED 0x01 +#define RX_TTY_OVERFLOWED 0x02 +#define RX_IBUF_BLOCKED 0x04 +#define RX_IBUF_OVERFLOWED 0x08 +#define RX_ANY_BLOCK 0x0f + zst_tx_busy, /* working on an output chunk */ + zst_tx_done, /* done with one output chunk */ + zst_tx_stopped, /* H/W level stop (lost CTS) */ + zst_st_check, /* got a status interrupt */ + zst_rx_ready; + + /* PPS signal on DCD, with or without inkernel clock disciplining */ + u_char zst_ppsmask; /* pps signal mask */ + u_char zst_ppsassert; /* pps leading edge */ + u_char zst_ppsclear; /* pps trailing edge */ +#if 0 + pps_info_t ppsinfo; + pps_params_t ppsparam; +#endif +}; + +/* Macros to clear/set/test flags. */ +#define SET(t, f) (t) |= (f) +#define CLR(t, f) (t) &= ~(f) +#define ISSET(t, f) ((t) & (f)) + +/* Definition of the driver for autoconfig. */ +static int zstty_match(struct device *, void *, void *); +static void zstty_attach(struct device *, struct device *, void *); + +struct cfattach zstty_ca = { + sizeof(struct zstty_softc), zstty_match, zstty_attach +}; + +extern struct cfdriver zstty_cd; + +struct zsops zsops_tty; + +/* Routines called from other code. */ +cdev_decl(zs); /* open, close, read, write, ioctl, stop, ... */ + +static void zs_shutdown __P((struct zstty_softc *)); +static void zsstart __P((struct tty *)); +static int zsparam __P((struct tty *, struct termios *)); +static void zs_modem __P((struct zstty_softc *, int)); +static void tiocm_to_zs __P((struct zstty_softc *, u_long, int)); +static int zs_to_tiocm __P((struct zstty_softc *)); +static int zshwiflow __P((struct tty *, int)); +static void zs_hwiflow __P((struct zstty_softc *)); +static void zs_maskintr __P((struct zstty_softc *)); + +struct zstty_softc *zs_device_lookup __P((struct cfdriver *, int)); + +/* Low-level routines. */ +static void zstty_rxint __P((struct zs_chanstate *)); +static void zstty_stint __P((struct zs_chanstate *, int)); +static void zstty_txint __P((struct zs_chanstate *)); +static void zstty_softint __P((struct zs_chanstate *)); +static void zstty_diag __P((void *)); + + +#define ZSUNIT(x) (minor(x) & 0x7ffff) +#define ZSDIALOUT(x) (minor(x) & 0x80000) + +struct zstty_softc * +zs_device_lookup(cf, unit) + struct cfdriver *cf; + int unit; +{ + return (struct zstty_softc *)device_lookup(cf, unit); +} + +/* + * zstty_match: how is this zs channel configured? + */ +int +zstty_match(parent, vcf, aux) + struct device *parent; + void *vcf; + void *aux; +{ + struct cfdata *cf = vcf; + struct zsc_attach_args *args = aux; + + /* Exact match is better than wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) + return 2; + + /* This driver accepts wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) + return 1; + + return 0; +} + +void +zstty_attach(parent, self, aux) + struct device *parent, *self; + void *aux; + +{ + struct zsc_softc *zsc = (void *) parent; + struct zstty_softc *zst = (void *) self; + struct cfdata *cf = self->dv_cfdata; + struct zsc_attach_args *args = aux; + struct zs_chanstate *cs; + struct tty *tp; + int channel, s, tty_unit; + dev_t dev; + char *i, *o; + + timeout_set(&zst->zst_diag_ch, zstty_diag, zst); +#if 0 + cn_init_magic(&zstty_cnm_state); +#endif + + tty_unit = zst->zst_dev.dv_unit; + channel = args->channel; + cs = zsc->zsc_cs[channel]; + cs->cs_private = zst; + cs->cs_ops = &zsops_tty; + + zst->zst_cs = cs; + zst->zst_swflags = cf->cf_flags; /* softcar, etc. */ + zst->zst_hwflags = args->hwflags; + dev = makedev(zs_major, tty_unit); + + if (zst->zst_swflags) + printf(" flags 0x%x", zst->zst_swflags); + + /* + * Check whether we serve as a console device. + * XXX - split console input/output channels aren't + * supported yet on /dev/console + */ + i = o = NULL; + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { + i = "input"; + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + args->consdev->cn_dev = dev; + cn_tab->cn_pollc = args->consdev->cn_pollc; + cn_tab->cn_getc = args->consdev->cn_getc; + } + cn_tab->cn_dev = dev; + /* Set console magic to BREAK */ +#if 0 + cn_set_magic("\047\001"); +#endif + } + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) { + o = "output"; + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + cn_tab->cn_putc = args->consdev->cn_putc; + } + cn_tab->cn_dev = dev; + } + if (i != NULL || o != NULL) + printf(" (console %s)", i ? (o ? "i/o" : i) : o); + +#ifdef KGDB + if (zs_check_kgdb(cs, dev)) { + /* + * Allow kgdb to "take over" this port. Returns true + * if this serial port is in-use by kgdb. + */ + printf(" (kgdb)\n"); + /* + * This is the kgdb port (exclusive use) + * so skip the normal attach code. + */ + return; + } +#endif + printf("\n"); + + tp = ttymalloc(); + tp->t_dev = dev; + tp->t_oproc = zsstart; + tp->t_param = zsparam; + tp->t_hwiflow = zshwiflow; + tty_attach(tp); + + zst->zst_tty = tp; + zst->zst_rbuf = malloc(zstty_rbuf_size << 1, M_DEVBUF, M_WAITOK); + zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size << 1); + /* Disable the high water mark. */ + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zstty_rbuf_size; + + /* if there are no enable/disable functions, assume the device + is always enabled */ + if (!cs->enable) + cs->enabled = 1; + + /* + * Hardware init + */ + if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + /* Call zsparam similar to open. */ + struct termios t; + + /* Wait a while for previous console output to complete */ + DELAY(10000); + + /* Setup the "new" parameters in t. */ + t.c_ispeed = 0; + t.c_ospeed = cs->cs_defspeed; + t.c_cflag = cs->cs_defcflag; + + s = splzs(); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + + splx(s); + + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void) zsparam(tp, &t); + + s = splzs(); + + /* Make sure DTR is on now. */ + zs_modem(zst, 1); + + splx(s); + } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) { + /* Not the console; may need reset. */ + int reset; + + reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; + + s = splzs(); + + zs_write_reg(cs, 9, reset); + + /* Will raise DTR in open. */ + zs_modem(zst, 0); + + splx(s); + } +} + + +/* + * Return pointer to our tty. + */ +struct tty * +zstty(dev) + dev_t dev; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + + return (zst->zst_tty); +} + + +void +zs_shutdown(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + struct tty *tp = zst->zst_tty; + int s; + + s = splzs(); + + /* If we were asserting flow control, then deassert it. */ + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + + /* Clear any break condition set with TIOCSBRK. */ + zs_break(cs, 0); + + /* Turn off PPS capture on last close. */ + zst->zst_ppsmask = 0; +#if 0 + zst->ppsparam.mode = 0; +#endif + + /* + * Hang up if necessary. Wait a bit, so the other side has time to + * notice even if we immediately open the port again. + */ + if (ISSET(tp->t_cflag, HUPCL)) { + zs_modem(zst, 0); + (void) tsleep(cs, TTIPRI, ttclos, hz); + } + + /* Turn off interrupts if not the console. */ + if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + + /* Call the power management hook. */ + if (cs->disable) { +#ifdef DIAGNOSTIC + if (!cs->enabled) + panic("zs_shutdown: not enabled?"); +#endif + (*cs->disable)(zst->zst_cs); + } + + splx(s); +} + +/* + * Open a zs serial (tty) port. + */ +int +zsopen(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + struct tty *tp; + int s, s2; + int error; + + zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + if (zst == NULL) + return (ENXIO); + + tp = zst->zst_tty; + cs = zst->zst_cs; + + /* If KGDB took the line, then tp==NULL */ + if (tp == NULL) + return (EBUSY); + + if (ISSET(tp->t_state, TS_ISOPEN) && + ISSET(tp->t_state, TS_XCLUDE) && + p->p_ucred->cr_uid != 0) + return (EBUSY); + + s = spltty(); + + /* + * Do the following iff this is a first open. + */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + struct termios t; + + tp->t_dev = dev; + + /* Call the power management hook. */ + if (cs->enable) { + if ((*cs->enable)(cs)) { + splx(s); + printf("%s: device enable failed\n", + zst->zst_dev.dv_xname); + return (EIO); + } + } + + /* + * Initialize the termios status to the defaults. Add in the + * sticky bits from TIOCSFLAGS. + */ + t.c_ispeed = 0; + t.c_ospeed = cs->cs_defspeed; + t.c_cflag = cs->cs_defcflag; + if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL)) + SET(t.c_cflag, CLOCAL); + if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS)) + SET(t.c_cflag, CRTSCTS); +#if 0 + if (ISSET(zst->zst_swflags, TIOCFLAG_CDTRCTS)) + SET(t.c_cflag, CDTRCTS); +#endif + if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF)) + SET(t.c_cflag, MDMBUF); + + s2 = splzs(); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + + /* Clear PPS capture state on first open. */ + zst->zst_ppsmask = 0; +#if 0 + zst->ppsparam.mode = 0; +#endif + + splx(s2); + + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void) zsparam(tp, &t); + + /* + * Note: zsparam has done: cflag, ispeed, ospeed + * so we just need to do: iflag, oflag, lflag, cc + * For "raw" mode, just leave all zeros. + */ + if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + } else { + tp->t_iflag = 0; + tp->t_oflag = 0; + tp->t_lflag = 0; + } + ttychars(tp); + ttsetwater(tp); + + s2 = splzs(); + + /* + * Turn on DTR. We must always do this, even if carrier is not + * present, because otherwise we'd have to use TIOCSDTR + * immediately after setting CLOCAL, which applications do not + * expect. We always assert DTR while the device is open + * unless explicitly requested to deassert it. + */ + zs_modem(zst, 1); + + /* Clear the input ring, and unblock. */ + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zstty_rbuf_size; + zs_iflush(cs); + CLR(zst->zst_rx_flags, RX_ANY_BLOCK); + zs_hwiflow(zst); + + splx(s2); + } + + splx(s); + + error = ((*linesw[tp->t_line].l_open)(dev, tp)); + if (error) + goto bad; + + return (0); + +bad: + if (!ISSET(tp->t_state, TS_ISOPEN)) { + /* + * We failed to open the device, and nobody else had it opened. + * Clean up the state as appropriate. + */ + zs_shutdown(zst); + } + + return (error); +} + +/* + * Close a zs serial port. + */ +int +zsclose(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct tty *tp = zst->zst_tty; + + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return 0; + + (*linesw[tp->t_line].l_close)(tp, flags); + ttyclose(tp); + + if (!ISSET(tp->t_state, TS_ISOPEN)) { + /* + * Although we got a last close, the device may still be in + * use; e.g. if this was the dialout node, and there are still + * processes waiting for carrier on the non-dialout node. + */ + zs_shutdown(zst); + } + + return (0); +} + +/* + * Read/write zs serial port. + */ +int +zsread(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct tty *tp = zst->zst_tty; + + return (*linesw[tp->t_line].l_read)(tp, uio, flags); +} + +int +zswrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct tty *tp = zst->zst_tty; + + return ((*linesw[tp->t_line].l_write)(tp, uio, flags)); +} + +#if 0 +int +zspoll(dev, events, p) + dev_t dev; + int events; + struct proc *p; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct tty *tp = zst->zst_tty; + + return ((*linesw[tp->t_line].l_poll)(tp, events, p)); +} +#endif + +int +zsioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(dev)); + struct zs_chanstate *cs = zst->zst_cs; + struct tty *tp = zst->zst_tty; + int error; + int s; + + error = ((*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p)); + if (error >= 0) + return (error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return (error); + +#ifdef ZS_MD_IOCTL + error = ZS_MD_IOCTL; + if (error >= 0) + return (error); +#endif /* ZS_MD_IOCTL */ + + error = 0; + + s = splzs(); + + switch (cmd) { + case TIOCSBRK: + zs_break(cs, 1); + break; + + case TIOCCBRK: + zs_break(cs, 0); + break; + + case TIOCGFLAGS: + *(int *)data = zst->zst_swflags; + break; + + case TIOCSFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error) + break; + zst->zst_swflags = *(int *)data; + break; + + case TIOCSDTR: + zs_modem(zst, 1); + break; + + case TIOCCDTR: + zs_modem(zst, 0); + break; + + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + tiocm_to_zs(zst, cmd, *(int *)data); + break; + + case TIOCMGET: + *(int *)data = zs_to_tiocm(zst); + break; + +#if 0 /* JLW */ + case PPS_IOC_CREATE: + break; + + case PPS_IOC_DESTROY: + break; + + case PPS_IOC_GETPARAMS: { + pps_params_t *pp; + pp = (pps_params_t *)data; + *pp = zst->ppsparam; + break; + } + + case PPS_IOC_SETPARAMS: { + pps_params_t *pp; + int mode; + if (cs->cs_rr0_pps == 0) { + error = EINVAL; + break; + } + pp = (pps_params_t *)data; + if (pp->mode & ~zsppscap) { + error = EINVAL; + break; + } + zst->ppsparam = *pp; + /* + * compute masks from user-specified timestamp state. + */ + mode = zst->ppsparam.mode; +#ifdef PPS_SYNC + if (mode & PPS_HARDPPSONASSERT) { + mode |= PPS_CAPTUREASSERT; + /* XXX revoke any previous HARDPPS source */ + } + if (mode & PPS_HARDPPSONCLEAR) { + mode |= PPS_CAPTURECLEAR; + /* XXX revoke any previous HARDPPS source */ + } +#endif /* PPS_SYNC */ + switch (mode & PPS_CAPTUREBOTH) { + case 0: + zst->zst_ppsmask = 0; + break; + + case PPS_CAPTUREASSERT: + zst->zst_ppsmask = ZSRR0_DCD; + zst->zst_ppsassert = ZSRR0_DCD; + zst->zst_ppsclear = -1; + break; + + case PPS_CAPTURECLEAR: + zst->zst_ppsmask = ZSRR0_DCD; + zst->zst_ppsassert = -1; + zst->zst_ppsclear = 0; + break; + + case PPS_CAPTUREBOTH: + zst->zst_ppsmask = ZSRR0_DCD; + zst->zst_ppsassert = ZSRR0_DCD; + zst->zst_ppsclear = 0; + break; + default: + error = EINVAL; + break; + } + + /* + * Now update interrupts. + */ + zs_maskintr(zst); + /* + * If nothing is being transmitted, set up new current values, + * else mark them as pending. + */ + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } + + break; + } + + case PPS_IOC_GETCAP: + *(int *)data = zsppscap; + break; + + case PPS_IOC_FETCH: { + pps_info_t *pi; + pi = (pps_info_t *)data; + *pi = zst->ppsinfo; + break; + } + + case TIOCDCDTIMESTAMP: /* XXX old, overloaded API used by xntpd v3 */ + if (cs->cs_rr0_pps == 0) { + error = EINVAL; + break; + } + /* + * Some GPS clocks models use the falling rather than + * rising edge as the on-the-second signal. + * The old API has no way to specify PPS polarity. + */ + zst->zst_ppsmask = ZSRR0_DCD; +#ifndef PPS_TRAILING_EDGE + zst->zst_ppsassert = ZSRR0_DCD; + zst->zst_ppsclear = -1; + TIMESPEC_TO_TIMEVAL((struct timeval *)data, + &zst->ppsinfo.assert_timestamp); +#else + zst->zst_ppsassert = -1; + zst->zst_ppsclear = 01; + TIMESPEC_TO_TIMEVAL((struct timeval *)data, + &zst->ppsinfo.clear_timestamp); +#endif + /* + * Now update interrupts. + */ + zs_maskintr(zst); + /* + * If nothing is being transmitted, set up new current values, + * else mark them as pending. + */ + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } + + break; +#endif /* JLW */ + + default: + error = ENOTTY; + break; + } + + splx(s); + + return (error); +} + +/* + * Start or restart transmission. + */ +static void +zsstart(tp) + struct tty *tp; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + struct zs_chanstate *cs = zst->zst_cs; + int s; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (zst->zst_tx_stopped) + goto out; + + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup((caddr_t)&tp->t_outq); + } + selwakeup(&tp->t_wsel); + if (tp->t_outq.c_cc == 0) + goto out; + } + + /* Grab the first contiguous region of buffer space. */ + { + u_char *tba; + int tbc; + + tba = tp->t_outq.c_cf; + tbc = ndqb(&tp->t_outq, 0); + + (void) splzs(); + + zst->zst_tba = tba; + zst->zst_tbc = tbc; + } + + SET(tp->t_state, TS_BUSY); + zst->zst_tx_busy = 1; + + /* Enable transmit completion interrupts if necessary. */ + if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + SET(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + + /* Output the first character of the contiguous buffer. */ + { + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + zst->zst_tba++; + } +out: + splx(s); + return; +} + +/* + * Stop output, e.g., for ^S or output flush. + */ +int +zsstop(tp, flag) + struct tty *tp; + int flag; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + int s; + + s = splzs(); + if (ISSET(tp->t_state, TS_BUSY)) { + /* Stop transmitting at the next chunk. */ + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + } + splx(s); + return (0); +} + +/* + * Set ZS tty parameters from termios. + * XXX - Should just copy the whole termios after + * making sure all the changes could be done. + */ +static int +zsparam(tp, t) + struct tty *tp; + struct termios *t; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + struct zs_chanstate *cs = zst->zst_cs; + int ospeed, cflag; + u_char tmp3, tmp4, tmp5; + int s, error; + + ospeed = t->c_ospeed; + cflag = t->c_cflag; + + /* Check requested parameters. */ + if (ospeed < 0) + return (EINVAL); + if (t->c_ispeed && t->c_ispeed != ospeed) + return (EINVAL); + + /* + * For the console, always force CLOCAL and !HUPCL, so that the port + * is always active. + */ + if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) || + ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + SET(cflag, CLOCAL); + CLR(cflag, HUPCL); + } + + /* + * Only whack the UART when params change. + * Some callers need to clear tp->t_ospeed + * to make sure initialization gets done. + */ + if (tp->t_ospeed == ospeed && + tp->t_cflag == cflag) + return (0); + + /* + * Call MD functions to deal with changed + * clock modes or H/W flow control modes. + * The BRG divisor is set now. (reg 12,13) + */ + error = zs_set_speed(cs, ospeed); + if (error) + return (error); + error = zs_set_modes(cs, cflag); + if (error) + return (error); + + /* + * Block interrupts so that state will not + * be altered until we are done setting it up. + * + * Initial values in cs_preg are set before + * our attach routine is called. The master + * interrupt enable is handled by zsc.c + * + */ + s = splzs(); + + /* + * Recalculate which status ints to enable. + */ + zs_maskintr(zst); + + /* Recompute character size bits. */ + tmp3 = cs->cs_preg[3]; + tmp5 = cs->cs_preg[5]; + CLR(tmp3, ZSWR3_RXSIZE); + CLR(tmp5, ZSWR5_TXSIZE); + switch (ISSET(cflag, CSIZE)) { + case CS5: + SET(tmp3, ZSWR3_RX_5); + SET(tmp5, ZSWR5_TX_5); + break; + case CS6: + SET(tmp3, ZSWR3_RX_6); + SET(tmp5, ZSWR5_TX_6); + break; + case CS7: + SET(tmp3, ZSWR3_RX_7); + SET(tmp5, ZSWR5_TX_7); + break; + case CS8: + SET(tmp3, ZSWR3_RX_8); + SET(tmp5, ZSWR5_TX_8); + break; + } + cs->cs_preg[3] = tmp3; + cs->cs_preg[5] = tmp5; + + /* + * Recompute the stop bits and parity bits. Note that + * zs_set_speed() may have set clock selection bits etc. + * in wr4, so those must preserved. + */ + tmp4 = cs->cs_preg[4]; + CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK); + if (ISSET(cflag, CSTOPB)) + SET(tmp4, ZSWR4_TWOSB); + else + SET(tmp4, ZSWR4_ONESB); + if (!ISSET(cflag, PARODD)) + SET(tmp4, ZSWR4_EVENP); + if (ISSET(cflag, PARENB)) + SET(tmp4, ZSWR4_PARENB); + cs->cs_preg[4] = tmp4; + + /* And copy to tty. */ + tp->t_ispeed = 0; + tp->t_ospeed = ospeed; + tp->t_cflag = cflag; + + /* + * If nothing is being transmitted, set up new current values, + * else mark them as pending. + */ + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } + + /* + * If hardware flow control is disabled, turn off the buffer water + * marks and unblock any soft flow control state. Otherwise, enable + * the water marks. + */ + if (!ISSET(cflag, CHWFLOW)) { + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } else { + zst->zst_r_hiwat = zstty_rbuf_hiwat; + zst->zst_r_lowat = zstty_rbuf_lowat; + } + + /* + * Force a recheck of the hardware carrier and flow control status, + * since we may have changed which bits we're looking at. + */ + zstty_stint(cs, 1); + + splx(s); + + /* + * If hardware flow control is disabled, unblock any hard flow control + * state. + */ + if (!ISSET(cflag, CHWFLOW)) { + if (zst->zst_tx_stopped) { + zst->zst_tx_stopped = 0; + zsstart(tp); + } + } + + zstty_softint(cs); + + return (0); +} + +/* + * Compute interupt enable bits and set in the pending bits. Called both + * in zsparam() and when PPS (pulse per second timing) state changes. + * Must be called at splzs(). + */ +static void +zs_maskintr(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + int tmp15; + + cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd; + if (zst->zst_ppsmask != 0) + cs->cs_rr0_mask |= cs->cs_rr0_pps; + tmp15 = cs->cs_preg[15]; + if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD)) + SET(tmp15, ZSWR15_DCD_IE); + else + CLR(tmp15, ZSWR15_DCD_IE); + if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS)) + SET(tmp15, ZSWR15_CTS_IE); + else + CLR(tmp15, ZSWR15_CTS_IE); + cs->cs_preg[15] = tmp15; +} + + +/* + * Raise or lower modem control (DTR/RTS) signals. If a character is + * in transmission, the change is deferred. + */ +static void +zs_modem(zst, onoff) + struct zstty_softc *zst; + int onoff; +{ + struct zs_chanstate *cs = zst->zst_cs; + + if (cs->cs_wr5_dtr == 0) + return; + + if (onoff) + SET(cs->cs_preg[5], cs->cs_wr5_dtr); + else + CLR(cs->cs_preg[5], cs->cs_wr5_dtr); + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +static void +tiocm_to_zs(zst, how, ttybits) + struct zstty_softc *zst; + u_long how; + int ttybits; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char zsbits; + + zsbits = 0; + if (ISSET(ttybits, TIOCM_DTR)) + SET(zsbits, ZSWR5_DTR); + if (ISSET(ttybits, TIOCM_RTS)) + SET(zsbits, ZSWR5_RTS); + + switch (how) { + case TIOCMBIC: + CLR(cs->cs_preg[5], zsbits); + break; + + case TIOCMBIS: + SET(cs->cs_preg[5], zsbits); + break; + + case TIOCMSET: + CLR(cs->cs_preg[5], ZSWR5_RTS | ZSWR5_DTR); + SET(cs->cs_preg[5], zsbits); + break; + } + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +static int +zs_to_tiocm(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char zsbits; + int ttybits = 0; + + zsbits = cs->cs_preg[5]; + if (ISSET(zsbits, ZSWR5_DTR)) + SET(ttybits, TIOCM_DTR); + if (ISSET(zsbits, ZSWR5_RTS)) + SET(ttybits, TIOCM_RTS); + + zsbits = cs->cs_rr0; + if (ISSET(zsbits, ZSRR0_DCD)) + SET(ttybits, TIOCM_CD); + if (ISSET(zsbits, ZSRR0_CTS)) + SET(ttybits, TIOCM_CTS); + + return (ttybits); +} + +/* + * Try to block or unblock input using hardware flow-control. + * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and + * if this function returns non-zero, the TS_TBLOCK flag will + * be set or cleared according to the "block" arg passed. + */ +int +zshwiflow(tp, block) + struct tty *tp; + int block; +{ + struct zstty_softc *zst = zs_device_lookup(&zstty_cd, ZSUNIT(tp->t_dev)); + struct zs_chanstate *cs = zst->zst_cs; + int s; + + if (cs->cs_wr5_rts == 0) + return (0); + + s = splzs(); + if (block) { + if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + SET(zst->zst_rx_flags, RX_TTY_BLOCKED); + zs_hwiflow(zst); + } + } else { + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + return (1); +} + +/* + * Internal version of zshwiflow + * called at splzs + */ +static void +zs_hwiflow(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + + if (cs->cs_wr5_rts == 0) + return; + + if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) { + CLR(cs->cs_preg[5], cs->cs_wr5_rts); + CLR(cs->cs_creg[5], cs->cs_wr5_rts); + } else { + SET(cs->cs_preg[5], cs->cs_wr5_rts); + SET(cs->cs_creg[5], cs->cs_wr5_rts); + } + zs_write_reg(cs, 5, cs->cs_creg[5]); +} + + +/**************************************************************** + * Interface to the lower layer (zscc) + ****************************************************************/ + +#define integrate static inline +integrate void zstty_rxsoft __P((struct zstty_softc *, struct tty *)); +integrate void zstty_txsoft __P((struct zstty_softc *, struct tty *)); +integrate void zstty_stsoft __P((struct zstty_softc *, struct tty *)); +/* + * receiver ready interrupt. + * called at splzs + */ +static void +zstty_rxint(cs) + struct zs_chanstate *cs; +{ + struct zstty_softc *zst = cs->cs_private; + u_char *put, *end; + u_int cc; + u_char rr0, rr1, c; + + end = zst->zst_ebuf; + put = zst->zst_rbput; + cc = zst->zst_rbavail; + + while (cc > 0) { + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + +#if 0 + cn_check_magic(zst->zst_tty->t_dev, c, zstty_cnm_state); +#endif + put[0] = c; + put[1] = rr1; + put += 2; + if (put >= end) + put = zst->zst_rbuf; + cc--; + + rr0 = zs_read_csr(cs); + if (!ISSET(rr0, ZSRR0_RX_READY)) + break; + } + + /* + * Current string of incoming characters ended because + * no more data was available or we ran out of space. + * Schedule a receive event if any data was received. + * If we're out of space, turn off receive interrupts. + */ + zst->zst_rbput = put; + zst->zst_rbavail = cc; + if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + + /* + * See if we are in danger of overflowing a buffer. If + * so, use hardware flow control to ease the pressure. + */ + if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) && + cc < zst->zst_r_hiwat) { + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + + /* + * If we're out of space, disable receive interrupts + * until the queue has drained a bit. + */ + if (!cc) { + SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + CLR(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + +#if 0 + printf("%xH%04d\n", zst->zst_rx_flags, zst->zst_rbavail); +#endif +} + +/* + * transmitter ready interrupt. (splzs) + */ +static void +zstty_txint(cs) + struct zs_chanstate *cs; +{ + struct zstty_softc *zst = cs->cs_private; + + /* + * If we've delayed a parameter change, do it now, and restart + * output. + */ + if (cs->cs_heldchange) { + zs_loadchannelregs(cs); + cs->cs_heldchange = 0; + zst->zst_tbc = zst->zst_heldtbc; + zst->zst_heldtbc = 0; + } + + /* Output the next character in the buffer, if any. */ + if (zst->zst_tbc > 0) { + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + zst->zst_tba++; + } else { + /* Disable transmit completion interrupts if necessary. */ + if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + CLR(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (zst->zst_tx_busy) { + zst->zst_tx_busy = 0; + zst->zst_tx_done = 1; + cs->cs_softreq = 1; + } + } +} + +/* + * status change interrupt. (splzs) + */ +static void +zstty_stint(cs, force) + struct zs_chanstate *cs; + int force; +{ + struct zstty_softc *zst = cs->cs_private; + u_char rr0, delta; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); + + /* + * Check here for console break, so that we can abort + * even when interrupts are locking up the machine. + */ +#if 0 + if (ISSET(rr0, ZSRR0_BREAK)) + cn_check_magic(zst->zst_tty->t_dev, CNC_BREAK, zstty_cnm_state); +#endif + + if (!force) + delta = rr0 ^ cs->cs_rr0; + else + delta = cs->cs_rr0_mask; + cs->cs_rr0 = rr0; + + if (ISSET(delta, cs->cs_rr0_mask)) { + SET(cs->cs_rr0_delta, delta); + + /* + * Pulse-per-second clock signal on edge of DCD? + */ +#if 0 /* JLW */ + if (ISSET(delta, zst->zst_ppsmask)) { + struct timeval tv; + if (ISSET(rr0, zst->zst_ppsmask) == zst->zst_ppsassert) { + /* XXX nanotime() */ + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, + &zst->ppsinfo.assert_timestamp); + if (zst->ppsparam.mode & PPS_OFFSETASSERT) { + timespecadd(&zst->ppsinfo.assert_timestamp, + &zst->ppsparam.assert_offset, + &zst->ppsinfo.assert_timestamp); + } + +#ifdef PPS_SYNC + if (zst->ppsparam.mode & PPS_HARDPPSONASSERT) + hardpps(&tv, tv.tv_usec); +#endif + zst->ppsinfo.assert_sequence++; + zst->ppsinfo.current_mode = zst->ppsparam.mode; + } else if (ISSET(rr0, zst->zst_ppsmask) == + zst->zst_ppsclear) { + /* XXX nanotime() */ + microtime(&tv); + TIMEVAL_TO_TIMESPEC(&tv, + &zst->ppsinfo.clear_timestamp); + if (zst->ppsparam.mode & PPS_OFFSETCLEAR) { + timespecadd(&zst->ppsinfo.clear_timestamp, + &zst->ppsparam.clear_offset, + &zst->ppsinfo.clear_timestamp); + } + +#ifdef PPS_SYNC + if (zst->ppsparam.mode & PPS_HARDPPSONCLEAR) + hardpps(&tv, tv.tv_usec); +#endif + zst->ppsinfo.clear_sequence++; + zst->ppsinfo.current_mode = zst->ppsparam.mode; + } + } +#endif /* JLW */ + + /* + * Stop output immediately if we lose the output + * flow control signal or carrier detect. + */ + if (ISSET(~rr0, cs->cs_rr0_mask)) { + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + } + + zst->zst_st_check = 1; + cs->cs_softreq = 1; + } +} + +void +zstty_diag(arg) + void *arg; +{ + struct zstty_softc *zst = arg; + int overflows, floods; + int s; + + s = splzs(); + overflows = zst->zst_overflows; + zst->zst_overflows = 0; + floods = zst->zst_floods; + zst->zst_floods = 0; + zst->zst_errors = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n", + zst->zst_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +integrate void +zstty_rxsoft(zst, tp) + struct zstty_softc *zst; + struct tty *tp; +{ + struct zs_chanstate *cs = zst->zst_cs; + int (*rint) __P((int c, struct tty *tp)) = linesw[tp->t_line].l_rint; + u_char *get, *end; + u_int cc, scc; + u_char rr1; + int code; + int s; + + end = zst->zst_ebuf; + get = zst->zst_rbget; + scc = cc = zstty_rbuf_size - zst->zst_rbavail; + + if (cc == zstty_rbuf_size) { + zst->zst_floods++; + if (zst->zst_errors++ == 0) + timeout_add(&zst->zst_diag_ch, 60 * hz); + } + + /* If not yet open, drop the entire buffer content here */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + get += cc << 1; + if (get >= end) + get -= zstty_rbuf_size << 1; + cc = 0; + } + while (cc) { + code = get[0]; + rr1 = get[1]; + if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) { + if (ISSET(rr1, ZSRR1_DO)) { + zst->zst_overflows++; + if (zst->zst_errors++ == 0) + timeout_add(&zst->zst_diag_ch, 60 * hz); + } + if (ISSET(rr1, ZSRR1_FE)) + SET(code, TTY_FE); + if (ISSET(rr1, ZSRR1_PE)) + SET(code, TTY_PE); + } + if ((*rint)(code, tp) == -1) { + /* + * The line discipline's buffer is out of space. + */ + if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + /* + * We're either not using flow control, or the + * line discipline didn't tell us to block for + * some reason. Either way, we have no way to + * know when there's more space available, so + * just drop the rest of the data. + */ + get += cc << 1; + if (get >= end) + get -= zstty_rbuf_size << 1; + cc = 0; + } else { + /* + * Don't schedule any more receive processing + * until the line discipline tells us there's + * space available (through comhwiflow()). + * Leave the rest of the data in the input + * buffer. + */ + SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + } + break; + } + get += 2; + if (get >= end) + get = zst->zst_rbuf; + cc--; + } + + if (cc != scc) { + zst->zst_rbget = get; + s = splzs(); + cc = zst->zst_rbavail += scc - cc; + /* Buffers should be ok again, release possible block. */ + if (cc >= zst->zst_r_lowat) { + if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + SET(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + } + +#if 0 + printf("%xS%04d\n", zst->zst_rx_flags, zst->zst_rbavail); +#endif +} + +integrate void +zstty_txsoft(zst, tp) + struct zstty_softc *zst; + struct tty *tp; +{ + + CLR(tp->t_state, TS_BUSY); + if (ISSET(tp->t_state, TS_FLUSH)) + CLR(tp->t_state, TS_FLUSH); + else + ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf)); + (*linesw[tp->t_line].l_start)(tp); +} + +integrate void +zstty_stsoft(zst, tp) + struct zstty_softc *zst; + struct tty *tp; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char rr0, delta; + int s; + + s = splzs(); + rr0 = cs->cs_rr0; + delta = cs->cs_rr0_delta; + cs->cs_rr0_delta = 0; + splx(s); + + if (ISSET(delta, cs->cs_rr0_dcd)) { + /* + * Inform the tty layer that carrier detect changed. + */ + (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD)); + } + + if (ISSET(delta, cs->cs_rr0_cts)) { + /* Block or unblock output according to flow control. */ + if (ISSET(rr0, cs->cs_rr0_cts)) { + zst->zst_tx_stopped = 0; + (*linesw[tp->t_line].l_start)(tp); + } else { + zst->zst_tx_stopped = 1; + } + } +} + +/* + * Software interrupt. Called at zssoft + * + * The main job to be done here is to empty the input ring + * by passing its contents up to the tty layer. The ring is + * always emptied during this operation, therefore the ring + * must not be larger than the space after "high water" in + * the tty layer, or the tty layer might drop our input. + * + * Note: an "input blockage" condition is assumed to exist if + * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set. + */ +static void +zstty_softint(cs) + struct zs_chanstate *cs; +{ + struct zstty_softc *zst = cs->cs_private; + struct tty *tp = zst->zst_tty; + int s; + + s = spltty(); + + if (zst->zst_rx_ready) { + zst->zst_rx_ready = 0; + zstty_rxsoft(zst, tp); + } + + if (zst->zst_st_check) { + zst->zst_st_check = 0; + zstty_stsoft(zst, tp); + } + + if (zst->zst_tx_done) { + zst->zst_tx_done = 0; + zstty_txsoft(zst, tp); + } + + splx(s); +} + +struct zsops zsops_tty = { + zstty_rxint, /* receive char available */ + zstty_stint, /* external/status */ + zstty_txint, /* xmit buffer empty */ + zstty_softint, /* process software interrupt */ +}; diff --git a/sys/arch/sparc64/dev/zs.c b/sys/arch/sparc64/dev/zs.c index fe44727fb00..1b2277e8442 100644 --- a/sys/arch/sparc64/dev/zs.c +++ b/sys/arch/sparc64/dev/zs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: zs.c,v 1.2 2001/08/20 20:23:52 jason Exp $ */ +/* $OpenBSD: zs.c,v 1.3 2001/08/21 21:42:30 jason Exp $ */ /* $NetBSD: zs.c,v 1.29 2001/05/30 15:24:24 lukem Exp $ */ /*- @@ -67,7 +67,7 @@ #include <machine/z8530var.h> #include <dev/cons.h> -#include <dev/ic/z8530reg.h> +#include <sparc64/dev/z8530reg.h> #include <dev/sun/kbd_ms_ttyvar.h> #include <ddb/db_output.h> @@ -77,6 +77,10 @@ #include "ms.h" /* NMS */ #include "zs.h" /* NZS */ +struct cfdriver zs_cd = { + NULL, "zs", DV_TTY +}; + /* Make life easier for the initialized arrays here. */ #if NZS < 3 #undef NZS @@ -156,7 +160,7 @@ struct consdev zs_consdev = { ****************************************************************/ /* Definition of the driver for autoconfig. */ -static int zs_match_mainbus __P((struct device *, struct cfdata *, void *)); +static int zs_match_mainbus __P((struct device *, void *, void *)); static void zs_attach_mainbus __P((struct device *, struct device *, void *)); static void zs_attach __P((struct zsc_softc *, struct zsdevice *, int)); @@ -193,11 +197,12 @@ void zs_disable __P((struct zs_chanstate *)); * Is the zs chip present? */ static int -zs_match_mainbus(parent, cf, aux) +zs_match_mainbus(parent, vcf, aux) struct device *parent; - struct cfdata *cf; + void *vcf; void *aux; { + struct cfdata *cf = vcf; struct sbus_attach_args *sa = aux; if (strcmp(cf->cf_driver->cd_name, sa->sa_name) != 0) @@ -237,7 +242,7 @@ zs_attach_mainbus(parent, self, aux) */ zsaddr[zs_unit] = (struct zsdevice *) - (uintptr_t)sa->sa_promvaddrs[0]; + (unsigned long int)sa->sa_promvaddrs[0]; } else { bus_space_handle_t kvaddr; @@ -251,7 +256,7 @@ zs_attach_mainbus(parent, self, aux) return; } zsaddr[zs_unit] = (struct zsdevice *) - (uintptr_t)kvaddr; + (unsigned long int)kvaddr; } } zsc->zsc_bustag = sa->sa_bustag; @@ -290,7 +295,9 @@ zs_attach(zsc, zsd, pri) for (channel = 0; channel < 2; channel++) { struct zschan *zc; struct device *child; +#if (NKBD > 0) || (NMS > 0) extern struct cfdriver zstty_cd; /* in ioconf.c */ +#endif zsc_args.channel = channel; cs = &zsc->zsc_cs_store[channel]; @@ -407,8 +414,7 @@ zs_attach(zsc, zsd, pri) if (!(zsc->zsc_softintr = softintr_establish(softpri, zssoft, zsc))) panic("zsattach: could not establish soft interrupt\n"); - evcnt_attach_dynamic(&zsc->zsc_intrcnt, EVCNT_TYPE_INTR, NULL, - zsc->zsc_dev.dv_xname, "intr"); + evcnt_attach(&zsc->zsc_dev, "intr", &zsc->zsc_intrcnt); /* @@ -591,10 +597,12 @@ zs_set_modes(cs, cflag) cs->cs_wr5_dtr = ZSWR5_DTR; cs->cs_wr5_rts = ZSWR5_RTS; cs->cs_rr0_cts = ZSRR0_CTS; +#if 0 /* JLW */ } else if ((cflag & CDTRCTS) != 0) { cs->cs_wr5_dtr = 0; cs->cs_wr5_rts = ZSWR5_DTR; cs->cs_rr0_cts = ZSRR0_CTS; +#endif } else if ((cflag & MDMBUF) != 0) { cs->cs_wr5_dtr = 0; cs->cs_wr5_rts = ZSWR5_DTR; diff --git a/sys/arch/sparc64/include/z8530var.h b/sys/arch/sparc64/include/z8530var.h index 4399274c6c2..402212b0eb5 100644 --- a/sys/arch/sparc64/include/z8530var.h +++ b/sys/arch/sparc64/include/z8530var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: z8530var.h,v 1.2 2001/08/20 20:23:52 jason Exp $ */ +/* $OpenBSD: z8530var.h,v 1.3 2001/08/21 21:42:30 jason Exp $ */ /* $NetBSD: z8530var.h,v 1.4 2000/11/08 23:41:42 eeh Exp $ */ /* @@ -46,7 +46,7 @@ */ #include <machine/bus.h> -#include <dev/ic/z8530sc.h> +#include <sparc64/dev/z8530sc.h> /* * Need to override cn_console_dev() for zstty and zskbd. |