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