si.c revision 38485
110015Speter/*
212496Speter * Device driver for Specialix range (SI/XIO) of serial line multiplexors.
310015Speter *
434832Speter * Copyright (C) 1990, 1992, 1998 Specialix International,
510015Speter * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
634832Speter * Copyright (C) 1995, Peter Wemm <peter@netplex.com.au>
710015Speter *
810015Speter * Originally derived from:	SunOS 4.x version
910015Speter * Ported from BSDI version to FreeBSD by Peter Wemm.
1010015Speter *
1110015Speter * Redistribution and use in source and binary forms, with or without
1210015Speter * modification, are permitted provided that the following conditions
1310015Speter * are met:
1410015Speter * 1. Redistributions of source code must retain the above copyright
1510015Speter *    notices, this list of conditions and the following disclaimer.
1610015Speter * 2. Redistributions in binary form must reproduce the above copyright
1710015Speter *    notices, this list of conditions and the following disclaimer in the
1810015Speter *    documentation and/or other materials provided with the distribution.
1910015Speter * 3. All advertising materials mentioning features or use of this software
2010015Speter *    must display the following acknowledgement:
2110015Speter *	This product includes software developed by Andy Rutter of
2210015Speter *	Advanced Methods and Tools Ltd. based on original information
2310015Speter *	from Specialix International.
2410015Speter * 4. Neither the name of Advanced Methods and Tools, nor Specialix
2510015Speter *    International may be used to endorse or promote products derived from
2610015Speter *    this software without specific prior written permission.
2710015Speter *
2810015Speter * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
2910015Speter * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
3010015Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
3110015Speter * NO EVENT SHALL THE AUTHORS BE LIABLE.
3210015Speter *
3338485Sbde *	$Id: si.c,v 1.75 1998/08/16 01:04:48 bde Exp $
3410015Speter */
3510015Speter
3610015Speter#ifndef lint
3734832Speterstatic const char si_copyright1[] =  "@(#) Copyright (C) Specialix International, 1990,1992,1998",
3834832Speter		  si_copyright2[] =  "@(#) Copyright (C) Andy Rutter 1993",
3934832Speter		  si_copyright3[] =  "@(#) Copyright (C) Peter Wemm 1995";
4010015Speter#endif	/* not lint */
4110015Speter
4231778Seivind#include "opt_compat.h"
4332929Seivind#include "opt_debug_si.h"
4432726Seivind#include "opt_devfs.h"
4531778Seivind
4610015Speter#include <sys/param.h>
4710015Speter#include <sys/systm.h>
4824207Sbde#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
4924207Sbde#include <sys/ioctl_compat.h>
5024207Sbde#endif
5110015Speter#include <sys/tty.h>
5210015Speter#include <sys/proc.h>
5310015Speter#include <sys/conf.h>
5424131Sbde#include <sys/fcntl.h>
5510015Speter#include <sys/dkstat.h>
5610015Speter#include <sys/kernel.h>
5710015Speter#include <sys/malloc.h>
5815683Speter#include <sys/sysctl.h>
5912675Sjulian#ifdef DEVFS
6012675Sjulian#include <sys/devfsext.h>
6112675Sjulian#endif /*DEVFS*/
6210015Speter
6310015Speter#include <machine/clock.h>
6410015Speter
6512659Sbde#include <vm/vm.h>
6612662Sdg#include <vm/pmap.h>
6712659Sbde
6810015Speter#include <i386/isa/icu.h>
6910015Speter#include <i386/isa/isa.h>
7010015Speter#include <i386/isa/isa_device.h>
7110015Speter
7210015Speter#include <i386/isa/sireg.h>
7310015Speter#include <machine/si.h>
7413353Speter#include <machine/stdarg.h>
7510015Speter
7633395Speter#include "pci.h"
7733395Speter#if NPCI > 0
7833395Speter#include <pci/pcivar.h>
7933395Speter#endif
8033395Speter
8134832Speter#include "eisa.h"
8234832Speter#if NEISA > 0
8334832Speter#include <i386/eisa/eisaconf.h>
8434832Speter#include <i386/isa/icu.h>
8534832Speter#endif
8634832Speter
8710015Speter#include "si.h"
8810015Speter
8910015Speter/*
9010015Speter * This device driver is designed to interface the Specialix International
9134832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA,
9234832Speter * EISA or PCI bus machine.
9310015Speter *
9434832Speter * The controller is interfaced to the host via dual port RAM
9534832Speter * and an interrupt.
9633395Speter *
9734832Speter * The code for the Host 1 (very old ISA cards) has not been tested.
9810015Speter */
9910015Speter
10017547Speter#define	POLL		/* turn on poller to scan for lost interrupts */
10117547Speter#define REALPOLL	/* on each poll, scan for work regardless */
10217547Speter#define POLLHZ	(hz/10)	/* 10 times per second */
10312496Speter#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
10434832Speter#define INT_COUNT 25000		/* max of 125 ints per second */
10534832Speter#define JET_INT_COUNT 100	/* max of 100 ints per second */
10615639Speter#define RXINT_COUNT 1	/* one rxint per 10 milliseconds */
10710015Speter
10810015Speterenum si_mctl { GET, SET, BIS, BIC };
10910015Speter
11010015Speterstatic void si_command __P((struct si_port *, int, int));
11110015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int));
11210015Speterstatic void si_write_enable __P((struct si_port *, int));
11338351Sbdestatic int si_Sioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
11410015Speterstatic void si_start __P((struct tty *));
11525047Sbdestatic timeout_t si_lstart;
11610015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
11710015Speter					struct si_port *pp));
11810015Speterstatic void sihardclose __P((struct si_port *pp));
11910015Speterstatic void sidtrwakeup __P((void *chan));
12010015Speter
12112724Sphkstatic int	siparam __P((struct tty *, struct termios *));
12210015Speter
12312724Sphkstatic	int	siprobe __P((struct isa_device *id));
12412724Sphkstatic	int	siattach __P((struct isa_device *id));
12510708Speterstatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
12634735Speterstatic void	si_intr __P((int unit));
12734832Speterstatic char *	si_modulename __P((int host_type, int uart_type));
12810708Speter
12912675Sjulianstruct isa_driver sidriver =
13012675Sjulian	{ siprobe, siattach, "si" };
13112675Sjulian
13234832Speterstatic u_long sipcieisacount = 0;
13334832Speter
13433395Speter#if NPCI > 0
13512675Sjulian
13633395Speterstatic char *sipciprobe __P((pcici_t, pcidi_t));
13733395Speterstatic void sipciattach __P((pcici_t, int));
13833395Speter
13933395Speterstatic struct pci_device sipcidev = {
14033395Speter	"si",
14133395Speter	sipciprobe,
14233395Speter	sipciattach,
14334832Speter	&sipcieisacount,
14433395Speter	NULL,
14533395Speter};
14633395Speter
14733395SpeterDATA_SET (pcidevice_set, sipcidev);
14833395Speter
14933395Speter#endif
15033395Speter
15134832Speter#if NEISA > 0
15234832Speter
15334832Speterstatic int si_eisa_probe __P((void));
15434832Speterstatic int si_eisa_attach __P((struct eisa_device *ed));
15534832Speter
15634832Speterstatic struct eisa_driver si_eisa_driver = {
15734832Speter	"si",
15834832Speter	si_eisa_probe,
15934832Speter	si_eisa_attach,
16034832Speter	NULL,
16134832Speter	&sipcieisacount,
16234832Speter};
16334832Speter
16434832SpeterDATA_SET(eisadriver_set, si_eisa_driver);
16534832Speter
16634832Speter#endif
16734832Speter
16812675Sjulianstatic	d_open_t	siopen;
16912675Sjulianstatic	d_close_t	siclose;
17012675Sjulianstatic	d_read_t	siread;
17112675Sjulianstatic	d_write_t	siwrite;
17212675Sjulianstatic	d_ioctl_t	siioctl;
17312675Sjulianstatic	d_stop_t	sistop;
17412731Sbdestatic	d_devtotty_t	sidevtotty;
17512675Sjulian
17638485Sbde#define	CDEV_MAJOR	68
17738485Sbdestatic	struct cdevsw	si_cdevsw = {
17838485Sbde	siopen,		siclose,	siread,		siwrite,
17938485Sbde	siioctl,	sistop,		noreset,	sidevtotty,
18038485Sbde	ttpoll,		nommap,		NULL,		"si",
18138485Sbde	NULL,		-1,		nodump,		nopsize,
18238485Sbde	D_TTY,
18338485Sbde};
18412675Sjulian
18512174Speter#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
18613353Speter
18713353Speterstatic	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,
18813353Speter				...));
18910708Speterstatic	char	*si_mctl2str __P((enum si_mctl cmd));
19013353Speter
19110708Speter#define	DPRINT(x)	si_dprintf x
19213353Speter
19310708Speter#else
19410708Speter#define	DPRINT(x)	/* void */
19510708Speter#endif
19610708Speter
19710962Speterstatic int si_Nports;
19810962Speterstatic int si_Nmodules;
19910962Speterstatic int si_debug = 0;	/* data, not bss, so it's patchable */
20010015Speter
20134832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, "");
20234832Speter
20310962Speterstatic struct tty *si_tty;
20410962Speter
20534832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */
20634832Speter/* old: si2_z280.c */
20734832Speterextern unsigned char si2_z280_download[];
20834832Speterextern unsigned short si2_z280_downloadaddr;
20934832Speterextern int si2_z280_dsize;
21034832Speter/* new: si3_t225.c */
21134832Speterextern unsigned char si3_t225_download[];
21234832Speterextern unsigned short si3_t225_downloadaddr;
21334832Speterextern int si3_t225_dsize;
21434832Speterextern unsigned char si3_t225_bootstrap[];
21534832Speterextern unsigned short si3_t225_bootloadaddr;
21634832Speterextern int si3_t225_bsize;
21710015Speter
21833395Speter
21910044Speterstruct si_softc {
22010044Speter	int 		sc_type;	/* adapter type */
22110044Speter	char 		*sc_typename;	/* adapter type string */
22210044Speter
22310044Speter	struct si_port	*sc_ports;	/* port structures for this card */
22410044Speter
22510044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
22610044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
22710044Speter	int		sc_nport;	/* # ports on this card */
22810044Speter	int		sc_irq;		/* copy of attach irq */
22934832Speter#if NEISA > 0
23010044Speter	int		sc_eisa_iobase;	/* EISA io port address */
23134832Speter	int		sc_eisa_irq;	/* EISA irq number */
23234832Speter#endif
23312675Sjulian#ifdef	DEVFS
23412675Sjulian	struct {
23534735Speter		void	*ttya;
23612826Speter		void	*cuaa;
23712675Sjulian		void	*ttyl;
23834735Speter		void	*cual;
23912675Sjulian		void	*ttyi;
24034735Speter		void	*cuai;
24112675Sjulian	} devfs_token[32]; /* what is the max per card? */
24213165Speter	void	*control_token;
24312675Sjulian#endif
24410044Speter};
24512724Sphkstatic struct si_softc si_softc[NSI];		/* up to 4 elements */
24610044Speter
24712174Speter#ifndef B2000	/* not standard, but the hardware knows it. */
24810015Speter# define B2000 2000
24910015Speter#endif
25010015Speterstatic struct speedtab bdrates[] = {
25110015Speter	B75,	CLK75,		/* 0x0 */
25210015Speter	B110,	CLK110,		/* 0x1 */
25310015Speter	B150,	CLK150,		/* 0x3 */
25410015Speter	B300,	CLK300,		/* 0x4 */
25510015Speter	B600,	CLK600,		/* 0x5 */
25610015Speter	B1200,	CLK1200,	/* 0x6 */
25710015Speter	B2000,	CLK2000,	/* 0x7 */
25810015Speter	B2400,	CLK2400,	/* 0x8 */
25910015Speter	B4800,	CLK4800,	/* 0x9 */
26010015Speter	B9600,	CLK9600,	/* 0xb */
26110015Speter	B19200,	CLK19200,	/* 0xc */
26210015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
26310015Speter	B57600, CLK57600,	/* 0xd */
26410015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
26510015Speter	-1,	-1
26610015Speter};
26710015Speter
26810015Speter
26910015Speter/* populated with approx character/sec rates - translated at card
27010015Speter * initialisation time to chars per tick of the clock */
27110015Speterstatic int done_chartimes = 0;
27210015Speterstatic struct speedtab chartimes[] = {
27310015Speter	B75,	8,
27410015Speter	B110,	11,
27510015Speter	B150,	15,
27610015Speter	B300,	30,
27710015Speter	B600,	60,
27810015Speter	B1200,	120,
27910015Speter	B2000,	200,
28010015Speter	B2400,	240,
28110015Speter	B4800,	480,
28210015Speter	B9600,	960,
28310015Speter	B19200,	1920,
28410015Speter	B38400, 3840,
28510015Speter	B57600, 5760,
28610015Speter	B115200, 11520,
28710015Speter	-1,	-1
28810015Speter};
28910015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
29010015Speter
29110015Speter#ifdef POLL
29215683Speterstatic int si_pollrate;			/* in addition to irq */
29317547Speterstatic int si_realpoll;			/* poll HW on timer */
29415639Speter
29516403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, "");
29617547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, "");
29715639Speter
29810015Speterstatic int init_finished = 0;
29910015Speterstatic void si_poll __P((void *));
30010015Speter#endif
30110015Speter
30210015Speter/*
30310015Speter * Array of adapter types and the corresponding RAM size. The order of
30410015Speter * entries here MUST match the ordinal of the adapter type.
30510015Speter */
30610015Speterstatic char *si_type[] = {
30710015Speter	"EMPTY",
30810015Speter	"SIHOST",
30934832Speter	"SIMCA",		/* FreeBSD does not support Microchannel */
31010015Speter	"SIHOST2",
31110015Speter	"SIEISA",
31233395Speter	"SIPCI",
31333395Speter	"SXPCI",
31433395Speter	"SXISA",
31510015Speter};
31610015Speter
31733395Speter#if NPCI > 0
31833395Speter
31933395Speterstatic char *
32033395Spetersipciprobe(configid, deviceid)
32133395Speterpcici_t configid;
32233395Speterpcidi_t deviceid;
32333395Speter{
32433395Speter	switch (deviceid)
32533395Speter	{
32633395Speter		case 0x400011cb:
32733395Speter			return("Specialix SI/XIO PCI host card");
32833395Speter			break;
32933395Speter		case 0x200011cb:
33033395Speter			if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb)
33133395Speter				return("Specialix SX PCI host card");
33233395Speter			else
33333395Speter				return NULL;
33433395Speter			break;
33533395Speter		default:
33633395Speter			return NULL;
33733395Speter	}
33833395Speter	/*NOTREACHED*/
33933395Speter}
34033395Speter
34133395Spetervoid
34233395Spetersipciattach(configid, unit)
34333395Speterpcici_t configid;
34433395Speterint unit;
34533395Speter{
34633395Speter	struct isa_device id;
34733395Speter	vm_offset_t vaddr,paddr;
34833395Speter	u_long mapval = 0;	/* shut up gcc, should not be needed */
34933395Speter
35033395Speter	switch ( pci_conf_read(configid, 0) >> 16 )
35133395Speter	{
35233395Speter		case 0x4000:
35333395Speter			si_softc[unit].sc_type = SIPCI;
35433395Speter			mapval = SIPCIBADR;
35534832Speter			break;
35633395Speter		case 0x2000:
35733395Speter			si_softc[unit].sc_type = SIJETPCI;
35833395Speter			mapval = SIJETBADR;
35934832Speter			break;
36033395Speter	}
36133395Speter	if (!pci_map_mem(configid, mapval, &vaddr, &paddr))
36233395Speter	{
36333395Speter		printf("si%d: couldn't map memory\n", unit);
36433395Speter	}
36533395Speter
36633395Speter	/*
36733395Speter	 * We're cheating here a little bit. The argument to an ISA
36833395Speter	 * interrupt routine is the unit number. The argument to a
36933395Speter	 * PCI interrupt handler is a void *, but we're simply going
37033395Speter	 * to be lazy and hand it the unit number.
37133395Speter	 */
37234735Speter	if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) {
37333395Speter		printf("si%d: couldn't map interrupt\n", unit);
37433395Speter	}
37533395Speter	si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type];
37633395Speter
37733395Speter	/*
37833395Speter	 * More cheating: We're going to dummy up a struct isa_device
37933395Speter	 * and call the other attach routine. We don't really have to
38033395Speter	 * fill in very much of the structure, since we filled in a
38133395Speter	 * little of the soft state already.
38233395Speter	 */
38334735Speter	id.id_unit = unit;
38434735Speter	id.id_maddr = (caddr_t) vaddr;
38533395Speter	siattach(&id);
38633395Speter}
38733395Speter
38833395Speter#endif
38933395Speter
39034832Speter#if NEISA > 0
39134832Speter
39234832Speterstatic const char *si_eisa_match __P((eisa_id_t id));
39334832Speter
39434832Speterstatic const char *
39534832Spetersi_eisa_match(id)
39634832Speter	eisa_id_t id;
39734832Speter{
39834832Speter	if (id == SIEISADEVID)
39934832Speter		return ("Specialix SI/XIO EISA host card");
40034832Speter	return (NULL);
40134832Speter}
40234832Speter
40334832Speterstatic int
40434832Spetersi_eisa_probe(void)
40534832Speter{
40634832Speter	struct eisa_device *ed = NULL;
40734832Speter	int count, irq;
40834832Speter
40934832Speter	for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++)
41034832Speter	{
41134832Speter		u_long port,maddr;
41234832Speter
41334832Speter		port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE;
41434832Speter		eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE);
41534832Speter		maddr = (inb(port+1) << 24) | (inb(port) << 16);
41634832Speter		irq  = ((inb(port+2) >> 4) & 0xf);
41734832Speter		eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE);
41834832Speter		eisa_add_intr(ed, irq);
41934832Speter		eisa_registerdev(ed, &si_eisa_driver);
42034832Speter		count++;
42134832Speter	}
42234832Speter	return count;
42334832Speter}
42434832Speter
42534832Speterstatic int
42634832Spetersi_eisa_attach(ed)
42734832Speter	struct eisa_device *ed;
42834832Speter{
42934832Speter	struct isa_device id;
43034832Speter	resvaddr_t *maddr,*iospace;
43134832Speter	u_int irq;
43234832Speter	struct si_softc *sc;
43334832Speter
43434832Speter	sc = &si_softc[ed->unit];
43534832Speter
43634832Speter	sc->sc_type = SIEISA;
43734832Speter	sc->sc_typename = si_type[sc->sc_type];
43834832Speter
43934832Speter	if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) {
44034832Speter		printf("si%d: no iospace??\n", ed->unit);
44134832Speter		return -1;
44234832Speter	}
44334832Speter	sc->sc_eisa_iobase = iospace->addr;
44434832Speter
44534832Speter	irq  = ((inb(iospace->addr + 2) >> 4) & 0xf);
44634832Speter	sc->sc_eisa_irq = irq;
44734832Speter
44834832Speter	if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) {
44934832Speter		printf("si%d: where am I??\n", ed->unit);
45034832Speter		return -1;
45134832Speter	}
45234832Speter	eisa_reg_start(ed);
45334832Speter	if (eisa_reg_iospace(ed, iospace)) {
45434832Speter		printf("si%d: failed to register iospace 0x%x\n",
45534832Speter			ed->unit, iospace);
45634832Speter		return -1;
45734832Speter	}
45834832Speter	if (eisa_reg_mspace(ed, maddr)) {
45934832Speter		printf("si%d: failed to register memspace 0x%x\n",
46034832Speter			ed->unit, maddr);
46134832Speter		return -1;
46234832Speter	}
46334832Speter	/*
46434832Speter	 * We're cheating here a little bit. The argument to an ISA
46534832Speter	 * interrupt routine is the unit number. The argument to a
46634832Speter	 * EISA interrupt handler is a void *, but we're simply going
46734832Speter	 * to be lazy and hand it the unit number.
46834832Speter	 */
46934832Speter	if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr,
47038353Sbde		(void *)(intptr_t)(ed->unit), &tty_imask, 1)) {
47134832Speter		printf("si%d: failed to register interrupt %d\n",
47234832Speter			ed->unit, irq);
47334832Speter		return -1;
47434832Speter	}
47534832Speter	eisa_reg_end(ed);
47634832Speter	if (eisa_enable_intr(ed, irq)) {
47734832Speter		return -1;
47834832Speter	}
47934832Speter
48034832Speter	/*
48134832Speter	 * More cheating: We're going to dummy up a struct isa_device
48234832Speter	 * and call the other attach routine. We don't really have to
48334832Speter	 * fill in very much of the structure, since we filled in a
48434832Speter	 * little of the soft state already.
48534832Speter	 */
48634832Speter	id.id_unit = ed->unit;
48734832Speter	id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE);
48834832Speter	return (siattach(&id));
48934832Speter}
49034832Speter
49134832Speter#endif
49234832Speter
49334832Speter
49410015Speter/* Look for a valid board at the given mem addr */
49512724Sphkstatic int
49610015Spetersiprobe(id)
49710015Speter	struct isa_device *id;
49810015Speter{
49910015Speter	struct si_softc *sc;
50010015Speter	int type;
50110015Speter	u_int i, ramsize;
50210015Speter	volatile BYTE was, *ux;
50310015Speter	volatile unsigned char *maddr;
50410015Speter	unsigned char *paddr;
50510015Speter
50617547Speter	si_pollrate = POLLHZ;		/* default 10 per second */
50717547Speter#ifdef REALPOLL
50817547Speter	si_realpoll = 1;		/* scan always */
50917547Speter#endif
51010015Speter	maddr = id->id_maddr;		/* virtual address... */
51110015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
51210015Speter
51312496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
51412496Speter		id->id_unit, id->id_maddr, paddr));
51510015Speter
51610015Speter	/*
51710015Speter	 * this is a lie, but it's easier than trying to handle caching
51810015Speter	 * and ram conflicts in the >1M and <16M region.
51910015Speter	 */
52010015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
52110015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
52238353Sbde		printf("si%d: iomem (%p) out of range\n",
52338353Sbde			id->id_unit, (void *)paddr);
52410015Speter		return(0);
52510015Speter	}
52610015Speter
52710015Speter	if (id->id_unit >= NSI) {
52810015Speter		/* THIS IS IMPOSSIBLE */
52910015Speter		return(0);
53010015Speter	}
53110015Speter
53210015Speter	if (((u_int)paddr & 0x7fff) != 0) {
53310015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
53410015Speter			"si%d: iomem (%x) not on 32k boundary\n",
53510015Speter			id->id_unit, paddr));
53610015Speter		return(0);
53710015Speter	}
53810015Speter
53934735Speter	if (si_softc[id->id_unit].sc_typename) {
54034832Speter		/* EISA or PCI has taken this unit, choose another */
54134735Speter		for (i=0; i < NSI; i++) {
54234735Speter			if (si_softc[i].sc_typename == NULL) {
54334735Speter				id->id_unit = i;
54434735Speter				break;
54534735Speter			}
54634735Speter		}
54734735Speter		if (i >= NSI) {
54834735Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
54934735Speter				"si%d: cannot realloc unit\n", id->id_unit));
55034735Speter			return (0);
55134735Speter		}
55234735Speter	}
55334735Speter
55410015Speter	for (i=0; i < NSI; i++) {
55534735Speter		sc = &si_softc[i];
55610015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
55710015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
55810015Speter				"si%d: iomem (%x) already configured to si%d\n",
55910015Speter				id->id_unit, sc->sc_paddr, i));
56010015Speter			return(0);
56110015Speter		}
56210015Speter	}
56310015Speter
56410015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
56510015Speter	*maddr = 0x17;
56610015Speter	if (*maddr != 0x17) {
56710015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
56810015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
56910015Speter			id->id_unit, paddr));
57010015Speterfail:
57110015Speter		return(0);
57210015Speter	}
57310015Speter	/*
57433395Speter	 * Let's look first for a JET ISA card, since that's pretty easy
57534832Speter	 *
57634832Speter	 * All jet hosts are supposed to have this string in the IDROM,
57734832Speter	 * but it's not worth checking on self-IDing busses like PCI.
57833395Speter	 */
57934832Speter	{
58034832Speter		unsigned char *jet_chk_str = "JET HOST BY KEV#";
58134832Speter
58234832Speter		for (i = 0; i < strlen(jet_chk_str); i++)
58334832Speter			if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i))
58434832Speter				goto try_mk2;
58534832Speter	}
58633395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
58733395Speter		"si%d: JET first check - 0x%x\n",
58833395Speter		id->id_unit, (*(maddr+SIJETIDBASE))));
58933395Speter	if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff))
59033395Speter		goto try_mk2;
59133395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
59233395Speter		"si%d: JET second check - 0x%x\n",
59333395Speter		id->id_unit, (*(maddr+SIJETIDBASE+2))));
59433395Speter	if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8))
59533395Speter		goto try_mk2;
59633395Speter	/* It must be a Jet ISA or RIO card */
59733395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
59833395Speter		"si%d: JET id check - 0x%x\n",
59933395Speter		id->id_unit, (*(maddr+SIUNIQID))));
60033395Speter	if ((*(maddr+SIUNIQID) & 0xf0) !=0x20)
60133395Speter		goto try_mk2;
60233395Speter	/* It must be a Jet ISA SI/XIO card */
60333395Speter	*(maddr + SIJETCONFIG) = 0;
60433395Speter	type = SIJETISA;
60533395Speter	ramsize = SIJET_RAMSIZE;
60633395Speter	goto got_card;
60733395Speter	/*
60810015Speter	 * OK, now to see if whatever responded is really an SI card.
60933395Speter	 * Try for a MK II next (SIHOST2)
61010015Speter	 */
61133395Spetertry_mk2:
61234832Speter	for (i = SIPLSIG; i < SIPLSIG + 8; i++)
61310015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
61410015Speter			goto try_mk1;
61510015Speter
61610015Speter	/* It must be an SIHOST2 */
61710015Speter	*(maddr + SIPLRESET) = 0;
61810015Speter	*(maddr + SIPLIRQCLR) = 0;
61910015Speter	*(maddr + SIPLIRQSET) = 0x10;
62010015Speter	type = SIHOST2;
62110015Speter	ramsize = SIHOST2_RAMSIZE;
62210015Speter	goto got_card;
62310015Speter
62410015Speter	/*
62510015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
62610015Speter	 */
62710015Spetertry_mk1:
62810015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
62910015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
63010015Speter	*(maddr+SIRAM) = 0x17;
63110015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
63210015Speter		goto fail;
63310015Speter	*(maddr+0x7ff8) = 0x17;
63410015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
63510015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
63610015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
63710015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
63810015Speter		goto fail;
63910015Speter	}
64010015Speter
64134832Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXX */
64210015Speter	type = SIHOST;
64310015Speter	ramsize = SIHOST_RAMSIZE;
64410015Speter
64510015Spetergot_card:
64612496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
64712496Speter		id->id_unit, type));
64810015Speter	/* Try the acid test */
64918515Speter	ux = maddr + SIRAM;
65034832Speter	for (i = 0; i < ramsize; i++, ux++)
65110015Speter		*ux = (BYTE)(i&0xff);
65218515Speter	ux = maddr + SIRAM;
65334832Speter	for (i = 0; i < ramsize; i++, ux++) {
65410015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
65510015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
65612174Speter				"si%d: match fail at phys 0x%x, was %x should be %x\n",
65734832Speter				id->id_unit, paddr + i, was, i&0xff));
65810015Speter			goto fail;
65910015Speter		}
66010015Speter	}
66110015Speter
66210015Speter	/* clear out the RAM */
66318515Speter	ux = maddr + SIRAM;
66434832Speter	for (i = 0; i < ramsize; i++)
66510015Speter		*ux++ = 0;
66618515Speter	ux = maddr + SIRAM;
66734832Speter	for (i = 0; i < ramsize; i++) {
66810015Speter		if ((was = *ux++) != 0) {
66910015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
67012174Speter				"si%d: clear fail at phys 0x%x, was %x\n",
67134832Speter				id->id_unit, paddr + i, was));
67210015Speter			goto fail;
67310015Speter		}
67410015Speter	}
67510015Speter
67610015Speter	/*
67710015Speter	 * Success, we've found a valid board, now fill in
67810015Speter	 * the adapter structure.
67910015Speter	 */
68010015Speter	switch (type) {
68110015Speter	case SIHOST2:
68234832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
68310015Speterbad_irq:
68410015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
68510015Speter				"si%d: bad IRQ value - %d\n",
68610015Speter				id->id_unit, id->id_irq));
68710015Speter			return(0);
68810015Speter		}
68910015Speter		id->id_msize = SIHOST2_MEMSIZE;
69010015Speter		break;
69110015Speter	case SIHOST:
69234832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
69310015Speter			goto bad_irq;
69410015Speter		}
69510015Speter		id->id_msize = SIHOST_MEMSIZE;
69610015Speter		break;
69733395Speter	case SIJETISA:
69834832Speter		if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) {
69933395Speter			goto bad_irq;
70033395Speter		}
70134832Speter		id->id_msize = SIJETISA_MEMSIZE;
70233395Speter		break;
70334832Speter	case SIMCA:		/* MCA */
70410015Speter	default:
70510015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
70610015Speter		return(0);
70710015Speter	}
70834832Speter	id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */
70910015Speter	si_softc[id->id_unit].sc_type = type;
71010015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
71110015Speter	return(-1);	/* -1 == found */
71210015Speter}
71310015Speter
71410015Speter/*
71534832Speter * We have to make an 8 bit version of bcopy, since some cards can't
71634832Speter * deal with 32 bit I/O
71734832Speter */
71834832Speter#if 1
71934832Speterstatic void
72034832Spetersi_bcopy(const void *src, void *dst, size_t len)
72134832Speter{
72234832Speter	while (len--)
72334832Speter		*(((u_char *)dst)++) = *(((u_char *)src)++);
72434832Speter}
72534832Speter#else
72634832Speter#define si_bcopy bcopy
72734832Speter#endif
72834832Speter
72934832Speter
73034832Speter/*
73110015Speter * Attach the device.  Initialize the card.
73234832Speter *
73334832Speter * This routine also gets called by the EISA and PCI attach routines.
73434832Speter * It presumes that the softstate for the unit has had had its type field
73534832Speter * and the EISA specific stuff filled in, as well as the kernel virtual
73634832Speter * base address and the unit number of the isa_device struct.
73710015Speter */
73812724Sphkstatic int
73910015Spetersiattach(id)
74010015Speter	struct isa_device *id;
74110015Speter{
74210015Speter	int unit = id->id_unit;
74310015Speter	struct si_softc *sc = &si_softc[unit];
74410015Speter	struct si_port *pp;
74510015Speter	volatile struct si_channel *ccbp;
74610015Speter	volatile struct si_reg *regp;
74710015Speter	volatile caddr_t maddr;
74810015Speter	struct si_module *modp;
74910015Speter	struct tty *tp;
75010015Speter	struct speedtab *spt;
75110015Speter	int nmodule, nport, x, y;
75212174Speter	int uart_type;
75310015Speter
75412496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
75510015Speter
75610015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
75710015Speter	sc->sc_maddr = id->id_maddr;
75810015Speter	sc->sc_irq = id->id_irq;
75910015Speter
76033395Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit,
76133395Speter		sc->sc_typename, sc->sc_paddr, sc->sc_maddr));
76233395Speter
76310015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
76410015Speter
76510015Speter	maddr = sc->sc_maddr;
76610015Speter
76734832Speter	/* Stop the CPU first so it won't stomp around while we load */
76834832Speter
76934832Speter	switch (sc->sc_type) {
77034832Speter#if NEISA > 0
77134832Speter		case SIEISA:
77234832Speter			outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4);
77334832Speter		break;
77434832Speter#endif
77534832Speter#if NPCI > 0
77634832Speter		case SIPCI:
77734832Speter			*(maddr+SIPCIRESET) = 0;
77834832Speter		break;
77934832Speter		case SIJETPCI: /* fall through to JET ISA */
78034832Speter#endif
78134832Speter		case SIJETISA:
78234832Speter			*(maddr+SIJETCONFIG) = 0;
78334832Speter		break;
78434832Speter		case SIHOST2:
78534832Speter			*(maddr+SIPLRESET) = 0;
78634832Speter		break;
78734832Speter		case SIHOST:
78834832Speter			*(maddr+SIRESET) = 0;
78934832Speter		break;
79034832Speter		default: /* this should never happen */
79134832Speter			printf("si%d: unsupported configuration\n", unit);
79234832Speter			return 0;
79334832Speter		break;
79434832Speter	}
79534832Speter
79634832Speter	/* OK, now lets download the download code */
79734832Speter
79836956Ssteve	if (SI_ISJET(sc->sc_type)) {
79933395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n",
80034832Speter			id->id_unit, si3_t225_dsize));
80134832Speter		si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr,
80234832Speter			si3_t225_dsize);
80334832Speter		DPRINT((0, DBG_DOWNLOAD,
80434832Speter			"si%d: jet_bootstrap: nbytes %d -> %x\n",
80534832Speter			id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr));
80634832Speter		si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr,
80734832Speter			si3_t225_bsize);
80834832Speter	} else {
80933395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
81034832Speter			id->id_unit, si2_z280_dsize));
81134832Speter		si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr,
81234832Speter			si2_z280_dsize);
81333395Speter	}
81410015Speter
81534832Speter	/* Now start the CPU */
81634832Speter
81710015Speter	switch (sc->sc_type) {
81834832Speter#if NEISA > 0
81910015Speter	case SIEISA:
82034832Speter		/* modify the download code to tell it that it's on an EISA */
82134832Speter		*(maddr + 0x42) = 1;
82234832Speter		outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4);
82334832Speter		(void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */
82410015Speter		break;
82534832Speter#endif
82633395Speter	case SIPCI:
82734832Speter		/* modify the download code to tell it that it's on a PCI */
82833395Speter		*(maddr+0x42) = 1;
82933395Speter		*(maddr+SIPCIRESET) = 1;
83033395Speter		*(maddr+SIPCIINTCL) = 0;
83133395Speter		break;
83233395Speter	case SIJETPCI:
83333395Speter		*(maddr+SIJETRESET) = 0;
83433395Speter		*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN;
83533395Speter		break;
83633395Speter	case SIJETISA:
83733395Speter		*(maddr+SIJETRESET) = 0;
83834832Speter		switch (sc->sc_irq) {
83934832Speter		case IRQ9:
84034832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90;
84134832Speter			break;
84234832Speter		case IRQ10:
84334832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0;
84434832Speter			break;
84534832Speter		case IRQ11:
84634832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0;
84734832Speter			break;
84834832Speter		case IRQ12:
84934832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0;
85034832Speter			break;
85134832Speter		case IRQ15:
85234832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0;
85334832Speter			break;
85434832Speter		}
85533395Speter		break;
85610015Speter	case SIHOST:
85710015Speter		*(maddr+SIRESET_CL) = 0;
85810015Speter		*(maddr+SIINTCL_CL) = 0;
85910015Speter		break;
86010015Speter	case SIHOST2:
86110015Speter		*(maddr+SIPLRESET) = 0x10;
86210015Speter		switch (sc->sc_irq) {
86310015Speter		case IRQ11:
86410015Speter			*(maddr+SIPLIRQ11) = 0x10;
86510015Speter			break;
86610015Speter		case IRQ12:
86710015Speter			*(maddr+SIPLIRQ12) = 0x10;
86810015Speter			break;
86910015Speter		case IRQ15:
87010015Speter			*(maddr+SIPLIRQ15) = 0x10;
87110015Speter			break;
87210015Speter		}
87310015Speter		*(maddr+SIPLIRQCLR) = 0x10;
87410015Speter		break;
87534832Speter	default: /* this should _REALLY_ never happen */
87634832Speter		printf("si%d: Uh, it was supported a second ago...\n", unit);
87734832Speter		return 0;
87810015Speter	}
87910015Speter
88010015Speter	DELAY(1000000);			/* wait around for a second */
88110015Speter
88210015Speter	regp = (struct si_reg *)maddr;
88310015Speter	y = 0;
88410015Speter					/* wait max of 5 sec for init OK */
88510015Speter	while (regp->initstat == 0 && y++ < 10) {
88610015Speter		DELAY(500000);
88710015Speter	}
88810015Speter	switch (regp->initstat) {
88910015Speter	case 0:
89010015Speter		printf("si%d: startup timeout - aborting\n", unit);
89112174Speter		sc->sc_type = SIEMPTY;
89210015Speter		return 0;
89310015Speter	case 1:
89436956Ssteve		if (SI_ISJET(sc->sc_type)) {
89534832Speter			/* set throttle to 100 times per second */
89634832Speter			regp->int_count = JET_INT_COUNT;
89734832Speter			/* rx_intr_count is a NOP in Jet */
89834832Speter		} else {
89934832Speter			/* set throttle to 125 times per second */
90034832Speter			regp->int_count = INT_COUNT;
90134832Speter			/* rx intr max of 25 times per second */
90234832Speter			regp->rx_int_count = RXINT_COUNT;
90334832Speter		}
90410015Speter		regp->int_pending = 0;		/* no intr pending */
90510015Speter		regp->int_scounter = 0;	/* reset counter */
90610015Speter		break;
90710015Speter	case 0xff:
90810015Speter		/*
90910015Speter		 * No modules found, so give up on this one.
91010015Speter		 */
91110015Speter		printf("si%d: %s - no ports found\n", unit,
91210015Speter			si_type[sc->sc_type]);
91310015Speter		return 0;
91410015Speter	default:
91534832Speter		printf("si%d: download code version error - initstat %x\n",
91610015Speter			unit, regp->initstat);
91710015Speter		return 0;
91810015Speter	}
91910015Speter
92010015Speter	/*
92110015Speter	 * First time around the ports just count them in order
92210015Speter	 * to allocate some memory.
92310015Speter	 */
92410015Speter	nport = 0;
92510015Speter	modp = (struct si_module *)(maddr + 0x80);
92610015Speter	for (;;) {
92712174Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
92834832Speter		switch (modp->sm_type) {
92934832Speter		case TA4:
93010015Speter			DPRINT((0, DBG_DOWNLOAD,
93134832Speter				"si%d: Found old TA4 module, 4 ports\n",
93234832Speter				unit));
93334832Speter			x = 4;
93410015Speter			break;
93534832Speter		case TA8:
93634832Speter			DPRINT((0, DBG_DOWNLOAD,
93734832Speter				"si%d: Found old TA8 module, 8 ports\n",
93834832Speter				unit));
93934832Speter			x = 8;
94034832Speter			break;
94134832Speter		case TA4_ASIC:
94234832Speter			DPRINT((0, DBG_DOWNLOAD,
94334832Speter				"si%d: Found ASIC TA4 module, 4 ports\n",
94434832Speter				unit));
94534832Speter			x = 4;
94634832Speter			break;
94734832Speter		case TA8_ASIC:
94834832Speter			DPRINT((0, DBG_DOWNLOAD,
94934832Speter				"si%d: Found ASIC TA8 module, 8 ports\n",
95034832Speter				unit));
95134832Speter			x = 8;
95234832Speter			break;
95334832Speter		case MTA:
95434832Speter			DPRINT((0, DBG_DOWNLOAD,
95534832Speter				"si%d: Found CD1400 module, 8 ports\n",
95634832Speter				unit));
95734832Speter			x = 8;
95834832Speter			break;
95934832Speter		case SXDC:
96034832Speter			DPRINT((0, DBG_DOWNLOAD,
96134832Speter				"si%d: Found SXDC module, 8 ports\n",
96234832Speter				unit));
96334832Speter			x = 8;
96434832Speter			break;
96510015Speter		default:
96610015Speter			printf("si%d: unknown module type %d\n",
96710015Speter				unit, modp->sm_type);
96834832Speter			goto try_next;
96910015Speter		}
97034832Speter
97134832Speter		/* this was limited in firmware and is also a driver issue */
97234832Speter		if ((nport + x) > SI_MAXPORTPERCARD) {
97334832Speter			printf("si%d: extra ports ignored\n", unit);
97434832Speter			goto try_next;
97534832Speter		}
97634832Speter
97734832Speter		nport += x;
97834832Speter		si_Nports += x;
97934832Speter		si_Nmodules++;
98034832Speter
98134832Spetertry_next:
98210015Speter		if (modp->sm_next == 0)
98310015Speter			break;
98410015Speter		modp = (struct si_module *)
98510015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
98610015Speter	}
98710015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
98810015Speter		M_DEVBUF, M_NOWAIT);
98910015Speter	if (sc->sc_ports == 0) {
99010015Spetermem_fail:
99110015Speter		printf("si%d: fail to malloc memory for port structs\n",
99210015Speter			unit);
99310015Speter		return 0;
99410015Speter	}
99510015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
99610015Speter	sc->sc_nport = nport;
99710015Speter
99810015Speter	/*
99910015Speter	 * allocate tty structures for ports
100010015Speter	 */
100110015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
100210015Speter	if (tp == 0)
100310015Speter		goto mem_fail;
100410015Speter	bzero(tp, sizeof(*tp) * nport);
100510962Speter	si_tty = tp;
100610015Speter
100710015Speter	/*
100810015Speter	 * Scan round the ports again, this time initialising.
100910015Speter	 */
101010015Speter	pp = sc->sc_ports;
101110015Speter	nmodule = 0;
101210015Speter	modp = (struct si_module *)(maddr + 0x80);
101334832Speter	uart_type = 1000;	/* arbitary, > uchar_max */
101410015Speter	for (;;) {
101534832Speter		switch (modp->sm_type) {
101634832Speter		case TA4:
101734832Speter			nport = 4;
101810015Speter			break;
101934832Speter		case TA8:
102034832Speter			nport = 8;
102134832Speter			break;
102234832Speter		case TA4_ASIC:
102334832Speter			nport = 4;
102434832Speter			break;
102534832Speter		case TA8_ASIC:
102634832Speter			nport = 8;
102734832Speter			break;
102834832Speter		case MTA:
102934832Speter			nport = 8;
103034832Speter			break;
103134832Speter		case SXDC:
103234832Speter			nport = 8;
103334832Speter			break;
103410015Speter		default:
103534832Speter			goto try_next2;
103610015Speter		}
103734832Speter		nmodule++;
103834832Speter		ccbp = (struct si_channel *)((char *)modp + 0x100);
103934832Speter		if (uart_type == 1000)
104034832Speter			uart_type = ccbp->type;
104134832Speter		else if (uart_type != ccbp->type)
104234832Speter			printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n",
104334832Speter			    unit, nmodule,
104434832Speter			    ccbp->type, si_modulename(sc->sc_type, ccbp->type),
104534832Speter			    uart_type, si_modulename(sc->sc_type, uart_type));
104634832Speter
104734832Speter		for (x = 0; x < nport; x++, pp++, ccbp++) {
104834832Speter			pp->sp_ccb = ccbp;	/* save the address */
104934832Speter			pp->sp_tty = tp++;
105034832Speter			pp->sp_pend = IDLE_CLOSE;
105134832Speter			pp->sp_state = 0;	/* internal flag */
105234832Speter			pp->sp_dtr_wait = 3 * hz;
105334832Speter			pp->sp_iin.c_iflag = TTYDEF_IFLAG;
105434832Speter			pp->sp_iin.c_oflag = TTYDEF_OFLAG;
105534832Speter			pp->sp_iin.c_cflag = TTYDEF_CFLAG;
105634832Speter			pp->sp_iin.c_lflag = TTYDEF_LFLAG;
105734832Speter			termioschars(&pp->sp_iin);
105834832Speter			pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
105934832Speter				TTYDEF_SPEED;;
106034832Speter			pp->sp_iout = pp->sp_iin;
106134832Speter		}
106234832Spetertry_next2:
106310015Speter		if (modp->sm_next == 0) {
106434832Speter			printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n",
106510015Speter				unit,
106610015Speter				sc->sc_typename,
106710015Speter				sc->sc_nport,
106812174Speter				nmodule,
106934832Speter				uart_type,
107034832Speter				si_modulename(sc->sc_type, uart_type));
107110015Speter			break;
107210015Speter		}
107310015Speter		modp = (struct si_module *)
107410015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
107510015Speter	}
107610015Speter	if (done_chartimes == 0) {
107710015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
107810015Speter			if ((spt->sp_code /= hz) == 0)
107910015Speter				spt->sp_code = 1;
108010015Speter		}
108110015Speter		done_chartimes = 1;
108210015Speter	}
108312502Sjulian
108412675Sjulian#ifdef DEVFS
108512675Sjulian/*	path	name	devsw		minor	type   uid gid perm*/
108613169Speter	for ( x = 0; x < sc->sc_nport; x++ ) {
108734735Speter		/* sync with the manuals that start at 1 */
108834735Speter		y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT);
108934735Speter		sc->devfs_token[x].ttya = devfs_add_devswf(
109013630Sphk			&si_cdevsw, x,
109113630Sphk			DV_CHR, 0, 0, 0600, "ttyA%02d", y);
109213630Sphk		sc->devfs_token[x].cuaa = devfs_add_devswf(
109334735Speter			&si_cdevsw, x + 0x00080,
109413630Sphk			DV_CHR, 0, 0, 0600, "cuaA%02d", y);
109513630Sphk		sc->devfs_token[x].ttyi = devfs_add_devswf(
109613630Sphk			&si_cdevsw, x + 0x10000,
109713630Sphk			DV_CHR, 0, 0, 0600, "ttyiA%02d", y);
109834735Speter		sc->devfs_token[x].cuai = devfs_add_devswf(
109934735Speter			&si_cdevsw, x + 0x10080,
110034735Speter			DV_CHR, 0, 0, 0600, "cuaiA%02d", y);
110113630Sphk		sc->devfs_token[x].ttyl = devfs_add_devswf(
110213630Sphk			&si_cdevsw, x + 0x20000,
110313630Sphk			DV_CHR, 0, 0, 0600, "ttylA%02d", y);
110434735Speter		sc->devfs_token[x].cual = devfs_add_devswf(
110534735Speter			&si_cdevsw, x + 0x20080,
110634735Speter			DV_CHR, 0, 0, 0600, "cualA%02d", y);
110712675Sjulian	}
110814873Sscrappy	sc->control_token =
110914873Sscrappy		devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600,
111014873Sscrappy				 "si_control");
111112675Sjulian#endif
111210015Speter	return (1);
111310015Speter}
111410015Speter
111512675Sjulianstatic	int
111610015Spetersiopen(dev, flag, mode, p)
111710015Speter	dev_t dev;
111810015Speter	int flag, mode;
111910015Speter	struct proc *p;
112010015Speter{
112110015Speter	int oldspl, error;
112210015Speter	int card, port;
112310015Speter	register struct si_softc *sc;
112410015Speter	register struct tty *tp;
112510015Speter	volatile struct si_channel *ccbp;
112610015Speter	struct si_port *pp;
112710015Speter	int mynor = minor(dev);
112810015Speter
112910015Speter	/* quickly let in /dev/si_control */
113010015Speter	if (IS_CONTROLDEV(mynor)) {
113118515Speter		if ((error = suser(p->p_ucred, &p->p_acflag)))
113210015Speter			return(error);
113310015Speter		return(0);
113410015Speter	}
113510015Speter
113610015Speter	card = SI_CARD(mynor);
113710015Speter	if (card >= NSI)
113810015Speter		return (ENXIO);
113910015Speter	sc = &si_softc[card];
114010015Speter
114112174Speter	if (sc->sc_type == SIEMPTY) {
114212174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
114310015Speter			card, sc->sc_typename));
114410015Speter		return(ENXIO);
114510015Speter	}
114610015Speter
114710015Speter	port = SI_PORT(mynor);
114810015Speter	if (port >= sc->sc_nport) {
114912174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
115010015Speter			card, sc->sc_nport));
115110015Speter		return(ENXIO);
115210015Speter	}
115310015Speter
115410015Speter#ifdef	POLL
115510015Speter	/*
115610015Speter	 * We've now got a device, so start the poller.
115710015Speter	 */
115810015Speter	if (init_finished == 0) {
115915639Speter		timeout(si_poll, (caddr_t)0L, si_pollrate);
116010015Speter		init_finished = 1;
116110015Speter	}
116210015Speter#endif
116310015Speter
116410015Speter	/* initial/lock device */
116510015Speter	if (IS_STATE(mynor)) {
116610015Speter		return(0);
116710015Speter	}
116810015Speter
116910015Speter	pp = sc->sc_ports + port;
117010015Speter	tp = pp->sp_tty;			/* the "real" tty */
117110015Speter	ccbp = pp->sp_ccb;			/* Find control block */
117210015Speter	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
117310015Speter		dev, flag, mode, p));
117410015Speter
117510015Speter	oldspl = spltty();			/* Keep others out */
117610015Speter	error = 0;
117710015Speter
117810015Speteropen_top:
117910015Speter	while (pp->sp_state & SS_DTR_OFF) {
118010015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
118110015Speter		if (error != 0)
118210015Speter			goto out;
118310015Speter	}
118410015Speter
118510015Speter	if (tp->t_state & TS_ISOPEN) {
118610015Speter		/*
118710015Speter		 * The device is open, so everything has been initialised.
118810015Speter		 * handle conflicts.
118910015Speter		 */
119010015Speter		if (IS_CALLOUT(mynor)) {
119110015Speter			if (!pp->sp_active_out) {
119210015Speter				error = EBUSY;
119310015Speter				goto out;
119410015Speter			}
119510015Speter		} else {
119610015Speter			if (pp->sp_active_out) {
119710015Speter				if (flag & O_NONBLOCK) {
119810015Speter					error = EBUSY;
119910015Speter					goto out;
120010015Speter				}
120110015Speter				error = tsleep(&pp->sp_active_out,
120210015Speter						TTIPRI|PCATCH, "sibi", 0);
120310015Speter				if (error != 0)
120410015Speter					goto out;
120510015Speter				goto open_top;
120610015Speter			}
120710015Speter		}
120810015Speter		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
120910015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
121010015Speter				"already open and EXCLUSIVE set\n"));
121110015Speter			error = EBUSY;
121210015Speter			goto out;
121310015Speter		}
121410015Speter	} else {
121510015Speter		/*
121610015Speter		 * The device isn't open, so there are no conflicts.
121710015Speter		 * Initialize it. Avoid sleep... :-)
121810015Speter		 */
121910015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
122010015Speter		tp->t_oproc = si_start;
122110015Speter		tp->t_param = siparam;
122210015Speter		tp->t_dev = dev;
122310015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
122410015Speter				? pp->sp_iout : pp->sp_iin;
122510015Speter
122610015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
122710015Speter
122810015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
122910015Speter
123010015Speter		error = siparam(tp, &tp->t_termios);
123110015Speter
123210015Speter		--pp->sp_wopeners;
123310015Speter		if (error != 0)
123410015Speter			goto out;
123510015Speter		/* XXX: we should goto_top if siparam slept */
123610015Speter
123710015Speter		/* set initial DCD state */
123810015Speter		pp->sp_last_hi_ip = ccbp->hi_ip;
123910015Speter		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
124010015Speter			(*linesw[tp->t_line].l_modem)(tp, 1);
124110015Speter		}
124210015Speter	}
124310015Speter
124410015Speter	/* whoops! we beat the close! */
124510015Speter	if (pp->sp_state & SS_CLOSING) {
124610015Speter		/* try and stop it from proceeding to bash the hardware */
124710015Speter		pp->sp_state &= ~SS_CLOSING;
124810015Speter	}
124910015Speter
125010015Speter	/*
125110015Speter	 * Wait for DCD if necessary
125210015Speter	 */
125310015Speter	if (!(tp->t_state & TS_CARR_ON)
125410015Speter	    && !IS_CALLOUT(mynor)
125510015Speter	    && !(tp->t_cflag & CLOCAL)
125610015Speter	    && !(flag & O_NONBLOCK)) {
125710015Speter		++pp->sp_wopeners;
125810015Speter		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
125910015Speter		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
126010015Speter		--pp->sp_wopeners;
126110015Speter		if (error != 0)
126210015Speter			goto out;
126310015Speter		goto open_top;
126410015Speter	}
126510015Speter
126610015Speter	error = (*linesw[tp->t_line].l_open)(dev, tp);
126710015Speter	si_disc_optim(tp, &tp->t_termios, pp);
126810015Speter	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
126910015Speter		pp->sp_active_out = TRUE;
127010015Speter
127110015Speter	pp->sp_state |= SS_OPEN;	/* made it! */
127210015Speter
127310015Speterout:
127410015Speter	splx(oldspl);
127510015Speter
127610015Speter	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
127710015Speter
127810015Speter	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
127910015Speter		sihardclose(pp);
128010015Speter
128110015Speter	return(error);
128210015Speter}
128310015Speter
128412675Sjulianstatic	int
128510015Spetersiclose(dev, flag, mode, p)
128610015Speter	dev_t dev;
128710015Speter	int flag, mode;
128810015Speter	struct proc *p;
128910015Speter{
129010015Speter	register struct si_port *pp;
129110015Speter	register struct tty *tp;
129210015Speter	int oldspl;
129310015Speter	int error = 0;
129410015Speter	int mynor = minor(dev);
129510015Speter
129610015Speter	if (IS_SPECIAL(mynor))
129710015Speter		return(0);
129810015Speter
129910015Speter	oldspl = spltty();
130010015Speter
130110015Speter	pp = MINOR2PP(mynor);
130210015Speter	tp = pp->sp_tty;
130310015Speter
130410015Speter	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
130510015Speter		dev, flag, mode, p, pp->sp_state));
130610015Speter
130710015Speter	/* did we sleep and loose a race? */
130810015Speter	if (pp->sp_state & SS_CLOSING) {
130910015Speter		/* error = ESOMETING? */
131010015Speter		goto out;
131110015Speter	}
131210015Speter
131310015Speter	/* begin race detection.. */
131410015Speter	pp->sp_state |= SS_CLOSING;
131510015Speter
131610015Speter	si_write_enable(pp, 0);		/* block writes for ttywait() */
131710015Speter
131810015Speter	/* THIS MAY SLEEP IN TTYWAIT!!! */
131910015Speter	(*linesw[tp->t_line].l_close)(tp, flag);
132010015Speter
132110015Speter	si_write_enable(pp, 1);
132210015Speter
132310015Speter	/* did we sleep and somebody started another open? */
132410015Speter	if (!(pp->sp_state & SS_CLOSING)) {
132510015Speter		/* error = ESOMETING? */
132610015Speter		goto out;
132710015Speter	}
132810015Speter	/* ok. we are now still on the right track.. nuke the hardware */
132910015Speter
133010015Speter	if (pp->sp_state & SS_LSTART) {
133129677Sgibbs		untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
133210015Speter		pp->sp_state &= ~SS_LSTART;
133310015Speter	}
133410015Speter
133510015Speter	sistop(tp, FREAD | FWRITE);
133610015Speter
133710015Speter	sihardclose(pp);
133810015Speter	ttyclose(tp);
133910015Speter	pp->sp_state &= ~SS_OPEN;
134010015Speter
134110015Speterout:
134210015Speter	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
134310015Speter	splx(oldspl);
134410015Speter	return(error);
134510015Speter}
134610015Speter
134710015Speterstatic void
134810015Spetersihardclose(pp)
134910015Speter	struct si_port *pp;
135010015Speter{
135110015Speter	int oldspl;
135210015Speter	struct tty *tp;
135310015Speter	volatile struct si_channel *ccbp;
135410015Speter
135510015Speter	oldspl = spltty();
135610015Speter
135710015Speter	tp = pp->sp_tty;
135810015Speter	ccbp = pp->sp_ccb;			/* Find control block */
135910015Speter	if (tp->t_cflag & HUPCL
136018515Speter	    || (!pp->sp_active_out
136134832Speter		&& !(ccbp->hi_ip & IP_DCD)
136234832Speter		&& !(pp->sp_iin.c_cflag && CLOCAL))
136310015Speter	    || !(tp->t_state & TS_ISOPEN)) {
136410015Speter
136510015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
136610015Speter		(void) si_command(pp, FCLOSE, SI_NOWAIT);
136710015Speter
136810015Speter		if (pp->sp_dtr_wait != 0) {
136910015Speter			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
137010015Speter			pp->sp_state |= SS_DTR_OFF;
137110015Speter		}
137210015Speter
137310015Speter	}
137410015Speter	pp->sp_active_out = FALSE;
137510015Speter	wakeup((caddr_t)&pp->sp_active_out);
137610015Speter	wakeup(TSA_CARR_ON(tp));
137710015Speter
137810015Speter	splx(oldspl);
137910015Speter}
138010015Speter
138110015Speter
138210015Speter/*
138310015Speter * called at splsoftclock()...
138410015Speter */
138510015Speterstatic void
138610015Spetersidtrwakeup(chan)
138710015Speter	void *chan;
138810015Speter{
138910015Speter	struct si_port *pp;
139010015Speter	int oldspl;
139110015Speter
139210015Speter	oldspl = spltty();
139310015Speter
139410015Speter	pp = (struct si_port *)chan;
139510015Speter	pp->sp_state &= ~SS_DTR_OFF;
139610015Speter	wakeup(&pp->sp_dtr_wait);
139710015Speter
139810015Speter	splx(oldspl);
139910015Speter}
140010015Speter
140110015Speter/*
140210015Speter * User level stuff - read and write
140310015Speter */
140412675Sjulianstatic	int
140510015Spetersiread(dev, uio, flag)
140610015Speter	register dev_t dev;
140710015Speter	struct uio *uio;
140810015Speter	int flag;
140910015Speter{
141010015Speter	register struct tty *tp;
141110015Speter	int mynor = minor(dev);
141210015Speter
141310015Speter	if (IS_SPECIAL(mynor)) {
141410015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
141510015Speter		return(ENODEV);
141610015Speter	}
141710015Speter	tp = MINOR2TP(mynor);
141810015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
141910015Speter		"siread(%x,%x,%x)\n", dev, uio, flag));
142010015Speter	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
142110015Speter}
142210015Speter
142310015Speter
142412675Sjulianstatic	int
142510015Spetersiwrite(dev, uio, flag)
142610015Speter	dev_t dev;
142710015Speter	struct uio *uio;
142810015Speter	int flag;
142910015Speter{
143010015Speter	register struct si_port *pp;
143110015Speter	register struct tty *tp;
143210015Speter	int error = 0;
143310015Speter	int mynor = minor(dev);
143410015Speter	int oldspl;
143510015Speter
143610015Speter	if (IS_SPECIAL(mynor)) {
143710015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
143810015Speter		return(ENODEV);
143910015Speter	}
144010015Speter	pp = MINOR2PP(mynor);
144110015Speter	tp = pp->sp_tty;
144210015Speter	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
144310015Speter
144410015Speter	oldspl = spltty();
144510015Speter	/*
144610015Speter	 * If writes are currently blocked, wait on the "real" tty
144710015Speter	 */
144810015Speter	while (pp->sp_state & SS_BLOCKWRITE) {
144910015Speter		pp->sp_state |= SS_WAITWRITE;
145010015Speter		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
145118515Speter		if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
145218515Speter				     "siwrite", tp->t_timeout))) {
145317291Speter			if (error == EWOULDBLOCK)
145417290Speter				error = EIO;
145510015Speter			goto out;
145617290Speter		}
145710015Speter	}
145810015Speter
145910015Speter	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
146010015Speterout:
146110015Speter	splx(oldspl);
146210015Speter	return (error);
146310015Speter}
146410015Speter
146510015Speter
146612675Sjulianstatic	struct tty *
146710015Spetersidevtotty(dev_t dev)
146810015Speter{
146910015Speter	struct si_port *pp;
147010015Speter	int mynor = minor(dev);
147110015Speter	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
147210015Speter
147310015Speter	if (IS_SPECIAL(mynor))
147410015Speter		return(NULL);
147510015Speter	if (SI_PORT(mynor) >= sc->sc_nport)
147610015Speter		return(NULL);
147710015Speter	pp = MINOR2PP(mynor);
147810015Speter	return (pp->sp_tty);
147910015Speter}
148010015Speter
148112675Sjulianstatic	int
148210015Spetersiioctl(dev, cmd, data, flag, p)
148310015Speter	dev_t dev;
148436735Sdfr	u_long cmd;
148510015Speter	caddr_t data;
148610015Speter	int flag;
148710015Speter	struct proc *p;
148810015Speter{
148910015Speter	struct si_port *pp;
149010015Speter	register struct tty *tp;
149110015Speter	int error;
149210015Speter	int mynor = minor(dev);
149310015Speter	int oldspl;
149410015Speter	int blocked = 0;
149510015Speter#if defined(COMPAT_43)
149638351Sbde	u_long oldcmd;
149710015Speter	struct termios term;
149810015Speter#endif
149910015Speter
150010015Speter	if (IS_SI_IOCTL(cmd))
150110015Speter		return(si_Sioctl(dev, cmd, data, flag, p));
150210015Speter
150310015Speter	pp = MINOR2PP(mynor);
150410015Speter	tp = pp->sp_tty;
150510015Speter
150638351Sbde	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%lx,%x,%x)\n",
150710015Speter		dev, cmd, data, flag));
150810015Speter	if (IS_STATE(mynor)) {
150910015Speter		struct termios *ct;
151010015Speter
151110015Speter		switch (mynor & SI_STATE_MASK) {
151210015Speter		case SI_INIT_STATE_MASK:
151310015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
151410015Speter			break;
151510015Speter		case SI_LOCK_STATE_MASK:
151616839Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin;
151710015Speter			break;
151810015Speter		default:
151910015Speter			return (ENODEV);
152010015Speter		}
152110015Speter		switch (cmd) {
152210015Speter		case TIOCSETA:
152310015Speter			error = suser(p->p_ucred, &p->p_acflag);
152410015Speter			if (error != 0)
152510015Speter				return (error);
152610015Speter			*ct = *(struct termios *)data;
152710015Speter			return (0);
152810015Speter		case TIOCGETA:
152910015Speter			*(struct termios *)data = *ct;
153010015Speter			return (0);
153110015Speter		case TIOCGETD:
153210015Speter			*(int *)data = TTYDISC;
153310015Speter			return (0);
153410015Speter		case TIOCGWINSZ:
153510015Speter			bzero(data, sizeof(struct winsize));
153610015Speter			return (0);
153710015Speter		default:
153810015Speter			return (ENOTTY);
153910015Speter		}
154010015Speter	}
154110015Speter	/*
154210015Speter	 * Do the old-style ioctl compat routines...
154310015Speter	 */
154410015Speter#if defined(COMPAT_43)
154510015Speter	term = tp->t_termios;
154610015Speter	oldcmd = cmd;
154710015Speter	error = ttsetcompat(tp, &cmd, data, &term);
154810015Speter	if (error != 0)
154910015Speter		return (error);
155010015Speter	if (cmd != oldcmd)
155110015Speter		data = (caddr_t)&term;
155210015Speter#endif
155310015Speter	/*
155410015Speter	 * Do the initial / lock state business
155510015Speter	 */
155610015Speter	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
155710015Speter		int     cc;
155810015Speter		struct termios *dt = (struct termios *)data;
155910015Speter		struct termios *lt = mynor & SI_CALLOUT_MASK
156010015Speter				     ? &pp->sp_lout : &pp->sp_lin;
156110015Speter
156210015Speter		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
156310015Speter			| (dt->c_iflag & ~lt->c_iflag);
156410015Speter		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
156510015Speter			| (dt->c_oflag & ~lt->c_oflag);
156610015Speter		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
156710015Speter			| (dt->c_cflag & ~lt->c_cflag);
156810015Speter		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
156910015Speter			| (dt->c_lflag & ~lt->c_lflag);
157010015Speter		for (cc = 0; cc < NCCS; ++cc)
157110015Speter			if (lt->c_cc[cc] != 0)
157210015Speter				dt->c_cc[cc] = tp->t_cc[cc];
157310015Speter		if (lt->c_ispeed != 0)
157410015Speter			dt->c_ispeed = tp->t_ispeed;
157510015Speter		if (lt->c_ospeed != 0)
157610015Speter			dt->c_ospeed = tp->t_ospeed;
157710015Speter	}
157810015Speter
157910015Speter	/*
158010015Speter	 * Block user-level writes to give the ttywait()
158110015Speter	 * a chance to completely drain for commands
158210015Speter	 * that require the port to be in a quiescent state.
158310015Speter	 */
158410015Speter	switch (cmd) {
158534832Speter	case TIOCSETAW:
158634832Speter	case TIOCSETAF:
158717396Speter	case TIOCDRAIN:
158817396Speter#ifdef COMPAT_43
158917396Speter	case TIOCSETP:
159017396Speter#endif
159110015Speter		blocked++;	/* block writes for ttywait() and siparam() */
159210015Speter		si_write_enable(pp, 0);
159310015Speter	}
159410015Speter
159510015Speter	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
159631577Sbde	if (error != ENOIOCTL)
159710015Speter		goto out;
159810015Speter
159910015Speter	oldspl = spltty();
160010015Speter
160110015Speter	error = ttioctl(tp, cmd, data, flag);
160210015Speter	si_disc_optim(tp, &tp->t_termios, pp);
160331577Sbde	if (error != ENOIOCTL)
160410015Speter		goto outspl;
160510015Speter
160610015Speter	switch (cmd) {
160710015Speter	case TIOCSBRK:
160816575Speter		si_command(pp, SBREAK, SI_WAIT);
160910015Speter		break;
161010015Speter	case TIOCCBRK:
161116575Speter		si_command(pp, EBREAK, SI_WAIT);
161210015Speter		break;
161310015Speter	case TIOCSDTR:
161410015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
161510015Speter		break;
161610015Speter	case TIOCCDTR:
161710015Speter		(void) si_modem(pp, SET, 0);
161810015Speter		break;
161910015Speter	case TIOCMSET:
162010015Speter		(void) si_modem(pp, SET, *(int *)data);
162110015Speter		break;
162210015Speter	case TIOCMBIS:
162310015Speter		(void) si_modem(pp, BIS, *(int *)data);
162410015Speter		break;
162510015Speter	case TIOCMBIC:
162610015Speter		(void) si_modem(pp, BIC, *(int *)data);
162710015Speter		break;
162810015Speter	case TIOCMGET:
162910015Speter		*(int *)data = si_modem(pp, GET, 0);
163010015Speter		break;
163110015Speter	case TIOCMSDTRWAIT:
163210015Speter		/* must be root since the wait applies to following logins */
163310015Speter		error = suser(p->p_ucred, &p->p_acflag);
163410015Speter		if (error != 0) {
163510015Speter			goto outspl;
163610015Speter		}
163710015Speter		pp->sp_dtr_wait = *(int *)data * hz / 100;
163810015Speter		break;
163910015Speter	case TIOCMGDTRWAIT:
164010015Speter		*(int *)data = pp->sp_dtr_wait * 100 / hz;
164110015Speter		break;
164210015Speter
164310015Speter	default:
164410015Speter		error = ENOTTY;
164510015Speter	}
164610015Speter	error = 0;
164710015Speteroutspl:
164810015Speter	splx(oldspl);
164910015Speterout:
165010015Speter	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
165110015Speter	if (blocked)
165210015Speter		si_write_enable(pp, 1);
165310015Speter	return(error);
165410015Speter}
165510015Speter
165610015Speter/*
165710015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device
165810015Speter */
165910015Speterstatic int
166038351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
166110015Speter{
166210015Speter	struct si_softc *xsc;
166310015Speter	register struct si_port *xpp;
166410015Speter	volatile struct si_reg *regp;
166510015Speter	struct si_tcsi *dp;
166610044Speter	struct si_pstat *sps;
166711872Sphk	int *ip, error = 0;
166810015Speter	int oldspl;
166910015Speter	int card, port;
167010015Speter	int mynor = minor(dev);
167110015Speter
167238351Sbde	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%lx,%x,%x)\n",
167310015Speter		dev, cmd, data, flag));
167410015Speter
167510044Speter#if 1
167610044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
167710044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
167810044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
167910044Speter#endif
168010044Speter
168110015Speter	if (!IS_CONTROLDEV(mynor)) {
168210015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
168310015Speter		return(ENODEV);
168410015Speter	}
168510015Speter
168610015Speter	oldspl = spltty();	/* better safe than sorry */
168710015Speter
168810015Speter	ip = (int *)data;
168910015Speter
169018515Speter#define SUCHECK if ((error = suser(p->p_ucred, &p->p_acflag))) goto out
169110015Speter
169210015Speter	switch (cmd) {
169310015Speter	case TCSIPORTS:
169410015Speter		*ip = si_Nports;
169510015Speter		goto out;
169610015Speter	case TCSIMODULES:
169710015Speter		*ip = si_Nmodules;
169810015Speter		goto out;
169910015Speter	case TCSISDBG_ALL:
170010015Speter		SUCHECK;
170110015Speter		si_debug = *ip;
170210015Speter		goto out;
170310015Speter	case TCSIGDBG_ALL:
170410015Speter		*ip = si_debug;
170510015Speter		goto out;
170610015Speter	default:
170710015Speter		/*
170810015Speter		 * Check that a controller for this port exists
170910015Speter		 */
171010044Speter
171110044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
171210044Speter
171310015Speter		dp = (struct si_tcsi *)data;
171410044Speter		sps = (struct si_pstat *)data;
171510015Speter		card = dp->tc_card;
171610015Speter		xsc = &si_softc[card];	/* check.. */
171712174Speter		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
171810015Speter			error = ENOENT;
171910015Speter			goto out;
172010015Speter		}
172110015Speter		/*
172210015Speter		 * And check that a port exists
172310015Speter		 */
172410015Speter		port = dp->tc_port;
172510015Speter		if (port < 0 || port >= xsc->sc_nport) {
172610015Speter			error = ENOENT;
172710015Speter			goto out;
172810015Speter		}
172910015Speter		xpp = xsc->sc_ports + port;
173010015Speter		regp = (struct si_reg *)xsc->sc_maddr;
173110015Speter	}
173210015Speter
173310015Speter	switch (cmd) {
173410015Speter	case TCSIDEBUG:
173510015Speter#ifdef	SI_DEBUG
173610015Speter		SUCHECK;
173710015Speter		if (xpp->sp_debug)
173810015Speter			xpp->sp_debug = 0;
173910015Speter		else {
174010015Speter			xpp->sp_debug = DBG_ALL;
174110015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
174210015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
174310015Speter		}
174410015Speter		break;
174510015Speter#else
174610015Speter		error = ENODEV;
174710015Speter		goto out;
174810015Speter#endif
174910015Speter	case TCSISDBG_LEVEL:
175010015Speter	case TCSIGDBG_LEVEL:
175110015Speter#ifdef	SI_DEBUG
175210015Speter		if (cmd == TCSIGDBG_LEVEL) {
175310015Speter			dp->tc_dbglvl = xpp->sp_debug;
175410015Speter		} else {
175510015Speter			SUCHECK;
175610015Speter			xpp->sp_debug = dp->tc_dbglvl;
175710015Speter		}
175810015Speter		break;
175910015Speter#else
176010015Speter		error = ENODEV;
176110015Speter		goto out;
176210015Speter#endif
176310015Speter	case TCSIGRXIT:
176410015Speter		dp->tc_int = regp->rx_int_count;
176510015Speter		break;
176610015Speter	case TCSIRXIT:
176710015Speter		SUCHECK;
176810015Speter		regp->rx_int_count = dp->tc_int;
176910015Speter		break;
177010015Speter	case TCSIGIT:
177110015Speter		dp->tc_int = regp->int_count;
177210015Speter		break;
177310015Speter	case TCSIIT:
177410015Speter		SUCHECK;
177510015Speter		regp->int_count = dp->tc_int;
177610015Speter		break;
177710044Speter	case TCSISTATE:
177810044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
177910015Speter		break;
178010044Speter	/* these next three use a different structure */
178110044Speter	case TCSI_PORT:
178210015Speter		SUCHECK;
178334832Speter		si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport));
178410015Speter		break;
178510044Speter	case TCSI_CCB:
178610044Speter		SUCHECK;
178734832Speter		si_bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb));
178810015Speter		break;
178910044Speter	case TCSI_TTY:
179010044Speter		SUCHECK;
179134832Speter		si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty));
179210015Speter		break;
179310015Speter	default:
179410015Speter		error = EINVAL;
179510015Speter		goto out;
179610015Speter	}
179710015Speterout:
179810015Speter	splx(oldspl);
179910015Speter	return(error);		/* success */
180010015Speter}
180110015Speter
180210015Speter/*
180310015Speter *	siparam()	: Configure line params
180410015Speter *	called at spltty();
180510015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
180610015Speter *	caller must arrange this if it's important..
180710015Speter */
180812724Sphkstatic int
180910015Spetersiparam(tp, t)
181010015Speter	register struct tty *tp;
181110015Speter	register struct termios *t;
181210015Speter{
181310015Speter	register struct si_port *pp = TP2PP(tp);
181410015Speter	volatile struct si_channel *ccbp;
181510015Speter	int oldspl, cflag, iflag, oflag, lflag;
181610015Speter	int error = 0;		/* shutup gcc */
181710015Speter	int ispeed = 0;		/* shutup gcc */
181810015Speter	int ospeed = 0;		/* shutup gcc */
181910161Speter	BYTE val;
182010015Speter
182110015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
182210015Speter	cflag = t->c_cflag;
182310015Speter	iflag = t->c_iflag;
182410015Speter	oflag = t->c_oflag;
182510015Speter	lflag = t->c_lflag;
182610044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
182710044Speter		oflag, cflag, iflag, lflag));
182810015Speter
182934832Speter	/* XXX - if Jet host and SXDC module, use extended baud rates */
183010015Speter
183110015Speter	/* if not hung up.. */
183210015Speter	if (t->c_ospeed != 0) {
183310015Speter		/* translate baud rate to firmware values */
183410015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
183510015Speter		ispeed = t->c_ispeed ?
183610015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
183710015Speter
183810015Speter		/* enforce legit baud rate */
183910015Speter		if (ospeed < 0 || ispeed < 0)
184010015Speter			return (EINVAL);
184110015Speter	}
184210015Speter
184310015Speter	oldspl = spltty();
184410015Speter
184510015Speter	ccbp = pp->sp_ccb;
184610015Speter
184710161Speter	/* ========== set hi_break ========== */
184810161Speter	val = 0;
184910161Speter	if (iflag & IGNBRK)		/* Breaks */
185010161Speter		val |= BR_IGN;
185110161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
185210161Speter		val |= BR_INT;
185310161Speter	if (iflag & PARMRK)		/* Parity mark? */
185410161Speter		val |= BR_PARMRK;
185510161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
185610161Speter		val |= BR_PARIGN;
185710161Speter	ccbp->hi_break = val;
185810161Speter
185910161Speter	/* ========== set hi_csr ========== */
186010015Speter	/* if not hung up.. */
186110015Speter	if (t->c_ospeed != 0) {
186210015Speter		/* Set I/O speeds */
186310161Speter		 val = (ispeed << 4) | ospeed;
186410015Speter	}
186510161Speter	ccbp->hi_csr = val;
186610015Speter
186710161Speter	/* ========== set hi_mr2 ========== */
186810161Speter	val = 0;
186910015Speter	if (cflag & CSTOPB)				/* Stop bits */
187010161Speter		val |= MR2_2_STOP;
187110015Speter	else
187210161Speter		val |= MR2_1_STOP;
187310161Speter	/*
187410161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
187510161Speter	 * a DCE, hence the reverse sense of RTS and CTS
187610161Speter	 */
187710161Speter	/* Output Flow - RTS must be raised before data can be sent */
187810161Speter	if (cflag & CCTS_OFLOW)
187910161Speter		val |= MR2_RTSCONT;
188010161Speter
188116575Speter	ccbp->hi_mr2 = val;
188210161Speter
188310161Speter	/* ========== set hi_mr1 ========== */
188410161Speter	val = 0;
188510015Speter	if (!(cflag & PARENB))				/* Parity */
188610161Speter		val |= MR1_NONE;
188710015Speter	else
188810161Speter		val |= MR1_WITH;
188910015Speter	if (cflag & PARODD)
189010161Speter		val |= MR1_ODD;
189110015Speter
189210015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
189310161Speter		val |= MR1_8_BITS;
189410015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
189510161Speter		val |= MR1_7_BITS;
189610015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
189710161Speter		val |= MR1_6_BITS;
189810015Speter	} else {					/* Must be 5 */
189910161Speter		val |= MR1_5_BITS;
190010015Speter	}
190110161Speter	/*
190210161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
190310161Speter	 * a DCE, hence the reverse sense of RTS and CTS
190410161Speter	 */
190510161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
190610161Speter	if (cflag & CRTS_IFLOW)
190710161Speter		val |= MR1_CTSCONT;
190810015Speter
190910161Speter	ccbp->hi_mr1 = val;
191010161Speter
191110161Speter	/* ========== set hi_mask ========== */
191210161Speter	val = 0xff;
191310161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
191410161Speter		val &= 0xFF;
191510161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
191610161Speter		val &= 0x7F;
191710161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
191810161Speter		val &= 0x3F;
191910161Speter	} else {					/* Must be 5 */
192010161Speter		val &= 0x1F;
192110161Speter	}
192210015Speter	if (iflag & ISTRIP)
192310161Speter		val &= 0x7F;
192410015Speter
192510161Speter	ccbp->hi_mask = val;
192610161Speter
192710161Speter	/* ========== set hi_prtcl ========== */
192810161Speter	val = 0;
192910015Speter				/* Monitor DCD etc. if a modem */
193010015Speter	if (!(cflag & CLOCAL))
193110161Speter		val |= SP_DCEN;
193210161Speter	if (iflag & IXANY)
193310161Speter		val |= SP_TANY;
193410161Speter	if (iflag & IXON)
193510161Speter		val |= SP_TXEN;
193610161Speter	if (iflag & IXOFF)
193710161Speter		val |= SP_RXEN;
193810161Speter	if (iflag & INPCK)
193910161Speter		val |= SP_PAEN;
194010015Speter
194110161Speter	ccbp->hi_prtcl = val;
194210161Speter
194310161Speter
194410161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
194510161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
194610015Speter	ccbp->hi_txon = t->c_cc[VSTART];
194710015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
194810015Speter
194910015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
195010015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
195110015Speter
195210161Speter	/* ========== send settings to the card ========== */
195310015Speter	/* potential sleep here */
195410015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
195510015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
195610015Speter	else
195710015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
195810015Speter
195910161Speter	/* ========== set DTR etc ========== */
196010015Speter	/* Hangup if ospeed == 0 */
196110015Speter	if (t->c_ospeed == 0) {
196210015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
196310015Speter	} else {
196410015Speter		/*
196510015Speter		 * If the previous speed was 0, may need to re-enable
196634832Speter		 * the modem signals
196734832Speter		 */
196810015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
196910015Speter	}
197010015Speter
197110044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
197210044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
197310015Speter
197410015Speter	splx(oldspl);
197510015Speter	return(error);
197610015Speter}
197710015Speter
197810015Speter/*
197910015Speter * Enable or Disable the writes to this channel...
198010015Speter * "state" ->  enabled = 1; disabled = 0;
198110015Speter */
198210015Speterstatic void
198310015Spetersi_write_enable(pp, state)
198410015Speter	register struct si_port *pp;
198510015Speter	int state;
198610015Speter{
198710015Speter	int oldspl;
198810015Speter
198910015Speter	oldspl = spltty();
199010015Speter
199110015Speter	if (state) {
199210015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
199310015Speter		if (pp->sp_state & SS_WAITWRITE) {
199410015Speter			pp->sp_state &= ~SS_WAITWRITE;
199510015Speter			/* thunder away! */
199610015Speter			wakeup((caddr_t)pp);
199710015Speter		}
199810015Speter	} else {
199910015Speter		pp->sp_state |= SS_BLOCKWRITE;
200010015Speter	}
200110015Speter
200210015Speter	splx(oldspl);
200310015Speter}
200410015Speter
200510015Speter/*
200610015Speter * Set/Get state of modem control lines.
200710015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
200810015Speter *	TIOCM_DTR	DSR
200910015Speter *	TIOCM_RTS	CTS
201010015Speter */
201110015Speterstatic int
201210015Spetersi_modem(pp, cmd, bits)
201310015Speter	struct si_port *pp;
201410015Speter	enum si_mctl cmd;
201510015Speter	int bits;
201610015Speter{
201710015Speter	volatile struct si_channel *ccbp;
201810015Speter	int x;
201910015Speter
202010015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
202110015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
202210015Speter	switch (cmd) {
202310015Speter	case GET:
202410015Speter		x = ccbp->hi_ip;
202510015Speter		bits = TIOCM_LE;
202610015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
202710015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
202810015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
202910015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
203010015Speter		return(bits);
203110015Speter	case SET:
203210015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
203310015Speter		/* fall through */
203410015Speter	case BIS:
203510015Speter		x = 0;
203610015Speter		if (bits & TIOCM_DTR)
203710015Speter			x |= OP_DSR;
203810015Speter		if (bits & TIOCM_RTS)
203910015Speter			x |= OP_CTS;
204010015Speter		ccbp->hi_op |= x;
204110015Speter		break;
204210015Speter	case BIC:
204310015Speter		if (bits & TIOCM_DTR)
204410015Speter			ccbp->hi_op &= ~OP_DSR;
204510015Speter		if (bits & TIOCM_RTS)
204610015Speter			ccbp->hi_op &= ~OP_CTS;
204710015Speter	}
204810015Speter	return 0;
204910015Speter}
205010015Speter
205110015Speter/*
205210015Speter * Handle change of modem state
205310015Speter */
205410015Speterstatic void
205510015Spetersi_modem_state(pp, tp, hi_ip)
205610015Speter	register struct si_port *pp;
205710015Speter	register struct tty *tp;
205810015Speter	register int hi_ip;
205910015Speter{
206010015Speter							/* if a modem dev */
206110015Speter	if (hi_ip & IP_DCD) {
206210015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
206310015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
206410015Speter				tp->t_line));
206510015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
206610015Speter		}
206710015Speter	} else {
206810015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
206910015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
207010015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
207110015Speter				(void) si_modem(pp, SET, 0);
207210015Speter		}
207310015Speter	}
207410015Speter	pp->sp_last_hi_ip = hi_ip;
207510015Speter
207610015Speter}
207710015Speter
207810015Speter/*
207910015Speter * Poller to catch missed interrupts.
208012174Speter *
208112496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get
208212496Speter * better response.  We could really use a "periodic" version timeout(). :-)
208310015Speter */
208410015Speter#ifdef POLL
208510708Speterstatic void
208610015Spetersi_poll(void *nothing)
208710015Speter{
208810015Speter	register struct si_softc *sc;
208910015Speter	register int i;
209010015Speter	volatile struct si_reg *regp;
209112174Speter	register struct si_port *pp;
209212174Speter	int lost, oldspl, port;
209310015Speter
209410015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
209511609Speter	oldspl = spltty();
209610015Speter	if (in_intr)
209710015Speter		goto out;
209810015Speter	lost = 0;
209910015Speter	for (i=0; i<NSI; i++) {
210010015Speter		sc = &si_softc[i];
210112174Speter		if (sc->sc_type == SIEMPTY)
210210015Speter			continue;
210310015Speter		regp = (struct si_reg *)sc->sc_maddr;
210434832Speter
210510015Speter		/*
210610015Speter		 * See if there has been a pending interrupt for 2 seconds
210733395Speter		 * or so. The test (int_scounter >= 200) won't correspond
210810015Speter		 * to 2 seconds if int_count gets changed.
210910015Speter		 */
211010015Speter		if (regp->int_pending != 0) {
211110015Speter			if (regp->int_scounter >= 200 &&
211210015Speter			    regp->initstat == 1) {
211312174Speter				printf("si%d: lost intr\n", i);
211410015Speter				lost++;
211510015Speter			}
211610015Speter		} else {
211710015Speter			regp->int_scounter = 0;
211810015Speter		}
211910015Speter
212012174Speter		/*
212112174Speter		 * gripe about no input flow control..
212212174Speter		 */
212312174Speter		pp = sc->sc_ports;
212412174Speter		for (port = 0; port < sc->sc_nport; pp++, port++) {
212512174Speter			if (pp->sp_delta_overflows > 0) {
212612174Speter				printf("si%d: %d tty level buffer overflows\n",
212712174Speter					i, pp->sp_delta_overflows);
212812174Speter				pp->sp_delta_overflows = 0;
212912174Speter			}
213012174Speter		}
213110015Speter	}
213217547Speter	if (lost || si_realpoll)
213334735Speter		si_intr(-1);	/* call intr with fake vector */
213411609Speterout:
213510015Speter	splx(oldspl);
213610015Speter
213715639Speter	timeout(si_poll, (caddr_t)0L, si_pollrate);
213810015Speter}
213910015Speter#endif	/* ifdef POLL */
214010015Speter
214110015Speter/*
214210015Speter * The interrupt handler polls ALL ports on ALL adapters each time
214310015Speter * it is called.
214410015Speter */
214510015Speter
214612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
214734832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE];	/* output staging area */
214810015Speter
214934735Speterstatic void
215034735Spetersi_intr(int unit)
215110015Speter{
215210015Speter	register struct si_softc *sc;
215310015Speter
215410015Speter	register struct si_port *pp;
215510015Speter	volatile struct si_channel *ccbp;
215610015Speter	register struct tty *tp;
215710015Speter	volatile caddr_t maddr;
215811872Sphk	BYTE op, ip;
215912174Speter	int x, card, port, n, i, isopen;
216010015Speter	volatile BYTE *z;
216110015Speter	BYTE c;
216210015Speter
216334735Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "si_intr(%d)\n", unit));
216411609Speter	if (in_intr) {
216511609Speter		if (unit < 0)	/* should never happen */
216634832Speter			printf("si%d: Warning poll entered during interrupt\n",
216734832Speter				unit);
216834832Speter		else
216934832Speter			printf("si%d: Warning interrupt handler re-entered\n",
217034832Speter				unit);
217110708Speter		return;
217210015Speter	}
217310015Speter	in_intr = 1;
217410015Speter
217510015Speter	/*
217610015Speter	 * When we get an int we poll all the channels and do ALL pending
217710015Speter	 * work, not just the first one we find. This allows all cards to
217810015Speter	 * share the same vector.
217934832Speter	 *
218034832Speter	 * XXX - But if we're sharing the vector with something that's NOT
218134832Speter	 * a SI/XIO/SX card, we may be making more work for ourselves.
218210015Speter	 */
218334832Speter	for (card = 0; card < NSI; card++) {
218410015Speter		sc = &si_softc[card];
218512174Speter		if (sc->sc_type == SIEMPTY)
218610015Speter			continue;
218712174Speter
218812174Speter		/*
218912174Speter		 * First, clear the interrupt
219012174Speter		 */
219110015Speter		switch(sc->sc_type) {
219234832Speter		case SIHOST:
219310015Speter			maddr = sc->sc_maddr;
219410015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
219510015Speter							/* flag nothing pending */
219610015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
219710015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
219810015Speter			break;
219910015Speter		case SIHOST2:
220010015Speter			maddr = sc->sc_maddr;
220110015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
220210015Speter			*(maddr+SIPLIRQCLR) = 0x00;
220310015Speter			*(maddr+SIPLIRQCLR) = 0x10;
220410015Speter			break;
220534832Speter#if NPCI > 0
220633395Speter		case SIPCI:
220733395Speter			maddr = sc->sc_maddr;
220833395Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
220933395Speter			*(maddr+SIPCIINTCL) = 0x0;
221033395Speter			break;
221134832Speter		case SIJETPCI:	/* fall through to JETISA case */
221234832Speter#endif
221333395Speter		case SIJETISA:
221433395Speter			maddr = sc->sc_maddr;
221533395Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
221633395Speter			*(maddr+SIJETINTCL) = 0x0;
221733395Speter			break;
221834832Speter#if NEISA > 0
221910015Speter		case SIEISA:
222010015Speter			maddr = sc->sc_maddr;
222110015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
222234832Speter			(void)inb(sc->sc_eisa_iobase + 3);
222310015Speter			break;
222434832Speter#endif
222510015Speter		case SIEMPTY:
222610015Speter		default:
222710015Speter			continue;
222810015Speter		}
222910015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
223010015Speter
223112174Speter		/*
223212174Speter		 * check each port
223312174Speter		 */
223434832Speter		for (pp = sc->sc_ports, port=0; port < sc->sc_nport;
223534832Speter		     pp++, port++) {
223610015Speter			ccbp = pp->sp_ccb;
223710015Speter			tp = pp->sp_tty;
223810015Speter
223910015Speter			/*
224010015Speter			 * See if a command has completed ?
224110015Speter			 */
224210015Speter			if (ccbp->hi_stat != pp->sp_pend) {
224310015Speter				DPRINT((pp, DBG_INTR,
224434735Speter					"si_intr hi_stat = 0x%x, pend = %d\n",
224510015Speter					ccbp->hi_stat, pp->sp_pend));
224610015Speter				switch(pp->sp_pend) {
224710015Speter				case LOPEN:
224810015Speter				case MPEND:
224910015Speter				case MOPEN:
225010015Speter				case CONFIG:
225116575Speter				case SBREAK:
225216575Speter				case EBREAK:
225310015Speter					pp->sp_pend = ccbp->hi_stat;
225410015Speter						/* sleeping in si_command */
225510015Speter					wakeup(&pp->sp_state);
225610015Speter					break;
225710015Speter				default:
225810015Speter					pp->sp_pend = ccbp->hi_stat;
225910015Speter				}
226034832Speter			}
226110015Speter
226210015Speter			/*
226310015Speter			 * Continue on if it's closed
226410015Speter			 */
226510015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
226610015Speter				continue;
226710015Speter			}
226810015Speter
226910015Speter			/*
227010015Speter			 * Do modem state change if not a local device
227110015Speter			 */
227210015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
227310015Speter
227410015Speter			/*
227534832Speter			 * Check to see if we should 'receive' characters.
227612174Speter			 */
227712174Speter			if (tp->t_state & TS_CONNECTED &&
227812174Speter			    tp->t_state & TS_ISOPEN)
227912174Speter				isopen = 1;
228012174Speter			else
228112174Speter				isopen = 0;
228212174Speter
228312174Speter			/*
228416575Speter			 * Do input break processing
228510015Speter			 */
228610015Speter			if (ccbp->hi_state & ST_BREAK) {
228712174Speter				if (isopen) {
228812174Speter				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
228910015Speter				}
229010015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
229110015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
229210015Speter			}
229310015Speter
229410015Speter			/*
229512174Speter			 * Do RX stuff - if not open then dump any characters.
229612174Speter			 * XXX: This is VERY messy and needs to be cleaned up.
229712174Speter			 *
229812174Speter			 * XXX: can we leave data in the host adapter buffer
229912174Speter			 * when the clists are full?  That may be dangerous
230012174Speter			 * if the user cannot get an interrupt signal through.
230110015Speter			 */
230210015Speter
230312174Speter	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
230412174Speter
230512174Speter			if (!isopen) {
230610015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
230712174Speter				goto end_rx;
230812174Speter			}
230910015Speter
231012174Speter			/*
231115640Speter			 * If the tty input buffers are blocked, stop emptying
231215640Speter			 * the incoming buffers and let the auto flow control
231315640Speter			 * assert..
231415640Speter			 */
231515640Speter			if (tp->t_state & TS_TBLOCK) {
231615640Speter				goto end_rx;
231715640Speter			}
231815640Speter
231915640Speter			/*
232012174Speter			 * Process read characters if not skipped above
232112174Speter			 */
232215640Speter			op = ccbp->hi_rxopos;
232315640Speter			ip = ccbp->hi_rxipos;
232415640Speter			c = ip - op;
232512174Speter			if (c == 0) {
232612174Speter				goto end_rx;
232712174Speter			}
232810015Speter
232912174Speter			n = c & 0xff;
233015640Speter			if (n > 250)
233115640Speter				n = 250;
233212174Speter
233312174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
233410015Speter						n, op, ip));
233510015Speter
233612174Speter			/*
233712174Speter			 * Suck characters out of host card buffer into the
233812174Speter			 * "input staging buffer" - so that we dont leave the
233912174Speter			 * host card in limbo while we're possibly echoing
234012174Speter			 * characters and possibly flushing input inside the
234112174Speter			 * ldisc l_rint() routine.
234212174Speter			 */
234312496Speter			if (n <= SI_BUFFERSIZE - op) {
234410015Speter
234512174Speter				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
234612174Speter				z = ccbp->hi_rxbuf + op;
234734832Speter				si_bcopy((caddr_t)z, si_rxbuf, n);
234810015Speter
234912174Speter				op += n;
235012174Speter			} else {
235112496Speter				x = SI_BUFFERSIZE - op;
235210015Speter
235312174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
235412174Speter				z = ccbp->hi_rxbuf + op;
235534832Speter				si_bcopy((caddr_t)z, si_rxbuf, x);
235610015Speter
235734832Speter				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n",
235834832Speter					n - x));
235912174Speter				z = ccbp->hi_rxbuf;
236034832Speter				si_bcopy((caddr_t)z, si_rxbuf + x, n - x);
236110015Speter
236212174Speter				op += n;
236312174Speter			}
236410015Speter
236512174Speter			/* clear collected characters from buffer */
236612174Speter			ccbp->hi_rxopos = op;
236712174Speter
236812174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
236910015Speter						n, op, ip));
237010015Speter
237112174Speter			/*
237212174Speter			 * at this point...
237312174Speter			 * n = number of chars placed in si_rxbuf
237412174Speter			 */
237510015Speter
237612174Speter			/*
237712174Speter			 * Avoid the grotesquely inefficient lineswitch
237812174Speter			 * routine (ttyinput) in "raw" mode. It usually
237912174Speter			 * takes about 450 instructions (that's without
238012174Speter			 * canonical processing or echo!). slinput is
238112174Speter			 * reasonably fast (usually 40 instructions
238212174Speter			 * plus call overhead).
238312174Speter			 */
238412174Speter			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
238510015Speter
238612174Speter				/* block if the driver supports it */
238712174Speter				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
238812174Speter				    && (tp->t_cflag & CRTS_IFLOW
238912174Speter					|| tp->t_iflag & IXOFF)
239012174Speter				    && !(tp->t_state & TS_TBLOCK))
239112174Speter					ttyblock(tp);
239210015Speter
239312174Speter				tk_nin += n;
239412174Speter				tk_rawcc += n;
239512174Speter				tp->t_rawcc += n;
239612174Speter
239712174Speter				pp->sp_delta_overflows +=
239812174Speter				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
239912174Speter
240012174Speter				ttwakeup(tp);
240112174Speter				if (tp->t_state & TS_TTSTOP
240212174Speter				    && (tp->t_iflag & IXANY
240312174Speter					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
240412174Speter					tp->t_state &= ~TS_TTSTOP;
240512174Speter					tp->t_lflag &= ~FLUSHO;
240612174Speter					si_start(tp);
240712174Speter				}
240812174Speter			} else {
240912174Speter				/*
241012174Speter				 * It'd be nice to not have to go through the
241112174Speter				 * function call overhead for each char here.
241212174Speter				 * It'd be nice to block input it, saving a
241312174Speter				 * loop here and the call/return overhead.
241412174Speter				 */
241512174Speter				for(x = 0; x < n; x++) {
241612174Speter					i = si_rxbuf[x];
241712174Speter					if ((*linesw[tp->t_line].l_rint)(i, tp)
241812174Speter					     == -1) {
241912174Speter						pp->sp_delta_overflows++;
242010015Speter					}
242112174Speter					/*
242212174Speter					 * doesn't seem to be much point doing
242312174Speter					 * this here.. this driver has no
242412174Speter					 * softtty processing! ??
242512174Speter					 */
242612174Speter					if (pp->sp_hotchar && i == pp->sp_hotchar) {
242712174Speter						setsofttty();
242812174Speter					}
242912174Speter				}
243012174Speter			}
243112174Speter			goto more_rx;	/* try for more until RXbuf is empty */
243210015Speter
243312174Speter	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
243410015Speter
243510015Speter			/*
243610015Speter			 * Do TX stuff
243710015Speter			 */
243810015Speter			(*linesw[tp->t_line].l_start)(tp);
243910015Speter
244010015Speter		} /* end of for (all ports on this controller) */
244110015Speter	} /* end of for (all controllers) */
244210015Speter
244311609Speter	in_intr = 0;
244434735Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end si_intr(%d)\n", unit));
244510015Speter}
244610015Speter
244710015Speter/*
244810015Speter * Nudge the transmitter...
244912174Speter *
245012174Speter * XXX: I inherited some funny code here.  It implies the host card only
245112174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does
245212174Speter * not interrupt when it's actually hits empty.  In some cases, we have
245312174Speter * processes waiting for complete drain, and we need to simulate an interrupt
245412174Speter * about when we think the buffer is going to be empty (and retry if not).
245512174Speter * I really am not certain about this...  I *need* the hardware manuals.
245610015Speter */
245710015Speterstatic void
245810015Spetersi_start(tp)
245910015Speter	register struct tty *tp;
246010015Speter{
246110015Speter	struct si_port *pp;
246210015Speter	volatile struct si_channel *ccbp;
246310015Speter	register struct clist *qp;
246410015Speter	BYTE ipos;
246510015Speter	int nchar;
246610015Speter	int oldspl, count, n, amount, buffer_full;
246710015Speter
246810015Speter	oldspl = spltty();
246910015Speter
247010015Speter	qp = &tp->t_outq;
247110015Speter	pp = TP2PP(tp);
247210015Speter
247310015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
247410015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
247510015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
247610015Speter
247710015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
247810015Speter		goto out;
247910015Speter
248010015Speter	buffer_full = 0;
248110015Speter	ccbp = pp->sp_ccb;
248210015Speter
248310015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
248410015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
248510015Speter
248610015Speter	while ((nchar = qp->c_cc) > 0) {
248710015Speter		if ((BYTE)count >= 255) {
248810015Speter			buffer_full++;
248910015Speter			break;
249010015Speter		}
249110015Speter		amount = min(nchar, (255 - (BYTE)count));
249210015Speter		ipos = (unsigned int)ccbp->hi_txipos;
249334832Speter		n = q_to_b(&tp->t_outq, si_txbuf, amount);
249410015Speter		/* will it fit in one lump? */
249534832Speter		if ((SI_BUFFERSIZE - ipos) >= n) {
249634832Speter			si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], n);
249710015Speter		} else {
249834832Speter			si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos],
249934832Speter				SI_BUFFERSIZE - ipos);
250034832Speter			si_bcopy(si_txbuf + (SI_BUFFERSIZE - ipos),
250134832Speter				(char *)&ccbp->hi_txbuf[0],
250234832Speter				n - (SI_BUFFERSIZE - ipos));
250310015Speter		}
250410015Speter		ccbp->hi_txipos += n;
250510015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
250610015Speter	}
250710015Speter
250810015Speter	if (count != 0 && nchar == 0) {
250910015Speter		tp->t_state |= TS_BUSY;
251010015Speter	} else {
251110015Speter		tp->t_state &= ~TS_BUSY;
251210015Speter	}
251310015Speter
251410015Speter	/* wakeup time? */
251510015Speter	ttwwakeup(tp);
251610015Speter
251710015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
251810015Speter		(BYTE)count, nchar, tp->t_state));
251910015Speter
252034735Speter	if (tp->t_state & TS_BUSY)
252110015Speter	{
252210015Speter		int time;
252310015Speter
252434735Speter		time = ttspeedtab(tp->t_ospeed, chartimes);
252534735Speter
252634735Speter		if (time > 0) {
252734735Speter			if (time < nchar)
252834735Speter				time = nchar / time;
252934735Speter			else
253034735Speter				time = 2;
253110015Speter		} else {
253234735Speter			DPRINT((pp, DBG_START,
253334735Speter				"bad char time value! %d\n", time));
253434735Speter			time = hz/10;
253510015Speter		}
253610015Speter
253710015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
253829677Sgibbs			untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
253910015Speter		} else {
254010015Speter			pp->sp_state |= SS_LSTART;
254110015Speter		}
254210015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
254329677Sgibbs		pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time);
254410015Speter	}
254510015Speter
254610015Speterout:
254710015Speter	splx(oldspl);
254810015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
254910015Speter}
255010015Speter
255110015Speter/*
255210015Speter * Note: called at splsoftclock from the timeout code
255310015Speter * This has to deal with two things...  cause wakeups while waiting for
255410015Speter * tty drains on last process exit, and call l_start at about the right
255510015Speter * time for protocols like ppp.
255610015Speter */
255710015Speterstatic void
255825047Sbdesi_lstart(void *arg)
255910015Speter{
256025047Sbde	register struct si_port *pp = arg;
256110015Speter	register struct tty *tp;
256210015Speter	int oldspl;
256310015Speter
256410015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
256510015Speter		pp, pp->sp_state));
256610015Speter
256710015Speter	oldspl = spltty();
256810015Speter
256910015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
257010015Speter		splx(oldspl);
257110015Speter		return;
257210015Speter	}
257310015Speter	pp->sp_state &= ~SS_LSTART;
257410015Speter	pp->sp_state |= SS_INLSTART;
257510015Speter
257610015Speter	tp = pp->sp_tty;
257710015Speter
257810015Speter	/* deal with the process exit case */
257910015Speter	ttwwakeup(tp);
258010015Speter
258112174Speter	/* nudge protocols - eg: ppp */
258210015Speter	(*linesw[tp->t_line].l_start)(tp);
258310015Speter
258410015Speter	pp->sp_state &= ~SS_INLSTART;
258510015Speter	splx(oldspl);
258610015Speter}
258710015Speter
258810015Speter/*
258910015Speter * Stop output on a line. called at spltty();
259010015Speter */
259110015Spetervoid
259210015Spetersistop(tp, rw)
259310015Speter	register struct tty *tp;
259410015Speter	int rw;
259510015Speter{
259610015Speter	volatile struct si_channel *ccbp;
259710015Speter	struct si_port *pp;
259810015Speter
259910015Speter	pp = TP2PP(tp);
260010015Speter	ccbp = pp->sp_ccb;
260110015Speter
260210015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
260310015Speter
260410015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
260510015Speter	if (rw & FWRITE) {
260610015Speter		/* what level are we meant to be flushing anyway? */
260710015Speter		if (tp->t_state & TS_BUSY) {
260810015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
260910015Speter			tp->t_state &= ~TS_BUSY;
261010015Speter			ttwwakeup(tp);	/* Bruce???? */
261110015Speter		}
261210015Speter	}
261312174Speter#if 1	/* XXX: this doesn't work right yet.. */
261412174Speter	/* XXX: this may have been failing because we used to call l_rint()
261512174Speter	 * while we were looping based on these two counters. Now, we collect
261612174Speter	 * the data and then loop stuffing it into l_rint(), making this
261712174Speter	 * useless.  Should we cause this to blow away the staging buffer?
261812174Speter	 */
261910015Speter	if (rw & FREAD) {
262010015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
262110015Speter	}
262210015Speter#endif
262310015Speter}
262410015Speter
262510015Speter/*
262634832Speter * Issue a command to the host card CPU.
262710015Speter */
262810015Speter
262910015Speterstatic void
263010015Spetersi_command(pp, cmd, waitflag)
263110015Speter	struct si_port *pp;		/* port control block (local) */
263210015Speter	int cmd;
263310015Speter	int waitflag;
263410015Speter{
263510015Speter	int oldspl;
263610015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
263710015Speter	int x;
263810015Speter
263910015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
264010015Speter		pp, cmd, waitflag, ccbp->hi_stat));
264110015Speter
264210015Speter	oldspl = spltty();		/* Keep others out */
264310015Speter
264410015Speter	/* wait until it's finished what it was doing.. */
264516575Speter	/* XXX: sits in IDLE_BREAK until something disturbs it or break
264616575Speter	 * is turned off. */
264710015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
264810015Speter			x != IDLE_CLOSE &&
264916575Speter			x != IDLE_BREAK &&
265010015Speter			x != cmd) {
265110015Speter		if (in_intr) {			/* Prevent sleep in intr */
265210015Speter			DPRINT((pp, DBG_PARAM,
265310015Speter				"cmd intr collision - completing %d\trequested %d\n",
265410015Speter				x, cmd));
265510015Speter			splx(oldspl);
265610015Speter			return;
265710015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
265810015Speter				"sicmd1", 1)) {
265910015Speter			splx(oldspl);
266010015Speter			return;
266110015Speter		}
266210015Speter	}
266316575Speter	/* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */
266410015Speter
266510015Speter	/* if there was a pending command, cause a state-change wakeup */
266616575Speter	switch(pp->sp_pend) {
266716575Speter	case LOPEN:
266816575Speter	case MPEND:
266916575Speter	case MOPEN:
267016575Speter	case CONFIG:
267116575Speter	case SBREAK:
267216575Speter	case EBREAK:
267316575Speter		wakeup(&pp->sp_state);
267416575Speter		break;
267516575Speter	default:
267616575Speter		break;
267710015Speter	}
267810015Speter
267910015Speter	pp->sp_pend = cmd;		/* New command pending */
268010015Speter	ccbp->hi_stat = cmd;		/* Post it */
268110015Speter
268210015Speter	if (waitflag) {
268310015Speter		if (in_intr) {		/* If in interrupt handler */
268410015Speter			DPRINT((pp, DBG_PARAM,
268510015Speter				"attempt to sleep in si_intr - cmd req %d\n",
268610015Speter				cmd));
268710015Speter			splx(oldspl);
268810015Speter			return;
268916575Speter		} else while(ccbp->hi_stat != IDLE_OPEN &&
269016575Speter			     ccbp->hi_stat != IDLE_BREAK) {
269110015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
269210015Speter			    "sicmd2", 0))
269310015Speter				break;
269410015Speter		}
269510015Speter	}
269610015Speter	splx(oldspl);
269710015Speter}
269810015Speter
269910015Speterstatic void
270010015Spetersi_disc_optim(tp, t, pp)
270110015Speter	struct tty	*tp;
270210015Speter	struct termios	*t;
270310015Speter	struct si_port	*pp;
270410015Speter{
270510015Speter	/*
270610015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
270710015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
270810015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
270910015Speter	 */
271010015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
271110015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
271210015Speter	    && (!(t->c_iflag & PARMRK)
271310015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
271410015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
271510015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
271610015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
271710015Speter	else
271810015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
271933322Sphk	pp->sp_hotchar = linesw[tp->t_line].l_hotchar;
272010161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
272110161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
272210161Speter		pp->sp_hotchar));
272310015Speter}
272410015Speter
272510015Speter
272610015Speter#ifdef	SI_DEBUG
272713353Speter
272810015Speterstatic void
272913353Speter#ifdef __STDC__
273013353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
273113353Speter#else
273213353Spetersi_dprintf(pp, flags, fmt, va_alist)
273310015Speter	struct si_port *pp;
273410015Speter	int flags;
273513353Speter	char *fmt;
273613353Speter#endif
273710015Speter{
273813353Speter	va_list ap;
273913630Sphk
274010015Speter	if ((pp == NULL && (si_debug&flags)) ||
274110015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
274234832Speter		if (pp != NULL)
274334832Speter			printf("%ci%d(%d): ", 's',
274434832Speter				(int)SI_CARD(pp->sp_tty->t_dev),
274534832Speter				(int)SI_PORT(pp->sp_tty->t_dev));
274613630Sphk		va_start(ap, fmt);
274713630Sphk		vprintf(fmt, ap);
274813353Speter		va_end(ap);
274910015Speter	}
275010015Speter}
275110015Speter
275210015Speterstatic char *
275310015Spetersi_mctl2str(cmd)
275410015Speter	enum si_mctl cmd;
275510015Speter{
275610015Speter	switch (cmd) {
275734832Speter	case GET:
275834832Speter		return("GET");
275934832Speter	case SET:
276034832Speter		return("SET");
276134832Speter	case BIS:
276234832Speter		return("BIS");
276334832Speter	case BIC:
276434832Speter		return("BIC");
276510015Speter	}
276610015Speter	return("BAD");
276710015Speter}
276812502Sjulian
276912624Speter#endif	/* DEBUG */
277012502Sjulian
277134832Speterstatic char *
277234832Spetersi_modulename(host_type, uart_type)
277334832Speter	int host_type, uart_type;
277434832Speter{
277534832Speter	switch (host_type) {
277634832Speter	/* Z280 based cards */
277734832Speter#if NEISA > 0
277834832Speter	case SIEISA:
277934832Speter#endif
278034832Speter	case SIHOST2:
278134832Speter	case SIHOST:
278234832Speter#if NPCI > 0
278334832Speter	case SIPCI:
278434832Speter#endif
278534832Speter		switch (uart_type) {
278634832Speter		case 0:
278734832Speter			return(" (XIO)");
278834832Speter		case 1:
278934832Speter			return(" (SI)");
279034832Speter		}
279134832Speter		break;
279234832Speter	/* T225 based hosts */
279334832Speter#if NPCI > 0
279434832Speter	case SIJETPCI:
279534832Speter#endif
279634832Speter	case SIJETISA:
279734832Speter		switch (uart_type) {
279834832Speter		case 0:
279934832Speter			return(" (SI)");
280034832Speter		case 40:
280134832Speter			return(" (XIO)");
280236856Sphk		case 72:
280336856Sphk			return(" (SXDC)");
280434832Speter		}
280534832Speter		break;
280634832Speter	}
280734832Speter	return("");
280834832Speter}
280912624Speter
281012502Sjulianstatic si_devsw_installed = 0;
281112502Sjulian
281234832Speterstatic void
281334832Spetersi_drvinit(void *unused)
281412502Sjulian{
281512517Sjulian	dev_t dev;
281612517Sjulian
281734832Speter	if (!si_devsw_installed) {
281812675Sjulian		dev = makedev(CDEV_MAJOR, 0);
281912675Sjulian		cdevsw_add(&dev,&si_cdevsw, NULL);
282012502Sjulian		si_devsw_installed = 1;
282134832Speter	}
282212502Sjulian}
282312517Sjulian
282412517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL)
2825