si.c revision 50016
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 *
3350016Snsayer *	$Id: si.c,v 1.87 1999/05/31 11:26:28 phk 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
8346332Speter#warning "Fix si eisa code! - newbus casualty"
8446332Speter#undef NEISA
8546332Speter#define NEISA 0
8646332Speter#endif
8746332Speter#if NEISA > 0
8834832Speter#include <i386/eisa/eisaconf.h>
8934832Speter#include <i386/isa/icu.h>
9034832Speter#endif
9134832Speter
9210015Speter#include "si.h"
9310015Speter
9410015Speter/*
9510015Speter * This device driver is designed to interface the Specialix International
9634832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA,
9734832Speter * EISA or PCI bus machine.
9810015Speter *
9934832Speter * The controller is interfaced to the host via dual port RAM
10034832Speter * and an interrupt.
10133395Speter *
10234832Speter * The code for the Host 1 (very old ISA cards) has not been tested.
10310015Speter */
10410015Speter
10517547Speter#define	POLL		/* turn on poller to scan for lost interrupts */
10617547Speter#define REALPOLL	/* on each poll, scan for work regardless */
10717547Speter#define POLLHZ	(hz/10)	/* 10 times per second */
10812496Speter#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
10934832Speter#define INT_COUNT 25000		/* max of 125 ints per second */
11034832Speter#define JET_INT_COUNT 100	/* max of 100 ints per second */
11115639Speter#define RXINT_COUNT 1	/* one rxint per 10 milliseconds */
11210015Speter
11310015Speterenum si_mctl { GET, SET, BIS, BIC };
11410015Speter
11510015Speterstatic void si_command __P((struct si_port *, int, int));
11610015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int));
11710015Speterstatic void si_write_enable __P((struct si_port *, int));
11838351Sbdestatic int si_Sioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
11910015Speterstatic void si_start __P((struct tty *));
12025047Sbdestatic timeout_t si_lstart;
12110015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
12210015Speter					struct si_port *pp));
12310015Speterstatic void sihardclose __P((struct si_port *pp));
12410015Speterstatic void sidtrwakeup __P((void *chan));
12510015Speter
12612724Sphkstatic int	siparam __P((struct tty *, struct termios *));
12710015Speter
12812724Sphkstatic	int	siprobe __P((struct isa_device *id));
12912724Sphkstatic	int	siattach __P((struct isa_device *id));
13010708Speterstatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
13134735Speterstatic void	si_intr __P((int unit));
13234832Speterstatic char *	si_modulename __P((int host_type, int uart_type));
13310708Speter
13412675Sjulianstruct isa_driver sidriver =
13512675Sjulian	{ siprobe, siattach, "si" };
13612675Sjulian
13734832Speterstatic u_long sipcieisacount = 0;
13834832Speter
13933395Speter#if NPCI > 0
14012675Sjulian
14142546Seivindstatic const char *sipciprobe __P((pcici_t, pcidi_t));
14233395Speterstatic void sipciattach __P((pcici_t, int));
14333395Speter
14433395Speterstatic struct pci_device sipcidev = {
14533395Speter	"si",
14633395Speter	sipciprobe,
14733395Speter	sipciattach,
14834832Speter	&sipcieisacount,
14933395Speter	NULL,
15033395Speter};
15133395Speter
15246024SpeterCOMPAT_PCI_DRIVER (sipci, sipcidev);
15333395Speter
15433395Speter#endif
15533395Speter
15634832Speter#if NEISA > 0
15734832Speter
15834832Speterstatic int si_eisa_probe __P((void));
15934832Speterstatic int si_eisa_attach __P((struct eisa_device *ed));
16034832Speter
16134832Speterstatic struct eisa_driver si_eisa_driver = {
16234832Speter	"si",
16334832Speter	si_eisa_probe,
16434832Speter	si_eisa_attach,
16534832Speter	NULL,
16634832Speter	&sipcieisacount,
16734832Speter};
16834832Speter
16934832SpeterDATA_SET(eisadriver_set, si_eisa_driver);
17034832Speter
17134832Speter#endif
17234832Speter
17312675Sjulianstatic	d_open_t	siopen;
17412675Sjulianstatic	d_close_t	siclose;
17512675Sjulianstatic	d_read_t	siread;
17612675Sjulianstatic	d_write_t	siwrite;
17712675Sjulianstatic	d_ioctl_t	siioctl;
17812675Sjulianstatic	d_stop_t	sistop;
17912731Sbdestatic	d_devtotty_t	sidevtotty;
18012675Sjulian
18138485Sbde#define	CDEV_MAJOR	68
18247625Sphkstatic struct cdevsw si_cdevsw = {
18347625Sphk	/* open */	siopen,
18447625Sphk	/* close */	siclose,
18547625Sphk	/* read */	siread,
18647625Sphk	/* write */	siwrite,
18747625Sphk	/* ioctl */	siioctl,
18847625Sphk	/* stop */	sistop,
18947625Sphk	/* reset */	noreset,
19047625Sphk	/* devtotty */	sidevtotty,
19147625Sphk	/* poll */	ttpoll,
19247625Sphk	/* mmap */	nommap,
19347625Sphk	/* strategy */	nostrategy,
19447625Sphk	/* name */	"si",
19547625Sphk	/* parms */	noparms,
19647625Sphk	/* maj */	CDEV_MAJOR,
19747625Sphk	/* dump */	nodump,
19847625Sphk	/* psize */	nopsize,
19947625Sphk	/* flags */	D_TTY,
20047625Sphk	/* maxio */	0,
20147625Sphk	/* bmaj */	-1
20238485Sbde};
20312675Sjulian
20412174Speter#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
20513353Speter
20613353Speterstatic	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,
20713353Speter				...));
20810708Speterstatic	char	*si_mctl2str __P((enum si_mctl cmd));
20913353Speter
21010708Speter#define	DPRINT(x)	si_dprintf x
21113353Speter
21210708Speter#else
21310708Speter#define	DPRINT(x)	/* void */
21410708Speter#endif
21510708Speter
21610962Speterstatic int si_Nports;
21710962Speterstatic int si_Nmodules;
21810962Speterstatic int si_debug = 0;	/* data, not bss, so it's patchable */
21910015Speter
22034832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, "");
22134832Speter
22210962Speterstatic struct tty *si_tty;
22310962Speter
22434832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */
22534832Speter/* old: si2_z280.c */
22634832Speterextern unsigned char si2_z280_download[];
22734832Speterextern unsigned short si2_z280_downloadaddr;
22834832Speterextern int si2_z280_dsize;
22934832Speter/* new: si3_t225.c */
23034832Speterextern unsigned char si3_t225_download[];
23134832Speterextern unsigned short si3_t225_downloadaddr;
23234832Speterextern int si3_t225_dsize;
23334832Speterextern unsigned char si3_t225_bootstrap[];
23434832Speterextern unsigned short si3_t225_bootloadaddr;
23534832Speterextern int si3_t225_bsize;
23610015Speter
23733395Speter
23810044Speterstruct si_softc {
23910044Speter	int 		sc_type;	/* adapter type */
24010044Speter	char 		*sc_typename;	/* adapter type string */
24110044Speter
24210044Speter	struct si_port	*sc_ports;	/* port structures for this card */
24310044Speter
24410044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
24510044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
24610044Speter	int		sc_nport;	/* # ports on this card */
24710044Speter	int		sc_irq;		/* copy of attach irq */
24834832Speter#if NEISA > 0
24910044Speter	int		sc_eisa_iobase;	/* EISA io port address */
25034832Speter	int		sc_eisa_irq;	/* EISA irq number */
25134832Speter#endif
25212675Sjulian#ifdef	DEVFS
25312675Sjulian	struct {
25434735Speter		void	*ttya;
25512826Speter		void	*cuaa;
25612675Sjulian		void	*ttyl;
25734735Speter		void	*cual;
25812675Sjulian		void	*ttyi;
25934735Speter		void	*cuai;
26012675Sjulian	} devfs_token[32]; /* what is the max per card? */
26113165Speter	void	*control_token;
26212675Sjulian#endif
26310044Speter};
26412724Sphkstatic struct si_softc si_softc[NSI];		/* up to 4 elements */
26510044Speter
26612174Speter#ifndef B2000	/* not standard, but the hardware knows it. */
26710015Speter# define B2000 2000
26810015Speter#endif
26910015Speterstatic struct speedtab bdrates[] = {
27010015Speter	B75,	CLK75,		/* 0x0 */
27110015Speter	B110,	CLK110,		/* 0x1 */
27210015Speter	B150,	CLK150,		/* 0x3 */
27310015Speter	B300,	CLK300,		/* 0x4 */
27410015Speter	B600,	CLK600,		/* 0x5 */
27510015Speter	B1200,	CLK1200,	/* 0x6 */
27610015Speter	B2000,	CLK2000,	/* 0x7 */
27710015Speter	B2400,	CLK2400,	/* 0x8 */
27810015Speter	B4800,	CLK4800,	/* 0x9 */
27910015Speter	B9600,	CLK9600,	/* 0xb */
28010015Speter	B19200,	CLK19200,	/* 0xc */
28110015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
28210015Speter	B57600, CLK57600,	/* 0xd */
28310015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
28410015Speter	-1,	-1
28510015Speter};
28610015Speter
28710015Speter
28810015Speter/* populated with approx character/sec rates - translated at card
28910015Speter * initialisation time to chars per tick of the clock */
29010015Speterstatic int done_chartimes = 0;
29110015Speterstatic struct speedtab chartimes[] = {
29210015Speter	B75,	8,
29310015Speter	B110,	11,
29410015Speter	B150,	15,
29510015Speter	B300,	30,
29610015Speter	B600,	60,
29710015Speter	B1200,	120,
29810015Speter	B2000,	200,
29910015Speter	B2400,	240,
30010015Speter	B4800,	480,
30110015Speter	B9600,	960,
30210015Speter	B19200,	1920,
30310015Speter	B38400, 3840,
30410015Speter	B57600, 5760,
30510015Speter	B115200, 11520,
30610015Speter	-1,	-1
30710015Speter};
30810015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
30910015Speter
31010015Speter#ifdef POLL
31115683Speterstatic int si_pollrate;			/* in addition to irq */
31217547Speterstatic int si_realpoll;			/* poll HW on timer */
31315639Speter
31416403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, "");
31517547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, "");
31615639Speter
31710015Speterstatic int init_finished = 0;
31810015Speterstatic void si_poll __P((void *));
31910015Speter#endif
32010015Speter
32110015Speter/*
32210015Speter * Array of adapter types and the corresponding RAM size. The order of
32310015Speter * entries here MUST match the ordinal of the adapter type.
32410015Speter */
32510015Speterstatic char *si_type[] = {
32610015Speter	"EMPTY",
32710015Speter	"SIHOST",
32834832Speter	"SIMCA",		/* FreeBSD does not support Microchannel */
32910015Speter	"SIHOST2",
33010015Speter	"SIEISA",
33133395Speter	"SIPCI",
33233395Speter	"SXPCI",
33333395Speter	"SXISA",
33410015Speter};
33510015Speter
33633395Speter#if NPCI > 0
33733395Speter
33842546Seivindstatic const char *
33933395Spetersipciprobe(configid, deviceid)
34033395Speterpcici_t configid;
34133395Speterpcidi_t deviceid;
34233395Speter{
34333395Speter	switch (deviceid)
34433395Speter	{
34533395Speter		case 0x400011cb:
34633395Speter			return("Specialix SI/XIO PCI host card");
34733395Speter			break;
34833395Speter		case 0x200011cb:
34933395Speter			if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb)
35033395Speter				return("Specialix SX PCI host card");
35133395Speter			else
35233395Speter				return NULL;
35333395Speter			break;
35433395Speter		default:
35533395Speter			return NULL;
35633395Speter	}
35733395Speter	/*NOTREACHED*/
35833395Speter}
35933395Speter
36033395Spetervoid
36133395Spetersipciattach(configid, unit)
36233395Speterpcici_t configid;
36333395Speterint unit;
36433395Speter{
36533395Speter	struct isa_device id;
36633395Speter	vm_offset_t vaddr,paddr;
36733395Speter	u_long mapval = 0;	/* shut up gcc, should not be needed */
36833395Speter
36933395Speter	switch ( pci_conf_read(configid, 0) >> 16 )
37033395Speter	{
37133395Speter		case 0x4000:
37233395Speter			si_softc[unit].sc_type = SIPCI;
37333395Speter			mapval = SIPCIBADR;
37434832Speter			break;
37533395Speter		case 0x2000:
37633395Speter			si_softc[unit].sc_type = SIJETPCI;
37733395Speter			mapval = SIJETBADR;
37834832Speter			break;
37933395Speter	}
38033395Speter	if (!pci_map_mem(configid, mapval, &vaddr, &paddr))
38133395Speter	{
38233395Speter		printf("si%d: couldn't map memory\n", unit);
38333395Speter	}
38433395Speter
38533395Speter	/*
38633395Speter	 * We're cheating here a little bit. The argument to an ISA
38733395Speter	 * interrupt routine is the unit number. The argument to a
38833395Speter	 * PCI interrupt handler is a void *, but we're simply going
38933395Speter	 * to be lazy and hand it the unit number.
39033395Speter	 */
39134735Speter	if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) {
39233395Speter		printf("si%d: couldn't map interrupt\n", unit);
39333395Speter	}
39433395Speter	si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type];
39533395Speter
39633395Speter	/*
39733395Speter	 * More cheating: We're going to dummy up a struct isa_device
39833395Speter	 * and call the other attach routine. We don't really have to
39933395Speter	 * fill in very much of the structure, since we filled in a
40033395Speter	 * little of the soft state already.
40133395Speter	 */
40234735Speter	id.id_unit = unit;
40334735Speter	id.id_maddr = (caddr_t) vaddr;
40433395Speter	siattach(&id);
40533395Speter}
40633395Speter
40733395Speter#endif
40833395Speter
40934832Speter#if NEISA > 0
41034832Speter
41134832Speterstatic const char *si_eisa_match __P((eisa_id_t id));
41234832Speter
41334832Speterstatic const char *
41434832Spetersi_eisa_match(id)
41534832Speter	eisa_id_t id;
41634832Speter{
41734832Speter	if (id == SIEISADEVID)
41834832Speter		return ("Specialix SI/XIO EISA host card");
41934832Speter	return (NULL);
42034832Speter}
42134832Speter
42234832Speterstatic int
42334832Spetersi_eisa_probe(void)
42434832Speter{
42534832Speter	struct eisa_device *ed = NULL;
42634832Speter	int count, irq;
42734832Speter
42834832Speter	for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++)
42934832Speter	{
43034832Speter		u_long port,maddr;
43134832Speter
43234832Speter		port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE;
43334832Speter		eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE);
43434832Speter		maddr = (inb(port+1) << 24) | (inb(port) << 16);
43534832Speter		irq  = ((inb(port+2) >> 4) & 0xf);
43634832Speter		eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE);
43734832Speter		eisa_add_intr(ed, irq);
43834832Speter		eisa_registerdev(ed, &si_eisa_driver);
43934832Speter		count++;
44034832Speter	}
44134832Speter	return count;
44234832Speter}
44334832Speter
44434832Speterstatic int
44534832Spetersi_eisa_attach(ed)
44634832Speter	struct eisa_device *ed;
44734832Speter{
44834832Speter	struct isa_device id;
44934832Speter	resvaddr_t *maddr,*iospace;
45034832Speter	u_int irq;
45134832Speter	struct si_softc *sc;
45234832Speter
45334832Speter	sc = &si_softc[ed->unit];
45434832Speter
45534832Speter	sc->sc_type = SIEISA;
45634832Speter	sc->sc_typename = si_type[sc->sc_type];
45734832Speter
45834832Speter	if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) {
45938487Sbde		printf("si%lu: no iospace??\n", ed->unit);
46034832Speter		return -1;
46134832Speter	}
46234832Speter	sc->sc_eisa_iobase = iospace->addr;
46334832Speter
46434832Speter	irq  = ((inb(iospace->addr + 2) >> 4) & 0xf);
46534832Speter	sc->sc_eisa_irq = irq;
46634832Speter
46734832Speter	if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) {
46838487Sbde		printf("si%lu: where am I??\n", ed->unit);
46934832Speter		return -1;
47034832Speter	}
47134832Speter	eisa_reg_start(ed);
47234832Speter	if (eisa_reg_iospace(ed, iospace)) {
47338487Sbde		printf("si%lu: failed to register iospace %p\n",
47438487Sbde			ed->unit, (void *)iospace);
47534832Speter		return -1;
47634832Speter	}
47734832Speter	if (eisa_reg_mspace(ed, maddr)) {
47838487Sbde		printf("si%lu: failed to register memspace %p\n",
47938487Sbde			ed->unit, (void *)maddr);
48034832Speter		return -1;
48134832Speter	}
48234832Speter	/*
48334832Speter	 * We're cheating here a little bit. The argument to an ISA
48434832Speter	 * interrupt routine is the unit number. The argument to a
48534832Speter	 * EISA interrupt handler is a void *, but we're simply going
48634832Speter	 * to be lazy and hand it the unit number.
48734832Speter	 */
48834832Speter	if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr,
48938353Sbde		(void *)(intptr_t)(ed->unit), &tty_imask, 1)) {
49038487Sbde		printf("si%lu: failed to register interrupt %d\n",
49134832Speter			ed->unit, irq);
49234832Speter		return -1;
49334832Speter	}
49434832Speter	eisa_reg_end(ed);
49534832Speter	if (eisa_enable_intr(ed, irq)) {
49634832Speter		return -1;
49734832Speter	}
49834832Speter
49934832Speter	/*
50034832Speter	 * More cheating: We're going to dummy up a struct isa_device
50134832Speter	 * and call the other attach routine. We don't really have to
50234832Speter	 * fill in very much of the structure, since we filled in a
50334832Speter	 * little of the soft state already.
50434832Speter	 */
50534832Speter	id.id_unit = ed->unit;
50634832Speter	id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE);
50734832Speter	return (siattach(&id));
50834832Speter}
50934832Speter
51034832Speter#endif
51134832Speter
51234832Speter
51310015Speter/* Look for a valid board at the given mem addr */
51412724Sphkstatic int
51510015Spetersiprobe(id)
51610015Speter	struct isa_device *id;
51710015Speter{
51810015Speter	struct si_softc *sc;
51910015Speter	int type;
52010015Speter	u_int i, ramsize;
52110015Speter	volatile BYTE was, *ux;
52210015Speter	volatile unsigned char *maddr;
52310015Speter	unsigned char *paddr;
52410015Speter
52517547Speter	si_pollrate = POLLHZ;		/* default 10 per second */
52617547Speter#ifdef REALPOLL
52717547Speter	si_realpoll = 1;		/* scan always */
52817547Speter#endif
52910015Speter	maddr = id->id_maddr;		/* virtual address... */
53010015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
53110015Speter
53212496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
53312496Speter		id->id_unit, id->id_maddr, paddr));
53410015Speter
53510015Speter	/*
53610015Speter	 * this is a lie, but it's easier than trying to handle caching
53710015Speter	 * and ram conflicts in the >1M and <16M region.
53810015Speter	 */
53910015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
54010015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
54138353Sbde		printf("si%d: iomem (%p) out of range\n",
54238353Sbde			id->id_unit, (void *)paddr);
54310015Speter		return(0);
54410015Speter	}
54510015Speter
54610015Speter	if (id->id_unit >= NSI) {
54710015Speter		/* THIS IS IMPOSSIBLE */
54810015Speter		return(0);
54910015Speter	}
55010015Speter
55110015Speter	if (((u_int)paddr & 0x7fff) != 0) {
55210015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
55310015Speter			"si%d: iomem (%x) not on 32k boundary\n",
55410015Speter			id->id_unit, paddr));
55510015Speter		return(0);
55610015Speter	}
55710015Speter
55834735Speter	if (si_softc[id->id_unit].sc_typename) {
55934832Speter		/* EISA or PCI has taken this unit, choose another */
56034735Speter		for (i=0; i < NSI; i++) {
56134735Speter			if (si_softc[i].sc_typename == NULL) {
56234735Speter				id->id_unit = i;
56334735Speter				break;
56434735Speter			}
56534735Speter		}
56634735Speter		if (i >= NSI) {
56734735Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
56834735Speter				"si%d: cannot realloc unit\n", id->id_unit));
56934735Speter			return (0);
57034735Speter		}
57134735Speter	}
57234735Speter
57310015Speter	for (i=0; i < NSI; i++) {
57434735Speter		sc = &si_softc[i];
57510015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
57610015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
57710015Speter				"si%d: iomem (%x) already configured to si%d\n",
57810015Speter				id->id_unit, sc->sc_paddr, i));
57910015Speter			return(0);
58010015Speter		}
58110015Speter	}
58210015Speter
58310015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
58410015Speter	*maddr = 0x17;
58510015Speter	if (*maddr != 0x17) {
58610015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
58710015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
58810015Speter			id->id_unit, paddr));
58910015Speterfail:
59010015Speter		return(0);
59110015Speter	}
59210015Speter	/*
59333395Speter	 * Let's look first for a JET ISA card, since that's pretty easy
59434832Speter	 *
59534832Speter	 * All jet hosts are supposed to have this string in the IDROM,
59634832Speter	 * but it's not worth checking on self-IDing busses like PCI.
59733395Speter	 */
59834832Speter	{
59934832Speter		unsigned char *jet_chk_str = "JET HOST BY KEV#";
60034832Speter
60134832Speter		for (i = 0; i < strlen(jet_chk_str); i++)
60234832Speter			if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i))
60334832Speter				goto try_mk2;
60434832Speter	}
60533395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
60633395Speter		"si%d: JET first check - 0x%x\n",
60733395Speter		id->id_unit, (*(maddr+SIJETIDBASE))));
60833395Speter	if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff))
60933395Speter		goto try_mk2;
61033395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
61133395Speter		"si%d: JET second check - 0x%x\n",
61233395Speter		id->id_unit, (*(maddr+SIJETIDBASE+2))));
61333395Speter	if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8))
61433395Speter		goto try_mk2;
61533395Speter	/* It must be a Jet ISA or RIO card */
61633395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
61733395Speter		"si%d: JET id check - 0x%x\n",
61833395Speter		id->id_unit, (*(maddr+SIUNIQID))));
61933395Speter	if ((*(maddr+SIUNIQID) & 0xf0) !=0x20)
62033395Speter		goto try_mk2;
62133395Speter	/* It must be a Jet ISA SI/XIO card */
62233395Speter	*(maddr + SIJETCONFIG) = 0;
62333395Speter	type = SIJETISA;
62433395Speter	ramsize = SIJET_RAMSIZE;
62533395Speter	goto got_card;
62633395Speter	/*
62710015Speter	 * OK, now to see if whatever responded is really an SI card.
62833395Speter	 * Try for a MK II next (SIHOST2)
62910015Speter	 */
63033395Spetertry_mk2:
63134832Speter	for (i = SIPLSIG; i < SIPLSIG + 8; i++)
63210015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
63310015Speter			goto try_mk1;
63410015Speter
63510015Speter	/* It must be an SIHOST2 */
63610015Speter	*(maddr + SIPLRESET) = 0;
63710015Speter	*(maddr + SIPLIRQCLR) = 0;
63810015Speter	*(maddr + SIPLIRQSET) = 0x10;
63910015Speter	type = SIHOST2;
64010015Speter	ramsize = SIHOST2_RAMSIZE;
64110015Speter	goto got_card;
64210015Speter
64310015Speter	/*
64410015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
64510015Speter	 */
64610015Spetertry_mk1:
64710015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
64810015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
64910015Speter	*(maddr+SIRAM) = 0x17;
65010015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
65110015Speter		goto fail;
65210015Speter	*(maddr+0x7ff8) = 0x17;
65310015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
65410015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
65510015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
65610015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
65710015Speter		goto fail;
65810015Speter	}
65910015Speter
66034832Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXX */
66110015Speter	type = SIHOST;
66210015Speter	ramsize = SIHOST_RAMSIZE;
66310015Speter
66410015Spetergot_card:
66512496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
66612496Speter		id->id_unit, type));
66710015Speter	/* Try the acid test */
66818515Speter	ux = maddr + SIRAM;
66934832Speter	for (i = 0; i < ramsize; i++, ux++)
67010015Speter		*ux = (BYTE)(i&0xff);
67118515Speter	ux = maddr + SIRAM;
67234832Speter	for (i = 0; i < ramsize; i++, ux++) {
67310015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
67410015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
67512174Speter				"si%d: match fail at phys 0x%x, was %x should be %x\n",
67634832Speter				id->id_unit, paddr + i, was, i&0xff));
67710015Speter			goto fail;
67810015Speter		}
67910015Speter	}
68010015Speter
68110015Speter	/* clear out the RAM */
68218515Speter	ux = maddr + SIRAM;
68334832Speter	for (i = 0; i < ramsize; i++)
68410015Speter		*ux++ = 0;
68518515Speter	ux = maddr + SIRAM;
68634832Speter	for (i = 0; i < ramsize; i++) {
68710015Speter		if ((was = *ux++) != 0) {
68810015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
68912174Speter				"si%d: clear fail at phys 0x%x, was %x\n",
69034832Speter				id->id_unit, paddr + i, was));
69110015Speter			goto fail;
69210015Speter		}
69310015Speter	}
69410015Speter
69510015Speter	/*
69610015Speter	 * Success, we've found a valid board, now fill in
69710015Speter	 * the adapter structure.
69810015Speter	 */
69910015Speter	switch (type) {
70010015Speter	case SIHOST2:
70134832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
70210015Speterbad_irq:
70310015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
70410015Speter				"si%d: bad IRQ value - %d\n",
70510015Speter				id->id_unit, id->id_irq));
70610015Speter			return(0);
70710015Speter		}
70810015Speter		id->id_msize = SIHOST2_MEMSIZE;
70910015Speter		break;
71010015Speter	case SIHOST:
71134832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
71210015Speter			goto bad_irq;
71310015Speter		}
71410015Speter		id->id_msize = SIHOST_MEMSIZE;
71510015Speter		break;
71633395Speter	case SIJETISA:
71734832Speter		if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) {
71833395Speter			goto bad_irq;
71933395Speter		}
72034832Speter		id->id_msize = SIJETISA_MEMSIZE;
72133395Speter		break;
72234832Speter	case SIMCA:		/* MCA */
72310015Speter	default:
72410015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
72510015Speter		return(0);
72610015Speter	}
72734832Speter	id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */
72810015Speter	si_softc[id->id_unit].sc_type = type;
72910015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
73010015Speter	return(-1);	/* -1 == found */
73110015Speter}
73210015Speter
73310015Speter/*
73434832Speter * We have to make an 8 bit version of bcopy, since some cards can't
73534832Speter * deal with 32 bit I/O
73634832Speter */
73734832Speter#if 1
73834832Speterstatic void
73934832Spetersi_bcopy(const void *src, void *dst, size_t len)
74034832Speter{
74134832Speter	while (len--)
74234832Speter		*(((u_char *)dst)++) = *(((u_char *)src)++);
74334832Speter}
74434832Speter#else
74534832Speter#define si_bcopy bcopy
74634832Speter#endif
74734832Speter
74834832Speter
74934832Speter/*
75010015Speter * Attach the device.  Initialize the card.
75134832Speter *
75234832Speter * This routine also gets called by the EISA and PCI attach routines.
75334832Speter * It presumes that the softstate for the unit has had had its type field
75434832Speter * and the EISA specific stuff filled in, as well as the kernel virtual
75534832Speter * base address and the unit number of the isa_device struct.
75610015Speter */
75712724Sphkstatic int
75810015Spetersiattach(id)
75910015Speter	struct isa_device *id;
76010015Speter{
76110015Speter	int unit = id->id_unit;
76210015Speter	struct si_softc *sc = &si_softc[unit];
76310015Speter	struct si_port *pp;
76410015Speter	volatile struct si_channel *ccbp;
76510015Speter	volatile struct si_reg *regp;
76610015Speter	volatile caddr_t maddr;
76710015Speter	struct si_module *modp;
76810015Speter	struct tty *tp;
76910015Speter	struct speedtab *spt;
77010015Speter	int nmodule, nport, x, y;
77112174Speter	int uart_type;
77210015Speter
77312496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
77410015Speter
77510015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
77610015Speter	sc->sc_maddr = id->id_maddr;
77710015Speter	sc->sc_irq = id->id_irq;
77810015Speter
77933395Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit,
78033395Speter		sc->sc_typename, sc->sc_paddr, sc->sc_maddr));
78133395Speter
78210015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
78310015Speter
78410015Speter	maddr = sc->sc_maddr;
78510015Speter
78634832Speter	/* Stop the CPU first so it won't stomp around while we load */
78734832Speter
78834832Speter	switch (sc->sc_type) {
78934832Speter#if NEISA > 0
79034832Speter		case SIEISA:
79134832Speter			outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4);
79234832Speter		break;
79334832Speter#endif
79434832Speter#if NPCI > 0
79534832Speter		case SIPCI:
79634832Speter			*(maddr+SIPCIRESET) = 0;
79734832Speter		break;
79834832Speter		case SIJETPCI: /* fall through to JET ISA */
79934832Speter#endif
80034832Speter		case SIJETISA:
80134832Speter			*(maddr+SIJETCONFIG) = 0;
80234832Speter		break;
80334832Speter		case SIHOST2:
80434832Speter			*(maddr+SIPLRESET) = 0;
80534832Speter		break;
80634832Speter		case SIHOST:
80734832Speter			*(maddr+SIRESET) = 0;
80834832Speter		break;
80934832Speter		default: /* this should never happen */
81034832Speter			printf("si%d: unsupported configuration\n", unit);
81134832Speter			return 0;
81234832Speter		break;
81334832Speter	}
81434832Speter
81534832Speter	/* OK, now lets download the download code */
81634832Speter
81736956Ssteve	if (SI_ISJET(sc->sc_type)) {
81833395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n",
81934832Speter			id->id_unit, si3_t225_dsize));
82034832Speter		si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr,
82134832Speter			si3_t225_dsize);
82234832Speter		DPRINT((0, DBG_DOWNLOAD,
82334832Speter			"si%d: jet_bootstrap: nbytes %d -> %x\n",
82434832Speter			id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr));
82534832Speter		si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr,
82634832Speter			si3_t225_bsize);
82734832Speter	} else {
82833395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
82934832Speter			id->id_unit, si2_z280_dsize));
83034832Speter		si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr,
83134832Speter			si2_z280_dsize);
83233395Speter	}
83310015Speter
83434832Speter	/* Now start the CPU */
83534832Speter
83610015Speter	switch (sc->sc_type) {
83734832Speter#if NEISA > 0
83810015Speter	case SIEISA:
83934832Speter		/* modify the download code to tell it that it's on an EISA */
84034832Speter		*(maddr + 0x42) = 1;
84134832Speter		outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4);
84234832Speter		(void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */
84310015Speter		break;
84434832Speter#endif
84533395Speter	case SIPCI:
84634832Speter		/* modify the download code to tell it that it's on a PCI */
84733395Speter		*(maddr+0x42) = 1;
84833395Speter		*(maddr+SIPCIRESET) = 1;
84933395Speter		*(maddr+SIPCIINTCL) = 0;
85033395Speter		break;
85133395Speter	case SIJETPCI:
85233395Speter		*(maddr+SIJETRESET) = 0;
85333395Speter		*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN;
85433395Speter		break;
85533395Speter	case SIJETISA:
85633395Speter		*(maddr+SIJETRESET) = 0;
85734832Speter		switch (sc->sc_irq) {
85834832Speter		case IRQ9:
85934832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90;
86034832Speter			break;
86134832Speter		case IRQ10:
86234832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0;
86334832Speter			break;
86434832Speter		case IRQ11:
86534832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0;
86634832Speter			break;
86734832Speter		case IRQ12:
86834832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0;
86934832Speter			break;
87034832Speter		case IRQ15:
87134832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0;
87234832Speter			break;
87334832Speter		}
87433395Speter		break;
87510015Speter	case SIHOST:
87610015Speter		*(maddr+SIRESET_CL) = 0;
87710015Speter		*(maddr+SIINTCL_CL) = 0;
87810015Speter		break;
87910015Speter	case SIHOST2:
88010015Speter		*(maddr+SIPLRESET) = 0x10;
88110015Speter		switch (sc->sc_irq) {
88210015Speter		case IRQ11:
88310015Speter			*(maddr+SIPLIRQ11) = 0x10;
88410015Speter			break;
88510015Speter		case IRQ12:
88610015Speter			*(maddr+SIPLIRQ12) = 0x10;
88710015Speter			break;
88810015Speter		case IRQ15:
88910015Speter			*(maddr+SIPLIRQ15) = 0x10;
89010015Speter			break;
89110015Speter		}
89210015Speter		*(maddr+SIPLIRQCLR) = 0x10;
89310015Speter		break;
89434832Speter	default: /* this should _REALLY_ never happen */
89534832Speter		printf("si%d: Uh, it was supported a second ago...\n", unit);
89634832Speter		return 0;
89710015Speter	}
89810015Speter
89910015Speter	DELAY(1000000);			/* wait around for a second */
90010015Speter
90110015Speter	regp = (struct si_reg *)maddr;
90210015Speter	y = 0;
90310015Speter					/* wait max of 5 sec for init OK */
90410015Speter	while (regp->initstat == 0 && y++ < 10) {
90510015Speter		DELAY(500000);
90610015Speter	}
90710015Speter	switch (regp->initstat) {
90810015Speter	case 0:
90910015Speter		printf("si%d: startup timeout - aborting\n", unit);
91012174Speter		sc->sc_type = SIEMPTY;
91110015Speter		return 0;
91210015Speter	case 1:
91336956Ssteve		if (SI_ISJET(sc->sc_type)) {
91434832Speter			/* set throttle to 100 times per second */
91534832Speter			regp->int_count = JET_INT_COUNT;
91634832Speter			/* rx_intr_count is a NOP in Jet */
91734832Speter		} else {
91834832Speter			/* set throttle to 125 times per second */
91934832Speter			regp->int_count = INT_COUNT;
92034832Speter			/* rx intr max of 25 times per second */
92134832Speter			regp->rx_int_count = RXINT_COUNT;
92234832Speter		}
92310015Speter		regp->int_pending = 0;		/* no intr pending */
92410015Speter		regp->int_scounter = 0;	/* reset counter */
92510015Speter		break;
92610015Speter	case 0xff:
92710015Speter		/*
92810015Speter		 * No modules found, so give up on this one.
92910015Speter		 */
93010015Speter		printf("si%d: %s - no ports found\n", unit,
93110015Speter			si_type[sc->sc_type]);
93210015Speter		return 0;
93310015Speter	default:
93434832Speter		printf("si%d: download code version error - initstat %x\n",
93510015Speter			unit, regp->initstat);
93610015Speter		return 0;
93710015Speter	}
93810015Speter
93910015Speter	/*
94010015Speter	 * First time around the ports just count them in order
94110015Speter	 * to allocate some memory.
94210015Speter	 */
94310015Speter	nport = 0;
94410015Speter	modp = (struct si_module *)(maddr + 0x80);
94510015Speter	for (;;) {
94612174Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
94734832Speter		switch (modp->sm_type) {
94834832Speter		case TA4:
94910015Speter			DPRINT((0, DBG_DOWNLOAD,
95034832Speter				"si%d: Found old TA4 module, 4 ports\n",
95134832Speter				unit));
95234832Speter			x = 4;
95310015Speter			break;
95434832Speter		case TA8:
95534832Speter			DPRINT((0, DBG_DOWNLOAD,
95634832Speter				"si%d: Found old TA8 module, 8 ports\n",
95734832Speter				unit));
95834832Speter			x = 8;
95934832Speter			break;
96034832Speter		case TA4_ASIC:
96134832Speter			DPRINT((0, DBG_DOWNLOAD,
96234832Speter				"si%d: Found ASIC TA4 module, 4 ports\n",
96334832Speter				unit));
96434832Speter			x = 4;
96534832Speter			break;
96634832Speter		case TA8_ASIC:
96734832Speter			DPRINT((0, DBG_DOWNLOAD,
96834832Speter				"si%d: Found ASIC TA8 module, 8 ports\n",
96934832Speter				unit));
97034832Speter			x = 8;
97134832Speter			break;
97234832Speter		case MTA:
97334832Speter			DPRINT((0, DBG_DOWNLOAD,
97434832Speter				"si%d: Found CD1400 module, 8 ports\n",
97534832Speter				unit));
97634832Speter			x = 8;
97734832Speter			break;
97834832Speter		case SXDC:
97934832Speter			DPRINT((0, DBG_DOWNLOAD,
98034832Speter				"si%d: Found SXDC module, 8 ports\n",
98134832Speter				unit));
98234832Speter			x = 8;
98334832Speter			break;
98410015Speter		default:
98510015Speter			printf("si%d: unknown module type %d\n",
98610015Speter				unit, modp->sm_type);
98734832Speter			goto try_next;
98810015Speter		}
98934832Speter
99034832Speter		/* this was limited in firmware and is also a driver issue */
99134832Speter		if ((nport + x) > SI_MAXPORTPERCARD) {
99234832Speter			printf("si%d: extra ports ignored\n", unit);
99334832Speter			goto try_next;
99434832Speter		}
99534832Speter
99634832Speter		nport += x;
99734832Speter		si_Nports += x;
99834832Speter		si_Nmodules++;
99934832Speter
100034832Spetertry_next:
100110015Speter		if (modp->sm_next == 0)
100210015Speter			break;
100310015Speter		modp = (struct si_module *)
100410015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
100510015Speter	}
100610015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
100710015Speter		M_DEVBUF, M_NOWAIT);
100810015Speter	if (sc->sc_ports == 0) {
100910015Spetermem_fail:
101010015Speter		printf("si%d: fail to malloc memory for port structs\n",
101110015Speter			unit);
101210015Speter		return 0;
101310015Speter	}
101410015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
101510015Speter	sc->sc_nport = nport;
101610015Speter
101710015Speter	/*
101810015Speter	 * allocate tty structures for ports
101910015Speter	 */
102010015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
102110015Speter	if (tp == 0)
102210015Speter		goto mem_fail;
102310015Speter	bzero(tp, sizeof(*tp) * nport);
102410962Speter	si_tty = tp;
102510015Speter
102610015Speter	/*
102710015Speter	 * Scan round the ports again, this time initialising.
102810015Speter	 */
102910015Speter	pp = sc->sc_ports;
103010015Speter	nmodule = 0;
103110015Speter	modp = (struct si_module *)(maddr + 0x80);
103234832Speter	uart_type = 1000;	/* arbitary, > uchar_max */
103310015Speter	for (;;) {
103434832Speter		switch (modp->sm_type) {
103534832Speter		case TA4:
103634832Speter			nport = 4;
103710015Speter			break;
103834832Speter		case TA8:
103934832Speter			nport = 8;
104034832Speter			break;
104134832Speter		case TA4_ASIC:
104234832Speter			nport = 4;
104334832Speter			break;
104434832Speter		case TA8_ASIC:
104534832Speter			nport = 8;
104634832Speter			break;
104734832Speter		case MTA:
104834832Speter			nport = 8;
104934832Speter			break;
105034832Speter		case SXDC:
105134832Speter			nport = 8;
105234832Speter			break;
105310015Speter		default:
105434832Speter			goto try_next2;
105510015Speter		}
105634832Speter		nmodule++;
105734832Speter		ccbp = (struct si_channel *)((char *)modp + 0x100);
105834832Speter		if (uart_type == 1000)
105934832Speter			uart_type = ccbp->type;
106034832Speter		else if (uart_type != ccbp->type)
106134832Speter			printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n",
106234832Speter			    unit, nmodule,
106334832Speter			    ccbp->type, si_modulename(sc->sc_type, ccbp->type),
106434832Speter			    uart_type, si_modulename(sc->sc_type, uart_type));
106534832Speter
106634832Speter		for (x = 0; x < nport; x++, pp++, ccbp++) {
106734832Speter			pp->sp_ccb = ccbp;	/* save the address */
106834832Speter			pp->sp_tty = tp++;
106934832Speter			pp->sp_pend = IDLE_CLOSE;
107034832Speter			pp->sp_state = 0;	/* internal flag */
107134832Speter			pp->sp_dtr_wait = 3 * hz;
107234832Speter			pp->sp_iin.c_iflag = TTYDEF_IFLAG;
107334832Speter			pp->sp_iin.c_oflag = TTYDEF_OFLAG;
107434832Speter			pp->sp_iin.c_cflag = TTYDEF_CFLAG;
107534832Speter			pp->sp_iin.c_lflag = TTYDEF_LFLAG;
107634832Speter			termioschars(&pp->sp_iin);
107734832Speter			pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
107834832Speter				TTYDEF_SPEED;;
107934832Speter			pp->sp_iout = pp->sp_iin;
108034832Speter		}
108134832Spetertry_next2:
108210015Speter		if (modp->sm_next == 0) {
108334832Speter			printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n",
108410015Speter				unit,
108510015Speter				sc->sc_typename,
108610015Speter				sc->sc_nport,
108712174Speter				nmodule,
108834832Speter				uart_type,
108934832Speter				si_modulename(sc->sc_type, uart_type));
109010015Speter			break;
109110015Speter		}
109210015Speter		modp = (struct si_module *)
109310015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
109410015Speter	}
109510015Speter	if (done_chartimes == 0) {
109610015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
109710015Speter			if ((spt->sp_code /= hz) == 0)
109810015Speter				spt->sp_code = 1;
109910015Speter		}
110010015Speter		done_chartimes = 1;
110110015Speter	}
110212502Sjulian
110312675Sjulian#ifdef DEVFS
110412675Sjulian/*	path	name	devsw		minor	type   uid gid perm*/
110513169Speter	for ( x = 0; x < sc->sc_nport; x++ ) {
110634735Speter		/* sync with the manuals that start at 1 */
110734735Speter		y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT);
110834735Speter		sc->devfs_token[x].ttya = devfs_add_devswf(
110913630Sphk			&si_cdevsw, x,
111013630Sphk			DV_CHR, 0, 0, 0600, "ttyA%02d", y);
111113630Sphk		sc->devfs_token[x].cuaa = devfs_add_devswf(
111234735Speter			&si_cdevsw, x + 0x00080,
111313630Sphk			DV_CHR, 0, 0, 0600, "cuaA%02d", y);
111413630Sphk		sc->devfs_token[x].ttyi = devfs_add_devswf(
111513630Sphk			&si_cdevsw, x + 0x10000,
111613630Sphk			DV_CHR, 0, 0, 0600, "ttyiA%02d", y);
111734735Speter		sc->devfs_token[x].cuai = devfs_add_devswf(
111834735Speter			&si_cdevsw, x + 0x10080,
111934735Speter			DV_CHR, 0, 0, 0600, "cuaiA%02d", y);
112013630Sphk		sc->devfs_token[x].ttyl = devfs_add_devswf(
112113630Sphk			&si_cdevsw, x + 0x20000,
112213630Sphk			DV_CHR, 0, 0, 0600, "ttylA%02d", y);
112334735Speter		sc->devfs_token[x].cual = devfs_add_devswf(
112434735Speter			&si_cdevsw, x + 0x20080,
112534735Speter			DV_CHR, 0, 0, 0600, "cualA%02d", y);
112612675Sjulian	}
112714873Sscrappy	sc->control_token =
112814873Sscrappy		devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600,
112914873Sscrappy				 "si_control");
113012675Sjulian#endif
113110015Speter	return (1);
113210015Speter}
113310015Speter
113412675Sjulianstatic	int
113510015Spetersiopen(dev, flag, mode, p)
113610015Speter	dev_t dev;
113710015Speter	int flag, mode;
113810015Speter	struct proc *p;
113910015Speter{
114010015Speter	int oldspl, error;
114110015Speter	int card, port;
114210015Speter	register struct si_softc *sc;
114310015Speter	register struct tty *tp;
114410015Speter	volatile struct si_channel *ccbp;
114510015Speter	struct si_port *pp;
114610015Speter	int mynor = minor(dev);
114710015Speter
114810015Speter	/* quickly let in /dev/si_control */
114910015Speter	if (IS_CONTROLDEV(mynor)) {
115046112Sphk		if ((error = suser(p)))
115110015Speter			return(error);
115210015Speter		return(0);
115310015Speter	}
115410015Speter
115510015Speter	card = SI_CARD(mynor);
115610015Speter	if (card >= NSI)
115710015Speter		return (ENXIO);
115810015Speter	sc = &si_softc[card];
115910015Speter
116012174Speter	if (sc->sc_type == SIEMPTY) {
116112174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
116210015Speter			card, sc->sc_typename));
116310015Speter		return(ENXIO);
116410015Speter	}
116510015Speter
116610015Speter	port = SI_PORT(mynor);
116710015Speter	if (port >= sc->sc_nport) {
116812174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
116910015Speter			card, sc->sc_nport));
117010015Speter		return(ENXIO);
117110015Speter	}
117210015Speter
117310015Speter#ifdef	POLL
117410015Speter	/*
117510015Speter	 * We've now got a device, so start the poller.
117610015Speter	 */
117710015Speter	if (init_finished == 0) {
117815639Speter		timeout(si_poll, (caddr_t)0L, si_pollrate);
117910015Speter		init_finished = 1;
118010015Speter	}
118110015Speter#endif
118210015Speter
118310015Speter	/* initial/lock device */
118410015Speter	if (IS_STATE(mynor)) {
118510015Speter		return(0);
118610015Speter	}
118710015Speter
118810015Speter	pp = sc->sc_ports + port;
118910015Speter	tp = pp->sp_tty;			/* the "real" tty */
119010015Speter	ccbp = pp->sp_ccb;			/* Find control block */
119150016Snsayer	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%s,%x,%x,%x)\n",
119250016Snsayer		devtoname(dev), flag, mode, p));
119310015Speter
119410015Speter	oldspl = spltty();			/* Keep others out */
119510015Speter	error = 0;
119610015Speter
119710015Speteropen_top:
119810015Speter	while (pp->sp_state & SS_DTR_OFF) {
119910015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
120010015Speter		if (error != 0)
120110015Speter			goto out;
120210015Speter	}
120310015Speter
120410015Speter	if (tp->t_state & TS_ISOPEN) {
120510015Speter		/*
120610015Speter		 * The device is open, so everything has been initialised.
120710015Speter		 * handle conflicts.
120810015Speter		 */
120910015Speter		if (IS_CALLOUT(mynor)) {
121010015Speter			if (!pp->sp_active_out) {
121110015Speter				error = EBUSY;
121210015Speter				goto out;
121310015Speter			}
121410015Speter		} else {
121510015Speter			if (pp->sp_active_out) {
121610015Speter				if (flag & O_NONBLOCK) {
121710015Speter					error = EBUSY;
121810015Speter					goto out;
121910015Speter				}
122010015Speter				error = tsleep(&pp->sp_active_out,
122110015Speter						TTIPRI|PCATCH, "sibi", 0);
122210015Speter				if (error != 0)
122310015Speter					goto out;
122410015Speter				goto open_top;
122510015Speter			}
122610015Speter		}
122743425Sphk		if (tp->t_state & TS_XCLUDE &&
122846112Sphk		    suser(p)) {
122910015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
123010015Speter				"already open and EXCLUSIVE set\n"));
123110015Speter			error = EBUSY;
123210015Speter			goto out;
123310015Speter		}
123410015Speter	} else {
123510015Speter		/*
123610015Speter		 * The device isn't open, so there are no conflicts.
123710015Speter		 * Initialize it. Avoid sleep... :-)
123810015Speter		 */
123910015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
124010015Speter		tp->t_oproc = si_start;
124110015Speter		tp->t_param = siparam;
124210015Speter		tp->t_dev = dev;
124310015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
124410015Speter				? pp->sp_iout : pp->sp_iin;
124510015Speter
124610015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
124710015Speter
124810015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
124910015Speter
125010015Speter		error = siparam(tp, &tp->t_termios);
125110015Speter
125210015Speter		--pp->sp_wopeners;
125310015Speter		if (error != 0)
125410015Speter			goto out;
125510015Speter		/* XXX: we should goto_top if siparam slept */
125610015Speter
125710015Speter		/* set initial DCD state */
125810015Speter		pp->sp_last_hi_ip = ccbp->hi_ip;
125910015Speter		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
126010015Speter			(*linesw[tp->t_line].l_modem)(tp, 1);
126110015Speter		}
126210015Speter	}
126310015Speter
126410015Speter	/* whoops! we beat the close! */
126510015Speter	if (pp->sp_state & SS_CLOSING) {
126610015Speter		/* try and stop it from proceeding to bash the hardware */
126710015Speter		pp->sp_state &= ~SS_CLOSING;
126810015Speter	}
126910015Speter
127010015Speter	/*
127110015Speter	 * Wait for DCD if necessary
127210015Speter	 */
127310015Speter	if (!(tp->t_state & TS_CARR_ON)
127410015Speter	    && !IS_CALLOUT(mynor)
127510015Speter	    && !(tp->t_cflag & CLOCAL)
127610015Speter	    && !(flag & O_NONBLOCK)) {
127710015Speter		++pp->sp_wopeners;
127810015Speter		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
127910015Speter		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
128010015Speter		--pp->sp_wopeners;
128110015Speter		if (error != 0)
128210015Speter			goto out;
128310015Speter		goto open_top;
128410015Speter	}
128510015Speter
128610015Speter	error = (*linesw[tp->t_line].l_open)(dev, tp);
128710015Speter	si_disc_optim(tp, &tp->t_termios, pp);
128810015Speter	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
128910015Speter		pp->sp_active_out = TRUE;
129010015Speter
129110015Speter	pp->sp_state |= SS_OPEN;	/* made it! */
129210015Speter
129310015Speterout:
129410015Speter	splx(oldspl);
129510015Speter
129610015Speter	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
129710015Speter
129810015Speter	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
129910015Speter		sihardclose(pp);
130010015Speter
130110015Speter	return(error);
130210015Speter}
130310015Speter
130412675Sjulianstatic	int
130510015Spetersiclose(dev, flag, mode, p)
130610015Speter	dev_t dev;
130710015Speter	int flag, mode;
130810015Speter	struct proc *p;
130910015Speter{
131010015Speter	register struct si_port *pp;
131110015Speter	register struct tty *tp;
131210015Speter	int oldspl;
131310015Speter	int error = 0;
131410015Speter	int mynor = minor(dev);
131510015Speter
131610015Speter	if (IS_SPECIAL(mynor))
131710015Speter		return(0);
131810015Speter
131910015Speter	oldspl = spltty();
132010015Speter
132110015Speter	pp = MINOR2PP(mynor);
132210015Speter	tp = pp->sp_tty;
132310015Speter
132450016Snsayer	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%s,%x,%x,%x) sp_state:%x\n",
132550016Snsayer		devtoname(dev), flag, mode, p, pp->sp_state));
132610015Speter
132710015Speter	/* did we sleep and loose a race? */
132810015Speter	if (pp->sp_state & SS_CLOSING) {
132910015Speter		/* error = ESOMETING? */
133010015Speter		goto out;
133110015Speter	}
133210015Speter
133310015Speter	/* begin race detection.. */
133410015Speter	pp->sp_state |= SS_CLOSING;
133510015Speter
133610015Speter	si_write_enable(pp, 0);		/* block writes for ttywait() */
133710015Speter
133810015Speter	/* THIS MAY SLEEP IN TTYWAIT!!! */
133910015Speter	(*linesw[tp->t_line].l_close)(tp, flag);
134010015Speter
134110015Speter	si_write_enable(pp, 1);
134210015Speter
134310015Speter	/* did we sleep and somebody started another open? */
134410015Speter	if (!(pp->sp_state & SS_CLOSING)) {
134510015Speter		/* error = ESOMETING? */
134610015Speter		goto out;
134710015Speter	}
134810015Speter	/* ok. we are now still on the right track.. nuke the hardware */
134910015Speter
135010015Speter	if (pp->sp_state & SS_LSTART) {
135129677Sgibbs		untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
135210015Speter		pp->sp_state &= ~SS_LSTART;
135310015Speter	}
135410015Speter
135510015Speter	sistop(tp, FREAD | FWRITE);
135610015Speter
135710015Speter	sihardclose(pp);
135810015Speter	ttyclose(tp);
135910015Speter	pp->sp_state &= ~SS_OPEN;
136010015Speter
136110015Speterout:
136210015Speter	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
136310015Speter	splx(oldspl);
136410015Speter	return(error);
136510015Speter}
136610015Speter
136710015Speterstatic void
136810015Spetersihardclose(pp)
136910015Speter	struct si_port *pp;
137010015Speter{
137110015Speter	int oldspl;
137210015Speter	struct tty *tp;
137310015Speter	volatile struct si_channel *ccbp;
137410015Speter
137510015Speter	oldspl = spltty();
137610015Speter
137710015Speter	tp = pp->sp_tty;
137810015Speter	ccbp = pp->sp_ccb;			/* Find control block */
137910015Speter	if (tp->t_cflag & HUPCL
138018515Speter	    || (!pp->sp_active_out
138134832Speter		&& !(ccbp->hi_ip & IP_DCD)
138234832Speter		&& !(pp->sp_iin.c_cflag && CLOCAL))
138310015Speter	    || !(tp->t_state & TS_ISOPEN)) {
138410015Speter
138510015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
138610015Speter		(void) si_command(pp, FCLOSE, SI_NOWAIT);
138710015Speter
138810015Speter		if (pp->sp_dtr_wait != 0) {
138910015Speter			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
139010015Speter			pp->sp_state |= SS_DTR_OFF;
139110015Speter		}
139210015Speter
139310015Speter	}
139410015Speter	pp->sp_active_out = FALSE;
139510015Speter	wakeup((caddr_t)&pp->sp_active_out);
139610015Speter	wakeup(TSA_CARR_ON(tp));
139710015Speter
139810015Speter	splx(oldspl);
139910015Speter}
140010015Speter
140110015Speter
140210015Speter/*
140310015Speter * called at splsoftclock()...
140410015Speter */
140510015Speterstatic void
140610015Spetersidtrwakeup(chan)
140710015Speter	void *chan;
140810015Speter{
140910015Speter	struct si_port *pp;
141010015Speter	int oldspl;
141110015Speter
141210015Speter	oldspl = spltty();
141310015Speter
141410015Speter	pp = (struct si_port *)chan;
141510015Speter	pp->sp_state &= ~SS_DTR_OFF;
141610015Speter	wakeup(&pp->sp_dtr_wait);
141710015Speter
141810015Speter	splx(oldspl);
141910015Speter}
142010015Speter
142110015Speter/*
142210015Speter * User level stuff - read and write
142310015Speter */
142412675Sjulianstatic	int
142510015Spetersiread(dev, uio, flag)
142610015Speter	register dev_t dev;
142710015Speter	struct uio *uio;
142810015Speter	int flag;
142910015Speter{
143010015Speter	register struct tty *tp;
143110015Speter	int mynor = minor(dev);
143210015Speter
143310015Speter	if (IS_SPECIAL(mynor)) {
143410015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
143510015Speter		return(ENODEV);
143610015Speter	}
143710015Speter	tp = MINOR2TP(mynor);
143810015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
143950016Snsayer		"siread(%s,%x,%x)\n", devtoname(dev), uio, flag));
144010015Speter	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
144110015Speter}
144210015Speter
144310015Speter
144412675Sjulianstatic	int
144510015Spetersiwrite(dev, uio, flag)
144610015Speter	dev_t dev;
144710015Speter	struct uio *uio;
144810015Speter	int flag;
144910015Speter{
145010015Speter	register struct si_port *pp;
145110015Speter	register struct tty *tp;
145210015Speter	int error = 0;
145310015Speter	int mynor = minor(dev);
145410015Speter	int oldspl;
145510015Speter
145610015Speter	if (IS_SPECIAL(mynor)) {
145710015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
145810015Speter		return(ENODEV);
145910015Speter	}
146010015Speter	pp = MINOR2PP(mynor);
146110015Speter	tp = pp->sp_tty;
146250016Snsayer	DPRINT((pp, DBG_WRITE, "siwrite(%s,%x,%x)\n", devtoname(dev), uio, flag));
146310015Speter
146410015Speter	oldspl = spltty();
146510015Speter	/*
146610015Speter	 * If writes are currently blocked, wait on the "real" tty
146710015Speter	 */
146810015Speter	while (pp->sp_state & SS_BLOCKWRITE) {
146910015Speter		pp->sp_state |= SS_WAITWRITE;
147010015Speter		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
147118515Speter		if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
147218515Speter				     "siwrite", tp->t_timeout))) {
147317291Speter			if (error == EWOULDBLOCK)
147417290Speter				error = EIO;
147510015Speter			goto out;
147617290Speter		}
147710015Speter	}
147810015Speter
147910015Speter	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
148010015Speterout:
148110015Speter	splx(oldspl);
148210015Speter	return (error);
148310015Speter}
148410015Speter
148510015Speter
148612675Sjulianstatic	struct tty *
148710015Spetersidevtotty(dev_t dev)
148810015Speter{
148910015Speter	struct si_port *pp;
149010015Speter	int mynor = minor(dev);
149110015Speter	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
149210015Speter
149310015Speter	if (IS_SPECIAL(mynor))
149410015Speter		return(NULL);
149510015Speter	if (SI_PORT(mynor) >= sc->sc_nport)
149610015Speter		return(NULL);
149710015Speter	pp = MINOR2PP(mynor);
149810015Speter	return (pp->sp_tty);
149910015Speter}
150010015Speter
150112675Sjulianstatic	int
150210015Spetersiioctl(dev, cmd, data, flag, p)
150310015Speter	dev_t dev;
150436735Sdfr	u_long cmd;
150510015Speter	caddr_t data;
150610015Speter	int flag;
150710015Speter	struct proc *p;
150810015Speter{
150910015Speter	struct si_port *pp;
151010015Speter	register struct tty *tp;
151110015Speter	int error;
151210015Speter	int mynor = minor(dev);
151310015Speter	int oldspl;
151410015Speter	int blocked = 0;
151510015Speter#if defined(COMPAT_43)
151638351Sbde	u_long oldcmd;
151710015Speter	struct termios term;
151810015Speter#endif
151910015Speter
152010015Speter	if (IS_SI_IOCTL(cmd))
152110015Speter		return(si_Sioctl(dev, cmd, data, flag, p));
152210015Speter
152310015Speter	pp = MINOR2PP(mynor);
152410015Speter	tp = pp->sp_tty;
152510015Speter
152650016Snsayer	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%s,%lx,%x,%x)\n",
152750016Snsayer		devtoname(dev), cmd, data, flag));
152810015Speter	if (IS_STATE(mynor)) {
152910015Speter		struct termios *ct;
153010015Speter
153110015Speter		switch (mynor & SI_STATE_MASK) {
153210015Speter		case SI_INIT_STATE_MASK:
153310015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
153410015Speter			break;
153510015Speter		case SI_LOCK_STATE_MASK:
153616839Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin;
153710015Speter			break;
153810015Speter		default:
153910015Speter			return (ENODEV);
154010015Speter		}
154110015Speter		switch (cmd) {
154210015Speter		case TIOCSETA:
154346112Sphk			error = suser(p);
154410015Speter			if (error != 0)
154510015Speter				return (error);
154610015Speter			*ct = *(struct termios *)data;
154710015Speter			return (0);
154810015Speter		case TIOCGETA:
154910015Speter			*(struct termios *)data = *ct;
155010015Speter			return (0);
155110015Speter		case TIOCGETD:
155210015Speter			*(int *)data = TTYDISC;
155310015Speter			return (0);
155410015Speter		case TIOCGWINSZ:
155510015Speter			bzero(data, sizeof(struct winsize));
155610015Speter			return (0);
155710015Speter		default:
155810015Speter			return (ENOTTY);
155910015Speter		}
156010015Speter	}
156110015Speter	/*
156210015Speter	 * Do the old-style ioctl compat routines...
156310015Speter	 */
156410015Speter#if defined(COMPAT_43)
156510015Speter	term = tp->t_termios;
156610015Speter	oldcmd = cmd;
156710015Speter	error = ttsetcompat(tp, &cmd, data, &term);
156810015Speter	if (error != 0)
156910015Speter		return (error);
157010015Speter	if (cmd != oldcmd)
157110015Speter		data = (caddr_t)&term;
157210015Speter#endif
157310015Speter	/*
157410015Speter	 * Do the initial / lock state business
157510015Speter	 */
157610015Speter	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
157710015Speter		int     cc;
157810015Speter		struct termios *dt = (struct termios *)data;
157910015Speter		struct termios *lt = mynor & SI_CALLOUT_MASK
158010015Speter				     ? &pp->sp_lout : &pp->sp_lin;
158110015Speter
158210015Speter		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
158310015Speter			| (dt->c_iflag & ~lt->c_iflag);
158410015Speter		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
158510015Speter			| (dt->c_oflag & ~lt->c_oflag);
158610015Speter		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
158710015Speter			| (dt->c_cflag & ~lt->c_cflag);
158810015Speter		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
158910015Speter			| (dt->c_lflag & ~lt->c_lflag);
159010015Speter		for (cc = 0; cc < NCCS; ++cc)
159110015Speter			if (lt->c_cc[cc] != 0)
159210015Speter				dt->c_cc[cc] = tp->t_cc[cc];
159310015Speter		if (lt->c_ispeed != 0)
159410015Speter			dt->c_ispeed = tp->t_ispeed;
159510015Speter		if (lt->c_ospeed != 0)
159610015Speter			dt->c_ospeed = tp->t_ospeed;
159710015Speter	}
159810015Speter
159910015Speter	/*
160010015Speter	 * Block user-level writes to give the ttywait()
160110015Speter	 * a chance to completely drain for commands
160210015Speter	 * that require the port to be in a quiescent state.
160310015Speter	 */
160410015Speter	switch (cmd) {
160534832Speter	case TIOCSETAW:
160634832Speter	case TIOCSETAF:
160717396Speter	case TIOCDRAIN:
160817396Speter#ifdef COMPAT_43
160917396Speter	case TIOCSETP:
161017396Speter#endif
161110015Speter		blocked++;	/* block writes for ttywait() and siparam() */
161210015Speter		si_write_enable(pp, 0);
161310015Speter	}
161410015Speter
161510015Speter	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
161631577Sbde	if (error != ENOIOCTL)
161710015Speter		goto out;
161810015Speter
161910015Speter	oldspl = spltty();
162010015Speter
162110015Speter	error = ttioctl(tp, cmd, data, flag);
162210015Speter	si_disc_optim(tp, &tp->t_termios, pp);
162331577Sbde	if (error != ENOIOCTL)
162410015Speter		goto outspl;
162510015Speter
162610015Speter	switch (cmd) {
162710015Speter	case TIOCSBRK:
162816575Speter		si_command(pp, SBREAK, SI_WAIT);
162910015Speter		break;
163010015Speter	case TIOCCBRK:
163116575Speter		si_command(pp, EBREAK, SI_WAIT);
163210015Speter		break;
163310015Speter	case TIOCSDTR:
163410015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
163510015Speter		break;
163610015Speter	case TIOCCDTR:
163710015Speter		(void) si_modem(pp, SET, 0);
163810015Speter		break;
163910015Speter	case TIOCMSET:
164010015Speter		(void) si_modem(pp, SET, *(int *)data);
164110015Speter		break;
164210015Speter	case TIOCMBIS:
164310015Speter		(void) si_modem(pp, BIS, *(int *)data);
164410015Speter		break;
164510015Speter	case TIOCMBIC:
164610015Speter		(void) si_modem(pp, BIC, *(int *)data);
164710015Speter		break;
164810015Speter	case TIOCMGET:
164910015Speter		*(int *)data = si_modem(pp, GET, 0);
165010015Speter		break;
165110015Speter	case TIOCMSDTRWAIT:
165210015Speter		/* must be root since the wait applies to following logins */
165346112Sphk		error = suser(p);
165410015Speter		if (error != 0) {
165510015Speter			goto outspl;
165610015Speter		}
165710015Speter		pp->sp_dtr_wait = *(int *)data * hz / 100;
165810015Speter		break;
165910015Speter	case TIOCMGDTRWAIT:
166010015Speter		*(int *)data = pp->sp_dtr_wait * 100 / hz;
166110015Speter		break;
166210015Speter
166310015Speter	default:
166410015Speter		error = ENOTTY;
166510015Speter	}
166610015Speter	error = 0;
166710015Speteroutspl:
166810015Speter	splx(oldspl);
166910015Speterout:
167010015Speter	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
167110015Speter	if (blocked)
167210015Speter		si_write_enable(pp, 1);
167310015Speter	return(error);
167410015Speter}
167510015Speter
167610015Speter/*
167710015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device
167810015Speter */
167910015Speterstatic int
168038351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
168110015Speter{
168210015Speter	struct si_softc *xsc;
168310015Speter	register struct si_port *xpp;
168410015Speter	volatile struct si_reg *regp;
168510015Speter	struct si_tcsi *dp;
168610044Speter	struct si_pstat *sps;
168711872Sphk	int *ip, error = 0;
168810015Speter	int oldspl;
168910015Speter	int card, port;
169010015Speter	int mynor = minor(dev);
169110015Speter
169250016Snsayer	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n",
169350016Snsayer		devtoname(dev), cmd, data, flag));
169410015Speter
169510044Speter#if 1
169610044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
169710044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
169810044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
169910044Speter#endif
170010044Speter
170110015Speter	if (!IS_CONTROLDEV(mynor)) {
170210015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
170310015Speter		return(ENODEV);
170410015Speter	}
170510015Speter
170610015Speter	oldspl = spltty();	/* better safe than sorry */
170710015Speter
170810015Speter	ip = (int *)data;
170910015Speter
171046112Sphk#define SUCHECK if ((error = suser(p))) goto out
171110015Speter
171210015Speter	switch (cmd) {
171310015Speter	case TCSIPORTS:
171410015Speter		*ip = si_Nports;
171510015Speter		goto out;
171610015Speter	case TCSIMODULES:
171710015Speter		*ip = si_Nmodules;
171810015Speter		goto out;
171910015Speter	case TCSISDBG_ALL:
172010015Speter		SUCHECK;
172110015Speter		si_debug = *ip;
172210015Speter		goto out;
172310015Speter	case TCSIGDBG_ALL:
172410015Speter		*ip = si_debug;
172510015Speter		goto out;
172610015Speter	default:
172710015Speter		/*
172810015Speter		 * Check that a controller for this port exists
172910015Speter		 */
173010044Speter
173110044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
173210044Speter
173310015Speter		dp = (struct si_tcsi *)data;
173410044Speter		sps = (struct si_pstat *)data;
173510015Speter		card = dp->tc_card;
173610015Speter		xsc = &si_softc[card];	/* check.. */
173712174Speter		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
173810015Speter			error = ENOENT;
173910015Speter			goto out;
174010015Speter		}
174110015Speter		/*
174210015Speter		 * And check that a port exists
174310015Speter		 */
174410015Speter		port = dp->tc_port;
174510015Speter		if (port < 0 || port >= xsc->sc_nport) {
174610015Speter			error = ENOENT;
174710015Speter			goto out;
174810015Speter		}
174910015Speter		xpp = xsc->sc_ports + port;
175010015Speter		regp = (struct si_reg *)xsc->sc_maddr;
175110015Speter	}
175210015Speter
175310015Speter	switch (cmd) {
175410015Speter	case TCSIDEBUG:
175510015Speter#ifdef	SI_DEBUG
175610015Speter		SUCHECK;
175710015Speter		if (xpp->sp_debug)
175810015Speter			xpp->sp_debug = 0;
175910015Speter		else {
176010015Speter			xpp->sp_debug = DBG_ALL;
176110015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
176210015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
176310015Speter		}
176410015Speter		break;
176510015Speter#else
176610015Speter		error = ENODEV;
176710015Speter		goto out;
176810015Speter#endif
176910015Speter	case TCSISDBG_LEVEL:
177010015Speter	case TCSIGDBG_LEVEL:
177110015Speter#ifdef	SI_DEBUG
177210015Speter		if (cmd == TCSIGDBG_LEVEL) {
177310015Speter			dp->tc_dbglvl = xpp->sp_debug;
177410015Speter		} else {
177510015Speter			SUCHECK;
177610015Speter			xpp->sp_debug = dp->tc_dbglvl;
177710015Speter		}
177810015Speter		break;
177910015Speter#else
178010015Speter		error = ENODEV;
178110015Speter		goto out;
178210015Speter#endif
178310015Speter	case TCSIGRXIT:
178410015Speter		dp->tc_int = regp->rx_int_count;
178510015Speter		break;
178610015Speter	case TCSIRXIT:
178710015Speter		SUCHECK;
178810015Speter		regp->rx_int_count = dp->tc_int;
178910015Speter		break;
179010015Speter	case TCSIGIT:
179110015Speter		dp->tc_int = regp->int_count;
179210015Speter		break;
179310015Speter	case TCSIIT:
179410015Speter		SUCHECK;
179510015Speter		regp->int_count = dp->tc_int;
179610015Speter		break;
179710044Speter	case TCSISTATE:
179810044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
179910015Speter		break;
180010044Speter	/* these next three use a different structure */
180110044Speter	case TCSI_PORT:
180210015Speter		SUCHECK;
180334832Speter		si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport));
180410015Speter		break;
180510044Speter	case TCSI_CCB:
180610044Speter		SUCHECK;
180734832Speter		si_bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb));
180810015Speter		break;
180910044Speter	case TCSI_TTY:
181010044Speter		SUCHECK;
181134832Speter		si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty));
181210015Speter		break;
181310015Speter	default:
181410015Speter		error = EINVAL;
181510015Speter		goto out;
181610015Speter	}
181710015Speterout:
181810015Speter	splx(oldspl);
181910015Speter	return(error);		/* success */
182010015Speter}
182110015Speter
182210015Speter/*
182310015Speter *	siparam()	: Configure line params
182410015Speter *	called at spltty();
182510015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
182610015Speter *	caller must arrange this if it's important..
182710015Speter */
182812724Sphkstatic int
182910015Spetersiparam(tp, t)
183010015Speter	register struct tty *tp;
183110015Speter	register struct termios *t;
183210015Speter{
183310015Speter	register struct si_port *pp = TP2PP(tp);
183410015Speter	volatile struct si_channel *ccbp;
183510015Speter	int oldspl, cflag, iflag, oflag, lflag;
183610015Speter	int error = 0;		/* shutup gcc */
183710015Speter	int ispeed = 0;		/* shutup gcc */
183810015Speter	int ospeed = 0;		/* shutup gcc */
183910161Speter	BYTE val;
184010015Speter
184110015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
184210015Speter	cflag = t->c_cflag;
184310015Speter	iflag = t->c_iflag;
184410015Speter	oflag = t->c_oflag;
184510015Speter	lflag = t->c_lflag;
184610044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
184710044Speter		oflag, cflag, iflag, lflag));
184810015Speter
184934832Speter	/* XXX - if Jet host and SXDC module, use extended baud rates */
185010015Speter
185110015Speter	/* if not hung up.. */
185210015Speter	if (t->c_ospeed != 0) {
185310015Speter		/* translate baud rate to firmware values */
185410015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
185510015Speter		ispeed = t->c_ispeed ?
185610015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
185710015Speter
185810015Speter		/* enforce legit baud rate */
185910015Speter		if (ospeed < 0 || ispeed < 0)
186010015Speter			return (EINVAL);
186110015Speter	}
186210015Speter
186310015Speter	oldspl = spltty();
186410015Speter
186510015Speter	ccbp = pp->sp_ccb;
186610015Speter
186710161Speter	/* ========== set hi_break ========== */
186810161Speter	val = 0;
186910161Speter	if (iflag & IGNBRK)		/* Breaks */
187010161Speter		val |= BR_IGN;
187110161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
187210161Speter		val |= BR_INT;
187310161Speter	if (iflag & PARMRK)		/* Parity mark? */
187410161Speter		val |= BR_PARMRK;
187510161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
187610161Speter		val |= BR_PARIGN;
187710161Speter	ccbp->hi_break = val;
187810161Speter
187910161Speter	/* ========== set hi_csr ========== */
188010015Speter	/* if not hung up.. */
188110015Speter	if (t->c_ospeed != 0) {
188210015Speter		/* Set I/O speeds */
188310161Speter		 val = (ispeed << 4) | ospeed;
188410015Speter	}
188510161Speter	ccbp->hi_csr = val;
188610015Speter
188710161Speter	/* ========== set hi_mr2 ========== */
188810161Speter	val = 0;
188910015Speter	if (cflag & CSTOPB)				/* Stop bits */
189010161Speter		val |= MR2_2_STOP;
189110015Speter	else
189210161Speter		val |= MR2_1_STOP;
189310161Speter	/*
189410161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
189510161Speter	 * a DCE, hence the reverse sense of RTS and CTS
189610161Speter	 */
189710161Speter	/* Output Flow - RTS must be raised before data can be sent */
189810161Speter	if (cflag & CCTS_OFLOW)
189910161Speter		val |= MR2_RTSCONT;
190010161Speter
190116575Speter	ccbp->hi_mr2 = val;
190210161Speter
190310161Speter	/* ========== set hi_mr1 ========== */
190410161Speter	val = 0;
190510015Speter	if (!(cflag & PARENB))				/* Parity */
190610161Speter		val |= MR1_NONE;
190710015Speter	else
190810161Speter		val |= MR1_WITH;
190910015Speter	if (cflag & PARODD)
191010161Speter		val |= MR1_ODD;
191110015Speter
191210015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
191310161Speter		val |= MR1_8_BITS;
191410015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
191510161Speter		val |= MR1_7_BITS;
191610015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
191710161Speter		val |= MR1_6_BITS;
191810015Speter	} else {					/* Must be 5 */
191910161Speter		val |= MR1_5_BITS;
192010015Speter	}
192110161Speter	/*
192210161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
192310161Speter	 * a DCE, hence the reverse sense of RTS and CTS
192410161Speter	 */
192510161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
192610161Speter	if (cflag & CRTS_IFLOW)
192710161Speter		val |= MR1_CTSCONT;
192810015Speter
192910161Speter	ccbp->hi_mr1 = val;
193010161Speter
193110161Speter	/* ========== set hi_mask ========== */
193210161Speter	val = 0xff;
193310161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
193410161Speter		val &= 0xFF;
193510161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
193610161Speter		val &= 0x7F;
193710161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
193810161Speter		val &= 0x3F;
193910161Speter	} else {					/* Must be 5 */
194010161Speter		val &= 0x1F;
194110161Speter	}
194210015Speter	if (iflag & ISTRIP)
194310161Speter		val &= 0x7F;
194410015Speter
194510161Speter	ccbp->hi_mask = val;
194610161Speter
194710161Speter	/* ========== set hi_prtcl ========== */
194810161Speter	val = 0;
194910015Speter				/* Monitor DCD etc. if a modem */
195010015Speter	if (!(cflag & CLOCAL))
195110161Speter		val |= SP_DCEN;
195210161Speter	if (iflag & IXANY)
195310161Speter		val |= SP_TANY;
195410161Speter	if (iflag & IXON)
195510161Speter		val |= SP_TXEN;
195610161Speter	if (iflag & IXOFF)
195710161Speter		val |= SP_RXEN;
195810161Speter	if (iflag & INPCK)
195910161Speter		val |= SP_PAEN;
196010015Speter
196110161Speter	ccbp->hi_prtcl = val;
196210161Speter
196310161Speter
196410161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
196510161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
196610015Speter	ccbp->hi_txon = t->c_cc[VSTART];
196710015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
196810015Speter
196910015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
197010015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
197110015Speter
197210161Speter	/* ========== send settings to the card ========== */
197310015Speter	/* potential sleep here */
197410015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
197510015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
197610015Speter	else
197710015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
197810015Speter
197910161Speter	/* ========== set DTR etc ========== */
198010015Speter	/* Hangup if ospeed == 0 */
198110015Speter	if (t->c_ospeed == 0) {
198210015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
198310015Speter	} else {
198410015Speter		/*
198510015Speter		 * If the previous speed was 0, may need to re-enable
198634832Speter		 * the modem signals
198734832Speter		 */
198810015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
198910015Speter	}
199010015Speter
199110044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
199210044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
199310015Speter
199410015Speter	splx(oldspl);
199510015Speter	return(error);
199610015Speter}
199710015Speter
199810015Speter/*
199910015Speter * Enable or Disable the writes to this channel...
200010015Speter * "state" ->  enabled = 1; disabled = 0;
200110015Speter */
200210015Speterstatic void
200310015Spetersi_write_enable(pp, state)
200410015Speter	register struct si_port *pp;
200510015Speter	int state;
200610015Speter{
200710015Speter	int oldspl;
200810015Speter
200910015Speter	oldspl = spltty();
201010015Speter
201110015Speter	if (state) {
201210015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
201310015Speter		if (pp->sp_state & SS_WAITWRITE) {
201410015Speter			pp->sp_state &= ~SS_WAITWRITE;
201510015Speter			/* thunder away! */
201610015Speter			wakeup((caddr_t)pp);
201710015Speter		}
201810015Speter	} else {
201910015Speter		pp->sp_state |= SS_BLOCKWRITE;
202010015Speter	}
202110015Speter
202210015Speter	splx(oldspl);
202310015Speter}
202410015Speter
202510015Speter/*
202610015Speter * Set/Get state of modem control lines.
202710015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
202810015Speter *	TIOCM_DTR	DSR
202910015Speter *	TIOCM_RTS	CTS
203010015Speter */
203110015Speterstatic int
203210015Spetersi_modem(pp, cmd, bits)
203310015Speter	struct si_port *pp;
203410015Speter	enum si_mctl cmd;
203510015Speter	int bits;
203610015Speter{
203710015Speter	volatile struct si_channel *ccbp;
203810015Speter	int x;
203910015Speter
204010015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
204110015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
204210015Speter	switch (cmd) {
204310015Speter	case GET:
204410015Speter		x = ccbp->hi_ip;
204510015Speter		bits = TIOCM_LE;
204610015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
204710015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
204810015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
204910015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
205010015Speter		return(bits);
205110015Speter	case SET:
205210015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
205310015Speter		/* fall through */
205410015Speter	case BIS:
205510015Speter		x = 0;
205610015Speter		if (bits & TIOCM_DTR)
205710015Speter			x |= OP_DSR;
205810015Speter		if (bits & TIOCM_RTS)
205910015Speter			x |= OP_CTS;
206010015Speter		ccbp->hi_op |= x;
206110015Speter		break;
206210015Speter	case BIC:
206310015Speter		if (bits & TIOCM_DTR)
206410015Speter			ccbp->hi_op &= ~OP_DSR;
206510015Speter		if (bits & TIOCM_RTS)
206610015Speter			ccbp->hi_op &= ~OP_CTS;
206710015Speter	}
206810015Speter	return 0;
206910015Speter}
207010015Speter
207110015Speter/*
207210015Speter * Handle change of modem state
207310015Speter */
207410015Speterstatic void
207510015Spetersi_modem_state(pp, tp, hi_ip)
207610015Speter	register struct si_port *pp;
207710015Speter	register struct tty *tp;
207810015Speter	register int hi_ip;
207910015Speter{
208010015Speter							/* if a modem dev */
208110015Speter	if (hi_ip & IP_DCD) {
208210015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
208310015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
208410015Speter				tp->t_line));
208510015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
208610015Speter		}
208710015Speter	} else {
208810015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
208910015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
209010015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
209110015Speter				(void) si_modem(pp, SET, 0);
209210015Speter		}
209310015Speter	}
209410015Speter	pp->sp_last_hi_ip = hi_ip;
209510015Speter
209610015Speter}
209710015Speter
209810015Speter/*
209910015Speter * Poller to catch missed interrupts.
210012174Speter *
210112496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get
210212496Speter * better response.  We could really use a "periodic" version timeout(). :-)
210310015Speter */
210410015Speter#ifdef POLL
210510708Speterstatic void
210610015Spetersi_poll(void *nothing)
210710015Speter{
210810015Speter	register struct si_softc *sc;
210910015Speter	register int i;
211010015Speter	volatile struct si_reg *regp;
211112174Speter	register struct si_port *pp;
211212174Speter	int lost, oldspl, port;
211310015Speter
211410015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
211511609Speter	oldspl = spltty();
211610015Speter	if (in_intr)
211710015Speter		goto out;
211810015Speter	lost = 0;
211910015Speter	for (i=0; i<NSI; i++) {
212010015Speter		sc = &si_softc[i];
212112174Speter		if (sc->sc_type == SIEMPTY)
212210015Speter			continue;
212310015Speter		regp = (struct si_reg *)sc->sc_maddr;
212434832Speter
212510015Speter		/*
212610015Speter		 * See if there has been a pending interrupt for 2 seconds
212733395Speter		 * or so. The test (int_scounter >= 200) won't correspond
212810015Speter		 * to 2 seconds if int_count gets changed.
212910015Speter		 */
213010015Speter		if (regp->int_pending != 0) {
213110015Speter			if (regp->int_scounter >= 200 &&
213210015Speter			    regp->initstat == 1) {
213312174Speter				printf("si%d: lost intr\n", i);
213410015Speter				lost++;
213510015Speter			}
213610015Speter		} else {
213710015Speter			regp->int_scounter = 0;
213810015Speter		}
213910015Speter
214012174Speter		/*
214112174Speter		 * gripe about no input flow control..
214212174Speter		 */
214312174Speter		pp = sc->sc_ports;
214412174Speter		for (port = 0; port < sc->sc_nport; pp++, port++) {
214512174Speter			if (pp->sp_delta_overflows > 0) {
214612174Speter				printf("si%d: %d tty level buffer overflows\n",
214712174Speter					i, pp->sp_delta_overflows);
214812174Speter				pp->sp_delta_overflows = 0;
214912174Speter			}
215012174Speter		}
215110015Speter	}
215217547Speter	if (lost || si_realpoll)
215334735Speter		si_intr(-1);	/* call intr with fake vector */
215411609Speterout:
215510015Speter	splx(oldspl);
215610015Speter
215715639Speter	timeout(si_poll, (caddr_t)0L, si_pollrate);
215810015Speter}
215910015Speter#endif	/* ifdef POLL */
216010015Speter
216110015Speter/*
216210015Speter * The interrupt handler polls ALL ports on ALL adapters each time
216310015Speter * it is called.
216410015Speter */
216510015Speter
216612496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
216734832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE];	/* output staging area */
216810015Speter
216934735Speterstatic void
217034735Spetersi_intr(int unit)
217110015Speter{
217210015Speter	register struct si_softc *sc;
217310015Speter
217410015Speter	register struct si_port *pp;
217510015Speter	volatile struct si_channel *ccbp;
217610015Speter	register struct tty *tp;
217710015Speter	volatile caddr_t maddr;
217811872Sphk	BYTE op, ip;
217912174Speter	int x, card, port, n, i, isopen;
218010015Speter	volatile BYTE *z;
218110015Speter	BYTE c;
218210015Speter
218334735Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "si_intr(%d)\n", unit));
218411609Speter	if (in_intr) {
218511609Speter		if (unit < 0)	/* should never happen */
218634832Speter			printf("si%d: Warning poll entered during interrupt\n",
218734832Speter				unit);
218834832Speter		else
218934832Speter			printf("si%d: Warning interrupt handler re-entered\n",
219034832Speter				unit);
219110708Speter		return;
219210015Speter	}
219310015Speter	in_intr = 1;
219410015Speter
219510015Speter	/*
219610015Speter	 * When we get an int we poll all the channels and do ALL pending
219710015Speter	 * work, not just the first one we find. This allows all cards to
219810015Speter	 * share the same vector.
219934832Speter	 *
220034832Speter	 * XXX - But if we're sharing the vector with something that's NOT
220134832Speter	 * a SI/XIO/SX card, we may be making more work for ourselves.
220210015Speter	 */
220334832Speter	for (card = 0; card < NSI; card++) {
220410015Speter		sc = &si_softc[card];
220512174Speter		if (sc->sc_type == SIEMPTY)
220610015Speter			continue;
220712174Speter
220812174Speter		/*
220912174Speter		 * First, clear the interrupt
221012174Speter		 */
221110015Speter		switch(sc->sc_type) {
221234832Speter		case SIHOST:
221310015Speter			maddr = sc->sc_maddr;
221410015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
221510015Speter							/* flag nothing pending */
221610015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
221710015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
221810015Speter			break;
221910015Speter		case SIHOST2:
222010015Speter			maddr = sc->sc_maddr;
222110015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
222210015Speter			*(maddr+SIPLIRQCLR) = 0x00;
222310015Speter			*(maddr+SIPLIRQCLR) = 0x10;
222410015Speter			break;
222534832Speter#if NPCI > 0
222633395Speter		case SIPCI:
222733395Speter			maddr = sc->sc_maddr;
222833395Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
222933395Speter			*(maddr+SIPCIINTCL) = 0x0;
223033395Speter			break;
223134832Speter		case SIJETPCI:	/* fall through to JETISA case */
223234832Speter#endif
223333395Speter		case SIJETISA:
223433395Speter			maddr = sc->sc_maddr;
223533395Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
223633395Speter			*(maddr+SIJETINTCL) = 0x0;
223733395Speter			break;
223834832Speter#if NEISA > 0
223910015Speter		case SIEISA:
224010015Speter			maddr = sc->sc_maddr;
224110015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
224234832Speter			(void)inb(sc->sc_eisa_iobase + 3);
224310015Speter			break;
224434832Speter#endif
224510015Speter		case SIEMPTY:
224610015Speter		default:
224710015Speter			continue;
224810015Speter		}
224910015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
225010015Speter
225112174Speter		/*
225212174Speter		 * check each port
225312174Speter		 */
225434832Speter		for (pp = sc->sc_ports, port=0; port < sc->sc_nport;
225534832Speter		     pp++, port++) {
225610015Speter			ccbp = pp->sp_ccb;
225710015Speter			tp = pp->sp_tty;
225810015Speter
225910015Speter			/*
226010015Speter			 * See if a command has completed ?
226110015Speter			 */
226210015Speter			if (ccbp->hi_stat != pp->sp_pend) {
226310015Speter				DPRINT((pp, DBG_INTR,
226434735Speter					"si_intr hi_stat = 0x%x, pend = %d\n",
226510015Speter					ccbp->hi_stat, pp->sp_pend));
226610015Speter				switch(pp->sp_pend) {
226710015Speter				case LOPEN:
226810015Speter				case MPEND:
226910015Speter				case MOPEN:
227010015Speter				case CONFIG:
227116575Speter				case SBREAK:
227216575Speter				case EBREAK:
227310015Speter					pp->sp_pend = ccbp->hi_stat;
227410015Speter						/* sleeping in si_command */
227510015Speter					wakeup(&pp->sp_state);
227610015Speter					break;
227710015Speter				default:
227810015Speter					pp->sp_pend = ccbp->hi_stat;
227910015Speter				}
228034832Speter			}
228110015Speter
228210015Speter			/*
228310015Speter			 * Continue on if it's closed
228410015Speter			 */
228510015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
228610015Speter				continue;
228710015Speter			}
228810015Speter
228910015Speter			/*
229010015Speter			 * Do modem state change if not a local device
229110015Speter			 */
229210015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
229310015Speter
229410015Speter			/*
229534832Speter			 * Check to see if we should 'receive' characters.
229612174Speter			 */
229712174Speter			if (tp->t_state & TS_CONNECTED &&
229812174Speter			    tp->t_state & TS_ISOPEN)
229912174Speter				isopen = 1;
230012174Speter			else
230112174Speter				isopen = 0;
230212174Speter
230312174Speter			/*
230416575Speter			 * Do input break processing
230510015Speter			 */
230610015Speter			if (ccbp->hi_state & ST_BREAK) {
230712174Speter				if (isopen) {
230812174Speter				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
230910015Speter				}
231010015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
231110015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
231210015Speter			}
231310015Speter
231410015Speter			/*
231512174Speter			 * Do RX stuff - if not open then dump any characters.
231612174Speter			 * XXX: This is VERY messy and needs to be cleaned up.
231712174Speter			 *
231812174Speter			 * XXX: can we leave data in the host adapter buffer
231912174Speter			 * when the clists are full?  That may be dangerous
232012174Speter			 * if the user cannot get an interrupt signal through.
232110015Speter			 */
232210015Speter
232312174Speter	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
232412174Speter
232512174Speter			if (!isopen) {
232610015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
232712174Speter				goto end_rx;
232812174Speter			}
232910015Speter
233012174Speter			/*
233115640Speter			 * If the tty input buffers are blocked, stop emptying
233215640Speter			 * the incoming buffers and let the auto flow control
233315640Speter			 * assert..
233415640Speter			 */
233515640Speter			if (tp->t_state & TS_TBLOCK) {
233615640Speter				goto end_rx;
233715640Speter			}
233815640Speter
233915640Speter			/*
234012174Speter			 * Process read characters if not skipped above
234112174Speter			 */
234215640Speter			op = ccbp->hi_rxopos;
234315640Speter			ip = ccbp->hi_rxipos;
234415640Speter			c = ip - op;
234512174Speter			if (c == 0) {
234612174Speter				goto end_rx;
234712174Speter			}
234810015Speter
234912174Speter			n = c & 0xff;
235015640Speter			if (n > 250)
235115640Speter				n = 250;
235212174Speter
235312174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
235410015Speter						n, op, ip));
235510015Speter
235612174Speter			/*
235712174Speter			 * Suck characters out of host card buffer into the
235812174Speter			 * "input staging buffer" - so that we dont leave the
235912174Speter			 * host card in limbo while we're possibly echoing
236012174Speter			 * characters and possibly flushing input inside the
236112174Speter			 * ldisc l_rint() routine.
236212174Speter			 */
236312496Speter			if (n <= SI_BUFFERSIZE - op) {
236410015Speter
236512174Speter				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
236612174Speter				z = ccbp->hi_rxbuf + op;
236734832Speter				si_bcopy((caddr_t)z, si_rxbuf, n);
236810015Speter
236912174Speter				op += n;
237012174Speter			} else {
237112496Speter				x = SI_BUFFERSIZE - op;
237210015Speter
237312174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
237412174Speter				z = ccbp->hi_rxbuf + op;
237534832Speter				si_bcopy((caddr_t)z, si_rxbuf, x);
237610015Speter
237734832Speter				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n",
237834832Speter					n - x));
237912174Speter				z = ccbp->hi_rxbuf;
238034832Speter				si_bcopy((caddr_t)z, si_rxbuf + x, n - x);
238110015Speter
238212174Speter				op += n;
238312174Speter			}
238410015Speter
238512174Speter			/* clear collected characters from buffer */
238612174Speter			ccbp->hi_rxopos = op;
238712174Speter
238812174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
238910015Speter						n, op, ip));
239010015Speter
239112174Speter			/*
239212174Speter			 * at this point...
239312174Speter			 * n = number of chars placed in si_rxbuf
239412174Speter			 */
239510015Speter
239612174Speter			/*
239712174Speter			 * Avoid the grotesquely inefficient lineswitch
239812174Speter			 * routine (ttyinput) in "raw" mode. It usually
239912174Speter			 * takes about 450 instructions (that's without
240012174Speter			 * canonical processing or echo!). slinput is
240112174Speter			 * reasonably fast (usually 40 instructions
240212174Speter			 * plus call overhead).
240312174Speter			 */
240412174Speter			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
240510015Speter
240612174Speter				/* block if the driver supports it */
240712174Speter				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
240812174Speter				    && (tp->t_cflag & CRTS_IFLOW
240912174Speter					|| tp->t_iflag & IXOFF)
241012174Speter				    && !(tp->t_state & TS_TBLOCK))
241112174Speter					ttyblock(tp);
241210015Speter
241312174Speter				tk_nin += n;
241412174Speter				tk_rawcc += n;
241512174Speter				tp->t_rawcc += n;
241612174Speter
241712174Speter				pp->sp_delta_overflows +=
241812174Speter				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
241912174Speter
242012174Speter				ttwakeup(tp);
242112174Speter				if (tp->t_state & TS_TTSTOP
242212174Speter				    && (tp->t_iflag & IXANY
242312174Speter					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
242412174Speter					tp->t_state &= ~TS_TTSTOP;
242512174Speter					tp->t_lflag &= ~FLUSHO;
242612174Speter					si_start(tp);
242712174Speter				}
242812174Speter			} else {
242912174Speter				/*
243012174Speter				 * It'd be nice to not have to go through the
243112174Speter				 * function call overhead for each char here.
243212174Speter				 * It'd be nice to block input it, saving a
243312174Speter				 * loop here and the call/return overhead.
243412174Speter				 */
243512174Speter				for(x = 0; x < n; x++) {
243612174Speter					i = si_rxbuf[x];
243712174Speter					if ((*linesw[tp->t_line].l_rint)(i, tp)
243812174Speter					     == -1) {
243912174Speter						pp->sp_delta_overflows++;
244010015Speter					}
244112174Speter					/*
244212174Speter					 * doesn't seem to be much point doing
244312174Speter					 * this here.. this driver has no
244412174Speter					 * softtty processing! ??
244512174Speter					 */
244612174Speter					if (pp->sp_hotchar && i == pp->sp_hotchar) {
244712174Speter						setsofttty();
244812174Speter					}
244912174Speter				}
245012174Speter			}
245112174Speter			goto more_rx;	/* try for more until RXbuf is empty */
245210015Speter
245312174Speter	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
245410015Speter
245510015Speter			/*
245610015Speter			 * Do TX stuff
245710015Speter			 */
245810015Speter			(*linesw[tp->t_line].l_start)(tp);
245910015Speter
246010015Speter		} /* end of for (all ports on this controller) */
246110015Speter	} /* end of for (all controllers) */
246210015Speter
246311609Speter	in_intr = 0;
246434735Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end si_intr(%d)\n", unit));
246510015Speter}
246610015Speter
246710015Speter/*
246810015Speter * Nudge the transmitter...
246912174Speter *
247012174Speter * XXX: I inherited some funny code here.  It implies the host card only
247112174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does
247212174Speter * not interrupt when it's actually hits empty.  In some cases, we have
247312174Speter * processes waiting for complete drain, and we need to simulate an interrupt
247412174Speter * about when we think the buffer is going to be empty (and retry if not).
247512174Speter * I really am not certain about this...  I *need* the hardware manuals.
247610015Speter */
247710015Speterstatic void
247810015Spetersi_start(tp)
247910015Speter	register struct tty *tp;
248010015Speter{
248110015Speter	struct si_port *pp;
248210015Speter	volatile struct si_channel *ccbp;
248310015Speter	register struct clist *qp;
248410015Speter	BYTE ipos;
248510015Speter	int nchar;
248610015Speter	int oldspl, count, n, amount, buffer_full;
248710015Speter
248810015Speter	oldspl = spltty();
248910015Speter
249010015Speter	qp = &tp->t_outq;
249110015Speter	pp = TP2PP(tp);
249210015Speter
249310015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
249410015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
249510015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
249610015Speter
249710015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
249810015Speter		goto out;
249910015Speter
250010015Speter	buffer_full = 0;
250110015Speter	ccbp = pp->sp_ccb;
250210015Speter
250310015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
250410015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
250510015Speter
250610015Speter	while ((nchar = qp->c_cc) > 0) {
250710015Speter		if ((BYTE)count >= 255) {
250810015Speter			buffer_full++;
250910015Speter			break;
251010015Speter		}
251110015Speter		amount = min(nchar, (255 - (BYTE)count));
251210015Speter		ipos = (unsigned int)ccbp->hi_txipos;
251334832Speter		n = q_to_b(&tp->t_outq, si_txbuf, amount);
251410015Speter		/* will it fit in one lump? */
251534832Speter		if ((SI_BUFFERSIZE - ipos) >= n) {
251634832Speter			si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], n);
251710015Speter		} else {
251834832Speter			si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos],
251934832Speter				SI_BUFFERSIZE - ipos);
252034832Speter			si_bcopy(si_txbuf + (SI_BUFFERSIZE - ipos),
252134832Speter				(char *)&ccbp->hi_txbuf[0],
252234832Speter				n - (SI_BUFFERSIZE - ipos));
252310015Speter		}
252410015Speter		ccbp->hi_txipos += n;
252510015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
252610015Speter	}
252710015Speter
252810015Speter	if (count != 0 && nchar == 0) {
252910015Speter		tp->t_state |= TS_BUSY;
253010015Speter	} else {
253110015Speter		tp->t_state &= ~TS_BUSY;
253210015Speter	}
253310015Speter
253410015Speter	/* wakeup time? */
253510015Speter	ttwwakeup(tp);
253610015Speter
253710015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
253810015Speter		(BYTE)count, nchar, tp->t_state));
253910015Speter
254034735Speter	if (tp->t_state & TS_BUSY)
254110015Speter	{
254210015Speter		int time;
254310015Speter
254434735Speter		time = ttspeedtab(tp->t_ospeed, chartimes);
254534735Speter
254634735Speter		if (time > 0) {
254734735Speter			if (time < nchar)
254834735Speter				time = nchar / time;
254934735Speter			else
255034735Speter				time = 2;
255110015Speter		} else {
255234735Speter			DPRINT((pp, DBG_START,
255334735Speter				"bad char time value! %d\n", time));
255434735Speter			time = hz/10;
255510015Speter		}
255610015Speter
255710015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
255829677Sgibbs			untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
255910015Speter		} else {
256010015Speter			pp->sp_state |= SS_LSTART;
256110015Speter		}
256210015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
256329677Sgibbs		pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time);
256410015Speter	}
256510015Speter
256610015Speterout:
256710015Speter	splx(oldspl);
256810015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
256910015Speter}
257010015Speter
257110015Speter/*
257210015Speter * Note: called at splsoftclock from the timeout code
257310015Speter * This has to deal with two things...  cause wakeups while waiting for
257410015Speter * tty drains on last process exit, and call l_start at about the right
257510015Speter * time for protocols like ppp.
257610015Speter */
257710015Speterstatic void
257825047Sbdesi_lstart(void *arg)
257910015Speter{
258025047Sbde	register struct si_port *pp = arg;
258110015Speter	register struct tty *tp;
258210015Speter	int oldspl;
258310015Speter
258410015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
258510015Speter		pp, pp->sp_state));
258610015Speter
258710015Speter	oldspl = spltty();
258810015Speter
258910015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
259010015Speter		splx(oldspl);
259110015Speter		return;
259210015Speter	}
259310015Speter	pp->sp_state &= ~SS_LSTART;
259410015Speter	pp->sp_state |= SS_INLSTART;
259510015Speter
259610015Speter	tp = pp->sp_tty;
259710015Speter
259810015Speter	/* deal with the process exit case */
259910015Speter	ttwwakeup(tp);
260010015Speter
260112174Speter	/* nudge protocols - eg: ppp */
260210015Speter	(*linesw[tp->t_line].l_start)(tp);
260310015Speter
260410015Speter	pp->sp_state &= ~SS_INLSTART;
260510015Speter	splx(oldspl);
260610015Speter}
260710015Speter
260810015Speter/*
260910015Speter * Stop output on a line. called at spltty();
261010015Speter */
261110015Spetervoid
261210015Spetersistop(tp, rw)
261310015Speter	register struct tty *tp;
261410015Speter	int rw;
261510015Speter{
261610015Speter	volatile struct si_channel *ccbp;
261710015Speter	struct si_port *pp;
261810015Speter
261910015Speter	pp = TP2PP(tp);
262010015Speter	ccbp = pp->sp_ccb;
262110015Speter
262210015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
262310015Speter
262410015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
262510015Speter	if (rw & FWRITE) {
262610015Speter		/* what level are we meant to be flushing anyway? */
262710015Speter		if (tp->t_state & TS_BUSY) {
262810015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
262910015Speter			tp->t_state &= ~TS_BUSY;
263010015Speter			ttwwakeup(tp);	/* Bruce???? */
263110015Speter		}
263210015Speter	}
263312174Speter#if 1	/* XXX: this doesn't work right yet.. */
263412174Speter	/* XXX: this may have been failing because we used to call l_rint()
263512174Speter	 * while we were looping based on these two counters. Now, we collect
263612174Speter	 * the data and then loop stuffing it into l_rint(), making this
263712174Speter	 * useless.  Should we cause this to blow away the staging buffer?
263812174Speter	 */
263910015Speter	if (rw & FREAD) {
264010015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
264110015Speter	}
264210015Speter#endif
264310015Speter}
264410015Speter
264510015Speter/*
264634832Speter * Issue a command to the host card CPU.
264710015Speter */
264810015Speter
264910015Speterstatic void
265010015Spetersi_command(pp, cmd, waitflag)
265110015Speter	struct si_port *pp;		/* port control block (local) */
265210015Speter	int cmd;
265310015Speter	int waitflag;
265410015Speter{
265510015Speter	int oldspl;
265610015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
265710015Speter	int x;
265810015Speter
265910015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
266010015Speter		pp, cmd, waitflag, ccbp->hi_stat));
266110015Speter
266210015Speter	oldspl = spltty();		/* Keep others out */
266310015Speter
266410015Speter	/* wait until it's finished what it was doing.. */
266516575Speter	/* XXX: sits in IDLE_BREAK until something disturbs it or break
266616575Speter	 * is turned off. */
266710015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
266810015Speter			x != IDLE_CLOSE &&
266916575Speter			x != IDLE_BREAK &&
267010015Speter			x != cmd) {
267110015Speter		if (in_intr) {			/* Prevent sleep in intr */
267210015Speter			DPRINT((pp, DBG_PARAM,
267310015Speter				"cmd intr collision - completing %d\trequested %d\n",
267410015Speter				x, cmd));
267510015Speter			splx(oldspl);
267610015Speter			return;
267710015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
267810015Speter				"sicmd1", 1)) {
267910015Speter			splx(oldspl);
268010015Speter			return;
268110015Speter		}
268210015Speter	}
268316575Speter	/* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */
268410015Speter
268510015Speter	/* if there was a pending command, cause a state-change wakeup */
268616575Speter	switch(pp->sp_pend) {
268716575Speter	case LOPEN:
268816575Speter	case MPEND:
268916575Speter	case MOPEN:
269016575Speter	case CONFIG:
269116575Speter	case SBREAK:
269216575Speter	case EBREAK:
269316575Speter		wakeup(&pp->sp_state);
269416575Speter		break;
269516575Speter	default:
269616575Speter		break;
269710015Speter	}
269810015Speter
269910015Speter	pp->sp_pend = cmd;		/* New command pending */
270010015Speter	ccbp->hi_stat = cmd;		/* Post it */
270110015Speter
270210015Speter	if (waitflag) {
270310015Speter		if (in_intr) {		/* If in interrupt handler */
270410015Speter			DPRINT((pp, DBG_PARAM,
270510015Speter				"attempt to sleep in si_intr - cmd req %d\n",
270610015Speter				cmd));
270710015Speter			splx(oldspl);
270810015Speter			return;
270916575Speter		} else while(ccbp->hi_stat != IDLE_OPEN &&
271016575Speter			     ccbp->hi_stat != IDLE_BREAK) {
271110015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
271210015Speter			    "sicmd2", 0))
271310015Speter				break;
271410015Speter		}
271510015Speter	}
271610015Speter	splx(oldspl);
271710015Speter}
271810015Speter
271910015Speterstatic void
272010015Spetersi_disc_optim(tp, t, pp)
272110015Speter	struct tty	*tp;
272210015Speter	struct termios	*t;
272310015Speter	struct si_port	*pp;
272410015Speter{
272510015Speter	/*
272610015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
272710015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
272810015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
272910015Speter	 */
273010015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
273110015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
273210015Speter	    && (!(t->c_iflag & PARMRK)
273310015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
273410015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
273510015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
273610015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
273710015Speter	else
273810015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
273933322Sphk	pp->sp_hotchar = linesw[tp->t_line].l_hotchar;
274010161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
274110161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
274210161Speter		pp->sp_hotchar));
274310015Speter}
274410015Speter
274510015Speter
274610015Speter#ifdef	SI_DEBUG
274713353Speter
274810015Speterstatic void
274913353Speter#ifdef __STDC__
275013353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
275113353Speter#else
275213353Spetersi_dprintf(pp, flags, fmt, va_alist)
275310015Speter	struct si_port *pp;
275410015Speter	int flags;
275513353Speter	char *fmt;
275613353Speter#endif
275710015Speter{
275813353Speter	va_list ap;
275913630Sphk
276010015Speter	if ((pp == NULL && (si_debug&flags)) ||
276110015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
276234832Speter		if (pp != NULL)
276334832Speter			printf("%ci%d(%d): ", 's',
276446679Sphk				(int)SI_CARD(minor(pp->sp_tty->t_dev)),
276546679Sphk				(int)SI_PORT(minor(pp->sp_tty->t_dev)));
276613630Sphk		va_start(ap, fmt);
276713630Sphk		vprintf(fmt, ap);
276813353Speter		va_end(ap);
276910015Speter	}
277010015Speter}
277110015Speter
277210015Speterstatic char *
277310015Spetersi_mctl2str(cmd)
277410015Speter	enum si_mctl cmd;
277510015Speter{
277610015Speter	switch (cmd) {
277734832Speter	case GET:
277834832Speter		return("GET");
277934832Speter	case SET:
278034832Speter		return("SET");
278134832Speter	case BIS:
278234832Speter		return("BIS");
278334832Speter	case BIC:
278434832Speter		return("BIC");
278510015Speter	}
278610015Speter	return("BAD");
278710015Speter}
278812502Sjulian
278912624Speter#endif	/* DEBUG */
279012502Sjulian
279134832Speterstatic char *
279234832Spetersi_modulename(host_type, uart_type)
279334832Speter	int host_type, uart_type;
279434832Speter{
279534832Speter	switch (host_type) {
279634832Speter	/* Z280 based cards */
279734832Speter#if NEISA > 0
279834832Speter	case SIEISA:
279934832Speter#endif
280034832Speter	case SIHOST2:
280134832Speter	case SIHOST:
280234832Speter#if NPCI > 0
280334832Speter	case SIPCI:
280434832Speter#endif
280534832Speter		switch (uart_type) {
280634832Speter		case 0:
280734832Speter			return(" (XIO)");
280834832Speter		case 1:
280934832Speter			return(" (SI)");
281034832Speter		}
281134832Speter		break;
281234832Speter	/* T225 based hosts */
281334832Speter#if NPCI > 0
281434832Speter	case SIJETPCI:
281534832Speter#endif
281634832Speter	case SIJETISA:
281734832Speter		switch (uart_type) {
281834832Speter		case 0:
281934832Speter			return(" (SI)");
282034832Speter		case 40:
282134832Speter			return(" (XIO)");
282236856Sphk		case 72:
282336856Sphk			return(" (SXDC)");
282434832Speter		}
282534832Speter		break;
282634832Speter	}
282734832Speter	return("");
282834832Speter}
282912624Speter
283046153Sdtstatic int si_devsw_installed;
283112502Sjulian
283234832Speterstatic void
283334832Spetersi_drvinit(void *unused)
283412502Sjulian{
283512517Sjulian
283647640Sphk	cdevsw_add(&si_cdevsw);
283712502Sjulian}
283812517Sjulian
283912517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL)
2840