xref: /openbsd-src/sys/arch/sh/dev/scif.c (revision 3836e7c723d9c621d1bfafcdf2fb1c68075fdb93)
1*3836e7c7Smiod /*	$OpenBSD: scif.c,v 1.24 2024/11/05 18:58:59 miod Exp $	*/
295c7671fSmiod /*	$NetBSD: scif.c,v 1.47 2006/07/23 22:06:06 ad Exp $ */
395c7671fSmiod 
495c7671fSmiod /*-
595c7671fSmiod  * Copyright (C) 1999 T.Horiuchi and SAITOH Masanobu.  All rights reserved.
695c7671fSmiod  *
795c7671fSmiod  * Redistribution and use in source and binary forms, with or without
895c7671fSmiod  * modification, are permitted provided that the following conditions
995c7671fSmiod  * are met:
1095c7671fSmiod  * 1. Redistributions of source code must retain the above copyright
1195c7671fSmiod  *    notice, this list of conditions and the following disclaimer.
1295c7671fSmiod  * 2. Redistributions in binary form must reproduce the above copyright
1395c7671fSmiod  *    notice, this list of conditions and the following disclaimer in the
1495c7671fSmiod  *    documentation and/or other materials provided with the distribution.
1595c7671fSmiod  * 3. The name of the author may not be used to endorse or promote products
1695c7671fSmiod  *    derived from this software without specific prior written permission.
1795c7671fSmiod  *
1895c7671fSmiod  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1995c7671fSmiod  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2095c7671fSmiod  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2195c7671fSmiod  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2295c7671fSmiod  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2395c7671fSmiod  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2495c7671fSmiod  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2595c7671fSmiod  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2695c7671fSmiod  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2795c7671fSmiod  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2895c7671fSmiod  */
2995c7671fSmiod 
3095c7671fSmiod /*-
3195c7671fSmiod  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
3295c7671fSmiod  * All rights reserved.
3395c7671fSmiod  *
3495c7671fSmiod  * This code is derived from software contributed to The NetBSD Foundation
3595c7671fSmiod  * by Charles M. Hannum.
3695c7671fSmiod  *
3795c7671fSmiod  * Redistribution and use in source and binary forms, with or without
3895c7671fSmiod  * modification, are permitted provided that the following conditions
3995c7671fSmiod  * are met:
4095c7671fSmiod  * 1. Redistributions of source code must retain the above copyright
4195c7671fSmiod  *    notice, this list of conditions and the following disclaimer.
4295c7671fSmiod  * 2. Redistributions in binary form must reproduce the above copyright
4395c7671fSmiod  *    notice, this list of conditions and the following disclaimer in the
4495c7671fSmiod  *    documentation and/or other materials provided with the distribution.
4595c7671fSmiod  *
4695c7671fSmiod  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
4795c7671fSmiod  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4895c7671fSmiod  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4995c7671fSmiod  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
5095c7671fSmiod  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5195c7671fSmiod  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5295c7671fSmiod  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5395c7671fSmiod  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5495c7671fSmiod  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5595c7671fSmiod  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5695c7671fSmiod  * POSSIBILITY OF SUCH DAMAGE.
5795c7671fSmiod  */
5895c7671fSmiod 
5995c7671fSmiod /*
6095c7671fSmiod  * Copyright (c) 1991 The Regents of the University of California.
6195c7671fSmiod  * All rights reserved.
6295c7671fSmiod  *
6395c7671fSmiod  * Redistribution and use in source and binary forms, with or without
6495c7671fSmiod  * modification, are permitted provided that the following conditions
6595c7671fSmiod  * are met:
6695c7671fSmiod  * 1. Redistributions of source code must retain the above copyright
6795c7671fSmiod  *    notice, this list of conditions and the following disclaimer.
6895c7671fSmiod  * 2. Redistributions in binary form must reproduce the above copyright
6995c7671fSmiod  *    notice, this list of conditions and the following disclaimer in the
7095c7671fSmiod  *    documentation and/or other materials provided with the distribution.
7195c7671fSmiod  * 3. Neither the name of the University nor the names of its contributors
7295c7671fSmiod  *    may be used to endorse or promote products derived from this software
7395c7671fSmiod  *    without specific prior written permission.
7495c7671fSmiod  *
7595c7671fSmiod  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
7695c7671fSmiod  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7795c7671fSmiod  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7895c7671fSmiod  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
7995c7671fSmiod  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
8095c7671fSmiod  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
8195c7671fSmiod  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
8295c7671fSmiod  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
8395c7671fSmiod  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
8495c7671fSmiod  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
8595c7671fSmiod  * SUCH DAMAGE.
8695c7671fSmiod  *
8795c7671fSmiod  *	@(#)com.c	7.5 (Berkeley) 5/16/91
8895c7671fSmiod  */
8995c7671fSmiod 
9095c7671fSmiod /*
9195c7671fSmiod  * SH internal serial driver
9295c7671fSmiod  *
9395c7671fSmiod  * This code is derived from both z8530tty.c and com.c
9495c7671fSmiod  */
9595c7671fSmiod 
9695c7671fSmiod #include <sys/param.h>
9795c7671fSmiod #include <sys/systm.h>
9895c7671fSmiod #include <sys/tty.h>
9995c7671fSmiod #include <sys/proc.h>
10095c7671fSmiod #include <sys/conf.h>
10195c7671fSmiod #include <sys/syslog.h>
10295c7671fSmiod #include <sys/kernel.h>
10395c7671fSmiod #include <sys/device.h>
10495c7671fSmiod #include <sys/malloc.h>
10595c7671fSmiod #include <sys/timeout.h>
10695c7671fSmiod 
10795c7671fSmiod #include <dev/cons.h>
10895c7671fSmiod 
10995c7671fSmiod #include <sh/clock.h>
11095c7671fSmiod #include <sh/trap.h>
11195c7671fSmiod #include <machine/intr.h>
112cd4d230cSmickey #include <machine/conf.h>
11395c7671fSmiod 
11495c7671fSmiod #include <sh/dev/scifreg.h>
11595c7671fSmiod 
11695c7671fSmiod #ifdef DDB
11795c7671fSmiod #include <ddb/db_var.h>
11895c7671fSmiod #endif
11995c7671fSmiod 
12095c7671fSmiod void	scifstart(struct tty *);
12195c7671fSmiod int	scifparam(struct tty *, struct termios *);
12295c7671fSmiod 
123e5f0bf7fSmiod cons_decl(scif);
12495c7671fSmiod void scif_intr_init(void);
12595c7671fSmiod int scifintr(void *);
12695c7671fSmiod 
12795c7671fSmiod struct scif_softc {
12895c7671fSmiod 	struct device sc_dev;		/* boilerplate */
12995c7671fSmiod 	struct tty *sc_tty;
13095c7671fSmiod 	void *sc_si;
13195c7671fSmiod 
13295c7671fSmiod 	struct timeout sc_diag_tmo;
13395c7671fSmiod 
13495c7671fSmiod #if 0
13595c7671fSmiod 	bus_space_tag_t sc_iot;		/* ISA i/o space identifier */
13695c7671fSmiod 	bus_space_handle_t   sc_ioh;	/* ISA io handle */
13795c7671fSmiod 
13895c7671fSmiod 	int sc_drq;
13995c7671fSmiod 
14095c7671fSmiod 	int sc_frequency;
14195c7671fSmiod #endif
14295c7671fSmiod 
14395c7671fSmiod 	u_int sc_overflows,
14495c7671fSmiod 	      sc_floods,
14595c7671fSmiod 	      sc_errors;		/* number of retries so far */
14695c7671fSmiod 	u_char sc_status[7];		/* copy of registers */
14795c7671fSmiod 
14895c7671fSmiod 	int sc_hwflags;
14995c7671fSmiod 	int sc_swflags;
15095c7671fSmiod 	u_int sc_fifolen;
15195c7671fSmiod 
15295c7671fSmiod 	u_int sc_r_hiwat,
15395c7671fSmiod 	      sc_r_lowat;
15495c7671fSmiod 	u_char *volatile sc_rbget,
15595c7671fSmiod 	       *volatile sc_rbput;
15695c7671fSmiod  	volatile u_int sc_rbavail;
15795c7671fSmiod 	u_char *sc_rbuf,
15895c7671fSmiod 	       *sc_ebuf;
15995c7671fSmiod 
16095c7671fSmiod  	u_char *sc_tba;			/* transmit buffer address */
16195c7671fSmiod  	u_int sc_tbc,			/* transmit byte count */
16295c7671fSmiod 	      sc_heldtbc;
16395c7671fSmiod 
16495c7671fSmiod 	volatile u_char sc_rx_flags,
16595c7671fSmiod #define	RX_TTY_BLOCKED		0x01
16695c7671fSmiod #define	RX_TTY_OVERFLOWED	0x02
16795c7671fSmiod #define	RX_IBUF_BLOCKED		0x04
16895c7671fSmiod #define	RX_IBUF_OVERFLOWED	0x08
16995c7671fSmiod #define	RX_ANY_BLOCK		0x0f
17095c7671fSmiod 			sc_tx_busy,	/* working on an output chunk */
17195c7671fSmiod 			sc_tx_done,	/* done with one output chunk */
17295c7671fSmiod 			sc_tx_stopped,	/* H/W level stop (lost CTS) */
17395c7671fSmiod 			sc_st_check,	/* got a status interrupt */
17495c7671fSmiod 			sc_rx_ready;
17595c7671fSmiod 
17695c7671fSmiod 	volatile u_char sc_heldchange;
17795c7671fSmiod };
17895c7671fSmiod 
17995c7671fSmiod /* controller driver configuration */
18095c7671fSmiod int scif_match(struct device *, void *, void *);
18195c7671fSmiod void scif_attach(struct device *, struct device *, void *);
18295c7671fSmiod 
18395c7671fSmiod void	scif_break(struct scif_softc *, int);
18495c7671fSmiod void	scif_iflush(struct scif_softc *);
18595c7671fSmiod 
18695c7671fSmiod void 	scifsoft(void *);
18795c7671fSmiod void scif_rxsoft(struct scif_softc *, struct tty *);
18895c7671fSmiod void scif_txsoft(struct scif_softc *, struct tty *);
18995c7671fSmiod void scif_stsoft(struct scif_softc *, struct tty *);
19095c7671fSmiod void scif_schedrx(struct scif_softc *);
19195c7671fSmiod void	scifdiag(void *);
19295c7671fSmiod 
19395c7671fSmiod 
19495c7671fSmiod #define	SCIFUNIT_MASK		0x7ffff
19595c7671fSmiod #define	SCIFDIALOUT_MASK	0x80000
19695c7671fSmiod 
19795c7671fSmiod #define	SCIFUNIT(x)	(minor(x) & SCIFUNIT_MASK)
19895c7671fSmiod #define	SCIFDIALOUT(x)	(minor(x) & SCIFDIALOUT_MASK)
19995c7671fSmiod 
20095c7671fSmiod /* Hardware flag masks */
20195c7671fSmiod #define	SCIF_HW_NOIEN	0x01
20295c7671fSmiod #define	SCIF_HW_FIFO	0x02
20395c7671fSmiod #define	SCIF_HW_FLOW	0x08
20495c7671fSmiod #define	SCIF_HW_DEV_OK	0x20
20595c7671fSmiod #define	SCIF_HW_CONSOLE	0x40
20695c7671fSmiod 
20795c7671fSmiod /* Buffer size for character buffer */
20895c7671fSmiod #define	SCIF_RING_SIZE	2048
20995c7671fSmiod 
21095c7671fSmiod /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
21195c7671fSmiod u_int scif_rbuf_hiwat = (SCIF_RING_SIZE * 1) / 4;
21295c7671fSmiod u_int scif_rbuf_lowat = (SCIF_RING_SIZE * 3) / 4;
21395c7671fSmiod 
21495c7671fSmiod #define	CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
21595c7671fSmiod int scifconscflag = CONMODE;
21695c7671fSmiod int scifisconsole = 0;
21795c7671fSmiod 
21895c7671fSmiod #ifdef SCIFCN_SPEED
21995c7671fSmiod unsigned int scifcn_speed = SCIFCN_SPEED;
22095c7671fSmiod #else
22195c7671fSmiod unsigned int scifcn_speed = 9600;
22295c7671fSmiod #endif
22395c7671fSmiod 
22495c7671fSmiod #define	divrnd(n, q)	(((n)*2/(q)+1)/2)	/* divide and round off */
22595c7671fSmiod 
22695c7671fSmiod u_int scif_rbuf_size = SCIF_RING_SIZE;
22795c7671fSmiod 
228471aeecfSnaddy const struct cfattach scif_ca = {
22995c7671fSmiod 	sizeof(struct scif_softc), scif_match, scif_attach
23095c7671fSmiod };
23195c7671fSmiod 
23295c7671fSmiod struct cfdriver scif_cd = {
233*3836e7c7Smiod 	NULL, "scif", DV_DULL
23495c7671fSmiod };
23595c7671fSmiod 
23695c7671fSmiod static int scif_attached;
23795c7671fSmiod 
23895c7671fSmiod void InitializeScif(unsigned int);
23995c7671fSmiod 
24095c7671fSmiod /*
241b076d4fbSjsg  * following functions are for debugging purposes only
24295c7671fSmiod  */
24395c7671fSmiod #define	CR      0x0D
24495c7671fSmiod #define	USART_ON (unsigned int)~0x08
24595c7671fSmiod 
24695c7671fSmiod void scif_putc(unsigned char);
24795c7671fSmiod unsigned char scif_getc(void);
24895c7671fSmiod int ScifErrCheck(void);
24995c7671fSmiod 
25095c7671fSmiod 
25195c7671fSmiod /* XXX: uwe
25295c7671fSmiod  * Prepare for bus_spacification.  The difference in access widths is
25395c7671fSmiod  * still handled by the magic definitions in scifreg.h
25495c7671fSmiod  */
25595c7671fSmiod #define scif_smr_read()		SHREG_SCSMR2
25695c7671fSmiod #define scif_smr_write(v)	(SHREG_SCSMR2 = (v))
25795c7671fSmiod 
25895c7671fSmiod #define scif_brr_read()		SHREG_SCBRR2
25995c7671fSmiod #define scif_brr_write(v)	(SHREG_SCBRR2 = (v))
26095c7671fSmiod 
26195c7671fSmiod #define scif_scr_read()		SHREG_SCSCR2
26295c7671fSmiod #define scif_scr_write(v)	(SHREG_SCSCR2 = (v))
26395c7671fSmiod 
26495c7671fSmiod #define scif_ftdr_write(v)	(SHREG_SCFTDR2 = (v))
26595c7671fSmiod 
26695c7671fSmiod #define scif_ssr_read()		SHREG_SCSSR2
26795c7671fSmiod #define scif_ssr_write(v)	(SHREG_SCSSR2 = (v))
26895c7671fSmiod 
26995c7671fSmiod #define scif_frdr_read()	SHREG_SCFRDR2
27095c7671fSmiod 
27195c7671fSmiod #define scif_fcr_read()		SHREG_SCFCR2
27295c7671fSmiod #define scif_fcr_write(v)	(SHREG_SCFCR2 = (v))
27395c7671fSmiod 
27495c7671fSmiod #define scif_fdr_read()		SHREG_SCFDR2
27595c7671fSmiod 
27695c7671fSmiod #ifdef SH4 /* additional registers in sh4 */
27795c7671fSmiod 
27895c7671fSmiod #define scif_sptr_read()	SHREG_SCSPTR2
27995c7671fSmiod #define scif_sptr_write(v)	(SHREG_SCSPTR2 = (v))
28095c7671fSmiod 
28195c7671fSmiod #define scif_lsr_read()		SHREG_SCLSR2
28295c7671fSmiod #define scif_lsr_write(v)	(SHREG_SCLSR2 = (v))
28395c7671fSmiod 
28495c7671fSmiod #endif /* SH4 */
28595c7671fSmiod 
28695c7671fSmiod 
28795c7671fSmiod /*
28895c7671fSmiod  * InitializeScif
28995c7671fSmiod  * : unsigned int bps;
29095c7671fSmiod  * : SCIF(Serial Communication Interface)
29195c7671fSmiod  */
29295c7671fSmiod 
29395c7671fSmiod void
29495c7671fSmiod InitializeScif(unsigned int bps)
29595c7671fSmiod {
29695c7671fSmiod 	/* Initialize SCR */
29795c7671fSmiod 	scif_scr_write(0x00);
29895c7671fSmiod 
29995c7671fSmiod #if 0
30095c7671fSmiod 	scif_fcr_write(SCFCR2_TFRST | SCFCR2_RFRST | SCFCR2_MCE);
30195c7671fSmiod #else
30295c7671fSmiod 	scif_fcr_write(SCFCR2_TFRST | SCFCR2_RFRST);
30395c7671fSmiod #endif
30495c7671fSmiod 	/* Serial Mode Register */
30595c7671fSmiod 	scif_smr_write(0x00);	/* 8bit,NonParity,Even,1Stop */
30695c7671fSmiod 
30795c7671fSmiod 	/* Bit Rate Register */
30895c7671fSmiod 	scif_brr_write(divrnd(sh_clock_get_pclock(), 32 * bps) - 1);
30995c7671fSmiod 
31095c7671fSmiod 	/*
31195c7671fSmiod 	 * wait 2m Sec, because Send/Recv must begin 1 bit period after
31295c7671fSmiod 	 * BRR is set.
31395c7671fSmiod 	 */
31495c7671fSmiod 	delay(2000);
31595c7671fSmiod 
31695c7671fSmiod #if 0
31795c7671fSmiod 	scif_fcr_write(FIFO_RCV_TRIGGER_14 | FIFO_XMT_TRIGGER_1 | SCFCR2_MCE);
31895c7671fSmiod #else
31995c7671fSmiod 	scif_fcr_write(FIFO_RCV_TRIGGER_14 | FIFO_XMT_TRIGGER_1);
32095c7671fSmiod #endif
32195c7671fSmiod 
32295c7671fSmiod 	/* Send permission, Receive permission ON */
32395c7671fSmiod 	scif_scr_write(SCSCR2_TE | SCSCR2_RE);
32495c7671fSmiod 
32595c7671fSmiod 	/* Serial Status Register */
32695c7671fSmiod 	scif_ssr_write(scif_ssr_read() & SCSSR2_TDFE); /* Clear Status */
32795c7671fSmiod }
32895c7671fSmiod 
32995c7671fSmiod 
33095c7671fSmiod /*
33195c7671fSmiod  * scif_putc
33295c7671fSmiod  *  : unsigned char c;
33395c7671fSmiod  */
33495c7671fSmiod 
33595c7671fSmiod void
33695c7671fSmiod scif_putc(unsigned char c)
33795c7671fSmiod {
33895c7671fSmiod 	/* wait for ready */
33995c7671fSmiod 	while ((scif_fdr_read() & SCFDR2_TXCNT) == SCFDR2_TXF_FULL)
34095c7671fSmiod 		continue;
34195c7671fSmiod 
34295c7671fSmiod 	/* write send data to send register */
34395c7671fSmiod 	scif_ftdr_write(c);
34495c7671fSmiod 
34595c7671fSmiod 	/* clear ready flag */
34695c7671fSmiod 	scif_ssr_write(scif_ssr_read() & ~(SCSSR2_TDFE | SCSSR2_TEND));
34795c7671fSmiod }
34895c7671fSmiod 
34995c7671fSmiod /*
35095c7671fSmiod  * : ScifErrCheck
35195c7671fSmiod  *	0x80 = error
35295c7671fSmiod  *	0x08 = frame error
35395c7671fSmiod  *	0x04 = parity error
35495c7671fSmiod  */
35595c7671fSmiod int
35695c7671fSmiod ScifErrCheck(void)
35795c7671fSmiod {
35895c7671fSmiod 	return (scif_ssr_read() & (SCSSR2_ER | SCSSR2_FER | SCSSR2_PER));
35995c7671fSmiod }
36095c7671fSmiod 
36195c7671fSmiod /*
36295c7671fSmiod  * scif_getc
36395c7671fSmiod  */
36495c7671fSmiod unsigned char
36595c7671fSmiod scif_getc(void)
36695c7671fSmiod {
36795c7671fSmiod 	unsigned char c, err_c;
36895c7671fSmiod #ifdef SH4
36995c7671fSmiod 	unsigned short err_c2 = 0; /* XXXGCC: -Wuninitialized */
37095c7671fSmiod #endif
37195c7671fSmiod 
37295c7671fSmiod 	for (;;) {
37395c7671fSmiod 		/* wait for ready */
37495c7671fSmiod 		while ((scif_fdr_read() & SCFDR2_RECVCNT) == 0)
37595c7671fSmiod 			continue;
37695c7671fSmiod 
37795c7671fSmiod 		c = scif_frdr_read();
37895c7671fSmiod 		err_c = scif_ssr_read();
37995c7671fSmiod 		scif_ssr_write(scif_ssr_read()
38095c7671fSmiod 			& ~(SCSSR2_ER | SCSSR2_BRK | SCSSR2_RDF | SCSSR2_DR));
38195c7671fSmiod #ifdef SH4
38295c7671fSmiod 		if (CPU_IS_SH4) {
38395c7671fSmiod 			err_c2 = scif_lsr_read();
38495c7671fSmiod 			scif_lsr_write(scif_lsr_read() & ~SCLSR2_ORER);
38595c7671fSmiod 		}
38695c7671fSmiod #endif
38795c7671fSmiod 		if ((err_c & (SCSSR2_ER | SCSSR2_BRK | SCSSR2_FER
38895c7671fSmiod 		    | SCSSR2_PER)) == 0) {
38995c7671fSmiod #ifdef SH4
39095c7671fSmiod 			if (CPU_IS_SH4 && ((err_c2 & SCLSR2_ORER) == 0))
39195c7671fSmiod #endif
39295c7671fSmiod 			return(c);
39395c7671fSmiod 		}
39495c7671fSmiod 	}
39595c7671fSmiod 
39695c7671fSmiod }
39795c7671fSmiod 
39895c7671fSmiod int
39995c7671fSmiod scif_match(struct device *parent, void *vcf, void *aux)
40095c7671fSmiod {
40195c7671fSmiod 	if (scif_attached != 0)
40295c7671fSmiod 		return 0;
40395c7671fSmiod 
40495c7671fSmiod 	return 1;
40595c7671fSmiod }
40695c7671fSmiod 
40795c7671fSmiod void
40895c7671fSmiod scif_attach(struct device *parent, struct device *self, void *aux)
40995c7671fSmiod {
41095c7671fSmiod 	struct scif_softc *sc = (struct scif_softc *)self;
41195c7671fSmiod 	struct tty *tp;
41295c7671fSmiod 
41395c7671fSmiod 	scif_attached = 1;
41495c7671fSmiod 
41595c7671fSmiod 	sc->sc_hwflags = 0;	/* XXX */
41695c7671fSmiod 	sc->sc_swflags = 0;	/* XXX */
41795c7671fSmiod 	sc->sc_fifolen = 16;
41895c7671fSmiod 
41995c7671fSmiod 	if (scifisconsole) {
42095c7671fSmiod 		/* InitializeScif(scifcn_speed); */
42195c7671fSmiod 		SET(sc->sc_hwflags, SCIF_HW_CONSOLE);
42295c7671fSmiod 		SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
42395c7671fSmiod 		printf("\n%s: console\n", sc->sc_dev.dv_xname);
42495c7671fSmiod 	} else {
42595c7671fSmiod 		InitializeScif(9600);
42695c7671fSmiod 		printf("\n");
42795c7671fSmiod 	}
42895c7671fSmiod 
42995c7671fSmiod 	timeout_set(&sc->sc_diag_tmo, scifdiag, sc);
43095c7671fSmiod #ifdef SH4
431266ce419Sdrahn 	intc_intr_establish(SH4_INTEVT_SCIF_ERI, IST_LEVEL, IPL_TTY,
43295c7671fSmiod 	    scifintr, sc, self->dv_xname);
433266ce419Sdrahn 	intc_intr_establish(SH4_INTEVT_SCIF_RXI, IST_LEVEL, IPL_TTY,
43495c7671fSmiod 	    scifintr, sc, self->dv_xname);
435266ce419Sdrahn 	intc_intr_establish(SH4_INTEVT_SCIF_BRI, IST_LEVEL, IPL_TTY,
43695c7671fSmiod 	    scifintr, sc, self->dv_xname);
437266ce419Sdrahn 	intc_intr_establish(SH4_INTEVT_SCIF_TXI, IST_LEVEL, IPL_TTY,
43895c7671fSmiod 	    scifintr, sc, self->dv_xname);
43995c7671fSmiod #else
440266ce419Sdrahn 	intc_intr_establish(SH7709_INTEVT2_SCIF_ERI, IST_LEVEL, IPL_TTY,
44195c7671fSmiod 	    scifintr, sc, self->dv_xname);
442266ce419Sdrahn 	intc_intr_establish(SH7709_INTEVT2_SCIF_RXI, IST_LEVEL, IPL_TTY,
44395c7671fSmiod 	    scifintr, sc, self->dv_xname);
444266ce419Sdrahn 	intc_intr_establish(SH7709_INTEVT2_SCIF_BRI, IST_LEVEL, IPL_TTY,
44595c7671fSmiod 	    scifintr, sc, self->dv_xname);
446266ce419Sdrahn 	intc_intr_establish(SH7709_INTEVT2_SCIF_TXI, IST_LEVEL, IPL_TTY,
44795c7671fSmiod 	    scifintr, sc, self->dv_xname);
44895c7671fSmiod #endif
44995c7671fSmiod 
45095c7671fSmiod 	sc->sc_si = softintr_establish(IPL_SOFTSERIAL, scifsoft, sc);
45195c7671fSmiod 	SET(sc->sc_hwflags, SCIF_HW_DEV_OK);
45295c7671fSmiod 
453197ff252Sderaadt 	tp = ttymalloc(0);
45495c7671fSmiod 	tp->t_oproc = scifstart;
45595c7671fSmiod 	tp->t_param = scifparam;
45695c7671fSmiod 	tp->t_hwiflow = NULL;
45795c7671fSmiod 
45895c7671fSmiod 	sc->sc_tty = tp;
45995c7671fSmiod 	sc->sc_rbuf = malloc(scif_rbuf_size << 1, M_DEVBUF, M_NOWAIT);
46095c7671fSmiod 	if (sc->sc_rbuf == NULL) {
46195c7671fSmiod 		printf("%s: unable to allocate ring buffer\n",
46295c7671fSmiod 		    sc->sc_dev.dv_xname);
46395c7671fSmiod 		return;
46495c7671fSmiod 	}
46595c7671fSmiod 	sc->sc_ebuf = sc->sc_rbuf + (scif_rbuf_size << 1);
46695c7671fSmiod }
46795c7671fSmiod 
46895c7671fSmiod /*
46995c7671fSmiod  * Start or restart transmission.
47095c7671fSmiod  */
47195c7671fSmiod void
47295c7671fSmiod scifstart(struct tty *tp)
47395c7671fSmiod {
47495c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(tp->t_dev)];
47595c7671fSmiod 	int s;
47695c7671fSmiod 
47795c7671fSmiod 	s = spltty();
47895c7671fSmiod 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
47995c7671fSmiod 		goto out;
48095c7671fSmiod 	if (sc->sc_tx_stopped)
48195c7671fSmiod 		goto out;
48295c7671fSmiod 
4834cc8800eSnicm 	ttwakeupwr(tp);
48495c7671fSmiod 	if (tp->t_outq.c_cc == 0)
48595c7671fSmiod 		goto out;
48695c7671fSmiod 
48795c7671fSmiod 	/* Grab the first contiguous region of buffer space. */
48895c7671fSmiod 	{
48995c7671fSmiod 		u_char *tba;
49095c7671fSmiod 		int tbc;
49195c7671fSmiod 
49295c7671fSmiod 		tba = tp->t_outq.c_cf;
49395c7671fSmiod 		tbc = ndqb(&tp->t_outq, 0);
49495c7671fSmiod 
49595c7671fSmiod 
49695c7671fSmiod 		sc->sc_tba = tba;
49795c7671fSmiod 		sc->sc_tbc = tbc;
49895c7671fSmiod 	}
49995c7671fSmiod 
50095c7671fSmiod 	SET(tp->t_state, TS_BUSY);
50195c7671fSmiod 	sc->sc_tx_busy = 1;
50295c7671fSmiod 
50395c7671fSmiod 	/* Enable transmit completion interrupts if necessary. */
50495c7671fSmiod 	scif_scr_write(scif_scr_read() | SCSCR2_TIE | SCSCR2_RIE);
50595c7671fSmiod 
50695c7671fSmiod 	/* Output the first chunk of the contiguous buffer. */
50795c7671fSmiod 	{
50895c7671fSmiod 		int n;
50995c7671fSmiod 		int maxchars;
51095c7671fSmiod 		int i;
51195c7671fSmiod 
51295c7671fSmiod 		n = sc->sc_tbc;
51395c7671fSmiod 		maxchars = sc->sc_fifolen
51495c7671fSmiod 			- ((scif_fdr_read() & SCFDR2_TXCNT) >> 8);
51595c7671fSmiod 		if (n > maxchars)
51695c7671fSmiod 			n = maxchars;
51795c7671fSmiod 
51895c7671fSmiod 		for (i = 0; i < n; i++) {
51995c7671fSmiod 			scif_putc(*(sc->sc_tba));
52095c7671fSmiod 			sc->sc_tba++;
52195c7671fSmiod 		}
52295c7671fSmiod 		sc->sc_tbc -= n;
52395c7671fSmiod 	}
52495c7671fSmiod out:
52595c7671fSmiod 	splx(s);
52695c7671fSmiod 	return;
52795c7671fSmiod }
52895c7671fSmiod 
52995c7671fSmiod /*
53095c7671fSmiod  * Set SCIF tty parameters from termios.
53195c7671fSmiod  * XXX - Should just copy the whole termios after
53295c7671fSmiod  * making sure all the changes could be done.
53395c7671fSmiod  */
53495c7671fSmiod int
53595c7671fSmiod scifparam(struct tty *tp, struct termios *t)
53695c7671fSmiod {
53795c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(tp->t_dev)];
53895c7671fSmiod 	int ospeed = t->c_ospeed;
53995c7671fSmiod 	int s;
54095c7671fSmiod 
54195c7671fSmiod 	/* Check requested parameters. */
54295c7671fSmiod 	if (ospeed < 0)
54395c7671fSmiod 		return (EINVAL);
54495c7671fSmiod 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
54595c7671fSmiod 		return (EINVAL);
54695c7671fSmiod 
54795c7671fSmiod 	/*
54895c7671fSmiod 	 * For the console, always force CLOCAL and !HUPCL, so that the port
54995c7671fSmiod 	 * is always active.
55095c7671fSmiod 	 */
55195c7671fSmiod 	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
55295c7671fSmiod 	    ISSET(sc->sc_hwflags, SCIF_HW_CONSOLE)) {
55395c7671fSmiod 		SET(t->c_cflag, CLOCAL);
55495c7671fSmiod 		CLR(t->c_cflag, HUPCL);
55595c7671fSmiod 	}
55695c7671fSmiod 
55795c7671fSmiod 	/*
55895c7671fSmiod 	 * If there were no changes, don't do anything.  This avoids dropping
55995c7671fSmiod 	 * input and improves performance when all we did was frob things like
56095c7671fSmiod 	 * VMIN and VTIME.
56195c7671fSmiod 	 */
56295c7671fSmiod 	if (tp->t_ospeed == t->c_ospeed &&
56395c7671fSmiod 	    tp->t_cflag == t->c_cflag)
56495c7671fSmiod 		return (0);
56595c7671fSmiod 
56695c7671fSmiod #if 0
56795c7671fSmiod /* XXX (msaitoh) */
56895c7671fSmiod 	lcr = ISSET(sc->sc_lcr, LCR_SBREAK) | cflag2lcr(t->c_cflag);
56995c7671fSmiod #endif
57095c7671fSmiod 
571266ce419Sdrahn 	s = spltty();
57295c7671fSmiod 
57395c7671fSmiod 	/*
57495c7671fSmiod 	 * Set the flow control pins depending on the current flow control
57595c7671fSmiod 	 * mode.
57695c7671fSmiod 	 */
57795c7671fSmiod 	if (ISSET(t->c_cflag, CRTSCTS)) {
57895c7671fSmiod 		scif_fcr_write(scif_fcr_read() | SCFCR2_MCE);
57995c7671fSmiod 	} else {
58095c7671fSmiod 		scif_fcr_write(scif_fcr_read() & ~SCFCR2_MCE);
58195c7671fSmiod 	}
58295c7671fSmiod 
58395c7671fSmiod 	scif_brr_write(divrnd(sh_clock_get_pclock(), 32 * ospeed) -1);
58495c7671fSmiod 
58595c7671fSmiod 	/*
58695c7671fSmiod 	 * Set the FIFO threshold based on the receive speed.
58795c7671fSmiod 	 *
58895c7671fSmiod 	 *  * If it's a low speed, it's probably a mouse or some other
58995c7671fSmiod 	 *    interactive device, so set the threshold low.
59095c7671fSmiod 	 *  * If it's a high speed, trim the trigger level down to prevent
59195c7671fSmiod 	 *    overflows.
59295c7671fSmiod 	 *  * Otherwise set it a bit higher.
59395c7671fSmiod 	 */
59495c7671fSmiod #if 0
59595c7671fSmiod /* XXX (msaitoh) */
59695c7671fSmiod 	if (ISSET(sc->sc_hwflags, SCIF_HW_HAYESP))
59795c7671fSmiod 		sc->sc_fifo = FIFO_DMA_MODE | FIFO_ENABLE | FIFO_TRIGGER_8;
59895c7671fSmiod 	else if (ISSET(sc->sc_hwflags, SCIF_HW_FIFO))
59995c7671fSmiod 		sc->sc_fifo = FIFO_ENABLE |
60095c7671fSmiod 		    (t->c_ospeed <= 1200 ? FIFO_TRIGGER_1 :
60195c7671fSmiod 		     t->c_ospeed <= 38400 ? FIFO_TRIGGER_8 : FIFO_TRIGGER_4);
60295c7671fSmiod 	else
60395c7671fSmiod 		sc->sc_fifo = 0;
60495c7671fSmiod #endif
60595c7671fSmiod 
60695c7671fSmiod 	/* And copy to tty. */
60795c7671fSmiod 	tp->t_ispeed = 0;
60895c7671fSmiod 	tp->t_ospeed = t->c_ospeed;
60995c7671fSmiod 	tp->t_cflag = t->c_cflag;
61095c7671fSmiod 
61195c7671fSmiod 	if (!sc->sc_heldchange) {
61295c7671fSmiod 		if (sc->sc_tx_busy) {
61395c7671fSmiod 			sc->sc_heldtbc = sc->sc_tbc;
61495c7671fSmiod 			sc->sc_tbc = 0;
61595c7671fSmiod 			sc->sc_heldchange = 1;
61695c7671fSmiod 		}
61795c7671fSmiod #if 0
61895c7671fSmiod /* XXX (msaitoh) */
61995c7671fSmiod 		else
62095c7671fSmiod 			scif_loadchannelregs(sc);
62195c7671fSmiod #endif
62295c7671fSmiod 	}
62395c7671fSmiod 
62495c7671fSmiod 	if (!ISSET(t->c_cflag, CHWFLOW)) {
62595c7671fSmiod 		/* Disable the high water mark. */
62695c7671fSmiod 		sc->sc_r_hiwat = 0;
62795c7671fSmiod 		sc->sc_r_lowat = 0;
62895c7671fSmiod 		if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
62995c7671fSmiod 			CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
63095c7671fSmiod 			scif_schedrx(sc);
63195c7671fSmiod 		}
63295c7671fSmiod 	} else {
63395c7671fSmiod 		sc->sc_r_hiwat = scif_rbuf_hiwat;
63495c7671fSmiod 		sc->sc_r_lowat = scif_rbuf_lowat;
63595c7671fSmiod 	}
63695c7671fSmiod 
63795c7671fSmiod 	splx(s);
63895c7671fSmiod 
63995c7671fSmiod #ifdef SCIF_DEBUG
64095c7671fSmiod 	if (scif_debug)
64195c7671fSmiod 		scifstatus(sc, "scifparam ");
64295c7671fSmiod #endif
64395c7671fSmiod 
64495c7671fSmiod 	if (!ISSET(t->c_cflag, CHWFLOW)) {
64595c7671fSmiod 		if (sc->sc_tx_stopped) {
64695c7671fSmiod 			sc->sc_tx_stopped = 0;
64795c7671fSmiod 			scifstart(tp);
64895c7671fSmiod 		}
64995c7671fSmiod 	}
65095c7671fSmiod 
65195c7671fSmiod 	return (0);
65295c7671fSmiod }
65395c7671fSmiod 
65495c7671fSmiod void
65595c7671fSmiod scif_iflush(struct scif_softc *sc)
65695c7671fSmiod {
65795c7671fSmiod 	int i;
65895c7671fSmiod 	unsigned char c;
65995c7671fSmiod 
66095c7671fSmiod 	i = scif_fdr_read() & SCFDR2_RECVCNT;
66195c7671fSmiod 
66295c7671fSmiod 	while (i > 0) {
66395c7671fSmiod 		c = scif_frdr_read();
66495c7671fSmiod 		scif_ssr_write(scif_ssr_read() & ~(SCSSR2_RDF | SCSSR2_DR));
66595c7671fSmiod 		i--;
66695c7671fSmiod 	}
66795c7671fSmiod }
66895c7671fSmiod 
66995c7671fSmiod int
67095c7671fSmiod scifopen(dev_t dev, int flag, int mode, struct proc *p)
67195c7671fSmiod {
67295c7671fSmiod 	int unit = SCIFUNIT(dev);
67395c7671fSmiod 	struct scif_softc *sc;
67495c7671fSmiod 	struct tty *tp;
675266ce419Sdrahn 	int s;
67695c7671fSmiod 	int error;
67795c7671fSmiod 
67895c7671fSmiod 	if (unit >= scif_cd.cd_ndevs)
67995c7671fSmiod 		return (ENXIO);
68095c7671fSmiod 	sc = scif_cd.cd_devs[unit];
68195c7671fSmiod 	if (sc == 0 || !ISSET(sc->sc_hwflags, SCIF_HW_DEV_OK) ||
68295c7671fSmiod 	    sc->sc_rbuf == NULL)
68395c7671fSmiod 		return (ENXIO);
68495c7671fSmiod 
68595c7671fSmiod 	tp = sc->sc_tty;
68695c7671fSmiod 
68795c7671fSmiod 	if (ISSET(tp->t_state, TS_ISOPEN) &&
68895c7671fSmiod 	    ISSET(tp->t_state, TS_XCLUDE) &&
6893e676399Smpi 	    suser(p) != 0)
69095c7671fSmiod 		return (EBUSY);
69195c7671fSmiod 
69295c7671fSmiod 	s = spltty();
69395c7671fSmiod 
69495c7671fSmiod 	/*
69595c7671fSmiod 	 * Do the following iff this is a first open.
69695c7671fSmiod 	 */
69795c7671fSmiod 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
69895c7671fSmiod 		struct termios t;
69995c7671fSmiod 
70095c7671fSmiod 		tp->t_dev = dev;
70195c7671fSmiod 
70295c7671fSmiod 
70395c7671fSmiod 		/* Turn on interrupts. */
70495c7671fSmiod 		scif_scr_write(scif_scr_read() | SCSCR2_TIE | SCSCR2_RIE);
70595c7671fSmiod 
70695c7671fSmiod 		/*
70795c7671fSmiod 		 * Initialize the termios status to the defaults.  Add in the
70895c7671fSmiod 		 * sticky bits from TIOCSFLAGS.
70995c7671fSmiod 		 */
71095c7671fSmiod 		t.c_ispeed = 0;
71195c7671fSmiod 		if (ISSET(sc->sc_hwflags, SCIF_HW_CONSOLE)) {
71295c7671fSmiod 			t.c_ospeed = scifcn_speed;	/* XXX (msaitoh) */
71395c7671fSmiod 			t.c_cflag = scifconscflag;
71495c7671fSmiod 		} else {
71595c7671fSmiod 			t.c_ospeed = TTYDEF_SPEED;
71695c7671fSmiod 			t.c_cflag = TTYDEF_CFLAG;
71795c7671fSmiod 		}
71895c7671fSmiod 		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
71995c7671fSmiod 			SET(t.c_cflag, CLOCAL);
72095c7671fSmiod 		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
72195c7671fSmiod 			SET(t.c_cflag, CRTSCTS);
72295c7671fSmiod 		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
72395c7671fSmiod 			SET(t.c_cflag, MDMBUF);
72495c7671fSmiod 		/* Make sure scifparam() will do something. */
72595c7671fSmiod 		tp->t_ospeed = 0;
72695c7671fSmiod 		(void) scifparam(tp, &t);
72716da585eSderaadt 
72816da585eSderaadt 		/*
72916da585eSderaadt 		 * XXX landisk has no hardware flow control!
73016da585eSderaadt 		 * When porting to another platform, fix this somehow
73116da585eSderaadt 		 */
73216da585eSderaadt 		SET(tp->t_state, TS_CARR_ON);
73316da585eSderaadt 
73495c7671fSmiod 		tp->t_iflag = TTYDEF_IFLAG;
73595c7671fSmiod 		tp->t_oflag = TTYDEF_OFLAG;
73695c7671fSmiod 		tp->t_lflag = TTYDEF_LFLAG;
73795c7671fSmiod 		ttychars(tp);
73895c7671fSmiod 		ttsetwater(tp);
73995c7671fSmiod 
74095c7671fSmiod 		/* Clear the input ring, and unblock. */
74195c7671fSmiod 		sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
74295c7671fSmiod 		sc->sc_rbavail = scif_rbuf_size;
74395c7671fSmiod 		scif_iflush(sc);
74495c7671fSmiod 		CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
74595c7671fSmiod #if 0
74695c7671fSmiod /* XXX (msaitoh) */
74795c7671fSmiod 		scif_hwiflow(sc);
74895c7671fSmiod #endif
74995c7671fSmiod 
75095c7671fSmiod #ifdef SCIF_DEBUG
75195c7671fSmiod 		if (scif_debug)
75295c7671fSmiod 			scifstatus(sc, "scifopen  ");
75395c7671fSmiod #endif
75495c7671fSmiod 
75595c7671fSmiod 	}
75695c7671fSmiod 
75795c7671fSmiod 	splx(s);
75895c7671fSmiod 
75979f6c33aStedu 	error = (*linesw[tp->t_line].l_open)(dev, tp, p);
76095c7671fSmiod 	if (error)
76195c7671fSmiod 		goto bad;
76295c7671fSmiod 
76395c7671fSmiod 	return (0);
76495c7671fSmiod 
76595c7671fSmiod bad:
76695c7671fSmiod 
76795c7671fSmiod 	return (error);
76895c7671fSmiod }
76995c7671fSmiod 
77095c7671fSmiod int
77195c7671fSmiod scifclose(dev_t dev, int flag, int mode, struct proc *p)
77295c7671fSmiod {
77395c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)];
77495c7671fSmiod 	struct tty *tp = sc->sc_tty;
77595c7671fSmiod 
77695c7671fSmiod 	/* XXX This is for cons.c. */
77795c7671fSmiod 	if (!ISSET(tp->t_state, TS_ISOPEN))
77895c7671fSmiod 		return (0);
77995c7671fSmiod 
78079f6c33aStedu 	(*linesw[tp->t_line].l_close)(tp, flag, p);
78195c7671fSmiod 	ttyclose(tp);
78295c7671fSmiod 
78395c7671fSmiod 	return (0);
78495c7671fSmiod }
78595c7671fSmiod 
78695c7671fSmiod int
78795c7671fSmiod scifread(dev_t dev, struct uio *uio, int flag)
78895c7671fSmiod {
78995c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)];
79095c7671fSmiod 	struct tty *tp = sc->sc_tty;
79195c7671fSmiod 
79295c7671fSmiod 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
79395c7671fSmiod }
79495c7671fSmiod 
79595c7671fSmiod int
79695c7671fSmiod scifwrite(dev_t dev, struct uio *uio, int flag)
79795c7671fSmiod {
79895c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)];
79995c7671fSmiod 	struct tty *tp = sc->sc_tty;
80095c7671fSmiod 
80195c7671fSmiod 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
80295c7671fSmiod }
80395c7671fSmiod 
80495c7671fSmiod struct tty *
80595c7671fSmiod sciftty(dev_t dev)
80695c7671fSmiod {
80795c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)];
80895c7671fSmiod 	struct tty *tp = sc->sc_tty;
80995c7671fSmiod 
81095c7671fSmiod 	return (tp);
81195c7671fSmiod }
81295c7671fSmiod 
81395c7671fSmiod int
81495c7671fSmiod scifioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
81595c7671fSmiod {
81695c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(dev)];
81795c7671fSmiod 	struct tty *tp = sc->sc_tty;
81895c7671fSmiod 	int error;
81995c7671fSmiod 	int s;
82095c7671fSmiod 
82195c7671fSmiod 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
82295c7671fSmiod 	if (error != -1)
82395c7671fSmiod 		return (error);
82495c7671fSmiod 
82595c7671fSmiod 	error = ttioctl(tp, cmd, data, flag, p);
82695c7671fSmiod 	if (error != -1)
82795c7671fSmiod 		return (error);
82895c7671fSmiod 
82995c7671fSmiod 	error = 0;
83095c7671fSmiod 
831266ce419Sdrahn 	s = spltty();
83295c7671fSmiod 
83395c7671fSmiod 	switch (cmd) {
83495c7671fSmiod 	case TIOCSBRK:
83595c7671fSmiod 		scif_break(sc, 1);
83695c7671fSmiod 		break;
83795c7671fSmiod 
83895c7671fSmiod 	case TIOCCBRK:
83995c7671fSmiod 		scif_break(sc, 0);
84095c7671fSmiod 		break;
84195c7671fSmiod 
84295c7671fSmiod 	case TIOCGFLAGS:
84395c7671fSmiod 		*(int *)data = sc->sc_swflags;
84495c7671fSmiod 		break;
84595c7671fSmiod 
84695c7671fSmiod 	case TIOCSFLAGS:
8473e676399Smpi 		error = suser(p);
84895c7671fSmiod 		if (error)
84995c7671fSmiod 			break;
85095c7671fSmiod 		sc->sc_swflags = *(int *)data;
85195c7671fSmiod 		break;
85295c7671fSmiod 
85395c7671fSmiod 	default:
85495c7671fSmiod 		error = -1;
85595c7671fSmiod 		break;
85695c7671fSmiod 	}
85795c7671fSmiod 
85895c7671fSmiod 	splx(s);
85995c7671fSmiod 
86095c7671fSmiod 	return (error);
86195c7671fSmiod }
86295c7671fSmiod 
86395c7671fSmiod void
86495c7671fSmiod scif_schedrx(struct scif_softc *sc)
86595c7671fSmiod {
86695c7671fSmiod 	sc->sc_rx_ready = 1;
86795c7671fSmiod 
86895c7671fSmiod 	/* Wake up the poller. */
86995c7671fSmiod 	softintr_schedule(sc->sc_si);
87095c7671fSmiod }
87195c7671fSmiod 
87295c7671fSmiod void
87395c7671fSmiod scif_break(struct scif_softc *sc, int onoff)
87495c7671fSmiod {
87595c7671fSmiod 	if (onoff)
87695c7671fSmiod 		scif_ssr_write(scif_ssr_read() & ~SCSSR2_TDFE);
87795c7671fSmiod 	else
87895c7671fSmiod 		scif_ssr_write(scif_ssr_read() | SCSSR2_TDFE);
87995c7671fSmiod 
88095c7671fSmiod #if 0	/* XXX */
88195c7671fSmiod 	if (!sc->sc_heldchange) {
88295c7671fSmiod 		if (sc->sc_tx_busy) {
88395c7671fSmiod 			sc->sc_heldtbc = sc->sc_tbc;
88495c7671fSmiod 			sc->sc_tbc = 0;
88595c7671fSmiod 			sc->sc_heldchange = 1;
88695c7671fSmiod 		} else
88795c7671fSmiod 			scif_loadchannelregs(sc);
88895c7671fSmiod 	}
88995c7671fSmiod #endif
89095c7671fSmiod }
89195c7671fSmiod 
89295c7671fSmiod /*
89395c7671fSmiod  * Stop output, e.g., for ^S or output flush.
89495c7671fSmiod  */
89595c7671fSmiod int
89695c7671fSmiod scifstop(struct tty *tp, int flag)
89795c7671fSmiod {
89895c7671fSmiod 	struct scif_softc *sc = scif_cd.cd_devs[SCIFUNIT(tp->t_dev)];
89995c7671fSmiod 	int s;
90095c7671fSmiod 
901266ce419Sdrahn 	s = spltty();
90295c7671fSmiod 	if (ISSET(tp->t_state, TS_BUSY)) {
90395c7671fSmiod 		/* Stop transmitting at the next chunk. */
90495c7671fSmiod 		sc->sc_tbc = 0;
90595c7671fSmiod 		sc->sc_heldtbc = 0;
90695c7671fSmiod 		if (!ISSET(tp->t_state, TS_TTSTOP))
90795c7671fSmiod 			SET(tp->t_state, TS_FLUSH);
90895c7671fSmiod 	}
90995c7671fSmiod 	splx(s);
91095c7671fSmiod 	return (0);
91195c7671fSmiod }
91295c7671fSmiod 
91395c7671fSmiod void
9140f1d1626Stobiasu scif_intr_init(void)
91595c7671fSmiod {
91695c7671fSmiod 	/* XXX */
91795c7671fSmiod }
91895c7671fSmiod 
91995c7671fSmiod void
92095c7671fSmiod scifdiag(void *arg)
92195c7671fSmiod {
92295c7671fSmiod 	struct scif_softc *sc = arg;
92395c7671fSmiod 	int overflows, floods;
92495c7671fSmiod 	int s;
92595c7671fSmiod 
926266ce419Sdrahn 	s = spltty();
92795c7671fSmiod 	overflows = sc->sc_overflows;
92895c7671fSmiod 	sc->sc_overflows = 0;
92995c7671fSmiod 	floods = sc->sc_floods;
93095c7671fSmiod 	sc->sc_floods = 0;
93195c7671fSmiod 	sc->sc_errors = 0;
93295c7671fSmiod 	splx(s);
93395c7671fSmiod 
93495c7671fSmiod 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
93595c7671fSmiod 	    sc->sc_dev.dv_xname,
93695c7671fSmiod 	    overflows, overflows == 1 ? "" : "s",
93795c7671fSmiod 	    floods, floods == 1 ? "" : "s");
93895c7671fSmiod }
93995c7671fSmiod 
94095c7671fSmiod void
94195c7671fSmiod scif_rxsoft(struct scif_softc *sc, struct tty *tp)
94295c7671fSmiod {
94395c7671fSmiod 	int (*rint)(int, struct tty *) = *linesw[tp->t_line].l_rint;
94495c7671fSmiod 	u_char *get, *end;
94595c7671fSmiod 	u_int cc, scc;
94695c7671fSmiod 	u_char ssr2;
94795c7671fSmiod 	int code;
94895c7671fSmiod 	int s;
94995c7671fSmiod 
95095c7671fSmiod 	end = sc->sc_ebuf;
95195c7671fSmiod 	get = sc->sc_rbget;
95295c7671fSmiod 	scc = cc = scif_rbuf_size - sc->sc_rbavail;
95395c7671fSmiod 
95495c7671fSmiod 	if (cc == scif_rbuf_size) {
95595c7671fSmiod 		sc->sc_floods++;
95695c7671fSmiod 		if (sc->sc_errors++ == 0)
95729e86e5eSblambert 			timeout_add_sec(&sc->sc_diag_tmo, 60);
95895c7671fSmiod 	}
95995c7671fSmiod 
96095c7671fSmiod 	while (cc) {
96195c7671fSmiod 		code = get[0];
96295c7671fSmiod 		ssr2 = get[1];
96395c7671fSmiod 		if (ISSET(ssr2, SCSSR2_BRK | SCSSR2_FER | SCSSR2_PER)) {
96495c7671fSmiod 			if (ISSET(ssr2, SCSSR2_BRK | SCSSR2_FER))
96595c7671fSmiod 				SET(code, TTY_FE);
96695c7671fSmiod 			if (ISSET(ssr2, SCSSR2_PER))
96795c7671fSmiod 				SET(code, TTY_PE);
96895c7671fSmiod 		}
96995c7671fSmiod 		if ((*rint)(code, tp) == -1) {
97095c7671fSmiod 			/*
97195c7671fSmiod 			 * The line discipline's buffer is out of space.
97295c7671fSmiod 			 */
97395c7671fSmiod 			if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
97495c7671fSmiod 				/*
97595c7671fSmiod 				 * We're either not using flow control, or the
97695c7671fSmiod 				 * line discipline didn't tell us to block for
97795c7671fSmiod 				 * some reason.  Either way, we have no way to
97895c7671fSmiod 				 * know when there's more space available, so
97995c7671fSmiod 				 * just drop the rest of the data.
98095c7671fSmiod 				 */
98195c7671fSmiod 				get += cc << 1;
98295c7671fSmiod 				if (get >= end)
98395c7671fSmiod 					get -= scif_rbuf_size << 1;
98495c7671fSmiod 				cc = 0;
98595c7671fSmiod 			} else {
98695c7671fSmiod 				/*
98795c7671fSmiod 				 * Don't schedule any more receive processing
98895c7671fSmiod 				 * until the line discipline tells us there's
98995c7671fSmiod 				 * space available (through scifhwiflow()).
99095c7671fSmiod 				 * Leave the rest of the data in the input
99195c7671fSmiod 				 * buffer.
99295c7671fSmiod 				 */
99395c7671fSmiod 				SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
99495c7671fSmiod 			}
99595c7671fSmiod 			break;
99695c7671fSmiod 		}
99795c7671fSmiod 		get += 2;
99895c7671fSmiod 		if (get >= end)
99995c7671fSmiod 			get = sc->sc_rbuf;
100095c7671fSmiod 		cc--;
100195c7671fSmiod 	}
100295c7671fSmiod 
100395c7671fSmiod 	if (cc != scc) {
100495c7671fSmiod 		sc->sc_rbget = get;
1005266ce419Sdrahn 		s = spltty();
100695c7671fSmiod 		cc = sc->sc_rbavail += scc - cc;
100795c7671fSmiod 		/* Buffers should be ok again, release possible block. */
100895c7671fSmiod 		if (cc >= sc->sc_r_lowat) {
100995c7671fSmiod 			if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
101095c7671fSmiod 				CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
101195c7671fSmiod 				scif_scr_write(scif_scr_read() | SCSCR2_RIE);
101295c7671fSmiod 			}
101395c7671fSmiod #if 0
101495c7671fSmiod 			if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
101595c7671fSmiod 				CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
101695c7671fSmiod 				scif_hwiflow(sc);
101795c7671fSmiod 			}
101895c7671fSmiod #endif
101995c7671fSmiod 		}
102095c7671fSmiod 		splx(s);
102195c7671fSmiod 	}
102295c7671fSmiod }
102395c7671fSmiod 
102495c7671fSmiod void
102595c7671fSmiod scif_txsoft(struct scif_softc *sc, struct tty *tp)
102695c7671fSmiod {
102795c7671fSmiod 	CLR(tp->t_state, TS_BUSY);
102895c7671fSmiod 	if (ISSET(tp->t_state, TS_FLUSH))
102995c7671fSmiod 		CLR(tp->t_state, TS_FLUSH);
103095c7671fSmiod 	else
103195c7671fSmiod 		ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
103295c7671fSmiod 	(*linesw[tp->t_line].l_start)(tp);
103395c7671fSmiod }
103495c7671fSmiod 
103595c7671fSmiod void
103695c7671fSmiod scif_stsoft(struct scif_softc *sc, struct tty *tp)
103795c7671fSmiod {
103895c7671fSmiod #if 0
103995c7671fSmiod /* XXX (msaitoh) */
104095c7671fSmiod 	u_char msr, delta;
104195c7671fSmiod 	int s;
104295c7671fSmiod 
1043266ce419Sdrahn 	s = spltty();
104495c7671fSmiod 	msr = sc->sc_msr;
104595c7671fSmiod 	delta = sc->sc_msr_delta;
104695c7671fSmiod 	sc->sc_msr_delta = 0;
104795c7671fSmiod 	splx(s);
104895c7671fSmiod 
104995c7671fSmiod 	if (ISSET(delta, sc->sc_msr_dcd)) {
105095c7671fSmiod 		/*
105195c7671fSmiod 		 * Inform the tty layer that carrier detect changed.
105295c7671fSmiod 		 */
105395c7671fSmiod 		(void) (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSR_DCD));
105495c7671fSmiod 	}
105595c7671fSmiod 
105695c7671fSmiod 	if (ISSET(delta, sc->sc_msr_cts)) {
105795c7671fSmiod 		/* Block or unblock output according to flow control. */
105895c7671fSmiod 		if (ISSET(msr, sc->sc_msr_cts)) {
105995c7671fSmiod 			sc->sc_tx_stopped = 0;
106095c7671fSmiod 			(*linesw[tp->t_line].l_start)(tp);
106195c7671fSmiod 		} else {
106295c7671fSmiod 			sc->sc_tx_stopped = 1;
106395c7671fSmiod 		}
106495c7671fSmiod 	}
106595c7671fSmiod 
106695c7671fSmiod #ifdef SCIF_DEBUG
106795c7671fSmiod 	if (scif_debug)
106895c7671fSmiod 		scifstatus(sc, "scif_stsoft");
106995c7671fSmiod #endif
107095c7671fSmiod #endif
107195c7671fSmiod }
107295c7671fSmiod 
107395c7671fSmiod void
107495c7671fSmiod scifsoft(void *arg)
107595c7671fSmiod {
107695c7671fSmiod 	struct scif_softc *sc = arg;
107795c7671fSmiod 	struct tty *tp;
107895c7671fSmiod 
107995c7671fSmiod 	tp = sc->sc_tty;
108095c7671fSmiod 
108195c7671fSmiod 	if (sc->sc_rx_ready) {
108295c7671fSmiod 		sc->sc_rx_ready = 0;
108395c7671fSmiod 		scif_rxsoft(sc, tp);
108495c7671fSmiod 	}
108595c7671fSmiod 
108695c7671fSmiod #if 0
108795c7671fSmiod 	if (sc->sc_st_check) {
108895c7671fSmiod 		sc->sc_st_check = 0;
108995c7671fSmiod 		scif_stsoft(sc, tp);
109095c7671fSmiod 	}
109195c7671fSmiod #endif
109295c7671fSmiod 
109395c7671fSmiod 	if (sc->sc_tx_done) {
109495c7671fSmiod 		sc->sc_tx_done = 0;
109595c7671fSmiod 		scif_txsoft(sc, tp);
109695c7671fSmiod 	}
109795c7671fSmiod }
109895c7671fSmiod 
109995c7671fSmiod int
110095c7671fSmiod scifintr(void *arg)
110195c7671fSmiod {
110295c7671fSmiod 	struct scif_softc *sc = arg;
110395c7671fSmiod 	u_char *put, *end;
110495c7671fSmiod 	u_int cc;
110595c7671fSmiod 	u_short ssr2;
110695c7671fSmiod 	int count;
110795c7671fSmiod 
110895c7671fSmiod 	end = sc->sc_ebuf;
110995c7671fSmiod 	put = sc->sc_rbput;
111095c7671fSmiod 	cc = sc->sc_rbavail;
111195c7671fSmiod 
111295c7671fSmiod 	do {
111395c7671fSmiod 		ssr2 = scif_ssr_read();
111495c7671fSmiod 		if (ISSET(ssr2, SCSSR2_BRK)) {
111595c7671fSmiod 			scif_ssr_write(scif_ssr_read()
111695c7671fSmiod 				& ~(SCSSR2_ER | SCSSR2_BRK | SCSSR2_DR));
111795c7671fSmiod #ifdef DDB
111895c7671fSmiod 			if (ISSET(sc->sc_hwflags, SCIF_HW_CONSOLE) &&
111995c7671fSmiod 			    db_console != 0) {
1120e97088d6Smpi 				db_enter();
112195c7671fSmiod 			}
112295c7671fSmiod #endif /* DDB */
112395c7671fSmiod 		}
112495c7671fSmiod 		count = scif_fdr_read() & SCFDR2_RECVCNT;
112595c7671fSmiod 		if (count != 0) {
112695c7671fSmiod 			for (;;) {
112795c7671fSmiod 				u_char c = scif_frdr_read();
112895c7671fSmiod 				u_char err = (u_char)(scif_ssr_read() & 0x00ff);
112995c7671fSmiod 
113095c7671fSmiod 				scif_ssr_write(scif_ssr_read()
113195c7671fSmiod 				    & ~(SCSSR2_ER | SCSSR2_RDF | SCSSR2_DR));
113295c7671fSmiod #ifdef SH4
113395c7671fSmiod 				if (CPU_IS_SH4)
113495c7671fSmiod 					scif_lsr_write(scif_lsr_read()
113595c7671fSmiod 						       & ~SCLSR2_ORER);
113695c7671fSmiod #endif
113795c7671fSmiod 				if ((cc > 0) && (count > 0)) {
113895c7671fSmiod 					put[0] = c;
113995c7671fSmiod 					put[1] = err;
114095c7671fSmiod 					put += 2;
114195c7671fSmiod 					if (put >= end)
114295c7671fSmiod 						put = sc->sc_rbuf;
114395c7671fSmiod 					cc--;
114495c7671fSmiod 					count--;
114595c7671fSmiod 				} else
114695c7671fSmiod 					break;
114795c7671fSmiod 			}
114895c7671fSmiod 
114995c7671fSmiod 			/*
115095c7671fSmiod 			 * Current string of incoming characters ended because
115195c7671fSmiod 			 * no more data was available or we ran out of space.
115295c7671fSmiod 			 * Schedule a receive event if any data was received.
115395c7671fSmiod 			 * If we're out of space, turn off receive interrupts.
115495c7671fSmiod 			 */
115595c7671fSmiod 			sc->sc_rbput = put;
115695c7671fSmiod 			sc->sc_rbavail = cc;
115795c7671fSmiod 			if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
115895c7671fSmiod 				sc->sc_rx_ready = 1;
115995c7671fSmiod 
116095c7671fSmiod 			/*
116195c7671fSmiod 			 * See if we are in danger of overflowing a buffer. If
116295c7671fSmiod 			 * so, use hardware flow control to ease the pressure.
116395c7671fSmiod 			 */
116495c7671fSmiod 			if (!ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED) &&
116595c7671fSmiod 			    cc < sc->sc_r_hiwat) {
116695c7671fSmiod 				SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
116795c7671fSmiod #if 0
116895c7671fSmiod 				scif_hwiflow(sc);
116995c7671fSmiod #endif
117095c7671fSmiod 			}
117195c7671fSmiod 
117295c7671fSmiod 			/*
117395c7671fSmiod 			 * If we're out of space, disable receive interrupts
117495c7671fSmiod 			 * until the queue has drained a bit.
117595c7671fSmiod 			 */
117695c7671fSmiod 			if (!cc) {
117795c7671fSmiod 				SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
117895c7671fSmiod 				scif_scr_write(scif_scr_read() & ~SCSCR2_RIE);
117995c7671fSmiod 			}
118095c7671fSmiod 		} else {
118195c7671fSmiod 			if (scif_ssr_read() & (SCSSR2_RDF | SCSSR2_DR)) {
118295c7671fSmiod 				scif_scr_write(scif_scr_read()
118395c7671fSmiod 					       & ~(SCSCR2_TIE | SCSCR2_RIE));
118495c7671fSmiod 				delay(10);
118595c7671fSmiod 				scif_scr_write(scif_scr_read()
118695c7671fSmiod 					       | SCSCR2_TIE | SCSCR2_RIE);
118795c7671fSmiod 				continue;
118895c7671fSmiod 			}
118995c7671fSmiod 		}
119095c7671fSmiod 	} while (scif_ssr_read() & (SCSSR2_RDF | SCSSR2_DR));
119195c7671fSmiod 
119295c7671fSmiod #if 0
119395c7671fSmiod 	msr = bus_space_read_1(iot, ioh, scif_msr);
119495c7671fSmiod 	delta = msr ^ sc->sc_msr;
119595c7671fSmiod 	sc->sc_msr = msr;
119695c7671fSmiod 	if (ISSET(delta, sc->sc_msr_mask)) {
119795c7671fSmiod 		SET(sc->sc_msr_delta, delta);
119895c7671fSmiod 
119995c7671fSmiod 		/*
120095c7671fSmiod 		 * Pulse-per-second clock signal on edge of DCD?
120195c7671fSmiod 		 */
120295c7671fSmiod 		if (ISSET(delta, sc->sc_ppsmask)) {
120395c7671fSmiod 			struct timeval tv;
120495c7671fSmiod 			if (ISSET(msr, sc->sc_ppsmask) ==
120595c7671fSmiod 			    sc->sc_ppsassert) {
120695c7671fSmiod 				/* XXX nanotime() */
120795c7671fSmiod 				microtime(&tv);
120895c7671fSmiod 				TIMEVAL_TO_TIMESPEC(&tv,
120995c7671fSmiod 						    &sc->ppsinfo.assert_timestamp);
121095c7671fSmiod 				if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
121195c7671fSmiod 					timespecadd(&sc->ppsinfo.assert_timestamp,
121295c7671fSmiod 						    &sc->ppsparam.assert_offset,
121395c7671fSmiod 						    &sc->ppsinfo.assert_timestamp);
121495c7671fSmiod 					TIMESPEC_TO_TIMEVAL(&tv, &sc->ppsinfo.assert_timestamp);
121595c7671fSmiod 				}
121695c7671fSmiod 
121795c7671fSmiod #ifdef PPS_SYNC
121895c7671fSmiod 				if (sc->ppsparam.mode & PPS_HARDPPSONASSERT)
121995c7671fSmiod 					hardpps(&tv, tv.tv_usec);
122095c7671fSmiod #endif
122195c7671fSmiod 				sc->ppsinfo.assert_sequence++;
122295c7671fSmiod 				sc->ppsinfo.current_mode =
122395c7671fSmiod 					sc->ppsparam.mode;
122495c7671fSmiod 
122595c7671fSmiod 			} else if (ISSET(msr, sc->sc_ppsmask) ==
122695c7671fSmiod 				   sc->sc_ppsclear) {
122795c7671fSmiod 				/* XXX nanotime() */
122895c7671fSmiod 				microtime(&tv);
122995c7671fSmiod 				TIMEVAL_TO_TIMESPEC(&tv,
123095c7671fSmiod 						    &sc->ppsinfo.clear_timestamp);
123195c7671fSmiod 				if (sc->ppsparam.mode & PPS_OFFSETCLEAR) {
123295c7671fSmiod 					timespecadd(&sc->ppsinfo.clear_timestamp,
123395c7671fSmiod 						    &sc->ppsparam.clear_offset,
123495c7671fSmiod 						    &sc->ppsinfo.clear_timestamp);
123595c7671fSmiod 					TIMESPEC_TO_TIMEVAL(&tv, &sc->ppsinfo.clear_timestamp);
123695c7671fSmiod 				}
123795c7671fSmiod 
123895c7671fSmiod #ifdef PPS_SYNC
123995c7671fSmiod 				if (sc->ppsparam.mode & PPS_HARDPPSONCLEAR)
124095c7671fSmiod 					hardpps(&tv, tv.tv_usec);
124195c7671fSmiod #endif
124295c7671fSmiod 				sc->ppsinfo.clear_sequence++;
124395c7671fSmiod 				sc->ppsinfo.current_mode =
124495c7671fSmiod 					sc->ppsparam.mode;
124595c7671fSmiod 			}
124695c7671fSmiod 		}
124795c7671fSmiod 
124895c7671fSmiod 		/*
124995c7671fSmiod 		 * Stop output immediately if we lose the output
125095c7671fSmiod 		 * flow control signal or carrier detect.
125195c7671fSmiod 		 */
125295c7671fSmiod 		if (ISSET(~msr, sc->sc_msr_mask)) {
125395c7671fSmiod 			sc->sc_tbc = 0;
125495c7671fSmiod 			sc->sc_heldtbc = 0;
125595c7671fSmiod #ifdef SCIF_DEBUG
125695c7671fSmiod 			if (scif_debug)
125795c7671fSmiod 				scifstatus(sc, "scifintr  ");
125895c7671fSmiod #endif
125995c7671fSmiod 		}
126095c7671fSmiod 
126195c7671fSmiod 		sc->sc_st_check = 1;
126295c7671fSmiod 	}
126395c7671fSmiod #endif
126495c7671fSmiod 
126595c7671fSmiod 	/*
126695c7671fSmiod 	 * Done handling any receive interrupts. See if data can be
126795c7671fSmiod 	 * transmitted as well. Schedule tx done event if no data left
126895c7671fSmiod 	 * and tty was marked busy.
126995c7671fSmiod 	 */
127095c7671fSmiod 	if (((scif_fdr_read() & SCFDR2_TXCNT) >> 8) != 16) { /* XXX (msaitoh) */
127195c7671fSmiod 		/*
127295c7671fSmiod 		 * If we've delayed a parameter change, do it now, and restart
127395c7671fSmiod 		 * output.
127495c7671fSmiod 		 */
127595c7671fSmiod 		if (sc->sc_heldchange) {
127695c7671fSmiod 			sc->sc_heldchange = 0;
127795c7671fSmiod 			sc->sc_tbc = sc->sc_heldtbc;
127895c7671fSmiod 			sc->sc_heldtbc = 0;
127995c7671fSmiod 		}
128095c7671fSmiod 
128195c7671fSmiod 		/* Output the next chunk of the contiguous buffer, if any. */
128295c7671fSmiod 		if (sc->sc_tbc > 0) {
128395c7671fSmiod 			int n;
128495c7671fSmiod 			int maxchars;
128595c7671fSmiod 			int i;
128695c7671fSmiod 
128795c7671fSmiod 			n = sc->sc_tbc;
128895c7671fSmiod 			maxchars = sc->sc_fifolen -
128995c7671fSmiod 				((scif_fdr_read() & SCFDR2_TXCNT) >> 8);
129095c7671fSmiod 			if (n > maxchars)
129195c7671fSmiod 				n = maxchars;
129295c7671fSmiod 
129395c7671fSmiod 			for (i = 0; i < n; i++) {
129495c7671fSmiod 				scif_putc(*(sc->sc_tba));
129595c7671fSmiod 				sc->sc_tba++;
129695c7671fSmiod 			}
129795c7671fSmiod 			sc->sc_tbc -= n;
129895c7671fSmiod 		} else {
129995c7671fSmiod 			/* Disable transmit completion interrupts if necessary. */
130095c7671fSmiod #if 0
130195c7671fSmiod 			if (ISSET(sc->sc_ier, IER_ETXRDY))
130295c7671fSmiod #endif
130395c7671fSmiod 				scif_scr_write(scif_scr_read() & ~SCSCR2_TIE);
130495c7671fSmiod 
130595c7671fSmiod 			if (sc->sc_tx_busy) {
130695c7671fSmiod 				sc->sc_tx_busy = 0;
130795c7671fSmiod 				sc->sc_tx_done = 1;
130895c7671fSmiod 			}
130995c7671fSmiod 		}
131095c7671fSmiod 	}
131195c7671fSmiod 
131295c7671fSmiod 	/* Wake up the poller. */
131395c7671fSmiod 	softintr_schedule(sc->sc_si);
131495c7671fSmiod 
131595c7671fSmiod 	return (1);
131695c7671fSmiod }
131795c7671fSmiod 
131895c7671fSmiod void
131995c7671fSmiod scifcnprobe(struct consdev *cp)
132095c7671fSmiod {
132195c7671fSmiod 	int maj;
132295c7671fSmiod 
132395c7671fSmiod 	/* locate the major number */
132495c7671fSmiod 	for (maj = 0; maj < nchrdev; maj++)
132595c7671fSmiod 		if (cdevsw[maj].d_open == scifopen)
132695c7671fSmiod 			break;
132795c7671fSmiod 
132895c7671fSmiod 	cp->cn_dev = makedev(maj, 0);
132995c7671fSmiod #ifdef SCIFCONSOLE
1330713cf266Sjsing 	cp->cn_pri = CN_HIGHPRI;
133195c7671fSmiod #else
1332713cf266Sjsing 	cp->cn_pri = CN_LOWPRI;
133395c7671fSmiod #endif
133495c7671fSmiod }
133595c7671fSmiod 
133695c7671fSmiod void
133795c7671fSmiod scifcninit(struct consdev *cp)
133895c7671fSmiod {
133995c7671fSmiod 	InitializeScif(scifcn_speed);
134095c7671fSmiod 	scifisconsole = 1;
134195c7671fSmiod }
134295c7671fSmiod 
134395c7671fSmiod int
134495c7671fSmiod scifcngetc(dev_t dev)
134595c7671fSmiod {
134695c7671fSmiod 	int c;
134795c7671fSmiod 	int s;
134895c7671fSmiod 
1349266ce419Sdrahn 	s = spltty();
135095c7671fSmiod 	c = scif_getc();
135195c7671fSmiod 	splx(s);
135295c7671fSmiod 
135395c7671fSmiod 	return (c);
135495c7671fSmiod }
135595c7671fSmiod 
135695c7671fSmiod void
135795c7671fSmiod scifcnputc(dev_t dev, int c)
135895c7671fSmiod {
135995c7671fSmiod 	int s;
136095c7671fSmiod 
1361266ce419Sdrahn 	s = spltty();
136295c7671fSmiod 	scif_putc((u_char)c);
136395c7671fSmiod 	splx(s);
136495c7671fSmiod }
1365