Import kernel parts of the v0.0.5alpha Stallion driver(s).

This is now two seperate drivers that support (I think) all of Stallions's
range, including the high performance intelligent cards, and their older
cards.

Submitted by: Greg Ungerer (gerg@stallion.oz.au)

(User-mode parts and patches to follow)
This commit is contained in:
Peter Wemm 1996-05-04 06:31:39 +00:00
parent 64b69fe2e7
commit c1e8e76993
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/stallion/dist/; revision=15599
6 changed files with 5055 additions and 110 deletions

493
sys/i386/include/cdk.h Normal file
View File

@ -0,0 +1,493 @@
/*****************************************************************************/
/*
* 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.
*/
/*****************************************************************************/
#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

120
sys/i386/include/comstats.h Normal file
View File

@ -0,0 +1,120 @@
/*****************************************************************************/
/*
* comstats.h -- Serial Port Stats.
*
* 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.
*/
/*****************************************************************************/
#ifndef _COMSTATS_H
#define _COMSTATS_H
/*****************************************************************************/
/*
* Serial port stats structure. The structure itself is UART
* independent, but some fields may be UART/driver specific (for
* example state).
*/
typedef struct {
unsigned long brd;
unsigned long panel;
unsigned long port;
unsigned long hwid;
unsigned long type;
unsigned long txtotal;
unsigned long rxtotal;
unsigned long txbuffered;
unsigned long rxbuffered;
unsigned long rxoverrun;
unsigned long rxparity;
unsigned long rxframing;
unsigned long rxlost;
unsigned long txbreaks;
unsigned long rxbreaks;
unsigned long txxon;
unsigned long txxoff;
unsigned long rxxon;
unsigned long rxxoff;
unsigned long txctson;
unsigned long txctsoff;
unsigned long rxrtson;
unsigned long rxrtsoff;
unsigned long modem;
unsigned long state;
unsigned long flags;
unsigned long ttystate;
unsigned long cflags;
unsigned long iflags;
unsigned long oflags;
unsigned long lflags;
unsigned long signals;
} comstats_t;
/*
* Board stats structure. Returns usefull info about the board.
*/
#define COM_MAXPANELS 8
typedef struct {
unsigned long panel;
unsigned long type;
unsigned long hwid;
unsigned long nrports;
} companel_t;
typedef struct {
unsigned long brd;
unsigned long type;
unsigned long hwid;
unsigned long state;
unsigned long ioaddr;
unsigned long ioaddr2;
unsigned long memaddr;
unsigned long irq;
unsigned long nrpanels;
unsigned long nrports;
companel_t panels[COM_MAXPANELS];
} combrd_t;
/*
* Define the ioctl operations for stats stuff.
*/
#define COM_GETPORTSTATS _IOWR('c', 30, comstats_t)
#define COM_CLRPORTSTATS _IOWR('c', 31, comstats_t)
#define COM_GETBRDSTATS _IOWR('c', 32, combrd_t)
/*****************************************************************************/
#endif

View File

@ -2,8 +2,8 @@
Stallion Multiport Serial Driver Readme
---------------------------------------
Version: 0.0.4 alpha
Date: 06FEB96
Version: 0.0.5 alpha
Date: 20MAR96
Author: Greg Ungerer (gerg@stallion.oz.au)
@ -16,50 +16,122 @@ 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.
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.)
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.
All of these boards are not classical 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).
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 IO address space and 1 interrupt. On an EISA system it is possible
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 that can be either
10 pin RJ connectors or DB-25 connectors. The EasyIO-8M has 6 pin RJ
connectors.
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 from 8 to 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 ports. The
EasyConnection 8/32 boards come in ISA 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 EasyConnection 8/32 board
requires 2 separate IO address ranges, one 2 bytes in size and a secondary
region of 32 bytes. Each board also requires 1 interrupt, on EISA systems
multiple boards can share 1 interrupt. The secondary IO range (the 32 byte
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.
So thats the hardware supported (sounds like a marketing spiel doesn't it!).
I am working on drivers for other boards in the Stallion range, so look
out for those some time soon...
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.1 HOW TO GET BOARDS
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
@ -83,24 +155,37 @@ 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 driver can support up to 8 boards, with any combination of EasyIO and
EasyConnection 8/32 boards. So there is a theoretical maximum of 256 ports.
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!)
Instructions to install:
2.1 Instructions to install:
1. Copy the driver source files into the kernel source tree.
cp stallion.c /usr/src/sys/i386/isa
cp scd1400.h /usr/src/sys/i386/ic
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 file and change the VFREEBSD define to match your version.
stallion.c and istallion.c files and change the VFREEBSD define to match
your version.
2. (Note: skip to next step if on a FreeBSD kernel later than 2.1.0)
Add a character device switch table entry for the driver into the cdevsw
table structure. This involves adding some code into the kernel conf.c
file:
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
@ -145,12 +230,60 @@ d_ttycv_t stldevtotty;
- 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 line into the list (it is stored
alphabetically, so insert it appropriately):
- 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
@ -166,13 +299,33 @@ i386/isa/stallion.c optional stl device-driver
- 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, eg:
- 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 vector stlintr
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 io address and irq in this line as required
- 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.
@ -187,23 +340,60 @@ device stl0 at isa? port 0x2a0 tty irq 10 vector stlintr
And there you have it! It is a little bit of effort to get it in there...
So once you have a new kernel built, reboot to start it up. On startup the
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 wrong. The easiest thing to do
is change the DIP switches on the board to the desired address and reboot.
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
wired into the stallion.c driver code. It is currently set to IO address
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
@ -220,8 +410,8 @@ 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 ttyE32,
the third boards from ttyE64, etc). It will also create a set of modem call
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
@ -246,11 +436,69 @@ under FreeBSD:
4. NOTES
Be aware that this driver is still very new, so there is sure to be some bugs
in it. Please email me any feedback on bugs, problems, or even good
experiences with this driver!
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!
I will probably also add LKM support some time soon.
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).

View File

@ -276,6 +276,7 @@
#define ST_SCHAR3 0x30
#define ST_SCHAR4 0x40
#define ST_RANGE 0x70
#define ST_SCHARMASK 0x70
#define ST_TIMEOUT 0x80
#define MISR_DCD 0x80

3876
sys/i386/isa/istallion.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -53,6 +53,7 @@
#include <machine/cpu.h>
#include <machine/clock.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/comstats.h>
#include <i386/isa/ic/scd1400.h>
#include <pci.h>
@ -106,7 +107,7 @@ static unsigned int stl_irqshared = 0;
#define STL_MAXBRDS 8
#define STL_MAXPANELS 4
#define STL_PORTSPERPANEL 16
#define STL_PORTSPERBRD 32
#define STL_PORTSPERBRD 64
/*
* Define the important minor number break down bits. These have been
@ -118,6 +119,8 @@ static unsigned int stl_irqshared = 0;
#define STL_CTRLINIT 0x20
#define STL_CTRLDEV (STL_CTRLLOCK | STL_CTRLINIT)
#define STL_MEMDEV 0x07000000
#define STL_DEFSPEED 9600
#define STL_DEFCFLAG (CS8 | CREAD | HUPCL)
@ -140,7 +143,7 @@ static unsigned int stl_irqshared = 0;
*/
static char *stl_drvname = "stl";
static char *stl_longdrvname = "Stallion Multiport Serial Driver";
static char *stl_drvversion = "0.0.4";
static char *stl_drvversion = "0.0.5";
static int stl_brdprobed[STL_MAXBRDS];
static int stl_nrbrds = 0;
@ -149,16 +152,11 @@ static int stl_doingtimeout = 0;
static char *__file__ = /*__FILE__*/ "stallion.c";
/*
* Define the set of RX character error types.
* Define global stats structures. Not used often, and can be
* re-used for each stats call.
*/
#define STL_NRRXERRS 6
#define STL_RXPARITY 0
#define STL_RXFRAMING 1
#define STL_RXOVERRUN 2
#define STL_RXBREAK 3
#define STL_RXLOST 4
#define STL_RXLDLOST 5
static combrd_t stl_brdstats;
static comstats_t stl_comstats;
/*****************************************************************************/
@ -211,16 +209,17 @@ typedef struct {
int waitopens;
int hotchar;
unsigned int state;
unsigned int hwid;
unsigned int sigs;
unsigned int rxignoremsk;
unsigned int rxmarkmsk;
unsigned int rxerrs[STL_NRRXERRS];
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;
@ -232,6 +231,7 @@ typedef struct {
int pagenr;
int nrports;
int iobase;
unsigned int hwid;
unsigned int ackmask;
stlport_t *ports[STL_PORTSPERPANEL];
} stlpanel_t;
@ -239,6 +239,7 @@ typedef struct {
typedef struct {
int brdnr;
int brdtype;
int unitid;
int state;
int nrpanels;
int nrports;
@ -249,6 +250,7 @@ typedef struct {
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];
@ -416,14 +418,14 @@ static int stl_cd1400clkdivs[] = {
* the device number. This gives us plenty of minor numbers to play
* with...
*/
#define MKDEV2BRD(m) (((m) & 0x00070000) >> 16)
#define MKDEV2PORT(m) ((m) & 0x3f)
#define MKDEV2BRD(m) (((m) & 0x00700000) >> 20)
#define MKDEV2PORT(m) (((m) & 0x1f) | (((m) & 0x00010000) >> 11))
/*
* Define some handy local macros...
*/
#ifndef MIN
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#endif
/*****************************************************************************/
@ -473,7 +475,7 @@ static 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 void stl_getsignals(stlport_t *portp);
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);
@ -482,6 +484,12 @@ 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, int cmd, caddr_t data, int flag,
struct proc *p);
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 char *stlpciprobe(pcici_t tag, pcidi_t type);
@ -642,6 +650,7 @@ int stlattach(struct isa_device *idp)
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;
@ -722,6 +731,7 @@ void stlpciattach(pcici_t tag, int unit)
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;
@ -757,6 +767,9 @@ STATIC int stlopen(dev_t dev, int flag, int mode, struct proc *p)
/*
* Firstly check if the supplied device number is a valid device.
*/
if (dev & STL_MEMDEV)
return(0);
portp = stl_dev2port(dev);
if (portp == (stlport_t *) NULL)
return(ENXIO);
@ -865,6 +878,9 @@ STATIC int stlclose(dev_t dev, int flag, int mode, struct proc *p)
printf("stlclose(dev=%x,flag=%x,mode=%x,p=%x)\n", dev, flag, mode, p);
#endif
if (dev & STL_MEMDEV)
return(0);
portp = stl_dev2port(dev);
if (portp == (stlport_t *) NULL)
return(ENXIO);
@ -962,8 +978,11 @@ STATIC int stlioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
data, flag, p);
#endif
portp = stl_dev2port(dev);
dev = minor(dev);
if (dev & STL_MEMDEV)
return(stl_memioctl(dev, cmd, data, flag, p));
portp = stl_dev2port(dev);
if (portp == (stlport_t *) NULL)
return(ENODEV);
tp = &portp->tty;
@ -1099,8 +1118,7 @@ STATIC int stlioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
((i & TIOCM_RTS) ? 0 : -1));
break;
case TIOCMGET:
stl_getsignals(portp);
*((int *) data) = (portp->sigs | TIOCM_LE);
*((int *) data) = (stl_getsignals(portp) | TIOCM_LE);
break;
case TIOCMSDTRWAIT:
if ((error = suser(p->p_ucred, &p->p_acflag)) == 0)
@ -1132,19 +1150,11 @@ STATIC int stlioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
STATIC stlport_t *stl_dev2port(dev_t dev)
{
stlbrd_t *brdp;
int brdnr, portnr;
dev = minor(dev);
brdnr = MKDEV2BRD(dev);
if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
return((stlport_t *) NULL);
brdp = stl_brds[brdnr];
brdp = stl_brds[MKDEV2BRD(dev)];
if (brdp == (stlbrd_t *) NULL)
return((stlport_t *) NULL);
portnr = MKDEV2PORT(dev);
if ((portnr < 0) || (portnr >= brdp->nrports))
return((stlport_t *) NULL);
return(brdp->ports[portnr]);
return(brdp->ports[MKDEV2PORT(dev)]);
}
/*****************************************************************************/
@ -1162,7 +1172,7 @@ static int stl_rawopen(stlport_t *portp)
portp, portp->brdnr, portp->panelnr, portp->portnr);
#endif
stl_param(&portp->tty, &portp->tty.t_termios);
stl_getsignals(portp);
portp->sigs = stl_getsignals(portp);
stl_setsignals(portp, 1, 1);
stl_enablerxtx(portp, 1, 1);
stl_startrxtx(portp, 1, 0);
@ -1541,6 +1551,7 @@ static inline void stl_txisr(stlpanel_t *panelp, int ioaddr)
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);
@ -1620,6 +1631,7 @@ static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr)
stl_setreg(portp, MCOR1,
(stl_getreg(portp, MCOR1) & 0xf0));
stl_setreg(portp, MSVR2, 0);
portp->stats.rxrtsoff++;
}
}
@ -1633,9 +1645,11 @@ static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr)
if (buflen == 0) {
outb(ioaddr, (RDSR + portp->uartaddr));
insb((ioaddr + EREG_DATA), &unwanted[0], len);
portp->rxerrs[STL_RXLOST] += 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));
@ -1654,13 +1668,20 @@ static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr)
status = inb(ioaddr + EREG_DATA);
ch = inb(ioaddr + EREG_DATA);
if (status & ST_BREAK)
portp->rxerrs[STL_RXBREAK]++;
portp->stats.rxbreaks++;
if (status & ST_FRAMING)
portp->rxerrs[STL_RXFRAMING]++;
portp->stats.rxframing++;
if (status & ST_PARITY)
portp->rxerrs[STL_RXPARITY]++;
portp->stats.rxparity++;
if (status & ST_OVERRUN)
portp->rxerrs[STL_RXOVERRUN]++;
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) ||
@ -1682,6 +1703,7 @@ static inline void stl_rxisr(stlpanel_t *panelp, int ioaddr)
portp->state |= ASY_RXDATA;
stl_dotimeout();
stl_rxalldone:
outb(ioaddr, (EOSRR + portp->uartaddr));
outb((ioaddr + EREG_DATA), 0);
}
@ -1716,6 +1738,7 @@ static inline void stl_mdmisr(stlpanel_t *panelp, int ioaddr)
misr = inb(ioaddr + EREG_DATA);
if (misr & MISR_DCD) {
portp->state |= ASY_DCDCHANGE;
portp->stats.modem++;
stl_dotimeout();
}
@ -1935,7 +1958,7 @@ static void stl_poll(void *arg)
stl_rxprocess(portp);
if (portp->state & ASY_DCDCHANGE) {
portp->state &= ~ASY_DCDCHANGE;
stl_getsignals(portp);
portp->sigs = stl_getsignals(portp);
(*linesw[tp->t_line].l_modem)(tp,
(portp->sigs & TIOCM_CD));
}
@ -2001,13 +2024,6 @@ static void stl_rxprocess(stlport_t *portp)
((portp->state & ASY_RTSFLOWMODE) ||
(tp->t_iflag & IXOFF)) &&
((tp->t_state & TS_TBLOCK) == 0)) {
#if 1
if ((TTYHOG - tp->t_rawq.c_cc - 1) < 0)
printf("%s(%d): len < 0, len=%d "
"stlen=%d TTYHOG=%d cc=%d\n",
__file__, __LINE__, len,
stlen, TTYHOG, tp->t_rawq.c_cc);
#endif
ch = TTYHOG - tp->t_rawq.c_cc - 1;
len = (ch > 0) ? ch : 0;
stlen = MIN(stlen, len);
@ -2021,7 +2037,7 @@ static void stl_rxprocess(stlport_t *portp)
lostlen += b_to_q(tail, len, &tp->t_rawq);
tail += len;
}
portp->rxerrs[STL_RXLDLOST] += lostlen;
portp->stats.rxlost += lostlen;
ttwakeup(tp);
portp->rx.tail = tail;
}
@ -2198,7 +2214,7 @@ static int stl_param(struct tty *tp, struct termios *tiosp)
*/
if (tiosp->c_iflag & IXON) {
cor2 |= COR2_TXIBE;
cor3 |= (COR3_FCT | COR3_SCD12);
cor3 |= COR3_SCD12;
if (tiosp->c_iflag & IXANY)
cor2 |= COR2_IXM;
}
@ -2317,11 +2333,13 @@ static void stl_flowcontrol(stlport_t *portp, int hw, int sw)
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);
enable_intr();
@ -2368,9 +2386,10 @@ static void stl_setsignals(stlport_t *portp, int dtr, int rts)
* Get the state of the signals.
*/
static void stl_getsignals(stlport_t *portp)
static int stl_getsignals(stlport_t *portp)
{
unsigned char msvr1, msvr2;
int sigs;
#if DEBUG
printf("stl_getsignals(portp=%x)\n", (int) portp);
@ -2382,14 +2401,15 @@ static void stl_getsignals(stlport_t *portp)
msvr1 = stl_getreg(portp, MSVR1);
msvr2 = stl_getreg(portp, MSVR2);
BRDDISABLE(portp->brdnr);
portp->sigs = 0;
portp->sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
portp->sigs |= (msvr1 & MSVR1_CTS) ? TIOCM_CTS : 0;
portp->sigs |= (msvr1 & MSVR1_RI) ? TIOCM_RI : 0;
portp->sigs |= (msvr1 & MSVR1_DSR) ? TIOCM_DSR : 0;
portp->sigs |= (msvr1 & MSVR1_DTR) ? TIOCM_DTR : 0;
portp->sigs |= (msvr2 & MSVR2_RTS) ? TIOCM_RTS : 0;
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;
enable_intr();
return(sigs);
}
/*****************************************************************************/
@ -2505,6 +2525,7 @@ static void stl_sendbreak(stlport_t *portp, long len)
} else {
portp->brklen = len;
}
portp->stats.txbreaks++;
enable_intr();
}
@ -2625,6 +2646,7 @@ static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
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;
@ -2726,8 +2748,10 @@ static int stl_initeio(stlbrd_t *brdp)
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);
}
@ -2760,6 +2784,7 @@ static int stl_initech(stlbrd_t *brdp)
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)) {
@ -2780,6 +2805,7 @@ static int stl_initech(stlbrd_t *brdp)
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)) {
@ -2823,6 +2849,7 @@ static int stl_initech(stlbrd_t *brdp)
panelp->panelnr = panelnr;
panelp->iobase = ioaddr;
panelp->pagenr = nxtid;
panelp->hwid = status;
if (status & ECH_PNL16PORT) {
if ((brdp->nrports + 16) > 32)
break;
@ -2904,10 +2931,190 @@ static int stl_brdinit(stlbrd_t *brdp)
}
}
printf("stl(%d): %s (driver version %s) nrpanels=%d nrports=%d\n",
brdp->brdnr, stl_brdnames[brdp->brdtype], stl_drvversion,
brdp->nrpanels, brdp->nrports);
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)
{
int rc;
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, int cmd, caddr_t data, int flag, struct proc *p)
{
stlbrd_t *brdp;
int brdnr, rc;
#if DEBUG
printf("stl_memioctl(dev=%x,cmd=%x,data=%x,flag=%x)\n", (int) dev,
cmd, (int) data, flag);
#endif
brdnr = 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);
}
/*****************************************************************************/