diff options
-rw-r--r-- | sys/conf/files.i386 | 2 | ||||
-rw-r--r-- | sys/conf/files.pc98 | 2 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 27 | ||||
-rw-r--r-- | sys/i386/include/cdk.h | 495 | ||||
-rw-r--r-- | sys/i386/isa/README.stl | 536 | ||||
-rw-r--r-- | sys/i386/isa/istallion.c | 3850 | ||||
-rw-r--r-- | sys/i386/isa/stallion.c | 3072 |
7 files changed, 0 insertions, 7984 deletions
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 22406ea..89b317a 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -272,7 +272,6 @@ i386/isa/isa.c optional isa i386/isa/isa_compat.c optional isa compat_oldisa \ warning "Old ISA driver compatibility shims present." i386/isa/isa_dma.c optional isa -i386/isa/istallion.c optional stli nowerror i386/isa/mse.c optional mse i386/isa/nmi.c standard i386/isa/npx.c optional npx @@ -288,7 +287,6 @@ i386/isa/prof_machdep.c optional profiling-routine i386/isa/spic.c optional spic i386/isa/spigot.c count spigot i386/isa/spkr.c optional speaker -i386/isa/stallion.c optional stl nowerror i386/isa/vesa.c optional vga vesa i386/linux/imgact_linux.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 981ee6d..d0a3f66 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -205,12 +205,10 @@ i386/isa/elink.c optional ie i386/isa/isa.c optional isa i386/isa/isa_compat.c optional isa compat_oldisa \ warning "Old ISA driver compatibility shims present." -i386/isa/istallion.c optional stli nowerror i386/isa/npx.c optional npx i386/isa/pmtimer.c optional pmtimer i386/isa/prof_machdep.c optional profiling-routine i386/isa/spkr.c optional speaker -i386/isa/stallion.c optional stl nowerror i386/linux/imgact_linux.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux i386/linux/linux_locore.s optional compat_linux \ diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index 4be524a..f6fe2d4 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -637,8 +637,6 @@ options SAFE_RNDTEST # enable rndtest support # digi: Digiboard driver # gsc: Genius GS-4500 hand scanner. # spic: Sony Programmable I/O controller (VAIO notebooks) -# stl: Stallion EasyIO and EasyConnection 8/32 (cd1400 based) -# stli: Stallion EasyConnection 8/64, ONboard, Brumby (intelligent) # Notes on APM # The flags takes the following meaning for apm0: @@ -673,21 +671,6 @@ options SAFE_RNDTEST # enable rndtest support # is the only thing truly supported, but apparently a fair percentage # of the Vaio extra features are controlled by this device. -# Notes on the Stallion stl and stli drivers: -# See src/i386/isa/README.stl for complete instructions. -# This is version 0.0.5alpha, unsupported by Stallion. -# The stl driver has a secondary IO port hard coded at 0x280. You need -# to change src/i386/isa/stallion.c if you reconfigure this on the boards. -# The "flags" and "msize" settings on the stli driver depend on the board: -# EasyConnection 8/64 ISA: flags 23 msize 0x1000 -# EasyConnection 8/64 EISA: flags 24 msize 0x10000 -# EasyConnection 8/64 MCA: flags 25 msize 0x1000 -# ONboard ISA: flags 4 msize 0x10000 -# ONboard EISA: flags 7 msize 0x10000 -# ONboard MCA: flags 3 msize 0x10000 -# Brumby: flags 2 msize 0x4000 -# Stallion: flags 1 msize 0x10000 - device spigot 1 hint.spigot.0.at="isa" hint.spigot.0.port="0xad6" @@ -721,16 +704,6 @@ hint.gsc.0.drq="3" device spic hint.spic.0.at="isa" hint.spic.0.port="0x10a0" -device stl -hint.stl.0.at="isa" -hint.stl.0.port="0x2a0" -hint.stl.0.irq="10" -device stli -hint.stli.0.at="isa" -hint.stli.0.port="0x2a0" -hint.stli.0.maddr="0xcc000" -hint.stli.0.flags="23" -hint.stli.0.msize="0x1000" # HOT1 Xilinx 6200 card (http://www.vcc.com/) device xrpu diff --git a/sys/i386/include/cdk.h b/sys/i386/include/cdk.h deleted file mode 100644 index 8080f2b..0000000 --- a/sys/i386/include/cdk.h +++ /dev/null @@ -1,495 +0,0 @@ -/*****************************************************************************/ - -/* - * cdk.h -- CDK interface definitions. - * - * Copyright (c) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Greg Ungerer. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/*****************************************************************************/ -#ifndef _CDK_H -#define _CDK_H -/*****************************************************************************/ - -#pragma pack(2) - -/* - * The following set of definitions is used to communicate with the - * shared memory interface of the Stallion intelligent multiport serial - * boards. The definitions in this file are taken directly from the - * document titled "Generic Stackable Interface, Downloader and - * Communications Development Kit". - */ - -/* - * Define the set of importrant shared memory addresses. These are - * required to intialize the board and get things started. All of these - * addresses are relative to the start of the shared memory. - */ -#define CDK_SIGADDR 0x200 -#define CDK_FEATADDR 0x280 -#define CDK_CDKADDR 0x300 -#define CDK_RDYADDR 0x262 - -#define CDK_ALIVEMARKER 13 - -/* - * On hardware power up the ROMs located on the EasyConnection 8/64 will - * fill out the following signature information into shared memory. This - * way the host system can quickly determine that the board is present - * and is operational. - */ -typedef struct cdkecpsig { - unsigned long magic; - unsigned short romver; - unsigned short cputype; - unsigned char panelid[8]; -} cdkecpsig_t; - -#define ECP_MAGIC 0x21504345 - -/* - * On hardware power up the ROMs located on the ONboard, Stallion and - * Brumbys will fill out the following signature information into shared - * memory. This way the host system can quickly determine that the board - * is present and is operational. - */ -typedef struct cdkonbsig { - unsigned short magic0; - unsigned short magic1; - unsigned short magic2; - unsigned short magic3; - unsigned short romver; - unsigned short memoff; - unsigned short memseg; - unsigned short amask0; - unsigned short pic; - unsigned short status; - unsigned short btype; - unsigned short clkticks; - unsigned short clkspeed; - unsigned short amask1; - unsigned short amask2; -} cdkonbsig_t; - -#define ONB_MAGIC0 0xf2a7 -#define ONB_MAGIC1 0xa149 -#define ONB_MAGIC2 0x6352 -#define ONB_MAGIC3 0xf121 - -/* - * Define the feature area structure. The feature area is the set of - * startup parameters used by the slave image when it starts executing. - * They allow for the specification of buffer sizes, debug trace, etc. - */ -typedef struct cdkfeature { - unsigned long debug; - unsigned long banner; - unsigned long etype; - unsigned long nrdevs; - unsigned long brdspec; - unsigned long txrqsize; - unsigned long rxrqsize; - unsigned long flags; -} cdkfeature_t; - -#define ETYP_DDK 0 -#define ETYP_CDK 1 - -/* - * Define the CDK header structure. This is the info that the slave - * environment sets up after it has been downloaded and started. It - * essentially provides a memory map for the shared memory interface. - */ -typedef struct cdkhdr { - unsigned short command; - unsigned short status; - unsigned short port; - unsigned short mode; - unsigned long cmd_buf[14]; - unsigned short alive_cnt; - unsigned short intrpt_mode; - unsigned char intrpt_id[8]; - unsigned char ver_release; - unsigned char ver_modification; - unsigned char ver_fix; - unsigned char deadman_restart; - unsigned short deadman; - unsigned short nrdevs; - unsigned long memp; - unsigned long hostp; - unsigned long slavep; - unsigned char hostreq; - unsigned char slavereq; - unsigned char cmd_reserved[30]; -} cdkhdr_t; - -#define MODE_DDK 0 -#define MODE_CDK 1 - -#define IMD_INTR 0x0 -#define IMD_PPINTR 0x1 -#define IMD_POLL 0xff - -/* - * Define the memory mapping structure. This structure is pointed to by - * the memp field in the stlcdkhdr struct. As many as these structures - * as required are layed out in shared memory to define how the rest of - * shared memory is divided up. There will be one for each port. - */ -typedef struct cdkmem { - unsigned short dtype; - unsigned long offset; -} cdkmem_t; - -#define TYP_UNDEFINED 0x0 -#define TYP_ASYNCTRL 0x1 -#define TYP_ASYNC 0x20 -#define TYP_PARALLEL 0x40 -#define TYP_SYNCX21 0x60 - -/*****************************************************************************/ - -/* - * Following is a set of defines and structures used to actually deal - * with the serial ports on the board. Firstly is the set of commands - * that can be applied to ports. - */ -#define ASYCMD (((unsigned long) 'a') << 8) - -#define A_NULL (ASYCMD | 0) -#define A_FLUSH (ASYCMD | 1) -#define A_BREAK (ASYCMD | 2) -#define A_GETPORT (ASYCMD | 3) -#define A_SETPORT (ASYCMD | 4) -#define A_SETPORTF (ASYCMD | 5) -#define A_SETPORTFTX (ASYCMD | 6) -#define A_SETPORTFRX (ASYCMD | 7) -#define A_GETSIGNALS (ASYCMD | 8) -#define A_SETSIGNALS (ASYCMD | 9) -#define A_SETSIGNALSF (ASYCMD | 10) -#define A_SETSIGNALSFTX (ASYCMD | 11) -#define A_SETSIGNALSFRX (ASYCMD | 12) -#define A_GETNOTIFY (ASYCMD | 13) -#define A_SETNOTIFY (ASYCMD | 14) -#define A_NOTIFY (ASYCMD | 15) -#define A_PORTCTRL (ASYCMD | 16) -#define A_GETSTATS (ASYCMD | 17) -#define A_RQSTATE (ASYCMD | 18) -#define A_FLOWSTATE (ASYCMD | 19) -#define A_CLEARSTATS (ASYCMD | 20) - -/* - * Define those arguments used for simple commands. - */ -#define FLUSHRX 0x1 -#define FLUSHTX 0x2 - -#define BREAKON -1 -#define BREAKOFF -2 - -/* - * Define the port setting structure, and all those defines that go along - * with it. Basically this structure defines the charcateristics of this - * port: baud rate, chars, parity, input/output char cooking etc. - */ -typedef struct asyport { - unsigned long baudout; - unsigned long baudin; - unsigned long iflag; - unsigned long oflag; - unsigned long lflag; - unsigned long pflag; - unsigned long flow; - unsigned long spare1; - unsigned short vtime; - unsigned short vmin; - unsigned short txlo; - unsigned short txhi; - unsigned short rxlo; - unsigned short rxhi; - unsigned short rxhog; - unsigned short spare2; - unsigned char csize; - unsigned char stopbs; - unsigned char parity; - unsigned char stopin; - unsigned char startin; - unsigned char stopout; - unsigned char startout; - unsigned char parmark; - unsigned char brkmark; - unsigned char cc[11]; -} asyport_t; - -#define PT_STOP1 0x0 -#define PT_STOP15 0x1 -#define PT_STOP2 0x2 - -#define PT_NOPARITY 0x0 -#define PT_ODDPARITY 0x1 -#define PT_EVENPARITY 0x2 -#define PT_MARKPARITY 0x3 -#define PT_SPACEPARITY 0x4 - -#define F_NONE 0x0 -#define F_IXON 0x1 -#define F_IXOFF 0x2 -#define F_IXANY 0x4 -#define F_IOXANY 0x8 -#define F_RTSFLOW 0x10 -#define F_CTSFLOW 0x20 -#define F_DTRFLOW 0x40 -#define F_DCDFLOW 0x80 -#define F_DSROFLOW 0x100 -#define F_DSRIFLOW 0x200 - -#define FI_NORX 0x1 -#define FI_RAW 0x2 -#define FI_ISTRIP 0x4 -#define FI_UCLC 0x8 -#define FI_INLCR 0x10 -#define FI_ICRNL 0x20 -#define FI_IGNCR 0x40 -#define FI_IGNBREAK 0x80 -#define FI_DSCRDBREAK 0x100 -#define FI_1MARKBREAK 0x200 -#define FI_2MARKBREAK 0x400 -#define FI_XCHNGBREAK 0x800 -#define FI_IGNRXERRS 0x1000 -#define FI_DSCDRXERRS 0x2000 -#define FI_1MARKRXERRS 0x4000 -#define FI_2MARKRXERRS 0x8000 -#define FI_XCHNGRXERRS 0x10000 -#define FI_DSCRDNULL 0x20000 - -#define FO_OLCUC 0x1 -#define FO_ONLCR 0x2 -#define FO_OOCRNL 0x4 -#define FO_ONOCR 0x8 -#define FO_ONLRET 0x10 -#define FO_ONL 0x20 -#define FO_OBS 0x40 -#define FO_OVT 0x80 -#define FO_OFF 0x100 -#define FO_OTAB1 0x200 -#define FO_OTAB2 0x400 -#define FO_OTAB3 0x800 -#define FO_OCR1 0x1000 -#define FO_OCR2 0x2000 -#define FO_OCR3 0x4000 -#define FO_OFILL 0x8000 -#define FO_ODELL 0x10000 - -#define P_RTSLOCK 0x1 -#define P_CTSLOCK 0x2 -#define P_MAPRTS 0x4 -#define P_MAPCTS 0x8 -#define P_LOOPBACK 0x10 -#define P_DTRFOLLOW 0x20 -#define P_FAKEDCD 0x40 - -/* - * Define a structure to communicate serial port signal and data state - * information. - */ -typedef struct asysigs { - unsigned long data; - unsigned long signal; - unsigned long sigvalue; -} asysigs_t; - -#define DT_TXBUSY 0x1 -#define DT_TXEMPTY 0x2 -#define DT_TXLOW 0x4 -#define DT_TXHIGH 0x8 -#define DT_TXFULL 0x10 -#define DT_TXHOG 0x20 -#define DT_TXFLOWED 0x40 -#define DT_TXBREAK 0x80 - -#define DT_RXBUSY 0x100 -#define DT_RXEMPTY 0x200 -#define DT_RXLOW 0x400 -#define DT_RXHIGH 0x800 -#define DT_RXFULL 0x1000 -#define DT_RXHOG 0x2000 -#define DT_RXFLOWED 0x4000 -#define DT_RXBREAK 0x8000 - -#define SG_DTR 0x1 -#define SG_DCD 0x2 -#define SG_RTS 0x4 -#define SG_CTS 0x8 -#define SG_DSR 0x10 -#define SG_RI 0x20 - -/* - * Define the notification setting structure. This is used to tell the - * port what events we want to be informed about. Fields here use the - * same defines as for the asysigs structure above. - */ -typedef struct asynotify { - unsigned long ctrl; - unsigned long data; - unsigned long signal; - unsigned long sigvalue; -} asynotify_t; - -/* - * Define the port control structure. It is used to do fine grain - * control operations on the port. - */ -typedef struct { - unsigned long rxctrl; - unsigned long txctrl; - char rximdch; - char tximdch; - char spare1; - char spare2; -} asyctrl_t; - -#define CT_ENABLE 0x1 -#define CT_DISABLE 0x2 -#define CT_STOP 0x4 -#define CT_START 0x8 -#define CT_STARTFLOW 0x10 -#define CT_STOPFLOW 0x20 -#define CT_SENDCHR 0x40 - -/* - * Define the stats structure kept for each port. This is a useful set - * of data collected for each port on the slave. The A_GETSTATS command - * is used to retrive this data from the slave. - */ -typedef struct asystats { - unsigned long opens; - unsigned long txchars; - unsigned long rxchars; - unsigned long txringq; - unsigned long rxringq; - unsigned long txmsgs; - unsigned long rxmsgs; - unsigned long txflushes; - unsigned long rxflushes; - unsigned long overruns; - unsigned long framing; - unsigned long parity; - unsigned long ringover; - unsigned long lost; - unsigned long rxstart; - unsigned long rxstop; - unsigned long txstart; - unsigned long txstop; - unsigned long dcdcnt; - unsigned long dtrcnt; - unsigned long ctscnt; - unsigned long rtscnt; - unsigned long dsrcnt; - unsigned long ricnt; - unsigned long txbreaks; - unsigned long rxbreaks; - unsigned long signals; - unsigned long state; - unsigned long hwid; -} asystats_t; - -/*****************************************************************************/ - -/* - * All command and control communication with a device on the slave is - * via a control block in shared memory. Each device has its own control - * block, defined by the following structure. The control block allows - * the host to open, close and control the device on the slave. - */ -typedef struct cdkctrl { - unsigned char open; - unsigned char close; - unsigned long openarg; - unsigned long closearg; - unsigned long cmd; - unsigned long status; - unsigned long args[32]; -} cdkctrl_t; - -/* - * Each device on the slave passes data to and from the host via a ring - * queue in shared memory. Define a ring queue structure to hold the - * vital information about each ring queue. Two ring queues will be - * allocated for each port, one for reveice data and one for transmit - * data. - */ -typedef struct cdkasyrq { - unsigned long offset; - unsigned short size; - unsigned short head; - unsigned short tail; -} cdkasyrq_t; - -/* - * Each asynchronous port is defined in shared memory by the following - * structure. It contains a control block to command a device, and also - * the neccessary data channel information as well. - */ -typedef struct cdkasy { - cdkctrl_t ctrl; - unsigned short notify; - asynotify_t changed; - unsigned short receive; - cdkasyrq_t rxq; - unsigned short transmit; - cdkasyrq_t txq; -} cdkasy_t; - -#pragma pack() - -/*****************************************************************************/ - -/* - * Define the set of ioctls used by the driver to do special things - * to the board. These include interrupting it, and initializeing - * the driver after board startup and shutdown. - */ -#define STL_BINTR _IO('s', 20) -#define STL_BSTART _IO('s', 21) -#define STL_BSTOP _IO('s', 22) -#define STL_BRESET _IO('s', 23) - -/* - * Define a set of ioctl extensions, used to get at special stuff. - */ -#define STL_GETPFLAG _IOR('s', 80, unsigned long) -#define STL_SETPFLAG _IOW('s', 81, unsigned long) - -/*****************************************************************************/ -#endif diff --git a/sys/i386/isa/README.stl b/sys/i386/isa/README.stl deleted file mode 100644 index d723dca..0000000 --- a/sys/i386/isa/README.stl +++ /dev/null @@ -1,536 +0,0 @@ -$FreeBSD$ - -Stallion Multiport Serial Driver Readme ---------------------------------------- - -Version: 0.0.5 alpha -Date: 20MAR96 -Author: Greg Ungerer (gerg@stallion.oz.au) - - - -1. INTRODUCTION - -This is a FreeBSD driver for some of the Stallion Technologies range of -multiport serial boards. This driver is still very new, so it should be -considered to be of very alpha quality. - -This driver has not been developed by Stallion Technologies. I developed it -in my spare time in the hope that it would be useful. As such there is no -warranty or support of any form. What this means is that this driver is not -officially supported by Stallion Technologies, so don't ring their support -if you can't get it working. They will probably not be able to help you. -Instead email me if you have problems or bug reports and I will do what I -can... (Sorry to sound so heavy handed, but I need to stress that this driver -is not officially supported in any way.) - -This package actually contains two drivers. One is for the true Stallion -intelligent multiport boards, and the other is for the smart range of boards. - -All host driver source is included in this package, and is copyrighted under -a BSD style copyright. The board "firmware" code in this package is copyright -Stallion Technologies (the files cdk.sys and 2681.sys). - - -1.1 SMART MULTIPORT BOARD DRIVER - -This driver supports the EasyIO and EasyConnection 8/32 range of boards. -These boards are not classic intelligent multiport boards, but are host -based multiport boards that use high performance Cirrus Logic CL-CD1400 RISC -UART's (they have built in FIFO's, automatic flow control and some other -good stuff). - -The EasyIO range of cards comes in 3 forms, the EasyIO-4, EasyIO-8 and the -EasyIO-8M. All of these are non-expandable, low cost, ISA, multiport boards -with 4, 8 and 8 RS-232C ports respectively. Each EasyIO board requires 8 -bytes of I/O address space and 1 interrupt. On an EISA system it is possible -to share 1 interrupt between multiple boards. The EasyIO-4 has 10 pin RJ -connectors, and the EasyIO-8 comes with a dongle cable with either 10 pin RJ -connectors or DB-25 connectors. The EasyIO-8M has 6 pin RJ connectors. - -The EasyConnection 8/32 family of boards is a relatively low cost modular -range of multiport serial boards. The EasyConnection 8/32 boards can be -configured to have from 8 to 32 serial ports by plugging in external serial -port modules that contain either 8 or 16 ports each. There is a wide range -of external modules available that offer: DB-25 connectors, RJ-45 connectors -(both with RS-232 D and E compatible drivers), and also RS-422 and RS-485 -ports. The EasyConnection 8/32 boards come in ISA, PCI and MCA bus versions. -The board takes the form of a host adapter card, with an external connector -cable that plugs into the external modules. The external modules just clip -together to add ports (BTW, they are NOT hot pluggable). Each ISA -EasyConnection 8/32 board requires two separate I/O address ranges, one two -bytes in size and a secondary region of 32 bytes. Each PCI EasyConnection -8/32 requires two regions of I/O address space, normally these will be -automatically allocated by the system BIOS at system power on time. Each MCA -EasyConnection board requires one I/O address region 64 bytes in size. All -board types also require one interrupt. On EISA systems multiple boards can -share one interrupt. The secondary I/O range of the ISA board (the 32 byte -range) can be shared between multiple boards on any bus type. - - -1.2 INTELLIGENT MULTIPORT BOARD DRIVER - -This driver is for Stallion's range of true intelligent multiport boards. -It supports the EasyConnection 8/64, ONboard, Brumby and original Stallion -families of multiport boards. The EasyConnection 8/64 and ONboard boards come -in ISA, EISA and Microchannel bus versions. The Brumby and Stallion boards -are only available in ISA versions. - -The EasyConnection 8/64 family of boards is a medium cost, high performance, -modular range of intelligent multiport serial boards. The EasyConnection 8/64 -boards can be configured to have from 8 to 64 serial ports by plugging in -external serial port modules that contain either 8 or 16 ports each (these -modules are the same used by the EasyConnection 8/32 board). There is a wide -range of external modules available that offer: DB-25 connectors, RJ-45 -connectors (both with RS-232 D and E compatible drivers), and also RS-422 and -RS-485 ports. The board takes the form of a host adapter card, with an external -connector cable that plugs into the external modules. The external modules -just clip together to add ports (BTW, they are NOT hot pluggable). Each -EasyConnection 8/64 board requires 4 bytes of I/O address space and a region -of memory space. The size of the memory region required depends on the exact -board type. The EISA version requires 64 Kbytes of address space (that can -reside anywhere in the 4 Gigabyte physical address space). The ISA and MCA -boards require 4 Kbytes of address space (which must reside in the lower -1 Mbyte of physical address space - typically in the c8000 to e0000 range). -No interrupts are required. The physical memory region of multiple -EasyConnection 8/64 boards can be shared, but each board must have a separate -I/O address space. - -The ONboard family of boards are traditional intelligent multiport serial -boards. They are Stallion's older range of boards with a limited expansion -capability. They come in 4, 8, 12, 16 and 32 port versions. The board uses -the same base card (which has 4 ports on it) and is expanded to more ports -via a mezzanine board that attaches directly onto the board. External panels -plug into the ONboard providing RS-232C ports with DB-25 plugs. An RS-422 -DB-25 dual interface panel is also available. The ISA and microchannel -ONboards require 16 bytes of I/O address space and 64K bytes of memory -space. The memory space can be anywhere in the 16 Mbyte ISA bus address -range. No interrupt is required. The EISA ONboard requires 64 Kbytes of -memory space that can be anywhere in the 4 Gigabyte physical address space. -All ONboard boards can share their memory region with other ONboards (or -EasyConnection 8/64 boards). - -The Brumby family of boards are traditional, low cost intelligent multiport -serial boards. They are non-expandable and come in 4, 8 and 16 port versions. -They are only available for the ISA bus. The serial ports are all on DB-25 -"dongle" cables that attach to the rear of the board. Each Brumby board -requires 16 bytes of I/O address space and 16 Kbytes of memory space. No -interrupts are required. - -The original Stallion boards are old. They went out of production some years -back. They offer limited expandability and are available in 8 or 16 port -configurations. An external panel houses 16 RS-232C ports with DB-9 -connectors. They require 16 bytes of I/O address space, and either 64K or -128K of memory space. No interrupt is required. I will not actively support -these boards, although they will work with the driver. - -That's the boards supported by the second driver. The ONboard, Brumby and -Stallion boards are Stallion's older range of intelligent multiports - so -there are lots of them around. They only support a maximum baud rate of -38400. The EasyConnection 8/64 is a true high performance intelligent -multiport board, having much greater throughput than any of Stallion's -older boards. It also supports speeds up to 115200 baud. - - -1.3 HOW TO GET BOARDS - -Stallion Technologies has offices all over the world, as well as many more -distributors and resellers. To find out about local availability please -contact the nearest Stallion office and they can give you all the information -you need. - - Stallion Technologies Sales and Support Offices - =============================================== - - Stallion Technologies Pty. Ltd. - P.O. Box 954 - Toowong, QLD 4066, Australia - Tel. +61 7 3270 4242 - Fax. +61 7 3270 4245 - Email: support@stallion.oz.au - - Stallion Technologies Inc. - 2880 Research Park Drive, - Soquel, CA 95073, USA. - Tel. +1 408 477 0440 - Fax. +1 408 477 0444 - Email: support@staltec.com - - Stallion Technologies Deutschland GmbH. - Martin-Behaim-Strasse 12 - 63263 Neu-Isenburg - Germany - Tel. +49 6102 73970 - Fax. +49 6102 739710 - -Another good source of information about the Stallion range of boards and -local availability is on the Stallion Web page. Check it out at -http://www.stallion.com. - - - -2. INSTALLATION - -This driver, as is, will work on a FreeBSD 2.1 system. It will run on -a 2.0.5 system, or -current version systems by changing a define in the -driver source. - -You will need to build a new kernel to use this driver. So the first thing -you need is to have the full kernel source. Most people will have this -(I hope!). The following assumes that the kernel source is in /usr/src/sys. - -The drivers can support up to 8 boards. For the smart board driver any -combination of EasyIO and EasyConnection 8/32 boards can be installed. For -the intelligent any combination of EasyConnection 8/64, ONboard, Brumby or -original Stallion. So there is a theoretical maximum of 512 ports. -(Off-course I have not tested a system with this many!) - - -[[[ The install instructions are obsolete, it is now standard ]]] -[[[ Skip forward to item 4, editing your kernel config file ]]] - -2.1 Instructions to install: - -1. Copy the driver source files into the kernel source tree. - - cp stallion.c istallion.c cdk.h comstats.h /usr/src/sys/i386/isa - cp scd1400.h /usr/src/sys/i386/isa/ic - - Note: if you are NOT using FreeBSD 2.1.0 then you will need to edit the - stallion.c and istallion.c files and change the VFREEBSD define to match - your version. - -2. Skip to next step if on a FreeBSD kernel later than 2.1.0. - Add a character device switch table entry for the driver that you which - to use into the cdevsw table structure. This involves adding some code - into the kernel conf.c file. - - If you are using an EasyIO or EasyConnection 8/32 then you need to use - the stallion.c driver. All other board types (EasyConnection 8/64, - ONboard, Brumby, Stallion) use the istallion.c driver. You can also have - a mix of boards using both drivers. You will need to use a different - major device number for the second driver though (not the default 72 - - see below for more details on this). - -2.1. If using the stallion.c driver then do: - - cd /usr/src/sys/i386/i386 - vi conf.c - - add the following lines (in 2.1 I put them at line 729): - -/* Stallion Multiport Serial Driver */ -#include "stl.h" -#if NSTL > 0 -d_open_t stlopen; -d_close_t stlclose; -d_read_t stlread; -d_write_t stlwrite; -d_ioctl_t stlioctl; -d_stop_t stlstop; -d_ttycv_t stldevtotty; -#define stlreset nxreset -#define stlmmap nxmmap -#define stlstrategy nxstrategy -#else -#define stlopen nxopen -#define stlclose nxclose -#define stlread nxread -#define stlwrite nxwrite -#define stlioctl nxioctl -#define stlstop nxstop -#define stlreset nxreset -#define stlmmap nxmmap -#define stlstrategy nxstrategy -#define stldevtotty nxdevtotty -#endif - - - - and then inside the actual cdevsw structure definition, at the - last entry add (this is now line 1384 in the 2.1 conf.c): - - { stlopen, stlclose, stlread, stlwrite, /*72*/ - stlioctl, stlstop, stlreset, stldevtotty,/*stallion*/ - ttselect, stlmmap, stlstrategy }, - - - the line above used major number 72, but this may be different - on your system. Take note of what major number you are using. - - - save the file and exit vi. - - -2.2. If using the istallion.c driver then do: - - cd /usr/src/sys/i386/i386 - vi conf.c - - add the following lines (in 2.1 I put them at line 729): - -/* Stallion Intelligent Multiport Serial Driver */ -#include "stl.h" -#if NSTL > 0 -d_open_t stliopen; -d_close_t stliclose; -d_read_t stliread; -d_write_t stliwrite; -d_ioctl_t stliioctl; -d_stop_t stlistop; -d_ttycv_t stlidevtotty; -#define stlireset nxreset -#define stlimmap nxmmap -#define stlistrategy nxstrategy -#else -#define stliopen nxopen -#define stliclose nxclose -#define stliread nxread -#define stliwrite nxwrite -#define stliioctl nxioctl -#define stlistop nxstop -#define stlireset nxreset -#define stlimmap nxmmap -#define stlistrategy nxstrategy -#define stlidevtotty nxdevtotty -#endif - - - - and then inside the actual cdevsw structure definition, at the - last entry add (this is now line 1384 in the 2.1 conf.c): - - { stliopen, stliclose, stliread, stliwrite, /*72*/ - stliioctl, stlistop, stlireset, stlidevtotty,/*istallion*/ - ttselect, stlimmap, stlistrategy }, - - - the line above used major number 72, but this may be different - on your system. Take note of what major number you are using. - - - save the file and exit vi. - -3. Add the driver source files to the kernel files list: - - cd /usr/src/sys/i386/conf - vi files.i386 - - add the following definition lines into the list (it is stored - alphabetically, so insert them appropriately): - -i386/isa/istallion.c optional stli device-driver - -i386/isa/stallion.c optional stl device-driver - - - save the file and exit vi. - -4. Add board probe entries into the kernel configuration file: - - cd /usr/src/sys/i386/conf - cp GENERIC MYKERNEL - - if you already have a kernel config that you use then you - could just use that (instead of MYKERNEL) - vi MYKERNEL - - if only using ECH-PCI boards then you don't need to enter a - configuration line, the kernel will automatically detect - the board at boot up, so skip to step 5. - - enter a line for each board that you want to use. For stallion.c - boards entries should look like: - -device stl0 at isa? port 0x2a0 tty irq 10 - - For istallion.c boards, the entries should look like: - -device stli0 at isa? port 0x2a0 tty iomem 0xcc000 iosiz 0x1000 flags 23 - - (I suggest you put them after the sio? entries) - (Don't enter lines for ECH-PCI boards) - - change the entry resources as required. For the Stallion.c - entries this may involve changing the port address or irq. - For the istallion.c entries this may involve changing the port - address, iomem address, iosiz value and the flags. Select from - the following table for appropriate flags and iosiz values for - your board type: - - EasyConnection 8/64 ISA: flags 23 iosiz 0x1000 - EasyConnection 8/64 EISA: flags 24 iosiz 0x10000 - EasyConnection 8/64 MCA: flags 25 iosiz 0x1000 - ONboard ISA: flags 4 iosiz 0x10000 - ONboard EISA: flags 7 iosiz 0x10000 - ONboard MCA: flags 3 iosiz 0x10000 - Brumby: flags 2 iosiz 0x4000 - Stallion: flags 1 iosiz 0x10000 - - - save the file and exit - -5. Build a new kernel using this configuration. - - cd /usr/src/sys/i386/conf - config MYKERNEL - cd ../../compile/MYKERNEL - make depend - make all - make install - - -And there you have it! It is a little bit of effort to get it in there... - -Once you have a new kernel built reboot to start it up. On startup the -Stallion board probes will report on whether the boards were found or not. -For each board found the driver will print out the type of board found, -and how many panels and ports it has. - -If a board is not found by the driver but is actually in the system then the -most likely problem is that the IO address is incorrect. The easiest thing to -do is change the DIP switches on the board to the desired address and reboot. - -On EasyIO and EasyConnection 8/32 boards the IRQ is software programmable, -so if there is a conflict you may need to change the IRQ used for a board in -the MYKERNEL configuration file and rebuild the kernel. - -Note that the secondary IO address of the EasyConnection 8/32 boards is hard -coded into the stallion.c driver code. It is currently set to IO address -0x280. If you need to use a different address then you will need to edit this -file and change the variable named stl_ioshared. - -On intelligent boards it is possible that the board shared memory region is -clashing with that of some other device. Check for this and change the device -or kernel configuration as required. - - -2.2 INTELLIGENT DRIVER OPERATION - -The intelligent boards also need to have their "firmware" code downloaded -to them. This is done via a user level application supplied in the driver -package called "stlload". Compile this program where ever you dropped the -package files, by typing "make". In its simplest form you can then type - ./stlload -i cdk.sys -in this directory and that will download board 0 (assuming board 0 is an -EasyConnection 8/64 board). To download to an ONboard, Brumby or Stallion do: - ./stlload -i 2681.sys - -Normally you would want all boards to be downloaded as part of the standard -system startup. To achieve this, add one of the lines above into the -/etc/rc.serial file. To download each board just add the "-b <brd-number>" -option to the line. You will need to download code for every board. You should -probably move the stlload program into a system directory, such as /usr/sbin. -Also, the default location of the cdk.sys image file in the stlload -down-loader is /usr/lib/stallion. Create that directory and put the cdk.sys -and 2681.sys files in it. (It's a convenient place to put them anyway). As an -example your /etc/rc.serial file might have the following lines added to it -(if you had 3 boards): - /usr/sbin/stlload -b 0 -i /usr/lib/stallion/cdk.sys - /usr/sbin/stlload -b 1 -i /usr/lib/stallion/2681.sys - /usr/sbin/stlload -b 2 -i /usr/lib/stallion/2681.sys - -The image files cdk.sys and 2681.sys are specific to the board types. The -cdk.sys will only function correctly on an EasyConnection 8/64 board. Similarly -the 2681.sys image will only operate on ONboard, Brumby and Stallion boards. -If you load the wrong image file into a board it will fail to start up, and -of course the ports will not be operational! - - - -3. USING THE DRIVER - -Once the driver is installed you will need to setup some device nodes to -access the serial ports. Use the supplied "mkdevnods" script to automatically -create all required device entries for your boards. To make device nodes for -more than 1 board then just supply the number of boards you are using as a -command line parameter to mkdevnods and it will create nodes for that number -of boards. By default it will create device nodes for 1 board only. - -Note that if the driver is not installed at character major number 72 then -you will need to edit the mkdevnods script and modify the STL_SERIALMAJOR -variable to the major number you are using. - -Device nodes created for the normal serial port devices are named /dev/ttyEX -where X is the port number. (The second boards ports will start from ttyE64, -the third boards from ttyE128, etc). It will also create a set of modem call -out devices named cueX where again X is the port number. - -For the most part the Stallion driver tries to emulate the standard PC system -com ports and the standard sio serial driver. The idea is that you should -be able to use Stallion board ports and com ports inter-changeably without -modifying anything but the device name. Anything that doesn't work like that -should be considered a bug in this driver! - -Since this driver tries to emulate the standard serial ports as much as -possible then most system utilities should work as they do for the standard -com ports. Most importantly "stty" works as expected and "comcontrol" can be -used just like for the serial ports. - -This driver should work with anything that works on standard com serial ports. -Having said that, I have used it on at least the following types of "things" -under FreeBSD: - a) standard dumb terminals (using getty) - b) modems (using cu, etc) - c) ppp (through pppd, kernel ppp) - - - -4. NOTES - -Be aware that these drivers are still very new, so there is sure to be some -bugs in them. Please email me any feedback on bugs, problems, or even good -experiences with these drivers! - -You can use both drivers at once if you have a mix of board types installed -in a system. However to do this you will need to change the major number used -by one of the drivers. Currently both drivers use default major number 72 for -their devices. Change one driver to use some other major number (how this is -achieved will depend on the kernel version you are using), and then modify the -mkdevnods script to make device nodes based on those new major numbers. For -example, you could change the stallion.c driver to use major number 73. You -will also need to create device nodes with different names for the ports, for -eg ttyFXXX. - -Currently the intelligent board driver (istallion.c) does not have the -ability to share a boards memory region with other boards (you can only do -this on EasyConnection 8/64 and ONboards normally anyway). It also does -not currently support any memory address ranges above the low 1Mb region. -These will be fixed in a future release of the driver. - -Finding a free physical memory address range can be a problem. The older -boards like the Stallion and ONboard need large areas (64K or even 128K), so -they can be very difficult to get into a system. If you have 16 Mb of RAM -then you have no choice but to put them somewhere in the 640K -> 1Mb range. -ONboards require 64K, so typically 0xd0000 is good, or 0xe0000 on some -systems. If you have an original Stallion board, "V4.0" or Rev.O, then you -need a 64K memory address space, so again 0xd0000 and 0xe0000 are good. Older -Stallion boards are a much bigger problem. They need 128K of address space and -must be on a 128K boundary. If you don't have a VGA card then 0xc0000 might be -usable - there is really no other place you can put them below 1Mb. - -Both the ONboard and old Stallion boards can use higher memory addresses as -well, but you must have less than 16Mb of RAM to be able to use them. Usual -high memory addresses used include 0xec0000 and 0xf00000. - -The Brumby boards only require 16Kb of address space, so you can usually -squeeze them in somewhere. Common addresses are 0xc8000, 0xcc000, or in -the 0xd0000 range. EasyConnection 8/64 boards are even better, they only -require 4Kb of address space, again usually 0xc8000, 0xcc000 or 0xd0000 -are good. - -If you are using an EasyConnection 8/64-EI or ONboard/E then usually the -0xd0000 or 0xe0000 ranges are the best options below 1Mb. If neither of -them can be used then the high memory support to use the really high address -ranges is the best option. Typically the 2Gb range is convenient for them, -and gets them well out of the way. - -The ports of the EasyIO-8M board do not have DCD or DTR signals. So these -ports cannot be used as real modem devices. Generally when using these -ports you should only use the cueX devices. - -There is a new utility in this package that reports statistics on the -serial ports. You will need to have the ncurses library installed on your -system to build it. - -To build the statistics display program type: - make stlstats -Once compiled simply run it (you will need to be root) and it will display -a port summary for the first board and panel installed. Use the digits to -select different board numbers, or 'n' to cycle through the panels on a -board. To look at detailed port information then hit 'p', that will display -detailed port 0 information. Use the digits and letters 'a' through 'f' to -select the different ports (on this board and panel). - - - -5. ACKNOWLEDGEMENTS - -This driver is loosely based on the code of the FreeBSD sio serial driver. -A big thanks to Stallion Technologies for the use of their equipment. - diff --git a/sys/i386/isa/istallion.c b/sys/i386/isa/istallion.c deleted file mode 100644 index f6f10b1..0000000 --- a/sys/i386/isa/istallion.c +++ /dev/null @@ -1,3850 +0,0 @@ -/*****************************************************************************/ - -/* - * istallion.c -- stallion intelligent multiport serial driver. - * - * Copyright (c) 1994-1996 Greg Ungerer (gerg@stallion.oz.au). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Greg Ungerer. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*****************************************************************************/ - -#include "opt_compat.h" -#include "opt_tty.h" - -#define TTYDEFCHARS 1 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/tty.h> -#include <sys/conf.h> -#include <sys/fcntl.h> -#include <sys/uio.h> -#include <sys/bus.h> -#include <vm/vm.h> -#include <vm/pmap.h> -#include <i386/isa/isa_device.h> -#include <machine/cdk.h> -#include <machine/comstats.h> - -#ifndef COMPAT_OLDISA -#error "The stli device requires the old isa compatibility shims" -#endif - -/*****************************************************************************/ - -/* - * Define the version level of the kernel - so we can compile in the - * appropriate bits of code. By default this will compile for a 2.1 - * level kernel. - */ -#define VFREEBSD 220 - -#if VFREEBSD >= 220 -#define STATIC static -#else -#define STATIC -#endif - -/*****************************************************************************/ - -/* - * Define different board types. Not all of the following board types - * are supported by this driver. But I will use the standard "assigned" - * board numbers. Currently supported boards are abbreviated as: - * ECP = EasyConnection 8/64, ONB = ONboard, BBY = Brumby and - * STAL = Stallion. - */ -#define BRD_UNKNOWN 0 -#define BRD_STALLION 1 -#define BRD_BRUMBY4 2 -#define BRD_ONBOARD2 3 -#define BRD_ONBOARD 4 -#define BRD_BRUMBY8 5 -#define BRD_BRUMBY16 6 -#define BRD_ONBOARDE 7 -#define BRD_ONBOARD32 9 -#define BRD_ONBOARD2_32 10 -#define BRD_ONBOARDRS 11 -#define BRD_EASYIO 20 -#define BRD_ECH 21 -#define BRD_ECHMC 22 -#define BRD_ECP 23 -#define BRD_ECPE 24 -#define BRD_ECPMC 25 -#define BRD_ECHPCI 26 - -#define BRD_BRUMBY BRD_BRUMBY4 - -/*****************************************************************************/ - -/* - * Define important driver limitations. - */ -#define STL_MAXBRDS 8 -#define STL_MAXPANELS 4 -#define STL_PORTSPERPANEL 16 -#define STL_PORTSPERBRD 64 - -#define STL_MAXCHANS STL_PORTSPERBRD - - -/* - * Define the important minor number break down bits. These have been - * chosen to be "compatible" with the standard sio driver minor numbers. - * Extra high bits are used to distinguish between boards and also for - * really high port numbers (> 32). - */ -#define STL_CALLOUTDEV 0x80 -#define STL_CTRLLOCK 0x40 -#define STL_CTRLINIT 0x20 -#define STL_CTRLDEV (STL_CTRLLOCK | STL_CTRLINIT) - -#define STL_MEMDEV 0x07000000 - -#define STL_DEFSPEED TTYDEF_SPEED -#define STL_DEFCFLAG (CS8 | CREAD | HUPCL) - -/*****************************************************************************/ - -/* - * Define our local driver identity first. Set up stuff to deal with - * all the local structures required by a serial tty driver. - */ -static char stli_drvname[] = "stli"; -static char const stli_longdrvname[] = "Stallion Multiport Serial Driver"; -static char const stli_drvversion[] = "1.0.0"; - -static int stli_nrbrds = 0; -static int stli_doingtimeout = 0; - -static char *__file__ = /*__FILE__*/ "istallion.c"; - -/* - * Define some macros to use to class define boards. - */ -#define BRD_ISA 0x1 -#define BRD_EISA 0x2 -#define BRD_MCA 0x4 -#define BRD_PCI 0x8 - -static unsigned char stli_stliprobed[STL_MAXBRDS]; - -/*****************************************************************************/ - -/* - * Define a set of structures to hold all the board/panel/port info - * for our ports. These will be dynamically allocated as required at - * driver initialization time. - */ - -/* - * Port and board structures to hold status info about each object. - * The board structure contains pointers to structures for each port - * connected to it. Panels are not distinguished here, since - * communication with the slave board will always be on a per port - * basis. - */ -typedef struct { - struct tty tty; - int portnr; - int panelnr; - int brdnr; - int ioaddr; - int callout; - int devnr; - int dtrwait; - int dotimestamp; - int waitopens; - int hotchar; - int rc; - int argsize; - void *argp; - unsigned int state; - unsigned int sigs; - struct termios initintios; - struct termios initouttios; - struct termios lockintios; - struct termios lockouttios; - struct timeval timestamp; - asysigs_t asig; - unsigned long addr; - unsigned long rxlost; - unsigned long rxoffset; - unsigned long txoffset; - unsigned long pflag; - unsigned int rxsize; - unsigned int txsize; - unsigned char reqidx; - unsigned char reqbit; - unsigned char portidx; - unsigned char portbit; -} stliport_t; - -/* - * Use a structure of function pointers to do board level operations. - * These include, enable/disable, paging shared memory, interrupting, etc. - */ -typedef struct stlibrd { - int brdnr; - int brdtype; - int unitid; - int state; - int nrpanels; - int nrports; - int nrdevs; - unsigned int iobase; - unsigned long paddr; - void *vaddr; - int memsize; - int pagesize; - int hostoffset; - int slaveoffset; - int bitsize; - int confbits; - void (*init)(struct stlibrd *brdp); - void (*enable)(struct stlibrd *brdp); - void (*reenable)(struct stlibrd *brdp); - void (*disable)(struct stlibrd *brdp); - void (*intr)(struct stlibrd *brdp); - void (*reset)(struct stlibrd *brdp); - char *(*getmemptr)(struct stlibrd *brdp, - unsigned long offset, int line); - int panels[STL_MAXPANELS]; - int panelids[STL_MAXPANELS]; - stliport_t *ports[STL_PORTSPERBRD]; -} stlibrd_t; - -static stlibrd_t *stli_brds[STL_MAXBRDS]; - -static int stli_shared = 0; - -/* - * Keep a local char buffer for processing chars into the LD. We - * do this to avoid copying from the boards shared memory one char - * at a time. - */ -static int stli_rxtmplen; -static stliport_t *stli_rxtmpport; -static char stli_rxtmpbuf[TTYHOG]; - -/* - * Define global stats structures. Not used often, and can be re-used - * for each stats call. - */ -static comstats_t stli_comstats; -static combrd_t stli_brdstats; -static asystats_t stli_cdkstats; - -/* - * Per board state flags. Used with the state field of the board struct. - * Not really much here... All we need to do is keep track of whether - * the board has been detected, and whether it is actully running a slave - * or not. - */ -#define BST_FOUND 0x1 -#define BST_STARTED 0x2 - -/* - * Define the set of port state flags. These are marked for internal - * state purposes only, usually to do with the state of communications - * with the slave. They need to be updated atomically. - */ -#define ST_INITIALIZING 0x1 -#define ST_INITIALIZED 0x2 -#define ST_OPENING 0x4 -#define ST_CLOSING 0x8 -#define ST_CMDING 0x10 -#define ST_RXING 0x20 -#define ST_TXBUSY 0x40 -#define ST_DOFLUSHRX 0x80 -#define ST_DOFLUSHTX 0x100 -#define ST_DOSIGS 0x200 -#define ST_GETSIGS 0x400 -#define ST_DTRWAIT 0x800 - -/* - * Define an array of board names as printable strings. Handy for - * referencing boards when printing trace and stuff. - */ -static char *stli_brdnames[] = { - "Unknown", - "Stallion", - "Brumby", - "ONboard-MC", - "ONboard", - "Brumby", - "Brumby", - "ONboard-EI", - (char *) NULL, - "ONboard", - "ONboard-MC", - "ONboard-MC", - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EasyIO", - "EC8/32-AT", - "EC8/32-MC", - "EC8/64-AT", - "EC8/64-EI", - "EC8/64-MC", - "EC8/32-PCI", -}; - -/*****************************************************************************/ - -/* - * Hardware configuration info for ECP boards. These defines apply - * to the directly accessible io ports of the ECP. There is a set of - * defines for each ECP board type, ISA, EISA and MCA. - */ -#define ECP_IOSIZE 4 -#define ECP_MEMSIZE (128 * 1024) -#define ECP_ATPAGESIZE (4 * 1024) -#define ECP_EIPAGESIZE (64 * 1024) -#define ECP_MCPAGESIZE (4 * 1024) - -#define STL_EISAID 0x8c4e - -/* - * Important defines for the ISA class of ECP board. - */ -#define ECP_ATIREG 0 -#define ECP_ATCONFR 1 -#define ECP_ATMEMAR 2 -#define ECP_ATMEMPR 3 -#define ECP_ATSTOP 0x1 -#define ECP_ATINTENAB 0x10 -#define ECP_ATENABLE 0x20 -#define ECP_ATDISABLE 0x00 -#define ECP_ATADDRMASK 0x3f000 -#define ECP_ATADDRSHFT 12 - -/* - * Important defines for the EISA class of ECP board. - */ -#define ECP_EIIREG 0 -#define ECP_EIMEMARL 1 -#define ECP_EICONFR 2 -#define ECP_EIMEMARH 3 -#define ECP_EIENABLE 0x1 -#define ECP_EIDISABLE 0x0 -#define ECP_EISTOP 0x4 -#define ECP_EIEDGE 0x00 -#define ECP_EILEVEL 0x80 -#define ECP_EIADDRMASKL 0x00ff0000 -#define ECP_EIADDRSHFTL 16 -#define ECP_EIADDRMASKH 0xff000000 -#define ECP_EIADDRSHFTH 24 -#define ECP_EIBRDENAB 0xc84 - -#define ECP_EISAID 0x4 - -/* - * Important defines for the Micro-channel class of ECP board. - * (It has a lot in common with the ISA boards.) - */ -#define ECP_MCIREG 0 -#define ECP_MCCONFR 1 -#define ECP_MCSTOP 0x20 -#define ECP_MCENABLE 0x80 -#define ECP_MCDISABLE 0x00 - -/* - * Hardware configuration info for ONboard and Brumby boards. These - * defines apply to the directly accessible io ports of these boards. - */ -#define ONB_IOSIZE 16 -#define ONB_MEMSIZE (64 * 1024) -#define ONB_ATPAGESIZE (64 * 1024) -#define ONB_MCPAGESIZE (64 * 1024) -#define ONB_EIMEMSIZE (128 * 1024) -#define ONB_EIPAGESIZE (64 * 1024) - -/* - * Important defines for the ISA class of ONboard board. - */ -#define ONB_ATIREG 0 -#define ONB_ATMEMAR 1 -#define ONB_ATCONFR 2 -#define ONB_ATSTOP 0x4 -#define ONB_ATENABLE 0x01 -#define ONB_ATDISABLE 0x00 -#define ONB_ATADDRMASK 0xff0000 -#define ONB_ATADDRSHFT 16 - -#define ONB_HIMEMENAB 0x02 - -/* - * Important defines for the EISA class of ONboard board. - */ -#define ONB_EIIREG 0 -#define ONB_EIMEMARL 1 -#define ONB_EICONFR 2 -#define ONB_EIMEMARH 3 -#define ONB_EIENABLE 0x1 -#define ONB_EIDISABLE 0x0 -#define ONB_EISTOP 0x4 -#define ONB_EIEDGE 0x00 -#define ONB_EILEVEL 0x80 -#define ONB_EIADDRMASKL 0x00ff0000 -#define ONB_EIADDRSHFTL 16 -#define ONB_EIADDRMASKH 0xff000000 -#define ONB_EIADDRSHFTH 24 -#define ONB_EIBRDENAB 0xc84 - -#define ONB_EISAID 0x1 - -/* - * Important defines for the Brumby boards. They are pretty simple, - * there is not much that is programmably configurable. - */ -#define BBY_IOSIZE 16 -#define BBY_MEMSIZE (64 * 1024) -#define BBY_PAGESIZE (16 * 1024) - -#define BBY_ATIREG 0 -#define BBY_ATCONFR 1 -#define BBY_ATSTOP 0x4 - -/* - * Important defines for the Stallion boards. They are pretty simple, - * there is not much that is programmably configurable. - */ -#define STAL_IOSIZE 16 -#define STAL_MEMSIZE (64 * 1024) -#define STAL_PAGESIZE (64 * 1024) - -/* - * Define the set of status register values for EasyConnection panels. - * The signature will return with the status value for each panel. From - * this we can determine what is attached to the board - before we have - * actually down loaded any code to it. - */ -#define ECH_PNLSTATUS 2 -#define ECH_PNL16PORT 0x20 -#define ECH_PNLIDMASK 0x07 -#define ECH_PNLINTRPEND 0x80 - -/* - * Define some macros to do things to the board. Even those these boards - * are somewhat related there is often significantly different ways of - * doing some operation on it (like enable, paging, reset, etc). So each - * board class has a set of functions which do the commonly required - * operations. The macros below basically just call these functions, - * generally checking for a NULL function - which means that the board - * needs nothing done to it to achieve this operation! - */ -#define EBRDINIT(brdp) \ - if (brdp->init != NULL) \ - (* brdp->init)(brdp) - -#define EBRDENABLE(brdp) \ - if (brdp->enable != NULL) \ - (* brdp->enable)(brdp); - -#define EBRDDISABLE(brdp) \ - if (brdp->disable != NULL) \ - (* brdp->disable)(brdp); - -#define EBRDINTR(brdp) \ - if (brdp->intr != NULL) \ - (* brdp->intr)(brdp); - -#define EBRDRESET(brdp) \ - if (brdp->reset != NULL) \ - (* brdp->reset)(brdp); - -#define EBRDGETMEMPTR(brdp,offset) \ - (* brdp->getmemptr)(brdp, offset, __LINE__) - -/* - * Define the maximal baud rate. - */ -#define STL_MAXBAUD 230400 - -/*****************************************************************************/ - -/* - * Define macros to extract a brd and port number from a minor number. - * This uses the extended minor number range in the upper 2 bytes of - * the device number. This gives us plenty of minor numbers to play - * with... - */ -#define MKDEV2BRD(m) ((minor(m) & 0x00700000) >> 20) -#define MKDEV2PORT(m) ((minor(m) & 0x1f) | ((minor(m) & 0x00010000) >> 11)) - -/* - * Define some handy local macros... - */ -#ifndef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) -#endif - -/*****************************************************************************/ - -/* - * Declare all those functions in this driver! First up is the set of - * externally visible functions. - */ -static int stliprobe(struct isa_device *idp); -static int stliattach(struct isa_device *idp); - -STATIC d_open_t stliopen; -STATIC d_close_t stliclose; -STATIC d_read_t stliread; -STATIC d_write_t stliwrite; -STATIC d_ioctl_t stliioctl; - -/* - * Internal function prototypes. - */ -static stliport_t *stli_dev2port(dev_t dev); -static int stli_isaprobe(struct isa_device *idp); -static int stli_eisaprobe(struct isa_device *idp); -static int stli_mcaprobe(struct isa_device *idp); -static int stli_brdinit(stlibrd_t *brdp); -static int stli_brdattach(stlibrd_t *brdp); -static int stli_initecp(stlibrd_t *brdp); -static int stli_initonb(stlibrd_t *brdp); -static int stli_initports(stlibrd_t *brdp); -static int stli_startbrd(stlibrd_t *brdp); -static void stli_poll(void *arg); -static __inline void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp); -static __inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp); -static __inline void stli_dodelaycmd(stliport_t *portp, - volatile cdkctrl_t *cp); -static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); -static long stli_mktiocm(unsigned long sigvalue); -static void stli_rxprocess(stlibrd_t *brdp, stliport_t *portp); -static void stli_flush(stliport_t *portp, int flag); -static void stli_start(struct tty *tp); -static void stli_stop(struct tty *tp, int rw); -static int stli_param(struct tty *tp, struct termios *tiosp); -static void stli_ttyoptim(stliport_t *portp, struct termios *tiosp); -static void stli_dtrwakeup(void *arg); -static int stli_initopen(stliport_t *portp); -static int stli_shutdownclose(stliport_t *portp); -static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, - unsigned long arg, int wait); -static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, - unsigned long arg, int wait); -static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, - unsigned long cmd, void *arg, int size, int copyback); -static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, - unsigned long cmd, void *arg, int size, int copyback); -static void stli_mkasyport(stliport_t *portp, asyport_t *pp, - struct termios *tiosp); -static int stli_memrw(dev_t dev, struct uio *uiop, int flag); -static int stli_memioctl(dev_t dev, unsigned long cmd, caddr_t data, - int flag, struct thread *td); -static int stli_getbrdstats(caddr_t data); -static int stli_getportstats(stliport_t *portp, caddr_t data); -static int stli_clrportstats(stliport_t *portp, caddr_t data); -static stliport_t *stli_getport(int brdnr, int panelnr, int portnr); - -static void stli_ecpinit(stlibrd_t *brdp); -static void stli_ecpenable(stlibrd_t *brdp); -static void stli_ecpdisable(stlibrd_t *brdp); -static void stli_ecpreset(stlibrd_t *brdp); -static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); -static void stli_ecpintr(stlibrd_t *brdp); -static void stli_ecpeiinit(stlibrd_t *brdp); -static void stli_ecpeienable(stlibrd_t *brdp); -static void stli_ecpeidisable(stlibrd_t *brdp); -static void stli_ecpeireset(stlibrd_t *brdp); -static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); -static void stli_ecpmcenable(stlibrd_t *brdp); -static void stli_ecpmcdisable(stlibrd_t *brdp); -static void stli_ecpmcreset(stlibrd_t *brdp); -static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); - -static void stli_onbinit(stlibrd_t *brdp); -static void stli_onbenable(stlibrd_t *brdp); -static void stli_onbdisable(stlibrd_t *brdp); -static void stli_onbreset(stlibrd_t *brdp); -static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); -static void stli_onbeinit(stlibrd_t *brdp); -static void stli_onbeenable(stlibrd_t *brdp); -static void stli_onbedisable(stlibrd_t *brdp); -static void stli_onbereset(stlibrd_t *brdp); -static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); -static void stli_bbyinit(stlibrd_t *brdp); -static void stli_bbyreset(stlibrd_t *brdp); -static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); -static void stli_stalinit(stlibrd_t *brdp); -static void stli_stalreset(stlibrd_t *brdp); -static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, - int line); - -/*****************************************************************************/ - -/* - * Declare the driver isa structure. - */ -struct isa_driver stlidriver = { - INTR_TYPE_TTY, - stliprobe, - stliattach, - stli_drvname -}; -COMPAT_ISA_DRIVER(stli, stlidriver); - -/*****************************************************************************/ - -#if VFREEBSD >= 220 - -/* - * FreeBSD-2.2+ kernel linkage. - */ - -static struct cdevsw stli_cdevsw = { - .d_version = D_VERSION, - .d_open = stliopen, - .d_close = stliclose, - .d_read = stliread, - .d_write = stliwrite, - .d_ioctl = stliioctl, - .d_name = stli_drvname, - .d_flags = D_TTY | D_NEEDGIANT, -}; - -#endif - -/*****************************************************************************/ - -static stlibrd_t *stli_brdalloc(void) -{ - stlibrd_t *brdp; - - brdp = (stlibrd_t *) malloc(sizeof(stlibrd_t), M_TTYS, M_NOWAIT|M_ZERO); - if (brdp == (stlibrd_t *) NULL) { - printf("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlibrd_t)); - return((stlibrd_t *) NULL); - } - return(brdp); -} - -/*****************************************************************************/ - -/* - * Find an available internal board number (unit number). The problem - * is that the same unit numbers can be assigned to different class - * boards - but we only want to maintain one setup board structures. - */ - -static int stli_findfreeunit(void) -{ - int i; - - for (i = 0; (i < STL_MAXBRDS); i++) - if (stli_brds[i] == (stlibrd_t *) NULL) - break; - return((i >= STL_MAXBRDS) ? -1 : i); -} - -/*****************************************************************************/ - -/* - * Try and determine the ISA board type. Hopefully the board - * configuration entry will help us out, using the flags field. - * If not, we may ne be able to determine the board type... - */ - -static int stli_isaprobe(struct isa_device *idp) -{ - int btype; - -#if DEBUG - printf("stli_isaprobe(idp=%x): unit=%d iobase=%x flags=%x\n", - (int) idp, idp->id_unit, idp->id_iobase, idp->id_flags); -#endif - - switch (idp->id_flags) { - case BRD_STALLION: - case BRD_BRUMBY4: - case BRD_BRUMBY8: - case BRD_BRUMBY16: - case BRD_ONBOARD: - case BRD_ONBOARD32: - case BRD_ECP: - btype = idp->id_flags; - break; - default: - btype = 0; - break; - } - return(btype); -} - -/*****************************************************************************/ - -/* - * Probe for an EISA board type. We should be able to read the EISA ID, - * that will tell us if a board is present or not... - */ - -static int stli_eisaprobe(struct isa_device *idp) -{ - int btype, eid; - -#if DEBUG - printf("stli_eisaprobe(idp=%x): unit=%d iobase=%x flags=%x\n", - (int) idp, idp->id_unit, idp->id_iobase, idp->id_flags); -#endif - -/* - * Firstly check if this is an EISA system. Do this by probing for - * the system board EISA ID. If this is not an EISA system then - * don't bother going any further! - */ - outb(0xc80, 0xff); - if (inb(0xc80) == 0xff) - return(0); - -/* - * Try and read the EISA ID from the board at specified address. - * If one is present it will tell us the board type as well. - */ - outb((idp->id_iobase + 0xc80), 0xff); - eid = inb(idp->id_iobase + 0xc80); - eid |= inb(idp->id_iobase + 0xc81) << 8; - if (eid != STL_EISAID) - return(0); - - btype = 0; - eid = inb(idp->id_iobase + 0xc82); - if (eid == ECP_EISAID) - btype = BRD_ECPE; - else if (eid == ONB_EISAID) - btype = BRD_ONBOARDE; - - outb((idp->id_iobase + 0xc84), 0x1); - return(btype); -} - -/*****************************************************************************/ - -/* - * Probe for an MCA board type. Not really sure how to do this yet, - * so for now just use the supplied flag specifier as board type... - */ - -static int stli_mcaprobe(struct isa_device *idp) -{ - int btype; - -#if DEBUG - printf("stli_mcaprobe(idp=%x): unit=%d iobase=%x flags=%x\n", - (int) idp, idp->id_unit, idp->id_iobase, idp->id_flags); -#endif - - switch (idp->id_flags) { - case BRD_ONBOARD2: - case BRD_ONBOARD2_32: - case BRD_ONBOARDRS: - case BRD_ECHMC: - case BRD_ECPMC: - btype = idp->id_flags; - break; - default: - btype = 0; - break; - } - return(0); -} - -/*****************************************************************************/ - -/* - * Probe for a board. This is involved, since we need to enable the - * shared memory region to see if the board is really there or not... - */ - -static int stliprobe(struct isa_device *idp) -{ - stlibrd_t *brdp; - int btype, bclass; - -#if DEBUG - printf("stliprobe(idp=%x): unit=%d iobase=%x flags=%x\n", (int) idp, - idp->id_unit, idp->id_iobase, idp->id_flags); -#endif - - if (idp->id_unit > STL_MAXBRDS) - return(0); - -/* - * First up determine what bus type of board we might be dealing - * with. It is easy to separate out the ISA from the EISA and MCA - * boards, based on their IO addresses. We may not be able to tell - * the EISA and MCA apart on IO address alone... - */ - bclass = 0; - if ((idp->id_iobase > 0) && (idp->id_iobase < 0x400)) { - bclass |= BRD_ISA; - } else { - /* ONboard2 range */ - if ((idp->id_iobase >= 0x700) && (idp->id_iobase < 0x900)) - bclass |= BRD_MCA; - /* EC-MCA ranges */ - if ((idp->id_iobase >= 0x7000) && (idp->id_iobase < 0x7400)) - bclass |= BRD_MCA; - if ((idp->id_iobase >= 0x8000) && (idp->id_iobase < 0xc000)) - bclass |= BRD_MCA; - /* EISA board range */ - if ((idp->id_iobase & ~0xf000) == 0) - bclass |= BRD_EISA; - } - - if ((bclass == 0) || (idp->id_iobase == 0)) - return(0); - -/* - * Based on the board bus type, try and figure out what it might be... - */ - btype = 0; - if (bclass & BRD_ISA) - btype = stli_isaprobe(idp); - if ((btype == 0) && (bclass & BRD_EISA)) - btype = stli_eisaprobe(idp); - if ((btype == 0) && (bclass & BRD_MCA)) - btype = stli_mcaprobe(idp); - if (btype == 0) - return(0); - -/* - * Go ahead and try probing for the shared memory region now. - * This way we will really know if the board is here... - */ - if ((brdp = stli_brdalloc()) == (stlibrd_t *) NULL) - return(0); - - brdp->brdnr = stli_findfreeunit(); - brdp->brdtype = btype; - brdp->unitid = idp->id_unit; - brdp->iobase = idp->id_iobase; - brdp->vaddr = idp->id_maddr; - brdp->paddr = vtophys(idp->id_maddr); - -#if DEBUG - printf("%s(%d): btype=%x unit=%d brd=%d io=%x mem=%lx(%p)\n", - __file__, __LINE__, btype, brdp->unitid, brdp->brdnr, - brdp->iobase, brdp->paddr, (void *) brdp->vaddr); -#endif - - stli_stliprobed[idp->id_unit] = brdp->brdnr; - stli_brdinit(brdp); - if ((brdp->state & BST_FOUND) == 0) { - stli_brds[brdp->brdnr] = (stlibrd_t *) NULL; - return(0); - } - stli_nrbrds++; - return(1); -} - -/*****************************************************************************/ - -/* - * Allocate resources for and initialize a board. - */ - -static int stliattach(struct isa_device *idp) -{ - stlibrd_t *brdp; - int brdnr; - -#if DEBUG - printf("stliattach(idp=%p): unit=%d iobase=%x\n", (void *) idp, - idp->id_unit, idp->id_iobase); -#endif - - brdnr = stli_stliprobed[idp->id_unit]; - brdp = stli_brds[brdnr]; - if (brdp == (stlibrd_t *) NULL) - return(0); - if (brdp->state & BST_FOUND) - stli_brdattach(brdp); - if (0) { - make_dev(&stli_cdevsw, 0, 0, 0, 0, "istallion_is_broken"); - } - return(1); -} - - -/*****************************************************************************/ - -STATIC int stliopen(dev_t dev, int flag, int mode, struct thread *td) -{ - struct tty *tp; - stliport_t *portp; - int error, callout, x; - -#if DEBUG - printf("stliopen(dev=%x,flag=%x,mode=%x,p=%x)\n", (int) dev, flag, - mode, (int) td); -#endif - -/* - * Firstly check if the supplied device number is a valid device. - */ - if (minor(dev) & STL_MEMDEV) - return(0); - - portp = stli_dev2port(dev); - if (portp == (stliport_t *) NULL) - return(ENXIO); - tp = &portp->tty; - dev->si_tty = tp; - callout = minor(dev) & STL_CALLOUTDEV; - error = 0; - - x = spltty(); - -stliopen_restart: -/* - * Wait here for the DTR drop timeout period to expire. - */ - while (portp->state & ST_DTRWAIT) { - error = tsleep(&portp->dtrwait, (TTIPRI | PCATCH), - "stlidtr", 0); - if (error) - goto stliopen_end; - } - -/* - * If the port is in its raw hardware initialization phase, then - * hold up here 'till it is done. - */ - while (portp->state & (ST_INITIALIZING | ST_CLOSING)) { - error = tsleep(&portp->state, (TTIPRI | PCATCH), - "stliraw", 0); - if (error) - goto stliopen_end; - } - -/* - * We have a valid device, so now we check if it is already open. - * If not then initialize the port hardware and set up the tty - * struct as required. - */ - if ((tp->t_state & TS_ISOPEN) == 0) { - tp->t_oproc = stli_start; - tp->t_param = stli_param; - tp->t_stop = stli_stop; - tp->t_dev = dev; - tp->t_termios = callout ? portp->initouttios : - portp->initintios; - stli_initopen(portp); - wakeup(&portp->state); - if ((portp->sigs & TIOCM_CD) || callout) - (*linesw[tp->t_line].l_modem)(tp, 1); - } else { - if (callout) { - if (portp->callout == 0) { - error = EBUSY; - goto stliopen_end; - } - } else { - if (portp->callout != 0) { - if (flag & O_NONBLOCK) { - error = EBUSY; - goto stliopen_end; - } - error = tsleep(&portp->callout, - (TTIPRI | PCATCH), "stlicall", 0); - if (error) - goto stliopen_end; - goto stliopen_restart; - } - } - if ((tp->t_state & TS_XCLUDE) && - suser(td)) { - error = EBUSY; - goto stliopen_end; - } - } - -/* - * If this port is not the callout device and we do not have carrier - * then we need to sleep, waiting for it to be asserted. - */ - if (((tp->t_state & TS_CARR_ON) == 0) && !callout && - ((tp->t_cflag & CLOCAL) == 0) && - ((flag & O_NONBLOCK) == 0)) { - portp->waitopens++; - error = tsleep(TSA_CARR_ON(tp), (TTIPRI | PCATCH), "stlidcd",0); - portp->waitopens--; - if (error) - goto stliopen_end; - goto stliopen_restart; - } - -/* - * Open the line discipline. - */ - error = (*linesw[tp->t_line].l_open)(dev, tp); - stli_ttyoptim(portp, &tp->t_termios); - if ((tp->t_state & TS_ISOPEN) && callout) - portp->callout = 1; - -/* - * If for any reason we get to here and the port is not actually - * open then close of the physical hardware - no point leaving it - * active when the open failed... - */ -stliopen_end: - splx(x); - if (((tp->t_state & TS_ISOPEN) == 0) && (portp->waitopens == 0)) - stli_shutdownclose(portp); - - return(error); -} - -/*****************************************************************************/ - -STATIC int stliclose(dev_t dev, int flag, int mode, struct thread *td) -{ - struct tty *tp; - stliport_t *portp; - int x; - -#if DEBUG - printf("stliclose(dev=%s,flag=%x,mode=%x,p=%p)\n", - devtoname(dev), flag, mode, (void *) td); -#endif - - if (minor(dev) & STL_MEMDEV) - return(0); - - portp = stli_dev2port(dev); - if (portp == (stliport_t *) NULL) - return(ENXIO); - tp = &portp->tty; - - x = spltty(); - (*linesw[tp->t_line].l_close)(tp, flag); - stli_ttyoptim(portp, &tp->t_termios); - stli_shutdownclose(portp); - ttyclose(tp); - splx(x); - return(0); -} - - -STATIC int stliread(dev_t dev, struct uio *uiop, int flag) -{ - -#if DEBUG - printf("stliread(dev=%s,uiop=%p,flag=%x)\n", devtoname(dev), - (void *) uiop, flag); -#endif - - if (minor(dev) & STL_MEMDEV) - return(stli_memrw(dev, uiop, flag)); - else - return(ttyread(dev, uiop, flag)); -} - -/*****************************************************************************/ - -#if VFREEBSD >= 220 - -STATIC void stli_stop(struct tty *tp, int rw) -{ -#if DEBUG - printf("stli_stop(tp=%x,rw=%x)\n", (int) tp, rw); -#endif - - stli_flush((stliport_t *) tp, rw); -} - -#else - -STATIC int stlistop(struct tty *tp, int rw) -{ -#if DEBUG - printf("stlistop(tp=%x,rw=%x)\n", (int) tp, rw); -#endif - - stli_flush((stliport_t *) tp, rw); - return(0); -} - -#endif - -/*****************************************************************************/ - -STATIC int stliwrite(dev_t dev, struct uio *uiop, int flag) -{ -#if DEBUG - printf("stliwrite(dev=%s,uiop=%p,flag=%x)\n", devtoname(dev), - (void *) uiop, flag); -#endif - - if (minor(dev) & STL_MEMDEV) - return(stli_memrw(dev, uiop, flag)); - else - return(ttywrite(dev, uiop, flag)); -} - -/*****************************************************************************/ - -STATIC int stliioctl(dev_t dev, unsigned long cmd, caddr_t data, int flag, - struct thread *td) -{ - struct termios *newtios, *localtios; - struct tty *tp; - stlibrd_t *brdp; - stliport_t *portp; - long arg; - int error, i, x; - -#if DEBUG - printf("stliioctl(dev=%s,cmd=%lx,data=%p,flag=%x,p=%p)\n", - devtoname(dev), cmd, (void *) data, flag, (void *) td); -#endif - - if (minor(dev) & STL_MEMDEV) - return(stli_memioctl(dev, cmd, data, flag, td)); - - portp = stli_dev2port(dev); - if (portp == (stliport_t *) NULL) - return(ENODEV); - if ((brdp = stli_brds[portp->brdnr]) == (stlibrd_t *) NULL) - return(ENODEV); - tp = &portp->tty; - error = 0; - -/* - * First up handle ioctls on the control devices. - */ - if (minor(dev) & STL_CTRLDEV) { - if ((minor(dev) & STL_CTRLDEV) == STL_CTRLINIT) - localtios = (minor(dev) & STL_CALLOUTDEV) ? - &portp->initouttios : &portp->initintios; - else if ((minor(dev) & STL_CTRLDEV) == STL_CTRLLOCK) - localtios = (minor(dev) & STL_CALLOUTDEV) ? - &portp->lockouttios : &portp->lockintios; - else - return(ENODEV); - - switch (cmd) { - case TIOCSETA: - if ((error = suser(td)) == 0) - *localtios = *((struct termios *) data); - break; - case TIOCGETA: - *((struct termios *) data) = *localtios; - break; - case TIOCGETD: - *((int *) data) = TTYDISC; - break; - case TIOCGWINSZ: - bzero(data, sizeof(struct winsize)); - break; - default: - error = ENOTTY; - break; - } - return(error); - } - -/* - * Deal with 4.3 compatibility issues if we have too... - */ -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) - if (1) { - struct termios tios; - unsigned long oldcmd; - - tios = tp->t_termios; - oldcmd = cmd; - if ((error = ttsetcompat(tp, &cmd, data, &tios))) - return(error); - if (cmd != oldcmd) - data = (caddr_t) &tios; - } -#endif - -/* - * Carry out some pre-cmd processing work first... - * Hmmm, not so sure we want this, disable for now... - */ - if ((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) { - newtios = (struct termios *) data; - localtios = (minor(dev) & STL_CALLOUTDEV) ? &portp->lockouttios : - &portp->lockintios; - - newtios->c_iflag = (tp->t_iflag & localtios->c_iflag) | - (newtios->c_iflag & ~localtios->c_iflag); - newtios->c_oflag = (tp->t_oflag & localtios->c_oflag) | - (newtios->c_oflag & ~localtios->c_oflag); - newtios->c_cflag = (tp->t_cflag & localtios->c_cflag) | - (newtios->c_cflag & ~localtios->c_cflag); - newtios->c_lflag = (tp->t_lflag & localtios->c_lflag) | - (newtios->c_lflag & ~localtios->c_lflag); - for (i = 0; (i < NCCS); i++) { - if (localtios->c_cc[i] != 0) - newtios->c_cc[i] = tp->t_cc[i]; - } - if (localtios->c_ispeed != 0) - newtios->c_ispeed = tp->t_ispeed; - if (localtios->c_ospeed != 0) - newtios->c_ospeed = tp->t_ospeed; - } - -/* - * Call the line discipline and the common command processing to - * process this command (if they can). - */ - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); - if (error != ENOIOCTL) - return(error); - - x = spltty(); - error = ttioctl(tp, cmd, data, flag); - stli_ttyoptim(portp, &tp->t_termios); - if (error != ENOIOCTL) { - splx(x); - return(error); - } - - error = 0; - -/* - * Process local commands here. These are all commands that only we - * can take care of (they all rely on actually doing something special - * to the actual hardware). - */ - switch (cmd) { - case TIOCSBRK: - arg = BREAKON; - error = stli_cmdwait(brdp, portp, A_BREAK, &arg, - sizeof(unsigned long), 0); - break; - case TIOCCBRK: - arg = BREAKOFF; - error = stli_cmdwait(brdp, portp, A_BREAK, &arg, - sizeof(unsigned long), 0); - break; - case TIOCSDTR: - stli_mkasysigs(&portp->asig, 1, -1); - error = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0); - break; - case TIOCCDTR: - stli_mkasysigs(&portp->asig, 0, -1); - error = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0); - break; - case TIOCMSET: - i = *((int *) data); - stli_mkasysigs(&portp->asig, ((i & TIOCM_DTR) ? 1 : 0), - ((i & TIOCM_RTS) ? 1 : 0)); - error = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0); - break; - case TIOCMBIS: - i = *((int *) data); - stli_mkasysigs(&portp->asig, ((i & TIOCM_DTR) ? 1 : -1), - ((i & TIOCM_RTS) ? 1 : -1)); - error = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0); - break; - case TIOCMBIC: - i = *((int *) data); - stli_mkasysigs(&portp->asig, ((i & TIOCM_DTR) ? 0 : -1), - ((i & TIOCM_RTS) ? 0 : -1)); - error = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0); - break; - case TIOCMGET: - if ((error = stli_cmdwait(brdp, portp, A_GETSIGNALS, - &portp->asig, sizeof(asysigs_t), 1)) < 0) - break; - portp->sigs = stli_mktiocm(portp->asig.sigvalue); - *((int *) data) = (portp->sigs | TIOCM_LE); - break; - case TIOCMSDTRWAIT: - if ((error = suser(td)) == 0) - portp->dtrwait = *((int *) data) * hz / 100; - break; - case TIOCMGDTRWAIT: - *((int *) data) = portp->dtrwait * 100 / hz; - break; - case TIOCTIMESTAMP: - portp->dotimestamp = 1; - *((struct timeval *) data) = portp->timestamp; - break; - default: - error = ENOTTY; - break; - } - splx(x); - - return(error); -} - -/*****************************************************************************/ - -/* - * Convert the specified minor device number into a port struct - * pointer. Return NULL if the device number is not a valid port. - */ - -STATIC stliport_t *stli_dev2port(dev_t dev) -{ - stlibrd_t *brdp; - - brdp = stli_brds[MKDEV2BRD(dev)]; - if (brdp == (stlibrd_t *) NULL) - return((stliport_t *) NULL); - if ((brdp->state & BST_STARTED) == 0) - return((stliport_t *) NULL); - return(brdp->ports[MKDEV2PORT(dev)]); -} - -/*****************************************************************************/ - -/* - * Carry out first open operations on a port. This involves a number of - * commands to be sent to the slave. We need to open the port, set the - * notification events, set the initial port settings, get and set the - * initial signal values. We sleep and wait in between each one. But - * this still all happens pretty quickly. - */ - -static int stli_initopen(stliport_t *portp) -{ - stlibrd_t *brdp; - asynotify_t nt; - asyport_t aport; - int rc; - -#if DEBUG - printf("stli_initopen(portp=%x)\n", (int) portp); -#endif - - if ((brdp = stli_brds[portp->brdnr]) == (stlibrd_t *) NULL) - return(ENXIO); - if (portp->state & ST_INITIALIZED) - return(0); - portp->state |= ST_INITIALIZED; - - if ((rc = stli_rawopen(brdp, portp, 0, 1)) < 0) - return(rc); - - bzero(&nt, sizeof(asynotify_t)); - nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK); - nt.signal = SG_DCD; - if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt, - sizeof(asynotify_t), 0)) < 0) - return(rc); - - stli_mkasyport(portp, &aport, &portp->tty.t_termios); - if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, - sizeof(asyport_t), 0)) < 0) - return(rc); - - portp->state |= ST_GETSIGS; - if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, - sizeof(asysigs_t), 1)) < 0) - return(rc); - if (portp->state & ST_GETSIGS) { - portp->sigs = stli_mktiocm(portp->asig.sigvalue); - portp->state &= ~ST_GETSIGS; - } - - stli_mkasysigs(&portp->asig, 1, 1); - if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, - sizeof(asysigs_t), 0)) < 0) - return(rc); - - return(0); -} - -/*****************************************************************************/ - -/* - * Shutdown the hardware of a port. - */ - -static int stli_shutdownclose(stliport_t *portp) -{ - stlibrd_t *brdp; - struct tty *tp; - int x; - -#if DEBUG - printf("stli_shutdownclose(portp=%p): brdnr=%d panelnr=%d portnr=%d\n", - (void *) portp, portp->brdnr, portp->panelnr, portp->portnr); -#endif - - if ((brdp = stli_brds[portp->brdnr]) == (stlibrd_t *) NULL) - return(ENXIO); - - tp = &portp->tty; - stli_rawclose(brdp, portp, 0, 0); - stli_flush(portp, (FWRITE | FREAD)); - if (tp->t_cflag & HUPCL) { - x = spltty(); - stli_mkasysigs(&portp->asig, 0, 0); - if (portp->state & ST_CMDING) { - portp->state |= ST_DOSIGS; - } else { - stli_sendcmd(brdp, portp, A_SETSIGNALS, - &portp->asig, sizeof(asysigs_t), 0); - } - splx(x); - if (portp->dtrwait != 0) { - portp->state |= ST_DTRWAIT; - timeout(stli_dtrwakeup, portp, portp->dtrwait); - } - } - portp->callout = 0; - portp->state &= ~ST_INITIALIZED; - wakeup(&portp->callout); - wakeup(TSA_CARR_ON(tp)); - return(0); -} - -/*****************************************************************************/ - -/* - * Clear the DTR waiting flag, and wake up any sleepers waiting for - * DTR wait period to finish. - */ - -static void stli_dtrwakeup(void *arg) -{ - stliport_t *portp; - - portp = (stliport_t *) arg; - portp->state &= ~ST_DTRWAIT; - wakeup(&portp->dtrwait); -} - -/*****************************************************************************/ - -/* - * Send an open message to the slave. This will sleep waiting for the - * acknowledgement, so must have user context. We need to co-ordinate - * with close events here, since we don't want open and close events - * to overlap. - */ - -static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait) -{ - volatile cdkhdr_t *hdrp; - volatile cdkctrl_t *cp; - volatile unsigned char *bits; - int rc, x; - -#if DEBUG - printf("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n", (int) brdp, - (int) portp, (int) arg, wait); -#endif - - x = spltty(); - -/* - * Slave is already closing this port. This can happen if a hangup - * occurs on this port. So we must wait until it is complete. The - * order of opens and closes may not be preserved across shared - * memory, so we must wait until it is complete. - */ - while (portp->state & ST_CLOSING) { - rc = tsleep(&portp->state, (TTIPRI | PCATCH), "stliraw", 0); - if (rc) { - splx(x); - return(rc); - } - } - -/* - * Everything is ready now, so write the open message into shared - * memory. Once the message is in set the service bits to say that - * this port wants service. - */ - EBRDENABLE(brdp); - cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; - cp->openarg = arg; - cp->open = 1; - hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + - portp->portidx; - *bits |= portp->portbit; - EBRDDISABLE(brdp); - - if (wait == 0) { - splx(x); - return(0); - } - -/* - * Slave is in action, so now we must wait for the open acknowledgment - * to come back. - */ - rc = 0; - portp->state |= ST_OPENING; - while (portp->state & ST_OPENING) { - rc = tsleep(&portp->state, (TTIPRI | PCATCH), "stliraw", 0); - if (rc) { - splx(x); - return(rc); - } - } - splx(x); - - if ((rc == 0) && (portp->rc != 0)) - rc = EIO; - return(rc); -} - -/*****************************************************************************/ - -/* - * Send a close message to the slave. Normally this will sleep waiting - * for the acknowledgement, but if wait parameter is 0 it will not. If - * wait is true then must have user context (to sleep). - */ - -static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait) -{ - volatile cdkhdr_t *hdrp; - volatile cdkctrl_t *cp; - volatile unsigned char *bits; - int rc, x; - -#if DEBUG - printf("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n", (int) brdp, - (int) portp, (int) arg, wait); -#endif - - x = spltty(); - -/* - * Slave is already closing this port. This can happen if a hangup - * occurs on this port. - */ - if (wait) { - while (portp->state & ST_CLOSING) { - rc = tsleep(&portp->state, (TTIPRI | PCATCH), - "stliraw", 0); - if (rc) { - splx(x); - return(rc); - } - } - } - -/* - * Write the close command into shared memory. - */ - EBRDENABLE(brdp); - cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; - cp->closearg = arg; - cp->close = 1; - hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + - portp->portidx; - *bits |= portp->portbit; - EBRDDISABLE(brdp); - - portp->state |= ST_CLOSING; - if (wait == 0) { - splx(x); - return(0); - } - -/* - * Slave is in action, so now we must wait for the open acknowledgment - * to come back. - */ - rc = 0; - while (portp->state & ST_CLOSING) { - rc = tsleep(&portp->state, (TTIPRI | PCATCH), "stliraw", 0); - if (rc) { - splx(x); - return(rc); - } - } - splx(x); - - if ((rc == 0) && (portp->rc != 0)) - rc = EIO; - return(rc); -} - -/*****************************************************************************/ - -/* - * Send a command to the slave and wait for the response. This must - * have user context (it sleeps). This routine is generic in that it - * can send any type of command. Its purpose is to wait for that command - * to complete (as opposed to initiating the command then returning). - */ - -static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback) -{ - int rc, x; - -#if DEBUG - printf("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d," - "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, - (int) arg, size, copyback); -#endif - - x = spltty(); - while (portp->state & ST_CMDING) { - rc = tsleep(&portp->state, (TTIPRI | PCATCH), "stliraw", 0); - if (rc) { - splx(x); - return(rc); - } - } - - stli_sendcmd(brdp, portp, cmd, arg, size, copyback); - - while (portp->state & ST_CMDING) { - rc = tsleep(&portp->state, (TTIPRI | PCATCH), "stliraw", 0); - if (rc) { - splx(x); - return(rc); - } - } - splx(x); - - if (portp->rc != 0) - return(EIO); - return(0); -} - -/*****************************************************************************/ - -/* - * Start (or continue) the transfer of TX data on this port. If the - * port is not currently busy then load up the interrupt ring queue - * buffer and kick of the transmitter. If the port is running low on - * TX data then refill the ring queue. This routine is also used to - * activate input flow control! - */ - -static void stli_start(struct tty *tp) -{ - volatile cdkasy_t *ap; - volatile cdkhdr_t *hdrp; - volatile unsigned char *bits; - unsigned char *shbuf; - stliport_t *portp; - stlibrd_t *brdp; - unsigned int len, stlen, head, tail, size; - int count, x; - - portp = (stliport_t *) tp; - -#if DEBUG - printf("stli_start(tp=%x): brdnr=%d portnr=%d\n", (int) tp, - portp->brdnr, portp->portnr); -#endif - - x = spltty(); - -#if VFREEBSD == 205 -/* - * Check if the output cooked clist buffers are near empty, wake up - * the line discipline to fill it up. - */ - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state & TS_ASLEEP) { - tp->t_state &= ~TS_ASLEEP; - wakeup(&tp->t_outq); - } - selwakeuppri(&tp->t_wsel, TTOPRI); - } -#endif - - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { - splx(x); - return; - } - -/* - * Copy data from the clists into the interrupt ring queue. This will - * require at most 2 copys... What we do is calculate how many chars - * can fit into the ring queue, and how many can fit in 1 copy. If after - * the first copy there is still more room then do the second copy. - */ - if (tp->t_outq.c_cc != 0) { - brdp = stli_brds[portp->brdnr]; - if (brdp == (stlibrd_t *) NULL) { - splx(x); - return; - } - - EBRDENABLE(brdp); - ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); - head = (unsigned int) ap->txq.head; - tail = (unsigned int) ap->txq.tail; - if (tail != ((unsigned int) ap->txq.tail)) - tail = (unsigned int) ap->txq.tail; - size = portp->txsize; - if (head >= tail) { - len = size - (head - tail) - 1; - stlen = size - head; - } else { - len = tail - head - 1; - stlen = len; - } - - count = 0; - shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset); - - if (len > 0) { - stlen = MIN(len, stlen); - count = q_to_b(&tp->t_outq, (shbuf + head), stlen); - len -= count; - head += count; - if (head >= size) { - head = 0; - if (len > 0) { - stlen = q_to_b(&tp->t_outq, shbuf, len); - head += stlen; - count += stlen; - } - } - } - - ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); - ap->txq.head = head; - hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + - portp->portidx; - *bits |= portp->portbit; - portp->state |= ST_TXBUSY; - tp->t_state |= TS_BUSY; - - EBRDDISABLE(brdp); - } - -#if VFREEBSD != 205 -/* - * Do any writer wakeups. - */ - ttwwakeup(tp); -#endif - - splx(x); -} - -/*****************************************************************************/ - -/* - * Send a new port configuration to the slave. - */ - -static int stli_param(struct tty *tp, struct termios *tiosp) -{ - stlibrd_t *brdp; - stliport_t *portp; - asyport_t aport; - int x, rc; - - portp = (stliport_t *) tp; - if ((brdp = stli_brds[portp->brdnr]) == (stlibrd_t *) NULL) - return(ENXIO); - - x = spltty(); - stli_mkasyport(portp, &aport, tiosp); - /* can we sleep here? */ - rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); - stli_ttyoptim(portp, tiosp); - splx(x); - return(rc); -} - -/*****************************************************************************/ - -/* - * Flush characters from the lower buffer. We may not have user context - * so we cannot sleep waiting for it to complete. Also we need to check - * if there is chars for this port in the TX cook buffer, and flush them - * as well. - */ - -static void stli_flush(stliport_t *portp, int flag) -{ - stlibrd_t *brdp; - unsigned long ftype; - int x; - -#if DEBUG - printf("stli_flush(portp=%x,flag=%x)\n", (int) portp, flag); -#endif - - if (portp == (stliport_t *) NULL) - return; - if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) - return; - brdp = stli_brds[portp->brdnr]; - if (brdp == (stlibrd_t *) NULL) - return; - - x = spltty(); - if (portp->state & ST_CMDING) { - portp->state |= (flag & FWRITE) ? ST_DOFLUSHTX : 0; - portp->state |= (flag & FREAD) ? ST_DOFLUSHRX : 0; - } else { - ftype = (flag & FWRITE) ? FLUSHTX : 0; - ftype |= (flag & FREAD) ? FLUSHRX : 0; - portp->state &= ~(ST_DOFLUSHTX | ST_DOFLUSHRX); - stli_sendcmd(brdp, portp, A_FLUSH, &ftype, - sizeof(unsigned long), 0); - } - if ((flag & FREAD) && (stli_rxtmpport == portp)) - stli_rxtmplen = 0; - splx(x); -} - -/*****************************************************************************/ - -/* - * Generic send command routine. This will send a message to the slave, - * of the specified type with the specified argument. Must be very - * carefull of data that will be copied out from shared memory - - * containing command results. The command completion is all done from - * a poll routine that does not have user coontext. Therefore you cannot - * copy back directly into user space, or to the kernel stack of a - * process. This routine does not sleep, so can be called from anywhere, - * and must be called with interrupt locks set. - */ - -static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback) -{ - volatile cdkhdr_t *hdrp; - volatile cdkctrl_t *cp; - volatile unsigned char *bits; - -#if DEBUG - printf("stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d," - "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, - (int) arg, size, copyback); -#endif - - if (portp->state & ST_CMDING) { - printf("STALLION: command already busy, cmd=%x!\n", (int) cmd); - return; - } - - EBRDENABLE(brdp); - cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; - if (size > 0) { - bcopy(arg, (void *) &(cp->args[0]), size); - if (copyback) { - portp->argp = arg; - portp->argsize = size; - } - } - cp->status = 0; - cp->cmd = cmd; - hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + - portp->portidx; - *bits |= portp->portbit; - portp->state |= ST_CMDING; - EBRDDISABLE(brdp); -} - -/*****************************************************************************/ - -/* - * Read data from shared memory. This assumes that the shared memory - * is enabled and that interrupts are off. Basically we just empty out - * the shared memory buffer into the tty buffer. Must be carefull to - * handle the case where we fill up the tty buffer, but still have - * more chars to unload. - */ - -static void stli_rxprocess(stlibrd_t *brdp, stliport_t *portp) -{ - volatile cdkasyrq_t *rp; - volatile char *shbuf; - struct tty *tp; - unsigned int head, tail, size; - unsigned int len, stlen, i; - int ch; - -#if DEBUG - printf("stli_rxprocess(brdp=%x,portp=%d)\n", (int) brdp, (int) portp); -#endif - - tp = &portp->tty; - if ((tp->t_state & TS_ISOPEN) == 0) { - stli_flush(portp, FREAD); - return; - } - if (tp->t_state & TS_TBLOCK) - return; - - rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq; - head = (unsigned int) rp->head; - if (head != ((unsigned int) rp->head)) - head = (unsigned int) rp->head; - tail = (unsigned int) rp->tail; - size = portp->rxsize; - if (head >= tail) { - len = head - tail; - stlen = len; - } else { - len = size - (tail - head); - stlen = size - tail; - } - - if (len == 0) - return; - - shbuf = (volatile char *) EBRDGETMEMPTR(brdp, portp->rxoffset); - -/* - * If we can bypass normal LD processing then just copy direct - * from board shared memory into the tty buffers. - */ - if (tp->t_state & TS_CAN_BYPASS_L_RINT) { - if (((tp->t_rawq.c_cc + len) >= TTYHOG) && - ((tp->t_cflag & CRTS_IFLOW) || (tp->t_iflag & IXOFF)) && - ((tp->t_state & TS_TBLOCK) == 0)) { - ch = TTYHOG - tp->t_rawq.c_cc - 1; - len = (ch > 0) ? ch : 0; - stlen = MIN(stlen, len); - tp->t_state |= TS_TBLOCK; - } - i = b_to_q((char *) (shbuf + tail), stlen, &tp->t_rawq); - tail += stlen; - len -= stlen; - if (tail >= size) { - tail = 0; - i += b_to_q((char *) shbuf, len, &tp->t_rawq); - tail += len; - } - portp->rxlost += i; - ttwakeup(tp); - rp = &((volatile cdkasy_t *) - EBRDGETMEMPTR(brdp, portp->addr))->rxq; - rp->tail = tail; - - } else { -/* - * Copy the data from board shared memory into a local - * memory buffer. Then feed them from here into the LD. - * We don't want to go into board shared memory one char - * at a time, it is too slow... - */ - if (len > TTYHOG) { - len = TTYHOG - 1; - stlen = min(len, stlen); - } - stli_rxtmpport = portp; - stli_rxtmplen = len; - bcopy((char *) (shbuf + tail), &stli_rxtmpbuf[0], stlen); - len -= stlen; - if (len > 0) - bcopy((char *) shbuf, &stli_rxtmpbuf[stlen], len); - - for (i = 0; (i < stli_rxtmplen); i++) { - ch = (unsigned char) stli_rxtmpbuf[i]; - (*linesw[tp->t_line].l_rint)(ch, tp); - } - EBRDENABLE(brdp); - rp = &((volatile cdkasy_t *) - EBRDGETMEMPTR(brdp, portp->addr))->rxq; - if (stli_rxtmplen == 0) { - head = (unsigned int) rp->head; - if (head != ((unsigned int) rp->head)) - head = (unsigned int) rp->head; - tail = head; - } else { - tail += i; - if (tail >= size) - tail -= size; - } - rp->tail = tail; - stli_rxtmpport = (stliport_t *) NULL; - stli_rxtmplen = 0; - } - - portp->state |= ST_RXING; -} - -/*****************************************************************************/ - -/* - * Set up and carry out any delayed commands. There is only a small set - * of slave commands that can be done "off-level". So it is not too - * difficult to deal with them as a special case here. - */ - -static __inline void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp) -{ - int cmd; - - if (portp->state & ST_DOSIGS) { - if ((portp->state & ST_DOFLUSHTX) && - (portp->state & ST_DOFLUSHRX)) - cmd = A_SETSIGNALSF; - else if (portp->state & ST_DOFLUSHTX) - cmd = A_SETSIGNALSFTX; - else if (portp->state & ST_DOFLUSHRX) - cmd = A_SETSIGNALSFRX; - else - cmd = A_SETSIGNALS; - portp->state &= ~(ST_DOFLUSHTX | ST_DOFLUSHRX | ST_DOSIGS); - bcopy((void *) &portp->asig, (void *) &(cp->args[0]), - sizeof(asysigs_t)); - cp->status = 0; - cp->cmd = cmd; - portp->state |= ST_CMDING; - } else if ((portp->state & ST_DOFLUSHTX) || - (portp->state & ST_DOFLUSHRX)) { - cmd = ((portp->state & ST_DOFLUSHTX) ? FLUSHTX : 0); - cmd |= ((portp->state & ST_DOFLUSHRX) ? FLUSHRX : 0); - portp->state &= ~(ST_DOFLUSHTX | ST_DOFLUSHRX); - bcopy((void *) &cmd, (void *) &(cp->args[0]), sizeof(int)); - cp->status = 0; - cp->cmd = A_FLUSH; - portp->state |= ST_CMDING; - } -} - -/*****************************************************************************/ - -/* - * Host command service checking. This handles commands or messages - * coming from the slave to the host. Must have board shared memory - * enabled and interrupts off when called. Notice that by servicing the - * read data last we don't need to change the shared memory pointer - * during processing (which is a slow IO operation). - * Return value indicates if this port is still awaiting actions from - * the slave (like open, command, or even TX data being sent). If 0 - * then port is still busy, otherwise the port request bit flag is - * returned. - */ - -static __inline int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp) -{ - volatile cdkasy_t *ap; - volatile cdkctrl_t *cp; - asynotify_t nt; - unsigned long oldsigs; - unsigned int head, tail; - int rc, donerx; - -#if DEBUG - printf("stli_hostcmd(brdp=%x,portp=%x)\n", (int) brdp, (int) portp); -#endif - - ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); - cp = &ap->ctrl; - -/* - * Check if we are waiting for an open completion message. - */ - if (portp->state & ST_OPENING) { - rc = (int) cp->openarg; - if ((cp->open == 0) && (rc != 0)) { - if (rc > 0) - rc--; - cp->openarg = 0; - portp->rc = rc; - portp->state &= ~ST_OPENING; - wakeup(&portp->state); - } - } - -/* - * Check if we are waiting for a close completion message. - */ - if (portp->state & ST_CLOSING) { - rc = (int) cp->closearg; - if ((cp->close == 0) && (rc != 0)) { - if (rc > 0) - rc--; - cp->closearg = 0; - portp->rc = rc; - portp->state &= ~ST_CLOSING; - wakeup(&portp->state); - } - } - -/* - * Check if we are waiting for a command completion message. We may - * need to copy out the command results associated with this command. - */ - if (portp->state & ST_CMDING) { - rc = cp->status; - if ((cp->cmd == 0) && (rc != 0)) { - if (rc > 0) - rc--; - if (portp->argp != (void *) NULL) { - bcopy((void *) &(cp->args[0]), portp->argp, - portp->argsize); - portp->argp = (void *) NULL; - } - cp->status = 0; - portp->rc = rc; - portp->state &= ~ST_CMDING; - stli_dodelaycmd(portp, cp); - wakeup(&portp->state); - } - } - -/* - * Check for any notification messages ready. This includes lots of - * different types of events - RX chars ready, RX break received, - * TX data low or empty in the slave, modem signals changed state. - * Must be extremely carefull if we call to the LD, it may call - * other routines of ours that will disable the memory... - * Something else we need to be carefull of is race conditions on - * marking the TX as empty... - */ - donerx = 0; - - if (ap->notify) { - struct tty *tp; - - nt = ap->changed; - ap->notify = 0; - tp = &portp->tty; - - if (nt.signal & SG_DCD) { - oldsigs = portp->sigs; - portp->sigs = stli_mktiocm(nt.sigvalue); - portp->state &= ~ST_GETSIGS; - (*linesw[tp->t_line].l_modem)(tp, - (portp->sigs & TIOCM_CD)); - EBRDENABLE(brdp); - } - if (nt.data & DT_RXBUSY) { - donerx++; - stli_rxprocess(brdp, portp); - } - if (nt.data & DT_RXBREAK) { - (*linesw[tp->t_line].l_rint)(TTY_BI, tp); - EBRDENABLE(brdp); - } - if (nt.data & DT_TXEMPTY) { - ap = (volatile cdkasy_t *) - EBRDGETMEMPTR(brdp, portp->addr); - head = (unsigned int) ap->txq.head; - tail = (unsigned int) ap->txq.tail; - if (tail != ((unsigned int) ap->txq.tail)) - tail = (unsigned int) ap->txq.tail; - head = (head >= tail) ? (head - tail) : - portp->txsize - (tail - head); - if (head == 0) { - portp->state &= ~ST_TXBUSY; - tp->t_state &= ~TS_BUSY; - } - } - if (nt.data & (DT_TXEMPTY | DT_TXLOW)) { - (*linesw[tp->t_line].l_start)(tp); - EBRDENABLE(brdp); - } - } - -/* - * It might seem odd that we are checking for more RX chars here. - * But, we need to handle the case where the tty buffer was previously - * filled, but we had more characters to pass up. The slave will not - * send any more RX notify messages until the RX buffer has been emptied. - * But it will leave the service bits on (since the buffer is not empty). - * So from here we can try to process more RX chars. - */ - if ((!donerx) && (portp->state & ST_RXING)) { - portp->state &= ~ST_RXING; - stli_rxprocess(brdp, portp); - } - - return((portp->state & (ST_OPENING | ST_CLOSING | ST_CMDING | - ST_TXBUSY | ST_RXING)) ? 0 : 1); -} - -/*****************************************************************************/ - -/* - * Service all ports on a particular board. Assumes that the boards - * shared memory is enabled, and that the page pointer is pointed - * at the cdk header structure. - */ - -static __inline void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp) -{ - stliport_t *portp; - unsigned char hostbits[(STL_MAXCHANS / 8) + 1]; - unsigned char slavebits[(STL_MAXCHANS / 8) + 1]; - unsigned char *slavep; - int bitpos, bitat, bitsize; - int channr, nrdevs, slavebitchange; - - bitsize = brdp->bitsize; - nrdevs = brdp->nrdevs; - -/* - * Check if slave wants any service. Basically we try to do as - * little work as possible here. There are 2 levels of service - * bits. So if there is nothing to do we bail early. We check - * 8 service bits at a time in the inner loop, so we can bypass - * the lot if none of them want service. - */ - bcopy((((unsigned char *) hdrp) + brdp->hostoffset), &hostbits[0], - bitsize); - - bzero(&slavebits[0], bitsize); - slavebitchange = 0; - - for (bitpos = 0; (bitpos < bitsize); bitpos++) { - if (hostbits[bitpos] == 0) - continue; - channr = bitpos * 8; - bitat = 0x1; - for (; (channr < nrdevs); channr++, bitat <<=1) { - if (hostbits[bitpos] & bitat) { - portp = brdp->ports[(channr - 1)]; - if (stli_hostcmd(brdp, portp)) { - slavebitchange++; - slavebits[bitpos] |= bitat; - } - } - } - } - -/* - * If any of the ports are no longer busy then update them in the - * slave request bits. We need to do this after, since a host port - * service may initiate more slave requests... - */ - if (slavebitchange) { - hdrp = (volatile cdkhdr_t *) - EBRDGETMEMPTR(brdp, CDK_CDKADDR); - slavep = ((unsigned char *) hdrp) + brdp->slaveoffset; - for (bitpos = 0; (bitpos < bitsize); bitpos++) { - if (slavebits[bitpos]) - slavep[bitpos] &= ~slavebits[bitpos]; - } - } -} - -/*****************************************************************************/ - -/* - * Driver poll routine. This routine polls the boards in use and passes - * messages back up to host when neccesary. This is actually very - * CPU efficient, since we will always have the kernel poll clock, it - * adds only a few cycles when idle (since board service can be - * determined very easily), but when loaded generates no interrupts - * (with their expensive associated context change). - */ - -static void stli_poll(void *arg) -{ - volatile cdkhdr_t *hdrp; - stlibrd_t *brdp; - int brdnr, x; - - x = spltty(); - -/* - * Check each board and do any servicing required. - */ - for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) { - brdp = stli_brds[brdnr]; - if (brdp == (stlibrd_t *) NULL) - continue; - if ((brdp->state & BST_STARTED) == 0) - continue; - - EBRDENABLE(brdp); - hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - if (hdrp->hostreq) - stli_brdpoll(brdp, hdrp); - EBRDDISABLE(brdp); - } - splx(x); - - timeout(stli_poll, 0, 1); -} - -/*****************************************************************************/ - -/* - * Translate the termios settings into the port setting structure of - * the slave. - */ - -static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp) -{ -#if DEBUG - printf("stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n", (int) portp, - (int) pp, (int) tiosp); -#endif - - bzero(pp, sizeof(asyport_t)); - -/* - * Start of by setting the baud, char size, parity and stop bit info. - */ - if (tiosp->c_ispeed == 0) - tiosp->c_ispeed = tiosp->c_ospeed; - if ((tiosp->c_ospeed < 0) || (tiosp->c_ospeed > STL_MAXBAUD)) - tiosp->c_ospeed = STL_MAXBAUD; - pp->baudout = tiosp->c_ospeed; - pp->baudin = pp->baudout; - - switch (tiosp->c_cflag & CSIZE) { - case CS5: - pp->csize = 5; - break; - case CS6: - pp->csize = 6; - break; - case CS7: - pp->csize = 7; - break; - default: - pp->csize = 8; - break; - } - - if (tiosp->c_cflag & CSTOPB) - pp->stopbs = PT_STOP2; - else - pp->stopbs = PT_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - pp->parity = PT_ODDPARITY; - else - pp->parity = PT_EVENPARITY; - } else { - pp->parity = PT_NOPARITY; - } - - if (tiosp->c_iflag & ISTRIP) - pp->iflag |= FI_ISTRIP; - -/* - * Set up any flow control options enabled. - */ - if (tiosp->c_iflag & IXON) { - pp->flow |= F_IXON; - if (tiosp->c_iflag & IXANY) - pp->flow |= F_IXANY; - } - if (tiosp->c_iflag & IXOFF) - pp->flow |= F_IXOFF; - if (tiosp->c_cflag & CCTS_OFLOW) - pp->flow |= F_CTSFLOW; - if (tiosp->c_cflag & CRTS_IFLOW) - pp->flow |= F_RTSFLOW; - - pp->startin = tiosp->c_cc[VSTART]; - pp->stopin = tiosp->c_cc[VSTOP]; - pp->startout = tiosp->c_cc[VSTART]; - pp->stopout = tiosp->c_cc[VSTOP]; - -/* - * Set up the RX char marking mask with those RX error types we must - * catch. We can get the slave to help us out a little here, it will - * ignore parity errors and breaks for us, and mark parity errors in - * the data stream. - */ - if (tiosp->c_iflag & IGNPAR) - pp->iflag |= FI_IGNRXERRS; - if (tiosp->c_iflag & IGNBRK) - pp->iflag |= FI_IGNBREAK; - if (tiosp->c_iflag & (INPCK | PARMRK)) - pp->iflag |= FI_1MARKRXERRS; - -/* - * Transfer any persistent flags into the asyport structure. - */ - pp->pflag = portp->pflag; -} - -/*****************************************************************************/ - -/* - * Construct a slave signals structure for setting the DTR and RTS - * signals as specified. - */ - -static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts) -{ -#if DEBUG - printf("stli_mkasysigs(sp=%x,dtr=%d,rts=%d)\n", (int) sp, dtr, rts); -#endif - - bzero(sp, sizeof(asysigs_t)); - if (dtr >= 0) { - sp->signal |= SG_DTR; - sp->sigvalue |= ((dtr > 0) ? SG_DTR : 0); - } - if (rts >= 0) { - sp->signal |= SG_RTS; - sp->sigvalue |= ((rts > 0) ? SG_RTS : 0); - } -} - -/*****************************************************************************/ - -/* - * Convert the signals returned from the slave into a local TIOCM type - * signals value. We keep them localy in TIOCM format. - */ - -static long stli_mktiocm(unsigned long sigvalue) -{ - long tiocm; - -#if DEBUG - printf("stli_mktiocm(sigvalue=%x)\n", (int) sigvalue); -#endif - - tiocm = 0; - tiocm |= ((sigvalue & SG_DCD) ? TIOCM_CD : 0); - tiocm |= ((sigvalue & SG_CTS) ? TIOCM_CTS : 0); - tiocm |= ((sigvalue & SG_RI) ? TIOCM_RI : 0); - tiocm |= ((sigvalue & SG_DSR) ? TIOCM_DSR : 0); - tiocm |= ((sigvalue & SG_DTR) ? TIOCM_DTR : 0); - tiocm |= ((sigvalue & SG_RTS) ? TIOCM_RTS : 0); - return(tiocm); -} - -/*****************************************************************************/ - -/* - * Enable l_rint processing bypass mode if tty modes allow it. - */ - -static void stli_ttyoptim(stliport_t *portp, struct termios *tiosp) -{ - struct tty *tp; - - tp = &portp->tty; - if (((tiosp->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR)) == 0) && - (((tiosp->c_iflag & BRKINT) == 0) || (tiosp->c_iflag & IGNBRK)) && - (((tiosp->c_iflag & PARMRK) == 0) || - ((tiosp->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))) && - ((tiosp->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) ==0) && - (linesw[tp->t_line].l_rint == ttyinput)) - tp->t_state |= TS_CAN_BYPASS_L_RINT; - else - tp->t_state &= ~TS_CAN_BYPASS_L_RINT; - portp->hotchar = linesw[tp->t_line].l_hotchar; -} - -/*****************************************************************************/ - -/* - * All panels and ports actually attached have been worked out. All - * we need to do here is set up the appropriate per port data structures. - */ - -static int stli_initports(stlibrd_t *brdp) -{ - stliport_t *portp; - int i, panelnr, panelport; - -#if DEBUG - printf("stli_initports(brdp=%x)\n", (int) brdp); -#endif - - for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) { - portp = (stliport_t *) malloc(sizeof(stliport_t), M_TTYS, - M_NOWAIT | M_ZERO); - if (portp == (stliport_t *) NULL) { - printf("STALLION: failed to allocate port structure\n"); - continue; - } - - portp->portnr = i; - portp->brdnr = brdp->brdnr; - portp->panelnr = panelnr; - portp->initintios.c_ispeed = STL_DEFSPEED; - portp->initintios.c_ospeed = STL_DEFSPEED; - portp->initintios.c_cflag = STL_DEFCFLAG; - portp->initintios.c_iflag = 0; - portp->initintios.c_oflag = 0; - portp->initintios.c_lflag = 0; - bcopy(&ttydefchars[0], &portp->initintios.c_cc[0], - sizeof(portp->initintios.c_cc)); - portp->initouttios = portp->initintios; - portp->dtrwait = 3 * hz; - - panelport++; - if (panelport >= brdp->panels[panelnr]) { - panelport = 0; - panelnr++; - } - brdp->ports[i] = portp; - } - - return(0); -} - -/*****************************************************************************/ - -/* - * All the following routines are board specific hardware operations. - */ - -static void stli_ecpinit(stlibrd_t *brdp) -{ - unsigned long memconf; - -#if DEBUG - printf("stli_ecpinit(brdp=%d)\n", (int) brdp); -#endif - - outb((brdp->iobase + ECP_ATCONFR), ECP_ATSTOP); - DELAY(10); - outb((brdp->iobase + ECP_ATCONFR), ECP_ATDISABLE); - DELAY(100); - - memconf = (brdp->paddr & ECP_ATADDRMASK) >> ECP_ATADDRSHFT; - outb((brdp->iobase + ECP_ATMEMAR), memconf); -} - -/*****************************************************************************/ - -static void stli_ecpenable(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_ecpenable(brdp=%x)\n", (int) brdp); -#endif - outb((brdp->iobase + ECP_ATCONFR), ECP_ATENABLE); -} - -/*****************************************************************************/ - -static void stli_ecpdisable(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_ecpdisable(brdp=%x)\n", (int) brdp); -#endif - outb((brdp->iobase + ECP_ATCONFR), ECP_ATDISABLE); -} - -/*****************************************************************************/ - -static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - unsigned char val; - -#if DEBUG - printf("stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, - (int) offset); -#endif - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - val = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % ECP_ATPAGESIZE); - val = (unsigned char) (offset / ECP_ATPAGESIZE); - } - outb((brdp->iobase + ECP_ATMEMPR), val); - return(ptr); -} - -/*****************************************************************************/ - -static void stli_ecpreset(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_ecpreset(brdp=%x)\n", (int) brdp); -#endif - - outb((brdp->iobase + ECP_ATCONFR), ECP_ATSTOP); - DELAY(10); - outb((brdp->iobase + ECP_ATCONFR), ECP_ATDISABLE); - DELAY(500); -} - -/*****************************************************************************/ - -static void stli_ecpintr(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_ecpintr(brdp=%x)\n", (int) brdp); -#endif - outb(brdp->iobase, 0x1); -} - -/*****************************************************************************/ - -/* - * The following set of functions act on ECP EISA boards. - */ - -static void stli_ecpeiinit(stlibrd_t *brdp) -{ - unsigned long memconf; - -#if DEBUG - printf("stli_ecpeiinit(brdp=%x)\n", (int) brdp); -#endif - - outb((brdp->iobase + ECP_EIBRDENAB), 0x1); - outb((brdp->iobase + ECP_EICONFR), ECP_EISTOP); - DELAY(10); - outb((brdp->iobase + ECP_EICONFR), ECP_EIDISABLE); - DELAY(500); - - memconf = (brdp->paddr & ECP_EIADDRMASKL) >> ECP_EIADDRSHFTL; - outb((brdp->iobase + ECP_EIMEMARL), memconf); - memconf = (brdp->paddr & ECP_EIADDRMASKH) >> ECP_EIADDRSHFTH; - outb((brdp->iobase + ECP_EIMEMARH), memconf); -} - -/*****************************************************************************/ - -static void stli_ecpeienable(stlibrd_t *brdp) -{ - outb((brdp->iobase + ECP_EICONFR), ECP_EIENABLE); -} - -/*****************************************************************************/ - -static void stli_ecpeidisable(stlibrd_t *brdp) -{ - outb((brdp->iobase + ECP_EICONFR), ECP_EIDISABLE); -} - -/*****************************************************************************/ - -static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - unsigned char val; - -#if DEBUG - printf("stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n", - (int) brdp, (int) offset, line); -#endif - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - val = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % ECP_EIPAGESIZE); - if (offset < ECP_EIPAGESIZE) - val = ECP_EIENABLE; - else - val = ECP_EIENABLE | 0x40; - } - outb((brdp->iobase + ECP_EICONFR), val); - return(ptr); -} - -/*****************************************************************************/ - -static void stli_ecpeireset(stlibrd_t *brdp) -{ - outb((brdp->iobase + ECP_EICONFR), ECP_EISTOP); - DELAY(10); - outb((brdp->iobase + ECP_EICONFR), ECP_EIDISABLE); - DELAY(500); -} - -/*****************************************************************************/ - -/* - * The following set of functions act on ECP MCA boards. - */ - -static void stli_ecpmcenable(stlibrd_t *brdp) -{ - outb((brdp->iobase + ECP_MCCONFR), ECP_MCENABLE); -} - -/*****************************************************************************/ - -static void stli_ecpmcdisable(stlibrd_t *brdp) -{ - outb((brdp->iobase + ECP_MCCONFR), ECP_MCDISABLE); -} - -/*****************************************************************************/ - -static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - unsigned char val; - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - val = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % ECP_MCPAGESIZE); - val = ((unsigned char) (offset / ECP_MCPAGESIZE)) | ECP_MCENABLE; - } - outb((brdp->iobase + ECP_MCCONFR), val); - return(ptr); -} - -/*****************************************************************************/ - -static void stli_ecpmcreset(stlibrd_t *brdp) -{ - outb((brdp->iobase + ECP_MCCONFR), ECP_MCSTOP); - DELAY(10); - outb((brdp->iobase + ECP_MCCONFR), ECP_MCDISABLE); - DELAY(500); -} - -/*****************************************************************************/ - -/* - * The following routines act on ONboards. - */ - -static void stli_onbinit(stlibrd_t *brdp) -{ - unsigned long memconf; - int i; - -#if DEBUG - printf("stli_onbinit(brdp=%d)\n", (int) brdp); -#endif - - outb((brdp->iobase + ONB_ATCONFR), ONB_ATSTOP); - DELAY(10); - outb((brdp->iobase + ONB_ATCONFR), ONB_ATDISABLE); - for (i = 0; (i < 1000); i++) - DELAY(1000); - - memconf = (brdp->paddr & ONB_ATADDRMASK) >> ONB_ATADDRSHFT; - outb((brdp->iobase + ONB_ATMEMAR), memconf); - outb(brdp->iobase, 0x1); - DELAY(1000); -} - -/*****************************************************************************/ - -static void stli_onbenable(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_onbenable(brdp=%x)\n", (int) brdp); -#endif - outb((brdp->iobase + ONB_ATCONFR), (ONB_ATENABLE | brdp->confbits)); -} - -/*****************************************************************************/ - -static void stli_onbdisable(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_onbdisable(brdp=%x)\n", (int) brdp); -#endif - outb((brdp->iobase + ONB_ATCONFR), (ONB_ATDISABLE | brdp->confbits)); -} - -/*****************************************************************************/ - -static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - -#if DEBUG - printf("stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, - (int) offset); -#endif - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % ONB_ATPAGESIZE); - } - return(ptr); -} - -/*****************************************************************************/ - -static void stli_onbreset(stlibrd_t *brdp) -{ - int i; - -#if DEBUG - printf("stli_onbreset(brdp=%x)\n", (int) brdp); -#endif - - outb((brdp->iobase + ONB_ATCONFR), ONB_ATSTOP); - DELAY(10); - outb((brdp->iobase + ONB_ATCONFR), ONB_ATDISABLE); - for (i = 0; (i < 1000); i++) - DELAY(1000); -} - -/*****************************************************************************/ - -/* - * The following routines act on ONboard EISA. - */ - -static void stli_onbeinit(stlibrd_t *brdp) -{ - unsigned long memconf; - int i; - -#if DEBUG - printf("stli_onbeinit(brdp=%d)\n", (int) brdp); -#endif - - outb((brdp->iobase + ONB_EIBRDENAB), 0x1); - outb((brdp->iobase + ONB_EICONFR), ONB_EISTOP); - DELAY(10); - outb((brdp->iobase + ONB_EICONFR), ONB_EIDISABLE); - for (i = 0; (i < 1000); i++) - DELAY(1000); - - memconf = (brdp->paddr & ONB_EIADDRMASKL) >> ONB_EIADDRSHFTL; - outb((brdp->iobase + ONB_EIMEMARL), memconf); - memconf = (brdp->paddr & ONB_EIADDRMASKH) >> ONB_EIADDRSHFTH; - outb((brdp->iobase + ONB_EIMEMARH), memconf); - outb(brdp->iobase, 0x1); - DELAY(1000); -} - -/*****************************************************************************/ - -static void stli_onbeenable(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_onbeenable(brdp=%x)\n", (int) brdp); -#endif - outb((brdp->iobase + ONB_EICONFR), ONB_EIENABLE); -} - -/*****************************************************************************/ - -static void stli_onbedisable(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_onbedisable(brdp=%x)\n", (int) brdp); -#endif - outb((brdp->iobase + ONB_EICONFR), ONB_EIDISABLE); -} - -/*****************************************************************************/ - -static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - unsigned char val; - -#if DEBUG - printf("stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n", (int) brdp, - (int) offset, line); -#endif - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - val = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % ONB_EIPAGESIZE); - if (offset < ONB_EIPAGESIZE) - val = ONB_EIENABLE; - else - val = ONB_EIENABLE | 0x40; - } - outb((brdp->iobase + ONB_EICONFR), val); - return(ptr); -} - -/*****************************************************************************/ - -static void stli_onbereset(stlibrd_t *brdp) -{ - int i; - -#if DEBUG - printf("stli_onbereset(brdp=%x)\n", (int) brdp); -#endif - - outb((brdp->iobase + ONB_EICONFR), ONB_EISTOP); - DELAY(10); - outb((brdp->iobase + ONB_EICONFR), ONB_EIDISABLE); - for (i = 0; (i < 1000); i++) - DELAY(1000); -} - -/*****************************************************************************/ - -/* - * The following routines act on Brumby boards. - */ - -static void stli_bbyinit(stlibrd_t *brdp) -{ - int i; - -#if DEBUG - printf("stli_bbyinit(brdp=%d)\n", (int) brdp); -#endif - - outb((brdp->iobase + BBY_ATCONFR), BBY_ATSTOP); - DELAY(10); - outb((brdp->iobase + BBY_ATCONFR), 0); - for (i = 0; (i < 1000); i++) - DELAY(1000); - outb(brdp->iobase, 0x1); - DELAY(1000); -} - -/*****************************************************************************/ - -static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - unsigned char val; - -#if DEBUG - printf("stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp, - (int) offset); -#endif - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - val = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % BBY_PAGESIZE); - val = (unsigned char) (offset / BBY_PAGESIZE); - } - outb((brdp->iobase + BBY_ATCONFR), val); - return(ptr); -} - -/*****************************************************************************/ - -static void stli_bbyreset(stlibrd_t *brdp) -{ - int i; - -#if DEBUG - printf("stli_bbyreset(brdp=%x)\n", (int) brdp); -#endif - - outb((brdp->iobase + BBY_ATCONFR), BBY_ATSTOP); - DELAY(10); - outb((brdp->iobase + BBY_ATCONFR), 0); - for (i = 0; (i < 1000); i++) - DELAY(1000); -} - -/*****************************************************************************/ - -/* - * The following routines act on original old Stallion boards. - */ - -static void stli_stalinit(stlibrd_t *brdp) -{ - int i; - -#if DEBUG - printf("stli_stalinit(brdp=%d)\n", (int) brdp); -#endif - - outb(brdp->iobase, 0x1); - for (i = 0; (i < 1000); i++) - DELAY(1000); -} - -/*****************************************************************************/ - -static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line) -{ - void *ptr; - -#if DEBUG - printf("stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp, - (int) offset); -#endif - - if (offset > brdp->memsize) { - printf("STALLION: shared memory pointer=%x out of range at " - "line=%d(%d), brd=%d\n", (int) offset, line, - __LINE__, brdp->brdnr); - ptr = 0; - } else { - ptr = (char *) brdp->vaddr + (offset % STAL_PAGESIZE); - } - return(ptr); -} - -/*****************************************************************************/ - -static void stli_stalreset(stlibrd_t *brdp) -{ - volatile unsigned long *vecp; - int i; - -#if DEBUG - printf("stli_stalreset(brdp=%x)\n", (int) brdp); -#endif - - vecp = (volatile unsigned long *) ((char *) brdp->vaddr + 0x30); - *vecp = 0xffff0000; - outb(brdp->iobase, 0); - for (i = 0; (i < 1000); i++) - DELAY(1000); -} - -/*****************************************************************************/ - -/* - * Try to find an ECP board and initialize it. This handles only ECP - * board types. - */ - -static int stli_initecp(stlibrd_t *brdp) -{ - cdkecpsig_t sig; - cdkecpsig_t *sigsp; - unsigned int status, nxtid; - int panelnr; - -#if DEBUG - printf("stli_initecp(brdp=%x)\n", (int) brdp); -#endif - -/* - * Do a basic sanity check on the IO and memory addresses. - */ - if ((brdp->iobase == 0) || (brdp->paddr == 0)) - return(EINVAL); - -/* - * Based on the specific board type setup the common vars to access - * and enable shared memory. Set all board specific information now - * as well. - */ - switch (brdp->brdtype) { - case BRD_ECP: - brdp->memsize = ECP_MEMSIZE; - brdp->pagesize = ECP_ATPAGESIZE; - brdp->init = stli_ecpinit; - brdp->enable = stli_ecpenable; - brdp->reenable = stli_ecpenable; - brdp->disable = stli_ecpdisable; - brdp->getmemptr = stli_ecpgetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_ecpreset; - break; - - case BRD_ECPE: - brdp->memsize = ECP_MEMSIZE; - brdp->pagesize = ECP_EIPAGESIZE; - brdp->init = stli_ecpeiinit; - brdp->enable = stli_ecpeienable; - brdp->reenable = stli_ecpeienable; - brdp->disable = stli_ecpeidisable; - brdp->getmemptr = stli_ecpeigetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_ecpeireset; - break; - - case BRD_ECPMC: - brdp->memsize = ECP_MEMSIZE; - brdp->pagesize = ECP_MCPAGESIZE; - brdp->init = NULL; - brdp->enable = stli_ecpmcenable; - brdp->reenable = stli_ecpmcenable; - brdp->disable = stli_ecpmcdisable; - brdp->getmemptr = stli_ecpmcgetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_ecpmcreset; - break; - - default: - return(EINVAL); - } - -/* - * The per-board operations structure is all setup, so now lets go - * and get the board operational. Firstly initialize board configuration - * registers. - */ - EBRDINIT(brdp); - -/* - * Now that all specific code is set up, enable the shared memory and - * look for the a signature area that will tell us exactly what board - * this is, and what it is connected to it. - */ - EBRDENABLE(brdp); - sigsp = (cdkecpsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR); - bcopy(sigsp, &sig, sizeof(cdkecpsig_t)); - EBRDDISABLE(brdp); - -#if 0 - printf("%s(%d): sig-> magic=%x rom=%x panel=%x,%x,%x,%x,%x,%x,%x,%x\n", - __file__, __LINE__, (int) sig.magic, sig.romver, - sig.panelid[0], (int) sig.panelid[1], (int) sig.panelid[2], - (int) sig.panelid[3], (int) sig.panelid[4], - (int) sig.panelid[5], (int) sig.panelid[6], - (int) sig.panelid[7]); -#endif - - if (sig.magic != ECP_MAGIC) - return(ENXIO); - -/* - * Scan through the signature looking at the panels connected to the - * board. Calculate the total number of ports as we go. - */ - for (panelnr = 0, nxtid = 0; (panelnr < STL_MAXPANELS); panelnr++) { - status = sig.panelid[nxtid]; - if ((status & ECH_PNLIDMASK) != nxtid) - break; - brdp->panelids[panelnr] = status; - if (status & ECH_PNL16PORT) { - brdp->panels[panelnr] = 16; - brdp->nrports += 16; - nxtid += 2; - } else { - brdp->panels[panelnr] = 8; - brdp->nrports += 8; - nxtid++; - } - brdp->nrpanels++; - } - - brdp->state |= BST_FOUND; - return(0); -} - -/*****************************************************************************/ - -/* - * Try to find an ONboard, Brumby or Stallion board and initialize it. - * This handles only these board types. - */ - -static int stli_initonb(stlibrd_t *brdp) -{ - cdkonbsig_t sig; - cdkonbsig_t *sigsp; - int i; - -#if DEBUG - printf("stli_initonb(brdp=%x)\n", (int) brdp); -#endif - -/* - * Do a basic sanity check on the IO and memory addresses. - */ - if ((brdp->iobase == 0) || (brdp->paddr == 0)) - return(EINVAL); - -/* - * Based on the specific board type setup the common vars to access - * and enable shared memory. Set all board specific information now - * as well. - */ - switch (brdp->brdtype) { - case BRD_ONBOARD: - case BRD_ONBOARD32: - case BRD_ONBOARD2: - case BRD_ONBOARD2_32: - case BRD_ONBOARDRS: - brdp->memsize = ONB_MEMSIZE; - brdp->pagesize = ONB_ATPAGESIZE; - brdp->init = stli_onbinit; - brdp->enable = stli_onbenable; - brdp->reenable = stli_onbenable; - brdp->disable = stli_onbdisable; - brdp->getmemptr = stli_onbgetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_onbreset; - brdp->confbits = (brdp->paddr > 0x100000) ? ONB_HIMEMENAB : 0; - break; - - case BRD_ONBOARDE: - brdp->memsize = ONB_EIMEMSIZE; - brdp->pagesize = ONB_EIPAGESIZE; - brdp->init = stli_onbeinit; - brdp->enable = stli_onbeenable; - brdp->reenable = stli_onbeenable; - brdp->disable = stli_onbedisable; - brdp->getmemptr = stli_onbegetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_onbereset; - break; - - case BRD_BRUMBY4: - case BRD_BRUMBY8: - case BRD_BRUMBY16: - brdp->memsize = BBY_MEMSIZE; - brdp->pagesize = BBY_PAGESIZE; - brdp->init = stli_bbyinit; - brdp->enable = NULL; - brdp->reenable = NULL; - brdp->disable = NULL; - brdp->getmemptr = stli_bbygetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_bbyreset; - break; - - case BRD_STALLION: - brdp->memsize = STAL_MEMSIZE; - brdp->pagesize = STAL_PAGESIZE; - brdp->init = stli_stalinit; - brdp->enable = NULL; - brdp->reenable = NULL; - brdp->disable = NULL; - brdp->getmemptr = stli_stalgetmemptr; - brdp->intr = stli_ecpintr; - brdp->reset = stli_stalreset; - break; - - default: - return(EINVAL); - } - -/* - * The per-board operations structure is all setup, so now lets go - * and get the board operational. Firstly initialize board configuration - * registers. - */ - EBRDINIT(brdp); - -/* - * Now that all specific code is set up, enable the shared memory and - * look for the a signature area that will tell us exactly what board - * this is, and how many ports. - */ - EBRDENABLE(brdp); - sigsp = (cdkonbsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR); - bcopy(sigsp, &sig, sizeof(cdkonbsig_t)); - EBRDDISABLE(brdp); - -#if 0 - printf("%s(%d): sig-> magic=%x:%x:%x:%x romver=%x amask=%x:%x:%x\n", - __file__, __LINE__, sig.magic0, sig.magic1, sig.magic2, - sig.magic3, sig.romver, sig.amask0, sig.amask1, sig.amask2); -#endif - - if ((sig.magic0 != ONB_MAGIC0) || (sig.magic1 != ONB_MAGIC1) || - (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3)) - return(ENXIO); - -/* - * Scan through the signature alive mask and calculate how many ports - * there are on this board. - */ - brdp->nrpanels = 1; - if (sig.amask1) { - brdp->nrports = 32; - } else { - for (i = 0; (i < 16); i++) { - if (((sig.amask0 << i) & 0x8000) == 0) - break; - } - brdp->nrports = i; - } - brdp->panels[0] = brdp->nrports; - - brdp->state |= BST_FOUND; - return(0); -} - -/*****************************************************************************/ - -/* - * Start up a running board. This routine is only called after the - * code has been down loaded to the board and is operational. It will - * read in the memory map, and get the show on the road... - */ - -static int stli_startbrd(stlibrd_t *brdp) -{ - volatile cdkhdr_t *hdrp; - volatile cdkmem_t *memp; - volatile cdkasy_t *ap; - stliport_t *portp; - int portnr, nrdevs, i, rc, x; - -#if DEBUG - printf("stli_startbrd(brdp=%x)\n", (int) brdp); -#endif - - rc = 0; - - x = spltty(); - EBRDENABLE(brdp); - hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); - nrdevs = hdrp->nrdevs; - -#if 0 - printf("%s(%d): CDK version %d.%d.%d --> nrdevs=%d memp=%x hostp=%x " - "slavep=%x\n", __file__, __LINE__, hdrp->ver_release, - hdrp->ver_modification, hdrp->ver_fix, nrdevs, - (int) hdrp->memp, (int) hdrp->hostp, (int) hdrp->slavep); -#endif - - if (nrdevs < (brdp->nrports + 1)) { - printf("STALLION: slave failed to allocate memory for all " - "devices, devices=%d\n", nrdevs); - brdp->nrports = nrdevs - 1; - } - brdp->nrdevs = nrdevs; - brdp->hostoffset = hdrp->hostp - CDK_CDKADDR; - brdp->slaveoffset = hdrp->slavep - CDK_CDKADDR; - brdp->bitsize = (nrdevs + 7) / 8; - memp = (volatile cdkmem_t *) (void *) (uintptr_t) hdrp->memp; - if (((uintptr_t) (void *) memp) > brdp->memsize) { - printf("STALLION: corrupted shared memory region?\n"); - rc = EIO; - goto stli_donestartup; - } - memp = (volatile cdkmem_t *) EBRDGETMEMPTR(brdp, - (uintptr_t) (void *) memp); - if (memp->dtype != TYP_ASYNCTRL) { - printf("STALLION: no slave control device found\n"); - rc = EIO; - goto stli_donestartup; - } - memp++; - -/* - * Cycle through memory allocation of each port. We are guaranteed to - * have all ports inside the first page of slave window, so no need to - * change pages while reading memory map. - */ - for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++, memp++) { - if (memp->dtype != TYP_ASYNC) - break; - portp = brdp->ports[portnr]; - if (portp == (stliport_t *) NULL) - break; - portp->devnr = i; - portp->addr = memp->offset; - portp->reqidx = (unsigned char) (i * 8 / nrdevs); - portp->reqbit = (unsigned char) (0x1 << portp->reqidx); - portp->portidx = (unsigned char) (i / 8); - portp->portbit = (unsigned char) (0x1 << (i % 8)); - } - - hdrp->slavereq = 0xff; - -/* - * For each port setup a local copy of the RX and TX buffer offsets - * and sizes. We do this separate from the above, because we need to - * move the shared memory page... - */ - for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++) { - portp = brdp->ports[portnr]; - if (portp == (stliport_t *) NULL) - break; - if (portp->addr == 0) - break; - ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); - if (ap != (volatile cdkasy_t *) NULL) { - portp->rxsize = ap->rxq.size; - portp->txsize = ap->txq.size; - portp->rxoffset = ap->rxq.offset; - portp->txoffset = ap->txq.offset; - } - } - -stli_donestartup: - EBRDDISABLE(brdp); - splx(x); - - if (rc == 0) - brdp->state |= BST_STARTED; - - if (stli_doingtimeout == 0) { - timeout(stli_poll, 0, 1); - stli_doingtimeout++; - } - - return(rc); -} - -/*****************************************************************************/ - -/* - * Probe and initialize the specified board. - */ - -static int stli_brdinit(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_brdinit(brdp=%x)\n", (int) brdp); -#endif - - stli_brds[brdp->brdnr] = brdp; - - switch (brdp->brdtype) { - case BRD_ECP: - case BRD_ECPE: - case BRD_ECPMC: - stli_initecp(brdp); - break; - case BRD_ONBOARD: - case BRD_ONBOARDE: - case BRD_ONBOARD2: - case BRD_ONBOARD32: - case BRD_ONBOARD2_32: - case BRD_ONBOARDRS: - case BRD_BRUMBY4: - case BRD_BRUMBY8: - case BRD_BRUMBY16: - case BRD_STALLION: - stli_initonb(brdp); - break; - case BRD_EASYIO: - case BRD_ECH: - case BRD_ECHMC: - case BRD_ECHPCI: - printf("STALLION: %s board type not supported in this driver\n", - stli_brdnames[brdp->brdtype]); - return(ENODEV); - default: - printf("STALLION: unit=%d is unknown board type=%d\n", - brdp->brdnr, brdp->brdtype); - return(ENODEV); - } - return(0); -} - -/*****************************************************************************/ - -/* - * Finish off the remaining initialization for a board. - */ - -static int stli_brdattach(stlibrd_t *brdp) -{ -#if DEBUG - printf("stli_brdattach(brdp=%x)\n", (int) brdp); -#endif - -#if 0 - if ((brdp->state & BST_FOUND) == 0) { - printf("STALLION: %s board not found, unit=%d io=%x mem=%x\n", - stli_brdnames[brdp->brdtype], brdp->brdnr, - brdp->iobase, (int) brdp->paddr); - return(ENXIO); - } -#endif - - stli_initports(brdp); - printf("stli%d: %s (driver version %s), unit=%d nrpanels=%d " - "nrports=%d\n", brdp->unitid, stli_brdnames[brdp->brdtype], - stli_drvversion, brdp->brdnr, brdp->nrpanels, brdp->nrports); - return(0); -} - -/*****************************************************************************/ - -/* - * Check for possible shared memory sharing between boards. - * FIX: need to start this optimization somewhere... - */ - -#ifdef notdef -static int stli_chksharemem() -{ - stlibrd_t *brdp, *nxtbrdp; - int i, j; - -#if DEBUG - printf("stli_chksharemem()\n"); -#endif - -/* - * All found boards are initialized. Now for a little optimization, if - * no boards are sharing the "shared memory" regions then we can just - * leave them all enabled. This is in fact the usual case. - */ - stli_shared = 0; - if (stli_nrbrds > 1) { - for (i = 0; (i < stli_nrbrds); i++) { - brdp = stli_brds[i]; - if (brdp == (stlibrd_t *) NULL) - continue; - for (j = i + 1; (j < stli_nrbrds); j++) { - nxtbrdp = stli_brds[j]; - if (nxtbrdp == (stlibrd_t *) NULL) - continue; - if ((brdp->paddr >= nxtbrdp->paddr) && - (brdp->paddr <= (nxtbrdp->paddr + - nxtbrdp->memsize - 1))) { - stli_shared++; - break; - } - } - } - } - - if (stli_shared == 0) { - for (i = 0; (i < stli_nrbrds); i++) { - brdp = stli_brds[i]; - if (brdp == (stlibrd_t *) NULL) - continue; - if (brdp->state & BST_FOUND) { - EBRDENABLE(brdp); - brdp->enable = NULL; - brdp->disable = NULL; - } - } - } - - return(0); -} -#endif /* notdef */ - -/*****************************************************************************/ - -/* - * Return the board stats structure to user app. - */ - -static int stli_getbrdstats(caddr_t data) -{ - stlibrd_t *brdp; - int i; - -#if DEBUG - printf("stli_getbrdstats(data=%p)\n", (void *) data); -#endif - - stli_brdstats = *((combrd_t *) data); - if (stli_brdstats.brd >= STL_MAXBRDS) - return(-ENODEV); - brdp = stli_brds[stli_brdstats.brd]; - if (brdp == (stlibrd_t *) NULL) - return(-ENODEV); - - bzero(&stli_brdstats, sizeof(combrd_t)); - stli_brdstats.brd = brdp->brdnr; - stli_brdstats.type = brdp->brdtype; - stli_brdstats.hwid = 0; - stli_brdstats.state = brdp->state; - stli_brdstats.ioaddr = brdp->iobase; - stli_brdstats.memaddr = brdp->paddr; - stli_brdstats.nrpanels = brdp->nrpanels; - stli_brdstats.nrports = brdp->nrports; - for (i = 0; (i < brdp->nrpanels); i++) { - stli_brdstats.panels[i].panel = i; - stli_brdstats.panels[i].hwid = brdp->panelids[i]; - stli_brdstats.panels[i].nrports = brdp->panels[i]; - } - - *((combrd_t *) data) = stli_brdstats; - return(0); -} - -/*****************************************************************************/ - -/* - * Resolve the referenced port number into a port struct pointer. - */ - -static stliport_t *stli_getport(int brdnr, int panelnr, int portnr) -{ - stlibrd_t *brdp; - int i; - - if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) - return((stliport_t *) NULL); - brdp = stli_brds[brdnr]; - if (brdp == (stlibrd_t *) NULL) - return((stliport_t *) NULL); - for (i = 0; (i < panelnr); i++) - portnr += brdp->panels[i]; - if ((portnr < 0) || (portnr >= brdp->nrports)) - return((stliport_t *) NULL); - return(brdp->ports[portnr]); -} - -/*****************************************************************************/ - -/* - * Return the port stats structure to user app. A NULL port struct - * pointer passed in means that we need to find out from the app - * what port to get stats for (used through board control device). - */ - -static int stli_getportstats(stliport_t *portp, caddr_t data) -{ - stlibrd_t *brdp; - int rc; - - if (portp == (stliport_t *) NULL) { - stli_comstats = *((comstats_t *) data); - portp = stli_getport(stli_comstats.brd, stli_comstats.panel, - stli_comstats.port); - if (portp == (stliport_t *) NULL) - return(-ENODEV); - } - - brdp = stli_brds[portp->brdnr]; - if (brdp == (stlibrd_t *) NULL) - return(-ENODEV); - - if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS, &stli_cdkstats, - sizeof(asystats_t), 1)) < 0) - return(rc); - - stli_comstats.brd = portp->brdnr; - stli_comstats.panel = portp->panelnr; - stli_comstats.port = portp->portnr; - stli_comstats.state = portp->state; - /*stli_comstats.flags = portp->flags;*/ - stli_comstats.ttystate = portp->tty.t_state; - stli_comstats.cflags = portp->tty.t_cflag; - stli_comstats.iflags = portp->tty.t_iflag; - stli_comstats.oflags = portp->tty.t_oflag; - stli_comstats.lflags = portp->tty.t_lflag; - - stli_comstats.txtotal = stli_cdkstats.txchars; - stli_comstats.rxtotal = stli_cdkstats.rxchars + stli_cdkstats.ringover; - stli_comstats.txbuffered = stli_cdkstats.txringq; - stli_comstats.rxbuffered = stli_cdkstats.rxringq; - stli_comstats.rxoverrun = stli_cdkstats.overruns; - stli_comstats.rxparity = stli_cdkstats.parity; - stli_comstats.rxframing = stli_cdkstats.framing; - stli_comstats.rxlost = stli_cdkstats.ringover + portp->rxlost; - stli_comstats.rxbreaks = stli_cdkstats.rxbreaks; - stli_comstats.txbreaks = stli_cdkstats.txbreaks; - stli_comstats.txxon = stli_cdkstats.txstart; - stli_comstats.txxoff = stli_cdkstats.txstop; - stli_comstats.rxxon = stli_cdkstats.rxstart; - stli_comstats.rxxoff = stli_cdkstats.rxstop; - stli_comstats.rxrtsoff = stli_cdkstats.rtscnt / 2; - stli_comstats.rxrtson = stli_cdkstats.rtscnt - stli_comstats.rxrtsoff; - stli_comstats.modem = stli_cdkstats.dcdcnt; - stli_comstats.hwid = stli_cdkstats.hwid; - stli_comstats.signals = stli_mktiocm(stli_cdkstats.signals); - - *((comstats_t *) data) = stli_comstats;; - return(0); -} - -/*****************************************************************************/ - -/* - * Clear the port stats structure. We also return it zeroed out... - */ - -static int stli_clrportstats(stliport_t *portp, caddr_t data) -{ - stlibrd_t *brdp; - int rc; - - if (portp == (stliport_t *) NULL) { - stli_comstats = *((comstats_t *) data); - portp = stli_getport(stli_comstats.brd, stli_comstats.panel, - stli_comstats.port); - if (portp == (stliport_t *) NULL) - return(-ENODEV); - } - - brdp = stli_brds[portp->brdnr]; - if (brdp == (stlibrd_t *) NULL) - return(-ENODEV); - - if ((rc = stli_cmdwait(brdp, portp, A_CLEARSTATS, 0, 0, 0)) < 0) - return(rc); - - portp->rxlost = 0; - bzero(&stli_comstats, sizeof(comstats_t)); - stli_comstats.brd = portp->brdnr; - stli_comstats.panel = portp->panelnr; - stli_comstats.port = portp->portnr; - - *((comstats_t *) data) = stli_comstats;; - return(0); -} - -/*****************************************************************************/ - -/* - * Code to handle a "staliomem" read and write operations. This device - * is the contents of the board shared memory. It is used for down - * loading the slave image (and debugging :-) - */ - -STATIC int stli_memrw(dev_t dev, struct uio *uiop, int flag) -{ - stlibrd_t *brdp; - void *memptr; - int brdnr, size, n, error, x; - -#if DEBUG - printf("stli_memrw(dev=%x,uiop=%x,flag=%x)\n", (int) dev, - (int) uiop, flag); -#endif - - brdnr = minor(dev) & 0x7; - brdp = stli_brds[brdnr]; - if (brdp == (stlibrd_t *) NULL) - return(ENODEV); - if (brdp->state == 0) - return(ENODEV); - - if (uiop->uio_offset >= brdp->memsize) - return(0); - - error = 0; - size = brdp->memsize - uiop->uio_offset; - - x = spltty(); - EBRDENABLE(brdp); - while (size > 0) { - memptr = (void *) EBRDGETMEMPTR(brdp, uiop->uio_offset); - n = MIN(size, (brdp->pagesize - - (((unsigned long) uiop->uio_offset) % brdp->pagesize))); - error = uiomove(memptr, n, uiop); - if ((uiop->uio_resid == 0) || error) - break; - } - EBRDDISABLE(brdp); - splx(x); - - return(error); -} - -/*****************************************************************************/ - -/* - * The "staliomem" device is also required to do some special operations - * on the board. We need to be able to send an interrupt to the board, - * reset it, and start/stop it. - */ - -static int stli_memioctl(dev_t dev, unsigned long cmd, caddr_t data, int flag, - struct thread *td) -{ - stlibrd_t *brdp; - int brdnr, rc; - -#if DEBUG - printf("stli_memioctl(dev=%s,cmd=%lx,data=%p,flag=%x)\n", - devtoname(dev), cmd, (void *) data, flag); -#endif - - brdnr = minor(dev) & 0x7; - brdp = stli_brds[brdnr]; - if (brdp == (stlibrd_t *) NULL) - return(ENODEV); - if (brdp->state == 0) - return(ENODEV); - - rc = 0; - - switch (cmd) { - case STL_BINTR: - EBRDINTR(brdp); - break; - case STL_BSTART: - rc = stli_startbrd(brdp); - break; - case STL_BSTOP: - brdp->state &= ~BST_STARTED; - break; - case STL_BRESET: - brdp->state &= ~BST_STARTED; - EBRDRESET(brdp); - if (stli_shared == 0) { - if (brdp->reenable != NULL) - (* brdp->reenable)(brdp); - } - break; - case COM_GETPORTSTATS: - rc = stli_getportstats((stliport_t *) NULL, data); - break; - case COM_CLRPORTSTATS: - rc = stli_clrportstats((stliport_t *) NULL, data); - break; - case COM_GETBRDSTATS: - rc = stli_getbrdstats(data); - break; - default: - rc = ENOTTY; - break; - } - - return(rc); -} - -/*****************************************************************************/ diff --git a/sys/i386/isa/stallion.c b/sys/i386/isa/stallion.c deleted file mode 100644 index 9a99f74..0000000 --- a/sys/i386/isa/stallion.c +++ /dev/null @@ -1,3072 +0,0 @@ -/*****************************************************************************/ - -/* - * stallion.c -- stallion multiport serial driver. - * - * Copyright (c) 1995-1996 Greg Ungerer (gerg@stallion.oz.au). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Greg Ungerer. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/*****************************************************************************/ - -#define TTYDEFCHARS 1 - -#include "opt_compat.h" -#include "opt_tty.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/tty.h> -#include <sys/conf.h> -#include <sys/fcntl.h> -#include <sys/bus.h> -#include <i386/isa/isa_device.h> -#include <i386/isa/ic/scd1400.h> -#include <machine/comstats.h> - -#warning "The stallion pci attachment is broken and not compiled" -#define NPCI 0 -#if NPCI > 0 -#ifndef COMPAT_OLDPCI -#error "The stallion pci driver requires the old pci compatibility shims" -#endif -#include <dev/pci/pcivar.h> -#include <dev/pci/pcireg.h> -#endif - -/*****************************************************************************/ - -/* - * Define the version level of the kernel - so we can compile in the - * appropriate bits of code. By default this will compile for a 2.1 - * level kernel. - */ -#define VFREEBSD 220 - -#if VFREEBSD >= 220 -#define STATIC static -#else -#define STATIC -#endif - -/*****************************************************************************/ - -/* - * Define different board types. At the moment I have only declared - * those boards that this driver supports. But I will use the standard - * "assigned" board numbers. In the future this driver will support - * some of the other Stallion boards. Currently supported boards are - * abbreviated as EIO = EasyIO and ECH = EasyConnection 8/32. - */ -#define BRD_EASYIO 20 -#define BRD_ECH 21 -#define BRD_ECHMC 22 -#define BRD_ECHPCI 26 - -/* - * When using the BSD "config" stuff there is no easy way to specifiy - * a secondary IO address region. So it is hard wired here. Also the - * shared interrupt information is hard wired here... - */ -static unsigned int stl_ioshared = 0x280; -static unsigned int stl_irqshared = 0; - -/*****************************************************************************/ - -/* - * Define important driver limitations. - */ -#define STL_MAXBRDS 8 -#define STL_MAXPANELS 4 -#define STL_PORTSPERPANEL 16 -#define STL_PORTSPERBRD 64 - -/* - * Define the important minor number break down bits. These have been - * chosen to be "compatible" with the standard sio driver minor numbers. - * Extra high bits are used to distinguish between boards. - */ -#define STL_CALLOUTDEV 0x80 -#define STL_CTRLLOCK 0x40 -#define STL_CTRLINIT 0x20 -#define STL_CTRLDEV (STL_CTRLLOCK | STL_CTRLINIT) - -#define STL_MEMDEV 0x07000000 - -#define STL_DEFSPEED TTYDEF_SPEED -#define STL_DEFCFLAG (CS8 | CREAD | HUPCL) - -/* - * I haven't really decided (or measured) what buffer sizes give - * a good balance between performance and memory usage. These seem - * to work pretty well... - */ -#define STL_RXBUFSIZE 2048 -#define STL_TXBUFSIZE 2048 - -#define STL_TXBUFLOW (STL_TXBUFSIZE / 4) -#define STL_RXBUFHIGH (3 * STL_RXBUFSIZE / 4) - -/*****************************************************************************/ - -/* - * Define our local driver identity first. Set up stuff to deal with - * all the local structures required by a serial tty driver. - */ -static const char stl_drvname[] = "stl"; -static const char stl_longdrvname[] = "Stallion Multiport Serial Driver"; -static const char stl_drvversion[] = "1.0.0"; -static int stl_brdprobed[STL_MAXBRDS]; - -static int stl_nrbrds = 0; -static int stl_doingtimeout = 0; - -static const char __file__[] = /*__FILE__*/ "stallion.c"; - -/* - * Define global stats structures. Not used often, and can be - * re-used for each stats call. - */ -static combrd_t stl_brdstats; -static comstats_t stl_comstats; - -/*****************************************************************************/ - -/* - * Define a set of structures to hold all the board/panel/port info - * for our ports. These will be dynamically allocated as required. - */ - -/* - * Define a ring queue structure for each port. This will hold the - * TX data waiting to be output. Characters are fed into this buffer - * from the line discipline (or even direct from user space!) and - * then fed into the UARTs during interrupts. Will use a clasic ring - * queue here for this. The good thing about this type of ring queue - * is that the head and tail pointers can be updated without interrupt - * protection - since "write" code only needs to change the head, and - * interrupt code only needs to change the tail. - */ -typedef struct { - char *buf; - char *endbuf; - char *head; - char *tail; -} stlrq_t; - -/* - * Port, panel and board structures to hold status info about each. - * The board structure contains pointers to structures for each panel - * connected to it, and in turn each panel structure contains pointers - * for each port structure for each port on that panel. Note that - * the port structure also contains the board and panel number that it - * is associated with, this makes it (fairly) easy to get back to the - * board/panel info for a port. Also note that the tty struct is at - * the top of the structure, this is important, since the code uses - * this fact to get the port struct pointer from the tty struct - * pointer! - */ -typedef struct { - struct tty tty; - int portnr; - int panelnr; - int brdnr; - int ioaddr; - int uartaddr; - int pagenr; - int callout; - int brklen; - int dtrwait; - int dotimestamp; - int waitopens; - int hotchar; - unsigned int state; - unsigned int hwid; - unsigned int sigs; - unsigned int rxignoremsk; - unsigned int rxmarkmsk; - unsigned long clk; - struct termios initintios; - struct termios initouttios; - struct termios lockintios; - struct termios lockouttios; - struct timeval timestamp; - comstats_t stats; - stlrq_t tx; - stlrq_t rx; - stlrq_t rxstatus; -} stlport_t; - -typedef struct { - int panelnr; - int brdnr; - int pagenr; - int nrports; - int iobase; - unsigned int hwid; - unsigned int ackmask; - stlport_t *ports[STL_PORTSPERPANEL]; -} stlpanel_t; - -typedef struct { - int brdnr; - int brdtype; - int unitid; - int state; - int nrpanels; - int nrports; - int irq; - int irqtype; - unsigned int ioaddr1; - unsigned int ioaddr2; - unsigned int iostatus; - unsigned int ioctrl; - unsigned int ioctrlval; - unsigned int hwid; - unsigned long clk; - stlpanel_t *panels[STL_MAXPANELS]; - stlport_t *ports[STL_PORTSPERBRD]; -} stlbrd_t; - -static stlbrd_t *stl_brds[STL_MAXBRDS]; - -/* - * Per board state flags. Used with the state field of the board struct. - * Not really much here yet! - */ -#define BRD_FOUND 0x1 - -/* - * Define the port structure state flags. These set of flags are - * modified at interrupt time - so setting and reseting them needs - * to be atomic. - */ -#define ASY_TXLOW 0x1 -#define ASY_RXDATA 0x2 -#define ASY_DCDCHANGE 0x4 -#define ASY_DTRWAIT 0x8 -#define ASY_RTSFLOW 0x10 -#define ASY_RTSFLOWMODE 0x20 -#define ASY_CTSFLOWMODE 0x40 - -#define ASY_ACTIVE (ASY_TXLOW | ASY_RXDATA | ASY_DCDCHANGE) - -/* - * Define an array of board names as printable strings. Handy for - * referencing boards when printing trace and stuff. - */ -static char *stl_brdnames[] = { - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EasyIO", - "EC8/32-AT", - "EC8/32-MC", - (char *) NULL, - (char *) NULL, - (char *) NULL, - "EC8/32-PCI", -}; - -/*****************************************************************************/ - -/* - * Hardware ID bits for the EasyIO and ECH boards. These defines apply - * to the directly accessible io ports of these boards (not the cd1400 - * uarts - they are in scd1400.h). - */ -#define EIO_8PORTRS 0x04 -#define EIO_4PORTRS 0x05 -#define EIO_8PORTDI 0x00 -#define EIO_8PORTM 0x06 -#define EIO_IDBITMASK 0x07 -#define EIO_INTRPEND 0x08 -#define EIO_INTEDGE 0x00 -#define EIO_INTLEVEL 0x08 - -#define ECH_ID 0xa0 -#define ECH_IDBITMASK 0xe0 -#define ECH_BRDENABLE 0x08 -#define ECH_BRDDISABLE 0x00 -#define ECH_INTENABLE 0x01 -#define ECH_INTDISABLE 0x00 -#define ECH_INTLEVEL 0x02 -#define ECH_INTEDGE 0x00 -#define ECH_INTRPEND 0x01 -#define ECH_BRDRESET 0x01 - -#define ECHMC_INTENABLE 0x01 -#define ECHMC_BRDRESET 0x02 - -#define ECH_PNLSTATUS 2 -#define ECH_PNL16PORT 0x20 -#define ECH_PNLIDMASK 0x07 -#define ECH_PNLINTRPEND 0x80 -#define ECH_ADDR2MASK 0x1e0 - -#define EIO_CLK 25000000 -#define EIO_CLK8M 20000000 -#define ECH_CLK EIO_CLK - -/* - * Define the offsets within the register bank for all io registers. - * These io address offsets are common to both the EIO and ECH. - */ -#define EREG_ADDR 0 -#define EREG_DATA 4 -#define EREG_RXACK 5 -#define EREG_TXACK 6 -#define EREG_MDACK 7 - -#define EREG_BANKSIZE 8 - -/* - * Define the PCI vendor and device id for ECH8/32-PCI. - */ -#define STL_PCIDEVID 0xd001100b - -/* - * Define the vector mapping bits for the programmable interrupt board - * hardware. These bits encode the interrupt for the board to use - it - * is software selectable (except the EIO-8M). - */ -static unsigned char stl_vecmap[] = { - 0xff, 0xff, 0xff, 0x04, 0x06, 0x05, 0xff, 0x07, - 0xff, 0xff, 0x00, 0x02, 0x01, 0xff, 0xff, 0x03 -}; - -/* - * Set up enable and disable macros for the ECH boards. They require - * the secondary io address space to be activated and deactivated. - * This way all ECH boards can share their secondary io region. - * If this is an ECH-PCI board then also need to set the page pointer - * to point to the correct page. - */ -#define BRDENABLE(brdnr,pagenr) \ - if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ - outb(stl_brds[(brdnr)]->ioctrl, \ - (stl_brds[(brdnr)]->ioctrlval | ECH_BRDENABLE));\ - else if (stl_brds[(brdnr)]->brdtype == BRD_ECHPCI) \ - outb(stl_brds[(brdnr)]->ioctrl, (pagenr)); - -#define BRDDISABLE(brdnr) \ - if (stl_brds[(brdnr)]->brdtype == BRD_ECH) \ - outb(stl_brds[(brdnr)]->ioctrl, \ - (stl_brds[(brdnr)]->ioctrlval | ECH_BRDDISABLE)); - -/* - * Define the cd1400 baud rate clocks. These are used when calculating - * what clock and divisor to use for the required baud rate. Also - * define the maximum baud rate allowed, and the default base baud. - */ -static int stl_cd1400clkdivs[] = { - CD1400_CLK0, CD1400_CLK1, CD1400_CLK2, CD1400_CLK3, CD1400_CLK4 -}; - -#define STL_MAXBAUD 230400 - -/*****************************************************************************/ - -/* - * Define macros to extract a brd and port number from a minor number. - * This uses the extended minor number range in the upper 2 bytes of - * the device number. This gives us plenty of minor numbers to play - * with... - */ -#define MKDEV2BRD(m) ((minor(m) & 0x00700000) >> 20) -#define MKDEV2PORT(m) ((minor(m) & 0x1f) | ((minor(m) & 0x00010000) >> 11)) - -/* - * Define some handy local macros... - */ -#ifndef MIN -#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) -#endif - -/*****************************************************************************/ - -/* - * Declare all those functions in this driver! First up is the set of - * externally visible functions. - */ - -static int stlprobe(struct isa_device *idp); -static int stlattach(struct isa_device *idp); - -STATIC d_open_t stlopen; -STATIC d_close_t stlclose; -STATIC d_ioctl_t stlioctl; - -/* - * Internal function prototypes. - */ -static stlport_t *stl_dev2port(dev_t dev); -static int stl_findfreeunit(void); -static int stl_rawopen(stlport_t *portp); -static int stl_rawclose(stlport_t *portp); -static int stl_param(struct tty *tp, struct termios *tiosp); -static void stl_start(struct tty *tp); -static void stl_stop(struct tty *tp, int); -static void stl_ttyoptim(stlport_t *portp, struct termios *tiosp); -static void stl_dotimeout(void); -static void stl_poll(void *arg); -static void stl_rxprocess(stlport_t *portp); -static void stl_dtrwakeup(void *arg); -static int stl_brdinit(stlbrd_t *brdp); -static int stl_initeio(stlbrd_t *brdp); -static int stl_initech(stlbrd_t *brdp); -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static ointhand2_t stlintr; -static __inline void stl_txisr(stlpanel_t *panelp, int ioaddr); -static __inline void stl_rxisr(stlpanel_t *panelp, int ioaddr); -static __inline void stl_mdmisr(stlpanel_t *panelp, int ioaddr); -static void stl_setreg(stlport_t *portp, int regnr, int value); -static int stl_getreg(stlport_t *portp, int regnr); -static int stl_updatereg(stlport_t *portp, int regnr, int value); -static int stl_getsignals(stlport_t *portp); -static void stl_setsignals(stlport_t *portp, int dtr, int rts); -static void stl_flowcontrol(stlport_t *portp, int hw, int sw); -static void stl_ccrwait(stlport_t *portp); -static void stl_enablerxtx(stlport_t *portp, int rx, int tx); -static void stl_startrxtx(stlport_t *portp, int rx, int tx); -static void stl_disableintrs(stlport_t *portp); -static void stl_sendbreak(stlport_t *portp, long len); -static void stl_flush(stlport_t *portp, int flag); -static int stl_memioctl(dev_t dev, unsigned long cmd, caddr_t data, - int flag, struct thread *td); -static int stl_getbrdstats(caddr_t data); -static int stl_getportstats(stlport_t *portp, caddr_t data); -static int stl_clrportstats(stlport_t *portp, caddr_t data); -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); - -#if NPCI > 0 -static const char *stlpciprobe(pcici_t tag, pcidi_t type); -static void stlpciattach(pcici_t tag, int unit); -static void stlpciintr(void * arg); -#endif - -/*****************************************************************************/ - -/* - * Declare the driver isa structure. - */ -struct isa_driver stldriver = { - INTR_TYPE_TTY, - stlprobe, - stlattach, - "stl" -}; -COMPAT_ISA_DRIVER(stl, stldriver); - -/*****************************************************************************/ - -#if NPCI > 0 - -/* - * Declare the driver pci structure. - */ -static unsigned long stl_count; - -static struct pci_device stlpcidriver = { - "stl", - stlpciprobe, - stlpciattach, - &stl_count, - NULL, -}; - -COMPAT_PCI_DRIVER (stlpci, stlpcidriver); - -#endif - -/*****************************************************************************/ - -#if VFREEBSD >= 220 - -/* - * FreeBSD-2.2+ kernel linkage. - */ - -static struct cdevsw stl_cdevsw = { - .d_version = D_VERSION, - .d_open = stlopen, - .d_close = stlclose, - .d_ioctl = stlioctl, - .d_name = "stl", - .d_flags = D_TTY | D_NEEDGIANT, -}; - -#endif - -/*****************************************************************************/ - -/* - * Probe for some type of EasyIO or EasyConnection 8/32 board at - * the supplied address. All we do is check if we can find the - * board ID for the board... (Note, PCI boards not checked here, - * they are done in the stlpciprobe() routine). - */ - -static int stlprobe(struct isa_device *idp) -{ - unsigned int status; - -#if DEBUG - printf("stlprobe(idp=%x): unit=%d iobase=%x\n", (int) idp, - idp->id_unit, idp->id_iobase); -#endif - - if (idp->id_unit > STL_MAXBRDS) - return(0); - - status = inb(idp->id_iobase + 1); - if ((status & ECH_IDBITMASK) == ECH_ID) { - stl_brdprobed[idp->id_unit] = BRD_ECH; - return(1); - } - - status = inb(idp->id_iobase + 2); - switch (status & EIO_IDBITMASK) { - case EIO_8PORTRS: - case EIO_8PORTM: - case EIO_8PORTDI: - case EIO_4PORTRS: - stl_brdprobed[idp->id_unit] = BRD_EASYIO; - return(1); - default: - break; - } - - return(0); -} - -/*****************************************************************************/ - -/* - * Find an available internal board number (unit number). The problem - * is that the same unit numbers can be assigned to different boards - * detected during the ISA and PCI initialization phases. - */ - -static int stl_findfreeunit() -{ - int i; - - for (i = 0; (i < STL_MAXBRDS); i++) - if (stl_brds[i] == (stlbrd_t *) NULL) - break; - return((i >= STL_MAXBRDS) ? -1 : i); -} - -/*****************************************************************************/ - -/* - * Allocate resources for and initialize the specified board. - */ - -static int stlattach(struct isa_device *idp) -{ - stlbrd_t *brdp; - -#if DEBUG - printf("stlattach(idp=%p): unit=%d iobase=%x\n", (void *) idp, - idp->id_unit, idp->id_iobase); -#endif - - idp->id_ointr = stlintr; - - brdp = (stlbrd_t *) malloc(sizeof(stlbrd_t), M_TTYS, M_NOWAIT | M_ZERO); - if (brdp == (stlbrd_t *) NULL) { - printf("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlbrd_t)); - return(0); - } - - if ((brdp->brdnr = stl_findfreeunit()) < 0) { - printf("STALLION: too many boards found, max=%d\n", - STL_MAXBRDS); - return(0); - } - if (brdp->brdnr >= stl_nrbrds) - stl_nrbrds = brdp->brdnr + 1; - - brdp->unitid = idp->id_unit; - brdp->brdtype = stl_brdprobed[idp->id_unit]; - brdp->ioaddr1 = idp->id_iobase; - brdp->ioaddr2 = stl_ioshared; - brdp->irq = ffs(idp->id_irq) - 1; - brdp->irqtype = stl_irqshared; - stl_brdinit(brdp); - - if (0) { - make_dev(&stl_cdevsw, 0, 0, 0, 0, "stallion_is_broken"); - } - return(1); -} - -/*****************************************************************************/ - -#if NPCI > 0 - -/* - * Probe specifically for the PCI boards. We need to be a little - * carefull here, since it looks sort like a Nat Semi IDE chip... - */ - -static const char *stlpciprobe(pcici_t tag, pcidi_t type) -{ - unsigned long class; - -#if DEBUG - printf("stlpciprobe(tag=%x,type=%x)\n", (int) &tag, (int) type); -#endif - - switch (type) { - case STL_PCIDEVID: - break; - default: - return((char *) NULL); - } - - class = pci_conf_read(tag, PCI_CLASS_REG); - if ((class & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE) - return((char *) NULL); - - return("Stallion EasyConnection 8/32-PCI"); -} - -/*****************************************************************************/ - -/* - * Allocate resources for and initialize the specified PCI board. - */ - -void stlpciattach(pcici_t tag, int unit) -{ - stlbrd_t *brdp; - -#if DEBUG - printf("stlpciattach(tag=%x,unit=%x)\n", (int) &tag, unit); -#endif - - brdp = (stlbrd_t *) malloc(sizeof(stlbrd_t), M_TTYS, M_NOWAIT | M_ZERO); - if (brdp == (stlbrd_t *) NULL) { - printf("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlbrd_t)); - return; - } - - if ((unit < 0) || (unit > STL_MAXBRDS)) { - printf("STALLION: bad PCI board unit number=%d\n", unit); - return; - } - -/* - * Allocate us a new driver unique unit number. - */ - if ((brdp->brdnr = stl_findfreeunit()) < 0) { - printf("STALLION: too many boards found, max=%d\n", - STL_MAXBRDS); - return; - } - if (brdp->brdnr >= stl_nrbrds) - stl_nrbrds = brdp->brdnr + 1; - - brdp->unitid = 0; - brdp->brdtype = BRD_ECHPCI; - brdp->ioaddr1 = ((unsigned int) pci_conf_read(tag, 0x14)) & 0xfffc; - brdp->ioaddr2 = ((unsigned int) pci_conf_read(tag, 0x10)) & 0xfffc; - brdp->irq = ((int) pci_conf_read(tag, 0x3c)) & 0xff; - brdp->irqtype = 0; - if (pci_map_int(tag, stlpciintr, (void *) NULL, &tty_imask) == 0) { - printf("STALLION: failed to map interrupt irq=%d for unit=%d\n", - brdp->irq, brdp->brdnr); - return; - } - -#if 0 - printf("%s(%d): ECH-PCI iobase=%x iopage=%x irq=%d\n", __file__, __LINE__, brdp->ioaddr2, brdp->ioaddr1, brdp->irq); -#endif - stl_brdinit(brdp); -} - -#endif - -/*****************************************************************************/ - -STATIC int stlopen(dev_t dev, int flag, int mode, struct thread *td) -{ - struct tty *tp; - stlport_t *portp; - int error, callout, x; - -#if DEBUG - printf("stlopen(dev=%x,flag=%x,mode=%x,p=%x)\n", (int) dev, flag, - mode, (int) td); -#endif - -/* - * Firstly check if the supplied device number is a valid device. - */ - if (minor(dev) & STL_MEMDEV) - return(0); - - portp = stl_dev2port(dev); - if (portp == (stlport_t *) NULL) - return(ENXIO); - tp = &portp->tty; - dev->si_tty = tp; - callout = minor(dev) & STL_CALLOUTDEV; - error = 0; - - x = spltty(); - -stlopen_restart: -/* - * Wait here for the DTR drop timeout period to expire. - */ - while (portp->state & ASY_DTRWAIT) { - error = tsleep(&portp->dtrwait, (TTIPRI | PCATCH), - "stldtr", 0); - if (error) - goto stlopen_end; - } - -/* - * We have a valid device, so now we check if it is already open. - * If not then initialize the port hardware and set up the tty - * struct as required. - */ - if ((tp->t_state & TS_ISOPEN) == 0) { - tp->t_oproc = stl_start; - tp->t_stop = stl_stop; - tp->t_param = stl_param; - tp->t_dev = dev; - tp->t_termios = callout ? portp->initouttios : - portp->initintios; - stl_rawopen(portp); - if ((portp->sigs & TIOCM_CD) || callout) - (*linesw[tp->t_line].l_modem)(tp, 1); - } else { - if (callout) { - if (portp->callout == 0) { - error = EBUSY; - goto stlopen_end; - } - } else { - if (portp->callout != 0) { - if (flag & O_NONBLOCK) { - error = EBUSY; - goto stlopen_end; - } - error = tsleep(&portp->callout, - (TTIPRI | PCATCH), "stlcall", 0); - if (error) - goto stlopen_end; - goto stlopen_restart; - } - } - if ((tp->t_state & TS_XCLUDE) && - suser(td)) { - error = EBUSY; - goto stlopen_end; - } - } - -/* - * If this port is not the callout device and we do not have carrier - * then we need to sleep, waiting for it to be asserted. - */ - if (((tp->t_state & TS_CARR_ON) == 0) && !callout && - ((tp->t_cflag & CLOCAL) == 0) && - ((flag & O_NONBLOCK) == 0)) { - portp->waitopens++; - error = tsleep(TSA_CARR_ON(tp), (TTIPRI | PCATCH), "stldcd", 0); - portp->waitopens--; - if (error) - goto stlopen_end; - goto stlopen_restart; - } - -/* - * Open the line discipline. - */ - error = (*linesw[tp->t_line].l_open)(dev, tp); - stl_ttyoptim(portp, &tp->t_termios); - if ((tp->t_state & TS_ISOPEN) && callout) - portp->callout = 1; - -/* - * If for any reason we get to here and the port is not actually - * open then close of the physical hardware - no point leaving it - * active when the open failed... - */ -stlopen_end: - splx(x); - if (((tp->t_state & TS_ISOPEN) == 0) && (portp->waitopens == 0)) - stl_rawclose(portp); - - return(error); -} - -/*****************************************************************************/ - -STATIC int stlclose(dev_t dev, int flag, int mode, struct thread *td) -{ - struct tty *tp; - stlport_t *portp; - int x; - -#if DEBUG - printf("stlclose(dev=%s,flag=%x,mode=%x,p=%p)\n", devtoname(dev), - flag, mode, (void *) td); -#endif - - if (minor(dev) & STL_MEMDEV) - return(0); - - portp = stl_dev2port(dev); - if (portp == (stlport_t *) NULL) - return(ENXIO); - tp = &portp->tty; - - x = spltty(); - (*linesw[tp->t_line].l_close)(tp, flag); - stl_ttyoptim(portp, &tp->t_termios); - stl_rawclose(portp); - ttyclose(tp); - splx(x); - return(0); -} - -/*****************************************************************************/ - -#if VFREEBSD >= 220 - -STATIC void stl_stop(struct tty *tp, int rw) -{ -#if DEBUG - printf("stl_stop(tp=%x,rw=%x)\n", (int) tp, rw); -#endif - - stl_flush((stlport_t *) tp, rw); -} - -#else - -STATIC int stlstop(struct tty *tp, int rw) -{ -#if DEBUG - printf("stlstop(tp=%x,rw=%x)\n", (int) tp, rw); -#endif - - stl_flush((stlport_t *) tp, rw); - return(0); -} - -#endif - -/*****************************************************************************/ - -STATIC int stlioctl(dev_t dev, unsigned long cmd, caddr_t data, int flag, - struct thread *td) -{ - struct termios *newtios, *localtios; - struct tty *tp; - stlport_t *portp; - int error, i, x; - -#if DEBUG - printf("stlioctl(dev=%s,cmd=%lx,data=%p,flag=%x,p=%p)\n", - devtoname(dev), cmd, (void *) data, flag, (void *) td); -#endif - - if (minor(dev) & STL_MEMDEV) - return(stl_memioctl(dev, cmd, data, flag, td)); - - portp = stl_dev2port(dev); - if (portp == (stlport_t *) NULL) - return(ENODEV); - tp = &portp->tty; - error = 0; - -/* - * First up handle ioctls on the control devices. - */ - if (minor(dev) & STL_CTRLDEV) { - if ((minor(dev) & STL_CTRLDEV) == STL_CTRLINIT) - localtios = (minor(dev) & STL_CALLOUTDEV) ? - &portp->initouttios : &portp->initintios; - else if ((minor(dev) & STL_CTRLDEV) == STL_CTRLLOCK) - localtios = (minor(dev) & STL_CALLOUTDEV) ? - &portp->lockouttios : &portp->lockintios; - else - return(ENODEV); - - switch (cmd) { - case TIOCSETA: - if ((error = suser(td)) == 0) - *localtios = *((struct termios *) data); - break; - case TIOCGETA: - *((struct termios *) data) = *localtios; - break; - case TIOCGETD: - *((int *) data) = TTYDISC; - break; - case TIOCGWINSZ: - bzero(data, sizeof(struct winsize)); - break; - default: - error = ENOTTY; - break; - } - return(error); - } - -/* - * Deal with 4.3 compatibility issues if we have too... - */ -#if defined(COMPAT_43) || defined(COMPAT_SUNOS) - if (1) { - struct termios tios; - unsigned long oldcmd; - - tios = tp->t_termios; - oldcmd = cmd; - if ((error = ttsetcompat(tp, &cmd, data, &tios))) - return(error); - if (cmd != oldcmd) - data = (caddr_t) &tios; - } -#endif - -/* - * Carry out some pre-cmd processing work first... - * Hmmm, not so sure we want this, disable for now... - */ - if ((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) { - newtios = (struct termios *) data; - localtios = (minor(dev) & STL_CALLOUTDEV) ? - &portp->lockouttios : &portp->lockintios; - - newtios->c_iflag = (tp->t_iflag & localtios->c_iflag) | - (newtios->c_iflag & ~localtios->c_iflag); - newtios->c_oflag = (tp->t_oflag & localtios->c_oflag) | - (newtios->c_oflag & ~localtios->c_oflag); - newtios->c_cflag = (tp->t_cflag & localtios->c_cflag) | - (newtios->c_cflag & ~localtios->c_cflag); - newtios->c_lflag = (tp->t_lflag & localtios->c_lflag) | - (newtios->c_lflag & ~localtios->c_lflag); - for (i = 0; (i < NCCS); i++) { - if (localtios->c_cc[i] != 0) - newtios->c_cc[i] = tp->t_cc[i]; - } - if (localtios->c_ispeed != 0) - newtios->c_ispeed = tp->t_ispeed; - if (localtios->c_ospeed != 0) - newtios->c_ospeed = tp->t_ospeed; - } - -/* - * Call the line discipline and the common command processing to - * process this command (if they can). - */ - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); - if (error != ENOIOCTL) - return(error); - - x = spltty(); - error = ttioctl(tp, cmd, data, flag); - stl_ttyoptim(portp, &tp->t_termios); - if (error != ENOIOCTL) { - splx(x); - return(error); - } - - error = 0; - -/* - * Process local commands here. These are all commands that only we - * can take care of (they all rely on actually doing something special - * to the actual hardware). - */ - switch (cmd) { - case TIOCSBRK: - stl_sendbreak(portp, -1); - break; - case TIOCCBRK: - stl_sendbreak(portp, -2); - break; - case TIOCSDTR: - stl_setsignals(portp, 1, -1); - break; - case TIOCCDTR: - stl_setsignals(portp, 0, -1); - break; - case TIOCMSET: - i = *((int *) data); - stl_setsignals(portp, ((i & TIOCM_DTR) ? 1 : 0), - ((i & TIOCM_RTS) ? 1 : 0)); - break; - case TIOCMBIS: - i = *((int *) data); - stl_setsignals(portp, ((i & TIOCM_DTR) ? 1 : -1), - ((i & TIOCM_RTS) ? 1 : -1)); - break; - case TIOCMBIC: - i = *((int *) data); - stl_setsignals(portp, ((i & TIOCM_DTR) ? 0 : -1), - ((i & TIOCM_RTS) ? 0 : -1)); - break; - case TIOCMGET: - *((int *) data) = (stl_getsignals(portp) | TIOCM_LE); - break; - case TIOCMSDTRWAIT: - if ((error = suser(td)) == 0) - portp->dtrwait = *((int *) data) * hz / 100; - break; - case TIOCMGDTRWAIT: - *((int *) data) = portp->dtrwait * 100 / hz; - break; - case TIOCTIMESTAMP: - portp->dotimestamp = 1; - *((struct timeval *) data) = portp->timestamp; - break; - default: - error = ENOTTY; - break; - } - splx(x); - - return(error); -} - -/*****************************************************************************/ - -/* - * Convert the specified minor device number into a port struct - * pointer. Return NULL if the device number is not a valid port. - */ - -STATIC stlport_t *stl_dev2port(dev_t dev) -{ - stlbrd_t *brdp; - - brdp = stl_brds[MKDEV2BRD(dev)]; - if (brdp == (stlbrd_t *) NULL) - return((stlport_t *) NULL); - return(brdp->ports[MKDEV2PORT(dev)]); -} - -/*****************************************************************************/ - -/* - * Initialize the port hardware. This involves enabling the transmitter - * and receiver, setting the port configuration, and setting the initial - * signal state. - */ - -static int stl_rawopen(stlport_t *portp) -{ -#if DEBUG - printf("stl_rawopen(portp=%p): brdnr=%d panelnr=%d portnr=%d\n", - (void *) portp, portp->brdnr, portp->panelnr, portp->portnr); -#endif - stl_param(&portp->tty, &portp->tty.t_termios); - portp->sigs = stl_getsignals(portp); - stl_setsignals(portp, 1, 1); - stl_enablerxtx(portp, 1, 1); - stl_startrxtx(portp, 1, 0); - return(0); -} - -/*****************************************************************************/ - -/* - * Shutdown the hardware of a port. Disable its transmitter and - * receiver, and maybe drop signals if appropriate. - */ - -static int stl_rawclose(stlport_t *portp) -{ - struct tty *tp; - -#if DEBUG - printf("stl_rawclose(portp=%p): brdnr=%d panelnr=%d portnr=%d\n", - (void *) portp, portp->brdnr, portp->panelnr, portp->portnr); -#endif - - tp = &portp->tty; - stl_disableintrs(portp); - stl_enablerxtx(portp, 0, 0); - stl_flush(portp, (FWRITE | FREAD)); - if (tp->t_cflag & HUPCL) { - stl_setsignals(portp, 0, 0); - if (portp->dtrwait != 0) { - portp->state |= ASY_DTRWAIT; - timeout(stl_dtrwakeup, portp, portp->dtrwait); - } - } - portp->callout = 0; - portp->brklen = 0; - portp->state &= ~(ASY_ACTIVE | ASY_RTSFLOW); - wakeup(&portp->callout); - wakeup(TSA_CARR_ON(tp)); - return(0); -} - -/*****************************************************************************/ - -/* - * Clear the DTR waiting flag, and wake up any sleepers waiting for - * DTR wait period to finish. - */ - -static void stl_dtrwakeup(void *arg) -{ - stlport_t *portp; - - portp = (stlport_t *) arg; - portp->state &= ~ASY_DTRWAIT; - wakeup(&portp->dtrwait); -} - -/*****************************************************************************/ - -/* - * Start (or continue) the transfer of TX data on this port. If the - * port is not currently busy then load up the interrupt ring queue - * buffer and kick of the transmitter. If the port is running low on - * TX data then refill the ring queue. This routine is also used to - * activate input flow control! - */ - -static void stl_start(struct tty *tp) -{ - stlport_t *portp; - unsigned int len, stlen; - char *head, *tail; - int count, x; - - portp = (stlport_t *) tp; - -#if DEBUG - printf("stl_start(tp=%x): brdnr=%d portnr=%d\n", (int) tp, - portp->brdnr, portp->portnr); -#endif - - x = spltty(); - -/* - * Check if the ports input has been blocked, and take appropriate action. - * Not very often do we really need to do anything, so make it quick. - */ - if (tp->t_state & TS_TBLOCK) { - if ((portp->state & ASY_RTSFLOW) == 0) - stl_flowcontrol(portp, 0, -1); - } else { - if (portp->state & ASY_RTSFLOW) - stl_flowcontrol(portp, 1, -1); - } - -#if VFREEBSD == 205 -/* - * Check if the output cooked clist buffers are near empty, wake up - * the line discipline to fill it up. - */ - if (tp->t_outq.c_cc <= tp->t_lowat) { - if (tp->t_state & TS_ASLEEP) { - tp->t_state &= ~TS_ASLEEP; - wakeup(&tp->t_outq); - } - selwakeuppri(&tp->t_wsel, TTOPRI); - } -#endif - - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { - splx(x); - return; - } - -/* - * Copy data from the clists into the interrupt ring queue. This will - * require at most 2 copys... What we do is calculate how many chars - * can fit into the ring queue, and how many can fit in 1 copy. If after - * the first copy there is still more room then do the second copy. - * The beauty of this type of ring queue is that we do not need to - * spl protect our-selves, since we only ever update the head pointer, - * and the interrupt routine only ever updates the tail pointer. - */ - if (tp->t_outq.c_cc != 0) { - head = portp->tx.head; - tail = portp->tx.tail; - if (head >= tail) { - len = STL_TXBUFSIZE - (head - tail) - 1; - stlen = portp->tx.endbuf - head; - } else { - len = tail - head - 1; - stlen = len; - } - - if (len > 0) { - stlen = MIN(len, stlen); - count = q_to_b(&tp->t_outq, head, stlen); - len -= count; - head += count; - if (head >= portp->tx.endbuf) { - head = portp->tx.buf; - if (len > 0) { - stlen = q_to_b(&tp->t_outq, head, len); - head += stlen; - count += stlen; - } - } - portp->tx.head = head; - if (count > 0) - stl_startrxtx(portp, -1, 1); - } - -/* - * If we sent something, make sure we are called again. - */ - tp->t_state |= TS_BUSY; - } - -#if VFREEBSD != 205 -/* - * Do any writer wakeups. - */ - ttwwakeup(tp); -#endif - - splx(x); -} - -/*****************************************************************************/ - -static void stl_flush(stlport_t *portp, int flag) -{ - char *head, *tail; - int len, x; - -#if DEBUG - printf("stl_flush(portp=%x,flag=%x)\n", (int) portp, flag); -#endif - - if (portp == (stlport_t *) NULL) - return; - - x = spltty(); - - if (flag & FWRITE) { - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_ccrwait(portp); - stl_setreg(portp, CCR, CCR_TXFLUSHFIFO); - stl_ccrwait(portp); - portp->tx.tail = portp->tx.head; - BRDDISABLE(portp->brdnr); - } - -/* - * The only thing to watch out for when flushing the read side is - * the RX status buffer. The interrupt code relys on the status - * bytes as being zeroed all the time (it does not bother setting - * a good char status to 0, it expects that it already will be). - * We also need to un-flow the RX channel if flow control was - * active. - */ - if (flag & FREAD) { - head = portp->rx.head; - tail = portp->rx.tail; - if (head != tail) { - if (head >= tail) { - len = head - tail; - } else { - len = portp->rx.endbuf - tail; - bzero(portp->rxstatus.buf, - (head - portp->rx.buf)); - } - bzero((tail + STL_RXBUFSIZE), len); - portp->rx.tail = head; - } - - if ((portp->state & ASY_RTSFLOW) && - ((portp->tty.t_state & TS_TBLOCK) == 0)) - stl_flowcontrol(portp, 1, -1); - } - - splx(x); -} - -/*****************************************************************************/ - -/* - * These functions get/set/update the registers of the cd1400 UARTs. - * Access to the cd1400 registers is via an address/data io port pair. - * (Maybe should make this inline...) - */ - -static int stl_getreg(stlport_t *portp, int regnr) -{ - outb(portp->ioaddr, (regnr + portp->uartaddr)); - return(inb(portp->ioaddr + EREG_DATA)); -} - -/*****************************************************************************/ - -static void stl_setreg(stlport_t *portp, int regnr, int value) -{ - outb(portp->ioaddr, (regnr + portp->uartaddr)); - outb((portp->ioaddr + EREG_DATA), value); -} - -/*****************************************************************************/ - -static int stl_updatereg(stlport_t *portp, int regnr, int value) -{ - outb(portp->ioaddr, (regnr + portp->uartaddr)); - if (inb(portp->ioaddr + EREG_DATA) != value) { - outb((portp->ioaddr + EREG_DATA), value); - return(1); - } - return(0); -} - -/*****************************************************************************/ - -/* - * Wait for the command register to be ready. We will poll this, since - * it won't usually take too long to be ready, and it is only really - * used for non-critical actions. - */ - -static void stl_ccrwait(stlport_t *portp) -{ - int i; - - for (i = 0; (i < CCR_MAXWAIT); i++) { - if (stl_getreg(portp, CCR) == 0) { - return; - } - } - - printf("STALLION: cd1400 device not responding, brd=%d panel=%d" - "port=%d\n", portp->brdnr, portp->panelnr, portp->portnr); -} - -/*****************************************************************************/ - -/* - * Transmit interrupt handler. This has gotta be fast! Handling TX - * chars is pretty simple, stuff as many as possible from the TX buffer - * into the cd1400 FIFO. Must also handle TX breaks here, since they - * are embedded as commands in the data stream. Oh no, had to use a goto! - * This could be optimized more, will do when I get time... - * In practice it is possible that interrupts are enabled but that the - * port has been hung up. Need to handle not having any TX buffer here, - * this is done by using the side effect that head and tail will also - * be NULL if the buffer has been freed. - */ - -static __inline void stl_txisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - int len, stlen; - char *head, *tail; - unsigned char ioack, srer; - -#if DEBUG - printf("stl_txisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_TXACK); - if (((ioack & panelp->ackmask) != 0) || - ((ioack & ACK_TYPMASK) != ACK_TYPTX)) { - printf("STALLION: bad TX interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - -/* - * Unfortunately we need to handle breaks in the data stream, since - * this is the only way to generate them on the cd1400. Do it now if - * a break is to be sent. Some special cases here: brklen is -1 then - * start sending an un-timed break, if brklen is -2 then stop sending - * an un-timed break, if brklen is -3 then we have just sent an - * un-timed break and do not want any data to go out, if brklen is -4 - * then a break has just completed so clean up the port settings. - */ - if (portp->brklen != 0) { - if (portp->brklen >= -1) { - outb(ioaddr, (TDR + portp->uartaddr)); - outb((ioaddr + EREG_DATA), ETC_CMD); - outb((ioaddr + EREG_DATA), ETC_STARTBREAK); - if (portp->brklen > 0) { - outb((ioaddr + EREG_DATA), ETC_CMD); - outb((ioaddr + EREG_DATA), ETC_DELAY); - outb((ioaddr + EREG_DATA), portp->brklen); - outb((ioaddr + EREG_DATA), ETC_CMD); - outb((ioaddr + EREG_DATA), ETC_STOPBREAK); - portp->brklen = -4; - } else { - portp->brklen = -3; - } - } else if (portp->brklen == -2) { - outb(ioaddr, (TDR + portp->uartaddr)); - outb((ioaddr + EREG_DATA), ETC_CMD); - outb((ioaddr + EREG_DATA), ETC_STOPBREAK); - portp->brklen = -4; - } else if (portp->brklen == -3) { - outb(ioaddr, (SRER + portp->uartaddr)); - srer = inb(ioaddr + EREG_DATA); - srer &= ~(SRER_TXDATA | SRER_TXEMPTY); - outb((ioaddr + EREG_DATA), srer); - } else { - outb(ioaddr, (COR2 + portp->uartaddr)); - outb((ioaddr + EREG_DATA), - (inb(ioaddr + EREG_DATA) & ~COR2_ETC)); - portp->brklen = 0; - } - goto stl_txalldone; - } - - head = portp->tx.head; - tail = portp->tx.tail; - len = (head >= tail) ? (head - tail) : (STL_TXBUFSIZE - (tail - head)); - if ((len == 0) || ((len < STL_TXBUFLOW) && - ((portp->state & ASY_TXLOW) == 0))) { - portp->state |= ASY_TXLOW; - stl_dotimeout(); - } - - if (len == 0) { - outb(ioaddr, (SRER + portp->uartaddr)); - srer = inb(ioaddr + EREG_DATA); - if (srer & SRER_TXDATA) { - srer = (srer & ~SRER_TXDATA) | SRER_TXEMPTY; - } else { - srer &= ~(SRER_TXDATA | SRER_TXEMPTY); - portp->tty.t_state &= ~TS_BUSY; - } - outb((ioaddr + EREG_DATA), srer); - } else { - len = MIN(len, CD1400_TXFIFOSIZE); - portp->stats.txtotal += len; - stlen = MIN(len, (portp->tx.endbuf - tail)); - outb(ioaddr, (TDR + portp->uartaddr)); - outsb((ioaddr + EREG_DATA), tail, stlen); - len -= stlen; - tail += stlen; - if (tail >= portp->tx.endbuf) - tail = portp->tx.buf; - if (len > 0) { - outsb((ioaddr + EREG_DATA), tail, len); - tail += len; - } - portp->tx.tail = tail; - } - -stl_txalldone: - outb(ioaddr, (EOSRR + portp->uartaddr)); - outb((ioaddr + EREG_DATA), 0); -} - -/*****************************************************************************/ - -/* - * Receive character interrupt handler. Determine if we have good chars - * or bad chars and then process appropriately. Good chars are easy - * just shove the lot into the RX buffer and set all status bytes to 0. - * If a bad RX char then process as required. This routine needs to be - * fast! - */ - -static __inline void stl_rxisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - struct tty *tp; - unsigned int ioack, len, buflen, stlen; - unsigned char status; - char ch; - char *head, *tail; - static char unwanted[CD1400_RXFIFOSIZE]; - -#if DEBUG - printf("stl_rxisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_RXACK); - if ((ioack & panelp->ackmask) != 0) { - printf("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - tp = &portp->tty; - -/* - * First up, caluclate how much room there is in the RX ring queue. - * We also want to keep track of the longest possible copy length, - * this has to allow for the wrapping of the ring queue. - */ - head = portp->rx.head; - tail = portp->rx.tail; - if (head >= tail) { - buflen = STL_RXBUFSIZE - (head - tail) - 1; - stlen = portp->rx.endbuf - head; - } else { - buflen = tail - head - 1; - stlen = buflen; - } - -/* - * Check if the input buffer is near full. If so then we should take - * some flow control action... It is very easy to do hardware and - * software flow control from here since we have the port selected on - * the UART. - */ - if (buflen <= (STL_RXBUFSIZE - STL_RXBUFHIGH)) { - if (((portp->state & ASY_RTSFLOW) == 0) && - (portp->state & ASY_RTSFLOWMODE)) { - portp->state |= ASY_RTSFLOW; - stl_setreg(portp, MCOR1, - (stl_getreg(portp, MCOR1) & 0xf0)); - stl_setreg(portp, MSVR2, 0); - portp->stats.rxrtsoff++; - } - } - -/* - * OK we are set, process good data... If the RX ring queue is full - * just chuck the chars - don't leave them in the UART. - */ - if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { - outb(ioaddr, (RDCR + portp->uartaddr)); - len = inb(ioaddr + EREG_DATA); - if (buflen == 0) { - outb(ioaddr, (RDSR + portp->uartaddr)); - insb((ioaddr + EREG_DATA), &unwanted[0], len); - portp->stats.rxlost += len; - portp->stats.rxtotal += len; - } else { - len = MIN(len, buflen); - portp->stats.rxtotal += len; - stlen = MIN(len, stlen); - if (len > 0) { - outb(ioaddr, (RDSR + portp->uartaddr)); - insb((ioaddr + EREG_DATA), head, stlen); - head += stlen; - if (head >= portp->rx.endbuf) { - head = portp->rx.buf; - len -= stlen; - insb((ioaddr + EREG_DATA), head, len); - head += len; - } - } - } - } else if ((ioack & ACK_TYPMASK) == ACK_TYPRXBAD) { - outb(ioaddr, (RDSR + portp->uartaddr)); - status = inb(ioaddr + EREG_DATA); - ch = inb(ioaddr + EREG_DATA); - if (status & ST_BREAK) - portp->stats.rxbreaks++; - if (status & ST_FRAMING) - portp->stats.rxframing++; - if (status & ST_PARITY) - portp->stats.rxparity++; - if (status & ST_OVERRUN) - portp->stats.rxoverrun++; - if (status & ST_SCHARMASK) { - if ((status & ST_SCHARMASK) == ST_SCHAR1) - portp->stats.txxon++; - if ((status & ST_SCHARMASK) == ST_SCHAR2) - portp->stats.txxoff++; - goto stl_rxalldone; - } - if ((portp->rxignoremsk & status) == 0) { - if ((tp->t_state & TS_CAN_BYPASS_L_RINT) && - ((status & ST_FRAMING) || - ((status & ST_PARITY) && (tp->t_iflag & INPCK)))) - ch = 0; - if ((portp->rxmarkmsk & status) == 0) - status = 0; - *(head + STL_RXBUFSIZE) = status; - *head++ = ch; - if (head >= portp->rx.endbuf) - head = portp->rx.buf; - } - } else { - printf("STALLION: bad RX interrupt ack value=%x\n", ioack); - return; - } - - portp->rx.head = head; - portp->state |= ASY_RXDATA; - stl_dotimeout(); - -stl_rxalldone: - outb(ioaddr, (EOSRR + portp->uartaddr)); - outb((ioaddr + EREG_DATA), 0); -} - -/*****************************************************************************/ - -/* - * Modem interrupt handler. The is called when the modem signal line - * (DCD) has changed state. Leave most of the work to the off-level - * processing routine. - */ - -static __inline void stl_mdmisr(stlpanel_t *panelp, int ioaddr) -{ - stlport_t *portp; - unsigned int ioack; - unsigned char misr; - -#if DEBUG - printf("stl_mdmisr(panelp=%x,ioaddr=%x)\n", (int) panelp, ioaddr); -#endif - - ioack = inb(ioaddr + EREG_MDACK); - if (((ioack & panelp->ackmask) != 0) || - ((ioack & ACK_TYPMASK) != ACK_TYPMDM)) { - printf("STALLION: bad MODEM interrupt ack value=%x\n", ioack); - return; - } - portp = panelp->ports[(ioack >> 3)]; - - outb(ioaddr, (MISR + portp->uartaddr)); - misr = inb(ioaddr + EREG_DATA); - if (misr & MISR_DCD) { - portp->state |= ASY_DCDCHANGE; - portp->stats.modem++; - stl_dotimeout(); - } - - outb(ioaddr, (EOSRR + portp->uartaddr)); - outb((ioaddr + EREG_DATA), 0); -} - -/*****************************************************************************/ - -/* - * Interrupt handler for EIO and ECH boards. This code ain't all that - * pretty, but the idea is to make it as fast as possible. This code is - * well suited to be assemblerized :-) We don't use the general purpose - * register access functions here, for speed we will go strait to the - * io register. - */ - -static void stlintr(int unit) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - unsigned char svrtype; - int i, panelnr, iobase; - int cnt; - -#if DEBUG - printf("stlintr(unit=%d)\n", unit); -#endif - - cnt = 0; - panelp = (stlpanel_t *) NULL; - for (i = 0; (i < stl_nrbrds); ) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) { - i++; - continue; - } - if (brdp->state == 0) { - i++; - continue; - } -/* - * The following section of code handles the subtle differences - * between board types. It is sort of similar, but different - * enough to handle each separately. - */ - if (brdp->brdtype == BRD_EASYIO) { - if ((inb(brdp->iostatus) & EIO_INTRPEND) == 0) { - i++; - continue; - } - panelp = brdp->panels[0]; - iobase = panelp->iobase; - outb(iobase, SVRR); - svrtype = inb(iobase + EREG_DATA); - if (brdp->nrports > 4) { - outb(iobase, (SVRR + 0x80)); - svrtype |= inb(iobase + EREG_DATA); - } - } else if (brdp->brdtype == BRD_ECH) { - if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) { - i++; - continue; - } - outb(brdp->ioctrl, (brdp->ioctrlval | ECH_BRDENABLE)); - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - iobase = panelp->iobase; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - if (panelp->nrports > 8) { - iobase += 0x8; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - } - } - if (panelnr >= brdp->nrpanels) { - i++; - continue; - } - outb(iobase, SVRR); - svrtype = inb(iobase + EREG_DATA); - outb(iobase, (SVRR + 0x80)); - svrtype |= inb(iobase + EREG_DATA); - } else if (brdp->brdtype == BRD_ECHPCI) { - iobase = brdp->ioaddr2; - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - outb(brdp->ioctrl, panelp->pagenr); - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - if (panelp->nrports > 8) { - outb(brdp->ioctrl, (panelp->pagenr + 1)); - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - } - } - if (panelnr >= brdp->nrpanels) { - i++; - continue; - } - outb(iobase, SVRR); - svrtype = inb(iobase + EREG_DATA); - outb(iobase, (SVRR + 0x80)); - svrtype |= inb(iobase + EREG_DATA); - } else if (brdp->brdtype == BRD_ECHMC) { - if ((inb(brdp->iostatus) & ECH_INTRPEND) == 0) { - i++; - continue; - } - for (panelnr = 0; (panelnr < brdp->nrpanels); panelnr++) { - panelp = brdp->panels[panelnr]; - iobase = panelp->iobase; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - if (panelp->nrports > 8) { - iobase += 0x8; - if (inb(iobase + ECH_PNLSTATUS) & ECH_PNLINTRPEND) - break; - } - } - if (panelnr >= brdp->nrpanels) { - i++; - continue; - } - outb(iobase, SVRR); - svrtype = inb(iobase + EREG_DATA); - outb(iobase, (SVRR + 0x80)); - svrtype |= inb(iobase + EREG_DATA); - } else { - printf("STALLION: unknown board type=%x\n", brdp->brdtype); - i++; - continue; - } - -/* - * We have determined what type of service is required for a - * port. From here on in the service of a port is the same no - * matter what the board type... - */ - if (svrtype & SVRR_RX) - stl_rxisr(panelp, iobase); - if (svrtype & SVRR_TX) - stl_txisr(panelp, iobase); - if (svrtype & SVRR_MDM) - stl_mdmisr(panelp, iobase); - - if (brdp->brdtype == BRD_ECH) - outb(brdp->ioctrl, (brdp->ioctrlval | ECH_BRDDISABLE)); - } -} - -/*****************************************************************************/ - -#if NPCI > 0 - -static void stlpciintr(void *arg) -{ - stlintr(0); -} - -#endif - -/*****************************************************************************/ - -/* - * If we haven't scheduled a timeout then do it, some port needs high - * level processing. - */ - -static void stl_dotimeout() -{ -#if DEBUG - printf("stl_dotimeout()\n"); -#endif - - if (stl_doingtimeout == 0) { - timeout(stl_poll, 0, 1); - stl_doingtimeout++; - } -} - -/*****************************************************************************/ - -/* - * Service "software" level processing. Too slow or painfull to be done - * at real hardware interrupt time. This way we might also be able to - * do some service on other waiting ports as well... - */ - -static void stl_poll(void *arg) -{ - stlbrd_t *brdp; - stlport_t *portp; - struct tty *tp; - int brdnr, portnr, rearm, x; - -#if DEBUG - printf("stl_poll()\n"); -#endif - - stl_doingtimeout = 0; - rearm = 0; - - x = spltty(); - for (brdnr = 0; (brdnr < stl_nrbrds); brdnr++) { - if ((brdp = stl_brds[brdnr]) == (stlbrd_t *) NULL) - continue; - for (portnr = 0; (portnr < brdp->nrports); portnr++) { - if ((portp = brdp->ports[portnr]) == (stlport_t *) NULL) - continue; - if ((portp->state & ASY_ACTIVE) == 0) - continue; - tp = &portp->tty; - - if (portp->state & ASY_RXDATA) - stl_rxprocess(portp); - if (portp->state & ASY_DCDCHANGE) { - portp->state &= ~ASY_DCDCHANGE; - portp->sigs = stl_getsignals(portp); - (*linesw[tp->t_line].l_modem)(tp, - (portp->sigs & TIOCM_CD)); - } - if (portp->state & ASY_TXLOW) { - portp->state &= ~ASY_TXLOW; - (*linesw[tp->t_line].l_start)(tp); - } - - if (portp->state & ASY_ACTIVE) - rearm++; - } - } - splx(x); - - if (rearm) - stl_dotimeout(); -} - -/*****************************************************************************/ - -/* - * Process the RX data that has been buffered up in the RX ring queue. - */ - -static void stl_rxprocess(stlport_t *portp) -{ - struct tty *tp; - unsigned int len, stlen, lostlen; - char *head, *tail; - char status; - int ch; - -#if DEBUG - printf("stl_rxprocess(portp=%x): brdnr=%d portnr=%d\n", (int) portp, - portp->brdnr, portp->portnr); -#endif - - tp = &portp->tty; - portp->state &= ~ASY_RXDATA; - - if ((tp->t_state & TS_ISOPEN) == 0) { - stl_flush(portp, FREAD); - return; - } - -/* - * Calculate the amount of data in the RX ring queue. Also calculate - * the largest single copy size... - */ - head = portp->rx.head; - tail = portp->rx.tail; - if (head >= tail) { - len = head - tail; - stlen = len; - } else { - len = STL_RXBUFSIZE - (tail - head); - stlen = portp->rx.endbuf - tail; - } - - if (tp->t_state & TS_CAN_BYPASS_L_RINT) { - if (len > 0) { - if (((tp->t_rawq.c_cc + len) >= TTYHOG) && - ((portp->state & ASY_RTSFLOWMODE) || - (tp->t_iflag & IXOFF)) && - ((tp->t_state & TS_TBLOCK) == 0)) { - ch = TTYHOG - tp->t_rawq.c_cc - 1; - len = (ch > 0) ? ch : 0; - stlen = MIN(stlen, len); - ttyblock(tp); - } - lostlen = b_to_q(tail, stlen, &tp->t_rawq); - tail += stlen; - len -= stlen; - if (tail >= portp->rx.endbuf) { - tail = portp->rx.buf; - lostlen += b_to_q(tail, len, &tp->t_rawq); - tail += len; - } - portp->stats.rxlost += lostlen; - ttwakeup(tp); - portp->rx.tail = tail; - } - } else { - while (portp->rx.tail != head) { - ch = (unsigned char) *(portp->rx.tail); - status = *(portp->rx.tail + STL_RXBUFSIZE); - if (status) { - *(portp->rx.tail + STL_RXBUFSIZE) = 0; - if (status & ST_BREAK) - ch |= TTY_BI; - if (status & ST_FRAMING) - ch |= TTY_FE; - if (status & ST_PARITY) - ch |= TTY_PE; - if (status & ST_OVERRUN) - ch |= TTY_OE; - } - (*linesw[tp->t_line].l_rint)(ch, tp); - if (portp->rx.tail == head) - break; - - if (++(portp->rx.tail) >= portp->rx.endbuf) - portp->rx.tail = portp->rx.buf; - } - } - - if (head != portp->rx.tail) - portp->state |= ASY_RXDATA; - -/* - * If we where flow controled then maybe the buffer is low enough that - * we can re-activate it. - */ - if ((portp->state & ASY_RTSFLOW) && ((tp->t_state & TS_TBLOCK) == 0)) - stl_flowcontrol(portp, 1, -1); -} - -/*****************************************************************************/ - -/* - * Set up the cd1400 registers for a port based on the termios port - * settings. - */ - -static int stl_param(struct tty *tp, struct termios *tiosp) -{ - stlport_t *portp; - unsigned int clkdiv; - unsigned char cor1, cor2, cor3; - unsigned char cor4, cor5, ccr; - unsigned char srer, sreron, sreroff; - unsigned char mcor1, mcor2, rtpr; - unsigned char clk, div; - int x; - - portp = (stlport_t *) tp; - -#if DEBUG - printf("stl_param(tp=%x,tiosp=%x): brdnr=%d portnr=%d\n", (int) tp, - (int) tiosp, portp->brdnr, portp->portnr); -#endif - - cor1 = 0; - cor2 = 0; - cor3 = 0; - cor4 = 0; - cor5 = 0; - ccr = 0; - rtpr = 0; - clk = 0; - div = 0; - mcor1 = 0; - mcor2 = 0; - sreron = 0; - sreroff = 0; - -/* - * Set up the RX char ignore mask with those RX error types we - * can ignore. We could have used some special modes of the cd1400 - * UART to help, but it is better this way because we can keep stats - * on the number of each type of RX exception event. - */ - portp->rxignoremsk = 0; - if (tiosp->c_iflag & IGNPAR) - portp->rxignoremsk |= (ST_PARITY | ST_FRAMING | ST_OVERRUN); - if (tiosp->c_iflag & IGNBRK) - portp->rxignoremsk |= ST_BREAK; - - portp->rxmarkmsk = ST_OVERRUN; - if (tiosp->c_iflag & (INPCK | PARMRK)) - portp->rxmarkmsk |= (ST_PARITY | ST_FRAMING); - if (tiosp->c_iflag & BRKINT) - portp->rxmarkmsk |= ST_BREAK; - -/* - * Go through the char size, parity and stop bits and set all the - * option registers appropriately. - */ - switch (tiosp->c_cflag & CSIZE) { - case CS5: - cor1 |= COR1_CHL5; - break; - case CS6: - cor1 |= COR1_CHL6; - break; - case CS7: - cor1 |= COR1_CHL7; - break; - default: - cor1 |= COR1_CHL8; - break; - } - - if (tiosp->c_cflag & CSTOPB) - cor1 |= COR1_STOP2; - else - cor1 |= COR1_STOP1; - - if (tiosp->c_cflag & PARENB) { - if (tiosp->c_cflag & PARODD) - cor1 |= (COR1_PARENB | COR1_PARODD); - else - cor1 |= (COR1_PARENB | COR1_PAREVEN); - } else { - cor1 |= COR1_PARNONE; - } - - if (tiosp->c_iflag & ISTRIP) - cor5 |= COR5_ISTRIP; - -/* - * Set the RX FIFO threshold at 6 chars. This gives a bit of breathing - * space for hardware flow control and the like. This should be set to - * VMIN. Also here we will set the RX data timeout to 10ms - this should - * really be based on VTIME... - */ - cor3 |= FIFO_RXTHRESHOLD; - rtpr = 2; - -/* - * Calculate the baud rate timers. For now we will just assume that - * the input and output baud are the same. Could have used a baud - * table here, but this way we can generate virtually any baud rate - * we like! - */ - if (tiosp->c_ispeed == 0) - tiosp->c_ispeed = tiosp->c_ospeed; - if ((tiosp->c_ospeed < 0) || (tiosp->c_ospeed > STL_MAXBAUD)) - return(EINVAL); - - if (tiosp->c_ospeed > 0) { - for (clk = 0; (clk < CD1400_NUMCLKS); clk++) { - clkdiv = ((portp->clk / stl_cd1400clkdivs[clk]) / - tiosp->c_ospeed); - if (clkdiv < 0x100) - break; - } - div = (unsigned char) clkdiv; - } - -/* - * Check what form of modem signaling is required and set it up. - */ - if ((tiosp->c_cflag & CLOCAL) == 0) { - mcor1 |= MCOR1_DCD; - mcor2 |= MCOR2_DCD; - sreron |= SRER_MODEM; - } - -/* - * Setup cd1400 enhanced modes if we can. In particular we want to - * handle as much of the flow control as possbile automatically. As - * well as saving a few CPU cycles it will also greatly improve flow - * control reliablilty. - */ - if (tiosp->c_iflag & IXON) { - cor2 |= COR2_TXIBE; - cor3 |= COR3_SCD12; - if (tiosp->c_iflag & IXANY) - cor2 |= COR2_IXM; - } - - if (tiosp->c_cflag & CCTS_OFLOW) - cor2 |= COR2_CTSAE; - if (tiosp->c_cflag & CRTS_IFLOW) - mcor1 |= FIFO_RTSTHRESHOLD; - -/* - * All cd1400 register values calculated so go through and set them - * all up. - */ -#if DEBUG - printf("SETPORT: portnr=%d panelnr=%d brdnr=%d\n", portp->portnr, - portp->panelnr, portp->brdnr); - printf(" cor1=%x cor2=%x cor3=%x cor4=%x cor5=%x\n", cor1, cor2, - cor3, cor4, cor5); - printf(" mcor1=%x mcor2=%x rtpr=%x sreron=%x sreroff=%x\n", - mcor1, mcor2, rtpr, sreron, sreroff); - printf(" tcor=%x tbpr=%x rcor=%x rbpr=%x\n", clk, div, clk, div); - printf(" schr1=%x schr2=%x schr3=%x schr4=%x\n", - tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP], tiosp->c_cc[VSTART], - tiosp->c_cc[VSTOP]); -#endif - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x3)); - srer = stl_getreg(portp, SRER); - stl_setreg(portp, SRER, 0); - ccr += stl_updatereg(portp, COR1, cor1); - ccr += stl_updatereg(portp, COR2, cor2); - ccr += stl_updatereg(portp, COR3, cor3); - if (ccr) { - stl_ccrwait(portp); - stl_setreg(portp, CCR, CCR_CORCHANGE); - } - stl_setreg(portp, COR4, cor4); - stl_setreg(portp, COR5, cor5); - stl_setreg(portp, MCOR1, mcor1); - stl_setreg(portp, MCOR2, mcor2); - if (tiosp->c_ospeed == 0) { - stl_setreg(portp, MSVR1, 0); - } else { - stl_setreg(portp, MSVR1, MSVR1_DTR); - stl_setreg(portp, TCOR, clk); - stl_setreg(portp, TBPR, div); - stl_setreg(portp, RCOR, clk); - stl_setreg(portp, RBPR, div); - } - stl_setreg(portp, SCHR1, tiosp->c_cc[VSTART]); - stl_setreg(portp, SCHR2, tiosp->c_cc[VSTOP]); - stl_setreg(portp, SCHR3, tiosp->c_cc[VSTART]); - stl_setreg(portp, SCHR4, tiosp->c_cc[VSTOP]); - stl_setreg(portp, RTPR, rtpr); - mcor1 = stl_getreg(portp, MSVR1); - if (mcor1 & MSVR1_DCD) - portp->sigs |= TIOCM_CD; - else - portp->sigs &= ~TIOCM_CD; - stl_setreg(portp, SRER, ((srer & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - portp->state &= ~(ASY_RTSFLOWMODE | ASY_CTSFLOWMODE); - portp->state |= ((tiosp->c_cflag & CRTS_IFLOW) ? ASY_RTSFLOWMODE : 0); - portp->state |= ((tiosp->c_cflag & CCTS_OFLOW) ? ASY_CTSFLOWMODE : 0); - stl_ttyoptim(portp, tiosp); - splx(x); - - return(0); -} - -/*****************************************************************************/ - -/* - * Action the flow control as required. The hw and sw args inform the - * routine what flow control methods it should try. - */ - -static void stl_flowcontrol(stlport_t *portp, int hw, int sw) -{ - unsigned char *head, *tail; - int len, hwflow, x; - -#if DEBUG - printf("stl_flowcontrol(portp=%x,hw=%d,sw=%d)\n", (int) portp, hw, sw); -#endif - - hwflow = -1; - - if (portp->state & ASY_RTSFLOWMODE) { - if (hw == 0) { - if ((portp->state & ASY_RTSFLOW) == 0) - hwflow = 0; - } else if (hw > 0) { - if (portp->state & ASY_RTSFLOW) { - head = portp->rx.head; - tail = portp->rx.tail; - len = (head >= tail) ? (head - tail) : - (STL_RXBUFSIZE - (tail - head)); - if (len < STL_RXBUFHIGH) - hwflow = 1; - } - } - } - -/* - * We have worked out what to do, if anything. So now apply it to the - * UART port. - */ - if (hwflow >= 0) { - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - if (hwflow == 0) { - portp->state |= ASY_RTSFLOW; - stl_setreg(portp, MCOR1, - (stl_getreg(portp, MCOR1) & 0xf0)); - stl_setreg(portp, MSVR2, 0); - portp->stats.rxrtsoff++; - } else if (hwflow > 0) { - portp->state &= ~ASY_RTSFLOW; - stl_setreg(portp, MSVR2, MSVR2_RTS); - stl_setreg(portp, MCOR1, - (stl_getreg(portp, MCOR1) | FIFO_RTSTHRESHOLD)); - portp->stats.rxrtson++; - } - BRDDISABLE(portp->brdnr); - splx(x); - } -} - - -/*****************************************************************************/ - -/* - * Set the state of the DTR and RTS signals. - */ - -static void stl_setsignals(stlport_t *portp, int dtr, int rts) -{ - unsigned char msvr1, msvr2; - int x; - -#if DEBUG - printf("stl_setsignals(portp=%x,dtr=%d,rts=%d)\n", (int) portp, - dtr, rts); -#endif - - msvr1 = 0; - msvr2 = 0; - if (dtr > 0) - msvr1 = MSVR1_DTR; - if (rts > 0) - msvr2 = MSVR2_RTS; - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - if (rts >= 0) - stl_setreg(portp, MSVR2, msvr2); - if (dtr >= 0) - stl_setreg(portp, MSVR1, msvr1); - BRDDISABLE(portp->brdnr); - splx(x); -} - -/*****************************************************************************/ - -/* - * Get the state of the signals. - */ - -static int stl_getsignals(stlport_t *portp) -{ - unsigned char msvr1, msvr2; - int sigs, x; - -#if DEBUG - printf("stl_getsignals(portp=%x)\n", (int) portp); -#endif - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x3)); - msvr1 = stl_getreg(portp, MSVR1); - msvr2 = stl_getreg(portp, MSVR2); - BRDDISABLE(portp->brdnr); - splx(x); - - sigs = 0; - sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0; - sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0; - sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0; - sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0; - sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0; - sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0; - return(sigs); -} - -/*****************************************************************************/ - -/* - * Enable or disable the Transmitter and/or Receiver. - */ - -static void stl_enablerxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char ccr; - int x; - -#if DEBUG - printf("stl_enablerxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx); -#endif - - ccr = 0; - if (tx == 0) - ccr |= CCR_TXDISABLE; - else if (tx > 0) - ccr |= CCR_TXENABLE; - if (rx == 0) - ccr |= CCR_RXDISABLE; - else if (rx > 0) - ccr |= CCR_RXENABLE; - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x03)); - stl_ccrwait(portp); - stl_setreg(portp, CCR, ccr); - stl_ccrwait(portp); - BRDDISABLE(portp->brdnr); - splx(x); -} - -/*****************************************************************************/ - -/* - * Start or stop the Transmitter and/or Receiver. - */ - -static void stl_startrxtx(stlport_t *portp, int rx, int tx) -{ - unsigned char sreron, sreroff; - int x; - -#if DEBUG - printf("stl_startrxtx(portp=%x,rx=%d,tx=%d)\n", (int) portp, rx, tx); -#endif - - sreron = 0; - sreroff = 0; - if (tx == 0) - sreroff |= (SRER_TXDATA | SRER_TXEMPTY); - else if (tx == 1) - sreron |= SRER_TXDATA; - else if (tx >= 2) - sreron |= SRER_TXEMPTY; - if (rx == 0) - sreroff |= SRER_RXDATA; - else if (rx > 0) - sreron |= SRER_RXDATA; - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x3)); - stl_setreg(portp, SRER, - ((stl_getreg(portp, SRER) & ~sreroff) | sreron)); - BRDDISABLE(portp->brdnr); - if (tx > 0) - portp->tty.t_state |= TS_BUSY; - splx(x); -} - -/*****************************************************************************/ - -/* - * Disable all interrupts from this port. - */ - -static void stl_disableintrs(stlport_t *portp) -{ - int x; - -#if DEBUG - printf("stl_disableintrs(portp=%x)\n", (int) portp); -#endif - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x3)); - stl_setreg(portp, SRER, 0); - BRDDISABLE(portp->brdnr); - splx(x); -} - -/*****************************************************************************/ - -static void stl_sendbreak(stlport_t *portp, long len) -{ - int x; - -#if DEBUG - printf("stl_sendbreak(portp=%x,len=%d)\n", (int) portp, (int) len); -#endif - - x = spltty(); - BRDENABLE(portp->brdnr, portp->pagenr); - stl_setreg(portp, CAR, (portp->portnr & 0x3)); - stl_setreg(portp, COR2, (stl_getreg(portp, COR2) | COR2_ETC)); - stl_setreg(portp, SRER, - ((stl_getreg(portp, SRER) & ~SRER_TXDATA) | SRER_TXEMPTY)); - BRDDISABLE(portp->brdnr); - if (len > 0) { - len = len / 5; - portp->brklen = (len > 255) ? 255 : len; - } else { - portp->brklen = len; - } - splx(x); - portp->stats.txbreaks++; -} - -/*****************************************************************************/ - -/* - * Enable l_rint processing bypass mode if tty modes allow it. - */ - -static void stl_ttyoptim(stlport_t *portp, struct termios *tiosp) -{ - struct tty *tp; - - tp = &portp->tty; - if (((tiosp->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR)) == 0) && - (((tiosp->c_iflag & BRKINT) == 0) || (tiosp->c_iflag & IGNBRK)) && - (((tiosp->c_iflag & PARMRK) == 0) || - ((tiosp->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))) && - ((tiosp->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN)) ==0) && - (linesw[tp->t_line].l_rint == ttyinput)) - tp->t_state |= TS_CAN_BYPASS_L_RINT; - else - tp->t_state &= ~TS_CAN_BYPASS_L_RINT; - portp->hotchar = linesw[tp->t_line].l_hotchar; -} - -/*****************************************************************************/ - -/* - * Try and find and initialize all the ports on a panel. We don't care - * what sort of board these ports are on - since the port io registers - * are almost identical when dealing with ports. - */ - -static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) -{ - stlport_t *portp; - unsigned int chipmask; - unsigned int gfrcr; - int nrchips, uartaddr, ioaddr; - int i, j; - -#if DEBUG - printf("stl_initports(panelp=%x)\n", (int) panelp); -#endif - - BRDENABLE(panelp->brdnr, panelp->pagenr); - -/* - * Check that each chip is present and started up OK. - */ - chipmask = 0; - nrchips = panelp->nrports / CD1400_PORTS; - for (i = 0; (i < nrchips); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb(brdp->ioctrl, (panelp->pagenr + (i >> 1))); - ioaddr = panelp->iobase; - } else { - ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 1)); - } - uartaddr = (i & 0x01) ? 0x080 : 0; - outb(ioaddr, (GFRCR + uartaddr)); - outb((ioaddr + EREG_DATA), 0); - outb(ioaddr, (CCR + uartaddr)); - outb((ioaddr + EREG_DATA), CCR_RESETFULL); - outb((ioaddr + EREG_DATA), CCR_RESETFULL); - outb(ioaddr, (GFRCR + uartaddr)); - for (j = 0; (j < CCR_MAXWAIT); j++) { - gfrcr = inb(ioaddr + EREG_DATA); - if ((gfrcr > 0x40) && (gfrcr < 0x60)) - break; - } - if (j >= CCR_MAXWAIT) { - printf("STALLION: cd1400 not responding, brd=%d " - "panel=%d chip=%d\n", panelp->brdnr, - panelp->panelnr, i); - continue; - } - chipmask |= (0x1 << i); - outb(ioaddr, (PPR + uartaddr)); - outb((ioaddr + EREG_DATA), PPR_SCALAR); - } - -/* - * All cd1400's are initialized (if found!). Now go through and setup - * each ports data structures. Also init the LIVR register of cd1400 - * for each port. - */ - ioaddr = panelp->iobase; - for (i = 0; (i < panelp->nrports); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb(brdp->ioctrl, (panelp->pagenr + (i >> 3))); - ioaddr = panelp->iobase; - } else { - ioaddr = panelp->iobase + (EREG_BANKSIZE * (i >> 3)); - } - if ((chipmask & (0x1 << (i / 4))) == 0) - continue; - portp = (stlport_t *) malloc(sizeof(stlport_t), M_TTYS, - M_NOWAIT | M_ZERO); - if (portp == (stlport_t *) NULL) { - printf("STALLION: failed to allocate port memory " - "(size=%d)\n", sizeof(stlport_t)); - break; - } - - portp->portnr = i; - portp->brdnr = panelp->brdnr; - portp->panelnr = panelp->panelnr; - portp->clk = brdp->clk; - portp->ioaddr = ioaddr; - portp->uartaddr = (i & 0x4) << 5; - portp->pagenr = panelp->pagenr + (i >> 3); - portp->hwid = stl_getreg(portp, GFRCR); - stl_setreg(portp, CAR, (i & 0x3)); - stl_setreg(portp, LIVR, (i << 3)); - panelp->ports[i] = portp; - - j = STL_TXBUFSIZE + (2 * STL_RXBUFSIZE); - portp->tx.buf = (char *) malloc(j, M_TTYS, M_NOWAIT); - if (portp->tx.buf == (char *) NULL) { - printf("STALLION: failed to allocate buffer memory " - "(size=%d)\n", j); - break; - } - portp->tx.endbuf = portp->tx.buf + STL_TXBUFSIZE; - portp->tx.head = portp->tx.buf; - portp->tx.tail = portp->tx.buf; - portp->rx.buf = portp->tx.buf + STL_TXBUFSIZE; - portp->rx.endbuf = portp->rx.buf + STL_RXBUFSIZE; - portp->rx.head = portp->rx.buf; - portp->rx.tail = portp->rx.buf; - portp->rxstatus.buf = portp->rx.buf + STL_RXBUFSIZE; - portp->rxstatus.endbuf = portp->rxstatus.buf + STL_RXBUFSIZE; - portp->rxstatus.head = portp->rxstatus.buf; - portp->rxstatus.tail = portp->rxstatus.buf; - bzero(portp->rxstatus.head, STL_RXBUFSIZE); - - portp->initintios.c_ispeed = STL_DEFSPEED; - portp->initintios.c_ospeed = STL_DEFSPEED; - portp->initintios.c_cflag = STL_DEFCFLAG; - portp->initintios.c_iflag = 0; - portp->initintios.c_oflag = 0; - portp->initintios.c_lflag = 0; - bcopy(&ttydefchars[0], &portp->initintios.c_cc[0], - sizeof(portp->initintios.c_cc)); - portp->initouttios = portp->initintios; - portp->dtrwait = 3 * hz; - } - - BRDDISABLE(panelp->brdnr); - return(0); -} - -/*****************************************************************************/ - -/* - * Try to find and initialize an EasyIO board. - */ - -static int stl_initeio(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status; - -#if DEBUG - printf("stl_initeio(brdp=%x)\n", (int) brdp); -#endif - - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 2; - brdp->clk = EIO_CLK; - - status = inb(brdp->iostatus); - switch (status & EIO_IDBITMASK) { - case EIO_8PORTM: - brdp->clk = EIO_CLK8M; - /* FALLTHROUGH */ - case EIO_8PORTRS: - case EIO_8PORTDI: - brdp->nrports = 8; - break; - case EIO_4PORTRS: - brdp->nrports = 4; - break; - default: - return(ENODEV); - } - -/* - * Check that the supplied IRQ is good and then use it to setup the - * programmable interrupt bits on EIO board. Also set the edge/level - * triggered interrupt bit. - */ - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printf("STALLION: invalid irq=%d for brd=%d\n", brdp->irq, - brdp->brdnr); - return(EINVAL); - } - outb(brdp->ioctrl, (stl_vecmap[brdp->irq] | - ((brdp->irqtype) ? EIO_INTLEVEL : EIO_INTEDGE))); - - panelp = (stlpanel_t *) malloc(sizeof(stlpanel_t), M_TTYS, - M_NOWAIT | M_ZERO); - if (panelp == (stlpanel_t *) NULL) { - printf("STALLION: failed to allocate memory (size=%d)\n", - sizeof(stlpanel_t)); - return(ENOMEM); - } - - panelp->brdnr = brdp->brdnr; - panelp->panelnr = 0; - panelp->nrports = brdp->nrports; - panelp->iobase = brdp->ioaddr1; - panelp->hwid = status; - brdp->panels[0] = panelp; - brdp->nrpanels = 1; - brdp->hwid = status; - brdp->state |= BRD_FOUND; - return(0); -} - -/*****************************************************************************/ - -/* - * Try to find an ECH board and initialize it. This code is capable of - * dealing with all types of ECH board. - */ - -static int stl_initech(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - unsigned int status, nxtid; - int panelnr, ioaddr, i; - -#if DEBUG - printf("stl_initech(brdp=%x)\n", (int) brdp); -#endif - -/* - * Set up the initial board register contents for boards. This varys a - * bit between the different board types. So we need to handle each - * separately. Also do a check that the supplied IRQ is good. - */ - if (brdp->brdtype == BRD_ECH) { - brdp->ioctrl = brdp->ioaddr1 + 1; - brdp->iostatus = brdp->ioaddr1 + 1; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(ENODEV); - brdp->hwid = status; - - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printf("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(EINVAL); - } - status = ((brdp->ioaddr2 & ECH_ADDR2MASK) >> 1); - status |= (stl_vecmap[brdp->irq] << 1); - outb(brdp->ioaddr1, (status | ECH_BRDRESET)); - brdp->ioctrlval = ECH_INTENABLE | - ((brdp->irqtype) ? ECH_INTLEVEL : ECH_INTEDGE); - outb(brdp->ioctrl, (brdp->ioctrlval | ECH_BRDENABLE)); - outb(brdp->ioaddr1, status); - } else if (brdp->brdtype == BRD_ECHMC) { - brdp->ioctrl = brdp->ioaddr1 + 0x20; - brdp->iostatus = brdp->ioctrl; - status = inb(brdp->iostatus); - if ((status & ECH_IDBITMASK) != ECH_ID) - return(ENODEV); - brdp->hwid = status; - - if ((brdp->irq < 0) || (brdp->irq > 15) || - (stl_vecmap[brdp->irq] == (unsigned char) 0xff)) { - printf("STALLION: invalid irq=%d for brd=%d\n", - brdp->irq, brdp->brdnr); - return(EINVAL); - } - outb(brdp->ioctrl, ECHMC_BRDRESET); - outb(brdp->ioctrl, ECHMC_INTENABLE); - } else if (brdp->brdtype == BRD_ECHPCI) { - brdp->ioctrl = brdp->ioaddr1 + 2; - } - - brdp->clk = ECH_CLK; - -/* - * Scan through the secondary io address space looking for panels. - * As we find'em allocate and initialize panel structures for each. - */ - ioaddr = brdp->ioaddr2; - panelnr = 0; - nxtid = 0; - - for (i = 0; (i < STL_MAXPANELS); i++) { - if (brdp->brdtype == BRD_ECHPCI) { - outb(brdp->ioctrl, nxtid); - ioaddr = brdp->ioaddr2; - } - status = inb(ioaddr + ECH_PNLSTATUS); - if ((status & ECH_PNLIDMASK) != nxtid) - break; - panelp = (stlpanel_t *) malloc(sizeof(stlpanel_t), M_TTYS, - M_NOWAIT | M_ZERO); - if (panelp == (stlpanel_t *) NULL) { - printf("STALLION: failed to allocate memory" - "(size=%d)\n", sizeof(stlpanel_t)); - break; - } - panelp->brdnr = brdp->brdnr; - panelp->panelnr = panelnr; - panelp->iobase = ioaddr; - panelp->pagenr = nxtid; - panelp->hwid = status; - if (status & ECH_PNL16PORT) { - if ((brdp->nrports + 16) > 32) - break; - panelp->nrports = 16; - panelp->ackmask = 0x80; - brdp->nrports += 16; - ioaddr += (EREG_BANKSIZE * 2); - nxtid += 2; - } else { - panelp->nrports = 8; - panelp->ackmask = 0xc0; - brdp->nrports += 8; - ioaddr += EREG_BANKSIZE; - nxtid++; - } - brdp->panels[panelnr++] = panelp; - brdp->nrpanels++; - if (ioaddr >= (brdp->ioaddr2 + 0x20)) - break; - } - - if (brdp->brdtype == BRD_ECH) - outb(brdp->ioctrl, (brdp->ioctrlval | ECH_BRDDISABLE)); - - brdp->state |= BRD_FOUND; - return(0); -} - -/*****************************************************************************/ - -/* - * Initialize and configure the specified board. This firstly probes - * for the board, if it is found then the board is initialized and - * then all its ports are initialized as well. - */ - -static int stl_brdinit(stlbrd_t *brdp) -{ - stlpanel_t *panelp; - int i, j, k; - -#if DEBUG - printf("stl_brdinit(brdp=%x): unit=%d type=%d io1=%x io2=%x irq=%d\n", - (int) brdp, brdp->brdnr, brdp->brdtype, brdp->ioaddr1, - brdp->ioaddr2, brdp->irq); -#endif - - switch (brdp->brdtype) { - case BRD_EASYIO: - stl_initeio(brdp); - break; - case BRD_ECH: - case BRD_ECHMC: - case BRD_ECHPCI: - stl_initech(brdp); - break; - default: - printf("STALLION: unit=%d is unknown board type=%d\n", - brdp->brdnr, brdp->brdtype); - return(ENODEV); - } - - stl_brds[brdp->brdnr] = brdp; - if ((brdp->state & BRD_FOUND) == 0) { -#if 0 - printf("STALLION: %s board not found, unit=%d io=%x irq=%d\n", - stl_brdnames[brdp->brdtype], brdp->brdnr, - brdp->ioaddr1, brdp->irq); -#endif - return(ENODEV); - } - - for (i = 0, k = 0; (i < STL_MAXPANELS); i++) { - panelp = brdp->panels[i]; - if (panelp != (stlpanel_t *) NULL) { - stl_initports(brdp, panelp); - for (j = 0; (j < panelp->nrports); j++) - brdp->ports[k++] = panelp->ports[j]; - } - } - - printf("stl%d: %s (driver version %s) unit=%d nrpanels=%d nrports=%d\n", - brdp->unitid, stl_brdnames[brdp->brdtype], stl_drvversion, - brdp->brdnr, brdp->nrpanels, brdp->nrports); - return(0); -} - -/*****************************************************************************/ - -/* - * Return the board stats structure to user app. - */ - -static int stl_getbrdstats(caddr_t data) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - int i; - - stl_brdstats = *((combrd_t *) data); - if (stl_brdstats.brd >= STL_MAXBRDS) - return(-ENODEV); - brdp = stl_brds[stl_brdstats.brd]; - if (brdp == (stlbrd_t *) NULL) - return(-ENODEV); - - bzero(&stl_brdstats, sizeof(combrd_t)); - stl_brdstats.brd = brdp->brdnr; - stl_brdstats.type = brdp->brdtype; - stl_brdstats.hwid = brdp->hwid; - stl_brdstats.state = brdp->state; - stl_brdstats.ioaddr = brdp->ioaddr1; - stl_brdstats.ioaddr2 = brdp->ioaddr2; - stl_brdstats.irq = brdp->irq; - stl_brdstats.nrpanels = brdp->nrpanels; - stl_brdstats.nrports = brdp->nrports; - for (i = 0; (i < brdp->nrpanels); i++) { - panelp = brdp->panels[i]; - stl_brdstats.panels[i].panel = i; - stl_brdstats.panels[i].hwid = panelp->hwid; - stl_brdstats.panels[i].nrports = panelp->nrports; - } - - *((combrd_t *) data) = stl_brdstats;; - return(0); -} - -/*****************************************************************************/ - -/* - * Resolve the referenced port number into a port struct pointer. - */ - -static stlport_t *stl_getport(int brdnr, int panelnr, int portnr) -{ - stlbrd_t *brdp; - stlpanel_t *panelp; - - if ((brdnr < 0) || (brdnr >= STL_MAXBRDS)) - return((stlport_t *) NULL); - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return((stlport_t *) NULL); - if ((panelnr < 0) || (panelnr >= brdp->nrpanels)) - return((stlport_t *) NULL); - panelp = brdp->panels[panelnr]; - if (panelp == (stlpanel_t *) NULL) - return((stlport_t *) NULL); - if ((portnr < 0) || (portnr >= panelp->nrports)) - return((stlport_t *) NULL); - return(panelp->ports[portnr]); -} - -/*****************************************************************************/ - -/* - * Return the port stats structure to user app. A NULL port struct - * pointer passed in means that we need to find out from the app - * what port to get stats for (used through board control device). - */ - -static int stl_getportstats(stlport_t *portp, caddr_t data) -{ - unsigned char *head, *tail; - - if (portp == (stlport_t *) NULL) { - stl_comstats = *((comstats_t *) data); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, - stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - portp->stats.state = portp->state; - /*portp->stats.flags = portp->flags;*/ - portp->stats.hwid = portp->hwid; - portp->stats.ttystate = portp->tty.t_state; - portp->stats.cflags = portp->tty.t_cflag; - portp->stats.iflags = portp->tty.t_iflag; - portp->stats.oflags = portp->tty.t_oflag; - portp->stats.lflags = portp->tty.t_lflag; - - head = portp->tx.head; - tail = portp->tx.tail; - portp->stats.txbuffered = ((head >= tail) ? (head - tail) : - (STL_TXBUFSIZE - (tail - head))); - - head = portp->rx.head; - tail = portp->rx.tail; - portp->stats.rxbuffered = (head >= tail) ? (head - tail) : - (STL_RXBUFSIZE - (tail - head)); - - portp->stats.signals = (unsigned long) stl_getsignals(portp); - - *((comstats_t *) data) = portp->stats; - return(0); -} - -/*****************************************************************************/ - -/* - * Clear the port stats structure. We also return it zeroed out... - */ - -static int stl_clrportstats(stlport_t *portp, caddr_t data) -{ - if (portp == (stlport_t *) NULL) { - stl_comstats = *((comstats_t *) data); - portp = stl_getport(stl_comstats.brd, stl_comstats.panel, - stl_comstats.port); - if (portp == (stlport_t *) NULL) - return(-ENODEV); - } - - bzero(&portp->stats, sizeof(comstats_t)); - portp->stats.brd = portp->brdnr; - portp->stats.panel = portp->panelnr; - portp->stats.port = portp->portnr; - *((comstats_t *) data) = stl_comstats; - return(0); -} - -/*****************************************************************************/ - -/* - * The "staliomem" device is used for stats collection in this driver. - */ - -static int stl_memioctl(dev_t dev, unsigned long cmd, caddr_t data, int flag, - struct thread *td) -{ - stlbrd_t *brdp; - int brdnr, rc; - -#if DEBUG - printf("stl_memioctl(dev=%s,cmd=%lx,data=%p,flag=%x)\n", - devtoname(dev), cmd, (void *) data, flag); -#endif - - brdnr = minor(dev) & 0x7; - brdp = stl_brds[brdnr]; - if (brdp == (stlbrd_t *) NULL) - return(ENODEV); - if (brdp->state == 0) - return(ENODEV); - - rc = 0; - - switch (cmd) { - case COM_GETPORTSTATS: - rc = stl_getportstats((stlport_t *) NULL, data); - break; - case COM_CLRPORTSTATS: - rc = stl_clrportstats((stlport_t *) NULL, data); - break; - case COM_GETBRDSTATS: - rc = stl_getbrdstats(data); - break; - default: - rc = ENOTTY; - break; - } - - return(rc); -} - -/*****************************************************************************/ |