si.c revision 46112
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 *
3346112Sphk *	$Id: si.c,v 1.80 1999/04/24 20:17:03 peter Exp $
3410015Speter */
3510015Speter
3610015Speter#ifndef lint
3734832Speterstatic const char si_copyright1[] =  "@(#) Copyright (C) Specialix International, 1990,1992,1998",
3834832Speter		  si_copyright2[] =  "@(#) Copyright (C) Andy Rutter 1993",
3934832Speter		  si_copyright3[] =  "@(#) Copyright (C) Peter Wemm 1995";
4010015Speter#endif	/* not lint */
4110015Speter
4231778Seivind#include "opt_compat.h"
4332929Seivind#include "opt_debug_si.h"
4432726Seivind#include "opt_devfs.h"
4531778Seivind
4610015Speter#include <sys/param.h>
4710015Speter#include <sys/systm.h>
4824207Sbde#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
4924207Sbde#include <sys/ioctl_compat.h>
5024207Sbde#endif
5110015Speter#include <sys/tty.h>
5210015Speter#include <sys/proc.h>
5310015Speter#include <sys/conf.h>
5424131Sbde#include <sys/fcntl.h>
5510015Speter#include <sys/dkstat.h>
5610015Speter#include <sys/kernel.h>
5710015Speter#include <sys/malloc.h>
5815683Speter#include <sys/sysctl.h>
5912675Sjulian#ifdef DEVFS
6012675Sjulian#include <sys/devfsext.h>
6112675Sjulian#endif /*DEVFS*/
6210015Speter
6310015Speter#include <machine/clock.h>
6410015Speter
6512659Sbde#include <vm/vm.h>
6612662Sdg#include <vm/pmap.h>
6712659Sbde
6810015Speter#include <i386/isa/icu.h>
6910015Speter#include <i386/isa/isa.h>
7010015Speter#include <i386/isa/isa_device.h>
7110015Speter
7210015Speter#include <i386/isa/sireg.h>
7310015Speter#include <machine/si.h>
7413353Speter#include <machine/stdarg.h>
7510015Speter
7633395Speter#include "pci.h"
7733395Speter#if NPCI > 0
7833395Speter#include <pci/pcivar.h>
7933395Speter#endif
8033395Speter
8134832Speter#include "eisa.h"
8234832Speter#if NEISA > 0
8334832Speter#include <i386/eisa/eisaconf.h>
8434832Speter#include <i386/isa/icu.h>
8534832Speter#endif
8634832Speter
8710015Speter#include "si.h"
8810015Speter
8910015Speter/*
9010015Speter * This device driver is designed to interface the Specialix International
9134832Speter * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA,
9234832Speter * EISA or PCI bus machine.
9310015Speter *
9434832Speter * The controller is interfaced to the host via dual port RAM
9534832Speter * and an interrupt.
9633395Speter *
9734832Speter * The code for the Host 1 (very old ISA cards) has not been tested.
9810015Speter */
9910015Speter
10017547Speter#define	POLL		/* turn on poller to scan for lost interrupts */
10117547Speter#define REALPOLL	/* on each poll, scan for work regardless */
10217547Speter#define POLLHZ	(hz/10)	/* 10 times per second */
10312496Speter#define SI_I_HIGH_WATER	(TTYHOG - 2 * SI_BUFFERSIZE)
10434832Speter#define INT_COUNT 25000		/* max of 125 ints per second */
10534832Speter#define JET_INT_COUNT 100	/* max of 100 ints per second */
10615639Speter#define RXINT_COUNT 1	/* one rxint per 10 milliseconds */
10710015Speter
10810015Speterenum si_mctl { GET, SET, BIS, BIC };
10910015Speter
11010015Speterstatic void si_command __P((struct si_port *, int, int));
11110015Speterstatic int si_modem __P((struct si_port *, enum si_mctl, int));
11210015Speterstatic void si_write_enable __P((struct si_port *, int));
11338351Sbdestatic int si_Sioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
11410015Speterstatic void si_start __P((struct tty *));
11525047Sbdestatic timeout_t si_lstart;
11610015Speterstatic void si_disc_optim __P((struct tty *tp, struct termios *t,
11710015Speter					struct si_port *pp));
11810015Speterstatic void sihardclose __P((struct si_port *pp));
11910015Speterstatic void sidtrwakeup __P((void *chan));
12010015Speter
12112724Sphkstatic int	siparam __P((struct tty *, struct termios *));
12210015Speter
12312724Sphkstatic	int	siprobe __P((struct isa_device *id));
12412724Sphkstatic	int	siattach __P((struct isa_device *id));
12510708Speterstatic	void	si_modem_state __P((struct si_port *pp, struct tty *tp, int hi_ip));
12634735Speterstatic void	si_intr __P((int unit));
12734832Speterstatic char *	si_modulename __P((int host_type, int uart_type));
12810708Speter
12912675Sjulianstruct isa_driver sidriver =
13012675Sjulian	{ siprobe, siattach, "si" };
13112675Sjulian
13234832Speterstatic u_long sipcieisacount = 0;
13334832Speter
13433395Speter#if NPCI > 0
13512675Sjulian
13642546Seivindstatic const char *sipciprobe __P((pcici_t, pcidi_t));
13733395Speterstatic void sipciattach __P((pcici_t, int));
13833395Speter
13933395Speterstatic struct pci_device sipcidev = {
14033395Speter	"si",
14133395Speter	sipciprobe,
14233395Speter	sipciattach,
14334832Speter	&sipcieisacount,
14433395Speter	NULL,
14533395Speter};
14633395Speter
14746024Speter#ifdef COMPAT_PCI_DRIVER
14846024SpeterCOMPAT_PCI_DRIVER (sipci, sipcidev);
14946024Speter#else
15033395SpeterDATA_SET (pcidevice_set, sipcidev);
15146024Speter#endif /* COMPAT_PCI_DRIVER */
15233395Speter
15333395Speter#endif
15433395Speter
15534832Speter#if NEISA > 0
15634832Speter
15734832Speterstatic int si_eisa_probe __P((void));
15834832Speterstatic int si_eisa_attach __P((struct eisa_device *ed));
15934832Speter
16034832Speterstatic struct eisa_driver si_eisa_driver = {
16134832Speter	"si",
16234832Speter	si_eisa_probe,
16334832Speter	si_eisa_attach,
16434832Speter	NULL,
16534832Speter	&sipcieisacount,
16634832Speter};
16734832Speter
16834832SpeterDATA_SET(eisadriver_set, si_eisa_driver);
16934832Speter
17034832Speter#endif
17134832Speter
17212675Sjulianstatic	d_open_t	siopen;
17312675Sjulianstatic	d_close_t	siclose;
17412675Sjulianstatic	d_read_t	siread;
17512675Sjulianstatic	d_write_t	siwrite;
17612675Sjulianstatic	d_ioctl_t	siioctl;
17712675Sjulianstatic	d_stop_t	sistop;
17812731Sbdestatic	d_devtotty_t	sidevtotty;
17912675Sjulian
18038485Sbde#define	CDEV_MAJOR	68
18138485Sbdestatic	struct cdevsw	si_cdevsw = {
18238485Sbde	siopen,		siclose,	siread,		siwrite,
18338485Sbde	siioctl,	sistop,		noreset,	sidevtotty,
18438485Sbde	ttpoll,		nommap,		NULL,		"si",
18538485Sbde	NULL,		-1,		nodump,		nopsize,
18638485Sbde	D_TTY,
18738485Sbde};
18812675Sjulian
18912174Speter#ifdef SI_DEBUG		/* use: ``options "SI_DEBUG"'' in your config file */
19013353Speter
19113353Speterstatic	void	si_dprintf __P((struct si_port *pp, int flags, const char *fmt,
19213353Speter				...));
19310708Speterstatic	char	*si_mctl2str __P((enum si_mctl cmd));
19413353Speter
19510708Speter#define	DPRINT(x)	si_dprintf x
19613353Speter
19710708Speter#else
19810708Speter#define	DPRINT(x)	/* void */
19910708Speter#endif
20010708Speter
20110962Speterstatic int si_Nports;
20210962Speterstatic int si_Nmodules;
20310962Speterstatic int si_debug = 0;	/* data, not bss, so it's patchable */
20410015Speter
20534832SpeterSYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, "");
20634832Speter
20710962Speterstatic struct tty *si_tty;
20810962Speter
20934832Speter/* where the firmware lives; defined in si2_z280.c and si3_t225.c */
21034832Speter/* old: si2_z280.c */
21134832Speterextern unsigned char si2_z280_download[];
21234832Speterextern unsigned short si2_z280_downloadaddr;
21334832Speterextern int si2_z280_dsize;
21434832Speter/* new: si3_t225.c */
21534832Speterextern unsigned char si3_t225_download[];
21634832Speterextern unsigned short si3_t225_downloadaddr;
21734832Speterextern int si3_t225_dsize;
21834832Speterextern unsigned char si3_t225_bootstrap[];
21934832Speterextern unsigned short si3_t225_bootloadaddr;
22034832Speterextern int si3_t225_bsize;
22110015Speter
22233395Speter
22310044Speterstruct si_softc {
22410044Speter	int 		sc_type;	/* adapter type */
22510044Speter	char 		*sc_typename;	/* adapter type string */
22610044Speter
22710044Speter	struct si_port	*sc_ports;	/* port structures for this card */
22810044Speter
22910044Speter	caddr_t		sc_paddr;	/* physical addr of iomem */
23010044Speter	caddr_t		sc_maddr;	/* kvaddr of iomem */
23110044Speter	int		sc_nport;	/* # ports on this card */
23210044Speter	int		sc_irq;		/* copy of attach irq */
23334832Speter#if NEISA > 0
23410044Speter	int		sc_eisa_iobase;	/* EISA io port address */
23534832Speter	int		sc_eisa_irq;	/* EISA irq number */
23634832Speter#endif
23712675Sjulian#ifdef	DEVFS
23812675Sjulian	struct {
23934735Speter		void	*ttya;
24012826Speter		void	*cuaa;
24112675Sjulian		void	*ttyl;
24234735Speter		void	*cual;
24312675Sjulian		void	*ttyi;
24434735Speter		void	*cuai;
24512675Sjulian	} devfs_token[32]; /* what is the max per card? */
24613165Speter	void	*control_token;
24712675Sjulian#endif
24810044Speter};
24912724Sphkstatic struct si_softc si_softc[NSI];		/* up to 4 elements */
25010044Speter
25112174Speter#ifndef B2000	/* not standard, but the hardware knows it. */
25210015Speter# define B2000 2000
25310015Speter#endif
25410015Speterstatic struct speedtab bdrates[] = {
25510015Speter	B75,	CLK75,		/* 0x0 */
25610015Speter	B110,	CLK110,		/* 0x1 */
25710015Speter	B150,	CLK150,		/* 0x3 */
25810015Speter	B300,	CLK300,		/* 0x4 */
25910015Speter	B600,	CLK600,		/* 0x5 */
26010015Speter	B1200,	CLK1200,	/* 0x6 */
26110015Speter	B2000,	CLK2000,	/* 0x7 */
26210015Speter	B2400,	CLK2400,	/* 0x8 */
26310015Speter	B4800,	CLK4800,	/* 0x9 */
26410015Speter	B9600,	CLK9600,	/* 0xb */
26510015Speter	B19200,	CLK19200,	/* 0xc */
26610015Speter	B38400, CLK38400,	/* 0x2 (out of order!) */
26710015Speter	B57600, CLK57600,	/* 0xd */
26810015Speter	B115200, CLK110,	/* 0x1 (dupe!, 110 baud on "si") */
26910015Speter	-1,	-1
27010015Speter};
27110015Speter
27210015Speter
27310015Speter/* populated with approx character/sec rates - translated at card
27410015Speter * initialisation time to chars per tick of the clock */
27510015Speterstatic int done_chartimes = 0;
27610015Speterstatic struct speedtab chartimes[] = {
27710015Speter	B75,	8,
27810015Speter	B110,	11,
27910015Speter	B150,	15,
28010015Speter	B300,	30,
28110015Speter	B600,	60,
28210015Speter	B1200,	120,
28310015Speter	B2000,	200,
28410015Speter	B2400,	240,
28510015Speter	B4800,	480,
28610015Speter	B9600,	960,
28710015Speter	B19200,	1920,
28810015Speter	B38400, 3840,
28910015Speter	B57600, 5760,
29010015Speter	B115200, 11520,
29110015Speter	-1,	-1
29210015Speter};
29310015Speterstatic volatile int in_intr = 0;	/* Inside interrupt handler? */
29410015Speter
29510015Speter#ifdef POLL
29615683Speterstatic int si_pollrate;			/* in addition to irq */
29717547Speterstatic int si_realpoll;			/* poll HW on timer */
29815639Speter
29916403SpeterSYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, "");
30017547SpeterSYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, "");
30115639Speter
30210015Speterstatic int init_finished = 0;
30310015Speterstatic void si_poll __P((void *));
30410015Speter#endif
30510015Speter
30610015Speter/*
30710015Speter * Array of adapter types and the corresponding RAM size. The order of
30810015Speter * entries here MUST match the ordinal of the adapter type.
30910015Speter */
31010015Speterstatic char *si_type[] = {
31110015Speter	"EMPTY",
31210015Speter	"SIHOST",
31334832Speter	"SIMCA",		/* FreeBSD does not support Microchannel */
31410015Speter	"SIHOST2",
31510015Speter	"SIEISA",
31633395Speter	"SIPCI",
31733395Speter	"SXPCI",
31833395Speter	"SXISA",
31910015Speter};
32010015Speter
32133395Speter#if NPCI > 0
32233395Speter
32342546Seivindstatic const char *
32433395Spetersipciprobe(configid, deviceid)
32533395Speterpcici_t configid;
32633395Speterpcidi_t deviceid;
32733395Speter{
32833395Speter	switch (deviceid)
32933395Speter	{
33033395Speter		case 0x400011cb:
33133395Speter			return("Specialix SI/XIO PCI host card");
33233395Speter			break;
33333395Speter		case 0x200011cb:
33433395Speter			if (pci_conf_read(configid, SIJETSSIDREG) == 0x020011cb)
33533395Speter				return("Specialix SX PCI host card");
33633395Speter			else
33733395Speter				return NULL;
33833395Speter			break;
33933395Speter		default:
34033395Speter			return NULL;
34133395Speter	}
34233395Speter	/*NOTREACHED*/
34333395Speter}
34433395Speter
34533395Spetervoid
34633395Spetersipciattach(configid, unit)
34733395Speterpcici_t configid;
34833395Speterint unit;
34933395Speter{
35033395Speter	struct isa_device id;
35133395Speter	vm_offset_t vaddr,paddr;
35233395Speter	u_long mapval = 0;	/* shut up gcc, should not be needed */
35333395Speter
35433395Speter	switch ( pci_conf_read(configid, 0) >> 16 )
35533395Speter	{
35633395Speter		case 0x4000:
35733395Speter			si_softc[unit].sc_type = SIPCI;
35833395Speter			mapval = SIPCIBADR;
35934832Speter			break;
36033395Speter		case 0x2000:
36133395Speter			si_softc[unit].sc_type = SIJETPCI;
36233395Speter			mapval = SIJETBADR;
36334832Speter			break;
36433395Speter	}
36533395Speter	if (!pci_map_mem(configid, mapval, &vaddr, &paddr))
36633395Speter	{
36733395Speter		printf("si%d: couldn't map memory\n", unit);
36833395Speter	}
36933395Speter
37033395Speter	/*
37133395Speter	 * We're cheating here a little bit. The argument to an ISA
37233395Speter	 * interrupt routine is the unit number. The argument to a
37333395Speter	 * PCI interrupt handler is a void *, but we're simply going
37433395Speter	 * to be lazy and hand it the unit number.
37533395Speter	 */
37634735Speter	if (!pci_map_int(configid, (pci_inthand_t *) si_intr, (void *)unit, &tty_imask)) {
37733395Speter		printf("si%d: couldn't map interrupt\n", unit);
37833395Speter	}
37933395Speter	si_softc[unit].sc_typename = si_type[si_softc[unit].sc_type];
38033395Speter
38133395Speter	/*
38233395Speter	 * More cheating: We're going to dummy up a struct isa_device
38333395Speter	 * and call the other attach routine. We don't really have to
38433395Speter	 * fill in very much of the structure, since we filled in a
38533395Speter	 * little of the soft state already.
38633395Speter	 */
38734735Speter	id.id_unit = unit;
38834735Speter	id.id_maddr = (caddr_t) vaddr;
38933395Speter	siattach(&id);
39033395Speter}
39133395Speter
39233395Speter#endif
39333395Speter
39434832Speter#if NEISA > 0
39534832Speter
39634832Speterstatic const char *si_eisa_match __P((eisa_id_t id));
39734832Speter
39834832Speterstatic const char *
39934832Spetersi_eisa_match(id)
40034832Speter	eisa_id_t id;
40134832Speter{
40234832Speter	if (id == SIEISADEVID)
40334832Speter		return ("Specialix SI/XIO EISA host card");
40434832Speter	return (NULL);
40534832Speter}
40634832Speter
40734832Speterstatic int
40834832Spetersi_eisa_probe(void)
40934832Speter{
41034832Speter	struct eisa_device *ed = NULL;
41134832Speter	int count, irq;
41234832Speter
41334832Speter	for (count=0; (ed = eisa_match_dev(ed, si_eisa_match)) != NULL; count++)
41434832Speter	{
41534832Speter		u_long port,maddr;
41634832Speter
41734832Speter		port = (ed->ioconf.slot * EISA_SLOT_SIZE) + SIEISABASE;
41834832Speter		eisa_add_iospace(ed, port, SIEISAIOSIZE, RESVADDR_NONE);
41934832Speter		maddr = (inb(port+1) << 24) | (inb(port) << 16);
42034832Speter		irq  = ((inb(port+2) >> 4) & 0xf);
42134832Speter		eisa_add_mspace(ed, maddr, SIEISA_MEMSIZE, RESVADDR_NONE);
42234832Speter		eisa_add_intr(ed, irq);
42334832Speter		eisa_registerdev(ed, &si_eisa_driver);
42434832Speter		count++;
42534832Speter	}
42634832Speter	return count;
42734832Speter}
42834832Speter
42934832Speterstatic int
43034832Spetersi_eisa_attach(ed)
43134832Speter	struct eisa_device *ed;
43234832Speter{
43334832Speter	struct isa_device id;
43434832Speter	resvaddr_t *maddr,*iospace;
43534832Speter	u_int irq;
43634832Speter	struct si_softc *sc;
43734832Speter
43834832Speter	sc = &si_softc[ed->unit];
43934832Speter
44034832Speter	sc->sc_type = SIEISA;
44134832Speter	sc->sc_typename = si_type[sc->sc_type];
44234832Speter
44334832Speter	if ((iospace = ed->ioconf.ioaddrs.lh_first) == NULL) {
44438487Sbde		printf("si%lu: no iospace??\n", ed->unit);
44534832Speter		return -1;
44634832Speter	}
44734832Speter	sc->sc_eisa_iobase = iospace->addr;
44834832Speter
44934832Speter	irq  = ((inb(iospace->addr + 2) >> 4) & 0xf);
45034832Speter	sc->sc_eisa_irq = irq;
45134832Speter
45234832Speter	if ((maddr = ed->ioconf.maddrs.lh_first) == NULL) {
45338487Sbde		printf("si%lu: where am I??\n", ed->unit);
45434832Speter		return -1;
45534832Speter	}
45634832Speter	eisa_reg_start(ed);
45734832Speter	if (eisa_reg_iospace(ed, iospace)) {
45838487Sbde		printf("si%lu: failed to register iospace %p\n",
45938487Sbde			ed->unit, (void *)iospace);
46034832Speter		return -1;
46134832Speter	}
46234832Speter	if (eisa_reg_mspace(ed, maddr)) {
46338487Sbde		printf("si%lu: failed to register memspace %p\n",
46438487Sbde			ed->unit, (void *)maddr);
46534832Speter		return -1;
46634832Speter	}
46734832Speter	/*
46834832Speter	 * We're cheating here a little bit. The argument to an ISA
46934832Speter	 * interrupt routine is the unit number. The argument to a
47034832Speter	 * EISA interrupt handler is a void *, but we're simply going
47134832Speter	 * to be lazy and hand it the unit number.
47234832Speter	 */
47334832Speter	if (eisa_reg_intr(ed, irq, (void (*)(void *)) si_intr,
47438353Sbde		(void *)(intptr_t)(ed->unit), &tty_imask, 1)) {
47538487Sbde		printf("si%lu: failed to register interrupt %d\n",
47634832Speter			ed->unit, irq);
47734832Speter		return -1;
47834832Speter	}
47934832Speter	eisa_reg_end(ed);
48034832Speter	if (eisa_enable_intr(ed, irq)) {
48134832Speter		return -1;
48234832Speter	}
48334832Speter
48434832Speter	/*
48534832Speter	 * More cheating: We're going to dummy up a struct isa_device
48634832Speter	 * and call the other attach routine. We don't really have to
48734832Speter	 * fill in very much of the structure, since we filled in a
48834832Speter	 * little of the soft state already.
48934832Speter	 */
49034832Speter	id.id_unit = ed->unit;
49134832Speter	id.id_maddr = (caddr_t) pmap_mapdev(maddr->addr, SIEISA_MEMSIZE);
49234832Speter	return (siattach(&id));
49334832Speter}
49434832Speter
49534832Speter#endif
49634832Speter
49734832Speter
49810015Speter/* Look for a valid board at the given mem addr */
49912724Sphkstatic int
50010015Spetersiprobe(id)
50110015Speter	struct isa_device *id;
50210015Speter{
50310015Speter	struct si_softc *sc;
50410015Speter	int type;
50510015Speter	u_int i, ramsize;
50610015Speter	volatile BYTE was, *ux;
50710015Speter	volatile unsigned char *maddr;
50810015Speter	unsigned char *paddr;
50910015Speter
51017547Speter	si_pollrate = POLLHZ;		/* default 10 per second */
51117547Speter#ifdef REALPOLL
51217547Speter	si_realpoll = 1;		/* scan always */
51317547Speter#endif
51410015Speter	maddr = id->id_maddr;		/* virtual address... */
51510015Speter	paddr = (caddr_t)vtophys(id->id_maddr);	/* physical address... */
51610015Speter
51712496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
51812496Speter		id->id_unit, id->id_maddr, paddr));
51910015Speter
52010015Speter	/*
52110015Speter	 * this is a lie, but it's easier than trying to handle caching
52210015Speter	 * and ram conflicts in the >1M and <16M region.
52310015Speter	 */
52410015Speter	if ((caddr_t)paddr < (caddr_t)IOM_BEGIN ||
52510015Speter	    (caddr_t)paddr >= (caddr_t)IOM_END) {
52638353Sbde		printf("si%d: iomem (%p) out of range\n",
52738353Sbde			id->id_unit, (void *)paddr);
52810015Speter		return(0);
52910015Speter	}
53010015Speter
53110015Speter	if (id->id_unit >= NSI) {
53210015Speter		/* THIS IS IMPOSSIBLE */
53310015Speter		return(0);
53410015Speter	}
53510015Speter
53610015Speter	if (((u_int)paddr & 0x7fff) != 0) {
53710015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
53810015Speter			"si%d: iomem (%x) not on 32k boundary\n",
53910015Speter			id->id_unit, paddr));
54010015Speter		return(0);
54110015Speter	}
54210015Speter
54334735Speter	if (si_softc[id->id_unit].sc_typename) {
54434832Speter		/* EISA or PCI has taken this unit, choose another */
54534735Speter		for (i=0; i < NSI; i++) {
54634735Speter			if (si_softc[i].sc_typename == NULL) {
54734735Speter				id->id_unit = i;
54834735Speter				break;
54934735Speter			}
55034735Speter		}
55134735Speter		if (i >= NSI) {
55234735Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
55334735Speter				"si%d: cannot realloc unit\n", id->id_unit));
55434735Speter			return (0);
55534735Speter		}
55634735Speter	}
55734735Speter
55810015Speter	for (i=0; i < NSI; i++) {
55934735Speter		sc = &si_softc[i];
56010015Speter		if ((caddr_t)sc->sc_paddr == (caddr_t)paddr) {
56110015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
56210015Speter				"si%d: iomem (%x) already configured to si%d\n",
56310015Speter				id->id_unit, sc->sc_paddr, i));
56410015Speter			return(0);
56510015Speter		}
56610015Speter	}
56710015Speter
56810015Speter	/* Is there anything out there? (0x17 is just an arbitrary number) */
56910015Speter	*maddr = 0x17;
57010015Speter	if (*maddr != 0x17) {
57110015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
57210015Speter			"si%d: 0x17 check fail at phys 0x%x\n",
57310015Speter			id->id_unit, paddr));
57410015Speterfail:
57510015Speter		return(0);
57610015Speter	}
57710015Speter	/*
57833395Speter	 * Let's look first for a JET ISA card, since that's pretty easy
57934832Speter	 *
58034832Speter	 * All jet hosts are supposed to have this string in the IDROM,
58134832Speter	 * but it's not worth checking on self-IDing busses like PCI.
58233395Speter	 */
58334832Speter	{
58434832Speter		unsigned char *jet_chk_str = "JET HOST BY KEV#";
58534832Speter
58634832Speter		for (i = 0; i < strlen(jet_chk_str); i++)
58734832Speter			if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i))
58834832Speter				goto try_mk2;
58934832Speter	}
59033395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
59133395Speter		"si%d: JET first check - 0x%x\n",
59233395Speter		id->id_unit, (*(maddr+SIJETIDBASE))));
59333395Speter	if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff))
59433395Speter		goto try_mk2;
59533395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
59633395Speter		"si%d: JET second check - 0x%x\n",
59733395Speter		id->id_unit, (*(maddr+SIJETIDBASE+2))));
59833395Speter	if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8))
59933395Speter		goto try_mk2;
60033395Speter	/* It must be a Jet ISA or RIO card */
60133395Speter	DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
60233395Speter		"si%d: JET id check - 0x%x\n",
60333395Speter		id->id_unit, (*(maddr+SIUNIQID))));
60433395Speter	if ((*(maddr+SIUNIQID) & 0xf0) !=0x20)
60533395Speter		goto try_mk2;
60633395Speter	/* It must be a Jet ISA SI/XIO card */
60733395Speter	*(maddr + SIJETCONFIG) = 0;
60833395Speter	type = SIJETISA;
60933395Speter	ramsize = SIJET_RAMSIZE;
61033395Speter	goto got_card;
61133395Speter	/*
61210015Speter	 * OK, now to see if whatever responded is really an SI card.
61333395Speter	 * Try for a MK II next (SIHOST2)
61410015Speter	 */
61533395Spetertry_mk2:
61634832Speter	for (i = SIPLSIG; i < SIPLSIG + 8; i++)
61710015Speter		if ((*(maddr+i) & 7) != (~(BYTE)i & 7))
61810015Speter			goto try_mk1;
61910015Speter
62010015Speter	/* It must be an SIHOST2 */
62110015Speter	*(maddr + SIPLRESET) = 0;
62210015Speter	*(maddr + SIPLIRQCLR) = 0;
62310015Speter	*(maddr + SIPLIRQSET) = 0x10;
62410015Speter	type = SIHOST2;
62510015Speter	ramsize = SIHOST2_RAMSIZE;
62610015Speter	goto got_card;
62710015Speter
62810015Speter	/*
62910015Speter	 * Its not a MK II, so try for a MK I (SIHOST)
63010015Speter	 */
63110015Spetertry_mk1:
63210015Speter	*(maddr+SIRESET) = 0x0;		/* reset the card */
63310015Speter	*(maddr+SIINTCL) = 0x0;		/* clear int */
63410015Speter	*(maddr+SIRAM) = 0x17;
63510015Speter	if (*(maddr+SIRAM) != (BYTE)0x17)
63610015Speter		goto fail;
63710015Speter	*(maddr+0x7ff8) = 0x17;
63810015Speter	if (*(maddr+0x7ff8) != (BYTE)0x17) {
63910015Speter		DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
64010015Speter			"si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
64110015Speter			id->id_unit, paddr+0x77f8, *(maddr+0x77f8)));
64210015Speter		goto fail;
64310015Speter	}
64410015Speter
64534832Speter	/* It must be an SIHOST (maybe?) - there must be a better way XXX */
64610015Speter	type = SIHOST;
64710015Speter	ramsize = SIHOST_RAMSIZE;
64810015Speter
64910015Spetergot_card:
65012496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
65112496Speter		id->id_unit, type));
65210015Speter	/* Try the acid test */
65318515Speter	ux = maddr + SIRAM;
65434832Speter	for (i = 0; i < ramsize; i++, ux++)
65510015Speter		*ux = (BYTE)(i&0xff);
65618515Speter	ux = maddr + SIRAM;
65734832Speter	for (i = 0; i < ramsize; i++, ux++) {
65810015Speter		if ((was = *ux) != (BYTE)(i&0xff)) {
65910015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
66012174Speter				"si%d: match fail at phys 0x%x, was %x should be %x\n",
66134832Speter				id->id_unit, paddr + i, was, i&0xff));
66210015Speter			goto fail;
66310015Speter		}
66410015Speter	}
66510015Speter
66610015Speter	/* clear out the RAM */
66718515Speter	ux = maddr + SIRAM;
66834832Speter	for (i = 0; i < ramsize; i++)
66910015Speter		*ux++ = 0;
67018515Speter	ux = maddr + SIRAM;
67134832Speter	for (i = 0; i < ramsize; i++) {
67210015Speter		if ((was = *ux++) != 0) {
67310015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
67412174Speter				"si%d: clear fail at phys 0x%x, was %x\n",
67534832Speter				id->id_unit, paddr + i, was));
67610015Speter			goto fail;
67710015Speter		}
67810015Speter	}
67910015Speter
68010015Speter	/*
68110015Speter	 * Success, we've found a valid board, now fill in
68210015Speter	 * the adapter structure.
68310015Speter	 */
68410015Speter	switch (type) {
68510015Speter	case SIHOST2:
68634832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
68710015Speterbad_irq:
68810015Speter			DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
68910015Speter				"si%d: bad IRQ value - %d\n",
69010015Speter				id->id_unit, id->id_irq));
69110015Speter			return(0);
69210015Speter		}
69310015Speter		id->id_msize = SIHOST2_MEMSIZE;
69410015Speter		break;
69510015Speter	case SIHOST:
69634832Speter		if ((id->id_irq & (IRQ11|IRQ12|IRQ15)) == 0) {
69710015Speter			goto bad_irq;
69810015Speter		}
69910015Speter		id->id_msize = SIHOST_MEMSIZE;
70010015Speter		break;
70133395Speter	case SIJETISA:
70234832Speter		if ((id->id_irq & (IRQ9|IRQ10|IRQ11|IRQ12|IRQ15)) == 0) {
70333395Speter			goto bad_irq;
70433395Speter		}
70534832Speter		id->id_msize = SIJETISA_MEMSIZE;
70633395Speter		break;
70734832Speter	case SIMCA:		/* MCA */
70810015Speter	default:
70910015Speter		printf("si%d: %s not supported\n", id->id_unit, si_type[type]);
71010015Speter		return(0);
71110015Speter	}
71234832Speter	id->id_intr = (inthand2_t *)si_intr; /* set here instead of config */
71310015Speter	si_softc[id->id_unit].sc_type = type;
71410015Speter	si_softc[id->id_unit].sc_typename = si_type[type];
71510015Speter	return(-1);	/* -1 == found */
71610015Speter}
71710015Speter
71810015Speter/*
71934832Speter * We have to make an 8 bit version of bcopy, since some cards can't
72034832Speter * deal with 32 bit I/O
72134832Speter */
72234832Speter#if 1
72334832Speterstatic void
72434832Spetersi_bcopy(const void *src, void *dst, size_t len)
72534832Speter{
72634832Speter	while (len--)
72734832Speter		*(((u_char *)dst)++) = *(((u_char *)src)++);
72834832Speter}
72934832Speter#else
73034832Speter#define si_bcopy bcopy
73134832Speter#endif
73234832Speter
73334832Speter
73434832Speter/*
73510015Speter * Attach the device.  Initialize the card.
73634832Speter *
73734832Speter * This routine also gets called by the EISA and PCI attach routines.
73834832Speter * It presumes that the softstate for the unit has had had its type field
73934832Speter * and the EISA specific stuff filled in, as well as the kernel virtual
74034832Speter * base address and the unit number of the isa_device struct.
74110015Speter */
74212724Sphkstatic int
74310015Spetersiattach(id)
74410015Speter	struct isa_device *id;
74510015Speter{
74610015Speter	int unit = id->id_unit;
74710015Speter	struct si_softc *sc = &si_softc[unit];
74810015Speter	struct si_port *pp;
74910015Speter	volatile struct si_channel *ccbp;
75010015Speter	volatile struct si_reg *regp;
75110015Speter	volatile caddr_t maddr;
75210015Speter	struct si_module *modp;
75310015Speter	struct tty *tp;
75410015Speter	struct speedtab *spt;
75510015Speter	int nmodule, nport, x, y;
75612174Speter	int uart_type;
75710015Speter
75812496Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", id->id_unit));
75910015Speter
76010015Speter	sc->sc_paddr = (caddr_t)vtophys(id->id_maddr);
76110015Speter	sc->sc_maddr = id->id_maddr;
76210015Speter	sc->sc_irq = id->id_irq;
76310015Speter
76433395Speter	DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit,
76533395Speter		sc->sc_typename, sc->sc_paddr, sc->sc_maddr));
76633395Speter
76710015Speter	sc->sc_ports = NULL;			/* mark as uninitialised */
76810015Speter
76910015Speter	maddr = sc->sc_maddr;
77010015Speter
77134832Speter	/* Stop the CPU first so it won't stomp around while we load */
77234832Speter
77334832Speter	switch (sc->sc_type) {
77434832Speter#if NEISA > 0
77534832Speter		case SIEISA:
77634832Speter			outb(sc->sc_eisa_iobase + 2, sc->sc_eisa_irq << 4);
77734832Speter		break;
77834832Speter#endif
77934832Speter#if NPCI > 0
78034832Speter		case SIPCI:
78134832Speter			*(maddr+SIPCIRESET) = 0;
78234832Speter		break;
78334832Speter		case SIJETPCI: /* fall through to JET ISA */
78434832Speter#endif
78534832Speter		case SIJETISA:
78634832Speter			*(maddr+SIJETCONFIG) = 0;
78734832Speter		break;
78834832Speter		case SIHOST2:
78934832Speter			*(maddr+SIPLRESET) = 0;
79034832Speter		break;
79134832Speter		case SIHOST:
79234832Speter			*(maddr+SIRESET) = 0;
79334832Speter		break;
79434832Speter		default: /* this should never happen */
79534832Speter			printf("si%d: unsupported configuration\n", unit);
79634832Speter			return 0;
79734832Speter		break;
79834832Speter	}
79934832Speter
80034832Speter	/* OK, now lets download the download code */
80134832Speter
80236956Ssteve	if (SI_ISJET(sc->sc_type)) {
80333395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n",
80434832Speter			id->id_unit, si3_t225_dsize));
80534832Speter		si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr,
80634832Speter			si3_t225_dsize);
80734832Speter		DPRINT((0, DBG_DOWNLOAD,
80834832Speter			"si%d: jet_bootstrap: nbytes %d -> %x\n",
80934832Speter			id->id_unit, si3_t225_bsize, si3_t225_bootloadaddr));
81034832Speter		si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr,
81134832Speter			si3_t225_bsize);
81234832Speter	} else {
81333395Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
81434832Speter			id->id_unit, si2_z280_dsize));
81534832Speter		si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr,
81634832Speter			si2_z280_dsize);
81733395Speter	}
81810015Speter
81934832Speter	/* Now start the CPU */
82034832Speter
82110015Speter	switch (sc->sc_type) {
82234832Speter#if NEISA > 0
82310015Speter	case SIEISA:
82434832Speter		/* modify the download code to tell it that it's on an EISA */
82534832Speter		*(maddr + 0x42) = 1;
82634832Speter		outb(sc->sc_eisa_iobase + 2, (sc->sc_eisa_irq << 4) | 4);
82734832Speter		(void)inb(sc->sc_eisa_iobase + 3); /* reset interrupt */
82810015Speter		break;
82934832Speter#endif
83033395Speter	case SIPCI:
83134832Speter		/* modify the download code to tell it that it's on a PCI */
83233395Speter		*(maddr+0x42) = 1;
83333395Speter		*(maddr+SIPCIRESET) = 1;
83433395Speter		*(maddr+SIPCIINTCL) = 0;
83533395Speter		break;
83633395Speter	case SIJETPCI:
83733395Speter		*(maddr+SIJETRESET) = 0;
83833395Speter		*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN;
83933395Speter		break;
84033395Speter	case SIJETISA:
84133395Speter		*(maddr+SIJETRESET) = 0;
84234832Speter		switch (sc->sc_irq) {
84334832Speter		case IRQ9:
84434832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90;
84534832Speter			break;
84634832Speter		case IRQ10:
84734832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0;
84834832Speter			break;
84934832Speter		case IRQ11:
85034832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0;
85134832Speter			break;
85234832Speter		case IRQ12:
85334832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0;
85434832Speter			break;
85534832Speter		case IRQ15:
85634832Speter			*(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0;
85734832Speter			break;
85834832Speter		}
85933395Speter		break;
86010015Speter	case SIHOST:
86110015Speter		*(maddr+SIRESET_CL) = 0;
86210015Speter		*(maddr+SIINTCL_CL) = 0;
86310015Speter		break;
86410015Speter	case SIHOST2:
86510015Speter		*(maddr+SIPLRESET) = 0x10;
86610015Speter		switch (sc->sc_irq) {
86710015Speter		case IRQ11:
86810015Speter			*(maddr+SIPLIRQ11) = 0x10;
86910015Speter			break;
87010015Speter		case IRQ12:
87110015Speter			*(maddr+SIPLIRQ12) = 0x10;
87210015Speter			break;
87310015Speter		case IRQ15:
87410015Speter			*(maddr+SIPLIRQ15) = 0x10;
87510015Speter			break;
87610015Speter		}
87710015Speter		*(maddr+SIPLIRQCLR) = 0x10;
87810015Speter		break;
87934832Speter	default: /* this should _REALLY_ never happen */
88034832Speter		printf("si%d: Uh, it was supported a second ago...\n", unit);
88134832Speter		return 0;
88210015Speter	}
88310015Speter
88410015Speter	DELAY(1000000);			/* wait around for a second */
88510015Speter
88610015Speter	regp = (struct si_reg *)maddr;
88710015Speter	y = 0;
88810015Speter					/* wait max of 5 sec for init OK */
88910015Speter	while (regp->initstat == 0 && y++ < 10) {
89010015Speter		DELAY(500000);
89110015Speter	}
89210015Speter	switch (regp->initstat) {
89310015Speter	case 0:
89410015Speter		printf("si%d: startup timeout - aborting\n", unit);
89512174Speter		sc->sc_type = SIEMPTY;
89610015Speter		return 0;
89710015Speter	case 1:
89836956Ssteve		if (SI_ISJET(sc->sc_type)) {
89934832Speter			/* set throttle to 100 times per second */
90034832Speter			regp->int_count = JET_INT_COUNT;
90134832Speter			/* rx_intr_count is a NOP in Jet */
90234832Speter		} else {
90334832Speter			/* set throttle to 125 times per second */
90434832Speter			regp->int_count = INT_COUNT;
90534832Speter			/* rx intr max of 25 times per second */
90634832Speter			regp->rx_int_count = RXINT_COUNT;
90734832Speter		}
90810015Speter		regp->int_pending = 0;		/* no intr pending */
90910015Speter		regp->int_scounter = 0;	/* reset counter */
91010015Speter		break;
91110015Speter	case 0xff:
91210015Speter		/*
91310015Speter		 * No modules found, so give up on this one.
91410015Speter		 */
91510015Speter		printf("si%d: %s - no ports found\n", unit,
91610015Speter			si_type[sc->sc_type]);
91710015Speter		return 0;
91810015Speter	default:
91934832Speter		printf("si%d: download code version error - initstat %x\n",
92010015Speter			unit, regp->initstat);
92110015Speter		return 0;
92210015Speter	}
92310015Speter
92410015Speter	/*
92510015Speter	 * First time around the ports just count them in order
92610015Speter	 * to allocate some memory.
92710015Speter	 */
92810015Speter	nport = 0;
92910015Speter	modp = (struct si_module *)(maddr + 0x80);
93010015Speter	for (;;) {
93112174Speter		DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
93234832Speter		switch (modp->sm_type) {
93334832Speter		case TA4:
93410015Speter			DPRINT((0, DBG_DOWNLOAD,
93534832Speter				"si%d: Found old TA4 module, 4 ports\n",
93634832Speter				unit));
93734832Speter			x = 4;
93810015Speter			break;
93934832Speter		case TA8:
94034832Speter			DPRINT((0, DBG_DOWNLOAD,
94134832Speter				"si%d: Found old TA8 module, 8 ports\n",
94234832Speter				unit));
94334832Speter			x = 8;
94434832Speter			break;
94534832Speter		case TA4_ASIC:
94634832Speter			DPRINT((0, DBG_DOWNLOAD,
94734832Speter				"si%d: Found ASIC TA4 module, 4 ports\n",
94834832Speter				unit));
94934832Speter			x = 4;
95034832Speter			break;
95134832Speter		case TA8_ASIC:
95234832Speter			DPRINT((0, DBG_DOWNLOAD,
95334832Speter				"si%d: Found ASIC TA8 module, 8 ports\n",
95434832Speter				unit));
95534832Speter			x = 8;
95634832Speter			break;
95734832Speter		case MTA:
95834832Speter			DPRINT((0, DBG_DOWNLOAD,
95934832Speter				"si%d: Found CD1400 module, 8 ports\n",
96034832Speter				unit));
96134832Speter			x = 8;
96234832Speter			break;
96334832Speter		case SXDC:
96434832Speter			DPRINT((0, DBG_DOWNLOAD,
96534832Speter				"si%d: Found SXDC module, 8 ports\n",
96634832Speter				unit));
96734832Speter			x = 8;
96834832Speter			break;
96910015Speter		default:
97010015Speter			printf("si%d: unknown module type %d\n",
97110015Speter				unit, modp->sm_type);
97234832Speter			goto try_next;
97310015Speter		}
97434832Speter
97534832Speter		/* this was limited in firmware and is also a driver issue */
97634832Speter		if ((nport + x) > SI_MAXPORTPERCARD) {
97734832Speter			printf("si%d: extra ports ignored\n", unit);
97834832Speter			goto try_next;
97934832Speter		}
98034832Speter
98134832Speter		nport += x;
98234832Speter		si_Nports += x;
98334832Speter		si_Nmodules++;
98434832Speter
98534832Spetertry_next:
98610015Speter		if (modp->sm_next == 0)
98710015Speter			break;
98810015Speter		modp = (struct si_module *)
98910015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
99010015Speter	}
99110015Speter	sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
99210015Speter		M_DEVBUF, M_NOWAIT);
99310015Speter	if (sc->sc_ports == 0) {
99410015Spetermem_fail:
99510015Speter		printf("si%d: fail to malloc memory for port structs\n",
99610015Speter			unit);
99710015Speter		return 0;
99810015Speter	}
99910015Speter	bzero(sc->sc_ports, sizeof(struct si_port) * nport);
100010015Speter	sc->sc_nport = nport;
100110015Speter
100210015Speter	/*
100310015Speter	 * allocate tty structures for ports
100410015Speter	 */
100510015Speter	tp = (struct tty *)malloc(sizeof(*tp) * nport, M_DEVBUF, M_NOWAIT);
100610015Speter	if (tp == 0)
100710015Speter		goto mem_fail;
100810015Speter	bzero(tp, sizeof(*tp) * nport);
100910962Speter	si_tty = tp;
101010015Speter
101110015Speter	/*
101210015Speter	 * Scan round the ports again, this time initialising.
101310015Speter	 */
101410015Speter	pp = sc->sc_ports;
101510015Speter	nmodule = 0;
101610015Speter	modp = (struct si_module *)(maddr + 0x80);
101734832Speter	uart_type = 1000;	/* arbitary, > uchar_max */
101810015Speter	for (;;) {
101934832Speter		switch (modp->sm_type) {
102034832Speter		case TA4:
102134832Speter			nport = 4;
102210015Speter			break;
102334832Speter		case TA8:
102434832Speter			nport = 8;
102534832Speter			break;
102634832Speter		case TA4_ASIC:
102734832Speter			nport = 4;
102834832Speter			break;
102934832Speter		case TA8_ASIC:
103034832Speter			nport = 8;
103134832Speter			break;
103234832Speter		case MTA:
103334832Speter			nport = 8;
103434832Speter			break;
103534832Speter		case SXDC:
103634832Speter			nport = 8;
103734832Speter			break;
103810015Speter		default:
103934832Speter			goto try_next2;
104010015Speter		}
104134832Speter		nmodule++;
104234832Speter		ccbp = (struct si_channel *)((char *)modp + 0x100);
104334832Speter		if (uart_type == 1000)
104434832Speter			uart_type = ccbp->type;
104534832Speter		else if (uart_type != ccbp->type)
104634832Speter			printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n",
104734832Speter			    unit, nmodule,
104834832Speter			    ccbp->type, si_modulename(sc->sc_type, ccbp->type),
104934832Speter			    uart_type, si_modulename(sc->sc_type, uart_type));
105034832Speter
105134832Speter		for (x = 0; x < nport; x++, pp++, ccbp++) {
105234832Speter			pp->sp_ccb = ccbp;	/* save the address */
105334832Speter			pp->sp_tty = tp++;
105434832Speter			pp->sp_pend = IDLE_CLOSE;
105534832Speter			pp->sp_state = 0;	/* internal flag */
105634832Speter			pp->sp_dtr_wait = 3 * hz;
105734832Speter			pp->sp_iin.c_iflag = TTYDEF_IFLAG;
105834832Speter			pp->sp_iin.c_oflag = TTYDEF_OFLAG;
105934832Speter			pp->sp_iin.c_cflag = TTYDEF_CFLAG;
106034832Speter			pp->sp_iin.c_lflag = TTYDEF_LFLAG;
106134832Speter			termioschars(&pp->sp_iin);
106234832Speter			pp->sp_iin.c_ispeed = pp->sp_iin.c_ospeed =
106334832Speter				TTYDEF_SPEED;;
106434832Speter			pp->sp_iout = pp->sp_iin;
106534832Speter		}
106634832Spetertry_next2:
106710015Speter		if (modp->sm_next == 0) {
106834832Speter			printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n",
106910015Speter				unit,
107010015Speter				sc->sc_typename,
107110015Speter				sc->sc_nport,
107212174Speter				nmodule,
107334832Speter				uart_type,
107434832Speter				si_modulename(sc->sc_type, uart_type));
107510015Speter			break;
107610015Speter		}
107710015Speter		modp = (struct si_module *)
107810015Speter			(maddr + (unsigned)(modp->sm_next & 0x7fff));
107910015Speter	}
108010015Speter	if (done_chartimes == 0) {
108110015Speter		for (spt = chartimes ; spt->sp_speed != -1; spt++) {
108210015Speter			if ((spt->sp_code /= hz) == 0)
108310015Speter				spt->sp_code = 1;
108410015Speter		}
108510015Speter		done_chartimes = 1;
108610015Speter	}
108712502Sjulian
108812675Sjulian#ifdef DEVFS
108912675Sjulian/*	path	name	devsw		minor	type   uid gid perm*/
109013169Speter	for ( x = 0; x < sc->sc_nport; x++ ) {
109134735Speter		/* sync with the manuals that start at 1 */
109234735Speter		y = x + 1 + id->id_unit * (1 << SI_CARDSHIFT);
109334735Speter		sc->devfs_token[x].ttya = devfs_add_devswf(
109413630Sphk			&si_cdevsw, x,
109513630Sphk			DV_CHR, 0, 0, 0600, "ttyA%02d", y);
109613630Sphk		sc->devfs_token[x].cuaa = devfs_add_devswf(
109734735Speter			&si_cdevsw, x + 0x00080,
109813630Sphk			DV_CHR, 0, 0, 0600, "cuaA%02d", y);
109913630Sphk		sc->devfs_token[x].ttyi = devfs_add_devswf(
110013630Sphk			&si_cdevsw, x + 0x10000,
110113630Sphk			DV_CHR, 0, 0, 0600, "ttyiA%02d", y);
110234735Speter		sc->devfs_token[x].cuai = devfs_add_devswf(
110334735Speter			&si_cdevsw, x + 0x10080,
110434735Speter			DV_CHR, 0, 0, 0600, "cuaiA%02d", y);
110513630Sphk		sc->devfs_token[x].ttyl = devfs_add_devswf(
110613630Sphk			&si_cdevsw, x + 0x20000,
110713630Sphk			DV_CHR, 0, 0, 0600, "ttylA%02d", y);
110834735Speter		sc->devfs_token[x].cual = devfs_add_devswf(
110934735Speter			&si_cdevsw, x + 0x20080,
111034735Speter			DV_CHR, 0, 0, 0600, "cualA%02d", y);
111112675Sjulian	}
111214873Sscrappy	sc->control_token =
111314873Sscrappy		devfs_add_devswf(&si_cdevsw, 0x40000, DV_CHR, 0, 0, 0600,
111414873Sscrappy				 "si_control");
111512675Sjulian#endif
111610015Speter	return (1);
111710015Speter}
111810015Speter
111912675Sjulianstatic	int
112010015Spetersiopen(dev, flag, mode, p)
112110015Speter	dev_t dev;
112210015Speter	int flag, mode;
112310015Speter	struct proc *p;
112410015Speter{
112510015Speter	int oldspl, error;
112610015Speter	int card, port;
112710015Speter	register struct si_softc *sc;
112810015Speter	register struct tty *tp;
112910015Speter	volatile struct si_channel *ccbp;
113010015Speter	struct si_port *pp;
113110015Speter	int mynor = minor(dev);
113210015Speter
113310015Speter	/* quickly let in /dev/si_control */
113410015Speter	if (IS_CONTROLDEV(mynor)) {
113546112Sphk		if ((error = suser(p)))
113610015Speter			return(error);
113710015Speter		return(0);
113810015Speter	}
113910015Speter
114010015Speter	card = SI_CARD(mynor);
114110015Speter	if (card >= NSI)
114210015Speter		return (ENXIO);
114310015Speter	sc = &si_softc[card];
114410015Speter
114512174Speter	if (sc->sc_type == SIEMPTY) {
114612174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: type %s??\n",
114710015Speter			card, sc->sc_typename));
114810015Speter		return(ENXIO);
114910015Speter	}
115010015Speter
115110015Speter	port = SI_PORT(mynor);
115210015Speter	if (port >= sc->sc_nport) {
115312174Speter		DPRINT((0, DBG_OPEN|DBG_FAIL, "si%d: nports %d\n",
115410015Speter			card, sc->sc_nport));
115510015Speter		return(ENXIO);
115610015Speter	}
115710015Speter
115810015Speter#ifdef	POLL
115910015Speter	/*
116010015Speter	 * We've now got a device, so start the poller.
116110015Speter	 */
116210015Speter	if (init_finished == 0) {
116315639Speter		timeout(si_poll, (caddr_t)0L, si_pollrate);
116410015Speter		init_finished = 1;
116510015Speter	}
116610015Speter#endif
116710015Speter
116810015Speter	/* initial/lock device */
116910015Speter	if (IS_STATE(mynor)) {
117010015Speter		return(0);
117110015Speter	}
117210015Speter
117310015Speter	pp = sc->sc_ports + port;
117410015Speter	tp = pp->sp_tty;			/* the "real" tty */
117510015Speter	ccbp = pp->sp_ccb;			/* Find control block */
117610015Speter	DPRINT((pp, DBG_ENTRY|DBG_OPEN, "siopen(%x,%x,%x,%x)\n",
117710015Speter		dev, flag, mode, p));
117810015Speter
117910015Speter	oldspl = spltty();			/* Keep others out */
118010015Speter	error = 0;
118110015Speter
118210015Speteropen_top:
118310015Speter	while (pp->sp_state & SS_DTR_OFF) {
118410015Speter		error = tsleep(&pp->sp_dtr_wait, TTIPRI|PCATCH, "sidtr", 0);
118510015Speter		if (error != 0)
118610015Speter			goto out;
118710015Speter	}
118810015Speter
118910015Speter	if (tp->t_state & TS_ISOPEN) {
119010015Speter		/*
119110015Speter		 * The device is open, so everything has been initialised.
119210015Speter		 * handle conflicts.
119310015Speter		 */
119410015Speter		if (IS_CALLOUT(mynor)) {
119510015Speter			if (!pp->sp_active_out) {
119610015Speter				error = EBUSY;
119710015Speter				goto out;
119810015Speter			}
119910015Speter		} else {
120010015Speter			if (pp->sp_active_out) {
120110015Speter				if (flag & O_NONBLOCK) {
120210015Speter					error = EBUSY;
120310015Speter					goto out;
120410015Speter				}
120510015Speter				error = tsleep(&pp->sp_active_out,
120610015Speter						TTIPRI|PCATCH, "sibi", 0);
120710015Speter				if (error != 0)
120810015Speter					goto out;
120910015Speter				goto open_top;
121010015Speter			}
121110015Speter		}
121243425Sphk		if (tp->t_state & TS_XCLUDE &&
121346112Sphk		    suser(p)) {
121410015Speter			DPRINT((pp, DBG_OPEN|DBG_FAIL,
121510015Speter				"already open and EXCLUSIVE set\n"));
121610015Speter			error = EBUSY;
121710015Speter			goto out;
121810015Speter		}
121910015Speter	} else {
122010015Speter		/*
122110015Speter		 * The device isn't open, so there are no conflicts.
122210015Speter		 * Initialize it. Avoid sleep... :-)
122310015Speter		 */
122410015Speter		DPRINT((pp, DBG_OPEN, "first open\n"));
122510015Speter		tp->t_oproc = si_start;
122610015Speter		tp->t_param = siparam;
122710015Speter		tp->t_dev = dev;
122810015Speter		tp->t_termios = mynor & SI_CALLOUT_MASK
122910015Speter				? pp->sp_iout : pp->sp_iin;
123010015Speter
123110015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
123210015Speter
123310015Speter		++pp->sp_wopeners;	/* in case of sleep in siparam */
123410015Speter
123510015Speter		error = siparam(tp, &tp->t_termios);
123610015Speter
123710015Speter		--pp->sp_wopeners;
123810015Speter		if (error != 0)
123910015Speter			goto out;
124010015Speter		/* XXX: we should goto_top if siparam slept */
124110015Speter
124210015Speter		/* set initial DCD state */
124310015Speter		pp->sp_last_hi_ip = ccbp->hi_ip;
124410015Speter		if ((pp->sp_last_hi_ip & IP_DCD) || IS_CALLOUT(mynor)) {
124510015Speter			(*linesw[tp->t_line].l_modem)(tp, 1);
124610015Speter		}
124710015Speter	}
124810015Speter
124910015Speter	/* whoops! we beat the close! */
125010015Speter	if (pp->sp_state & SS_CLOSING) {
125110015Speter		/* try and stop it from proceeding to bash the hardware */
125210015Speter		pp->sp_state &= ~SS_CLOSING;
125310015Speter	}
125410015Speter
125510015Speter	/*
125610015Speter	 * Wait for DCD if necessary
125710015Speter	 */
125810015Speter	if (!(tp->t_state & TS_CARR_ON)
125910015Speter	    && !IS_CALLOUT(mynor)
126010015Speter	    && !(tp->t_cflag & CLOCAL)
126110015Speter	    && !(flag & O_NONBLOCK)) {
126210015Speter		++pp->sp_wopeners;
126310015Speter		DPRINT((pp, DBG_OPEN, "sleeping for carrier\n"));
126410015Speter		error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "sidcd", 0);
126510015Speter		--pp->sp_wopeners;
126610015Speter		if (error != 0)
126710015Speter			goto out;
126810015Speter		goto open_top;
126910015Speter	}
127010015Speter
127110015Speter	error = (*linesw[tp->t_line].l_open)(dev, tp);
127210015Speter	si_disc_optim(tp, &tp->t_termios, pp);
127310015Speter	if (tp->t_state & TS_ISOPEN && IS_CALLOUT(mynor))
127410015Speter		pp->sp_active_out = TRUE;
127510015Speter
127610015Speter	pp->sp_state |= SS_OPEN;	/* made it! */
127710015Speter
127810015Speterout:
127910015Speter	splx(oldspl);
128010015Speter
128110015Speter	DPRINT((pp, DBG_OPEN, "leaving siopen\n"));
128210015Speter
128310015Speter	if (!(tp->t_state & TS_ISOPEN) && pp->sp_wopeners == 0)
128410015Speter		sihardclose(pp);
128510015Speter
128610015Speter	return(error);
128710015Speter}
128810015Speter
128912675Sjulianstatic	int
129010015Spetersiclose(dev, flag, mode, p)
129110015Speter	dev_t dev;
129210015Speter	int flag, mode;
129310015Speter	struct proc *p;
129410015Speter{
129510015Speter	register struct si_port *pp;
129610015Speter	register struct tty *tp;
129710015Speter	int oldspl;
129810015Speter	int error = 0;
129910015Speter	int mynor = minor(dev);
130010015Speter
130110015Speter	if (IS_SPECIAL(mynor))
130210015Speter		return(0);
130310015Speter
130410015Speter	oldspl = spltty();
130510015Speter
130610015Speter	pp = MINOR2PP(mynor);
130710015Speter	tp = pp->sp_tty;
130810015Speter
130910015Speter	DPRINT((pp, DBG_ENTRY|DBG_CLOSE, "siclose(%x,%x,%x,%x) sp_state:%x\n",
131010015Speter		dev, flag, mode, p, pp->sp_state));
131110015Speter
131210015Speter	/* did we sleep and loose a race? */
131310015Speter	if (pp->sp_state & SS_CLOSING) {
131410015Speter		/* error = ESOMETING? */
131510015Speter		goto out;
131610015Speter	}
131710015Speter
131810015Speter	/* begin race detection.. */
131910015Speter	pp->sp_state |= SS_CLOSING;
132010015Speter
132110015Speter	si_write_enable(pp, 0);		/* block writes for ttywait() */
132210015Speter
132310015Speter	/* THIS MAY SLEEP IN TTYWAIT!!! */
132410015Speter	(*linesw[tp->t_line].l_close)(tp, flag);
132510015Speter
132610015Speter	si_write_enable(pp, 1);
132710015Speter
132810015Speter	/* did we sleep and somebody started another open? */
132910015Speter	if (!(pp->sp_state & SS_CLOSING)) {
133010015Speter		/* error = ESOMETING? */
133110015Speter		goto out;
133210015Speter	}
133310015Speter	/* ok. we are now still on the right track.. nuke the hardware */
133410015Speter
133510015Speter	if (pp->sp_state & SS_LSTART) {
133629677Sgibbs		untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
133710015Speter		pp->sp_state &= ~SS_LSTART;
133810015Speter	}
133910015Speter
134010015Speter	sistop(tp, FREAD | FWRITE);
134110015Speter
134210015Speter	sihardclose(pp);
134310015Speter	ttyclose(tp);
134410015Speter	pp->sp_state &= ~SS_OPEN;
134510015Speter
134610015Speterout:
134710015Speter	DPRINT((pp, DBG_CLOSE|DBG_EXIT, "close done, returning\n"));
134810015Speter	splx(oldspl);
134910015Speter	return(error);
135010015Speter}
135110015Speter
135210015Speterstatic void
135310015Spetersihardclose(pp)
135410015Speter	struct si_port *pp;
135510015Speter{
135610015Speter	int oldspl;
135710015Speter	struct tty *tp;
135810015Speter	volatile struct si_channel *ccbp;
135910015Speter
136010015Speter	oldspl = spltty();
136110015Speter
136210015Speter	tp = pp->sp_tty;
136310015Speter	ccbp = pp->sp_ccb;			/* Find control block */
136410015Speter	if (tp->t_cflag & HUPCL
136518515Speter	    || (!pp->sp_active_out
136634832Speter		&& !(ccbp->hi_ip & IP_DCD)
136734832Speter		&& !(pp->sp_iin.c_cflag && CLOCAL))
136810015Speter	    || !(tp->t_state & TS_ISOPEN)) {
136910015Speter
137010015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
137110015Speter		(void) si_command(pp, FCLOSE, SI_NOWAIT);
137210015Speter
137310015Speter		if (pp->sp_dtr_wait != 0) {
137410015Speter			timeout(sidtrwakeup, pp, pp->sp_dtr_wait);
137510015Speter			pp->sp_state |= SS_DTR_OFF;
137610015Speter		}
137710015Speter
137810015Speter	}
137910015Speter	pp->sp_active_out = FALSE;
138010015Speter	wakeup((caddr_t)&pp->sp_active_out);
138110015Speter	wakeup(TSA_CARR_ON(tp));
138210015Speter
138310015Speter	splx(oldspl);
138410015Speter}
138510015Speter
138610015Speter
138710015Speter/*
138810015Speter * called at splsoftclock()...
138910015Speter */
139010015Speterstatic void
139110015Spetersidtrwakeup(chan)
139210015Speter	void *chan;
139310015Speter{
139410015Speter	struct si_port *pp;
139510015Speter	int oldspl;
139610015Speter
139710015Speter	oldspl = spltty();
139810015Speter
139910015Speter	pp = (struct si_port *)chan;
140010015Speter	pp->sp_state &= ~SS_DTR_OFF;
140110015Speter	wakeup(&pp->sp_dtr_wait);
140210015Speter
140310015Speter	splx(oldspl);
140410015Speter}
140510015Speter
140610015Speter/*
140710015Speter * User level stuff - read and write
140810015Speter */
140912675Sjulianstatic	int
141010015Spetersiread(dev, uio, flag)
141110015Speter	register dev_t dev;
141210015Speter	struct uio *uio;
141310015Speter	int flag;
141410015Speter{
141510015Speter	register struct tty *tp;
141610015Speter	int mynor = minor(dev);
141710015Speter
141810015Speter	if (IS_SPECIAL(mynor)) {
141910015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_READ, "siread(CONTROLDEV!!)\n"));
142010015Speter		return(ENODEV);
142110015Speter	}
142210015Speter	tp = MINOR2TP(mynor);
142310015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_READ,
142410015Speter		"siread(%x,%x,%x)\n", dev, uio, flag));
142510015Speter	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
142610015Speter}
142710015Speter
142810015Speter
142912675Sjulianstatic	int
143010015Spetersiwrite(dev, uio, flag)
143110015Speter	dev_t dev;
143210015Speter	struct uio *uio;
143310015Speter	int flag;
143410015Speter{
143510015Speter	register struct si_port *pp;
143610015Speter	register struct tty *tp;
143710015Speter	int error = 0;
143810015Speter	int mynor = minor(dev);
143910015Speter	int oldspl;
144010015Speter
144110015Speter	if (IS_SPECIAL(mynor)) {
144210015Speter		DPRINT((0, DBG_ENTRY|DBG_FAIL|DBG_WRITE, "siwrite(CONTROLDEV!!)\n"));
144310015Speter		return(ENODEV);
144410015Speter	}
144510015Speter	pp = MINOR2PP(mynor);
144610015Speter	tp = pp->sp_tty;
144710015Speter	DPRINT((pp, DBG_WRITE, "siwrite(%x,%x,%x)\n", dev, uio, flag));
144810015Speter
144910015Speter	oldspl = spltty();
145010015Speter	/*
145110015Speter	 * If writes are currently blocked, wait on the "real" tty
145210015Speter	 */
145310015Speter	while (pp->sp_state & SS_BLOCKWRITE) {
145410015Speter		pp->sp_state |= SS_WAITWRITE;
145510015Speter		DPRINT((pp, DBG_WRITE, "in siwrite, wait for SS_BLOCKWRITE to clear\n"));
145618515Speter		if ((error = ttysleep(tp, (caddr_t)pp, TTOPRI|PCATCH,
145718515Speter				     "siwrite", tp->t_timeout))) {
145817291Speter			if (error == EWOULDBLOCK)
145917290Speter				error = EIO;
146010015Speter			goto out;
146117290Speter		}
146210015Speter	}
146310015Speter
146410015Speter	error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
146510015Speterout:
146610015Speter	splx(oldspl);
146710015Speter	return (error);
146810015Speter}
146910015Speter
147010015Speter
147112675Sjulianstatic	struct tty *
147210015Spetersidevtotty(dev_t dev)
147310015Speter{
147410015Speter	struct si_port *pp;
147510015Speter	int mynor = minor(dev);
147610015Speter	struct si_softc *sc = &si_softc[SI_CARD(mynor)];
147710015Speter
147810015Speter	if (IS_SPECIAL(mynor))
147910015Speter		return(NULL);
148010015Speter	if (SI_PORT(mynor) >= sc->sc_nport)
148110015Speter		return(NULL);
148210015Speter	pp = MINOR2PP(mynor);
148310015Speter	return (pp->sp_tty);
148410015Speter}
148510015Speter
148612675Sjulianstatic	int
148710015Spetersiioctl(dev, cmd, data, flag, p)
148810015Speter	dev_t dev;
148936735Sdfr	u_long cmd;
149010015Speter	caddr_t data;
149110015Speter	int flag;
149210015Speter	struct proc *p;
149310015Speter{
149410015Speter	struct si_port *pp;
149510015Speter	register struct tty *tp;
149610015Speter	int error;
149710015Speter	int mynor = minor(dev);
149810015Speter	int oldspl;
149910015Speter	int blocked = 0;
150010015Speter#if defined(COMPAT_43)
150138351Sbde	u_long oldcmd;
150210015Speter	struct termios term;
150310015Speter#endif
150410015Speter
150510015Speter	if (IS_SI_IOCTL(cmd))
150610015Speter		return(si_Sioctl(dev, cmd, data, flag, p));
150710015Speter
150810015Speter	pp = MINOR2PP(mynor);
150910015Speter	tp = pp->sp_tty;
151010015Speter
151138351Sbde	DPRINT((pp, DBG_ENTRY|DBG_IOCTL, "siioctl(%x,%lx,%x,%x)\n",
151210015Speter		dev, cmd, data, flag));
151310015Speter	if (IS_STATE(mynor)) {
151410015Speter		struct termios *ct;
151510015Speter
151610015Speter		switch (mynor & SI_STATE_MASK) {
151710015Speter		case SI_INIT_STATE_MASK:
151810015Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_iout : &pp->sp_iin;
151910015Speter			break;
152010015Speter		case SI_LOCK_STATE_MASK:
152116839Speter			ct = IS_CALLOUT(mynor) ? &pp->sp_lout : &pp->sp_lin;
152210015Speter			break;
152310015Speter		default:
152410015Speter			return (ENODEV);
152510015Speter		}
152610015Speter		switch (cmd) {
152710015Speter		case TIOCSETA:
152846112Sphk			error = suser(p);
152910015Speter			if (error != 0)
153010015Speter				return (error);
153110015Speter			*ct = *(struct termios *)data;
153210015Speter			return (0);
153310015Speter		case TIOCGETA:
153410015Speter			*(struct termios *)data = *ct;
153510015Speter			return (0);
153610015Speter		case TIOCGETD:
153710015Speter			*(int *)data = TTYDISC;
153810015Speter			return (0);
153910015Speter		case TIOCGWINSZ:
154010015Speter			bzero(data, sizeof(struct winsize));
154110015Speter			return (0);
154210015Speter		default:
154310015Speter			return (ENOTTY);
154410015Speter		}
154510015Speter	}
154610015Speter	/*
154710015Speter	 * Do the old-style ioctl compat routines...
154810015Speter	 */
154910015Speter#if defined(COMPAT_43)
155010015Speter	term = tp->t_termios;
155110015Speter	oldcmd = cmd;
155210015Speter	error = ttsetcompat(tp, &cmd, data, &term);
155310015Speter	if (error != 0)
155410015Speter		return (error);
155510015Speter	if (cmd != oldcmd)
155610015Speter		data = (caddr_t)&term;
155710015Speter#endif
155810015Speter	/*
155910015Speter	 * Do the initial / lock state business
156010015Speter	 */
156110015Speter	if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
156210015Speter		int     cc;
156310015Speter		struct termios *dt = (struct termios *)data;
156410015Speter		struct termios *lt = mynor & SI_CALLOUT_MASK
156510015Speter				     ? &pp->sp_lout : &pp->sp_lin;
156610015Speter
156710015Speter		dt->c_iflag = (tp->t_iflag & lt->c_iflag)
156810015Speter			| (dt->c_iflag & ~lt->c_iflag);
156910015Speter		dt->c_oflag = (tp->t_oflag & lt->c_oflag)
157010015Speter			| (dt->c_oflag & ~lt->c_oflag);
157110015Speter		dt->c_cflag = (tp->t_cflag & lt->c_cflag)
157210015Speter			| (dt->c_cflag & ~lt->c_cflag);
157310015Speter		dt->c_lflag = (tp->t_lflag & lt->c_lflag)
157410015Speter			| (dt->c_lflag & ~lt->c_lflag);
157510015Speter		for (cc = 0; cc < NCCS; ++cc)
157610015Speter			if (lt->c_cc[cc] != 0)
157710015Speter				dt->c_cc[cc] = tp->t_cc[cc];
157810015Speter		if (lt->c_ispeed != 0)
157910015Speter			dt->c_ispeed = tp->t_ispeed;
158010015Speter		if (lt->c_ospeed != 0)
158110015Speter			dt->c_ospeed = tp->t_ospeed;
158210015Speter	}
158310015Speter
158410015Speter	/*
158510015Speter	 * Block user-level writes to give the ttywait()
158610015Speter	 * a chance to completely drain for commands
158710015Speter	 * that require the port to be in a quiescent state.
158810015Speter	 */
158910015Speter	switch (cmd) {
159034832Speter	case TIOCSETAW:
159134832Speter	case TIOCSETAF:
159217396Speter	case TIOCDRAIN:
159317396Speter#ifdef COMPAT_43
159417396Speter	case TIOCSETP:
159517396Speter#endif
159610015Speter		blocked++;	/* block writes for ttywait() and siparam() */
159710015Speter		si_write_enable(pp, 0);
159810015Speter	}
159910015Speter
160010015Speter	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
160131577Sbde	if (error != ENOIOCTL)
160210015Speter		goto out;
160310015Speter
160410015Speter	oldspl = spltty();
160510015Speter
160610015Speter	error = ttioctl(tp, cmd, data, flag);
160710015Speter	si_disc_optim(tp, &tp->t_termios, pp);
160831577Sbde	if (error != ENOIOCTL)
160910015Speter		goto outspl;
161010015Speter
161110015Speter	switch (cmd) {
161210015Speter	case TIOCSBRK:
161316575Speter		si_command(pp, SBREAK, SI_WAIT);
161410015Speter		break;
161510015Speter	case TIOCCBRK:
161616575Speter		si_command(pp, EBREAK, SI_WAIT);
161710015Speter		break;
161810015Speter	case TIOCSDTR:
161910015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
162010015Speter		break;
162110015Speter	case TIOCCDTR:
162210015Speter		(void) si_modem(pp, SET, 0);
162310015Speter		break;
162410015Speter	case TIOCMSET:
162510015Speter		(void) si_modem(pp, SET, *(int *)data);
162610015Speter		break;
162710015Speter	case TIOCMBIS:
162810015Speter		(void) si_modem(pp, BIS, *(int *)data);
162910015Speter		break;
163010015Speter	case TIOCMBIC:
163110015Speter		(void) si_modem(pp, BIC, *(int *)data);
163210015Speter		break;
163310015Speter	case TIOCMGET:
163410015Speter		*(int *)data = si_modem(pp, GET, 0);
163510015Speter		break;
163610015Speter	case TIOCMSDTRWAIT:
163710015Speter		/* must be root since the wait applies to following logins */
163846112Sphk		error = suser(p);
163910015Speter		if (error != 0) {
164010015Speter			goto outspl;
164110015Speter		}
164210015Speter		pp->sp_dtr_wait = *(int *)data * hz / 100;
164310015Speter		break;
164410015Speter	case TIOCMGDTRWAIT:
164510015Speter		*(int *)data = pp->sp_dtr_wait * 100 / hz;
164610015Speter		break;
164710015Speter
164810015Speter	default:
164910015Speter		error = ENOTTY;
165010015Speter	}
165110015Speter	error = 0;
165210015Speteroutspl:
165310015Speter	splx(oldspl);
165410015Speterout:
165510015Speter	DPRINT((pp, DBG_IOCTL|DBG_EXIT, "siioctl ret %d\n", error));
165610015Speter	if (blocked)
165710015Speter		si_write_enable(pp, 1);
165810015Speter	return(error);
165910015Speter}
166010015Speter
166110015Speter/*
166210015Speter * Handle the Specialix ioctls. All MUST be called via the CONTROL device
166310015Speter */
166410015Speterstatic int
166538351Sbdesi_Sioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
166610015Speter{
166710015Speter	struct si_softc *xsc;
166810015Speter	register struct si_port *xpp;
166910015Speter	volatile struct si_reg *regp;
167010015Speter	struct si_tcsi *dp;
167110044Speter	struct si_pstat *sps;
167211872Sphk	int *ip, error = 0;
167310015Speter	int oldspl;
167410015Speter	int card, port;
167510015Speter	int mynor = minor(dev);
167610015Speter
167738351Sbde	DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%x,%lx,%x,%x)\n",
167810015Speter		dev, cmd, data, flag));
167910015Speter
168010044Speter#if 1
168110044Speter	DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
168210044Speter	DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
168310044Speter	DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
168410044Speter#endif
168510044Speter
168610015Speter	if (!IS_CONTROLDEV(mynor)) {
168710015Speter		DPRINT((0, DBG_IOCTL|DBG_FAIL, "not called from control device!\n"));
168810015Speter		return(ENODEV);
168910015Speter	}
169010015Speter
169110015Speter	oldspl = spltty();	/* better safe than sorry */
169210015Speter
169310015Speter	ip = (int *)data;
169410015Speter
169546112Sphk#define SUCHECK if ((error = suser(p))) goto out
169610015Speter
169710015Speter	switch (cmd) {
169810015Speter	case TCSIPORTS:
169910015Speter		*ip = si_Nports;
170010015Speter		goto out;
170110015Speter	case TCSIMODULES:
170210015Speter		*ip = si_Nmodules;
170310015Speter		goto out;
170410015Speter	case TCSISDBG_ALL:
170510015Speter		SUCHECK;
170610015Speter		si_debug = *ip;
170710015Speter		goto out;
170810015Speter	case TCSIGDBG_ALL:
170910015Speter		*ip = si_debug;
171010015Speter		goto out;
171110015Speter	default:
171210015Speter		/*
171310015Speter		 * Check that a controller for this port exists
171410015Speter		 */
171510044Speter
171610044Speter		/* may also be a struct si_pstat, a superset of si_tcsi */
171710044Speter
171810015Speter		dp = (struct si_tcsi *)data;
171910044Speter		sps = (struct si_pstat *)data;
172010015Speter		card = dp->tc_card;
172110015Speter		xsc = &si_softc[card];	/* check.. */
172212174Speter		if (card < 0 || card >= NSI || xsc->sc_type == SIEMPTY) {
172310015Speter			error = ENOENT;
172410015Speter			goto out;
172510015Speter		}
172610015Speter		/*
172710015Speter		 * And check that a port exists
172810015Speter		 */
172910015Speter		port = dp->tc_port;
173010015Speter		if (port < 0 || port >= xsc->sc_nport) {
173110015Speter			error = ENOENT;
173210015Speter			goto out;
173310015Speter		}
173410015Speter		xpp = xsc->sc_ports + port;
173510015Speter		regp = (struct si_reg *)xsc->sc_maddr;
173610015Speter	}
173710015Speter
173810015Speter	switch (cmd) {
173910015Speter	case TCSIDEBUG:
174010015Speter#ifdef	SI_DEBUG
174110015Speter		SUCHECK;
174210015Speter		if (xpp->sp_debug)
174310015Speter			xpp->sp_debug = 0;
174410015Speter		else {
174510015Speter			xpp->sp_debug = DBG_ALL;
174610015Speter			DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
174710015Speter				(xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
174810015Speter		}
174910015Speter		break;
175010015Speter#else
175110015Speter		error = ENODEV;
175210015Speter		goto out;
175310015Speter#endif
175410015Speter	case TCSISDBG_LEVEL:
175510015Speter	case TCSIGDBG_LEVEL:
175610015Speter#ifdef	SI_DEBUG
175710015Speter		if (cmd == TCSIGDBG_LEVEL) {
175810015Speter			dp->tc_dbglvl = xpp->sp_debug;
175910015Speter		} else {
176010015Speter			SUCHECK;
176110015Speter			xpp->sp_debug = dp->tc_dbglvl;
176210015Speter		}
176310015Speter		break;
176410015Speter#else
176510015Speter		error = ENODEV;
176610015Speter		goto out;
176710015Speter#endif
176810015Speter	case TCSIGRXIT:
176910015Speter		dp->tc_int = regp->rx_int_count;
177010015Speter		break;
177110015Speter	case TCSIRXIT:
177210015Speter		SUCHECK;
177310015Speter		regp->rx_int_count = dp->tc_int;
177410015Speter		break;
177510015Speter	case TCSIGIT:
177610015Speter		dp->tc_int = regp->int_count;
177710015Speter		break;
177810015Speter	case TCSIIT:
177910015Speter		SUCHECK;
178010015Speter		regp->int_count = dp->tc_int;
178110015Speter		break;
178210044Speter	case TCSISTATE:
178310044Speter		dp->tc_int = xpp->sp_ccb->hi_ip;
178410015Speter		break;
178510044Speter	/* these next three use a different structure */
178610044Speter	case TCSI_PORT:
178710015Speter		SUCHECK;
178834832Speter		si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport));
178910015Speter		break;
179010044Speter	case TCSI_CCB:
179110044Speter		SUCHECK;
179234832Speter		si_bcopy((char *)xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb));
179310015Speter		break;
179410044Speter	case TCSI_TTY:
179510044Speter		SUCHECK;
179634832Speter		si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty));
179710015Speter		break;
179810015Speter	default:
179910015Speter		error = EINVAL;
180010015Speter		goto out;
180110015Speter	}
180210015Speterout:
180310015Speter	splx(oldspl);
180410015Speter	return(error);		/* success */
180510015Speter}
180610015Speter
180710015Speter/*
180810015Speter *	siparam()	: Configure line params
180910015Speter *	called at spltty();
181010015Speter *	this may sleep, does not flush, nor wait for drain, nor block writes
181110015Speter *	caller must arrange this if it's important..
181210015Speter */
181312724Sphkstatic int
181410015Spetersiparam(tp, t)
181510015Speter	register struct tty *tp;
181610015Speter	register struct termios *t;
181710015Speter{
181810015Speter	register struct si_port *pp = TP2PP(tp);
181910015Speter	volatile struct si_channel *ccbp;
182010015Speter	int oldspl, cflag, iflag, oflag, lflag;
182110015Speter	int error = 0;		/* shutup gcc */
182210015Speter	int ispeed = 0;		/* shutup gcc */
182310015Speter	int ospeed = 0;		/* shutup gcc */
182410161Speter	BYTE val;
182510015Speter
182610015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
182710015Speter	cflag = t->c_cflag;
182810015Speter	iflag = t->c_iflag;
182910015Speter	oflag = t->c_oflag;
183010015Speter	lflag = t->c_lflag;
183110044Speter	DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
183210044Speter		oflag, cflag, iflag, lflag));
183310015Speter
183434832Speter	/* XXX - if Jet host and SXDC module, use extended baud rates */
183510015Speter
183610015Speter	/* if not hung up.. */
183710015Speter	if (t->c_ospeed != 0) {
183810015Speter		/* translate baud rate to firmware values */
183910015Speter		ospeed = ttspeedtab(t->c_ospeed, bdrates);
184010015Speter		ispeed = t->c_ispeed ?
184110015Speter			 ttspeedtab(t->c_ispeed, bdrates) : ospeed;
184210015Speter
184310015Speter		/* enforce legit baud rate */
184410015Speter		if (ospeed < 0 || ispeed < 0)
184510015Speter			return (EINVAL);
184610015Speter	}
184710015Speter
184810015Speter	oldspl = spltty();
184910015Speter
185010015Speter	ccbp = pp->sp_ccb;
185110015Speter
185210161Speter	/* ========== set hi_break ========== */
185310161Speter	val = 0;
185410161Speter	if (iflag & IGNBRK)		/* Breaks */
185510161Speter		val |= BR_IGN;
185610161Speter	if (iflag & BRKINT)		/* Interrupt on break? */
185710161Speter		val |= BR_INT;
185810161Speter	if (iflag & PARMRK)		/* Parity mark? */
185910161Speter		val |= BR_PARMRK;
186010161Speter	if (iflag & IGNPAR)		/* Ignore chars with parity errors? */
186110161Speter		val |= BR_PARIGN;
186210161Speter	ccbp->hi_break = val;
186310161Speter
186410161Speter	/* ========== set hi_csr ========== */
186510015Speter	/* if not hung up.. */
186610015Speter	if (t->c_ospeed != 0) {
186710015Speter		/* Set I/O speeds */
186810161Speter		 val = (ispeed << 4) | ospeed;
186910015Speter	}
187010161Speter	ccbp->hi_csr = val;
187110015Speter
187210161Speter	/* ========== set hi_mr2 ========== */
187310161Speter	val = 0;
187410015Speter	if (cflag & CSTOPB)				/* Stop bits */
187510161Speter		val |= MR2_2_STOP;
187610015Speter	else
187710161Speter		val |= MR2_1_STOP;
187810161Speter	/*
187910161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
188010161Speter	 * a DCE, hence the reverse sense of RTS and CTS
188110161Speter	 */
188210161Speter	/* Output Flow - RTS must be raised before data can be sent */
188310161Speter	if (cflag & CCTS_OFLOW)
188410161Speter		val |= MR2_RTSCONT;
188510161Speter
188616575Speter	ccbp->hi_mr2 = val;
188710161Speter
188810161Speter	/* ========== set hi_mr1 ========== */
188910161Speter	val = 0;
189010015Speter	if (!(cflag & PARENB))				/* Parity */
189110161Speter		val |= MR1_NONE;
189210015Speter	else
189310161Speter		val |= MR1_WITH;
189410015Speter	if (cflag & PARODD)
189510161Speter		val |= MR1_ODD;
189610015Speter
189710015Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
189810161Speter		val |= MR1_8_BITS;
189910015Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
190010161Speter		val |= MR1_7_BITS;
190110015Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
190210161Speter		val |= MR1_6_BITS;
190310015Speter	} else {					/* Must be 5 */
190410161Speter		val |= MR1_5_BITS;
190510015Speter	}
190610161Speter	/*
190710161Speter	 * Enable H/W RTS/CTS handshaking. The default TA/MTA is
190810161Speter	 * a DCE, hence the reverse sense of RTS and CTS
190910161Speter	 */
191010161Speter	/* Input Flow - CTS is raised when port is ready to receive data */
191110161Speter	if (cflag & CRTS_IFLOW)
191210161Speter		val |= MR1_CTSCONT;
191310015Speter
191410161Speter	ccbp->hi_mr1 = val;
191510161Speter
191610161Speter	/* ========== set hi_mask ========== */
191710161Speter	val = 0xff;
191810161Speter	if ((cflag & CS8) == CS8) {			/* 8 data bits? */
191910161Speter		val &= 0xFF;
192010161Speter	} else if ((cflag & CS7) == CS7) {		/* 7 data bits? */
192110161Speter		val &= 0x7F;
192210161Speter	} else if ((cflag & CS6) == CS6) {		/* 6 data bits? */
192310161Speter		val &= 0x3F;
192410161Speter	} else {					/* Must be 5 */
192510161Speter		val &= 0x1F;
192610161Speter	}
192710015Speter	if (iflag & ISTRIP)
192810161Speter		val &= 0x7F;
192910015Speter
193010161Speter	ccbp->hi_mask = val;
193110161Speter
193210161Speter	/* ========== set hi_prtcl ========== */
193310161Speter	val = 0;
193410015Speter				/* Monitor DCD etc. if a modem */
193510015Speter	if (!(cflag & CLOCAL))
193610161Speter		val |= SP_DCEN;
193710161Speter	if (iflag & IXANY)
193810161Speter		val |= SP_TANY;
193910161Speter	if (iflag & IXON)
194010161Speter		val |= SP_TXEN;
194110161Speter	if (iflag & IXOFF)
194210161Speter		val |= SP_RXEN;
194310161Speter	if (iflag & INPCK)
194410161Speter		val |= SP_PAEN;
194510015Speter
194610161Speter	ccbp->hi_prtcl = val;
194710161Speter
194810161Speter
194910161Speter	/* ========== set hi_{rx|tx}{on|off} ========== */
195010161Speter	/* XXX: the card TOTALLY shields us from the flow control... */
195110015Speter	ccbp->hi_txon = t->c_cc[VSTART];
195210015Speter	ccbp->hi_txoff = t->c_cc[VSTOP];
195310015Speter
195410015Speter	ccbp->hi_rxon = t->c_cc[VSTART];
195510015Speter	ccbp->hi_rxoff = t->c_cc[VSTOP];
195610015Speter
195710161Speter	/* ========== send settings to the card ========== */
195810015Speter	/* potential sleep here */
195910015Speter	if (ccbp->hi_stat == IDLE_CLOSE)		/* Not yet open */
196010015Speter		si_command(pp, LOPEN, SI_WAIT);		/* open it */
196110015Speter	else
196210015Speter		si_command(pp, CONFIG, SI_WAIT);	/* change params */
196310015Speter
196410161Speter	/* ========== set DTR etc ========== */
196510015Speter	/* Hangup if ospeed == 0 */
196610015Speter	if (t->c_ospeed == 0) {
196710015Speter		(void) si_modem(pp, BIC, TIOCM_DTR|TIOCM_RTS);
196810015Speter	} else {
196910015Speter		/*
197010015Speter		 * If the previous speed was 0, may need to re-enable
197134832Speter		 * the modem signals
197234832Speter		 */
197310015Speter		(void) si_modem(pp, SET, TIOCM_DTR|TIOCM_RTS);
197410015Speter	}
197510015Speter
197610044Speter	DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
197710044Speter		ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
197810015Speter
197910015Speter	splx(oldspl);
198010015Speter	return(error);
198110015Speter}
198210015Speter
198310015Speter/*
198410015Speter * Enable or Disable the writes to this channel...
198510015Speter * "state" ->  enabled = 1; disabled = 0;
198610015Speter */
198710015Speterstatic void
198810015Spetersi_write_enable(pp, state)
198910015Speter	register struct si_port *pp;
199010015Speter	int state;
199110015Speter{
199210015Speter	int oldspl;
199310015Speter
199410015Speter	oldspl = spltty();
199510015Speter
199610015Speter	if (state) {
199710015Speter		pp->sp_state &= ~SS_BLOCKWRITE;
199810015Speter		if (pp->sp_state & SS_WAITWRITE) {
199910015Speter			pp->sp_state &= ~SS_WAITWRITE;
200010015Speter			/* thunder away! */
200110015Speter			wakeup((caddr_t)pp);
200210015Speter		}
200310015Speter	} else {
200410015Speter		pp->sp_state |= SS_BLOCKWRITE;
200510015Speter	}
200610015Speter
200710015Speter	splx(oldspl);
200810015Speter}
200910015Speter
201010015Speter/*
201110015Speter * Set/Get state of modem control lines.
201210015Speter * Due to DCE-like behaviour of the adapter, some signals need translation:
201310015Speter *	TIOCM_DTR	DSR
201410015Speter *	TIOCM_RTS	CTS
201510015Speter */
201610015Speterstatic int
201710015Spetersi_modem(pp, cmd, bits)
201810015Speter	struct si_port *pp;
201910015Speter	enum si_mctl cmd;
202010015Speter	int bits;
202110015Speter{
202210015Speter	volatile struct si_channel *ccbp;
202310015Speter	int x;
202410015Speter
202510015Speter	DPRINT((pp, DBG_ENTRY|DBG_MODEM, "si_modem(%x,%s,%x)\n", pp, si_mctl2str(cmd), bits));
202610015Speter	ccbp = pp->sp_ccb;		/* Find channel address */
202710015Speter	switch (cmd) {
202810015Speter	case GET:
202910015Speter		x = ccbp->hi_ip;
203010015Speter		bits = TIOCM_LE;
203110015Speter		if (x & IP_DCD)		bits |= TIOCM_CAR;
203210015Speter		if (x & IP_DTR)		bits |= TIOCM_DTR;
203310015Speter		if (x & IP_RTS)		bits |= TIOCM_RTS;
203410015Speter		if (x & IP_RI)		bits |= TIOCM_RI;
203510015Speter		return(bits);
203610015Speter	case SET:
203710015Speter		ccbp->hi_op &= ~(OP_DSR|OP_CTS);
203810015Speter		/* fall through */
203910015Speter	case BIS:
204010015Speter		x = 0;
204110015Speter		if (bits & TIOCM_DTR)
204210015Speter			x |= OP_DSR;
204310015Speter		if (bits & TIOCM_RTS)
204410015Speter			x |= OP_CTS;
204510015Speter		ccbp->hi_op |= x;
204610015Speter		break;
204710015Speter	case BIC:
204810015Speter		if (bits & TIOCM_DTR)
204910015Speter			ccbp->hi_op &= ~OP_DSR;
205010015Speter		if (bits & TIOCM_RTS)
205110015Speter			ccbp->hi_op &= ~OP_CTS;
205210015Speter	}
205310015Speter	return 0;
205410015Speter}
205510015Speter
205610015Speter/*
205710015Speter * Handle change of modem state
205810015Speter */
205910015Speterstatic void
206010015Spetersi_modem_state(pp, tp, hi_ip)
206110015Speter	register struct si_port *pp;
206210015Speter	register struct tty *tp;
206310015Speter	register int hi_ip;
206410015Speter{
206510015Speter							/* if a modem dev */
206610015Speter	if (hi_ip & IP_DCD) {
206710015Speter		if ( !(pp->sp_last_hi_ip & IP_DCD)) {
206810015Speter			DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
206910015Speter				tp->t_line));
207010015Speter			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
207110015Speter		}
207210015Speter	} else {
207310015Speter		if (pp->sp_last_hi_ip & IP_DCD) {
207410015Speter			DPRINT((pp, DBG_INTR, "modem carr off\n"));
207510015Speter			if ((*linesw[tp->t_line].l_modem)(tp, 0))
207610015Speter				(void) si_modem(pp, SET, 0);
207710015Speter		}
207810015Speter	}
207910015Speter	pp->sp_last_hi_ip = hi_ip;
208010015Speter
208110015Speter}
208210015Speter
208310015Speter/*
208410015Speter * Poller to catch missed interrupts.
208512174Speter *
208612496Speter * Note that the SYSV Specialix drivers poll at 100 times per second to get
208712496Speter * better response.  We could really use a "periodic" version timeout(). :-)
208810015Speter */
208910015Speter#ifdef POLL
209010708Speterstatic void
209110015Spetersi_poll(void *nothing)
209210015Speter{
209310015Speter	register struct si_softc *sc;
209410015Speter	register int i;
209510015Speter	volatile struct si_reg *regp;
209612174Speter	register struct si_port *pp;
209712174Speter	int lost, oldspl, port;
209810015Speter
209910015Speter	DPRINT((0, DBG_POLL, "si_poll()\n"));
210011609Speter	oldspl = spltty();
210110015Speter	if (in_intr)
210210015Speter		goto out;
210310015Speter	lost = 0;
210410015Speter	for (i=0; i<NSI; i++) {
210510015Speter		sc = &si_softc[i];
210612174Speter		if (sc->sc_type == SIEMPTY)
210710015Speter			continue;
210810015Speter		regp = (struct si_reg *)sc->sc_maddr;
210934832Speter
211010015Speter		/*
211110015Speter		 * See if there has been a pending interrupt for 2 seconds
211233395Speter		 * or so. The test (int_scounter >= 200) won't correspond
211310015Speter		 * to 2 seconds if int_count gets changed.
211410015Speter		 */
211510015Speter		if (regp->int_pending != 0) {
211610015Speter			if (regp->int_scounter >= 200 &&
211710015Speter			    regp->initstat == 1) {
211812174Speter				printf("si%d: lost intr\n", i);
211910015Speter				lost++;
212010015Speter			}
212110015Speter		} else {
212210015Speter			regp->int_scounter = 0;
212310015Speter		}
212410015Speter
212512174Speter		/*
212612174Speter		 * gripe about no input flow control..
212712174Speter		 */
212812174Speter		pp = sc->sc_ports;
212912174Speter		for (port = 0; port < sc->sc_nport; pp++, port++) {
213012174Speter			if (pp->sp_delta_overflows > 0) {
213112174Speter				printf("si%d: %d tty level buffer overflows\n",
213212174Speter					i, pp->sp_delta_overflows);
213312174Speter				pp->sp_delta_overflows = 0;
213412174Speter			}
213512174Speter		}
213610015Speter	}
213717547Speter	if (lost || si_realpoll)
213834735Speter		si_intr(-1);	/* call intr with fake vector */
213911609Speterout:
214010015Speter	splx(oldspl);
214110015Speter
214215639Speter	timeout(si_poll, (caddr_t)0L, si_pollrate);
214310015Speter}
214410015Speter#endif	/* ifdef POLL */
214510015Speter
214610015Speter/*
214710015Speter * The interrupt handler polls ALL ports on ALL adapters each time
214810015Speter * it is called.
214910015Speter */
215010015Speter
215112496Speterstatic BYTE si_rxbuf[SI_BUFFERSIZE];	/* input staging area */
215234832Speterstatic BYTE si_txbuf[SI_BUFFERSIZE];	/* output staging area */
215310015Speter
215434735Speterstatic void
215534735Spetersi_intr(int unit)
215610015Speter{
215710015Speter	register struct si_softc *sc;
215810015Speter
215910015Speter	register struct si_port *pp;
216010015Speter	volatile struct si_channel *ccbp;
216110015Speter	register struct tty *tp;
216210015Speter	volatile caddr_t maddr;
216311872Sphk	BYTE op, ip;
216412174Speter	int x, card, port, n, i, isopen;
216510015Speter	volatile BYTE *z;
216610015Speter	BYTE c;
216710015Speter
216834735Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "si_intr(%d)\n", unit));
216911609Speter	if (in_intr) {
217011609Speter		if (unit < 0)	/* should never happen */
217134832Speter			printf("si%d: Warning poll entered during interrupt\n",
217234832Speter				unit);
217334832Speter		else
217434832Speter			printf("si%d: Warning interrupt handler re-entered\n",
217534832Speter				unit);
217610708Speter		return;
217710015Speter	}
217810015Speter	in_intr = 1;
217910015Speter
218010015Speter	/*
218110015Speter	 * When we get an int we poll all the channels and do ALL pending
218210015Speter	 * work, not just the first one we find. This allows all cards to
218310015Speter	 * share the same vector.
218434832Speter	 *
218534832Speter	 * XXX - But if we're sharing the vector with something that's NOT
218634832Speter	 * a SI/XIO/SX card, we may be making more work for ourselves.
218710015Speter	 */
218834832Speter	for (card = 0; card < NSI; card++) {
218910015Speter		sc = &si_softc[card];
219012174Speter		if (sc->sc_type == SIEMPTY)
219110015Speter			continue;
219212174Speter
219312174Speter		/*
219412174Speter		 * First, clear the interrupt
219512174Speter		 */
219610015Speter		switch(sc->sc_type) {
219734832Speter		case SIHOST:
219810015Speter			maddr = sc->sc_maddr;
219910015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
220010015Speter							/* flag nothing pending */
220110015Speter			*(maddr+SIINTCL) = 0x00;	/* Set IRQ clear */
220210015Speter			*(maddr+SIINTCL_CL) = 0x00;	/* Clear IRQ clear */
220310015Speter			break;
220410015Speter		case SIHOST2:
220510015Speter			maddr = sc->sc_maddr;
220610015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
220710015Speter			*(maddr+SIPLIRQCLR) = 0x00;
220810015Speter			*(maddr+SIPLIRQCLR) = 0x10;
220910015Speter			break;
221034832Speter#if NPCI > 0
221133395Speter		case SIPCI:
221233395Speter			maddr = sc->sc_maddr;
221333395Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
221433395Speter			*(maddr+SIPCIINTCL) = 0x0;
221533395Speter			break;
221634832Speter		case SIJETPCI:	/* fall through to JETISA case */
221734832Speter#endif
221833395Speter		case SIJETISA:
221933395Speter			maddr = sc->sc_maddr;
222033395Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
222133395Speter			*(maddr+SIJETINTCL) = 0x0;
222233395Speter			break;
222334832Speter#if NEISA > 0
222410015Speter		case SIEISA:
222510015Speter			maddr = sc->sc_maddr;
222610015Speter			((volatile struct si_reg *)maddr)->int_pending = 0;
222734832Speter			(void)inb(sc->sc_eisa_iobase + 3);
222810015Speter			break;
222934832Speter#endif
223010015Speter		case SIEMPTY:
223110015Speter		default:
223210015Speter			continue;
223310015Speter		}
223410015Speter		((volatile struct si_reg *)maddr)->int_scounter = 0;
223510015Speter
223612174Speter		/*
223712174Speter		 * check each port
223812174Speter		 */
223934832Speter		for (pp = sc->sc_ports, port=0; port < sc->sc_nport;
224034832Speter		     pp++, port++) {
224110015Speter			ccbp = pp->sp_ccb;
224210015Speter			tp = pp->sp_tty;
224310015Speter
224410015Speter			/*
224510015Speter			 * See if a command has completed ?
224610015Speter			 */
224710015Speter			if (ccbp->hi_stat != pp->sp_pend) {
224810015Speter				DPRINT((pp, DBG_INTR,
224934735Speter					"si_intr hi_stat = 0x%x, pend = %d\n",
225010015Speter					ccbp->hi_stat, pp->sp_pend));
225110015Speter				switch(pp->sp_pend) {
225210015Speter				case LOPEN:
225310015Speter				case MPEND:
225410015Speter				case MOPEN:
225510015Speter				case CONFIG:
225616575Speter				case SBREAK:
225716575Speter				case EBREAK:
225810015Speter					pp->sp_pend = ccbp->hi_stat;
225910015Speter						/* sleeping in si_command */
226010015Speter					wakeup(&pp->sp_state);
226110015Speter					break;
226210015Speter				default:
226310015Speter					pp->sp_pend = ccbp->hi_stat;
226410015Speter				}
226534832Speter			}
226610015Speter
226710015Speter			/*
226810015Speter			 * Continue on if it's closed
226910015Speter			 */
227010015Speter			if (ccbp->hi_stat == IDLE_CLOSE) {
227110015Speter				continue;
227210015Speter			}
227310015Speter
227410015Speter			/*
227510015Speter			 * Do modem state change if not a local device
227610015Speter			 */
227710015Speter			si_modem_state(pp, tp, ccbp->hi_ip);
227810015Speter
227910015Speter			/*
228034832Speter			 * Check to see if we should 'receive' characters.
228112174Speter			 */
228212174Speter			if (tp->t_state & TS_CONNECTED &&
228312174Speter			    tp->t_state & TS_ISOPEN)
228412174Speter				isopen = 1;
228512174Speter			else
228612174Speter				isopen = 0;
228712174Speter
228812174Speter			/*
228916575Speter			 * Do input break processing
229010015Speter			 */
229110015Speter			if (ccbp->hi_state & ST_BREAK) {
229212174Speter				if (isopen) {
229312174Speter				    (*linesw[tp->t_line].l_rint)(TTY_BI, tp);
229410015Speter				}
229510015Speter				ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
229610015Speter				DPRINT((pp, DBG_INTR, "si_intr break\n"));
229710015Speter			}
229810015Speter
229910015Speter			/*
230012174Speter			 * Do RX stuff - if not open then dump any characters.
230112174Speter			 * XXX: This is VERY messy and needs to be cleaned up.
230212174Speter			 *
230312174Speter			 * XXX: can we leave data in the host adapter buffer
230412174Speter			 * when the clists are full?  That may be dangerous
230512174Speter			 * if the user cannot get an interrupt signal through.
230610015Speter			 */
230710015Speter
230812174Speter	more_rx:	/* XXX Sorry. the nesting was driving me bats! :-( */
230912174Speter
231012174Speter			if (!isopen) {
231110015Speter				ccbp->hi_rxopos = ccbp->hi_rxipos;
231212174Speter				goto end_rx;
231312174Speter			}
231410015Speter
231512174Speter			/*
231615640Speter			 * If the tty input buffers are blocked, stop emptying
231715640Speter			 * the incoming buffers and let the auto flow control
231815640Speter			 * assert..
231915640Speter			 */
232015640Speter			if (tp->t_state & TS_TBLOCK) {
232115640Speter				goto end_rx;
232215640Speter			}
232315640Speter
232415640Speter			/*
232512174Speter			 * Process read characters if not skipped above
232612174Speter			 */
232715640Speter			op = ccbp->hi_rxopos;
232815640Speter			ip = ccbp->hi_rxipos;
232915640Speter			c = ip - op;
233012174Speter			if (c == 0) {
233112174Speter				goto end_rx;
233212174Speter			}
233310015Speter
233412174Speter			n = c & 0xff;
233515640Speter			if (n > 250)
233615640Speter				n = 250;
233712174Speter
233812174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
233910015Speter						n, op, ip));
234010015Speter
234112174Speter			/*
234212174Speter			 * Suck characters out of host card buffer into the
234312174Speter			 * "input staging buffer" - so that we dont leave the
234412174Speter			 * host card in limbo while we're possibly echoing
234512174Speter			 * characters and possibly flushing input inside the
234612174Speter			 * ldisc l_rint() routine.
234712174Speter			 */
234812496Speter			if (n <= SI_BUFFERSIZE - op) {
234910015Speter
235012174Speter				DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
235112174Speter				z = ccbp->hi_rxbuf + op;
235234832Speter				si_bcopy((caddr_t)z, si_rxbuf, n);
235310015Speter
235412174Speter				op += n;
235512174Speter			} else {
235612496Speter				x = SI_BUFFERSIZE - op;
235710015Speter
235812174Speter				DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
235912174Speter				z = ccbp->hi_rxbuf + op;
236034832Speter				si_bcopy((caddr_t)z, si_rxbuf, x);
236110015Speter
236234832Speter				DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n",
236334832Speter					n - x));
236412174Speter				z = ccbp->hi_rxbuf;
236534832Speter				si_bcopy((caddr_t)z, si_rxbuf + x, n - x);
236610015Speter
236712174Speter				op += n;
236812174Speter			}
236910015Speter
237012174Speter			/* clear collected characters from buffer */
237112174Speter			ccbp->hi_rxopos = op;
237212174Speter
237312174Speter			DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
237410015Speter						n, op, ip));
237510015Speter
237612174Speter			/*
237712174Speter			 * at this point...
237812174Speter			 * n = number of chars placed in si_rxbuf
237912174Speter			 */
238010015Speter
238112174Speter			/*
238212174Speter			 * Avoid the grotesquely inefficient lineswitch
238312174Speter			 * routine (ttyinput) in "raw" mode. It usually
238412174Speter			 * takes about 450 instructions (that's without
238512174Speter			 * canonical processing or echo!). slinput is
238612174Speter			 * reasonably fast (usually 40 instructions
238712174Speter			 * plus call overhead).
238812174Speter			 */
238912174Speter			if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
239010015Speter
239112174Speter				/* block if the driver supports it */
239212174Speter				if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER
239312174Speter				    && (tp->t_cflag & CRTS_IFLOW
239412174Speter					|| tp->t_iflag & IXOFF)
239512174Speter				    && !(tp->t_state & TS_TBLOCK))
239612174Speter					ttyblock(tp);
239710015Speter
239812174Speter				tk_nin += n;
239912174Speter				tk_rawcc += n;
240012174Speter				tp->t_rawcc += n;
240112174Speter
240212174Speter				pp->sp_delta_overflows +=
240312174Speter				    b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
240412174Speter
240512174Speter				ttwakeup(tp);
240612174Speter				if (tp->t_state & TS_TTSTOP
240712174Speter				    && (tp->t_iflag & IXANY
240812174Speter					|| tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
240912174Speter					tp->t_state &= ~TS_TTSTOP;
241012174Speter					tp->t_lflag &= ~FLUSHO;
241112174Speter					si_start(tp);
241212174Speter				}
241312174Speter			} else {
241412174Speter				/*
241512174Speter				 * It'd be nice to not have to go through the
241612174Speter				 * function call overhead for each char here.
241712174Speter				 * It'd be nice to block input it, saving a
241812174Speter				 * loop here and the call/return overhead.
241912174Speter				 */
242012174Speter				for(x = 0; x < n; x++) {
242112174Speter					i = si_rxbuf[x];
242212174Speter					if ((*linesw[tp->t_line].l_rint)(i, tp)
242312174Speter					     == -1) {
242412174Speter						pp->sp_delta_overflows++;
242510015Speter					}
242612174Speter					/*
242712174Speter					 * doesn't seem to be much point doing
242812174Speter					 * this here.. this driver has no
242912174Speter					 * softtty processing! ??
243012174Speter					 */
243112174Speter					if (pp->sp_hotchar && i == pp->sp_hotchar) {
243212174Speter						setsofttty();
243312174Speter					}
243412174Speter				}
243512174Speter			}
243612174Speter			goto more_rx;	/* try for more until RXbuf is empty */
243710015Speter
243812174Speter	end_rx:		/* XXX: Again, sorry about the gotos.. :-) */
243910015Speter
244010015Speter			/*
244110015Speter			 * Do TX stuff
244210015Speter			 */
244310015Speter			(*linesw[tp->t_line].l_start)(tp);
244410015Speter
244510015Speter		} /* end of for (all ports on this controller) */
244610015Speter	} /* end of for (all controllers) */
244710015Speter
244811609Speter	in_intr = 0;
244934735Speter	DPRINT((0, (unit < 0) ? DBG_POLL:DBG_INTR, "end si_intr(%d)\n", unit));
245010015Speter}
245110015Speter
245210015Speter/*
245310015Speter * Nudge the transmitter...
245412174Speter *
245512174Speter * XXX: I inherited some funny code here.  It implies the host card only
245612174Speter * interrupts when the transmit buffer reaches the low-water-mark, and does
245712174Speter * not interrupt when it's actually hits empty.  In some cases, we have
245812174Speter * processes waiting for complete drain, and we need to simulate an interrupt
245912174Speter * about when we think the buffer is going to be empty (and retry if not).
246012174Speter * I really am not certain about this...  I *need* the hardware manuals.
246110015Speter */
246210015Speterstatic void
246310015Spetersi_start(tp)
246410015Speter	register struct tty *tp;
246510015Speter{
246610015Speter	struct si_port *pp;
246710015Speter	volatile struct si_channel *ccbp;
246810015Speter	register struct clist *qp;
246910015Speter	BYTE ipos;
247010015Speter	int nchar;
247110015Speter	int oldspl, count, n, amount, buffer_full;
247210015Speter
247310015Speter	oldspl = spltty();
247410015Speter
247510015Speter	qp = &tp->t_outq;
247610015Speter	pp = TP2PP(tp);
247710015Speter
247810015Speter	DPRINT((pp, DBG_ENTRY|DBG_START,
247910015Speter		"si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
248010015Speter		tp, tp->t_state, pp->sp_state, qp->c_cc));
248110015Speter
248210015Speter	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
248310015Speter		goto out;
248410015Speter
248510015Speter	buffer_full = 0;
248610015Speter	ccbp = pp->sp_ccb;
248710015Speter
248810015Speter	count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
248910015Speter	DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
249010015Speter
249110015Speter	while ((nchar = qp->c_cc) > 0) {
249210015Speter		if ((BYTE)count >= 255) {
249310015Speter			buffer_full++;
249410015Speter			break;
249510015Speter		}
249610015Speter		amount = min(nchar, (255 - (BYTE)count));
249710015Speter		ipos = (unsigned int)ccbp->hi_txipos;
249834832Speter		n = q_to_b(&tp->t_outq, si_txbuf, amount);
249910015Speter		/* will it fit in one lump? */
250034832Speter		if ((SI_BUFFERSIZE - ipos) >= n) {
250134832Speter			si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos], n);
250210015Speter		} else {
250334832Speter			si_bcopy(si_txbuf, (char *)&ccbp->hi_txbuf[ipos],
250434832Speter				SI_BUFFERSIZE - ipos);
250534832Speter			si_bcopy(si_txbuf + (SI_BUFFERSIZE - ipos),
250634832Speter				(char *)&ccbp->hi_txbuf[0],
250734832Speter				n - (SI_BUFFERSIZE - ipos));
250810015Speter		}
250910015Speter		ccbp->hi_txipos += n;
251010015Speter		count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
251110015Speter	}
251210015Speter
251310015Speter	if (count != 0 && nchar == 0) {
251410015Speter		tp->t_state |= TS_BUSY;
251510015Speter	} else {
251610015Speter		tp->t_state &= ~TS_BUSY;
251710015Speter	}
251810015Speter
251910015Speter	/* wakeup time? */
252010015Speter	ttwwakeup(tp);
252110015Speter
252210015Speter	DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
252310015Speter		(BYTE)count, nchar, tp->t_state));
252410015Speter
252534735Speter	if (tp->t_state & TS_BUSY)
252610015Speter	{
252710015Speter		int time;
252810015Speter
252934735Speter		time = ttspeedtab(tp->t_ospeed, chartimes);
253034735Speter
253134735Speter		if (time > 0) {
253234735Speter			if (time < nchar)
253334735Speter				time = nchar / time;
253434735Speter			else
253534735Speter				time = 2;
253610015Speter		} else {
253734735Speter			DPRINT((pp, DBG_START,
253834735Speter				"bad char time value! %d\n", time));
253934735Speter			time = hz/10;
254010015Speter		}
254110015Speter
254210015Speter		if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
254329677Sgibbs			untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
254410015Speter		} else {
254510015Speter			pp->sp_state |= SS_LSTART;
254610015Speter		}
254710015Speter		DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
254829677Sgibbs		pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time);
254910015Speter	}
255010015Speter
255110015Speterout:
255210015Speter	splx(oldspl);
255310015Speter	DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
255410015Speter}
255510015Speter
255610015Speter/*
255710015Speter * Note: called at splsoftclock from the timeout code
255810015Speter * This has to deal with two things...  cause wakeups while waiting for
255910015Speter * tty drains on last process exit, and call l_start at about the right
256010015Speter * time for protocols like ppp.
256110015Speter */
256210015Speterstatic void
256325047Sbdesi_lstart(void *arg)
256410015Speter{
256525047Sbde	register struct si_port *pp = arg;
256610015Speter	register struct tty *tp;
256710015Speter	int oldspl;
256810015Speter
256910015Speter	DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
257010015Speter		pp, pp->sp_state));
257110015Speter
257210015Speter	oldspl = spltty();
257310015Speter
257410015Speter	if ((pp->sp_state & SS_OPEN) == 0 || (pp->sp_state & SS_LSTART) == 0) {
257510015Speter		splx(oldspl);
257610015Speter		return;
257710015Speter	}
257810015Speter	pp->sp_state &= ~SS_LSTART;
257910015Speter	pp->sp_state |= SS_INLSTART;
258010015Speter
258110015Speter	tp = pp->sp_tty;
258210015Speter
258310015Speter	/* deal with the process exit case */
258410015Speter	ttwwakeup(tp);
258510015Speter
258612174Speter	/* nudge protocols - eg: ppp */
258710015Speter	(*linesw[tp->t_line].l_start)(tp);
258810015Speter
258910015Speter	pp->sp_state &= ~SS_INLSTART;
259010015Speter	splx(oldspl);
259110015Speter}
259210015Speter
259310015Speter/*
259410015Speter * Stop output on a line. called at spltty();
259510015Speter */
259610015Spetervoid
259710015Spetersistop(tp, rw)
259810015Speter	register struct tty *tp;
259910015Speter	int rw;
260010015Speter{
260110015Speter	volatile struct si_channel *ccbp;
260210015Speter	struct si_port *pp;
260310015Speter
260410015Speter	pp = TP2PP(tp);
260510015Speter	ccbp = pp->sp_ccb;
260610015Speter
260710015Speter	DPRINT((TP2PP(tp), DBG_ENTRY|DBG_STOP, "sistop(%x,%x)\n", tp, rw));
260810015Speter
260910015Speter	/* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
261010015Speter	if (rw & FWRITE) {
261110015Speter		/* what level are we meant to be flushing anyway? */
261210015Speter		if (tp->t_state & TS_BUSY) {
261310015Speter			si_command(TP2PP(tp), WFLUSH, SI_NOWAIT);
261410015Speter			tp->t_state &= ~TS_BUSY;
261510015Speter			ttwwakeup(tp);	/* Bruce???? */
261610015Speter		}
261710015Speter	}
261812174Speter#if 1	/* XXX: this doesn't work right yet.. */
261912174Speter	/* XXX: this may have been failing because we used to call l_rint()
262012174Speter	 * while we were looping based on these two counters. Now, we collect
262112174Speter	 * the data and then loop stuffing it into l_rint(), making this
262212174Speter	 * useless.  Should we cause this to blow away the staging buffer?
262312174Speter	 */
262410015Speter	if (rw & FREAD) {
262510015Speter		ccbp->hi_rxopos = ccbp->hi_rxipos;
262610015Speter	}
262710015Speter#endif
262810015Speter}
262910015Speter
263010015Speter/*
263134832Speter * Issue a command to the host card CPU.
263210015Speter */
263310015Speter
263410015Speterstatic void
263510015Spetersi_command(pp, cmd, waitflag)
263610015Speter	struct si_port *pp;		/* port control block (local) */
263710015Speter	int cmd;
263810015Speter	int waitflag;
263910015Speter{
264010015Speter	int oldspl;
264110015Speter	volatile struct si_channel *ccbp = pp->sp_ccb;
264210015Speter	int x;
264310015Speter
264410015Speter	DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
264510015Speter		pp, cmd, waitflag, ccbp->hi_stat));
264610015Speter
264710015Speter	oldspl = spltty();		/* Keep others out */
264810015Speter
264910015Speter	/* wait until it's finished what it was doing.. */
265016575Speter	/* XXX: sits in IDLE_BREAK until something disturbs it or break
265116575Speter	 * is turned off. */
265210015Speter	while((x = ccbp->hi_stat) != IDLE_OPEN &&
265310015Speter			x != IDLE_CLOSE &&
265416575Speter			x != IDLE_BREAK &&
265510015Speter			x != cmd) {
265610015Speter		if (in_intr) {			/* Prevent sleep in intr */
265710015Speter			DPRINT((pp, DBG_PARAM,
265810015Speter				"cmd intr collision - completing %d\trequested %d\n",
265910015Speter				x, cmd));
266010015Speter			splx(oldspl);
266110015Speter			return;
266210015Speter		} else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
266310015Speter				"sicmd1", 1)) {
266410015Speter			splx(oldspl);
266510015Speter			return;
266610015Speter		}
266710015Speter	}
266816575Speter	/* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */
266910015Speter
267010015Speter	/* if there was a pending command, cause a state-change wakeup */
267116575Speter	switch(pp->sp_pend) {
267216575Speter	case LOPEN:
267316575Speter	case MPEND:
267416575Speter	case MOPEN:
267516575Speter	case CONFIG:
267616575Speter	case SBREAK:
267716575Speter	case EBREAK:
267816575Speter		wakeup(&pp->sp_state);
267916575Speter		break;
268016575Speter	default:
268116575Speter		break;
268210015Speter	}
268310015Speter
268410015Speter	pp->sp_pend = cmd;		/* New command pending */
268510015Speter	ccbp->hi_stat = cmd;		/* Post it */
268610015Speter
268710015Speter	if (waitflag) {
268810015Speter		if (in_intr) {		/* If in interrupt handler */
268910015Speter			DPRINT((pp, DBG_PARAM,
269010015Speter				"attempt to sleep in si_intr - cmd req %d\n",
269110015Speter				cmd));
269210015Speter			splx(oldspl);
269310015Speter			return;
269416575Speter		} else while(ccbp->hi_stat != IDLE_OPEN &&
269516575Speter			     ccbp->hi_stat != IDLE_BREAK) {
269610015Speter			if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
269710015Speter			    "sicmd2", 0))
269810015Speter				break;
269910015Speter		}
270010015Speter	}
270110015Speter	splx(oldspl);
270210015Speter}
270310015Speter
270410015Speterstatic void
270510015Spetersi_disc_optim(tp, t, pp)
270610015Speter	struct tty	*tp;
270710015Speter	struct termios	*t;
270810015Speter	struct si_port	*pp;
270910015Speter{
271010015Speter	/*
271110015Speter	 * XXX can skip a lot more cases if Smarts.  Maybe
271210015Speter	 * (IGNCR | ISTRIP | IXON) in c_iflag.  But perhaps we
271310015Speter	 * shouldn't skip if (TS_CNTTB | TS_LNCH) is set in t_state.
271410015Speter	 */
271510015Speter	if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
271610015Speter	    && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
271710015Speter	    && (!(t->c_iflag & PARMRK)
271810015Speter		|| (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
271910015Speter	    && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
272010015Speter	    && linesw[tp->t_line].l_rint == ttyinput)
272110015Speter		tp->t_state |= TS_CAN_BYPASS_L_RINT;
272210015Speter	else
272310015Speter		tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
272433322Sphk	pp->sp_hotchar = linesw[tp->t_line].l_hotchar;
272510161Speter	DPRINT((pp, DBG_OPTIM, "bypass: %s, hotchar: %x\n",
272610161Speter		(tp->t_state & TS_CAN_BYPASS_L_RINT) ? "on" : "off",
272710161Speter		pp->sp_hotchar));
272810015Speter}
272910015Speter
273010015Speter
273110015Speter#ifdef	SI_DEBUG
273213353Speter
273310015Speterstatic void
273413353Speter#ifdef __STDC__
273513353Spetersi_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
273613353Speter#else
273713353Spetersi_dprintf(pp, flags, fmt, va_alist)
273810015Speter	struct si_port *pp;
273910015Speter	int flags;
274013353Speter	char *fmt;
274113353Speter#endif
274210015Speter{
274313353Speter	va_list ap;
274413630Sphk
274510015Speter	if ((pp == NULL && (si_debug&flags)) ||
274610015Speter	    (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
274734832Speter		if (pp != NULL)
274834832Speter			printf("%ci%d(%d): ", 's',
274934832Speter				(int)SI_CARD(pp->sp_tty->t_dev),
275034832Speter				(int)SI_PORT(pp->sp_tty->t_dev));
275113630Sphk		va_start(ap, fmt);
275213630Sphk		vprintf(fmt, ap);
275313353Speter		va_end(ap);
275410015Speter	}
275510015Speter}
275610015Speter
275710015Speterstatic char *
275810015Spetersi_mctl2str(cmd)
275910015Speter	enum si_mctl cmd;
276010015Speter{
276110015Speter	switch (cmd) {
276234832Speter	case GET:
276334832Speter		return("GET");
276434832Speter	case SET:
276534832Speter		return("SET");
276634832Speter	case BIS:
276734832Speter		return("BIS");
276834832Speter	case BIC:
276934832Speter		return("BIC");
277010015Speter	}
277110015Speter	return("BAD");
277210015Speter}
277312502Sjulian
277412624Speter#endif	/* DEBUG */
277512502Sjulian
277634832Speterstatic char *
277734832Spetersi_modulename(host_type, uart_type)
277834832Speter	int host_type, uart_type;
277934832Speter{
278034832Speter	switch (host_type) {
278134832Speter	/* Z280 based cards */
278234832Speter#if NEISA > 0
278334832Speter	case SIEISA:
278434832Speter#endif
278534832Speter	case SIHOST2:
278634832Speter	case SIHOST:
278734832Speter#if NPCI > 0
278834832Speter	case SIPCI:
278934832Speter#endif
279034832Speter		switch (uart_type) {
279134832Speter		case 0:
279234832Speter			return(" (XIO)");
279334832Speter		case 1:
279434832Speter			return(" (SI)");
279534832Speter		}
279634832Speter		break;
279734832Speter	/* T225 based hosts */
279834832Speter#if NPCI > 0
279934832Speter	case SIJETPCI:
280034832Speter#endif
280134832Speter	case SIJETISA:
280234832Speter		switch (uart_type) {
280334832Speter		case 0:
280434832Speter			return(" (SI)");
280534832Speter		case 40:
280634832Speter			return(" (XIO)");
280736856Sphk		case 72:
280836856Sphk			return(" (SXDC)");
280934832Speter		}
281034832Speter		break;
281134832Speter	}
281234832Speter	return("");
281334832Speter}
281412624Speter
281512502Sjulianstatic si_devsw_installed = 0;
281612502Sjulian
281734832Speterstatic void
281834832Spetersi_drvinit(void *unused)
281912502Sjulian{
282012517Sjulian	dev_t dev;
282112517Sjulian
282234832Speter	if (!si_devsw_installed) {
282312675Sjulian		dev = makedev(CDEV_MAJOR, 0);
282412675Sjulian		cdevsw_add(&dev,&si_cdevsw, NULL);
282512502Sjulian		si_devsw_installed = 1;
282634832Speter	}
282712502Sjulian}
282812517Sjulian
282912517SjulianSYSINIT(sidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,si_drvinit,NULL)
2830