Home | History | Annotate | Line # | Download | only in clps711x
      1  1.11    andvar /*      $NetBSD: clpscom.c,v 1.11 2023/09/01 08:53:52 andvar Exp $      */
      2   1.1  kiyohara /*
      3   1.1  kiyohara  * Copyright (c) 2013 KIYOHARA Takashi
      4   1.1  kiyohara  * All rights reserved.
      5   1.1  kiyohara  *
      6   1.1  kiyohara  * Redistribution and use in source and binary forms, with or without
      7   1.1  kiyohara  * modification, are permitted provided that the following conditions
      8   1.1  kiyohara  * are met:
      9   1.1  kiyohara  * 1. Redistributions of source code must retain the above copyright
     10   1.1  kiyohara  *    notice, this list of conditions and the following disclaimer.
     11   1.1  kiyohara  * 2. Redistributions in binary form must reproduce the above copyright
     12   1.1  kiyohara  *    notice, this list of conditions and the following disclaimer in the
     13   1.1  kiyohara  *    documentation and/or other materials provided with the distribution.
     14   1.1  kiyohara  *
     15   1.1  kiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16   1.1  kiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17   1.1  kiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18   1.1  kiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     19   1.1  kiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     20   1.1  kiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21   1.1  kiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22   1.1  kiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     23   1.1  kiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     24   1.1  kiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25   1.1  kiyohara  * POSSIBILITY OF SUCH DAMAGE.
     26   1.1  kiyohara  */
     27   1.1  kiyohara #include <sys/cdefs.h>
     28  1.11    andvar __KERNEL_RCSID(0, "$NetBSD: clpscom.c,v 1.11 2023/09/01 08:53:52 andvar Exp $");
     29   1.1  kiyohara 
     30   1.1  kiyohara #include "rnd.h"
     31   1.1  kiyohara 
     32   1.1  kiyohara #include <sys/param.h>
     33   1.1  kiyohara #include <sys/bus.h>
     34   1.1  kiyohara #include <sys/conf.h>
     35   1.1  kiyohara #include <sys/device.h>
     36   1.1  kiyohara #include <sys/errno.h>
     37   1.1  kiyohara #include <sys/fcntl.h>
     38   1.1  kiyohara #include <sys/intr.h>
     39   1.1  kiyohara #include <sys/kauth.h>
     40   1.1  kiyohara #include <sys/lwp.h>
     41   1.9   thorpej #include <sys/kmem.h>
     42   1.1  kiyohara #include <sys/systm.h>
     43   1.1  kiyohara #include <sys/termios.h>
     44   1.1  kiyohara #include <sys/tty.h>
     45   1.1  kiyohara #include <sys/types.h>
     46   1.1  kiyohara 
     47  1.10  riastrad #include <ddb/db_active.h>
     48  1.10  riastrad 
     49   1.1  kiyohara #include <arm/clps711x/clps711xreg.h>
     50   1.1  kiyohara #include <arm/clps711x/clpssocvar.h>
     51   1.1  kiyohara 
     52   1.1  kiyohara #include <dev/cons.h>
     53   1.1  kiyohara 
     54   1.1  kiyohara #ifdef RND_COM
     55   1.6  riastrad #include <sys/rndsource.h>
     56   1.1  kiyohara #endif
     57   1.1  kiyohara 
     58   1.1  kiyohara #include "ioconf.h"
     59   1.1  kiyohara #include "locators.h"
     60   1.1  kiyohara 
     61   1.5  christos #define COMUNIT(x)	TTUNIT(x)
     62   1.5  christos #define COMDIALOUT(x)	TTDIALOUT(x)
     63   1.1  kiyohara 
     64   1.1  kiyohara #define CLPSCOM_RING_SIZE	2048
     65   1.1  kiyohara #define UART_FIFO_SIZE		16
     66   1.1  kiyohara 
     67   1.1  kiyohara #define CLPSCOM_READ_CON(sc) \
     68   1.1  kiyohara 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON)
     69   1.1  kiyohara #define CLPSCOM_WRITE_CON(sc, val) \
     70   1.1  kiyohara 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSCON, (val))
     71   1.1  kiyohara #define CLPSCOM_READ_FLG(sc) \
     72   1.1  kiyohara 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG)
     73   1.1  kiyohara #define CLPSCOM_WRITE_FLG(sc, val) \
     74   1.1  kiyohara 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_SYSFLG, (val))
     75   1.1  kiyohara #define CLPSCOM_READ(sc) \
     76   1.1  kiyohara 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR)
     77   1.1  kiyohara #define CLPSCOM_WRITE(sc, val) \
     78   1.1  kiyohara 	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val))
     79   1.1  kiyohara #define CLPSCOM_WRITE_MULTI(sc, val, n) \
     80   1.1  kiyohara   bus_space_write_multi_1((sc)->sc_iot, (sc)->sc_ioh, PS711X_UARTDR, (val), (n))
     81   1.1  kiyohara #define CLPSCOM_READ_UBRLCR(sc) \
     82   1.1  kiyohara 	bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR)
     83   1.1  kiyohara #define CLPSCOM_WRITE_UBRLCR(sc, val) \
     84   1.1  kiyohara 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, PS711X_UBRLCR, (val))
     85   1.1  kiyohara 
     86   1.1  kiyohara struct clpscom_softc {
     87   1.1  kiyohara 	device_t sc_dev;
     88   1.1  kiyohara 	bus_space_tag_t sc_iot;
     89   1.1  kiyohara 	bus_space_handle_t sc_ioh;
     90   1.1  kiyohara 	int sc_irq[3];
     91   1.1  kiyohara 	void *sc_ih[3];
     92   1.1  kiyohara #define CLPSCOM_TXINT	0
     93   1.1  kiyohara #define CLPSCOM_RXINT	1
     94   1.1  kiyohara #define CLPSCOM_MSINT	2
     95   1.1  kiyohara 
     96   1.1  kiyohara 	void *sc_si;
     97   1.1  kiyohara 
     98   1.1  kiyohara 	struct tty *sc_tty;
     99   1.1  kiyohara 
    100   1.1  kiyohara 	u_char *sc_tba;
    101   1.1  kiyohara 	u_int sc_tbc;
    102   1.1  kiyohara 	u_char *sc_rbuf;
    103   1.1  kiyohara 	char *volatile sc_rbget;
    104   1.1  kiyohara 	char *volatile sc_rbput;
    105   1.1  kiyohara 	volatile int sc_rbavail;
    106   1.1  kiyohara 
    107   1.1  kiyohara #define CLPSCOM_MODEM_STATUS_MASK (SYSFLG_DCD | SYSFLG_DSR | SYSFLG_CTS)
    108   1.1  kiyohara 	uint32_t sc_ms;
    109   1.1  kiyohara 	uint32_t sc_ms_dcd;
    110   1.1  kiyohara 	uint32_t sc_ms_cts;
    111   1.1  kiyohara 	uint32_t sc_ms_mask;
    112   1.1  kiyohara 	uint32_t sc_ms_delta;
    113   1.1  kiyohara 
    114   1.1  kiyohara 	int sc_tx_stopped;
    115   1.1  kiyohara 
    116   1.1  kiyohara 	int sc_tx_done;
    117   1.1  kiyohara 	int sc_rx_ready;
    118   1.1  kiyohara 	int sc_ms_changed;
    119   1.1  kiyohara 
    120   1.1  kiyohara 	int sc_hwflags;
    121   1.1  kiyohara #define COM_HW_CONSOLE	(1 << 0)
    122   1.1  kiyohara #define COM_HW_DEV_OK	(1 << 1)
    123   1.1  kiyohara #define COM_HW_KGDB	(1 << 2)
    124   1.1  kiyohara 	int sc_swflags;
    125   1.1  kiyohara 
    126   1.1  kiyohara #ifdef RND_COM
    127  1.11    andvar 	krndsource_t rnd_source;
    128   1.1  kiyohara #endif
    129   1.1  kiyohara };
    130   1.1  kiyohara 
    131   1.1  kiyohara static int clpscom_match(device_t, cfdata_t, void *);
    132   1.1  kiyohara static void clpscom_attach(device_t, device_t, void *);
    133   1.1  kiyohara 
    134   1.1  kiyohara static int clpscom_txintr(void *);
    135   1.1  kiyohara static int clpscom_rxintr(void *);
    136   1.1  kiyohara static int clpscom_msintr(void *);
    137   1.1  kiyohara static void clpscom_soft(void *);
    138   1.1  kiyohara 
    139   1.1  kiyohara static void clpscom_start(struct tty *);
    140   1.1  kiyohara static int clpscom_param(struct tty *, struct termios *);
    141   1.1  kiyohara static int clpscom_hwiflow(struct tty *, int);
    142   1.1  kiyohara 
    143   1.1  kiyohara dev_type_open(clpscomopen);
    144   1.1  kiyohara dev_type_close(clpscomclose);
    145   1.1  kiyohara dev_type_read(clpscomread);
    146   1.1  kiyohara dev_type_write(clpscomwrite);
    147   1.1  kiyohara dev_type_ioctl(clpscomioctl);
    148   1.1  kiyohara dev_type_stop(clpscomstop);
    149   1.1  kiyohara dev_type_tty(clpscomtty);
    150   1.1  kiyohara dev_type_poll(clpscompoll);
    151   1.1  kiyohara 
    152   1.1  kiyohara static void clpscom_iflush(struct clpscom_softc *);
    153   1.1  kiyohara static void clpscom_shutdown(struct clpscom_softc *);
    154   1.1  kiyohara static void clpscom_break(struct clpscom_softc *, int);
    155   1.1  kiyohara static int clpscom_to_tiocm(struct clpscom_softc *);
    156   1.1  kiyohara 
    157   1.1  kiyohara static void clpscom_rxsoft(struct clpscom_softc *, struct tty *);
    158   1.1  kiyohara static void clpscom_mssoft(struct clpscom_softc *, struct tty *);
    159   1.1  kiyohara 
    160   1.1  kiyohara static inline uint32_t clpscom_rate2ubrlcr(int);
    161   1.1  kiyohara static uint32_t clpscom_cflag2ubrlcr(tcflag_t);
    162   1.1  kiyohara 
    163   1.1  kiyohara static int clpscom_cngetc(dev_t);
    164   1.1  kiyohara static void clpscom_cnputc(dev_t, int);
    165   1.1  kiyohara static void clpscom_cnpollc(dev_t, int);
    166   1.1  kiyohara 
    167   1.1  kiyohara CFATTACH_DECL_NEW(clpscom, sizeof(struct clpscom_softc),
    168   1.1  kiyohara     clpscom_match, clpscom_attach, NULL, NULL);
    169   1.1  kiyohara 
    170   1.1  kiyohara const struct cdevsw clpscom_cdevsw = {
    171   1.2  dholland 	.d_open = clpscomopen,
    172   1.2  dholland 	.d_close = clpscomclose,
    173   1.2  dholland 	.d_read = clpscomread,
    174   1.2  dholland 	.d_write = clpscomwrite,
    175   1.2  dholland 	.d_ioctl = clpscomioctl,
    176   1.2  dholland 	.d_stop = clpscomstop,
    177   1.2  dholland 	.d_tty = clpscomtty,
    178   1.2  dholland 	.d_poll = clpscompoll,
    179   1.2  dholland 	.d_mmap = nommap,
    180   1.2  dholland 	.d_kqfilter = ttykqfilter,
    181   1.3  dholland 	.d_discard = nodiscard,
    182   1.2  dholland 	.d_flag = D_TTY
    183   1.1  kiyohara };
    184   1.1  kiyohara 
    185   1.1  kiyohara static struct cnm_state clpscom_cnm_state;
    186   1.1  kiyohara static vaddr_t clpscom_cnaddr = 0;
    187   1.1  kiyohara static int clpscom_cnrate;
    188   1.1  kiyohara static tcflag_t clpscom_cncflag;
    189   1.1  kiyohara 
    190   1.1  kiyohara 
    191   1.1  kiyohara /* ARGSUSED */
    192   1.1  kiyohara static int
    193   1.1  kiyohara clpscom_match(device_t parent, cfdata_t match, void *aux)
    194   1.1  kiyohara {
    195   1.1  kiyohara 
    196   1.1  kiyohara 	return 1;
    197   1.1  kiyohara }
    198   1.1  kiyohara 
    199   1.1  kiyohara /* ARGSUSED */
    200   1.1  kiyohara static void
    201   1.1  kiyohara clpscom_attach(device_t parent, device_t self, void *aux)
    202   1.1  kiyohara {
    203   1.1  kiyohara 	struct clpscom_softc *sc = device_private(self);
    204   1.1  kiyohara 	struct clpssoc_attach_args *aa = aux;
    205   1.1  kiyohara 	int i;
    206   1.1  kiyohara 
    207   1.1  kiyohara 	aprint_naive("\n");
    208   1.1  kiyohara 	aprint_normal("\n");
    209   1.1  kiyohara 
    210   1.1  kiyohara 	sc->sc_dev = self;
    211   1.1  kiyohara 	sc->sc_iot = aa->aa_iot;
    212   1.1  kiyohara 	sc->sc_ioh = *aa->aa_ioh;
    213   1.1  kiyohara 	for (i = 0; i < __arraycount(aa->aa_irq); i++) {
    214   1.1  kiyohara 		sc->sc_irq[i] = aa->aa_irq[i];
    215   1.1  kiyohara 		sc->sc_ih[i] = NULL;
    216   1.1  kiyohara 	}
    217   1.1  kiyohara 
    218   1.1  kiyohara 	if (clpscom_cnaddr != 0)
    219   1.1  kiyohara 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
    220   1.1  kiyohara 
    221   1.1  kiyohara 	sc->sc_tty = tty_alloc();
    222   1.1  kiyohara 	sc->sc_tty->t_oproc = clpscom_start;
    223   1.1  kiyohara 	sc->sc_tty->t_param = clpscom_param;
    224   1.1  kiyohara 	sc->sc_tty->t_hwiflow = clpscom_hwiflow;
    225   1.1  kiyohara 
    226   1.1  kiyohara 	sc->sc_tbc = 0;
    227   1.9   thorpej 	sc->sc_rbuf = kmem_alloc(CLPSCOM_RING_SIZE << 1, KM_SLEEP);
    228   1.1  kiyohara 	sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
    229   1.1  kiyohara 	sc->sc_rbavail = CLPSCOM_RING_SIZE;
    230   1.1  kiyohara 
    231   1.1  kiyohara 	tty_attach(sc->sc_tty);
    232   1.1  kiyohara 
    233   1.1  kiyohara 	if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    234   1.1  kiyohara 		int maj = cdevsw_lookup_major(&clpscom_cdevsw);
    235   1.1  kiyohara 
    236   1.1  kiyohara 		sc->sc_tty->t_dev = makedev(maj, device_unit(sc->sc_dev));
    237   1.1  kiyohara 		cn_tab->cn_dev = sc->sc_tty->t_dev;
    238   1.1  kiyohara 
    239   1.1  kiyohara 		aprint_normal_dev(self, "console\n");
    240   1.1  kiyohara 	}
    241   1.1  kiyohara 
    242   1.1  kiyohara 	sc->sc_si = softint_establish(SOFTINT_SERIAL, clpscom_soft, sc);
    243   1.1  kiyohara 
    244   1.1  kiyohara #ifdef RND_COM
    245   1.1  kiyohara 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
    246   1.4       tls 	    RND_TYPE_TTY, RND_FLAG_DEFAULT);
    247   1.1  kiyohara #endif
    248   1.1  kiyohara 
    249   1.1  kiyohara 	SET(sc->sc_hwflags, COM_HW_DEV_OK);
    250   1.1  kiyohara }
    251   1.1  kiyohara 
    252   1.1  kiyohara static int
    253   1.1  kiyohara clpscom_txintr(void *arg)
    254   1.1  kiyohara {
    255   1.1  kiyohara 	struct clpscom_softc *sc = arg;
    256   1.1  kiyohara 	uint32_t sysflg;
    257   1.1  kiyohara 
    258   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    259   1.1  kiyohara 		return 0;
    260   1.1  kiyohara 
    261   1.1  kiyohara 	sysflg = CLPSCOM_READ_FLG(sc);
    262   1.1  kiyohara 
    263   1.1  kiyohara 	/*
    264   1.1  kiyohara 	 * Done handling any receive interrupts. See if data can be
    265   1.1  kiyohara 	 * transmitted as well. Schedule tx done event if no data left
    266   1.1  kiyohara 	 * and tty was marked busy.
    267   1.1  kiyohara 	 */
    268   1.1  kiyohara 
    269   1.1  kiyohara 	if (!ISSET(sysflg, SYSFLG_UTXFF)) {
    270   1.1  kiyohara 		/* Output the next chunk of the contiguous buffer, if any. */
    271   1.1  kiyohara 		if (sc->sc_tbc > 0) {
    272   1.1  kiyohara 			while (sc->sc_tbc > 0 && !ISSET(sysflg, SYSFLG_UTXFF)) {
    273   1.1  kiyohara 				CLPSCOM_WRITE(sc, *sc->sc_tba);
    274   1.1  kiyohara 				sc->sc_tba++;
    275   1.1  kiyohara 				sc->sc_tbc--;
    276   1.1  kiyohara 				sysflg = CLPSCOM_READ_FLG(sc);
    277   1.1  kiyohara 			}
    278   1.1  kiyohara 		} else if (!ISSET(sysflg, SYSFLG_UBUSY) &&
    279   1.1  kiyohara 					sc->sc_ih[CLPSCOM_TXINT] != NULL) {
    280   1.1  kiyohara 			intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]);
    281   1.1  kiyohara 			sc->sc_ih[CLPSCOM_TXINT] = NULL;
    282   1.1  kiyohara 			sc->sc_tx_done = 1;
    283   1.1  kiyohara 		}
    284   1.1  kiyohara 	}
    285   1.1  kiyohara 
    286   1.1  kiyohara 	/* Wake up the poller. */
    287   1.1  kiyohara 	softint_schedule(sc->sc_si);
    288   1.1  kiyohara 
    289   1.1  kiyohara 	return 1;
    290   1.1  kiyohara }
    291   1.1  kiyohara 
    292   1.1  kiyohara static int
    293   1.1  kiyohara clpscom_rxintr(void *arg)
    294   1.1  kiyohara {
    295   1.1  kiyohara 	struct clpscom_softc *sc = arg;
    296   1.1  kiyohara 	int cc;
    297   1.1  kiyohara 	uint32_t sysflg;
    298   1.1  kiyohara 	uint16_t data;
    299   1.1  kiyohara 	u_char *put;
    300   1.1  kiyohara 
    301   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    302   1.1  kiyohara 		return 0;
    303   1.1  kiyohara 
    304   1.1  kiyohara 	if (sc->sc_ih[CLPSCOM_RXINT] != NULL) {
    305   1.1  kiyohara 		put = sc->sc_rbput;
    306   1.1  kiyohara 		cc = sc->sc_rbavail;
    307   1.1  kiyohara 		while (cc > 0) {
    308   1.1  kiyohara 			sysflg = CLPSCOM_READ_FLG(sc);
    309   1.1  kiyohara 			if (ISSET(sysflg, SYSFLG_URXFE))
    310   1.1  kiyohara 				break;
    311   1.1  kiyohara 			data = CLPSCOM_READ(sc);
    312   1.1  kiyohara 			cn_check_magic(sc->sc_tty->t_dev, data & 0xff,
    313   1.1  kiyohara 			    clpscom_cnm_state);
    314   1.1  kiyohara 
    315   1.1  kiyohara 			put[0] = data & 0xff;
    316   1.1  kiyohara 			put[1] = (data >> 8) & 0xff;
    317   1.1  kiyohara 			put += 2;
    318   1.1  kiyohara 			if (put >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1))
    319   1.1  kiyohara 				put = sc->sc_rbuf;
    320   1.1  kiyohara 			cc--;
    321   1.1  kiyohara 			sc->sc_rx_ready = 1;
    322   1.1  kiyohara 		}
    323   1.1  kiyohara 
    324   1.1  kiyohara 		/*
    325   1.1  kiyohara 		 * Current string of incoming characters ended because
    326   1.1  kiyohara 		 * no more data was available or we ran out of space.
    327   1.1  kiyohara 		 * Schedule a receive event if any data was received.
    328   1.1  kiyohara 		 * If we're out of space, turn off receive interrupts.
    329   1.1  kiyohara 		 */
    330   1.1  kiyohara 		sc->sc_rbput = put;
    331   1.1  kiyohara 		sc->sc_rbavail = cc;
    332   1.1  kiyohara 
    333   1.1  kiyohara 		/*
    334   1.1  kiyohara 		 * See if we are in danger of overflowing a buffer. If
    335   1.1  kiyohara 		 * so, use hardware flow control to ease the pressure.
    336   1.1  kiyohara 		 */
    337   1.1  kiyohara 
    338   1.1  kiyohara 		/* but clpscom cannot. X-( */
    339   1.1  kiyohara 
    340   1.1  kiyohara 		/*
    341   1.1  kiyohara 		 * If we're out of space, disable receive interrupts
    342   1.1  kiyohara 		 * until the queue has drained a bit.
    343   1.1  kiyohara 		 */
    344   1.1  kiyohara 		if (cc <= 0) {
    345   1.1  kiyohara 			intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]);
    346   1.1  kiyohara 			sc->sc_ih[CLPSCOM_RXINT] = NULL;
    347   1.1  kiyohara 		}
    348   1.1  kiyohara 	}
    349   1.1  kiyohara 
    350   1.1  kiyohara 	/* Wake up the poller. */
    351   1.1  kiyohara 	softint_schedule(sc->sc_si);
    352   1.1  kiyohara 
    353   1.1  kiyohara 	return 1;
    354   1.1  kiyohara }
    355   1.1  kiyohara 
    356   1.1  kiyohara static int
    357   1.1  kiyohara clpscom_msintr(void *arg)
    358   1.1  kiyohara {
    359   1.1  kiyohara 	struct clpscom_softc *sc = arg;
    360   1.1  kiyohara 	uint32_t ms, delta;
    361   1.1  kiyohara 
    362   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    363   1.1  kiyohara 		return 0;
    364   1.1  kiyohara 
    365   1.1  kiyohara 	if (sc->sc_ih[CLPSCOM_MSINT] != NULL) {
    366   1.1  kiyohara 		ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK;
    367   1.1  kiyohara 		delta = ms ^ sc->sc_ms;
    368   1.1  kiyohara 		sc->sc_ms = ms;
    369   1.1  kiyohara 
    370   1.1  kiyohara 		if (ISSET(delta, sc->sc_ms_mask)) {
    371   1.1  kiyohara 			SET(sc->sc_ms_delta, delta);
    372   1.1  kiyohara 
    373   1.1  kiyohara 			/*
    374   1.1  kiyohara 			 * Stop output immediately if we lose the output
    375   1.1  kiyohara 			 * flow control signal or carrier detect.
    376   1.1  kiyohara 			 */
    377   1.1  kiyohara 			if (ISSET(~ms, sc->sc_ms_mask))
    378   1.1  kiyohara 				sc->sc_tbc = 0;
    379   1.1  kiyohara 			sc->sc_ms_changed = 1;
    380   1.1  kiyohara 		}
    381   1.1  kiyohara 	}
    382   1.1  kiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PS711X_UMSEOI, 1);
    383   1.1  kiyohara 
    384   1.1  kiyohara 	/* Wake up the poller. */
    385   1.1  kiyohara 	softint_schedule(sc->sc_si);
    386   1.1  kiyohara 
    387   1.1  kiyohara 	return 1;
    388   1.1  kiyohara }
    389   1.1  kiyohara 
    390   1.1  kiyohara static void
    391   1.1  kiyohara clpscom_soft(void *arg)
    392   1.1  kiyohara {
    393   1.1  kiyohara 	struct clpscom_softc *sc = arg;
    394   1.1  kiyohara 	struct tty *tp = sc->sc_tty;
    395   1.1  kiyohara 
    396   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    397   1.1  kiyohara 		return;
    398   1.1  kiyohara 
    399   1.1  kiyohara 	if (sc->sc_rx_ready) {
    400   1.1  kiyohara 		sc->sc_rx_ready = 0;
    401   1.1  kiyohara 		clpscom_rxsoft(sc, tp);
    402   1.1  kiyohara 	}
    403   1.1  kiyohara 	if (sc->sc_tx_done) {
    404   1.1  kiyohara 		sc->sc_tx_done = 0;
    405   1.1  kiyohara 		CLR(tp->t_state, TS_BUSY);
    406   1.1  kiyohara 		if (ISSET(tp->t_state, TS_FLUSH))
    407   1.1  kiyohara 			CLR(tp->t_state, TS_FLUSH);
    408   1.1  kiyohara 		else
    409   1.1  kiyohara 			ndflush(&tp->t_outq,
    410   1.1  kiyohara 			    (int)(sc->sc_tba - tp->t_outq.c_cf));
    411   1.1  kiyohara 		(*tp->t_linesw->l_start)(tp);
    412   1.1  kiyohara 	}
    413   1.1  kiyohara 	if (sc->sc_ms_changed == 1) {
    414   1.1  kiyohara 		sc->sc_ms_changed = 0;
    415   1.1  kiyohara 		clpscom_mssoft(sc, tp);
    416   1.1  kiyohara 	}
    417   1.1  kiyohara }
    418   1.1  kiyohara 
    419   1.1  kiyohara static void
    420   1.1  kiyohara clpscom_start(struct tty *tp)
    421   1.1  kiyohara {
    422   1.1  kiyohara 	struct clpscom_softc *sc
    423   1.1  kiyohara 		= device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev));
    424   1.1  kiyohara 	int s, n;
    425   1.1  kiyohara 
    426   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    427   1.1  kiyohara 		return;
    428   1.1  kiyohara 
    429   1.1  kiyohara 	s = spltty();
    430   1.1  kiyohara 	if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
    431   1.1  kiyohara 		goto out;
    432   1.1  kiyohara 	if (sc->sc_tx_stopped)
    433   1.1  kiyohara 		goto out;
    434   1.1  kiyohara 	if (!ttypull(tp))
    435   1.1  kiyohara 		goto out;
    436   1.1  kiyohara 
    437   1.1  kiyohara 	/* Grab the first contiguous region of buffer space. */
    438   1.1  kiyohara 	{
    439   1.1  kiyohara 		u_char *tba;
    440   1.1  kiyohara 		int tbc;
    441   1.1  kiyohara 
    442   1.1  kiyohara 		tba = tp->t_outq.c_cf;
    443   1.1  kiyohara 		tbc = ndqb(&tp->t_outq, 0);
    444   1.1  kiyohara 
    445   1.1  kiyohara 		(void)splserial();
    446   1.1  kiyohara 
    447   1.1  kiyohara 		sc->sc_tba = tba;
    448   1.1  kiyohara 		sc->sc_tbc = tbc;
    449   1.1  kiyohara 	}
    450   1.1  kiyohara 
    451   1.1  kiyohara 	SET(tp->t_state, TS_BUSY);
    452   1.1  kiyohara 
    453   1.1  kiyohara 	if (sc->sc_ih[CLPSCOM_TXINT] == NULL) {
    454   1.1  kiyohara 		sc->sc_ih[CLPSCOM_TXINT] =
    455   1.1  kiyohara 		    intr_establish(sc->sc_irq[CLPSCOM_TXINT], IPL_SERIAL, 0,
    456   1.1  kiyohara 		    clpscom_txintr, sc);
    457   1.1  kiyohara 		if (sc->sc_ih[CLPSCOM_TXINT] == NULL)
    458   1.1  kiyohara 			printf("%s: can't establish tx interrupt\n",
    459   1.1  kiyohara 			    device_xname(sc->sc_dev));
    460   1.1  kiyohara 
    461   1.1  kiyohara 		/* Output the first chunk of the contiguous buffer. */
    462   1.7  riastrad 		n = uimin(sc->sc_tbc, UART_FIFO_SIZE);
    463   1.1  kiyohara 		CLPSCOM_WRITE_MULTI(sc, sc->sc_tba, n);
    464   1.1  kiyohara 		sc->sc_tba += n;
    465   1.1  kiyohara 		sc->sc_tbc -= n;
    466   1.1  kiyohara 	}
    467   1.1  kiyohara out:
    468   1.1  kiyohara 	splx(s);
    469   1.1  kiyohara 	return;
    470   1.1  kiyohara }
    471   1.1  kiyohara 
    472   1.1  kiyohara static int
    473   1.1  kiyohara clpscom_param(struct tty *tp, struct termios *t)
    474   1.1  kiyohara {
    475   1.1  kiyohara 	struct clpscom_softc *sc =
    476   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(tp->t_dev));
    477   1.1  kiyohara 	int s;
    478   1.1  kiyohara 
    479   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    480   1.1  kiyohara 		return ENXIO;
    481   1.1  kiyohara 	if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
    482   1.1  kiyohara 		return EINVAL;
    483   1.1  kiyohara 
    484   1.1  kiyohara 	/*
    485   1.1  kiyohara 	 * For the console, always force CLOCAL and !HUPCL, so that the port
    486   1.1  kiyohara 	 * is always active.
    487   1.1  kiyohara 	 */
    488   1.1  kiyohara 	if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
    489   1.1  kiyohara 	    ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    490   1.1  kiyohara 		SET(t->c_cflag, CLOCAL);
    491   1.1  kiyohara 		CLR(t->c_cflag, HUPCL);
    492   1.1  kiyohara 	}
    493   1.1  kiyohara 
    494   1.1  kiyohara 	/*
    495   1.1  kiyohara 	 * If there were no changes, don't do anything.  This avoids dropping
    496   1.1  kiyohara 	 * input and improves performance when all we did was frob things like
    497   1.1  kiyohara 	 * VMIN and VTIME.
    498   1.1  kiyohara 	 */
    499   1.1  kiyohara 	if (tp->t_ospeed == t->c_ospeed &&
    500   1.1  kiyohara 	    tp->t_cflag == t->c_cflag)
    501   1.1  kiyohara 		return 0;
    502   1.1  kiyohara 
    503   1.1  kiyohara 	/*
    504   1.1  kiyohara 	 * If we're not in a mode that assumes a connection is present, then
    505   1.1  kiyohara 	 * ignore carrier changes.
    506   1.1  kiyohara 	 */
    507   1.1  kiyohara 	if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
    508   1.1  kiyohara 		sc->sc_ms_dcd = 0;
    509   1.1  kiyohara 	else
    510   1.1  kiyohara 		sc->sc_ms_dcd = SYSFLG_DCD;
    511   1.1  kiyohara 	/*
    512   1.1  kiyohara 	 * Set the flow control pins depending on the current flow control
    513   1.1  kiyohara 	 * mode.
    514   1.1  kiyohara 	 */
    515   1.1  kiyohara 	if (ISSET(t->c_cflag, CRTSCTS)) {
    516   1.1  kiyohara 		sc->sc_ms_cts = SYSFLG_CTS;
    517   1.1  kiyohara 	} else if (ISSET(t->c_cflag, MDMBUF)) {
    518   1.1  kiyohara 		/*
    519   1.1  kiyohara 		 * For DTR/DCD flow control, make sure we don't toggle DTR for
    520   1.1  kiyohara 		 * carrier detection.
    521   1.1  kiyohara 		 */
    522   1.1  kiyohara 		sc->sc_ms_cts = SYSFLG_DCD;
    523   1.1  kiyohara 	} else {
    524   1.1  kiyohara 		/*
    525   1.1  kiyohara 		 * If no flow control, then always set RTS.  This will make
    526   1.1  kiyohara 		 * the other side happy if it mistakenly thinks we're doing
    527   1.1  kiyohara 		 * RTS/CTS flow control.
    528   1.1  kiyohara 		 */
    529   1.1  kiyohara 		sc->sc_ms_cts = 0;
    530   1.1  kiyohara 	}
    531   1.1  kiyohara 	sc->sc_ms_mask = sc->sc_ms_cts | sc->sc_ms_dcd;
    532   1.1  kiyohara 
    533   1.1  kiyohara 	s = splserial();
    534   1.1  kiyohara 	CLPSCOM_WRITE_UBRLCR(sc,
    535   1.1  kiyohara 	    UBRLCR_FIFOEN |
    536   1.1  kiyohara 	    clpscom_rate2ubrlcr(t->c_ospeed) |
    537   1.1  kiyohara 	    clpscom_cflag2ubrlcr(t->c_cflag));
    538   1.1  kiyohara 
    539   1.1  kiyohara 	/* And copy to tty. */
    540   1.1  kiyohara 	tp->t_ispeed = 0;
    541   1.1  kiyohara 	tp->t_ospeed = t->c_ospeed;
    542   1.1  kiyohara 	tp->t_cflag = t->c_cflag;
    543   1.1  kiyohara 	splx(s);
    544   1.1  kiyohara 
    545   1.1  kiyohara 	/*
    546   1.1  kiyohara 	 * Update the tty layer's idea of the carrier bit, in case we changed
    547   1.1  kiyohara 	 * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
    548   1.1  kiyohara 	 * explicit request.
    549   1.1  kiyohara 	 */
    550   1.1  kiyohara 	(*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_ms, SYSFLG_DCD));
    551   1.1  kiyohara 
    552   1.1  kiyohara 	if (!ISSET(t->c_cflag, CHWFLOW))
    553   1.1  kiyohara 		if (sc->sc_tx_stopped) {
    554   1.1  kiyohara 			sc->sc_tx_stopped = 0;
    555   1.1  kiyohara 			clpscom_start(tp);
    556   1.1  kiyohara 		}
    557   1.1  kiyohara 
    558   1.1  kiyohara 	return 0;
    559   1.1  kiyohara }
    560   1.1  kiyohara 
    561   1.1  kiyohara static int
    562   1.1  kiyohara clpscom_hwiflow(struct tty *tp, int block)
    563   1.1  kiyohara {
    564   1.1  kiyohara 	/* Nothing */
    565   1.1  kiyohara 	return 0;
    566   1.1  kiyohara }
    567   1.1  kiyohara 
    568   1.1  kiyohara /* ARGSUSED */
    569   1.1  kiyohara int
    570   1.1  kiyohara clpscomopen(dev_t dev, int flag, int mode, struct lwp *l)
    571   1.1  kiyohara {
    572   1.1  kiyohara 	struct clpscom_softc *sc;
    573   1.1  kiyohara 	struct tty *tp;
    574   1.1  kiyohara 	int error, s, s2;
    575   1.1  kiyohara 
    576   1.1  kiyohara 	sc = device_lookup_private(&clpscom_cd, COMUNIT(dev));
    577   1.1  kiyohara 	if (sc == NULL || !ISSET(sc->sc_hwflags, COM_HW_DEV_OK))
    578   1.1  kiyohara 		return ENXIO;
    579   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    580   1.1  kiyohara 		return ENXIO;
    581   1.1  kiyohara 
    582   1.1  kiyohara #ifdef KGDB
    583   1.1  kiyohara 	/*
    584   1.1  kiyohara 	 * If this is the kgdb port, no other use is permitted.
    585   1.1  kiyohara 	 */
    586   1.1  kiyohara 	if (ISSET(sc->sc_hwflags, COM_HW_KGDB))
    587   1.1  kiyohara 		return EBUSY;
    588   1.1  kiyohara #endif
    589   1.1  kiyohara 
    590   1.1  kiyohara 	tp = sc->sc_tty;
    591   1.1  kiyohara 
    592   1.1  kiyohara 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    593   1.1  kiyohara 		return EBUSY;
    594   1.1  kiyohara 
    595   1.1  kiyohara 	s = spltty();
    596   1.1  kiyohara 
    597   1.1  kiyohara 	/*
    598   1.1  kiyohara 	 * Do the following iff this is a first open.
    599   1.1  kiyohara 	 */
    600   1.1  kiyohara 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    601   1.1  kiyohara 		struct termios t;
    602   1.1  kiyohara 
    603   1.1  kiyohara 		tp->t_dev = dev;
    604   1.1  kiyohara 
    605   1.1  kiyohara 		/* Enable and turn on interrupt */
    606   1.1  kiyohara 		CLPSCOM_WRITE_CON(sc, CLPSCOM_READ_CON(sc) | SYSCON_UARTEN);
    607   1.1  kiyohara 
    608   1.1  kiyohara 		/* Fetch the current modem control status, needed later. */
    609   1.1  kiyohara 		sc->sc_ms = CLPSCOM_READ_FLG(sc) & CLPSCOM_MODEM_STATUS_MASK;
    610   1.1  kiyohara 
    611   1.1  kiyohara 		/*
    612   1.1  kiyohara 		 * Initialize the termios status to the defaults.  Add in the
    613   1.1  kiyohara 		 * sticky bits from TIOCSFLAGS.
    614   1.1  kiyohara 		 */
    615   1.1  kiyohara 		t.c_ispeed = 0;
    616   1.1  kiyohara 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
    617   1.1  kiyohara 			t.c_ospeed = clpscom_cnrate;
    618   1.1  kiyohara 			t.c_cflag = clpscom_cncflag;
    619   1.1  kiyohara 		} else {
    620   1.1  kiyohara 			t.c_ospeed = TTYDEF_SPEED;
    621   1.1  kiyohara 			t.c_cflag = TTYDEF_CFLAG;
    622   1.1  kiyohara 		}
    623   1.1  kiyohara 		if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
    624   1.1  kiyohara 			SET(t.c_cflag, CLOCAL);
    625   1.1  kiyohara 		if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
    626   1.1  kiyohara 			SET(t.c_cflag, CRTSCTS);
    627   1.1  kiyohara 		if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
    628   1.1  kiyohara 			SET(t.c_cflag, MDMBUF);
    629   1.1  kiyohara 		/* Make sure pscom_param() we do something */
    630   1.1  kiyohara 		tp->t_ospeed = 0;
    631   1.1  kiyohara 		clpscom_param(tp, &t);
    632   1.1  kiyohara 		tp->t_iflag = TTYDEF_IFLAG;
    633   1.1  kiyohara 		tp->t_oflag = TTYDEF_OFLAG;
    634   1.1  kiyohara 		tp->t_lflag = TTYDEF_LFLAG;
    635   1.1  kiyohara 		ttychars(tp);
    636   1.1  kiyohara 		ttsetwater(tp);
    637   1.1  kiyohara 
    638   1.1  kiyohara 		s2 = splserial();
    639   1.1  kiyohara 
    640   1.1  kiyohara 		/* Clear the input ring. */
    641   1.1  kiyohara 		sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
    642   1.1  kiyohara 		sc->sc_rbavail = CLPSCOM_RING_SIZE;
    643   1.1  kiyohara 		clpscom_iflush(sc);
    644   1.1  kiyohara 
    645   1.1  kiyohara 		splx(s2);
    646   1.1  kiyohara 	}
    647   1.1  kiyohara 
    648   1.1  kiyohara 	splx(s);
    649   1.1  kiyohara 
    650   1.1  kiyohara 	error = ttyopen(tp, COMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
    651   1.1  kiyohara 	if (error)
    652   1.1  kiyohara 		goto bad;
    653   1.1  kiyohara 
    654   1.1  kiyohara 	error = (*tp->t_linesw->l_open)(dev, tp);
    655   1.1  kiyohara 	if (error)
    656   1.1  kiyohara 		goto bad;
    657   1.1  kiyohara 	return 0;
    658   1.1  kiyohara 
    659   1.1  kiyohara bad:
    660   1.1  kiyohara 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    661   1.1  kiyohara 		/*
    662   1.1  kiyohara 		 * We failed to open the device, and nobody else had it opened.
    663   1.1  kiyohara 		 * Clean up the state as appropriate.
    664   1.1  kiyohara 		 */
    665   1.1  kiyohara 		clpscom_shutdown(sc);
    666   1.1  kiyohara 
    667   1.1  kiyohara 		/* Disable UART */
    668   1.1  kiyohara 		if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
    669   1.1  kiyohara 			CLPSCOM_WRITE_CON(sc,
    670   1.1  kiyohara 			    CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN);
    671   1.1  kiyohara 	}
    672   1.1  kiyohara 
    673   1.1  kiyohara 	return error;
    674   1.1  kiyohara }
    675   1.1  kiyohara 
    676   1.1  kiyohara /* ARGSUSED */
    677   1.1  kiyohara int
    678   1.1  kiyohara clpscomclose(dev_t dev, int flag, int mode, struct lwp *l)
    679   1.1  kiyohara {
    680   1.1  kiyohara 	struct clpscom_softc *sc =
    681   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
    682   1.1  kiyohara 	struct tty *tp = sc->sc_tty;
    683   1.1  kiyohara 
    684   1.1  kiyohara 	/* XXXX This is for cons.c. */
    685   1.1  kiyohara 	if (!ISSET(tp->t_state, TS_ISOPEN))
    686   1.1  kiyohara 		return 0;
    687   1.1  kiyohara 
    688   1.1  kiyohara 	(*tp->t_linesw->l_close)(tp, flag);
    689   1.1  kiyohara 	ttyclose(tp);
    690   1.1  kiyohara 
    691   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    692   1.1  kiyohara 		return 0;
    693   1.1  kiyohara 
    694   1.1  kiyohara 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    695   1.1  kiyohara 		/*
    696   1.1  kiyohara 		 * Although we got a last close, the device may still be in
    697   1.1  kiyohara 		 * use; e.g. if this was the dialout node, and there are still
    698   1.1  kiyohara 		 * processes waiting for carrier on the non-dialout node.
    699   1.1  kiyohara 		 */
    700   1.1  kiyohara 		clpscom_shutdown(sc);
    701   1.1  kiyohara 
    702   1.1  kiyohara 		/* Disable UART */
    703   1.1  kiyohara 		if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
    704   1.1  kiyohara 			CLPSCOM_WRITE_CON(sc,
    705   1.1  kiyohara 			    CLPSCOM_READ_CON(sc) & ~SYSCON_UARTEN);
    706   1.1  kiyohara 	}
    707   1.1  kiyohara 
    708   1.1  kiyohara 	return 0;
    709   1.1  kiyohara }
    710   1.1  kiyohara 
    711   1.1  kiyohara int
    712   1.1  kiyohara clpscomread(dev_t dev, struct uio *uio, int flag)
    713   1.1  kiyohara {
    714   1.1  kiyohara 	struct clpscom_softc *sc =
    715   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
    716   1.1  kiyohara 	struct tty *tp = sc->sc_tty;
    717   1.1  kiyohara 
    718   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    719   1.1  kiyohara 		return EIO;
    720   1.1  kiyohara 
    721   1.1  kiyohara 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    722   1.1  kiyohara }
    723   1.1  kiyohara 
    724   1.1  kiyohara int
    725   1.1  kiyohara clpscomwrite(dev_t dev, struct uio *uio, int flag)
    726   1.1  kiyohara {
    727   1.1  kiyohara 	struct clpscom_softc *sc =
    728   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
    729   1.1  kiyohara 	struct tty *tp = sc->sc_tty;
    730   1.1  kiyohara 
    731   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    732   1.1  kiyohara 		return EIO;
    733   1.1  kiyohara 
    734   1.1  kiyohara 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    735   1.1  kiyohara }
    736   1.1  kiyohara 
    737   1.1  kiyohara int
    738   1.1  kiyohara clpscomioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    739   1.1  kiyohara {
    740   1.1  kiyohara 	struct clpscom_softc *sc =
    741   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
    742   1.1  kiyohara 	struct tty *tp = sc->sc_tty;
    743   1.1  kiyohara 	int error, s;
    744   1.1  kiyohara 
    745   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    746   1.1  kiyohara 		return EIO;
    747   1.1  kiyohara 
    748   1.1  kiyohara 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    749   1.1  kiyohara 	if (error != EPASSTHROUGH)
    750   1.1  kiyohara 		return error;
    751   1.1  kiyohara 
    752   1.1  kiyohara 	error = ttioctl(tp, cmd, data, flag, l);
    753   1.1  kiyohara 	if (error != EPASSTHROUGH)
    754   1.1  kiyohara 		return error;
    755   1.1  kiyohara 
    756   1.1  kiyohara 	switch (cmd) {
    757   1.1  kiyohara 	case TIOCSFLAGS:
    758   1.1  kiyohara 		error = kauth_authorize_device_tty(l->l_cred,
    759   1.1  kiyohara 		    KAUTH_DEVICE_TTY_PRIVSET, tp);
    760   1.1  kiyohara 		break;
    761   1.1  kiyohara 	default:
    762   1.1  kiyohara 		break;
    763   1.1  kiyohara 	}
    764   1.1  kiyohara 	if (error)
    765   1.1  kiyohara 		return error;
    766   1.1  kiyohara 
    767   1.1  kiyohara 	s = splserial();
    768   1.1  kiyohara 	error = 0;
    769   1.1  kiyohara 	switch (cmd) {
    770   1.1  kiyohara 	case TIOCSBRK:
    771   1.1  kiyohara 		clpscom_break(sc, 1);
    772   1.1  kiyohara 		break;
    773   1.1  kiyohara 
    774   1.1  kiyohara 	case TIOCCBRK:
    775   1.1  kiyohara 		clpscom_break(sc, 0);
    776   1.1  kiyohara 		break;
    777   1.1  kiyohara 
    778   1.1  kiyohara 	case TIOCGFLAGS:
    779   1.1  kiyohara 		*(int *)data = sc->sc_swflags;
    780   1.1  kiyohara 		break;
    781   1.1  kiyohara 
    782   1.1  kiyohara 	case TIOCSFLAGS:
    783   1.1  kiyohara 		sc->sc_swflags = *(int *)data;
    784   1.1  kiyohara 		break;
    785   1.1  kiyohara 
    786   1.1  kiyohara 	case TIOCMGET:
    787   1.1  kiyohara 		*(int *)data = clpscom_to_tiocm(sc);
    788   1.1  kiyohara 		break;
    789   1.1  kiyohara 
    790   1.1  kiyohara 	default:
    791   1.1  kiyohara 		error = EPASSTHROUGH;
    792   1.1  kiyohara 		break;
    793   1.1  kiyohara 	}
    794   1.1  kiyohara 	splx(s);
    795   1.1  kiyohara 	return error;
    796   1.1  kiyohara }
    797   1.1  kiyohara 
    798   1.1  kiyohara int
    799   1.1  kiyohara clpscompoll(dev_t dev, int events, struct lwp *l)
    800   1.1  kiyohara {
    801   1.1  kiyohara 	struct clpscom_softc *sc =
    802   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
    803   1.1  kiyohara 	struct tty *tp = sc->sc_tty;
    804   1.1  kiyohara 
    805   1.1  kiyohara 	if (!device_is_active(sc->sc_dev))
    806   1.1  kiyohara 		return EIO;
    807   1.1  kiyohara 
    808   1.1  kiyohara 	return (*tp->t_linesw->l_poll)(tp, events, l);
    809   1.1  kiyohara }
    810   1.1  kiyohara 
    811   1.1  kiyohara struct tty *
    812   1.1  kiyohara clpscomtty(dev_t dev)
    813   1.1  kiyohara {
    814   1.1  kiyohara 	struct clpscom_softc *sc =
    815   1.1  kiyohara 	    device_lookup_private(&clpscom_cd, COMUNIT(dev));
    816   1.1  kiyohara 
    817   1.1  kiyohara 	return sc->sc_tty;
    818   1.1  kiyohara }
    819   1.1  kiyohara 
    820   1.1  kiyohara void
    821   1.1  kiyohara clpscomstop(struct tty *tp, int flag)
    822   1.1  kiyohara {
    823   1.1  kiyohara 	int s;
    824   1.1  kiyohara 
    825   1.1  kiyohara 	s = splserial();
    826   1.1  kiyohara 	if (ISSET(tp->t_state, TS_BUSY)) {
    827   1.1  kiyohara 		/* Stop transmitting at the next chunk. */
    828   1.1  kiyohara 		if (!ISSET(tp->t_state, TS_TTSTOP))
    829   1.1  kiyohara 			SET(tp->t_state, TS_FLUSH);
    830   1.1  kiyohara 	}
    831   1.1  kiyohara 	splx(s);
    832   1.1  kiyohara }
    833   1.1  kiyohara 
    834   1.1  kiyohara 
    835   1.1  kiyohara static void
    836   1.1  kiyohara clpscom_iflush(struct clpscom_softc *sc)
    837   1.1  kiyohara {
    838   1.1  kiyohara 	int timo;
    839   1.1  kiyohara 
    840   1.1  kiyohara 	timo = 50000;
    841   1.1  kiyohara 	while ((CLPSCOM_READ_FLG(sc) & SYSFLG_URXFE) == 0
    842   1.1  kiyohara 	    && timo--)
    843   1.1  kiyohara 		CLPSCOM_READ(sc);
    844   1.1  kiyohara 	if (timo == 0)
    845   1.1  kiyohara 		printf("%s: iflush timeout\n", device_xname(sc->sc_dev));
    846   1.1  kiyohara }
    847   1.1  kiyohara 
    848   1.1  kiyohara static void
    849   1.1  kiyohara clpscom_shutdown(struct clpscom_softc *sc)
    850   1.1  kiyohara {
    851   1.1  kiyohara 	int s;
    852   1.1  kiyohara 
    853   1.1  kiyohara 	s = splserial();
    854   1.1  kiyohara 
    855   1.1  kiyohara 	/* Turn off all interrupts */
    856   1.1  kiyohara 	if (sc->sc_ih[CLPSCOM_TXINT] != NULL)
    857   1.1  kiyohara 		intr_disestablish(sc->sc_ih[CLPSCOM_TXINT]);
    858   1.1  kiyohara 	sc->sc_ih[CLPSCOM_TXINT] = NULL;
    859   1.1  kiyohara 	if (sc->sc_ih[CLPSCOM_RXINT] != NULL)
    860   1.1  kiyohara 		intr_disestablish(sc->sc_ih[CLPSCOM_RXINT]);
    861   1.1  kiyohara 	sc->sc_ih[CLPSCOM_RXINT] = NULL;
    862   1.1  kiyohara 	if (sc->sc_ih[CLPSCOM_MSINT] != NULL)
    863   1.1  kiyohara 		intr_disestablish(sc->sc_ih[CLPSCOM_MSINT]);
    864   1.1  kiyohara 	sc->sc_ih[CLPSCOM_MSINT] = NULL;
    865   1.1  kiyohara 
    866   1.1  kiyohara 	/* Clear any break condition set with TIOCSBRK. */
    867   1.1  kiyohara 	clpscom_break(sc, 0);
    868   1.1  kiyohara 
    869   1.1  kiyohara 	splx(s);
    870   1.1  kiyohara }
    871   1.1  kiyohara 
    872   1.1  kiyohara static void
    873   1.1  kiyohara clpscom_break(struct clpscom_softc *sc, int onoff)
    874   1.1  kiyohara {
    875   1.1  kiyohara 	int s;
    876   1.1  kiyohara 	uint8_t ubrlcr;
    877   1.1  kiyohara 
    878   1.1  kiyohara 	s = splserial();
    879   1.1  kiyohara 	ubrlcr = CLPSCOM_READ_UBRLCR(sc);
    880   1.1  kiyohara 	if (onoff)
    881   1.1  kiyohara 		SET(ubrlcr, UBRLCR_BREAK);
    882   1.1  kiyohara 	else
    883   1.1  kiyohara 		CLR(ubrlcr, UBRLCR_BREAK);
    884   1.1  kiyohara 	CLPSCOM_WRITE_UBRLCR(sc, ubrlcr);
    885   1.1  kiyohara 	splx(s);
    886   1.1  kiyohara }
    887   1.1  kiyohara 
    888   1.1  kiyohara static int
    889   1.1  kiyohara clpscom_to_tiocm(struct clpscom_softc *sc)
    890   1.1  kiyohara {
    891   1.1  kiyohara 	uint32_t combits;
    892   1.1  kiyohara 	int ttybits = 0;
    893   1.1  kiyohara 
    894   1.1  kiyohara 	combits = sc->sc_ms;
    895   1.1  kiyohara 	if (ISSET(combits, SYSFLG_DCD))
    896   1.1  kiyohara 		SET(ttybits, TIOCM_CD);
    897   1.1  kiyohara 	if (ISSET(combits, SYSFLG_CTS))
    898   1.1  kiyohara 		SET(ttybits, TIOCM_CTS);
    899   1.1  kiyohara 	if (ISSET(combits, SYSFLG_DSR))
    900   1.1  kiyohara 		SET(ttybits, TIOCM_DSR);
    901   1.1  kiyohara 
    902   1.1  kiyohara 	return ttybits;
    903   1.1  kiyohara }
    904   1.1  kiyohara 
    905   1.1  kiyohara static void
    906   1.1  kiyohara clpscom_rxsoft(struct clpscom_softc *sc, struct tty *tp)
    907   1.1  kiyohara {
    908   1.1  kiyohara 	int code, s;
    909   1.1  kiyohara 	u_int cc, scc;
    910   1.1  kiyohara 	u_char sts, *get;
    911   1.1  kiyohara 
    912   1.1  kiyohara 	get = sc->sc_rbget;
    913   1.1  kiyohara 	scc = cc = CLPSCOM_RING_SIZE - sc->sc_rbavail;
    914   1.1  kiyohara 	while (cc) {
    915   1.1  kiyohara 		code = get[0];
    916   1.1  kiyohara 		sts = get[1];
    917   1.1  kiyohara 		if (ISSET(sts, UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)) {
    918   1.1  kiyohara 			if (ISSET(sts, (UARTDR_FRMERR)))
    919   1.1  kiyohara 				SET(code, TTY_FE);
    920   1.1  kiyohara 			if (ISSET(sts, UARTDR_PARERR))
    921   1.1  kiyohara 				SET(code, TTY_PE);
    922   1.1  kiyohara 			if (ISSET(sts, UARTDR_OVERR))
    923   1.1  kiyohara 				;		/* XXXXX: Overrun */
    924   1.1  kiyohara 		}
    925   1.1  kiyohara 		if ((*tp->t_linesw->l_rint)(code, tp) == -1) {
    926   1.1  kiyohara 			/*
    927   1.1  kiyohara 			 * The line discipline's buffer is out of space.
    928   1.1  kiyohara 			 */
    929   1.1  kiyohara 			/*
    930   1.1  kiyohara 			 * We're either not using flow control, or the
    931   1.1  kiyohara 			 * line discipline didn't tell us to block for
    932   1.1  kiyohara 			 * some reason.  Either way, we have no way to
    933   1.1  kiyohara 			 * know when there's more space available, so
    934   1.1  kiyohara 			 * just drop the rest of the data.
    935   1.1  kiyohara 			 */
    936   1.1  kiyohara 			get += cc << 1;
    937   1.1  kiyohara 			if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1))
    938   1.1  kiyohara 				get -= (CLPSCOM_RING_SIZE << 1);
    939   1.1  kiyohara 			cc = 0;
    940   1.1  kiyohara 			break;
    941   1.1  kiyohara 		}
    942   1.1  kiyohara 		get += 2;
    943   1.1  kiyohara 		if (get >= sc->sc_rbuf + (CLPSCOM_RING_SIZE << 1))
    944   1.1  kiyohara 			get = sc->sc_rbuf;
    945   1.1  kiyohara 		cc--;
    946   1.1  kiyohara 	}
    947   1.1  kiyohara 
    948   1.1  kiyohara 	if (cc != scc) {
    949   1.1  kiyohara 		sc->sc_rbget = get;
    950   1.1  kiyohara 		s = splserial();
    951   1.1  kiyohara 
    952   1.1  kiyohara 		cc = sc->sc_rbavail += scc - cc;
    953   1.1  kiyohara 		/* Buffers should be ok again, release possible block. */
    954   1.1  kiyohara 		if (cc >= 1) {
    955   1.1  kiyohara 			if (sc->sc_ih[CLPSCOM_RXINT] == NULL) {
    956   1.1  kiyohara 				sc->sc_ih[CLPSCOM_RXINT] =
    957   1.1  kiyohara 				    intr_establish(sc->sc_irq[CLPSCOM_RXINT],
    958   1.1  kiyohara 				    IPL_SERIAL, 0, clpscom_rxintr, sc);
    959   1.1  kiyohara 				if (sc->sc_ih[CLPSCOM_RXINT] == NULL)
    960   1.1  kiyohara 					printf("%s: can't establish"
    961   1.1  kiyohara 					    " rx interrupt\n",
    962   1.1  kiyohara 					    device_xname(sc->sc_dev));
    963   1.1  kiyohara 			}
    964   1.1  kiyohara 			if (sc->sc_ih[CLPSCOM_MSINT] == NULL) {
    965   1.1  kiyohara 				sc->sc_ih[CLPSCOM_MSINT] =
    966   1.1  kiyohara 				    intr_establish(sc->sc_irq[CLPSCOM_MSINT],
    967   1.1  kiyohara 				    IPL_SERIAL, 0, clpscom_msintr, sc);
    968   1.1  kiyohara 				if (sc->sc_ih[CLPSCOM_MSINT] == NULL)
    969   1.1  kiyohara 					printf("%s: can't establish"
    970   1.1  kiyohara 					    " ms interrupt\n",
    971   1.1  kiyohara 					    device_xname(sc->sc_dev));
    972   1.1  kiyohara 			}
    973   1.1  kiyohara 		}
    974   1.1  kiyohara 		splx(s);
    975   1.1  kiyohara 	}
    976   1.1  kiyohara }
    977   1.1  kiyohara 
    978   1.1  kiyohara static void
    979   1.1  kiyohara clpscom_mssoft(struct clpscom_softc *sc, struct tty *tp)
    980   1.1  kiyohara {
    981   1.1  kiyohara 	uint32_t ms, delta;
    982   1.1  kiyohara 
    983   1.1  kiyohara 	ms = sc->sc_ms;
    984   1.1  kiyohara 	delta = sc->sc_ms_delta;
    985   1.1  kiyohara 	sc->sc_ms_delta = 0;
    986   1.1  kiyohara 
    987   1.1  kiyohara 	if (ISSET(delta, sc->sc_ms_dcd))
    988   1.1  kiyohara 		/*
    989   1.1  kiyohara 		 * Inform the tty layer that carrier detect changed.
    990   1.1  kiyohara 		 */
    991   1.1  kiyohara 		(void) (*tp->t_linesw->l_modem)(tp, ISSET(ms, SYSFLG_DCD));
    992   1.1  kiyohara 
    993   1.1  kiyohara 	if (ISSET(delta, sc->sc_ms_cts)) {
    994   1.1  kiyohara 		/* Block or unblock output according to flow control. */
    995   1.1  kiyohara 		if (ISSET(ms, sc->sc_ms_cts)) {
    996   1.1  kiyohara 			sc->sc_tx_stopped = 0;
    997   1.1  kiyohara 			(*tp->t_linesw->l_start)(tp);
    998   1.1  kiyohara 		} else
    999   1.1  kiyohara 			sc->sc_tx_stopped = 1;
   1000   1.1  kiyohara 	}
   1001   1.1  kiyohara }
   1002   1.1  kiyohara 
   1003   1.1  kiyohara static inline uint32_t
   1004   1.1  kiyohara clpscom_rate2ubrlcr(int rate)
   1005   1.1  kiyohara {
   1006   1.1  kiyohara 
   1007   1.1  kiyohara 	return 230400 / rate - 1;
   1008   1.1  kiyohara }
   1009   1.1  kiyohara 
   1010   1.1  kiyohara static uint32_t
   1011   1.1  kiyohara clpscom_cflag2ubrlcr(tcflag_t cflag)
   1012   1.1  kiyohara {
   1013   1.1  kiyohara 	int32_t ubrlcr = 0;
   1014   1.1  kiyohara 
   1015   1.1  kiyohara 	switch (cflag & CSIZE) {
   1016   1.1  kiyohara 	case CS5: SET(ubrlcr, UBRLCR_WRDLEN_5B); break;
   1017   1.1  kiyohara 	case CS6: SET(ubrlcr, UBRLCR_WRDLEN_6B); break;
   1018   1.1  kiyohara 	case CS7: SET(ubrlcr, UBRLCR_WRDLEN_7B); break;
   1019   1.1  kiyohara 	case CS8: SET(ubrlcr, UBRLCR_WRDLEN_8B); break;
   1020   1.1  kiyohara 	default:  SET(ubrlcr, UBRLCR_WRDLEN_8B); break;
   1021   1.1  kiyohara 	}
   1022   1.1  kiyohara 	if (cflag & CSTOPB)
   1023   1.1  kiyohara 		SET(ubrlcr, UBRLCR_XSTOP);
   1024   1.1  kiyohara 	if (cflag & PARENB) {
   1025   1.1  kiyohara 		SET(ubrlcr, (UBRLCR_PRTEN | UBRLCR_EVENPRT));
   1026   1.1  kiyohara 		if (cflag & PARODD)
   1027   1.1  kiyohara 			CLR(ubrlcr, UBRLCR_EVENPRT);
   1028   1.1  kiyohara 	}
   1029   1.1  kiyohara 	return ubrlcr;
   1030   1.1  kiyohara }
   1031   1.1  kiyohara 
   1032   1.1  kiyohara #define CLPSCOM_CNREAD() \
   1033   1.1  kiyohara 	(*(volatile uint32_t *)(clpscom_cnaddr + PS711X_UARTDR))
   1034   1.1  kiyohara #define CLPSCOM_CNWRITE(val) \
   1035   1.1  kiyohara 	(*(volatile uint8_t *)(clpscom_cnaddr + PS711X_UARTDR) = val)
   1036   1.1  kiyohara #define CLPSCOM_CNSTATUS() \
   1037   1.1  kiyohara 	(*(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG))
   1038   1.1  kiyohara 
   1039   1.1  kiyohara static struct consdev clpscomcons = {
   1040   1.1  kiyohara 	NULL, NULL, clpscom_cngetc, clpscom_cnputc, clpscom_cnpollc,
   1041   1.1  kiyohara 	NULL, NULL, NULL, NODEV, CN_NORMAL
   1042   1.1  kiyohara };
   1043   1.1  kiyohara 
   1044   1.1  kiyohara int
   1045   1.1  kiyohara clpscom_cnattach(vaddr_t addr, int rate, tcflag_t cflag)
   1046   1.1  kiyohara {
   1047   1.1  kiyohara 
   1048   1.1  kiyohara 	clpscom_cnaddr = addr;
   1049   1.1  kiyohara 	clpscom_cnrate = rate;
   1050   1.1  kiyohara 	clpscom_cncflag = cflag;
   1051   1.1  kiyohara 	*(volatile uint32_t *)(clpscom_cnaddr + PS711X_SYSFLG) |= SYSCON_UARTEN;
   1052   1.1  kiyohara 	*(volatile uint32_t *)(clpscom_cnaddr + PS711X_UBRLCR) =
   1053   1.1  kiyohara 	    UBRLCR_FIFOEN |
   1054   1.1  kiyohara 	    clpscom_cflag2ubrlcr(cflag) |
   1055   1.1  kiyohara 	    clpscom_rate2ubrlcr(rate);
   1056   1.1  kiyohara 
   1057   1.1  kiyohara 	cn_tab = &clpscomcons;
   1058   1.1  kiyohara 	cn_init_magic(&clpscom_cnm_state);
   1059   1.1  kiyohara 	cn_set_magic("\047\001");	/* default magic is BREAK */
   1060   1.1  kiyohara 
   1061   1.1  kiyohara 	return 0;
   1062   1.1  kiyohara }
   1063   1.1  kiyohara 
   1064   1.1  kiyohara /* ARGSUSED */
   1065   1.1  kiyohara static int
   1066   1.1  kiyohara clpscom_cngetc(dev_t dev)
   1067   1.1  kiyohara {
   1068   1.1  kiyohara 	int s = splserial();
   1069   1.1  kiyohara 	char ch;
   1070   1.1  kiyohara 
   1071   1.1  kiyohara 	while (CLPSCOM_CNSTATUS() & SYSFLG_URXFE);
   1072   1.1  kiyohara 
   1073   1.1  kiyohara 	ch = CLPSCOM_CNREAD();
   1074   1.1  kiyohara 
   1075  1.10  riastrad 	if (!db_active)
   1076  1.10  riastrad 		cn_check_magic(dev, ch, clpscom_cnm_state);
   1077   1.1  kiyohara 
   1078   1.1  kiyohara 	splx(s);
   1079   1.1  kiyohara 	return ch;
   1080   1.1  kiyohara }
   1081   1.1  kiyohara 
   1082   1.1  kiyohara /* ARGSUSED */
   1083   1.1  kiyohara static void
   1084   1.1  kiyohara clpscom_cnputc(dev_t dev, int c)
   1085   1.1  kiyohara {
   1086   1.1  kiyohara 	int s = splserial();
   1087   1.1  kiyohara 
   1088   1.1  kiyohara 	while (CLPSCOM_CNSTATUS() & SYSFLG_UTXFF);
   1089   1.1  kiyohara 
   1090   1.1  kiyohara 	CLPSCOM_CNWRITE(c);
   1091   1.1  kiyohara 
   1092   1.1  kiyohara 	/* Make sure output. */
   1093   1.1  kiyohara 	while (CLPSCOM_CNSTATUS() & SYSFLG_UBUSY);
   1094   1.1  kiyohara 
   1095   1.1  kiyohara 	splx(s);
   1096   1.1  kiyohara }
   1097   1.1  kiyohara 
   1098   1.1  kiyohara /* ARGSUSED */
   1099   1.1  kiyohara static void
   1100   1.1  kiyohara clpscom_cnpollc(dev_t dev, int on)
   1101   1.1  kiyohara {
   1102   1.1  kiyohara 	/* Nothing */
   1103   1.1  kiyohara }
   1104