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