si.c revision 38351
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 *
3338351Sbde *	$Id: si.c,v 1.73 1998/06/13 19:36:22 steve 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
17612675Sjulian#define CDEV_MAJOR 68
17734832Speterstatic struct cdevsw si_cdevsw =
17812675Sjulian	{ siopen,	siclose,	siread,		siwrite,	/*68*/
17912743Sbde	  siioctl,	sistop,		noreset,	sidevtotty,/* si */
18029368Speter	  ttpoll,	nommap,		NULL,	"si",	NULL,	-1 };
18112675Sjulian
18212675Sjulian
18312174Speter#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
18413353Speter
18513353Speterstatic	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,
18613353Speter				...));
18710708Speterstatic	char	*si_mctl2str __P((enum si_mctl cmd));
18813353Speter
18910708Speter#define	DPRINT(x)	si_dprintf x
19013353Speter
19110708Speter#else
19210708Speter#define	DPRINT(x)	/* void */
19310708Speter#endif
19410708Speter
19510962Speterstatic int si_Nports;
19610962Speterstatic int si_Nmodules;
19710962Speterstatic int si_debug = 0;	/* data, not bss, so it's patchable */
19810015Speter
19934832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, "");
20034832Speter
20110962Speterstatic struct tty *si_tty;
20210962Speter
20334832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */
20434832Speter/* old: si2_z280.c */
20534832Speterextern unsigned char si2_z280_download[];
20634832Speterextern unsigned short si2_z280_downloadaddr;
20734832Speterextern int si2_z280_dsize;
20834832Speter/* new: si3_t225.c */
20934832Speterextern unsigned char si3_t225_download[];
21034832Speterextern unsigned short si3_t225_downloadaddr;
21134832Speterextern int si3_t225_dsize;
21234832Speterextern unsigned char si3_t225_bootstrap[];
21334832Speterextern unsigned short si3_t225_bootloadaddr;
21434832Speterextern int si3_t225_bsize;
21510015Speter
21633395Speter
21710044Speterstruct si_softc {
21810044Speter	int 		sc_type;	/* adapter type */
21910044Speter	char 		*sc_typename;	/* adapter type string */
22010044Speter
22110044Speter	struct si_port	*sc_ports;	/* port structures for this card */
22210044Speter
22310044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
22410044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
22510044Speter	int		sc_nport;	/* # ports on this card */
22610044Speter	int		sc_irq;		/* copy of attach irq */
22734832Speter#if NEISA > 0
22810044Speter	int		sc_eisa_iobase;	/* EISA io port address */
22934832Speter	int		sc_eisa_irq;	/* EISA irq number */
23034832Speter#endif
23112675Sjulian#ifdef	DEVFS
23212675Sjulian	struct {
23334735Speter		void	*ttya;
23412826Speter		void	*cuaa;
23512675Sjulian		void	*ttyl;
23634735Speter		void	*cual;
23712675Sjulian		void	*ttyi;
23834735Speter		void	*cuai;
23912675Sjulian	} devfs_token[32]; /* what is the max per card? */
24013165Speter	void	*control_token;
24112675Sjulian#endif
24210044Speter};
24312724Sphkstatic struct si_softc si_softc[NSI];		/* up to 4 elements */
24410044Speter
24512174Speter#ifndef B2000	/* not standard, but the hardware knows it. */
24610015Speter# define B2000 2000
24710015Speter#endif
24810015Speterstatic struct speedtab bdrates[] = {
24910015Speter	B75,	CLK75,		/* 0x0 */
25010015Speter	B110,	CLK110,		/* 0x1 */
25110015Speter	B150,	CLK150,		/* 0x3 */
25210015Speter	B300,	CLK300,		/* 0x4 */
25310015Speter	B600,	CLK600,		/* 0x5 */
25410015Speter	B1200,	CLK1200,	/* 0x6 */
25510015Speter	B2000,	CLK2000,	/* 0x7 */
25610015Speter	B2400,	CLK2400,	/* 0x8 */
25710015Speter	B4800,	CLK4800,	/* 0x9 */
25810015Speter	B9600,	CLK9600,	/* 0xb */
25910015Speter	B19200,	CLK19200,	/* 0xc */
26010015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
26110015Speter	B57600, CLK57600,	/* 0xd */
26210015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
26310015Speter	-1,	-1
26410015Speter};
26510015Speter
26610015Speter
26710015Speter/* populated with approx character/sec rates - translated at card
26810015Speter * initialisation time to chars per tick of the clock */
26910015Speterstatic int done_chartimes = 0;
27010015Speterstatic struct speedtab chartimes[] = {
27110015Speter	B75,	8,
27210015Speter	B110,	11,
27310015Speter	B150,	15,
27410015Speter	B300,	30,
27510015Speter	B600,	60,
27610015Speter	B1200,	120,
27710015Speter	B2000,	200,
27810015Speter	B2400,	240,
27910015Speter	B4800,	480,
28010015Speter	B9600,	960,
28110015Speter	B19200,	1920,
28210015Speter	B38400, 3840,
28310015Speter	B57600, 5760,
28410015Speter	B115200, 11520,
28510015Speter	-1,	-1
28610015Speter};
28710015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
28810015Speter
28910015Speter#ifdef POLL
29015683Speterstatic int si_pollrate;			/* in addition to irq */
29117547Speterstatic int si_realpoll;			/* poll HW on timer */
29215639Speter
29316403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, "");
29417547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, "");
29515639Speter
29610015Speterstatic int init_finished = 0;
29710015Speterstatic void si_poll __P((void *));
29810015Speter#endif
29910015Speter
30010015Speter/*
30110015Speter * Array of adapter types and the corresponding RAM size. The order of
30210015Speter * entries here MUST match the ordinal of the adapter type.
30310015Speter */
30410015Speterstatic char *si_type[] = {
30510015Speter	"EMPTY",
30610015Speter	"SIHOST",
30734832Speter	"SIMCA",		/* FreeBSD does not support Microchannel */
30810015Speter	"SIHOST2",
30910015Speter	"SIEISA",
31033395Speter	"SIPCI",
31133395Speter	"SXPCI",
31233395Speter	"SXISA",
31310015Speter};
31410015Speter
31533395Speter#if NPCI > 0
31633395Speter
31733395Speterstatic char *
31833395Spetersipciprobe(configid, deviceid)
31933395Speterpcici_t configid;
32033395Speterpcidi_t deviceid;
32133395Speter{
32233395Speter	switch (deviceid)
32333395Speter	{
32433395Speter		case 0x400011cb:
32533395Speter			return("Specialix SI/XIO PCI host card");
32633395Speter			break;
32733395Speter		case 0x200011cb:
32833395Speter			if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb)
32933395Speter				return("Specialix SX PCI host card");
33033395Speter			else
33133395Speter				return NULL;
33233395Speter			break;
33333395Speter		default:
33433395Speter			return NULL;
33533395Speter	}
33633395Speter	/*NOTREACHED*/
33733395Speter}
33833395Speter
33933395Spetervoid
34033395Spetersipciattach(configid, unit)
34133395Speterpcici_t configid;
34233395Speterint unit;
34333395Speter{
34433395Speter	struct isa_device id;
34533395Speter	vm_offset_t vaddr,paddr;
34633395Speter	u_long mapval = 0;	/* shut up gcc, should not be needed */
34733395Speter
34833395Speter	switch ( pci_conf_read(configid, 0) >> 16 )
34933395Speter	{
35033395Speter		case 0x4000:
35133395Speter			si_softc[unit].sc_type = SIPCI;
35233395Speter			mapval = SIPCIBADR;
35334832Speter			break;
35433395Speter		case 0x2000:
35533395Speter			si_softc[unit].sc_type = SIJETPCI;
35633395Speter			mapval = SIJETBADR;
35734832Speter			break;
35833395Speter	}
35933395Speter	if (!pci_map_mem(configid, mapval, &vaddr, &paddr))
36033395Speter	{
36133395Speter		printf("si%d: couldn't map memory\n", unit);
36233395Speter	}
36333395Speter
36433395Speter	/*
36533395Speter	 * We're cheating here a little bit. The argument to an ISA
36633395Speter	 * interrupt routine is the unit number. The argument to a
36733395Speter	 * PCI interrupt handler is a void *, but we're simply going
36833395Speter	 * to be lazy and hand it the unit number.
36933395Speter	 */
37034735Speter	if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) {
37133395Speter		printf("si%d: couldn't map interrupt\n", unit);
37233395Speter	}
37333395Speter	si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type];
37433395Speter
37533395Speter	/*
37633395Speter	 * More cheating: We're going to dummy up a struct isa_device
37733395Speter	 * and call the other attach routine. We don't really have to
37833395Speter	 * fill in very much of the structure, since we filled in a
37933395Speter	 * little of the soft state already.
38033395Speter	 */
38134735Speter	id.id_unit = unit;
38234735Speter	id.id_maddr = (caddr_t) vaddr;
38333395Speter	siattach(&id);
38433395Speter}
38533395Speter
38633395Speter#endif
38733395Speter
38834832Speter#if NEISA > 0
38934832Speter
39034832Speterstatic const char *si_eisa_match __P((eisa_id_t id));
39134832Speter
39234832Speterstatic const char *
39334832Spetersi_eisa_match(id)
39434832Speter	eisa_id_t id;
39534832Speter{
39634832Speter	if (id == SIEISADEVID)
39734832Speter		return ("Specialix SI/XIO EISA host card");
39834832Speter	return (NULL);
39934832Speter}
40034832Speter
40134832Speterstatic int
40234832Spetersi_eisa_probe(void)
40334832Speter{
40434832Speter	struct eisa_device *ed = NULL;
40534832Speter	int count, irq;
40634832Speter
40734832Speter	for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++)
40834832Speter	{
40934832Speter		u_long port,maddr;
41034832Speter
41134832Speter		port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE;
41234832Speter		eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE);
41334832Speter		maddr = (inb(port+1) << 24) | (inb(port) << 16);
41434832Speter		irq  = ((inb(port+2) >> 4) & 0xf);
41534832Speter		eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE);
41634832Speter		eisa_add_intr(ed, irq);
41734832Speter		eisa_registerdev(ed, &si_eisa_driver);
41834832Speter		count++;
41934832Speter	}
42034832Speter	return count;
42134832Speter}
42234832Speter
42334832Speterstatic int
42434832Spetersi_eisa_attach(ed)
42534832Speter	struct eisa_device *ed;
42634832Speter{
42734832Speter	struct isa_device id;
42834832Speter	resvaddr_t *maddr,*iospace;
42934832Speter	u_int irq;
43034832Speter	struct si_softc *sc;
43134832Speter
43234832Speter	sc = &si_softc[ed->unit];
43334832Speter
43434832Speter	sc->sc_type = SIEISA;
43534832Speter	sc->sc_typename = si_type[sc->sc_type];
43634832Speter
43734832Speter	if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) {
43834832Speter		printf("si%d: no iospace??\n", ed->unit);
43934832Speter		return -1;
44034832Speter	}
44134832Speter	sc->sc_eisa_iobase = iospace->addr;
44234832Speter
44334832Speter	irq  = ((inb(iospace->addr + 2) >> 4) & 0xf);
44434832Speter	sc->sc_eisa_irq = irq;
44534832Speter
44634832Speter	if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) {
44734832Speter		printf("si%d: where am I??\n", ed->unit);
44834832Speter		return -1;
44934832Speter	}
45034832Speter	eisa_reg_start(ed);
45134832Speter	if (eisa_reg_iospace(ed, iospace)) {
45234832Speter		printf("si%d: failed to register iospace 0x%x\n",
45334832Speter			ed->unit, iospace);
45434832Speter		return -1;
45534832Speter	}
45634832Speter	if (eisa_reg_mspace(ed, maddr)) {
45734832Speter		printf("si%d: failed to register memspace 0x%x\n",
45834832Speter			ed->unit, maddr);
45934832Speter		return -1;
46034832Speter	}
46134832Speter	/*
46234832Speter	 * We're cheating here a little bit. The argument to an ISA
46334832Speter	 * interrupt routine is the unit number. The argument to a
46434832Speter	 * EISA interrupt handler is a void *, but we're simply going
46534832Speter	 * to be lazy and hand it the unit number.
46634832Speter	 */
46734832Speter	if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr,
46834832Speter		(void *)(ed->unit), &tty_imask, 1)) {
46934832Speter		printf("si%d: failed to register interrupt %d\n",
47034832Speter			ed->unit, irq);
47134832Speter		return -1;
47234832Speter	}
47334832Speter	eisa_reg_end(ed);
47434832Speter	if (eisa_enable_intr(ed, irq)) {
47534832Speter		return -1;
47634832Speter	}
47734832Speter
47834832Speter	/*
47934832Speter	 * More cheating: We're going to dummy up a struct isa_device
48034832Speter	 * and call the other attach routine. We don't really have to
48134832Speter	 * fill in very much of the structure, since we filled in a
48234832Speter	 * little of the soft state already.
48334832Speter	 */
48434832Speter	id.id_unit = ed->unit;
48534832Speter	id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE);
48634832Speter	return (siattach(&id));
48734832Speter}
48834832Speter
48934832Speter#endif
49034832Speter
49134832Speter
49210015Speter/* Look for a valid board at the given mem addr */
49312724Sphkstatic int
49410015Spetersiprobe(id)
49510015Speter	struct isa_device *id;
49610015Speter{
49710015Speter	struct si_softc *sc;
49810015Speter	int type;
49910015Speter	u_int i, ramsize;
50010015Speter	volatile BYTE was, *ux;
50110015Speter	volatile unsigned char *maddr;
50210015Speter	unsigned char *paddr;
50310015Speter
50417547Speter	si_pollrate = POLLHZ;		/* default 10 per second */
50517547Speter#ifdef REALPOLL
50617547Speter	si_realpoll = 1;		/* scan always */
50717547Speter#endif
50810015Speter	maddr = id->id_maddr;		/* virtual address... */
50910015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
51010015Speter
51112496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
51212496Speter		id->id_unit, id->id_maddr, paddr));
51310015Speter
51410015Speter	/*
51510015Speter	 * this is a lie, but it's easier than trying to handle caching
51610015Speter	 * and ram conflicts in the >1M and <16M region.
51710015Speter	 */
51810015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
51910015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
52012174Speter		printf("si%d: iomem (%lx) out of range\n",
52112174Speter			id->id_unit, (long)paddr);
52210015Speter		return(0);
52310015Speter	}
52410015Speter
52510015Speter	if (id->id_unit >= NSI) {
52610015Speter		/* THIS IS IMPOSSIBLE */
52710015Speter		return(0);
52810015Speter	}
52910015Speter
53010015Speter	if (((u_int)paddr & 0x7fff) != 0) {
53110015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
53210015Speter			"si%d: iomem (%x) not on 32k boundary\n",
53310015Speter			id->id_unit, paddr));
53410015Speter		return(0);
53510015Speter	}
53610015Speter
53734735Speter	if (si_softc[id->id_unit].sc_typename) {
53834832Speter		/* EISA or PCI has taken this unit, choose another */
53934735Speter		for (i=0; i < NSI; i++) {
54034735Speter			if (si_softc[i].sc_typename == NULL) {
54134735Speter				id->id_unit = i;
54234735Speter				break;
54334735Speter			}
54434735Speter		}
54534735Speter		if (i >= NSI) {
54634735Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
54734735Speter				"si%d: cannot realloc unit\n", id->id_unit));
54834735Speter			return (0);
54934735Speter		}
55034735Speter	}
55134735Speter
55210015Speter	for (i=0; i < NSI; i++) {
55334735Speter		sc = &si_softc[i];
55410015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
55510015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
55610015Speter				"si%d: iomem (%x) already configured to si%d\n",
55710015Speter				id->id_unit, sc->sc_paddr, i));
55810015Speter			return(0);
55910015Speter		}
56010015Speter	}
56110015Speter
56210015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
56310015Speter	*maddr = 0x17;
56410015Speter	if (*maddr != 0x17) {
56510015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
56610015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
56710015Speter			id->id_unit, paddr));
56810015Speterfail:
56910015Speter		return(0);
57010015Speter	}
57110015Speter	/*
57233395Speter	 * Let's look first for a JET ISA card, since that's pretty easy
57334832Speter	 *
57434832Speter	 * All jet hosts are supposed to have this string in the IDROM,
57534832Speter	 * but it's not worth checking on self-IDing busses like PCI.
57633395Speter	 */
57734832Speter	{
57834832Speter		unsigned char *jet_chk_str = "JET HOST BY KEV#";
57934832Speter
58034832Speter		for (i = 0; i < strlen(jet_chk_str); i++)
58134832Speter			if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i))
58234832Speter				goto try_mk2;
58334832Speter	}
58433395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
58533395Speter		"si%d: JET first check - 0x%x\n",
58633395Speter		id->id_unit, (*(maddr+SIJETIDBASE))));
58733395Speter	if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff))
58833395Speter		goto try_mk2;
58933395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
59033395Speter		"si%d: JET second check - 0x%x\n",
59133395Speter		id->id_unit, (*(maddr+SIJETIDBASE+2))));
59233395Speter	if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8))
59333395Speter		goto try_mk2;
59433395Speter	/* It must be a Jet ISA or RIO card */
59533395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
59633395Speter		"si%d: JET id check - 0x%x\n",
59733395Speter		id->id_unit, (*(maddr+SIUNIQID))));
59833395Speter	if ((*(maddr+SIUNIQID) & 0xf0) !=0x20)
59933395Speter		goto try_mk2;
60033395Speter	/* It must be a Jet ISA SI/XIO card */
60133395Speter	*(maddr + SIJETCONFIG) = 0;
60233395Speter	type = SIJETISA;
60333395Speter	ramsize = SIJET_RAMSIZE;
60433395Speter	goto got_card;
60533395Speter	/*
60610015Speter	 * OK, now to see if whatever responded is really an SI card.
60733395Speter	 * Try for a MK II next (SIHOST2)
60810015Speter	 */
60933395Spetertry_mk2:
61034832Speter	for (i = SIPLSIG; i < SIPLSIG + 8; i++)
61110015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
61210015Speter			goto try_mk1;
61310015Speter
61410015Speter	/* It must be an SIHOST2 */
61510015Speter	*(maddr + SIPLRESET) = 0;
61610015Speter	*(maddr + SIPLIRQCLR) = 0;
61710015Speter	*(maddr + SIPLIRQSET) = 0x10;
61810015Speter	type = SIHOST2;
61910015Speter	ramsize = SIHOST2_RAMSIZE;
62010015Speter	goto got_card;
62110015Speter
62210015Speter	/*
62310015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
62410015Speter	 */
62510015Spetertry_mk1:
62610015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
62710015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
62810015Speter	*(maddr+SIRAM) = 0x17;
62910015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
63010015Speter		goto fail;
63110015Speter	*(maddr+0x7ff8) = 0x17;
63210015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
63310015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
63410015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
63510015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
63610015Speter		goto fail;
63710015Speter	}
63810015Speter
63934832Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXX */
64010015Speter	type = SIHOST;
64110015Speter	ramsize = SIHOST_RAMSIZE;
64210015Speter
64310015Spetergot_card:
64412496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
64512496Speter		id->id_unit, type));
64610015Speter	/* Try the acid test */
64718515Speter	ux = maddr + SIRAM;
64834832Speter	for (i = 0; i < ramsize; i++, ux++)
64910015Speter		*ux = (BYTE)(i&0xff);
65018515Speter	ux = maddr + SIRAM;
65134832Speter	for (i = 0; i < ramsize; i++, ux++) {
65210015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
65310015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
65412174Speter				"si%d: match fail at phys 0x%x, was %x should be %x\n",
65534832Speter				id->id_unit, paddr + i, was, i&0xff));
65610015Speter			goto fail;
65710015Speter		}
65810015Speter	}
65910015Speter
66010015Speter	/* clear out the RAM */
66118515Speter	ux = maddr + SIRAM;
66234832Speter	for (i = 0; i < ramsize; i++)
66310015Speter		*ux++ = 0;
66418515Speter	ux = maddr + SIRAM;
66534832Speter	for (i = 0; i < ramsize; i++) {
66610015Speter		if ((was = *ux++) != 0) {
66710015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
66812174Speter				"si%d: clear fail at phys 0x%x, was %x\n",
66934832Speter				id->id_unit, paddr + i, was));
67010015Speter			goto fail;
67110015Speter		}
67210015Speter	}
67310015Speter
67410015Speter	/*
67510015Speter	 * Success, we've found a valid board, now fill in
67610015Speter	 * the adapter structure.
67710015Speter	 */
67810015Speter	switch (type) {
67910015Speter	case SIHOST2:
68034832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
68110015Speterbad_irq:
68210015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
68310015Speter				"si%d: bad IRQ value - %d\n",
68410015Speter				id->id_unit, id->id_irq));
68510015Speter			return(0);
68610015Speter		}
68710015Speter		id->id_msize = SIHOST2_MEMSIZE;
68810015Speter		break;
68910015Speter	case SIHOST:
69034832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
69110015Speter			goto bad_irq;
69210015Speter		}
69310015Speter		id->id_msize = SIHOST_MEMSIZE;
69410015Speter		break;
69533395Speter	case SIJETISA:
69634832Speter		if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) {
69733395Speter			goto bad_irq;
69833395Speter		}
69934832Speter		id->id_msize = SIJETISA_MEMSIZE;
70033395Speter		break;
70134832Speter	case SIMCA:		/* MCA */
70210015Speter	default:
70310015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
70410015Speter		return(0);
70510015Speter	}
70634832Speter	id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */
70710015Speter	si_softc[id->id_unit].sc_type = type;
70810015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
70910015Speter	return(-1);	/* -1 == found */
71010015Speter}
71110015Speter
71210015Speter/*
71334832Speter * We have to make an 8 bit version of bcopy, since some cards can't
71434832Speter * deal with 32 bit I/O
71534832Speter */
71634832Speter#if 1
71734832Speterstatic void
71834832Spetersi_bcopy(const void *src, void *dst, size_t len)
71934832Speter{
72034832Speter	while (len--)
72134832Speter		*(((u_char *)dst)++) = *(((u_char *)src)++);
72234832Speter}
72334832Speter#else
72434832Speter#define si_bcopy bcopy
72534832Speter#endif
72634832Speter
72734832Speter
72834832Speter/*
72910015Speter * Attach the device.  Initialize the card.
73034832Speter *
73134832Speter * This routine also gets called by the EISA and PCI attach routines.
73234832Speter * It presumes that the softstate for the unit has had had its type field
73334832Speter * and the EISA specific stuff filled in, as well as the kernel virtual
73434832Speter * base address and the unit number of the isa_device struct.
73510015Speter */
73612724Sphkstatic int
73710015Spetersiattach(id)
73810015Speter	struct isa_device *id;
73910015Speter{
74010015Speter	int unit = id->id_unit;
74110015Speter	struct si_softc *sc = &si_softc[unit];
74210015Speter	struct si_port *pp;
74310015Speter	volatile struct si_channel *ccbp;
74410015Speter	volatile struct si_reg *regp;
74510015Speter	volatile caddr_t maddr;
74610015Speter	struct si_module *modp;
74710015Speter	struct tty *tp;
74810015Speter	struct speedtab *spt;
74910015Speter	int nmodule, nport, x, y;
75012174Speter	int uart_type;
75110015Speter
75212496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
75310015Speter
75410015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
75510015Speter	sc->sc_maddr = id->id_maddr;
75610015Speter	sc->sc_irq = id->id_irq;
75710015Speter
75833395Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit,
75933395Speter		sc->sc_typename, sc->sc_paddr, sc->sc_maddr));
76033395Speter
76110015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
76210015Speter
76310015Speter	maddr = sc->sc_maddr;
76410015Speter
76534832Speter	/* Stop the CPU first so it won't stomp around while we load */
76634832Speter
76734832Speter	switch (sc->sc_type) {
76834832Speter#if NEISA > 0
76934832Speter		case SIEISA:
77034832Speter			outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4);
77134832Speter		break;
77234832Speter#endif
77334832Speter#if NPCI > 0
77434832Speter		case SIPCI:
77534832Speter			*(maddr+SIPCIRESET) = 0;
77634832Speter		break;
77734832Speter		case SIJETPCI: /* fall through to JET ISA */
77834832Speter#endif
77934832Speter		case SIJETISA:
78034832Speter			*(maddr+SIJETCONFIG) = 0;
78134832Speter		break;
78234832Speter		case SIHOST2:
78334832Speter			*(maddr+SIPLRESET) = 0;
78434832Speter		break;
78534832Speter		case SIHOST:
78634832Speter			*(maddr+SIRESET) = 0;
78734832Speter		break;
78834832Speter		default: /* this should never happen */
78934832Speter			printf("si%d: unsupported configuration\n", unit);
79034832Speter			return 0;
79134832Speter		break;
79234832Speter	}
79334832Speter
79434832Speter	/* OK, now lets download the download code */
79534832Speter
79636956Ssteve	if (SI_ISJET(sc->sc_type)) {
79733395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n",
79834832Speter			id->id_unit, si3_t225_dsize));
79934832Speter		si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr,
80034832Speter			si3_t225_dsize);
80134832Speter		DPRINT((0, DBG_DOWNLOAD,
80234832Speter			"si%d: jet_bootstrap: nbytes %d -> %x\n",
80334832Speter			id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr));
80434832Speter		si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr,
80534832Speter			si3_t225_bsize);
80634832Speter	} else {
80733395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
80834832Speter			id->id_unit, si2_z280_dsize));
80934832Speter		si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr,
81034832Speter			si2_z280_dsize);
81133395Speter	}
81210015Speter
81334832Speter	/* Now start the CPU */
81434832Speter
81510015Speter	switch (sc->sc_type) {
81634832Speter#if NEISA > 0
81710015Speter	case SIEISA:
81834832Speter		/* modify the download code to tell it that it's on an EISA */
81934832Speter		*(maddr + 0x42) = 1;
82034832Speter		outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4);
82134832Speter		(void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */
82210015Speter		break;
82334832Speter#endif
82433395Speter	case SIPCI:
82534832Speter		/* modify the download code to tell it that it's on a PCI */
82633395Speter		*(maddr+0x42) = 1;
82733395Speter		*(maddr+SIPCIRESET) = 1;
82833395Speter		*(maddr+SIPCIINTCL) = 0;
82933395Speter		break;
83033395Speter	case SIJETPCI:
83133395Speter		*(maddr+SIJETRESET) = 0;
83233395Speter		*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN;
83333395Speter		break;
83433395Speter	case SIJETISA:
83533395Speter		*(maddr+SIJETRESET) = 0;
83634832Speter		switch (sc->sc_irq) {
83734832Speter		case IRQ9:
83834832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90;
83934832Speter			break;
84034832Speter		case IRQ10:
84134832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0;
84234832Speter			break;
84334832Speter		case IRQ11:
84434832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0;
84534832Speter			break;
84634832Speter		case IRQ12:
84734832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0;
84834832Speter			break;
84934832Speter		case IRQ15:
85034832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0;
85134832Speter			break;
85234832Speter		}
85333395Speter		break;
85410015Speter	case SIHOST:
85510015Speter		*(maddr+SIRESET_CL) = 0;
85610015Speter		*(maddr+SIINTCL_CL) = 0;
85710015Speter		break;
85810015Speter	case SIHOST2:
85910015Speter		*(maddr+SIPLRESET) = 0x10;
86010015Speter		switch (sc->sc_irq) {
86110015Speter		case IRQ11:
86210015Speter			*(maddr+SIPLIRQ11) = 0x10;
86310015Speter			break;
86410015Speter		case IRQ12:
86510015Speter			*(maddr+SIPLIRQ12) = 0x10;
86610015Speter			break;
86710015Speter		case IRQ15:
86810015Speter			*(maddr+SIPLIRQ15) = 0x10;
86910015Speter			break;
87010015Speter		}
87110015Speter		*(maddr+SIPLIRQCLR) = 0x10;
87210015Speter		break;
87334832Speter	default: /* this should _REALLY_ never happen */
87434832Speter		printf("si%d: Uh, it was supported a second ago...\n", unit);
87534832Speter		return 0;
87610015Speter	}
87710015Speter
87810015Speter	DELAY(1000000);			/* wait around for a second */
87910015Speter
88010015Speter	regp = (struct si_reg *)maddr;
88110015Speter	y = 0;
88210015Speter					/* wait max of 5 sec for init OK */
88310015Speter	while (regp->initstat == 0 && y++ < 10) {
88410015Speter		DELAY(500000);
88510015Speter	}
88610015Speter	switch (regp->initstat) {
88710015Speter	case 0:
88810015Speter		printf("si%d: startup timeout - aborting\n", unit);
88912174Speter		sc->sc_type = SIEMPTY;
89010015Speter		return 0;
89110015Speter	case 1:
89236956Ssteve		if (SI_ISJET(sc->sc_type)) {
89334832Speter			/* set throttle to 100 times per second */
89434832Speter			regp->int_count = JET_INT_COUNT;
89534832Speter			/* rx_intr_count is a NOP in Jet */
89634832Speter		} else {
89734832Speter			/* set throttle to 125 times per second */
89834832Speter			regp->int_count = INT_COUNT;
89934832Speter			/* rx intr max of 25 times per second */
90034832Speter			regp->rx_int_count = RXINT_COUNT;
90134832Speter		}
90210015Speter		regp->int_pending = 0;		/* no intr pending */
90310015Speter		regp->int_scounter = 0;	/* reset counter */
90410015Speter		break;
90510015Speter	case 0xff:
90610015Speter		/*
90710015Speter		 * No modules found, so give up on this one.
90810015Speter		 */
90910015Speter		printf("si%d: %s - no ports found\n", unit,
91010015Speter			si_type[sc->sc_type]);
91110015Speter		return 0;
91210015Speter	default:
91334832Speter		printf("si%d: download code version error - initstat %x\n",
91410015Speter			unit, regp->initstat);
91510015Speter		return 0;
91610015Speter	}
91710015Speter
91810015Speter	/*
91910015Speter	 * First time around the ports just count them in order
92010015Speter	 * to allocate some memory.
92110015Speter	 */
92210015Speter	nport = 0;
92310015Speter	modp = (struct si_module *)(maddr + 0x80);
92410015Speter	for (;;) {
92512174Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
92634832Speter		switch (modp->sm_type) {
92734832Speter		case TA4:
92810015Speter			DPRINT((0, DBG_DOWNLOAD,
92934832Speter				"si%d: Found old TA4 module, 4 ports\n",
93034832Speter				unit));
93134832Speter			x = 4;
93210015Speter			break;
93334832Speter		case TA8:
93434832Speter			DPRINT((0, DBG_DOWNLOAD,
93534832Speter				"si%d: Found old TA8 module, 8 ports\n",
93634832Speter				unit));
93734832Speter			x = 8;
93834832Speter			break;
93934832Speter		case TA4_ASIC:
94034832Speter			DPRINT((0, DBG_DOWNLOAD,
94134832Speter				"si%d: Found ASIC TA4 module, 4 ports\n",
94234832Speter				unit));
94334832Speter			x = 4;
94434832Speter			break;
94534832Speter		case TA8_ASIC:
94634832Speter			DPRINT((0, DBG_DOWNLOAD,
94734832Speter				"si%d: Found ASIC TA8 module, 8 ports\n",
94834832Speter				unit));
94934832Speter			x = 8;
95034832Speter			break;
95134832Speter		case MTA:
95234832Speter			DPRINT((0, DBG_DOWNLOAD,
95334832Speter				"si%d: Found CD1400 module, 8 ports\n",
95434832Speter				unit));
95534832Speter			x = 8;
95634832Speter			break;
95734832Speter		case SXDC:
95834832Speter			DPRINT((0, DBG_DOWNLOAD,
95934832Speter				"si%d: Found SXDC module, 8 ports\n",
96034832Speter				unit));
96134832Speter			x = 8;
96234832Speter			break;
96310015Speter		default:
96410015Speter			printf("si%d: unknown module type %d\n",
96510015Speter				unit, modp->sm_type);
96634832Speter			goto try_next;
96710015Speter		}
96834832Speter
96934832Speter		/* this was limited in firmware and is also a driver issue */
97034832Speter		if ((nport + x) > SI_MAXPORTPERCARD) {
97134832Speter			printf("si%d: extra ports ignored\n", unit);
97234832Speter			goto try_next;
97334832Speter		}
97434832Speter
97534832Speter		nport += x;
97634832Speter		si_Nports += x;
97734832Speter		si_Nmodules++;
97834832Speter
97934832Spetertry_next:
98010015Speter		if (modp->sm_next == 0)
98110015Speter			break;
98210015Speter		modp = (struct si_module *)
98310015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
98410015Speter	}
98510015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
98610015Speter		M_DEVBUF, M_NOWAIT);
98710015Speter	if (sc->sc_ports == 0) {
98810015Spetermem_fail:
98910015Speter		printf("si%d: fail to malloc memory for port structs\n",
99010015Speter			unit);
99110015Speter		return 0;
99210015Speter	}
99310015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
99410015Speter	sc->sc_nport = nport;
99510015Speter
99610015Speter	/*
99710015Speter	 * allocate tty structures for ports
99810015Speter	 */
99910015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
100010015Speter	if (tp == 0)
100110015Speter		goto mem_fail;
100210015Speter	bzero(tp, sizeof(*tp) * nport);
100310962Speter	si_tty = tp;
100410015Speter
100510015Speter	/*
100610015Speter	 * Scan round the ports again, this time initialising.
100710015Speter	 */
100810015Speter	pp = sc->sc_ports;
100910015Speter	nmodule = 0;
101010015Speter	modp = (struct si_module *)(maddr + 0x80);
101134832Speter	uart_type = 1000;	/* arbitary, > uchar_max */
101210015Speter	for (;;) {
101334832Speter		switch (modp->sm_type) {
101434832Speter		case TA4:
101534832Speter			nport = 4;
101610015Speter			break;
101734832Speter		case TA8:
101834832Speter			nport = 8;
101934832Speter			break;
102034832Speter		case TA4_ASIC:
102134832Speter			nport = 4;
102234832Speter			break;
102334832Speter		case TA8_ASIC:
102434832Speter			nport = 8;
102534832Speter			break;
102634832Speter		case MTA:
102734832Speter			nport = 8;
102834832Speter			break;
102934832Speter		case SXDC:
103034832Speter			nport = 8;
103134832Speter			break;
103210015Speter		default:
103334832Speter			goto try_next2;
103410015Speter		}
103534832Speter		nmodule++;
103634832Speter		ccbp = (struct si_channel *)((char *)modp + 0x100);
103734832Speter		if (uart_type == 1000)
103834832Speter			uart_type = ccbp->type;
103934832Speter		else if (uart_type != ccbp->type)
104034832Speter			printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n",
104134832Speter			    unit, nmodule,
104234832Speter			    ccbp->type, si_modulename(sc->sc_type, ccbp->type),
104334832Speter			    uart_type, si_modulename(sc->sc_type, uart_type));
104434832Speter
104534832Speter		for (x = 0; x < nport; x++, pp++, ccbp++) {
104634832Speter			pp->sp_ccb = ccbp;	/* save the address */
104734832Speter			pp->sp_tty = tp++;
104834832Speter			pp->sp_pend = IDLE_CLOSE;
104934832Speter			pp->sp_state = 0;	/* internal flag */
105034832Speter			pp->sp_dtr_wait = 3 * hz;
105134832Speter			pp->sp_iin.c_iflag = TTYDEF_IFLAG;
105234832Speter			pp->sp_iin.c_oflag = TTYDEF_OFLAG;
105334832Speter			pp->sp_iin.c_cflag = TTYDEF_CFLAG;
105434832Speter			pp->sp_iin.c_lflag = TTYDEF_LFLAG;
105534832Speter			termioschars(&pp->sp_iin);
105634832Speter			pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
105734832Speter				TTYDEF_SPEED;;
105834832Speter			pp->sp_iout = pp->sp_iin;
105934832Speter		}
106034832Spetertry_next2:
106110015Speter		if (modp->sm_next == 0) {
106234832Speter			printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n",
106310015Speter				unit,
106410015Speter				sc->sc_typename,
106510015Speter				sc->sc_nport,
106612174Speter				nmodule,
106734832Speter				uart_type,
106834832Speter				si_modulename(sc->sc_type, uart_type));
106910015Speter			break;
107010015Speter		}
107110015Speter		modp = (struct si_module *)
107210015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
107310015Speter	}
107410015Speter	if (done_chartimes == 0) {
107510015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
107610015Speter			if ((spt->sp_code /= hz) == 0)
107710015Speter				spt->sp_code = 1;
107810015Speter		}
107910015Speter		done_chartimes = 1;
108010015Speter	}
108112502Sjulian
108212675Sjulian#ifdef DEVFS
108312675Sjulian/*	path	name	devsw		minor	type   uid gid perm*/
108413169Speter	for ( x = 0; x < sc->sc_nport; x++ ) {
108534735Speter		/* sync with the manuals that start at 1 */
108634735Speter		y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT);
108734735Speter		sc->devfs_token[x].ttya = devfs_add_devswf(
108813630Sphk			&si_cdevsw, x,
108913630Sphk			DV_CHR, 0, 0, 0600, "ttyA%02d", y);
109013630Sphk		sc->devfs_token[x].cuaa = devfs_add_devswf(
109134735Speter			&si_cdevsw, x + 0x00080,
109213630Sphk			DV_CHR, 0, 0, 0600, "cuaA%02d", y);
109313630Sphk		sc->devfs_token[x].ttyi = devfs_add_devswf(
109413630Sphk			&si_cdevsw, x + 0x10000,
109513630Sphk			DV_CHR, 0, 0, 0600, "ttyiA%02d", y);
109634735Speter		sc->devfs_token[x].cuai = devfs_add_devswf(
109734735Speter			&si_cdevsw, x + 0x10080,
109834735Speter			DV_CHR, 0, 0, 0600, "cuaiA%02d", y);
109913630Sphk		sc->devfs_token[x].ttyl = devfs_add_devswf(
110013630Sphk			&si_cdevsw, x + 0x20000,
110113630Sphk			DV_CHR, 0, 0, 0600, "ttylA%02d", y);
110234735Speter		sc->devfs_token[x].cual = devfs_add_devswf(
110334735Speter			&si_cdevsw, x + 0x20080,
110434735Speter			DV_CHR, 0, 0, 0600, "cualA%02d", y);
110512675Sjulian	}
110614873Sscrappy	sc->control_token =
110714873Sscrappy		devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600,
110814873Sscrappy				 "si_control");
110912675Sjulian#endif
111010015Speter	return (1);
111110015Speter}
111210015Speter
111312675Sjulianstatic	int
111410015Spetersiopen(dev, flag, mode, p)
111510015Speter	dev_t dev;
111610015Speter	int flag, mode;
111710015Speter	struct proc *p;
111810015Speter{
111910015Speter	int oldspl, error;
112010015Speter	int card, port;
112110015Speter	register struct si_softc *sc;
112210015Speter	register struct tty *tp;
112310015Speter	volatile struct si_channel *ccbp;
112410015Speter	struct si_port *pp;
112510015Speter	int mynor = minor(dev);
112610015Speter
112710015Speter	/* quickly let in /dev/si_control */
112810015Speter	if (IS_CONTROLDEV(mynor)) {
112918515Speter		if ((error = suser(p->p_ucred, &p->p_acflag)))
113010015Speter			return(error);
113110015Speter		return(0);
113210015Speter	}
113310015Speter
113410015Speter	card = SI_CARD(mynor);
113510015Speter	if (card >= NSI)
113610015Speter		return (ENXIO);
113710015Speter	sc = &si_softc[card];
113810015Speter
113912174Speter	if (sc->sc_type == SIEMPTY) {
114012174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
114110015Speter			card, sc->sc_typename));
114210015Speter		return(ENXIO);
114310015Speter	}
114410015Speter
114510015Speter	port = SI_PORT(mynor);
114610015Speter	if (port >= sc->sc_nport) {
114712174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
114810015Speter			card, sc->sc_nport));
114910015Speter		return(ENXIO);
115010015Speter	}
115110015Speter
115210015Speter#ifdef	POLL
115310015Speter	/*
115410015Speter	 * We've now got a device, so start the poller.
115510015Speter	 */
115610015Speter	if (init_finished == 0) {
115715639Speter		timeout(si_poll, (caddr_t)0L, si_pollrate);
115810015Speter		init_finished = 1;
115910015Speter	}
116010015Speter#endif
116110015Speter
116210015Speter	/* initial/lock device */
116310015Speter	if (IS_STATE(mynor)) {
116410015Speter		return(0);
116510015Speter	}
116610015Speter
116710015Speter	pp = sc->sc_ports + port;
116810015Speter	tp = pp->sp_tty;			/* the "real" tty */
116910015Speter	ccbp = pp->sp_ccb;			/* Find control block */
117010015Speter	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
117110015Speter		dev, flag, mode, p));
117210015Speter
117310015Speter	oldspl = spltty();			/* Keep others out */
117410015Speter	error = 0;
117510015Speter
117610015Speteropen_top:
117710015Speter	while (pp->sp_state & SS_DTR_OFF) {
117810015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
117910015Speter		if (error != 0)
118010015Speter			goto out;
118110015Speter	}
118210015Speter
118310015Speter	if (tp->t_state & TS_ISOPEN) {
118410015Speter		/*
118510015Speter		 * The device is open, so everything has been initialised.
118610015Speter		 * handle conflicts.
118710015Speter		 */
118810015Speter		if (IS_CALLOUT(mynor)) {
118910015Speter			if (!pp->sp_active_out) {
119010015Speter				error = EBUSY;
119110015Speter				goto out;
119210015Speter			}
119310015Speter		} else {
119410015Speter			if (pp->sp_active_out) {
119510015Speter				if (flag & O_NONBLOCK) {
119610015Speter					error = EBUSY;
119710015Speter					goto out;
119810015Speter				}
119910015Speter				error = tsleep(&pp->sp_active_out,
120010015Speter						TTIPRI|PCATCH, "sibi", 0);
120110015Speter				if (error != 0)
120210015Speter					goto out;
120310015Speter				goto open_top;
120410015Speter			}
120510015Speter		}
120610015Speter		if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
120710015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
120810015Speter				"already open and EXCLUSIVE set\n"));
120910015Speter			error = EBUSY;
121010015Speter			goto out;
121110015Speter		}
121210015Speter	} else {
121310015Speter		/*
121410015Speter		 * The device isn't open, so there are no conflicts.
121510015Speter		 * Initialize it. Avoid sleep... :-)
121610015Speter		 */
121710015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
121810015Speter		tp->t_oproc = si_start;
121910015Speter		tp->t_param = siparam;
122010015Speter		tp->t_dev = dev;
122110015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
122210015Speter				? pp->sp_iout : pp->sp_iin;
122310015Speter
122410015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
122510015Speter
122610015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
122710015Speter
122810015Speter		error = siparam(tp, &tp->t_termios);
122910015Speter
123010015Speter		--pp->sp_wopeners;
123110015Speter		if (error != 0)
123210015Speter			goto out;
123310015Speter		/* XXX: we should goto_top if siparam slept */
123410015Speter
123510015Speter		ttsetwater(tp);
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