Home | History | Annotate | Line # | Download | only in dev
      1  1.30   tsutsui /*	$NetBSD: zs_hb.c,v 1.30 2023/10/25 12:59:09 tsutsui Exp $	*/
      2   1.1    tsubai 
      3   1.1    tsubai /*-
      4   1.1    tsubai  * Copyright (c) 1996 The NetBSD Foundation, Inc.
      5   1.1    tsubai  * All rights reserved.
      6   1.1    tsubai  *
      7   1.1    tsubai  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1    tsubai  * by Gordon W. Ross.
      9   1.1    tsubai  *
     10   1.1    tsubai  * Redistribution and use in source and binary forms, with or without
     11   1.1    tsubai  * modification, are permitted provided that the following conditions
     12   1.1    tsubai  * are met:
     13   1.1    tsubai  * 1. Redistributions of source code must retain the above copyright
     14   1.1    tsubai  *    notice, this list of conditions and the following disclaimer.
     15   1.1    tsubai  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1    tsubai  *    notice, this list of conditions and the following disclaimer in the
     17   1.1    tsubai  *    documentation and/or other materials provided with the distribution.
     18   1.1    tsubai  *
     19   1.1    tsubai  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20   1.1    tsubai  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21   1.1    tsubai  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22   1.1    tsubai  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23   1.1    tsubai  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24   1.1    tsubai  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25   1.1    tsubai  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26   1.1    tsubai  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27   1.1    tsubai  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28   1.1    tsubai  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29   1.1    tsubai  * POSSIBILITY OF SUCH DAMAGE.
     30   1.1    tsubai  */
     31   1.1    tsubai 
     32   1.1    tsubai /*
     33   1.1    tsubai  * Zilog Z8530 Dual UART driver (machine-dependent part)
     34   1.1    tsubai  *
     35   1.1    tsubai  * Runs two serial lines per chip using slave drivers.
     36   1.1    tsubai  * Plain tty/async lines use the zs_async slave.
     37   1.1    tsubai  * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves.
     38   1.1    tsubai  */
     39  1.17     lukem 
     40  1.17     lukem #include <sys/cdefs.h>
     41  1.30   tsutsui __KERNEL_RCSID(0, "$NetBSD: zs_hb.c,v 1.30 2023/10/25 12:59:09 tsutsui Exp $");
     42   1.1    tsubai 
     43   1.1    tsubai #include <sys/param.h>
     44   1.1    tsubai #include <sys/systm.h>
     45   1.1    tsubai #include <sys/device.h>
     46   1.1    tsubai #include <sys/tty.h>
     47   1.5   gehenna #include <sys/conf.h>
     48  1.23        ad #include <sys/cpu.h>
     49  1.23        ad #include <sys/intr.h>
     50   1.1    tsubai 
     51  1.27  christos #include <mips/locore.h>
     52  1.27  christos 
     53   1.1    tsubai #include <machine/adrsmap.h>
     54   1.1    tsubai #include <machine/z8530var.h>
     55   1.1    tsubai 
     56   1.1    tsubai #include <dev/cons.h>
     57   1.1    tsubai #include <dev/ic/z8530reg.h>
     58   1.1    tsubai 
     59  1.12   tsutsui #include <newsmips/dev/hbvar.h>
     60  1.12   tsutsui 
     61   1.1    tsubai #include "zsc.h"	/* NZSC */
     62   1.1    tsubai #define NZS NZSC
     63   1.1    tsubai 
     64   1.1    tsubai /* Make life easier for the initialized arrays here. */
     65   1.1    tsubai #if NZS < 2
     66   1.1    tsubai #undef  NZS
     67   1.1    tsubai #define NZS 2
     68   1.1    tsubai #endif
     69   1.1    tsubai 
     70   1.3    tsubai #define ZSCFLAG_EX	0x01	/* expansion board */
     71   1.3    tsubai 
     72   1.1    tsubai /*
     73   1.1    tsubai  * The news3400 provides a 4.9152 MHz clock to the ZS chips.
     74   1.1    tsubai  */
     75   1.3    tsubai #define PCLK	(9600 * 512)	/* PCLK pin input clock rate */
     76   1.3    tsubai #define PCLK_EX	(9600 * 384)
     77   1.1    tsubai 
     78   1.1    tsubai /*
     79   1.1    tsubai  * Define interrupt levels.
     80   1.1    tsubai  */
     81   1.1    tsubai #define ZSHARD_PRI 64
     82   1.1    tsubai 
     83   1.1    tsubai #define ZS_DELAY() {(void)*(volatile char *)INTEN1; delay(2);}
     84   1.1    tsubai 
     85   1.1    tsubai /* The layout of this is hardware-dependent (padding, order). */
     86   1.1    tsubai struct zschan {
     87  1.24   tsutsui 	volatile uint8_t zc_csr;	/* ctrl,status, and indirect access */
     88  1.24   tsutsui 	volatile uint8_t zc_data;	/* data */
     89   1.1    tsubai };
     90   1.1    tsubai struct zsdevice {
     91   1.1    tsubai 	/* Yes, they are backwards. */
     92   1.1    tsubai 	struct	zschan zs_chan_b;
     93   1.1    tsubai 	struct	zschan zs_chan_a;
     94   1.1    tsubai };
     95   1.1    tsubai 
     96   1.1    tsubai extern int zs_def_cflag;
     97   1.1    tsubai 
     98   1.1    tsubai static struct zsdevice *zsaddr[NZS];
     99   1.1    tsubai 
    100   1.1    tsubai /* Flags from cninit() */
    101   1.1    tsubai static int zs_hwflags[NZS][2];
    102   1.1    tsubai 
    103   1.1    tsubai /* Default speed for all channels */
    104   1.1    tsubai static int zs_defspeed = 9600;
    105   1.1    tsubai 
    106  1.24   tsutsui static uint8_t zs_init_reg[16] = {
    107   1.1    tsubai 	0,	/* 0: CMD (reset, etc.) */
    108   1.1    tsubai 	0,	/* 1: No interrupts yet. */
    109   1.1    tsubai 	ZSHARD_PRI,	/* IVECT */
    110   1.1    tsubai 	ZSWR3_RX_8 | ZSWR3_RX_ENABLE,
    111   1.1    tsubai 	ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP,
    112   1.1    tsubai 	ZSWR5_TX_8 | ZSWR5_TX_ENABLE,
    113   1.1    tsubai 	0,	/* 6: TXSYNC/SYNCLO */
    114   1.1    tsubai 	0,	/* 7: RXSYNC/SYNCHI */
    115   1.1    tsubai 	0,	/* 8: alias for data port */
    116   1.1    tsubai 	ZSWR9_MASTER_IE,
    117   1.1    tsubai 	0,	/*10: Misc. TX/RX control bits */
    118   1.1    tsubai 	ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD,
    119   1.3    tsubai 	((PCLK/32)/9600)-2,	/*12: BAUDLO (default=9600) */
    120   1.1    tsubai 	0,			/*13: BAUDHI (default=9600) */
    121   1.1    tsubai 	ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK,
    122   1.1    tsubai 	ZSWR15_BREAK_IE,
    123   1.1    tsubai };
    124   1.1    tsubai 
    125  1.18   tsutsui static struct zschan * zs_get_chan_addr(int, int);
    126  1.18   tsutsui static void zs_hb_delay(void);
    127  1.18   tsutsui static int zshard_hb(void *);
    128  1.18   tsutsui static int zs_getc(void *);
    129  1.18   tsutsui static void zs_putc(void *, int);
    130   1.1    tsubai 
    131   1.2    tsubai struct zschan *
    132  1.18   tsutsui zs_get_chan_addr(int zs_unit, int channel)
    133   1.1    tsubai {
    134   1.1    tsubai 	struct zsdevice *addr;
    135   1.1    tsubai 	struct zschan *zc;
    136   1.1    tsubai 
    137   1.1    tsubai 	if (zs_unit >= NZS)
    138   1.1    tsubai 		return NULL;
    139   1.1    tsubai 	addr = zsaddr[zs_unit];
    140   1.1    tsubai 	if (addr == NULL)
    141   1.1    tsubai 		return NULL;
    142   1.1    tsubai 	if (channel == 0) {
    143   1.1    tsubai 		zc = &addr->zs_chan_a;
    144   1.1    tsubai 	} else {
    145   1.1    tsubai 		zc = &addr->zs_chan_b;
    146   1.1    tsubai 	}
    147  1.18   tsutsui 	return zc;
    148   1.1    tsubai }
    149   1.1    tsubai 
    150  1.11   tsutsui static void
    151  1.18   tsutsui zs_hb_delay(void)
    152   1.1    tsubai {
    153  1.11   tsutsui 
    154   1.1    tsubai 	ZS_DELAY();
    155   1.1    tsubai }
    156   1.1    tsubai 
    157   1.1    tsubai /****************************************************************
    158   1.1    tsubai  * Autoconfig
    159   1.1    tsubai  ****************************************************************/
    160   1.1    tsubai 
    161   1.1    tsubai /* Definition of the driver for autoconfig. */
    162  1.24   tsutsui int zs_hb_match(device_t, cfdata_t, void *);
    163  1.24   tsutsui void zs_hb_attach(device_t, device_t, void *);
    164   1.1    tsubai 
    165  1.24   tsutsui CFATTACH_DECL_NEW(zsc_hb, sizeof(struct zsc_softc),
    166   1.7   thorpej     zs_hb_match, zs_hb_attach, NULL, NULL);
    167   1.1    tsubai 
    168   1.1    tsubai /*
    169   1.1    tsubai  * Is the zs chip present?
    170   1.1    tsubai  */
    171   1.1    tsubai int
    172  1.24   tsutsui zs_hb_match(device_t parent, cfdata_t cf, void *aux)
    173   1.1    tsubai {
    174  1.12   tsutsui 	struct hb_attach_args *ha = aux;
    175   1.1    tsubai 
    176  1.12   tsutsui 	if (strcmp(ha->ha_name, "zsc"))
    177   1.1    tsubai 		return 0;
    178   1.1    tsubai 
    179   1.1    tsubai 	/* This returns -1 on a fault (bus error). */
    180  1.12   tsutsui 	if (hb_badaddr((char *)ha->ha_addr, 1))
    181   1.1    tsubai 		return 0;
    182   1.1    tsubai 
    183   1.1    tsubai 	return 1;
    184   1.1    tsubai }
    185   1.1    tsubai 
    186   1.1    tsubai /*
    187   1.1    tsubai  * Attach a found zs.
    188   1.1    tsubai  *
    189   1.1    tsubai  * Match slave number to zs unit number, so that misconfiguration will
    190   1.1    tsubai  * not set up the keyboard as ttya, etc.
    191   1.1    tsubai  */
    192   1.1    tsubai void
    193  1.24   tsutsui zs_hb_attach(device_t parent, device_t self, void *aux)
    194   1.1    tsubai {
    195  1.24   tsutsui 	struct zsc_softc *zsc = device_private(self);
    196  1.12   tsutsui 	struct hb_attach_args *ha = aux;
    197   1.1    tsubai 	struct zsc_attach_args zsc_args;
    198   1.1    tsubai 	volatile struct zschan *zc;
    199   1.1    tsubai 	struct zs_chanstate *cs;
    200   1.1    tsubai 	int s, zs_unit, channel, intlevel;
    201   1.1    tsubai 
    202  1.24   tsutsui 	zsc->zsc_dev = self;
    203  1.24   tsutsui 	zs_unit = device_unit(self);
    204  1.12   tsutsui 	intlevel = ha->ha_level;
    205  1.12   tsutsui 	zsaddr[zs_unit] = (void *)ha->ha_addr;
    206   1.1    tsubai 
    207   1.1    tsubai 	if (intlevel == -1) {
    208   1.1    tsubai #if 0
    209  1.24   tsutsui 		aprint_error(": interrupt level not configured\n");
    210   1.1    tsubai 		return;
    211   1.1    tsubai #else
    212  1.24   tsutsui 		aprint_error(": interrupt level not configured; using");
    213   1.1    tsubai 		intlevel = 1;
    214   1.1    tsubai #endif
    215   1.1    tsubai 	}
    216   1.1    tsubai 
    217  1.30   tsutsui 	aprint_normal(" level %d\n", intlevel);
    218   1.1    tsubai 
    219   1.1    tsubai 	zs_delay = zs_hb_delay;
    220   1.1    tsubai 
    221   1.1    tsubai 	/*
    222   1.1    tsubai 	 * Initialize software state for each channel.
    223   1.1    tsubai 	 */
    224   1.1    tsubai 	for (channel = 0; channel < 2; channel++) {
    225   1.1    tsubai 		zsc_args.channel = channel;
    226   1.1    tsubai 		zsc_args.hwflags = zs_hwflags[zs_unit][channel];
    227   1.1    tsubai 		cs = &zsc->zsc_cs_store[channel];
    228   1.1    tsubai 		zsc->zsc_cs[channel] = cs;
    229   1.1    tsubai 
    230  1.22        ad 		zs_lock_init(cs);
    231   1.1    tsubai 		cs->cs_channel = channel;
    232   1.1    tsubai 		cs->cs_private = NULL;
    233   1.1    tsubai 		cs->cs_ops = &zsops_null;
    234  1.24   tsutsui 		if ((device_cfdata(self)->cf_flags & ZSCFLAG_EX) == 0)
    235   1.3    tsubai 			cs->cs_brg_clk = PCLK / 16;
    236   1.1    tsubai 		else
    237   1.3    tsubai 			cs->cs_brg_clk = PCLK_EX / 16;
    238   1.1    tsubai 
    239   1.1    tsubai 		zc = zs_get_chan_addr(zs_unit, channel);
    240   1.1    tsubai 		cs->cs_reg_csr  = &zc->zc_csr;
    241   1.1    tsubai 		cs->cs_reg_data = &zc->zc_data;
    242   1.1    tsubai 
    243  1.18   tsutsui 		memcpy(cs->cs_creg, zs_init_reg, 16);
    244  1.18   tsutsui 		memcpy(cs->cs_preg, zs_init_reg, 16);
    245   1.1    tsubai 
    246   1.1    tsubai 		/* XXX: Get these from the EEPROM instead? */
    247   1.1    tsubai 		/* XXX: See the mvme167 code.  Better. */
    248   1.1    tsubai 		if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE)
    249   1.1    tsubai 			cs->cs_defspeed = zs_get_speed(cs);
    250   1.1    tsubai 		else
    251   1.1    tsubai 			cs->cs_defspeed = zs_defspeed;
    252   1.1    tsubai 		cs->cs_defcflag = zs_def_cflag;
    253   1.1    tsubai 
    254   1.1    tsubai 		/* Make these correspond to cs_defcflag (-crtscts) */
    255   1.1    tsubai 		cs->cs_rr0_dcd = ZSRR0_DCD;
    256   1.1    tsubai 		cs->cs_rr0_cts = 0;
    257   1.1    tsubai 		cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS;
    258   1.1    tsubai 		cs->cs_wr5_rts = 0;
    259   1.1    tsubai 
    260   1.1    tsubai 		/*
    261   1.1    tsubai 		 * Clear the master interrupt enable.
    262   1.1    tsubai 		 * The INTENA is common to both channels,
    263   1.1    tsubai 		 * so just do it on the A channel.
    264   1.1    tsubai 		 */
    265   1.1    tsubai 		if (channel == 0) {
    266   1.1    tsubai 			zs_write_reg(cs, 9, 0);
    267   1.1    tsubai 		}
    268   1.1    tsubai 
    269   1.1    tsubai 		/*
    270   1.1    tsubai 		 * Look for a child driver for this channel.
    271   1.1    tsubai 		 * The child attach will setup the hardware.
    272   1.1    tsubai 		 */
    273  1.28   thorpej 		if (!config_found(self, (void *)&zsc_args, zs_print,
    274  1.29   thorpej 		    CFARGS_NONE)) {
    275   1.1    tsubai 			/* No sub-driver.  Just reset it. */
    276  1.24   tsutsui 			uint8_t reset = (channel == 0) ?
    277  1.24   tsutsui 			    ZSWR9_A_RESET : ZSWR9_B_RESET;
    278   1.1    tsubai 			s = splhigh();
    279   1.1    tsubai 			zs_write_reg(cs, 9, reset);
    280   1.1    tsubai 			splx(s);
    281   1.1    tsubai 		}
    282   1.1    tsubai 	}
    283   1.1    tsubai 
    284   1.1    tsubai 	/*
    285   1.1    tsubai 	 * Now safe to install interrupt handlers.  Note the arguments
    286   1.1    tsubai 	 * to the interrupt handlers aren't used.  Note, we only do this
    287   1.1    tsubai 	 * once since both SCCs interrupt at the same level and vector.
    288   1.1    tsubai 	 */
    289  1.26   tsutsui 	zsc->zsc_si = softint_establish(SOFTINT_SERIAL,
    290  1.26   tsutsui 	    (void (*)(void *))zsc_intr_soft, zsc);
    291  1.26   tsutsui 	hb_intr_establish(intlevel, INTST1_SCC, IPL_SERIAL, zshard_hb, zsc);
    292   1.1    tsubai 	/* XXX; evcnt_attach() ? */
    293   1.1    tsubai 
    294   1.1    tsubai 	/*
    295   1.1    tsubai 	 * Set the master interrupt enable and interrupt vector.
    296   1.1    tsubai 	 * (common to both channels, do it on A)
    297   1.1    tsubai 	 */
    298   1.1    tsubai 	cs = zsc->zsc_cs[0];
    299   1.1    tsubai 	s = splhigh();
    300   1.1    tsubai 	/* interrupt vector */
    301   1.1    tsubai 	zs_write_reg(cs, 2, zs_init_reg[2]);
    302   1.1    tsubai 	/* master interrupt control (enable) */
    303   1.1    tsubai 	zs_write_reg(cs, 9, zs_init_reg[9]);
    304   1.1    tsubai 	splx(s);
    305   1.1    tsubai }
    306   1.1    tsubai 
    307   1.1    tsubai static int
    308  1.18   tsutsui zshard_hb(void *arg)
    309   1.1    tsubai {
    310  1.14   tsutsui 	int rv;
    311  1.14   tsutsui 
    312   1.1    tsubai 	(void) *(volatile u_char *)SCCVECT;
    313  1.14   tsutsui 	rv = zshard(arg);
    314  1.14   tsutsui 
    315  1.14   tsutsui 	/* XXX news3400 sometimes losts zs interrupt */
    316  1.14   tsutsui 	if (rv)
    317  1.14   tsutsui 		zshard(arg);
    318   1.1    tsubai 
    319  1.14   tsutsui 	return rv;
    320   1.1    tsubai }
    321   1.1    tsubai 
    322   1.1    tsubai /*
    323   1.1    tsubai  * Polled input char.
    324   1.1    tsubai  */
    325   1.1    tsubai int
    326  1.18   tsutsui zs_getc(void *arg)
    327   1.1    tsubai {
    328  1.11   tsutsui 	volatile struct zschan *zc = arg;
    329  1.11   tsutsui 	int s, c, rr0;
    330   1.1    tsubai 
    331   1.1    tsubai 	s = splhigh();
    332   1.1    tsubai 	/* Wait for a character to arrive. */
    333   1.1    tsubai 	do {
    334   1.1    tsubai 		rr0 = zc->zc_csr;
    335   1.1    tsubai 		ZS_DELAY();
    336   1.1    tsubai 	} while ((rr0 & ZSRR0_RX_READY) == 0);
    337   1.1    tsubai 
    338   1.1    tsubai 	c = zc->zc_data;
    339   1.1    tsubai 	ZS_DELAY();
    340   1.1    tsubai 	splx(s);
    341   1.1    tsubai 
    342   1.1    tsubai 	/*
    343   1.1    tsubai 	 * This is used by the kd driver to read scan codes,
    344   1.1    tsubai 	 * so don't translate '\r' ==> '\n' here...
    345   1.1    tsubai 	 */
    346  1.18   tsutsui 	return c;
    347   1.1    tsubai }
    348   1.1    tsubai 
    349   1.1    tsubai /*
    350   1.1    tsubai  * Polled output char.
    351   1.1    tsubai  */
    352   1.1    tsubai void
    353  1.18   tsutsui zs_putc(void *arg, int c)
    354   1.1    tsubai {
    355  1.11   tsutsui 	volatile struct zschan *zc = arg;
    356  1.11   tsutsui 	int s, rr0;
    357   1.1    tsubai 
    358   1.1    tsubai 	s = splhigh();
    359   1.1    tsubai 	/* Wait for transmitter to become ready. */
    360   1.1    tsubai 	do {
    361   1.1    tsubai 		rr0 = zc->zc_csr;
    362   1.1    tsubai 		ZS_DELAY();
    363   1.1    tsubai 	} while ((rr0 & ZSRR0_TX_READY) == 0);
    364   1.1    tsubai 
    365   1.1    tsubai 	zc->zc_data = c;
    366   1.1    tsubai 	ZS_DELAY();
    367   1.1    tsubai 	splx(s);
    368   1.1    tsubai }
    369   1.1    tsubai 
    370   1.1    tsubai /*****************************************************************/
    371   1.1    tsubai 
    372  1.18   tsutsui static void zscnprobe(struct consdev *);
    373  1.18   tsutsui static void zscninit(struct consdev *);
    374  1.18   tsutsui static int  zscngetc(dev_t);
    375  1.18   tsutsui static void zscnputc(dev_t, int);
    376   1.1    tsubai 
    377   1.1    tsubai struct consdev consdev_zs = {
    378   1.1    tsubai 	zscnprobe,
    379   1.1    tsubai 	zscninit,
    380   1.1    tsubai 	zscngetc,
    381   1.1    tsubai 	zscnputc,
    382  1.11   tsutsui 	nullcnpollc,
    383  1.11   tsutsui 	NULL,
    384  1.11   tsutsui 	NULL,
    385   1.4   thorpej 	NULL,
    386  1.11   tsutsui 	NODEV,
    387  1.11   tsutsui 	CN_DEAD
    388   1.1    tsubai };
    389   1.1    tsubai 
    390  1.11   tsutsui static void
    391  1.18   tsutsui zscnprobe(struct consdev *cn)
    392   1.1    tsubai {
    393   1.1    tsubai }
    394   1.1    tsubai 
    395  1.11   tsutsui static void
    396  1.18   tsutsui zscninit(struct consdev *cn)
    397   1.1    tsubai {
    398   1.5   gehenna 	extern const struct cdevsw zstty_cdevsw;
    399   1.5   gehenna 
    400   1.5   gehenna 	cn->cn_dev = makedev(cdevsw_lookup_major(&zstty_cdevsw), 0);
    401   1.1    tsubai 	cn->cn_pri = CN_REMOTE;
    402   1.1    tsubai 	zs_hwflags[0][0] = ZS_HWFLAG_CONSOLE;
    403   1.1    tsubai }
    404   1.1    tsubai 
    405  1.11   tsutsui static int
    406  1.18   tsutsui zscngetc(dev_t dev)
    407   1.1    tsubai {
    408  1.11   tsutsui 
    409   1.1    tsubai 	return zs_getc((void *)SCCPORT0A);
    410   1.1    tsubai }
    411   1.1    tsubai 
    412  1.11   tsutsui static void
    413  1.18   tsutsui zscnputc(dev_t dev, int c)
    414   1.1    tsubai {
    415  1.11   tsutsui 
    416   1.1    tsubai 	zs_putc((void *)SCCPORT0A, c);
    417   1.1    tsubai }
    418