Home | History | Annotate | Line # | Download | only in dev
      1  1.11   thorpej /*	$NetBSD: scn.c,v 1.11 2023/12/20 15:29:07 thorpej Exp $ */
      2   1.1    rumble 
      3   1.1    rumble /*
      4   1.1    rumble  * Resurrected from the old pc532 port 1/18/2009.
      5   1.1    rumble  *
      6   1.1    rumble  * XXX- The locking in this is probably totally broken. I haven't attempted
      7   1.1    rumble  *      to get it right, but it seems to work okay anyhow.
      8   1.1    rumble  */
      9   1.1    rumble 
     10   1.1    rumble /*
     11   1.1    rumble  * Copyright (c) 1991, 1992, 1993
     12   1.1    rumble  *	The Regents of the University of California.  All rights reserved.
     13   1.1    rumble  *
     14   1.1    rumble  * Portions of this software were developed by the Computer Systems
     15   1.1    rumble  * Engineering group at Lawrence Berkeley Laboratory under DARPA
     16   1.1    rumble  * contract BG 91-66 and contributed to Berkeley.
     17   1.1    rumble  *
     18   1.1    rumble  * All advertising materials mentioning features or use of this software
     19   1.1    rumble  * must display the following acknowledgement:
     20   1.1    rumble  *	This product includes software developed by the University of
     21   1.1    rumble  *	California, Lawrence Berkeley Laboratory.
     22   1.1    rumble  *
     23   1.1    rumble  * Redistribution and use in source and binary forms, with or without
     24   1.1    rumble  * modification, are permitted provided that the following conditions
     25   1.1    rumble  * are met:
     26   1.1    rumble  * 1. Redistributions of source code must retain the above copyright
     27   1.1    rumble  *    notice, this list of conditions and the following disclaimer.
     28   1.1    rumble  * 2. Redistributions in binary form must reproduce the above copyright
     29   1.1    rumble  *    notice, this list of conditions and the following disclaimer in the
     30   1.1    rumble  *    documentation and/or other materials provided with the distribution.
     31   1.1    rumble  * 3. Neither the name of the University nor the names of its contributors
     32   1.1    rumble  *    may be used to endorse or promote products derived from this software
     33   1.1    rumble  *    without specific prior written permission.
     34   1.1    rumble  *
     35   1.1    rumble  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     36   1.1    rumble  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     37   1.1    rumble  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     38   1.1    rumble  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     39   1.1    rumble  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     40   1.1    rumble  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     41   1.1    rumble  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     42   1.1    rumble  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     43   1.1    rumble  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     44   1.1    rumble  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     45   1.1    rumble  * SUCH DAMAGE.
     46   1.1    rumble  *
     47   1.1    rumble  *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
     48   1.1    rumble  */
     49   1.1    rumble 
     50   1.1    rumble /*
     51   1.1    rumble  * Copyright (c) 1996, 1997 Philip L. Budne.
     52   1.1    rumble  * Copyright (c) 1993 Philip A. Nelson.
     53   1.1    rumble  *
     54   1.1    rumble  * Portions of this software were developed by the Computer Systems
     55   1.1    rumble  * Engineering group at Lawrence Berkeley Laboratory under DARPA
     56   1.1    rumble  * contract BG 91-66 and contributed to Berkeley.
     57   1.1    rumble  *
     58   1.1    rumble  * All advertising materials mentioning features or use of this software
     59   1.1    rumble  * must display the following acknowledgement:
     60   1.1    rumble  *	This product includes software developed by the University of
     61   1.1    rumble  *	California, Lawrence Berkeley Laboratory.
     62   1.1    rumble  *
     63   1.1    rumble  * Redistribution and use in source and binary forms, with or without
     64   1.1    rumble  * modification, are permitted provided that the following conditions
     65   1.1    rumble  * are met:
     66   1.1    rumble  * 1. Redistributions of source code must retain the above copyright
     67   1.1    rumble  *    notice, this list of conditions and the following disclaimer.
     68   1.1    rumble  * 2. Redistributions in binary form must reproduce the above copyright
     69   1.1    rumble  *    notice, this list of conditions and the following disclaimer in the
     70   1.1    rumble  *    documentation and/or other materials provided with the distribution.
     71   1.1    rumble  * 3. All advertising materials mentioning features or use of this software
     72   1.1    rumble  *    must display the following acknowledgement:
     73   1.1    rumble  *	This product includes software developed by the University of
     74   1.1    rumble  *	California, Berkeley and its contributors.
     75   1.1    rumble  * 4. Neither the name of the University nor the names of its contributors
     76   1.1    rumble  *    may be used to endorse or promote products derived from this software
     77   1.1    rumble  *    without specific prior written permission.
     78   1.1    rumble  *
     79   1.1    rumble  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     80   1.1    rumble  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     81   1.1    rumble  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     82   1.1    rumble  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     83   1.1    rumble  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     84   1.1    rumble  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     85   1.1    rumble  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     86   1.1    rumble  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     87   1.1    rumble  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     88   1.1    rumble  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     89   1.1    rumble  * SUCH DAMAGE.
     90   1.1    rumble  *
     91   1.1    rumble  *	from: @(#)com.c	7.5 (Berkeley) 5/16/91
     92   1.1    rumble  */
     93   1.1    rumble 
     94   1.1    rumble #include <sys/cdefs.h>
     95  1.11   thorpej __KERNEL_RCSID(0, "$NetBSD: scn.c,v 1.11 2023/12/20 15:29:07 thorpej Exp $");
     96   1.1    rumble 
     97   1.1    rumble #include "opt_ddb.h"
     98   1.1    rumble #include "opt_kgdb.h"
     99   1.1    rumble #include "scn.h"
    100   1.1    rumble 
    101   1.1    rumble #include <sys/param.h>
    102   1.1    rumble #include <sys/systm.h>
    103   1.1    rumble #include <sys/ioctl.h>
    104   1.1    rumble #include <sys/select.h>
    105   1.1    rumble #include <sys/tty.h>
    106   1.1    rumble #include <sys/proc.h>
    107   1.1    rumble #include <sys/file.h>
    108   1.1    rumble #include <sys/uio.h>
    109   1.1    rumble #include <sys/kernel.h>
    110   1.1    rumble #include <sys/syslog.h>
    111   1.1    rumble #include <sys/types.h>
    112   1.1    rumble #include <sys/device.h>
    113   1.1    rumble #include <sys/conf.h>
    114   1.1    rumble #include <sys/intr.h>
    115   1.1    rumble #ifdef KGDB
    116   1.1    rumble #include <sys/kgdb.h>
    117   1.1    rumble #endif
    118   1.1    rumble #include <sys/kauth.h>
    119   1.1    rumble 
    120   1.1    rumble #include <dev/cons.h>
    121   1.1    rumble 
    122   1.1    rumble #include <machine/autoconf.h>
    123   1.1    rumble #include <machine/machtype.h>
    124   1.1    rumble 
    125   1.1    rumble #include <sgimips/dev/scnreg.h>
    126   1.1    rumble #include <sgimips/dev/scnvar.h>
    127   1.1    rumble 
    128   1.1    rumble int     scn_match(device_t, struct cfdata *, void *);
    129   1.1    rumble void    scn_attach(device_t, device_t, void *);
    130   1.1    rumble int     scnparam(struct tty *, struct termios *);
    131   1.1    rumble void    scnstart(struct tty *);
    132   1.1    rumble int     scnhwiflow(struct tty *, int);
    133   1.1    rumble 
    134   1.1    rumble void	scncnprobe(struct consdev *);
    135   1.1    rumble void	scncninit(struct consdev *);
    136   1.1    rumble int     scncngetc(dev_t);
    137   1.1    rumble void    scncnputc(dev_t, int);
    138   1.1    rumble void	scncnpollc(dev_t, int);
    139   1.1    rumble int	scninit(dev_t, int);
    140   1.1    rumble void	scncnreinit(void *);
    141   1.1    rumble 
    142   1.4       chs CFATTACH_DECL_NEW(scn, sizeof(struct scn_softc),
    143   1.1    rumble     scn_match, scn_attach, NULL, NULL);
    144   1.1    rumble 
    145   1.1    rumble extern struct cfdriver scn_cd;
    146   1.1    rumble 
    147   1.1    rumble dev_type_open(scnopen);
    148   1.1    rumble dev_type_close(scnclose);
    149   1.1    rumble dev_type_read(scnread);
    150   1.1    rumble dev_type_write(scnwrite);
    151   1.1    rumble dev_type_ioctl(scnioctl);
    152   1.1    rumble dev_type_stop(scnstop);
    153   1.1    rumble dev_type_tty(scntty);
    154   1.1    rumble dev_type_poll(scnpoll);
    155   1.1    rumble 
    156   1.1    rumble const struct cdevsw scn_cdevsw = {
    157   1.5  dholland 	.d_open = scnopen,
    158   1.5  dholland 	.d_close = scnclose,
    159   1.5  dholland 	.d_read = scnread,
    160   1.5  dholland 	.d_write = scnwrite,
    161   1.5  dholland 	.d_ioctl = scnioctl,
    162   1.5  dholland 	.d_stop = scnstop,
    163   1.5  dholland 	.d_tty = scntty,
    164   1.5  dholland 	.d_poll = scnpoll,
    165   1.5  dholland 	.d_mmap = nommap,
    166   1.5  dholland 	.d_kqfilter = ttykqfilter,
    167   1.7  dholland 	.d_discard = nodiscard,
    168   1.5  dholland 	.d_flag = D_TTY
    169   1.1    rumble };
    170   1.1    rumble 
    171   1.1    rumble struct consdev scn_cn = {
    172   1.1    rumble 	scncnprobe,
    173   1.1    rumble 	scncninit,
    174   1.1    rumble 	scncngetc,
    175   1.1    rumble 	scncnputc,
    176   1.1    rumble 	scncnpollc,
    177   1.1    rumble 	NULL,
    178   1.1    rumble 	NULL,
    179   1.1    rumble 	NULL,
    180   1.1    rumble 	NODEV,
    181   1.1    rumble 	CN_NORMAL
    182   1.1    rumble };
    183   1.1    rumble 
    184   1.1    rumble #ifndef CONSOLE_SPEED
    185   1.1    rumble #define CONSOLE_SPEED TTYDEF_SPEED
    186   1.1    rumble #endif
    187   1.1    rumble 
    188   1.1    rumble #ifndef SCNDEF_CFLAG
    189   1.1    rumble #define SCNDEF_CFLAG TTYDEF_CFLAG
    190   1.1    rumble #endif
    191   1.1    rumble 
    192   1.1    rumble #ifdef CPU30MHZ
    193   1.1    rumble #define RECOVER()	__asm volatile("bispsrw 0x800" : : : "cc")
    194   1.1    rumble #else
    195   1.1    rumble #define RECOVER()
    196   1.1    rumble #endif
    197   1.1    rumble 
    198   1.1    rumble int     scndefaultrate = TTYDEF_SPEED;
    199   1.1    rumble int     scnconsrate = CONSOLE_SPEED;
    200   1.1    rumble 
    201   1.1    rumble static inline struct scn_softc *
    202   1.1    rumble SOFTC(int unit)
    203   1.1    rumble {
    204   1.1    rumble 	if (unit < 0 || unit >= scn_cd.cd_ndevs)
    205   1.1    rumble 		return (NULL);
    206   1.4       chs 	return device_private(scn_cd.cd_devs[unit]);
    207   1.1    rumble }
    208   1.1    rumble 
    209   1.1    rumble static int	scnintr(void *);
    210   1.1    rumble static void	scnrxintr(void *);
    211   1.1    rumble static int	scn_rxintr(struct scn_softc *);
    212   1.1    rumble static void	scnsoft(void *);
    213   1.1    rumble static void	scn_setchip(struct scn_softc *sc);
    214   1.1    rumble static int	scniter(int *, int, int*, int*, struct chan *, int);
    215   1.1    rumble static int	scn_config(int, int, int, int, u_char, u_char);
    216   1.1    rumble static void	scn_rxenable(struct scn_softc *);
    217   1.1    rumble static void	scn_rxdisable(struct scn_softc *);
    218   1.1    rumble static void	dcd_int(struct scn_softc *, struct tty *, u_char);
    219   1.1    rumble static void	scnoverrun(int, long *, const char *);
    220   1.1    rumble static u_char	opbits(struct scn_softc *, int);
    221   1.1    rumble 
    222   1.1    rumble static void *scnsir = NULL;		/* s/w intr cookie */
    223   1.1    rumble #define setsoftscn()	softint_schedule(scnsir)
    224   1.1    rumble 
    225   1.1    rumble #ifdef SCN_TIMING
    226   1.1    rumble /*
    227   1.1    rumble  * Keep timing info on latency of software interrupt used by
    228   1.1    rumble  * the ringbuf code to empty ring buffer.
    229   1.1    rumble  * "getinfo" program reads data from /dev/kmem.
    230   1.1    rumble  */
    231   1.1    rumble static struct timeval tstart;
    232   1.1    rumble #define NJITTER 100
    233   1.1    rumble int     scn_njitter = NJITTER;
    234   1.1    rumble int     scn_jitter[NJITTER];
    235   1.1    rumble #endif
    236   1.1    rumble 
    237   1.1    rumble #define SCN_CLOCK	3686400		/* input clock */
    238   1.1    rumble 
    239   1.1    rumble /* speed table groups ACR[7] */
    240   1.1    rumble #define GRP_A	0
    241   1.1    rumble #define GRP_B	ACR_BRG
    242   1.1    rumble 
    243   1.1    rumble /* combo of MR0[2:0] and ACR[7] */
    244   1.1    rumble #define MODE0A	MR0_MODE_0
    245   1.1    rumble #define MODE0B	(MR0_MODE_0|ACR_BRG)
    246   1.1    rumble #define MODE1A	MR0_MODE_1
    247   1.1    rumble #define MODE1B	(MR0_MODE_1|ACR_BRG)
    248   1.1    rumble #define MODE2A	MR0_MODE_2
    249   1.1    rumble #define MODE2B	(MR0_MODE_2|ACR_BRG)
    250   1.1    rumble 
    251   1.1    rumble #define ANYMODE	-1
    252   1.1    rumble #define DEFMODE(C92) MODE0A		/* use MODE4A if 26c92? */
    253   1.1    rumble 
    254   1.1    rumble /* speed code for Counter/Timer (all modes, groups) */
    255   1.1    rumble #define USE_CT 0xd
    256   1.1    rumble 
    257   1.1    rumble /*
    258   1.1    rumble  * Rate table, ordered by speed, then mode.
    259   1.1    rumble  * NOTE: ordering of modes must be done carefully!
    260   1.1    rumble  */
    261   1.1    rumble struct tabent {
    262   1.1    rumble 	int32_t speed;
    263   1.1    rumble 	int16_t code;
    264   1.1    rumble 	int16_t mode;
    265   1.1    rumble } table[] = {
    266   1.1    rumble 	{     50, 0x0, MODE0A },
    267   1.1    rumble 	{     75, 0x0, MODE0B },
    268   1.1    rumble 	{    110, 0x1, MODE0A },
    269   1.1    rumble 	{    110, 0x1, MODE0B },
    270   1.1    rumble 	{    110, 0x1, MODE1A },
    271   1.1    rumble 	{    110, 0x1, MODE1B },
    272   1.1    rumble 	{    134, 0x2, MODE0A },	/* 134.5 */
    273   1.1    rumble 	{    134, 0x2, MODE0B },	/* 134.5 */
    274   1.1    rumble 	{    134, 0x2, MODE1A },	/* 134.5 */
    275   1.1    rumble 	{    134, 0x2, MODE1B },	/* 134.5 */
    276   1.1    rumble 	{    150, 0x3, MODE0A },
    277   1.1    rumble 	{    150, 0x3, MODE0A },
    278   1.1    rumble 	{    200, 0x3, MODE0A },
    279   1.1    rumble 	{    300, 0x4, MODE0A },
    280   1.1    rumble 	{    300, 0x4, MODE0B },
    281   1.1    rumble 	{    300, 0x0, MODE1A },
    282   1.1    rumble 	{    450, 0x0, MODE1B },
    283   1.1    rumble 	{    600, 0x5, MODE0A },
    284   1.1    rumble 	{    600, 0x5, MODE0B },
    285   1.1    rumble 	{    880, 0x1, MODE2A },
    286   1.1    rumble 	{    880, 0x1, MODE2B },
    287   1.1    rumble 	{    900, 0x3, MODE1B },
    288   1.1    rumble 	{   1050, 0x7, MODE0A },
    289   1.1    rumble 	{   1050, 0x7, MODE1A },
    290   1.1    rumble 	{   1076, 0x2, MODE2A },
    291   1.1    rumble 	{   1076, 0x2, MODE2B },
    292   1.1    rumble 	{   1200, 0x6, MODE0A },
    293   1.1    rumble 	{   1200, 0x6, MODE0B },
    294   1.1    rumble 	{   1200, 0x3, MODE1A },
    295   1.1    rumble 	{   1800, 0xa, MODE0B },
    296   1.1    rumble 	{   1800, 0x4, MODE1A },
    297   1.1    rumble 	{   1800, 0x4, MODE1B },
    298   1.1    rumble 	{   2000, 0x7, MODE0B },
    299   1.1    rumble 	{   2000, 0x7, MODE1B },
    300   1.1    rumble 	{   2400, 0x8, MODE0A },
    301   1.1    rumble 	{   2400, 0x8, MODE0B },
    302   1.1    rumble 	{   3600, 0x5, MODE1A },
    303   1.1    rumble 	{   3600, 0x5, MODE1B },
    304   1.1    rumble 	{   4800, 0x9, MODE2A },
    305   1.1    rumble 	{   4800, 0x9, MODE2B },
    306   1.1    rumble 	{   4800, 0x9, MODE0A },
    307   1.1    rumble 	{   4800, 0x9, MODE0B },
    308   1.1    rumble 	{   7200, 0xa, MODE0A },
    309   1.1    rumble 	{   7200, 0x0, MODE2B },
    310   1.1    rumble 	{   7200, 0x6, MODE1A },
    311   1.1    rumble 	{   7200, 0x6, MODE1B },
    312   1.1    rumble 	{   9600, 0xb, MODE2A },
    313   1.1    rumble 	{   9600, 0xb, MODE2B },
    314   1.1    rumble 	{   9600, 0xb, MODE0A },
    315   1.1    rumble 	{   9600, 0xb, MODE0B },
    316   1.1    rumble 	{   9600, 0xd, MODE1A },	/* use C/T as entre' to mode1 */
    317   1.1    rumble 	{   9600, 0xd, MODE1B },	/* use C/T as entre' to mode1 */
    318   1.1    rumble 	{  14400, 0x3, MODE2B },
    319   1.1    rumble 	{  14400, 0x8, MODE1A },
    320   1.1    rumble 	{  14400, 0x8, MODE1B },
    321   1.1    rumble 	{  19200, 0x3, MODE2A },
    322   1.1    rumble 	{  19200, 0xc, MODE2B },
    323   1.1    rumble 	{  19200, 0xc, MODE0B },
    324   1.1    rumble 	{  19200, 0xd, MODE1A },	/* use C/T as entre' to mode1 */
    325   1.1    rumble 	{  19200, 0xd, MODE1B },	/* use C/T as entre' to mode1 */
    326   1.1    rumble 	{  28800, 0x4, MODE2A },
    327   1.1    rumble 	{  28800, 0x4, MODE2B },
    328   1.1    rumble 	{  28800, 0x9, MODE1A },
    329   1.1    rumble 	{  28800, 0x9, MODE1B },
    330   1.1    rumble 	{  38400, 0xc, MODE2A },
    331   1.1    rumble 	{  38400, 0xc, MODE0A },
    332   1.1    rumble 	{  57600, 0x5, MODE2A },
    333   1.1    rumble 	{  57600, 0x5, MODE2B },
    334   1.1    rumble 	{  57600, 0xb, MODE1A },
    335   1.1    rumble 	{  57600, 0xb, MODE1B },
    336   1.1    rumble 	{ 115200, 0x6, MODE2A },
    337   1.1    rumble 	{ 115200, 0x6, MODE2B },
    338   1.1    rumble 	{ 115200, 0xc, MODE1B },
    339   1.1    rumble 	{ 230400, 0xc, MODE1A }
    340   1.1    rumble };
    341   1.1    rumble #define TABENTRIES (sizeof(table)/sizeof(table[0]))
    342   1.1    rumble 
    343   1.1    rumble /*
    344   1.1    rumble  * boolean for speed codes which are identical in both A/B BRG groups
    345   1.1    rumble  * in all modes
    346   1.1    rumble  */
    347   1.1    rumble static u_char bothgroups[16] = {
    348   1.1    rumble 	0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1
    349   1.1    rumble };
    350   1.1    rumble 
    351   1.1    rumble /*
    352   1.1    rumble  * Manually constructed divisors table
    353   1.1    rumble  * for minimum error (from some of Dave Rand's code)
    354   1.1    rumble  */
    355   1.1    rumble const struct {
    356   1.1    rumble 	uint16_t speed;
    357   1.1    rumble 	uint16_t div;
    358   1.1    rumble } divs[] = {
    359   1.1    rumble 	{    50, 2303 },	/* 2304 is exact?? */
    360   1.1    rumble 	{   110, 1047 },	/* Should be 1047.27 */
    361   1.1    rumble 	{   134, 857 },		/* Should be 856.505576 */
    362   1.1    rumble 	{  1050, 110 },		/* Should be 109.7142857 */
    363   1.1    rumble 	{  2000, 57 }		/* Should be 57.6 */
    364   1.1    rumble };
    365   1.1    rumble #define DIVS (sizeof(divs)/sizeof(divs[0]))
    366   1.1    rumble 
    367   1.1    rumble /*
    368   1.1    rumble  * minor unit bit decode:
    369   1.1    rumble  * CxxxUUU
    370   1.1    rumble  *
    371   1.1    rumble  * C - carrier
    372   1.1    rumble  *	0 - delay open until carrier high
    373   1.1    rumble  *	1 - allow open with carrier low
    374   1.1    rumble  * UUU - unit 0-7
    375   1.1    rumble  */
    376   1.1    rumble 
    377   1.1    rumble #define DEV_UNIT(x)	(minor(x) & 0x7)
    378   1.1    rumble #define DEV_DIALOUT(x)	(minor(x) & 0x80)
    379   1.1    rumble 
    380   1.1    rumble #define SCN_MAXDUART 4
    381   1.1    rumble static struct duart scn_duart[SCN_MAXDUART];
    382   1.1    rumble 
    383   1.1    rumble #ifdef KGDB
    384   1.1    rumble extern int kgdb_dev;
    385   1.1    rumble extern int kgdb_rate;
    386   1.1    rumble extern int kgdb_debug_init;
    387   1.1    rumble #endif
    388   1.1    rumble 
    389   1.1    rumble /* XXXXX - fix this */
    390   1.1    rumble #define splrtty() spltty()
    391   1.1    rumble 
    392   1.1    rumble /* RS-232 configuration routines */
    393   1.1    rumble 
    394   1.1    rumble /*
    395   1.1    rumble  * set chip parameters, or mark for delayed change.
    396   1.1    rumble  * called at spltty() or on TxEMPTY interrupt.
    397   1.1    rumble  *
    398   1.1    rumble  * Reads current values to avoid glitches from redundant sets.
    399   1.1    rumble  * Perhaps should save last value set to avoid read/write?  NOTE:
    400   1.1    rumble  * Would still need to do read if write not needed to advance MR
    401   1.1    rumble  * pointer.
    402   1.1    rumble  *
    403   1.1    rumble  * new 2/97 -plb
    404   1.1    rumble  */
    405   1.1    rumble 
    406   1.1    rumble static void
    407   1.1    rumble scn_setchip(struct scn_softc *sc)
    408   1.1    rumble {
    409   1.1    rumble 	struct duart *dp;
    410   1.1    rumble 	u_char acr, csr, mr1, mr2;
    411   1.1    rumble 	int chan;
    412   1.1    rumble 
    413   1.1    rumble 	if (sc->sc_tty && (sc->sc_tty->t_state & TS_BUSY)) {
    414   1.1    rumble 		sc->sc_heldchanges = 1;
    415   1.1    rumble 		return;
    416   1.1    rumble 	}
    417   1.1    rumble 
    418   1.1    rumble 	chan = sc->sc_channel;
    419   1.1    rumble 	dp = sc->sc_duart;
    420   1.1    rumble 	if (dp->type == SC26C92) {
    421   1.1    rumble 		u_char nmr0a, mr0a;
    422   1.1    rumble 
    423   1.1    rumble 		/* input rate high enough so 64 bit time watchdog not
    424   1.1    rumble 		 * onerous? */
    425   1.1    rumble 		if (dp->chan[chan].ispeed >= 1200) {
    426   1.1    rumble 			/* set FIFO threshold at 6 for other
    427   1.1    rumble 			 * thresholds we could have to set MR1_FFULL
    428   1.1    rumble 			 */
    429   1.1    rumble 			dp->chan[chan].mr0 |= MR0_RXWD | MR0_RXINT;
    430   1.1    rumble 		} else {
    431   1.1    rumble 			dp->chan[chan].mr0 &= ~(MR0_RXWD | MR0_RXINT);
    432   1.1    rumble 		}
    433   1.1    rumble 
    434   1.1    rumble 		/* select BRG mode (MR0A only) */
    435   1.1    rumble 		nmr0a = dp->chan[0].mr0 | (dp->mode & MR0_MODE);
    436   1.1    rumble 
    437   1.1    rumble 		dp->base[CH_CR] = CR_CMD_MR0;
    438   1.1    rumble 		RECOVER();
    439   1.1    rumble 
    440   1.1    rumble 		mr0a = dp->base[CH_MR];
    441   1.1    rumble 		if (mr0a != nmr0a) {
    442   1.1    rumble 			dp->base[CH_CR] = CR_CMD_MR0;
    443   1.1    rumble 			RECOVER();
    444   1.1    rumble 			dp->base[CH_MR] = nmr0a;
    445   1.1    rumble 		}
    446   1.1    rumble 
    447   1.1    rumble 		if (chan) {	 /* channel B? */
    448   1.1    rumble 			u_char mr0b;
    449   1.1    rumble 
    450   1.1    rumble 			sc->sc_chbase[CH_CR] = CR_CMD_MR0;
    451   1.1    rumble 			RECOVER();
    452   1.1    rumble 			mr0b = dp->base[CH_MR];
    453   1.1    rumble 
    454   1.1    rumble 			if (dp->chan[chan].mr0 != mr0b) {
    455   1.1    rumble 				sc->sc_chbase[CH_CR] = CR_CMD_MR0;
    456   1.1    rumble 				RECOVER();
    457   1.1    rumble 				sc->sc_chbase[CH_MR] = dp->chan[chan].mr0;
    458   1.1    rumble 			}
    459   1.1    rumble 		}
    460   1.1    rumble 	} else {
    461   1.1    rumble 		sc->sc_chbase[CH_CR] = CR_CMD_MR1;
    462   1.1    rumble 		RECOVER();
    463   1.1    rumble 	}
    464   1.1    rumble 
    465   1.1    rumble 	mr1 = sc->sc_chbase[CH_MR];
    466   1.1    rumble 	mr2 = sc->sc_chbase[CH_MR];
    467   1.1    rumble 	if (mr1 != dp->chan[chan].new_mr1 ||
    468   1.1    rumble 	    mr2 != dp->chan[chan].new_mr2) {
    469   1.1    rumble 		sc->sc_chbase[CH_CR] = CR_CMD_MR1;
    470   1.1    rumble 		RECOVER();
    471   1.1    rumble 		sc->sc_chbase[CH_MR] = dp->chan[chan].new_mr1;
    472   1.1    rumble 		sc->sc_chbase[CH_MR] = dp->chan[chan].new_mr2;
    473   1.1    rumble 	}
    474   1.1    rumble 
    475   1.1    rumble 	acr = dp->acr | (dp->mode & ACR_BRG);
    476   1.1    rumble 	dp->base[DU_ACR] = acr;		/* write-only reg! */
    477   1.1    rumble 
    478   1.1    rumble 	/* set speed codes */
    479   1.1    rumble 	csr = (dp->chan[chan].icode<<4) | dp->chan[chan].ocode;
    480   1.1    rumble 	if (sc->sc_chbase[CH_CSR] != csr) {
    481   1.1    rumble 		sc->sc_chbase[CH_CSR] = csr;
    482   1.1    rumble 	}
    483   1.1    rumble 
    484   1.1    rumble 	/* see if counter/timer in use */
    485   1.1    rumble 	if (dp->counter &&
    486   1.1    rumble 	    (dp->chan[0].icode == USE_CT || dp->chan[0].ocode == USE_CT ||
    487   1.1    rumble 	     dp->chan[1].icode == USE_CT || dp->chan[1].ocode == USE_CT)) {
    488   1.1    rumble 
    489   1.1    rumble 		/* program counter/timer only if necessary */
    490   1.1    rumble 		if (dp->counter != dp->ocounter) {
    491   1.1    rumble 			uint16_t div;
    492   1.1    rumble #ifdef DIVS
    493   1.1    rumble 			int i;
    494   1.1    rumble 
    495   1.1    rumble 			/* look for precalculated rate, for minimum error */
    496   1.1    rumble 			for (i = 0; i < DIVS && divs[i].speed <= dp->counter; i++) {
    497   1.1    rumble 				if (divs[i].speed == dp->counter) {
    498   1.1    rumble 					div = divs[i].div;
    499   1.1    rumble 					goto found;
    500   1.1    rumble 				}
    501   1.1    rumble 			}
    502   1.1    rumble #endif
    503   1.1    rumble 
    504   1.1    rumble 			/* not found in table; calculate a value (rounding up) */
    505   1.1    rumble 			div = ((long)SCN_CLOCK/16/2 + dp->counter/2) / dp->counter;
    506   1.1    rumble 
    507   1.1    rumble 		found:
    508   1.1    rumble 			/* halt before loading? may ALWAYS glitch?
    509   1.1    rumble 			 * reload race may only sometimes glitch??
    510   1.1    rumble 			 */
    511   1.1    rumble 			dp->base[DU_CTUR] = div >> 8;
    512   1.1    rumble 			dp->base[DU_CTLR] = div & 255;
    513   1.1    rumble 			if (dp->ocounter == 0) {
    514   1.1    rumble 				/* not previously used? */
    515   1.1    rumble 				u_char temp;
    516   1.1    rumble 				/* start C/T running */
    517   1.1    rumble 				temp = dp->base[DU_CSTRT];
    518   1.6  christos 				__USE(temp);
    519   1.1    rumble 			}
    520   1.1    rumble 			dp->ocounter = dp->counter;
    521   1.1    rumble 		}
    522   1.1    rumble 	} else {
    523   1.1    rumble 		/* counter not in use; mark as free */
    524   1.1    rumble 		dp->counter = 0;
    525   1.1    rumble 	}
    526   1.1    rumble 	sc->sc_heldchanges = 0;
    527   1.1    rumble 
    528   1.1    rumble 	/*
    529   1.1    rumble 	 * delay a tiny bit to try and avoid tx glitching.
    530   1.1    rumble 	 * I know we're at spltty(), but this is much better than the
    531   1.1    rumble 	 * old version used DELAY((96000 / out_speed) * 10000)
    532   1.1    rumble 	 * -plb
    533   1.1    rumble 	 */
    534   1.1    rumble 	DELAY(10);
    535   1.1    rumble }
    536   1.1    rumble 
    537   1.1    rumble /*
    538   1.1    rumble  * iterator function for speeds.
    539   1.1    rumble  * (could be called "findnextcode")
    540   1.1    rumble  * Returns sequence of possible speed codes for a given rate.
    541   1.1    rumble  * should set index to zero before first call.
    542   1.1    rumble  *
    543   1.1    rumble  * Could be implemented as a "checkspeed()" function called
    544   1.1    rumble  * to evaluate table entries, BUT this allows more variety in
    545   1.1    rumble  * use of C/T with fewer table entries.
    546   1.1    rumble  */
    547   1.1    rumble 
    548   1.1    rumble static int
    549   1.1    rumble scniter(int *index, int wanted, int *counter, int *mode, struct chan *other,
    550   1.1    rumble     int c92)
    551   1.1    rumble {
    552   1.1    rumble 
    553   1.1    rumble 	while (*index < TABENTRIES) {
    554   1.1    rumble 		struct tabent *tp;
    555   1.1    rumble 
    556   1.1    rumble 		tp = table + (*index)++;
    557   1.1    rumble 		if (tp->speed != wanted)
    558   1.1    rumble 			continue;
    559   1.1    rumble 
    560   1.1    rumble 		/* if not a 26C92 only look at MODE0 entries */
    561   1.1    rumble 		if (!c92 && (tp->mode & MR0_MODE) != MR0_MODE_0)
    562   1.1    rumble 			continue;
    563   1.1    rumble 
    564   1.1    rumble 		/*
    565   1.1    rumble 		 * check mode;
    566   1.1    rumble 		 * OK if this table entry for current mode, or mode not
    567   1.1    rumble 		 * yet set, or other channel's rates are available in both
    568   1.1    rumble 		 * A and B groups.
    569   1.1    rumble 		 */
    570   1.1    rumble 
    571   1.1    rumble 		if (tp->mode == *mode || *mode == ANYMODE ||
    572   1.1    rumble 		    (other != NULL && (tp->mode & MR0_MODE) == (*mode & MR0_MODE) &&
    573   1.1    rumble 		     bothgroups[other->icode] && bothgroups[other->ocode])) {
    574   1.1    rumble 			/*
    575   1.1    rumble 			 * for future table entries specifying
    576   1.1    rumble 			 * use of counter/timer
    577   1.1    rumble 			 */
    578   1.1    rumble 			if (tp->code == USE_CT) {
    579   1.1    rumble 				if (*counter != wanted && *counter != 0)
    580   1.1    rumble 					continue;	/* counter busy */
    581   1.1    rumble 				*counter = wanted;
    582   1.1    rumble 			}
    583   1.1    rumble 			*mode = tp->mode;
    584   1.1    rumble 			return tp->code;
    585   1.1    rumble 		}
    586   1.1    rumble 	}
    587   1.1    rumble 
    588   1.1    rumble 	/* here after returning all applicable table entries */
    589   1.1    rumble 	/* XXX return sequence of USE_CT with all possible modes?? */
    590   1.1    rumble 	if ((*index)++ == TABENTRIES) {
    591   1.1    rumble 		/* Max C/T rate (even on 26C92?) is 57600 */
    592   1.1    rumble 		if (wanted <= 57600 && (*counter == wanted || *counter == 0)) {
    593   1.1    rumble 			*counter = wanted;
    594   1.1    rumble 			return USE_CT;
    595   1.1    rumble 		}
    596   1.1    rumble 	}
    597   1.1    rumble 
    598   1.1    rumble 	return -1;			/* FAIL */
    599   1.1    rumble }
    600   1.1    rumble 
    601   1.1    rumble /*
    602   1.1    rumble  * calculate configuration
    603   1.1    rumble  * rewritten 2/97 -plb
    604   1.1    rumble  */
    605   1.1    rumble static int
    606   1.1    rumble scn_config(int unit, int chan, int ispeed, int ospeed, u_char mr1, u_char mr2)
    607   1.1    rumble {
    608   1.1    rumble 	struct scn_softc *sc;
    609   1.1    rumble 	struct duart *dp;
    610   1.1    rumble 	int other;		/* opposite of chan */
    611   1.1    rumble 	int mode;
    612   1.1    rumble 	int counter;
    613   1.1    rumble 	int i, o;		/* input, output iterator indexes */
    614   1.1    rumble 	int ic, oc;		/* input, output codes */
    615   1.1    rumble 	struct chan *ocp;	/* other duart channel */
    616   1.1    rumble 	struct tty *otp;	/* other channel tty struct */
    617   1.1    rumble 	int c92;		/* true if duart is sc26c92 */
    618   1.1    rumble 	int s;
    619   1.1    rumble 
    620   1.1    rumble 	/* Set up softc pointer. */
    621   1.1    rumble 	if (unit >= scn_cd.cd_ndevs)
    622   1.1    rumble 		return ENXIO;
    623   1.1    rumble 	sc = SOFTC(unit);
    624   1.1    rumble 	chan = sc->sc_channel;
    625   1.1    rumble 	other = chan ^ 1;
    626   1.1    rumble 	dp = sc->sc_duart;
    627   1.1    rumble 	ocp = &dp->chan[other];
    628   1.1    rumble 	otp = ocp->tty;
    629   1.1    rumble 	c92 = (dp->type == SC26C92);
    630   1.1    rumble 
    631   1.1    rumble 	/*
    632   1.1    rumble 	 * Right now the first combination that works is used.
    633   1.1    rumble 	 * Perhaps it should search entire solution space for "best"
    634   1.1    rumble 	 * combination. For example, use heuristic weighting of mode
    635   1.1    rumble 	 * preferences, and use of counter timer?
    636   1.1    rumble 	 *
    637   1.1    rumble 	 * For example right now with 2681/2692 when default rate is
    638   1.1    rumble 	 * 9600 and other channel is closed setting 19200 will pick
    639   1.1    rumble 	 * mode 0a and use counter/timer.  Better solution might be
    640   1.1    rumble 	 * mode 0b, leaving counter/timer free!
    641   1.1    rumble 	 *
    642   1.1    rumble 	 * When other channel is open might want to prefer
    643   1.1    rumble 	 * leaving counter timer free, or not flipping A/B group?
    644   1.1    rumble 	 */
    645   1.1    rumble 	if (otp && (otp->t_state & TS_ISOPEN)) {
    646   1.1    rumble 
    647   1.1    rumble 		/*
    648   1.1    rumble 		 * Other channel open;
    649   1.1    rumble 		 * Find speed codes compatible with current mode/counter.
    650   1.1    rumble 		 */
    651   1.1    rumble 
    652   1.1    rumble 		i = 0;
    653   1.1    rumble 		for (;;) {
    654   1.1    rumble 			mode = dp->mode;
    655   1.1    rumble 			counter = dp->counter;
    656   1.1    rumble 
    657   1.1    rumble 			/* NOTE: pass other chan pointer to allow group flipping */
    658   1.1    rumble 			ic = scniter(&i, ispeed, &counter, &mode, ocp, c92);
    659   1.1    rumble 			if (ic == -1)
    660   1.1    rumble 				break;
    661   1.1    rumble 
    662   1.1    rumble 			o = 0;
    663   1.1    rumble 			if ((oc = scniter(&o, ospeed, &counter,
    664   1.1    rumble 					  &mode, NULL, c92)) != -1) {
    665   1.1    rumble 				/*
    666   1.1    rumble 				 * take first match
    667   1.1    rumble 				 *
    668   1.1    rumble 				 * Perhaps calculate heuristic "score",
    669   1.1    rumble 				 * save score,codes,mode,counter if score
    670   1.1    rumble 				 * better than previous best?
    671   1.1    rumble 				 */
    672   1.1    rumble 				goto gotit;
    673   1.1    rumble 			}
    674   1.1    rumble 		}
    675   1.1    rumble 		/* XXX try looping for ospeed? */
    676   1.1    rumble 	} else {
    677   1.1    rumble 		/* other channel closed */
    678   1.1    rumble 		int oo, oi;	/* other input, output iterators */
    679   1.1    rumble 		int oic, ooc;	/* other input, output codes */
    680   1.1    rumble 
    681   1.1    rumble 		/*
    682   1.1    rumble 		 * Here when other channel closed.  Finds first
    683   1.1    rumble 		 * combination that will allow other channel to be opened
    684   1.1    rumble 		 * (with defaults) and fits our needs.
    685   1.1    rumble 		 */
    686   1.1    rumble 		oi = 0;
    687   1.1    rumble 		for (;;) {
    688   1.1    rumble 			mode = ANYMODE;
    689   1.1    rumble 			counter = 0;
    690   1.1    rumble 
    691   1.1    rumble 			oic = scniter(&oi, ocp->ispeed, &counter, &mode, NULL, c92);
    692   1.1    rumble 			if (oic == -1)
    693   1.1    rumble 				break;
    694   1.1    rumble 
    695   1.1    rumble 			oo = 0;
    696   1.1    rumble 			while ((ooc = scniter(&oo, ocp->ospeed, &counter,
    697   1.1    rumble 					   &mode, NULL, c92)) != -1) {
    698   1.1    rumble 				i = 0;
    699   1.1    rumble 				while ((ic = scniter(&i, ispeed, &counter,
    700   1.1    rumble 						  &mode, NULL, c92)) != -1) {
    701   1.1    rumble 					o = 0;
    702   1.1    rumble 					if ((oc = scniter(&o, ospeed, &counter,
    703   1.1    rumble 						       &mode, NULL, c92)) != -1) {
    704   1.1    rumble 						/*
    705   1.1    rumble 						 * take first match
    706   1.1    rumble 						 *
    707   1.1    rumble 						 * Perhaps calculate heuristic
    708   1.1    rumble 						 * "score", save
    709   1.1    rumble 						 *     score,codes,mode,counter
    710   1.1    rumble 						 * if score better than
    711   1.1    rumble 						 * previous best?
    712   1.1    rumble 						 */
    713   1.1    rumble 						s = spltty();
    714   1.1    rumble 						dp->chan[other].icode = oic;
    715   1.1    rumble 						dp->chan[other].ocode = ooc;
    716   1.1    rumble 						goto gotit2;
    717   1.1    rumble 					}
    718   1.1    rumble 				}
    719   1.1    rumble 			}
    720   1.1    rumble 		}
    721   1.1    rumble 	}
    722   1.1    rumble 	return EINVAL;
    723   1.1    rumble 
    724   1.1    rumble  gotit:
    725   1.1    rumble 	s = spltty();
    726   1.1    rumble  gotit2:
    727   1.1    rumble 	dp->chan[chan].new_mr1 = mr1;
    728   1.1    rumble 	dp->chan[chan].new_mr2 = mr2;
    729   1.1    rumble 	dp->chan[chan].ispeed = ispeed;
    730   1.1    rumble 	dp->chan[chan].ospeed = ospeed;
    731   1.1    rumble 	dp->chan[chan].icode = ic;
    732   1.1    rumble 	dp->chan[chan].ocode = oc;
    733   1.1    rumble 	if (mode == ANYMODE)		/* no mode selected?? */
    734   1.1    rumble 		mode = DEFMODE(c92);
    735   1.1    rumble 	dp->mode = mode;
    736   1.1    rumble 	dp->counter = counter;
    737   1.1    rumble 
    738   1.1    rumble 	scn_setchip(sc);		/* set chip now, if possible */
    739   1.1    rumble 	splx(s);
    740   1.1    rumble 	return (0);
    741   1.1    rumble }
    742   1.1    rumble 
    743   1.1    rumble int
    744   1.1    rumble scn_match(device_t parent, struct cfdata *cf, void *aux)
    745   1.1    rumble {
    746   1.1    rumble 	struct mainbus_attach_args *ma = aux;
    747   1.1    rumble 
    748   1.1    rumble 	if ((mach_type == MACH_SGI_IP6 || mach_type == MACH_SGI_IP10) &&
    749   1.1    rumble 	    ma->ma_addr == 0x1fb80004)
    750   1.1    rumble 		return (1);
    751   1.1    rumble 
    752   1.1    rumble 	return (0);
    753   1.1    rumble }
    754   1.1    rumble 
    755   1.1    rumble /*
    756   1.1    rumble  * No need to make scn_rx{en,dis}able too efficient,
    757   1.1    rumble  * they're only called on setup, open & close!
    758   1.1    rumble  */
    759   1.1    rumble static inline void
    760   1.1    rumble scn_rxenable(struct scn_softc *sc)
    761   1.1    rumble {
    762   1.1    rumble 	struct duart *dp;
    763   1.1    rumble 	int channel;
    764   1.1    rumble 
    765   1.1    rumble 	dp = sc->sc_duart;
    766   1.1    rumble 	channel = sc->sc_channel;
    767   1.1    rumble 
    768   1.1    rumble 	/* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
    769   1.1    rumble 	if (channel == 0)
    770   1.1    rumble 		dp->opcr |= OPCR_OP4_RXRDYA;
    771   1.1    rumble 	else
    772   1.1    rumble 		dp->opcr |= OPCR_OP5_RXRDYB;
    773   1.1    rumble 	dp->base[DU_OPCR] = dp->opcr;
    774   1.1    rumble 	dp->imr |= sc->sc_rx_int;
    775   1.1    rumble 	dp->base[DU_IMR] = dp->imr;
    776   1.1    rumble }
    777   1.1    rumble 
    778   1.1    rumble static inline void
    779   1.1    rumble scn_rxdisable(struct scn_softc *sc)
    780   1.1    rumble {
    781   1.1    rumble 	struct duart *dp;
    782   1.1    rumble 	int channel;
    783   1.1    rumble 
    784   1.1    rumble 	dp = sc->sc_duart;
    785   1.1    rumble 	channel = sc->sc_channel;
    786   1.1    rumble 
    787   1.1    rumble 	/* Outputs wire-ored and connected to ICU input for fast rx interrupt. */
    788   1.1    rumble 	if (channel == 0)
    789   1.1    rumble 		dp->opcr &= ~OPCR_OP4_RXRDYA;
    790   1.1    rumble 	else
    791   1.1    rumble 		dp->opcr &= ~OPCR_OP5_RXRDYB;
    792   1.1    rumble 	dp->base[DU_OPCR] = dp->opcr;
    793   1.1    rumble 	dp->imr &= ~sc->sc_rx_int;
    794   1.1    rumble 	dp->base[DU_IMR] = dp->imr;
    795   1.1    rumble }
    796   1.1    rumble 
    797   1.1    rumble void
    798   1.1    rumble scn_attach(device_t parent, device_t self, void *aux)
    799   1.1    rumble {
    800   1.1    rumble 	struct mainbus_attach_args *ma = aux;
    801   1.1    rumble 	struct scn_softc *sc;
    802   1.1    rumble 	struct duart *duart;
    803   1.1    rumble 	volatile u_char *ch_base;
    804   1.1    rumble 	volatile u_char *duart_base;
    805   1.1    rumble 	int channel;
    806   1.1    rumble 	int speed;
    807   1.1    rumble 	int s;
    808   1.6  christos 	int maj __diagused;
    809   1.1    rumble 	u_char unit;
    810   1.1    rumble 	u_char duartno;
    811   1.1    rumble 	u_char delim = ':';
    812   1.1    rumble 	u_char mr1, mr2;
    813   1.1    rumble 	enum scntype scntype = SCNUNK;
    814   1.1    rumble 	const char *duart_type = "Unknown";
    815   1.1    rumble 	bool console, first;
    816   1.1    rumble 	devmajor_t major;
    817   1.1    rumble 
    818   1.1    rumble 	(void)major;
    819   1.1    rumble 
    820   1.1    rumble 	sc = device_private(self);
    821   1.1    rumble 	unit = device_unit(self);
    822   1.1    rumble 
    823   1.1    rumble 	/* XXX - hard-coded */
    824   1.1    rumble 	if (ma->ma_addr == 0x1fb80004)
    825   1.1    rumble 		duartno = 1;
    826   1.1    rumble 	else
    827   1.1    rumble 		duartno = 0;
    828   1.1    rumble 	channel = 0;
    829   1.1    rumble 	console = 1;
    830   1.1    rumble 
    831   1.1    rumble 	duart = sc->sc_duart = &scn_duart[duartno];
    832   1.1    rumble 	duart->chan[channel].sc = sc;
    833   1.1    rumble 	first =	(duart->base == NULL);
    834   1.1    rumble 
    835   1.1    rumble 	if (console) {
    836   1.1    rumble 		sc->sc_isconsole = 1;
    837   1.1    rumble 		sc->sc_swflags |= SCN_SW_SOFTCAR;	/* ignore carrier */
    838   1.1    rumble 	}
    839   1.1    rumble 
    840   1.1    rumble 	duart_base = (volatile u_char *)MIPS_PHYS_TO_KSEG1(ma->ma_addr);
    841   1.1    rumble 	ch_base    = duart_base; /* XXX */
    842   1.1    rumble 
    843   1.1    rumble 	if (first) {
    844   1.1    rumble 		/* Probe DUART type */
    845   1.1    rumble 		s = spltty();
    846   1.1    rumble 		if (console) {
    847   1.1    rumble 			ch_base[CH_CR] = CR_DIS_TX;
    848   1.1    rumble 			delay(5 * 10000);
    849   1.1    rumble 		}
    850   1.1    rumble 		ch_base[CH_CR] = CR_CMD_MR1;
    851   1.1    rumble 		RECOVER();
    852   1.1    rumble 		mr1 = ch_base[CH_MR];
    853   1.1    rumble 		mr2 = ch_base[CH_MR];
    854   1.1    rumble 		ch_base[CH_CR] = CR_CMD_MR1;
    855   1.1    rumble 		RECOVER();
    856   1.1    rumble 		ch_base[CH_MR] = 1;
    857   1.1    rumble 		ch_base[CH_MR] = 0;
    858   1.1    rumble 		ch_base[CH_CR] = CR_CMD_MR1;
    859   1.1    rumble 		RECOVER();
    860   1.1    rumble 		if (ch_base[CH_MR] == 1) {
    861   1.1    rumble 			/* MR 2 selected */
    862   1.1    rumble 			ch_base[CH_CR] = CR_CMD_MR0;
    863   1.1    rumble 			RECOVER();
    864   1.1    rumble 			/* if 2681, MR2 still selected */
    865   1.1    rumble 			ch_base[CH_MR] = 1;
    866   1.1    rumble 			ch_base[CH_CR] = CR_CMD_MR1;
    867   1.1    rumble 			RECOVER();
    868   1.1    rumble 			ch_base[CH_MR] = 0; /* MR1 */
    869   1.1    rumble 			ch_base[CH_MR] = 0; /* MR2 */
    870   1.1    rumble 			ch_base[CH_CR] = CR_CMD_MR0;
    871   1.1    rumble 			RECOVER();
    872   1.1    rumble 			/* if 2681, MR2 still selected */
    873   1.1    rumble 			if((ch_base[CH_MR] & 1) == 1) {
    874   1.1    rumble 				duart_type = "sc26c92";
    875   1.1    rumble 				scntype = SC26C92;
    876   1.1    rumble 			} else {
    877   1.1    rumble 				/* 2681 treats as MR1 Select */
    878   1.1    rumble 				ch_base[CH_CR] = CR_CMD_RTS_OFF;
    879   1.1    rumble 				RECOVER();
    880   1.1    rumble 				ch_base[CH_MR] = 1;
    881   1.1    rumble 				ch_base[CH_MR] = 0;
    882   1.1    rumble 				ch_base[CH_CR] = CR_CMD_RTS_OFF;
    883   1.1    rumble 				RECOVER();
    884   1.1    rumble 				if (ch_base[CH_MR] == 1) {
    885   1.1    rumble 					duart_type = "scn2681";
    886   1.1    rumble 					scntype = SCN2681;
    887   1.1    rumble 				} else {
    888   1.1    rumble 					duart_type = "scn2692";
    889   1.1    rumble 					scntype = SCN2692;
    890   1.1    rumble 				}
    891   1.1    rumble 			}
    892   1.1    rumble 		}
    893   1.1    rumble 
    894   1.1    rumble 		/* If a 2681, the CR_CMD_MR0 is interpreted as a TX_RESET */
    895   1.1    rumble 		if (console) {
    896   1.1    rumble 			ch_base[CH_CR] = CR_ENA_TX;
    897   1.1    rumble 			RECOVER();
    898   1.1    rumble 		}
    899   1.1    rumble 		ch_base[CH_CR] = CR_CMD_MR1;
    900   1.1    rumble 		RECOVER();
    901   1.1    rumble 		ch_base[CH_MR] = mr1;
    902   1.1    rumble 		ch_base[CH_MR] = mr2;
    903   1.1    rumble 		splx(s);
    904   1.1    rumble 
    905   1.1    rumble 		/*
    906   1.1    rumble 		 * On IP6 the console chip is duart1. The keyboard/mouse
    907   1.1    rumble 		 * is duart0. Each chip has two channels and the channels
    908   1.1    rumble 		 * share an interrupt. Duart0 is interrupt 0, duart1 is
    909   1.1    rumble 		 * interrupt 1.
    910   1.1    rumble 		 */
    911   1.1    rumble 		if (duartno != 0 && duartno != 1)
    912   1.1    rumble 			panic("scn_attach: bad duartno: %d", duartno);
    913   1.1    rumble 		cpu_intr_establish(duartno, IPL_TTY, scnintr, duart);
    914   1.1    rumble 
    915   1.1    rumble 		printf("%c %s", delim, duart_type);
    916   1.1    rumble 		delim = ',';
    917   1.1    rumble 
    918   1.1    rumble 		duart->base = duart_base;
    919   1.1    rumble 		duart->type = scntype;
    920   1.1    rumble 	}
    921   1.1    rumble 	/* Record channel, uart */
    922   1.1    rumble 	sc->sc_channel = channel;
    923   1.1    rumble 	sc->sc_chbase = ch_base;
    924   1.1    rumble 
    925   1.1    rumble 	/* Initialize modem/interrupt bit masks */
    926   1.1    rumble 	if (channel == 0) {
    927   1.1    rumble 		sc->sc_op_rts = OP_RTSA;
    928   1.1    rumble 		sc->sc_op_dtr = OP_DTRA;
    929   1.1    rumble 		sc->sc_ip_cts = IP_CTSA;
    930   1.1    rumble 		sc->sc_ip_dcd = IP_DCDA;
    931   1.1    rumble 
    932   1.1    rumble 		sc->sc_tx_int = INT_TXA;
    933   1.1    rumble 		sc->sc_rx_int = INT_RXA;
    934   1.1    rumble 	} else {
    935   1.1    rumble 		sc->sc_op_rts = OP_RTSB;
    936   1.1    rumble 		sc->sc_op_dtr = OP_DTRB;
    937   1.1    rumble 		sc->sc_ip_cts = IP_CTSB;
    938   1.1    rumble 		sc->sc_ip_dcd = IP_DCDB;
    939   1.1    rumble 
    940   1.1    rumble 		sc->sc_tx_int = INT_TXB;
    941   1.1    rumble 		sc->sc_rx_int = INT_RXB;
    942   1.1    rumble 	}
    943   1.1    rumble 
    944   1.1    rumble 	/* Initialize counters */
    945   1.1    rumble 	sc->sc_framing_errors = 0;
    946   1.1    rumble 	sc->sc_fifo_overruns = 0;
    947   1.1    rumble 	sc->sc_parity_errors = 0;
    948   1.1    rumble 	sc->sc_breaks = 0;
    949   1.1    rumble 
    950   1.1    rumble 	if (console) {
    951   1.1    rumble 		DELAY(5 * 10000);	/* Let the output go out.... */
    952   1.1    rumble 	}
    953   1.1    rumble 
    954   1.1    rumble 	/*
    955   1.1    rumble 	 * Set up the hardware to a base state, in particular:
    956   1.1    rumble 	 * o reset transmitter and receiver
    957   1.1    rumble 	 * o set speeds and configurations
    958   1.1    rumble 	 * o receiver interrupts only (RxRDY and BREAK)
    959   1.1    rumble 	 */
    960   1.1    rumble 
    961   1.1    rumble 	s = spltty();
    962   1.1    rumble 	/* RTS off... */
    963   1.1    rumble 	SCN_OP_BIC(sc, sc->sc_op_rts);	/* "istop" */
    964   1.1    rumble 
    965   1.1    rumble 	ch_base[CH_CR] = CR_DIS_RX | CR_DIS_TX;
    966   1.1    rumble 	RECOVER();
    967   1.1    rumble 	ch_base[CH_CR] = CR_CMD_RESET_RX;
    968   1.1    rumble 	RECOVER();
    969   1.1    rumble 	ch_base[CH_CR] = CR_CMD_RESET_TX;
    970   1.1    rumble 	RECOVER();
    971   1.1    rumble 	ch_base[CH_CR] = CR_CMD_RESET_ERR;
    972   1.1    rumble 	RECOVER();
    973   1.1    rumble 	ch_base[CH_CR] = CR_CMD_RESET_BRK;
    974   1.1    rumble 	RECOVER();
    975   1.1    rumble 	ch_base[CH_CR] = CR_CMD_MR1;
    976   1.1    rumble 	RECOVER();
    977   1.1    rumble 
    978   1.1    rumble 	/* No receiver control of RTS. */
    979   1.1    rumble 	ch_base[CH_MR] = 0;
    980   1.1    rumble 	ch_base[CH_MR] = 0;
    981   1.1    rumble 
    982   1.1    rumble 	/* Initialize the uart structure if this is channel A. */
    983   1.1    rumble 	if (first) {
    984   1.1    rumble 		/* Disable all interrupts. */
    985   1.1    rumble 		duart_base[DU_IMR] = duart->imr = 0;
    986   1.1    rumble 
    987   1.1    rumble 		/* Output port config */
    988   1.1    rumble 		duart_base[DU_OPCR] = duart->opcr = 0;
    989   1.1    rumble 
    990   1.1    rumble 		/* Speeds... */
    991   1.1    rumble 		duart->mode = 0;
    992   1.1    rumble 
    993   1.1    rumble 		/*
    994   1.1    rumble 		 * Set initial speed to an illegal code that can be changed to
    995   1.1    rumble 		 * any other baud.
    996   1.1    rumble 		 */
    997   1.1    rumble 		duart->chan[0].icode = duart->chan[0].ocode = 0x2f;
    998   1.1    rumble 		duart->chan[1].icode = duart->chan[1].ocode = 0x2f;
    999   1.1    rumble 		duart->chan[0].ispeed = duart->chan[0].ospeed = 0;
   1000   1.1    rumble 		duart->chan[1].ispeed = duart->chan[1].ospeed = 0;
   1001   1.1    rumble 
   1002   1.1    rumble 		duart->acr = 0;
   1003   1.1    rumble 		duart->acr |= ACR_CT_TCLK1;	/* timer mode 1x clk */
   1004   1.1    rumble 	}
   1005   1.1    rumble 
   1006   1.1    rumble 	if (channel == 0) {
   1007   1.1    rumble 		duart->acr |= ACR_DELTA_DCDA;	/* Set CD int */
   1008   1.1    rumble 	} else {
   1009   1.1    rumble 		duart->acr |= ACR_DELTA_DCDB;	/* Set CD int */
   1010   1.1    rumble 	}
   1011   1.1    rumble 
   1012   1.1    rumble 	if (scnsir == NULL) {
   1013   1.1    rumble 		/* software intr: calls tty code, hence IPL_TTY */
   1014   1.1    rumble 		scnsir = softint_establish(SOFTINT_SERIAL, scnsoft, NULL);
   1015   1.1    rumble 	}
   1016   1.1    rumble 
   1017   1.1    rumble 	duart_base[DU_ACR] = (duart->mode & ACR_BRG) | duart->acr;
   1018   1.1    rumble 
   1019   1.1    rumble 	if (console)
   1020   1.1    rumble 		speed = scnconsrate;
   1021   1.1    rumble 	else
   1022   1.1    rumble 		speed = scndefaultrate;
   1023   1.1    rumble 
   1024   1.1    rumble 	scn_config(unit, channel, speed, speed, MR1_PNONE | MR1_CS8, MR2_STOP1);
   1025   1.1    rumble 	if (console) {
   1026   1.1    rumble 		maj = cdevsw_lookup_major(&scn_cdevsw);
   1027   1.1    rumble 		KASSERT(maj != NODEVMAJOR);
   1028   1.1    rumble 		shutdownhook_establish(scncnreinit, NULL);
   1029   1.1    rumble 		/* Make sure console can do scncngetc */
   1030   1.1    rumble 		duart_base[DU_OPSET] = channel ? (OP_RTSB | OP_DTRB) :
   1031   1.1    rumble 			(OP_RTSA | OP_DTRA);
   1032   1.1    rumble 	}
   1033   1.1    rumble 
   1034   1.1    rumble 	/* Turn on the receiver and transmitters */
   1035   1.1    rumble 	ch_base[CH_CR] = CR_ENA_RX | CR_ENA_TX;
   1036   1.1    rumble 
   1037   1.1    rumble 	/* Set up the interrupts. */
   1038   1.1    rumble 	duart->imr |= INT_IP;
   1039   1.1    rumble 	scn_rxdisable(sc);
   1040   1.1    rumble 	splx(s);
   1041   1.1    rumble 
   1042   1.1    rumble 	if (sc->sc_swflags) {
   1043   1.1    rumble 		printf("%c flags %d", delim, sc->sc_swflags);
   1044   1.1    rumble 		delim = ',';
   1045   1.1    rumble 	}
   1046   1.1    rumble 
   1047   1.1    rumble #ifdef KGDB
   1048   1.1    rumble 	major = cdevsw_lookup_major(&scn_cdevsw);
   1049   1.1    rumble 	KASSERT(major != NODEVMAJOR);
   1050   1.1    rumble 	if (kgdb_dev == makedev(major, unit)) {
   1051   1.1    rumble 		if (console)
   1052   1.1    rumble 			kgdb_dev = NODEV; /* can't debug over console port */
   1053   1.1    rumble 		else {
   1054   1.1    rumble 			scninit(kgdb_dev, kgdb_rate);
   1055   1.1    rumble 			scn_rxenable(sc);
   1056   1.1    rumble 			scn->sc_iskgdb = 1;
   1057   1.1    rumble 			kgdb_attach(scncngetc, scncnputc, kgdb_dev);
   1058   1.1    rumble 			if (kgdb_debug_init) {
   1059   1.1    rumble 				printf("%c ", delim);
   1060   1.1    rumble 				kgdb_connect(1);
   1061   1.1    rumble 			} else
   1062   1.1    rumble 				printf("%c kgdb enabled", delim);
   1063   1.1    rumble 			delim = ',';
   1064   1.1    rumble 		}
   1065   1.1    rumble 	}
   1066   1.1    rumble #endif
   1067   1.1    rumble 	printf("\n");
   1068   1.1    rumble }
   1069   1.1    rumble 
   1070   1.1    rumble /* ARGSUSED */
   1071   1.1    rumble int
   1072   1.1    rumble scnopen(dev_t dev, int flags, int mode, struct lwp *l)
   1073   1.1    rumble {
   1074   1.1    rumble 	struct tty *tp;
   1075   1.1    rumble 	int unit = DEV_UNIT(dev);
   1076   1.1    rumble 	struct scn_softc *sc;
   1077   1.1    rumble 	int error = 0;
   1078   1.1    rumble 
   1079   1.1    rumble 	if (unit >= scn_cd.cd_ndevs)
   1080   1.1    rumble 		return ENXIO;
   1081   1.1    rumble 	sc = SOFTC(unit);
   1082   1.1    rumble 	if (!sc)
   1083   1.1    rumble 		return ENXIO;
   1084   1.1    rumble 
   1085   1.1    rumble 	tp = sc->sc_tty;
   1086   1.1    rumble 	if (!tp) {
   1087   1.3     rmind 		tp = tty_alloc();
   1088   1.1    rumble 		sc->sc_tty = sc->sc_duart->chan[sc->sc_channel].tty = tp;
   1089   1.1    rumble 		tty_attach(tp);
   1090   1.1    rumble 	}
   1091   1.1    rumble 
   1092   1.1    rumble 	tp->t_oproc = scnstart;
   1093   1.1    rumble 	tp->t_param = scnparam;
   1094   1.1    rumble 	tp->t_hwiflow = scnhwiflow;
   1095   1.1    rumble 	tp->t_dev = dev;
   1096   1.1    rumble 
   1097   1.1    rumble 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
   1098   1.1    rumble 		return (EBUSY);
   1099   1.1    rumble 
   1100  1.10  riastrad 	ttylock(tp);
   1101   1.1    rumble 
   1102   1.1    rumble 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
   1103   1.1    rumble 		ttychars(tp);
   1104   1.1    rumble 		tp->t_iflag = TTYDEF_IFLAG;
   1105   1.1    rumble 		tp->t_oflag = TTYDEF_OFLAG;
   1106   1.1    rumble 		tp->t_cflag = SCNDEF_CFLAG;
   1107   1.1    rumble 
   1108   1.1    rumble 		sc->sc_rx_blocked = 0;
   1109   1.1    rumble 
   1110   1.1    rumble 		if (sc->sc_swflags & SCN_SW_CLOCAL)
   1111   1.1    rumble 			tp->t_cflag |= CLOCAL;
   1112   1.1    rumble 		if (sc->sc_swflags & SCN_SW_CRTSCTS)
   1113   1.1    rumble 			tp->t_cflag |= CCTS_OFLOW | CRTS_IFLOW;
   1114   1.1    rumble 		tp->t_lflag = TTYDEF_LFLAG;
   1115   1.1    rumble 		if (sc->sc_isconsole)
   1116   1.1    rumble 			tp->t_ispeed = tp->t_ospeed = scnconsrate;
   1117   1.1    rumble 		else
   1118   1.1    rumble 			tp->t_ispeed = tp->t_ospeed = scndefaultrate;
   1119   1.1    rumble 		scnparam(tp, &tp->t_termios);
   1120   1.1    rumble 		ttsetwater(tp);
   1121   1.1    rumble 
   1122   1.1    rumble 		/* Turn on DTR and RTS. */
   1123   1.1    rumble 		SCN_OP_BIS(sc, sc->sc_op_rts | sc->sc_op_dtr);
   1124   1.1    rumble 
   1125   1.1    rumble 		/* enable receiver interrupts */
   1126   1.1    rumble 		scn_rxenable(sc);
   1127   1.1    rumble 
   1128   1.1    rumble 		/* set carrier state; */
   1129   1.1    rumble 		if ((sc->sc_swflags & SCN_SW_SOFTCAR) || /* check ttyflags */
   1130   1.1    rumble 		    SCN_DCD(sc) ||			 /* check h/w */
   1131   1.1    rumble 		    DEV_DIALOUT(dev))
   1132   1.1    rumble 			tp->t_state |= TS_CARR_ON;
   1133   1.1    rumble 		else
   1134   1.1    rumble 			tp->t_state &= ~TS_CARR_ON;
   1135   1.1    rumble 	}
   1136   1.1    rumble 
   1137  1.10  riastrad 	ttyunlock(tp);
   1138   1.1    rumble 
   1139   1.1    rumble 	error = ttyopen(tp, SCN_DIALOUT(sc), flags & O_NONBLOCK);
   1140   1.1    rumble if (error) printf("ttyopen failed line %d, error %d\n", __LINE__, error);
   1141   1.1    rumble 	if (error)
   1142   1.1    rumble 		goto bad;
   1143   1.1    rumble 
   1144   1.1    rumble 	error = (*tp->t_linesw->l_open) (dev, tp);
   1145   1.1    rumble if (error) printf("l_open failed line %d, error %d\n", __LINE__, error);
   1146   1.1    rumble 	if (error)
   1147   1.1    rumble 		goto bad;
   1148   1.1    rumble 
   1149   1.1    rumble 	return (0);
   1150   1.1    rumble 
   1151   1.1    rumble bad:
   1152   1.1    rumble 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
   1153   1.1    rumble 		scn_rxdisable(sc);
   1154   1.1    rumble 		SCN_OP_BIC(sc, sc->sc_op_rts | sc->sc_op_dtr);
   1155   1.1    rumble 	}
   1156   1.1    rumble 
   1157   1.1    rumble 	return (error);
   1158   1.1    rumble }
   1159   1.1    rumble 
   1160   1.1    rumble 
   1161   1.1    rumble /*ARGSUSED*/
   1162   1.1    rumble int
   1163   1.1    rumble scnclose(dev_t dev, int flags, int mode, struct lwp *l)
   1164   1.1    rumble {
   1165   1.1    rumble 	int unit = DEV_UNIT(dev);
   1166   1.1    rumble 	struct scn_softc *sc = SOFTC(unit);
   1167   1.1    rumble 	struct tty *tp = sc->sc_tty;
   1168   1.1    rumble 	devmajor_t major;
   1169   1.1    rumble 
   1170   1.1    rumble 	(void)major;
   1171   1.1    rumble 
   1172   1.1    rumble 	if ((tp->t_state & TS_ISOPEN) == 0)
   1173   1.1    rumble 		return 0;
   1174   1.1    rumble 
   1175   1.1    rumble 	(*tp->t_linesw->l_close) (tp, flags);
   1176   1.1    rumble 
   1177   1.1    rumble #ifdef KGDB
   1178   1.1    rumble 	/* do not disable interrupts if debugging */
   1179   1.1    rumble 	major = cdevsw_lookup_major(&scn_devsw);
   1180   1.1    rumble 	KASSERT(major != cdevsw_lookup_major);
   1181   1.1    rumble 	if (kgdb_dev != makedev(major, unit))
   1182   1.1    rumble #endif
   1183   1.1    rumble 		if ((tp->t_state & TS_ISOPEN) == 0) {
   1184   1.1    rumble 			scn_rxdisable(sc);
   1185   1.1    rumble 		}
   1186   1.1    rumble 	if ((tp->t_cflag & HUPCL) && (sc->sc_swflags & SCN_SW_SOFTCAR) == 0) {
   1187   1.1    rumble 		SCN_OP_BIC(sc, sc->sc_op_dtr);
   1188   1.1    rumble 		/* hold low for 1 second */
   1189   1.1    rumble 		tsleep(sc, TTIPRI, ttclos, hz);
   1190   1.1    rumble 	}
   1191   1.1    rumble 	SCN_CLRDIALOUT(sc);
   1192   1.1    rumble 	ttyclose(tp);
   1193   1.1    rumble 
   1194   1.1    rumble #if 0
   1195   1.1    rumble 	if ((tp->t_state & TS_ISOPEN) == 0) {
   1196   1.3     rmind 		tty_free(tp);
   1197   1.1    rumble 		sc->sc_tty = (struct tty *) NULL;
   1198   1.1    rumble 	}
   1199   1.1    rumble #endif
   1200   1.1    rumble 
   1201   1.1    rumble 	return (0);
   1202   1.1    rumble }
   1203   1.1    rumble 
   1204   1.1    rumble int
   1205   1.1    rumble scnread(dev_t dev, struct uio *uio, int flags)
   1206   1.1    rumble {
   1207   1.1    rumble 	struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
   1208   1.1    rumble 	struct tty *tp = sc->sc_tty;
   1209   1.1    rumble 
   1210   1.1    rumble 	return ((*tp->t_linesw->l_read) (tp, uio, flags));
   1211   1.1    rumble }
   1212   1.1    rumble 
   1213   1.1    rumble int
   1214   1.1    rumble scnwrite(dev_t dev, struct uio *uio, int flags)
   1215   1.1    rumble {
   1216   1.1    rumble 	struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
   1217   1.1    rumble 	struct tty *tp = sc->sc_tty;
   1218   1.1    rumble 
   1219   1.1    rumble 	return ((*tp->t_linesw->l_write) (tp, uio, flags));
   1220   1.1    rumble }
   1221   1.1    rumble 
   1222   1.1    rumble int
   1223   1.1    rumble scnpoll(dev_t dev, int events, struct lwp *l)
   1224   1.1    rumble {
   1225   1.1    rumble 	struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
   1226   1.1    rumble 	struct tty *tp = sc->sc_tty;
   1227   1.1    rumble 
   1228   1.1    rumble 	return ((*tp->t_linesw->l_poll)(tp, events, l));
   1229   1.1    rumble }
   1230   1.1    rumble 
   1231   1.1    rumble struct tty *
   1232   1.1    rumble scntty(dev_t dev)
   1233   1.1    rumble {
   1234   1.1    rumble 	struct scn_softc *sc = SOFTC(DEV_UNIT(dev));
   1235   1.1    rumble 
   1236   1.1    rumble 	return sc->sc_tty;
   1237   1.1    rumble }
   1238   1.1    rumble 
   1239   1.1    rumble /* Worker routines for interrupt processing */
   1240   1.1    rumble static inline void
   1241   1.1    rumble dcd_int(struct scn_softc *sc, struct tty *tp, u_char new)
   1242   1.1    rumble {
   1243   1.1    rumble 
   1244   1.1    rumble 	if (sc->sc_swflags & SCN_SW_SOFTCAR)
   1245   1.1    rumble 		return;
   1246   1.1    rumble 
   1247   1.1    rumble #if 0
   1248   1.1    rumble 	printf("scn%d: dcd_int ip %x SCN_DCD %x new %x ipcr %x\n",
   1249   1.1    rumble 	    sc->unit,
   1250   1.1    rumble 	    sc->sc_duart->base[DU_IP],
   1251   1.1    rumble 	    SCN_DCD(sc),
   1252   1.1    rumble 	    new,
   1253   1.1    rumble 	    sc->sc_duart->base[DU_IPCR]
   1254   1.1    rumble 	    );
   1255   1.1    rumble #endif
   1256   1.1    rumble 
   1257   1.1    rumble /* XXX set some flag to have some lower (soft) int call line discipline? */
   1258   1.1    rumble 	if (!(*tp->t_linesw->l_modem) (tp, new == 0? 1: 0)) {
   1259   1.1    rumble 		SCN_OP_BIC(sc, sc->sc_op_rts | sc->sc_op_dtr);
   1260   1.1    rumble 	}
   1261   1.1    rumble }
   1262   1.1    rumble 
   1263   1.1    rumble /*
   1264   1.1    rumble  * Print out a ring or fifo overrun error message.
   1265   1.1    rumble  */
   1266   1.1    rumble static void
   1267   1.1    rumble scnoverrun(int unit, long *ptime, const char *what)
   1268   1.1    rumble {
   1269   1.1    rumble 
   1270   1.1    rumble 	if (*ptime != time_second) {
   1271   1.1    rumble 		*ptime = time_second;
   1272   1.1    rumble 		log(LOG_WARNING, "scn%d: %s overrun\n", unit, what);
   1273   1.1    rumble 	}
   1274   1.1    rumble }
   1275   1.1    rumble 
   1276   1.1    rumble /*
   1277   1.1    rumble  * Try to block or unblock input using hardware flow-control.
   1278   1.1    rumble  * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
   1279   1.1    rumble  * if this function returns non-zero, the TS_TBLOCK flag will
   1280   1.1    rumble  * be set or cleared according to the "stop" arg passed.
   1281   1.1    rumble  */
   1282   1.1    rumble int
   1283   1.1    rumble scnhwiflow(struct tty *tp, int stop)
   1284   1.1    rumble {
   1285   1.1    rumble 	int unit = DEV_UNIT(tp->t_dev);
   1286   1.1    rumble 	struct scn_softc *sc = SOFTC(unit);
   1287   1.1    rumble 	int s;
   1288   1.1    rumble 
   1289   1.1    rumble 	s = splrtty();
   1290   1.1    rumble 	if (!stop) {
   1291   1.1    rumble 		if (sc->sc_rbput - sc->sc_rbget - 1) {
   1292   1.1    rumble 			setsoftscn();
   1293   1.1    rumble 		}
   1294   1.1    rumble 	}
   1295   1.1    rumble 	splx(s);
   1296   1.1    rumble 	return 1;
   1297   1.1    rumble }
   1298   1.1    rumble 
   1299   1.1    rumble static int
   1300   1.1    rumble scnintr(void *arg)
   1301   1.1    rumble {
   1302   1.1    rumble 	struct duart *duart = arg;
   1303   1.1    rumble 	struct scn_softc *sc0 = duart->chan[0].sc;
   1304   1.1    rumble 	struct scn_softc *sc1 = duart->chan[1].sc;
   1305   1.1    rumble 
   1306   1.1    rumble 	struct tty *tp0 = (sc0 != NULL) ? sc0->sc_tty : NULL;
   1307   1.1    rumble 	struct tty *tp1 = (sc1 != NULL) ? sc1->sc_tty : NULL;
   1308   1.1    rumble 
   1309   1.1    rumble 	char rs_work;
   1310   1.1    rumble 	u_char rs_stat;
   1311   1.1    rumble 	u_char rs_ipcr;
   1312   1.1    rumble 
   1313   1.1    rumble 	/* Check for RX interrupts first, since we cannot distinguish by irq. */
   1314   1.1    rumble 	scnrxintr(duart);
   1315   1.1    rumble 
   1316   1.1    rumble 	do {
   1317   1.1    rumble 		/* Loop to pick up ALL pending interrupts for device. */
   1318   1.1    rumble 		rs_work = false;
   1319   1.1    rumble 		rs_stat = duart->base[DU_ISR];
   1320   1.1    rumble 
   1321   1.1    rumble /* channel a */
   1322   1.1    rumble 		if (tp0 != NULL) {
   1323   1.1    rumble 			if ((rs_stat & INT_TXA) && (tp0->t_state & TS_BUSY)) {
   1324   1.1    rumble 				/* output char done. */
   1325   1.1    rumble 				tp0->t_state &= ~(TS_BUSY | TS_FLUSH);
   1326   1.1    rumble 
   1327   1.1    rumble 				/* disable tx ints */
   1328   1.1    rumble 				duart->imr &= ~sc0->sc_tx_int;
   1329   1.1    rumble 				duart->base[DU_IMR] = duart->imr;
   1330   1.1    rumble 
   1331   1.1    rumble 				if (sc0->sc_heldchanges) {
   1332   1.1    rumble 					scn_setchip(sc0);
   1333   1.1    rumble 				}
   1334   1.1    rumble 
   1335   1.1    rumble 				(*tp0->t_linesw->l_start) (tp0);
   1336   1.1    rumble 				rs_work = true;
   1337   1.1    rumble 			}
   1338   1.1    rumble 		}
   1339   1.1    rumble 		/* channel b */
   1340   1.1    rumble 		if (tp1 != NULL) {
   1341   1.1    rumble 			if ((rs_stat & INT_TXB) && (tp1->t_state & TS_BUSY)) {
   1342   1.1    rumble 				/* output char done. */
   1343   1.1    rumble 				tp1->t_state &= ~(TS_BUSY | TS_FLUSH);
   1344   1.1    rumble 
   1345   1.1    rumble 				/* disable tx ints */
   1346   1.1    rumble 				duart->imr &= ~sc1->sc_tx_int;
   1347   1.1    rumble 				duart->base[DU_IMR] = duart->imr;
   1348   1.1    rumble 
   1349   1.1    rumble 				if (sc1->sc_heldchanges) {
   1350   1.1    rumble 					scn_setchip(sc1);
   1351   1.1    rumble 				}
   1352   1.1    rumble 
   1353   1.1    rumble 				(*tp1->t_linesw->l_start) (tp1);
   1354   1.1    rumble 				rs_work = true;
   1355   1.1    rumble 			}
   1356   1.1    rumble 		}
   1357   1.1    rumble 		if (rs_stat & INT_IP) {
   1358   1.1    rumble 			rs_work = true;
   1359   1.1    rumble 			rs_ipcr = duart->base[DU_IPCR];
   1360   1.1    rumble 
   1361   1.1    rumble 			if (rs_ipcr & IPCR_DELTA_DCDA && tp0 != NULL) {
   1362   1.1    rumble 				dcd_int(sc0, tp0, rs_ipcr & IPCR_DCDA);
   1363   1.1    rumble 			}
   1364   1.1    rumble 			if (rs_ipcr & IPCR_DELTA_DCDB && tp1 != NULL) {
   1365   1.1    rumble 				dcd_int(sc1, tp1, rs_ipcr & IPCR_DCDB);
   1366   1.1    rumble 			}
   1367   1.1    rumble 		}
   1368   1.1    rumble 	} while (rs_work);
   1369   1.1    rumble 
   1370   1.1    rumble 	return (1);	/* ? */
   1371   1.1    rumble }
   1372   1.1    rumble 
   1373   1.1    rumble /*
   1374   1.1    rumble  * Handle rxrdy/ffull interrupt: QUICKLY poll both channels (checking
   1375   1.1    rumble  * status first) and stash data in a ring buffer.  Ring buffer scheme
   1376   1.1    rumble  * borowed from sparc/zs.c requires NO interlock on data!
   1377   1.1    rumble  *
   1378   1.1    rumble  * This interrupt should NOT be included in spltty() mask since it
   1379   1.1    rumble  * invokes NO tty code!  The whole point is to allow tty input as much
   1380   1.1    rumble  * of the time as possible, while deferring "heavy" character
   1381   1.1    rumble  * processing until later.
   1382   1.1    rumble  *
   1383   1.1    rumble  * see scn.hw.README and scnsoft() for more info.
   1384   1.1    rumble  *
   1385   1.1    rumble  * THIS ROUTINE SHOULD BE KEPT AS CLEAN AS POSSIBLE!!
   1386   1.1    rumble  * IT'S A CANDIDATE FOR RECODING IN ASSEMBLER!!
   1387   1.1    rumble  */
   1388   1.1    rumble static inline int
   1389   1.1    rumble scn_rxintr(struct scn_softc *sc)
   1390   1.1    rumble {
   1391   1.1    rumble 	char sr;
   1392   1.1    rumble 	int i, n;
   1393   1.1    rumble 	int work;
   1394   1.1    rumble 
   1395   1.1    rumble 	work = 0;
   1396   1.1    rumble 	i = sc->sc_rbput;
   1397   1.1    rumble 	while (work <= 10) {
   1398   1.1    rumble #define SCN_GETCH(SC) \
   1399   1.1    rumble 		sr = (SC)->sc_chbase[CH_SR]; \
   1400   1.1    rumble 		if ((sr & SR_RX_RDY) == 0) \
   1401   1.1    rumble 			break; \
   1402   1.1    rumble 		if (sr & (SR_PARITY | SR_FRAME | SR_BREAK | SR_OVERRUN)) \
   1403   1.1    rumble 			goto exception; \
   1404   1.1    rumble 		work++; \
   1405   1.1    rumble 		(SC)->sc_rbuf[i++ & SCN_RING_MASK] = (SC)->sc_chbase[CH_DAT]
   1406   1.1    rumble 
   1407   1.1    rumble 		SCN_GETCH(sc); SCN_GETCH(sc); SCN_GETCH(sc);
   1408   1.1    rumble 		/* XXX more here if 26C92? -plb */
   1409   1.1    rumble 		continue;
   1410   1.1    rumble 	exception:
   1411   1.1    rumble #if defined(DDB)
   1412   1.1    rumble 		if (sc->sc_isconsole && (sr & SR_BREAK)) {
   1413   1.1    rumble 			Debugger();
   1414   1.1    rumble 			sr = sc->sc_chbase[CH_SR];
   1415   1.1    rumble 		}
   1416   1.1    rumble #endif
   1417   1.1    rumble #if defined(KGDB)
   1418   1.1    rumble 		if (sc->sc_iskgdb && (sr & SR_RX_RDY)) {
   1419   1.1    rumble 			kgdb_connect(1);
   1420   1.1    rumble 			sr = sc->sc_chbase[CH_SR];
   1421   1.1    rumble 		}
   1422   1.1    rumble #endif
   1423   1.1    rumble 		work++;
   1424   1.1    rumble 		sc->sc_rbuf[i++ & SCN_RING_MASK] = (sr << 8) | sc->sc_chbase[CH_DAT];
   1425   1.1    rumble 		sc->sc_chbase[CH_CR] = CR_CMD_RESET_ERR;	/* resets break? */
   1426   1.1    rumble 		RECOVER();
   1427   1.1    rumble 	}
   1428   1.1    rumble 	/*
   1429   1.1    rumble 	 * If ring is getting too full, try to block input.
   1430   1.1    rumble 	 */
   1431   1.1    rumble 	n = i - sc->sc_rbget;
   1432   1.1    rumble 	if (sc->sc_rbhiwat && (n > sc->sc_rbhiwat)) {
   1433   1.1    rumble 		/* If not CRTSCTS sc_rbhiwat is such that this
   1434   1.1    rumble 		 *  never happens.
   1435   1.1    rumble 		 * Clear RTS
   1436   1.1    rumble 		 */
   1437   1.1    rumble 		SCN_OP_BIC(sc, sc->sc_op_rts);
   1438   1.1    rumble 		sc->sc_rx_blocked = 1;
   1439   1.1    rumble 	}
   1440   1.1    rumble 	sc->sc_rbput = i;
   1441   1.1    rumble 
   1442   1.1    rumble 	return work;
   1443   1.1    rumble }
   1444   1.1    rumble 
   1445   1.1    rumble static void
   1446   1.1    rumble scnrxintr(void *arg)
   1447   1.1    rumble {
   1448   1.1    rumble 	struct duart *duart = arg;
   1449   1.1    rumble 	int work = 0;
   1450   1.1    rumble 
   1451   1.1    rumble 	if (duart->chan[0].sc != NULL)
   1452   1.1    rumble 		work += scn_rxintr(duart->chan[0].sc);
   1453   1.1    rumble 	if (duart->chan[1].sc != NULL)
   1454   1.1    rumble 		work += scn_rxintr(duart->chan[1].sc);
   1455   1.1    rumble 	if (work > 0) {
   1456   1.1    rumble 		setsoftscn();	/* trigger s/w intr */
   1457   1.1    rumble #ifdef SCN_TIMING
   1458   1.1    rumble 		microtime(&tstart);
   1459   1.1    rumble #endif
   1460   1.1    rumble 	}
   1461   1.1    rumble }
   1462   1.1    rumble 
   1463   1.1    rumble /*
   1464   1.1    rumble  * Here on soft interrupt (at spltty) to empty ring buffers.
   1465   1.1    rumble  *
   1466   1.1    rumble  * Dave's original scheme was to use the DUART receiver timeout
   1467   1.1    rumble  * interrupt. This requires 2692's (which my board doesn't have), and
   1468   1.1    rumble  * I also liked the idea of using the C/T to generate alternate and/or
   1469   1.1    rumble  * arbitrary bauds. -plb
   1470   1.1    rumble  *
   1471   1.1    rumble  * The ringbuffer code comes from Chris Torek's SPARC 44bsd zs driver
   1472   1.1    rumble  * (hence the LBL notice on top of this file), DOES NOT require
   1473   1.1    rumble  * interlocking with interrupt levels!
   1474   1.1    rumble  *
   1475   1.1    rumble  * The 44bsd sparc/zs driver reads the ring buffer from a separate
   1476   1.1    rumble  * zssoftint, while the SunOS 4.x zs driver appears to use
   1477   1.1    rumble  * timeout()'s.  timeouts seem to be too slow to deal with high data
   1478   1.1    rumble  * rates.  I know, I tried them.
   1479   1.1    rumble  * -plb.
   1480   1.1    rumble  */
   1481   1.1    rumble static void
   1482   1.1    rumble scnsoft(void *arg)
   1483   1.1    rumble {
   1484   1.1    rumble 	int s, unit;
   1485   1.1    rumble #ifdef SCN_TIMING
   1486   1.1    rumble 	struct timeval tend;
   1487   1.1    rumble 	u_long  t;
   1488   1.1    rumble 
   1489   1.1    rumble 	microtime(&tend);
   1490   1.1    rumble 	t = (tend.tv_sec - tstart.tv_sec) * 1000000 + (tend.tv_usec - tstart.tv_usec);
   1491   1.1    rumble 	t = (t + tick / 20) / (tick / 10);
   1492   1.1    rumble 	if (t >= NJITTER - 1) {
   1493   1.1    rumble 		t = NJITTER - 1;
   1494   1.1    rumble 	}
   1495   1.1    rumble 	scn_jitter[t]++;
   1496   1.1    rumble #endif
   1497   1.1    rumble 
   1498   1.1    rumble 	for (unit = 0; unit < scn_cd.cd_ndevs; unit++) {
   1499   1.1    rumble 		struct scn_softc *sc;
   1500   1.1    rumble 		struct tty *tp;
   1501   1.1    rumble 		int n, get;
   1502   1.1    rumble 
   1503   1.1    rumble 		sc = SOFTC(unit);
   1504   1.1    rumble 		if (sc == NULL) {
   1505   1.1    rumble 			continue;
   1506   1.1    rumble 		}
   1507   1.1    rumble 		tp = sc->sc_tty;
   1508   1.1    rumble #ifdef KGDB
   1509   1.1    rumble 		if (tp == NULL) {
   1510   1.1    rumble 			sc->sc_rbget = sc->sc_rbput;
   1511   1.1    rumble 			continue;
   1512   1.1    rumble 		}
   1513   1.1    rumble #endif
   1514   1.1    rumble 		if (tp == NULL || tp->t_state & TS_TBLOCK) {
   1515   1.1    rumble 			continue;
   1516   1.1    rumble 		}
   1517   1.1    rumble 
   1518   1.1    rumble 
   1519   1.1    rumble 		get = sc->sc_rbget;
   1520   1.1    rumble 
   1521   1.1    rumble 		/* NOTE: fetch from rbput is atomic */
   1522   1.1    rumble 		while (get != (n = sc->sc_rbput)) {
   1523   1.1    rumble 			/*
   1524   1.1    rumble 			 * Compute the number of interrupts in the receive ring.
   1525   1.1    rumble 			 * If the count is overlarge, we lost some events, and
   1526   1.1    rumble 			 * must advance to the first valid one.  It may get
   1527   1.1    rumble 			 * overwritten if more data are arriving, but this is
   1528   1.1    rumble 			 * too expensive to check and gains nothing (we already
   1529   1.1    rumble 			 * lost out; all we can do at this point is trade one
   1530   1.1    rumble 			 * kind of loss for another).
   1531   1.1    rumble 			 */
   1532   1.1    rumble 			n -= get;
   1533   1.1    rumble 			if (n > SCN_RING_SIZE) {
   1534   1.1    rumble 				scnoverrun(unit, &sc->sc_rotime, "ring");
   1535   1.1    rumble 				get += n - SCN_RING_SIZE;
   1536   1.1    rumble 				n = SCN_RING_SIZE;
   1537   1.1    rumble 				sc->sc_ring_overruns++;
   1538   1.1    rumble 			}
   1539   1.1    rumble 			while (--n >= 0) {
   1540   1.1    rumble 				int c, sr;
   1541   1.1    rumble 
   1542   1.1    rumble 				if (tp->t_state & TS_TBLOCK) {
   1543   1.1    rumble 					sc->sc_rbget = get;
   1544   1.1    rumble 					goto done;
   1545   1.1    rumble 				}
   1546   1.1    rumble 				/* Race to keep ahead of incoming interrupts. */
   1547   1.1    rumble 				c = sc->sc_rbuf[get++ & SCN_RING_MASK];
   1548   1.1    rumble 
   1549   1.1    rumble 				sr = c >> 8;	/* extract status */
   1550   1.1    rumble 				c &= 0xff;	/* leave just character */
   1551   1.1    rumble 
   1552   1.1    rumble 				if (sr & SR_OVERRUN) {
   1553   1.1    rumble 					scnoverrun(unit, &sc->sc_fotime, "fifo");
   1554   1.1    rumble 					sc->sc_fifo_overruns++;
   1555   1.1    rumble 				}
   1556   1.1    rumble 				if (sr & SR_PARITY) {
   1557   1.1    rumble 					c |= TTY_PE;
   1558   1.1    rumble 					sc->sc_parity_errors++;
   1559   1.1    rumble 				}
   1560   1.1    rumble 				if (sr & SR_FRAME) {
   1561   1.1    rumble 					c |= TTY_FE;
   1562   1.1    rumble 					sc->sc_framing_errors++;
   1563   1.1    rumble 				}
   1564   1.1    rumble 				if (sr & SR_BREAK) {
   1565   1.1    rumble #if 0
   1566   1.1    rumble 					/*
   1567   1.1    rumble 					 * See DDB_CHECK() comments in
   1568   1.1    rumble 					 * scnrxintr()
   1569   1.1    rumble 					 */
   1570   1.1    rumble 					if (sc->sc_isconsole)
   1571   1.1    rumble 						Debugger();
   1572   1.1    rumble #endif
   1573   1.1    rumble 					c = TTY_FE | 0;
   1574   1.1    rumble 					sc->sc_breaks++;
   1575   1.1    rumble 				}
   1576   1.1    rumble 
   1577   1.1    rumble 				(*tp->t_linesw->l_rint) (c, tp);
   1578   1.1    rumble 
   1579   1.1    rumble 				if (sc->sc_rx_blocked && n < SCN_RING_THRESH) {
   1580   1.1    rumble 					s = splrtty();
   1581   1.1    rumble 					sc->sc_rx_blocked = 0;
   1582   1.1    rumble 					SCN_OP_BIS(sc, sc->sc_op_rts);
   1583   1.1    rumble 					splx(s);
   1584   1.1    rumble 				}
   1585   1.1    rumble 
   1586   1.1    rumble 			}
   1587   1.1    rumble 			sc->sc_rbget = get;
   1588   1.1    rumble 		}
   1589   1.1    rumble 	done: ;
   1590   1.1    rumble 	}
   1591   1.1    rumble }
   1592   1.1    rumble 
   1593   1.1    rumble /* Convert TIOCM_xxx bits to output port bits. */
   1594   1.1    rumble static unsigned char
   1595   1.1    rumble opbits(struct scn_softc *sc, int tioc_bits)
   1596   1.1    rumble {
   1597   1.1    rumble 
   1598   1.1    rumble 	return ((((tioc_bits) & TIOCM_DTR) ? sc->sc_op_dtr : 0) |
   1599   1.1    rumble 	    (((tioc_bits) & TIOCM_RTS) ? sc->sc_op_rts : 0));
   1600   1.1    rumble }
   1601   1.1    rumble 
   1602   1.1    rumble int
   1603   1.1    rumble scnioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
   1604   1.1    rumble {
   1605   1.1    rumble 	int unit = DEV_UNIT(dev);
   1606   1.1    rumble 	struct scn_softc *sc = SOFTC(unit);
   1607   1.1    rumble 	struct tty *tp = sc->sc_tty;
   1608   1.1    rumble 	int error;
   1609   1.1    rumble 
   1610   1.1    rumble 	error = (*tp->t_linesw->l_ioctl) (tp, cmd, data, flags, l);
   1611   1.1    rumble 	if (error != EPASSTHROUGH)
   1612   1.1    rumble 		return (error);
   1613   1.1    rumble 
   1614   1.1    rumble 	error = ttioctl(tp, cmd, data, flags, l);
   1615   1.1    rumble 	if (error != EPASSTHROUGH)
   1616   1.1    rumble 		return (error);
   1617   1.1    rumble 
   1618   1.1    rumble 	switch (cmd) {
   1619   1.1    rumble 	case TIOCSBRK:
   1620   1.1    rumble 		sc->sc_chbase[CH_CR] = CR_CMD_START_BRK;
   1621   1.1    rumble 		break;
   1622   1.1    rumble 
   1623   1.1    rumble 	case TIOCCBRK:
   1624   1.1    rumble 		sc->sc_chbase[CH_CR] = CR_CMD_STOP_BRK;
   1625   1.1    rumble 		break;
   1626   1.1    rumble 
   1627   1.1    rumble 	case TIOCSDTR:
   1628   1.1    rumble 		SCN_OP_BIS(sc, sc->sc_op_dtr | sc->sc_op_rts);
   1629   1.1    rumble 		break;
   1630   1.1    rumble 
   1631   1.1    rumble 	case TIOCCDTR:
   1632   1.1    rumble 		SCN_OP_BIC(sc, sc->sc_op_dtr | sc->sc_op_rts);
   1633   1.1    rumble 		break;
   1634   1.1    rumble 
   1635   1.1    rumble 	case TIOCMSET: {
   1636   1.1    rumble 			int     s;
   1637   1.1    rumble 			unsigned char sbits, cbits;
   1638   1.1    rumble 
   1639   1.1    rumble 			/* set bits */
   1640   1.1    rumble 			sbits = opbits(sc, *(int *) data);
   1641   1.1    rumble 
   1642   1.1    rumble 			/* get bits to clear */
   1643   1.1    rumble 			cbits = ~sbits & (sc->sc_op_dtr | sc->sc_op_rts);
   1644   1.1    rumble 
   1645   1.1    rumble 			s = spltty();
   1646   1.1    rumble 			if (sbits) {
   1647   1.1    rumble 				SCN_OP_BIS(sc, sbits);
   1648   1.1    rumble 			}
   1649   1.1    rumble 			if (cbits) {
   1650   1.1    rumble 				SCN_OP_BIC(sc, cbits);
   1651   1.1    rumble 			}
   1652   1.1    rumble 			splx(s);
   1653   1.1    rumble 			break;
   1654   1.1    rumble 		}
   1655   1.1    rumble 
   1656   1.1    rumble 	case TIOCMBIS:
   1657   1.1    rumble 		SCN_OP_BIS(sc, opbits(sc, *(int *) data));
   1658   1.1    rumble 		break;
   1659   1.1    rumble 
   1660   1.1    rumble 	case TIOCMBIC:
   1661   1.1    rumble 		SCN_OP_BIC(sc, opbits(sc, *(int *) data));
   1662   1.1    rumble 		break;
   1663   1.1    rumble 
   1664   1.1    rumble 	case TIOCMGET: {
   1665   1.1    rumble 			int     bits;
   1666   1.6  christos 			unsigned char ip;
   1667   1.1    rumble 
   1668   1.1    rumble 			/* s = spltty(); */
   1669   1.1    rumble 			ip = sc->sc_duart->base[DU_IP];
   1670   1.1    rumble 			/* splx(s); */
   1671   1.1    rumble 
   1672   1.1    rumble 			bits = 0;
   1673   1.1    rumble 			if (ip & sc->sc_ip_dcd)
   1674   1.1    rumble 				bits |= TIOCM_CD;
   1675   1.1    rumble 			if (ip & sc->sc_ip_cts)
   1676   1.1    rumble 				bits |= TIOCM_CTS;
   1677   1.1    rumble 
   1678   1.1    rumble #if 0
   1679   1.6  christos 			/*
   1680   1.6  christos 			 * XXX sigh; cannot get op current state!! even if
   1681   1.6  christos 			 * maintained in private, RTS is done in h/w!!
   1682   1.6  christos 			 */
   1683   1.6  christos 			unsigned char op = 0;
   1684   1.1    rumble 			if (op & sc->sc_op_dtr)
   1685   1.1    rumble 				bits |= TIOCM_DTR;
   1686   1.1    rumble 			if (op & sc->sc_op_rts)
   1687   1.1    rumble 				bits |= TIOCM_RTS;
   1688   1.1    rumble #endif
   1689   1.1    rumble 
   1690   1.1    rumble 			*(int *) data = bits;
   1691   1.1    rumble 			break;
   1692   1.1    rumble 		}
   1693   1.1    rumble 
   1694   1.1    rumble 	case TIOCGFLAGS:{
   1695   1.1    rumble 			int     bits = 0;
   1696   1.1    rumble 
   1697   1.1    rumble 			if (sc->sc_swflags & SCN_SW_SOFTCAR)
   1698   1.1    rumble 				bits |= TIOCFLAG_SOFTCAR;
   1699   1.1    rumble 			if (sc->sc_swflags & SCN_SW_CLOCAL)
   1700   1.1    rumble 				bits |= TIOCFLAG_CLOCAL;
   1701   1.1    rumble 			if (sc->sc_swflags & SCN_SW_CRTSCTS)
   1702   1.1    rumble 				bits |= TIOCFLAG_CRTSCTS;
   1703   1.1    rumble 			if (sc->sc_swflags & SCN_SW_MDMBUF)
   1704   1.1    rumble 				bits |= TIOCFLAG_MDMBUF;
   1705   1.1    rumble 
   1706   1.1    rumble 			*(int *) data = bits;
   1707   1.1    rumble 			break;
   1708   1.1    rumble 		}
   1709   1.1    rumble 	case TIOCSFLAGS:{
   1710   1.1    rumble 			int     userbits, driverbits = 0;
   1711   1.1    rumble 
   1712   1.1    rumble 			error = kauth_authorize_device_tty(l->l_cred,
   1713   1.1    rumble 			    KAUTH_DEVICE_TTY_PRIVSET, tp);
   1714   1.1    rumble 			if (error != 0)
   1715   1.1    rumble 				return (EPERM);
   1716   1.1    rumble 
   1717   1.1    rumble 			userbits = *(int *) data;
   1718   1.1    rumble 			if (userbits & TIOCFLAG_SOFTCAR)
   1719   1.1    rumble 				driverbits |= SCN_SW_SOFTCAR;
   1720   1.1    rumble 			if (userbits & TIOCFLAG_CLOCAL)
   1721   1.1    rumble 				driverbits |= SCN_SW_CLOCAL;
   1722   1.1    rumble 			if (userbits & TIOCFLAG_CRTSCTS)
   1723   1.1    rumble 				driverbits |= SCN_SW_CRTSCTS;
   1724   1.1    rumble 			if (userbits & TIOCFLAG_MDMBUF)
   1725   1.1    rumble 				driverbits |= SCN_SW_MDMBUF;
   1726   1.1    rumble 
   1727   1.1    rumble 			sc->sc_swflags = driverbits;
   1728   1.1    rumble 
   1729   1.1    rumble 			break;
   1730   1.1    rumble 		}
   1731   1.1    rumble 
   1732   1.1    rumble 	default:
   1733   1.1    rumble 		return (EPASSTHROUGH);
   1734   1.1    rumble 	}
   1735   1.1    rumble 	return (0);
   1736   1.1    rumble }
   1737   1.1    rumble 
   1738   1.1    rumble int
   1739   1.1    rumble scnparam(struct tty *tp, struct termios *t)
   1740   1.1    rumble {
   1741   1.1    rumble 	int cflag = t->c_cflag;
   1742   1.1    rumble 	int unit = DEV_UNIT(tp->t_dev);
   1743   1.1    rumble 	char mr1, mr2;
   1744   1.1    rumble 	int error;
   1745   1.1    rumble 	struct scn_softc *sc = SOFTC(unit);
   1746   1.1    rumble 
   1747   1.1    rumble 	/* Is this a hang up? */
   1748   1.1    rumble 	if (t->c_ospeed == B0) {
   1749   1.1    rumble 		SCN_OP_BIC(sc, sc->sc_op_dtr);
   1750   1.1    rumble 		/* leave DTR down. see comment in scnclose() -plb */
   1751   1.1    rumble 		return (0);
   1752   1.1    rumble 	}
   1753   1.1    rumble 	mr1 = mr2 = 0;
   1754   1.1    rumble 
   1755   1.1    rumble 	/* Parity? */
   1756   1.1    rumble 	if (cflag & PARENB) {
   1757   1.1    rumble 		if ((cflag & PARODD) == 0)
   1758   1.1    rumble 			mr1 |= MR1_PEVEN;
   1759   1.1    rumble 		else
   1760   1.1    rumble 			mr1 |= MR1_PODD;
   1761   1.1    rumble 	} else
   1762   1.1    rumble 		mr1 |= MR1_PNONE;
   1763   1.1    rumble 
   1764   1.1    rumble 	/* Stop bits. */
   1765   1.1    rumble 	if (cflag & CSTOPB)
   1766   1.1    rumble 		mr2 |= MR2_STOP2;
   1767   1.1    rumble 	else
   1768   1.1    rumble 		mr2 |= MR2_STOP1;
   1769   1.1    rumble 
   1770   1.1    rumble 	/* Data bits. */
   1771   1.1    rumble 	switch (cflag & CSIZE) {
   1772   1.1    rumble 	case CS5:
   1773   1.1    rumble 		mr1 |= MR1_CS5;
   1774   1.1    rumble 		break;
   1775   1.1    rumble 	case CS6:
   1776   1.1    rumble 		mr1 |= MR1_CS6;
   1777   1.1    rumble 		break;
   1778   1.1    rumble 	case CS7:
   1779   1.1    rumble 		mr1 |= MR1_CS7;
   1780   1.1    rumble 		break;
   1781   1.1    rumble 	case CS8:
   1782   1.1    rumble 	default:
   1783   1.1    rumble 		mr1 |= MR1_CS8;
   1784   1.1    rumble 		break;
   1785   1.1    rumble 	}
   1786   1.1    rumble 
   1787   1.1    rumble 	if (cflag & CCTS_OFLOW)
   1788   1.1    rumble 		mr2 |= MR2_TXCTS;
   1789   1.1    rumble 
   1790   1.1    rumble 	if (cflag & CRTS_IFLOW) {
   1791   1.1    rumble 		mr1 |= MR1_RXRTS;
   1792   1.1    rumble 		sc->sc_rbhiwat = SCN_RING_HIWAT;
   1793   1.1    rumble 	} else {
   1794   1.1    rumble 		sc->sc_rbhiwat = 0;
   1795   1.1    rumble 	}
   1796   1.1    rumble 
   1797   1.1    rumble 	error = scn_config(unit, sc->sc_channel, t->c_ispeed,
   1798   1.1    rumble 	    t->c_ospeed, mr1, mr2);
   1799   1.1    rumble 
   1800   1.1    rumble 	/* If successful, copy to tty */
   1801   1.1    rumble 	if (!error) {
   1802   1.1    rumble 		tp->t_ispeed = t->c_ispeed;
   1803   1.1    rumble 		tp->t_ospeed = t->c_ospeed;
   1804   1.1    rumble 		tp->t_cflag = cflag;
   1805   1.1    rumble 	}
   1806   1.1    rumble 	return (error);
   1807   1.1    rumble }
   1808   1.1    rumble 
   1809   1.1    rumble /*
   1810   1.1    rumble  * Start or restart a transmission.
   1811   1.1    rumble  */
   1812   1.1    rumble void
   1813   1.1    rumble scnstart(struct tty *tp)
   1814   1.1    rumble {
   1815   1.1    rumble 	int s, c;
   1816   1.1    rumble 	int unit = DEV_UNIT(tp->t_dev);
   1817   1.1    rumble 	struct scn_softc *sc = SOFTC(unit);
   1818   1.1    rumble 
   1819   1.1    rumble 	s = spltty();
   1820   1.1    rumble 	if (tp->t_state & (TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
   1821   1.1    rumble 		goto out;
   1822   1.1    rumble 	if (!ttypull(tp))
   1823   1.1    rumble 		goto out;
   1824   1.1    rumble 
   1825   1.1    rumble 	tp->t_state |= TS_BUSY;
   1826   1.1    rumble 
   1827   1.1    rumble 	while (sc->sc_chbase[CH_SR] & SR_TX_RDY) {
   1828   1.1    rumble 		if ((c = getc(&tp->t_outq)) == -1)
   1829   1.1    rumble 			break;
   1830   1.1    rumble 		sc->sc_chbase[CH_DAT] = c;
   1831   1.1    rumble 	}
   1832   1.1    rumble 	sc->sc_duart->imr |= (sc->sc_tx_int | sc->sc_rx_int);
   1833   1.1    rumble 	sc->sc_duart->base[DU_IMR] = sc->sc_duart->imr;
   1834   1.1    rumble 
   1835   1.1    rumble out:
   1836   1.1    rumble 	splx(s);
   1837   1.1    rumble }
   1838   1.1    rumble 
   1839   1.1    rumble /*
   1840   1.1    rumble  * Stop output on a line.
   1841   1.1    rumble  */
   1842   1.1    rumble /*ARGSUSED*/
   1843   1.1    rumble void
   1844   1.1    rumble scnstop(struct tty *tp, int flags)
   1845   1.1    rumble {
   1846   1.1    rumble 	int s;
   1847   1.1    rumble 
   1848   1.1    rumble 	s = spltty();
   1849   1.1    rumble 	if (tp->t_state & TS_BUSY) {
   1850   1.1    rumble 		if ((tp->t_state & TS_TTSTOP) == 0)
   1851   1.1    rumble 			tp->t_state |= TS_FLUSH;
   1852   1.1    rumble 	}
   1853   1.1    rumble 	splx(s);
   1854   1.1    rumble }
   1855   1.1    rumble 
   1856   1.1    rumble /*
   1857   1.1    rumble  * Following are all routines needed for SCN to act as console.
   1858   1.1    rumble  */
   1859   1.1    rumble 
   1860   1.1    rumble void
   1861   1.1    rumble scncnprobe(struct consdev *cn)
   1862   1.1    rumble {
   1863   1.1    rumble }
   1864   1.1    rumble 
   1865   1.1    rumble void
   1866   1.1    rumble scncnreinit(void *v)
   1867   1.1    rumble {
   1868   1.1    rumble 	volatile u_char *du_base =
   1869   1.1    rumble 	    (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
   1870   1.1    rumble 
   1871   1.1    rumble 	du_base[DU_OPSET] =
   1872   1.1    rumble 	    SCN_CONSCHAN ? (OP_RTSB | OP_DTRB) : (OP_RTSA | OP_DTRA);
   1873   1.1    rumble }
   1874   1.1    rumble 
   1875   1.1    rumble void
   1876   1.1    rumble scncninit(struct consdev *cn)
   1877   1.1    rumble {
   1878   1.1    rumble 	devmajor_t major;
   1879   1.1    rumble 
   1880   1.1    rumble 	/* initialize required fields */
   1881   1.1    rumble 	major = cdevsw_lookup_major(&scn_cdevsw);
   1882   1.1    rumble 	KASSERT(major != NODEV);
   1883   1.1    rumble 	cn->cn_dev = makedev(major, SCN_CONSOLE);
   1884   1.1    rumble 	cn->cn_pri = CN_REMOTE;
   1885   1.1    rumble 
   1886   1.1    rumble 	scninit(cn->cn_dev, scnconsrate);
   1887   1.1    rumble }
   1888   1.1    rumble 
   1889   1.1    rumble /* Used by scncninit and kgdb startup. */
   1890   1.1    rumble int
   1891   1.1    rumble scninit(dev_t dev, int rate)
   1892   1.1    rumble {
   1893   1.1    rumble /* XXX - maintain PROM's settings */
   1894   1.1    rumble #if 0
   1895   1.1    rumble 	volatile u_char *du_base =
   1896   1.1    rumble 	    (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
   1897   1.1    rumble 	int unit = DEV_UNIT(dev);
   1898   1.1    rumble 
   1899   1.1    rumble 	du_base[DU_OPSET] =
   1900   1.1    rumble 	    SCN_CONSCHAN ? (OP_RTSB | OP_DTRB) : (OP_RTSA | OP_DTRA);
   1901   1.1    rumble 	scn_config(unit, SCN_CONSCHAN, rate, rate,
   1902   1.1    rumble 	    MR1_PNONE | MR1_CS8, MR2_STOP1);
   1903   1.1    rumble #endif
   1904   1.1    rumble 	return (0);
   1905   1.1    rumble }
   1906   1.1    rumble 
   1907   1.1    rumble /*
   1908   1.1    rumble  * Console kernel input character routine.
   1909   1.1    rumble  */
   1910   1.1    rumble int
   1911   1.1    rumble scncngetc(dev_t dev)
   1912   1.1    rumble {
   1913   1.1    rumble 	volatile u_char *ch_base =
   1914   1.1    rumble 	    (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
   1915   1.1    rumble 	char c;
   1916   1.1    rumble 	int s;
   1917   1.1    rumble 
   1918   1.1    rumble 	s = spltty();
   1919   1.1    rumble 
   1920   1.1    rumble 	while ((ch_base[CH_SR] & SR_RX_RDY) == 0)
   1921   1.1    rumble 		;
   1922   1.1    rumble 	c = ch_base[CH_DAT];
   1923   1.1    rumble 
   1924   1.1    rumble 	splx(s);
   1925   1.1    rumble 	return c;
   1926   1.1    rumble }
   1927   1.1    rumble 
   1928   1.1    rumble void
   1929   1.1    rumble scncnpollc(dev_t dev, int on)
   1930   1.1    rumble {
   1931   1.1    rumble }
   1932   1.1    rumble 
   1933   1.1    rumble /*
   1934   1.1    rumble  * Console kernel output character routine.
   1935   1.1    rumble  */
   1936   1.1    rumble void
   1937   1.1    rumble scncnputc(dev_t dev, int c)
   1938   1.1    rumble {
   1939   1.1    rumble 	volatile u_char *ch_base =
   1940   1.1    rumble 	    (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
   1941   1.1    rumble 	volatile u_char *du_base =
   1942   1.1    rumble 	    (volatile u_char *)MIPS_PHYS_TO_KSEG1(0x1fb80004);
   1943   1.1    rumble 	int s;
   1944   1.1    rumble 
   1945   1.1    rumble 	s = spltty();
   1946   1.1    rumble 
   1947   1.1    rumble 	if (c == '\n')
   1948   1.1    rumble 		scncnputc(dev, '\r');
   1949   1.1    rumble 
   1950   1.1    rumble 	while ((ch_base[CH_SR] & SR_TX_RDY) == 0)
   1951   1.1    rumble 		;
   1952   1.1    rumble 	ch_base[CH_DAT] = c;
   1953   1.1    rumble 	while ((ch_base[CH_SR] & SR_TX_RDY) == 0)
   1954   1.1    rumble 		;
   1955   1.1    rumble 	du_base[DU_ISR];
   1956   1.1    rumble 
   1957   1.1    rumble 	splx(s);
   1958   1.1    rumble }
   1959