summaryrefslogtreecommitdiffstats
path: root/drivers/char/rio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/rio')
-rw-r--r--drivers/char/rio/Makefile12
-rw-r--r--drivers/char/rio/board.h132
-rw-r--r--drivers/char/rio/cirrus.h210
-rw-r--r--drivers/char/rio/cmdblk.h53
-rw-r--r--drivers/char/rio/cmdpkt.h177
-rw-r--r--drivers/char/rio/daemon.h307
-rw-r--r--drivers/char/rio/errors.h98
-rw-r--r--drivers/char/rio/func.h143
-rw-r--r--drivers/char/rio/host.h123
-rw-r--r--drivers/char/rio/link.h96
-rw-r--r--drivers/char/rio/linux_compat.h77
-rw-r--r--drivers/char/rio/map.h98
-rw-r--r--drivers/char/rio/param.h55
-rw-r--r--drivers/char/rio/parmmap.h81
-rw-r--r--drivers/char/rio/pci.h72
-rw-r--r--drivers/char/rio/phb.h142
-rw-r--r--drivers/char/rio/pkt.h77
-rw-r--r--drivers/char/rio/port.h179
-rw-r--r--drivers/char/rio/protsts.h110
-rw-r--r--drivers/char/rio/rio.h208
-rw-r--r--drivers/char/rio/rio_linux.c1212
-rw-r--r--drivers/char/rio/rio_linux.h197
-rw-r--r--drivers/char/rio/rioboard.h275
-rw-r--r--drivers/char/rio/rioboot.c1113
-rw-r--r--drivers/char/rio/riocmd.c938
-rw-r--r--drivers/char/rio/rioctrl.c1503
-rw-r--r--drivers/char/rio/riodrvr.h138
-rw-r--r--drivers/char/rio/rioinfo.h92
-rw-r--r--drivers/char/rio/rioinit.c422
-rw-r--r--drivers/char/rio/riointr.c646
-rw-r--r--drivers/char/rio/rioioctl.h57
-rw-r--r--drivers/char/rio/rioparam.c664
-rw-r--r--drivers/char/rio/rioroute.c1040
-rw-r--r--drivers/char/rio/riospace.h154
-rw-r--r--drivers/char/rio/riotable.c941
-rw-r--r--drivers/char/rio/riotty.c654
-rw-r--r--drivers/char/rio/route.h101
-rw-r--r--drivers/char/rio/rup.h69
-rw-r--r--drivers/char/rio/unixrup.h51
39 files changed, 12717 insertions, 0 deletions
diff --git a/drivers/char/rio/Makefile b/drivers/char/rio/Makefile
new file mode 100644
index 0000000..2d1c5a7
--- /dev/null
+++ b/drivers/char/rio/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux rio-subsystem.
+#
+# (C) R.E.Wolff@BitWizard.nl
+#
+# This file is GPL. See other files for the full Blurb. I'm lazy today.
+#
+
+obj-$(CONFIG_RIO) += rio.o
+
+rio-objs := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
+ rioparam.o rioroute.o riotable.o riotty.o
diff --git a/drivers/char/rio/board.h b/drivers/char/rio/board.h
new file mode 100644
index 0000000..bdea633
--- /dev/null
+++ b/drivers/char/rio/board.h
@@ -0,0 +1,132 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : board.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:07
+** Retrieved : 11/6/98 11:34:20
+**
+** ident @(#)board.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_board_h__
+#define __rio_board_h__
+
+/*
+** board.h contains the definitions for the *hardware* of the host cards.
+** It describes the memory overlay for the dual port RAM area.
+*/
+
+#define DP_SRAM1_SIZE 0x7C00
+#define DP_SRAM2_SIZE 0x0200
+#define DP_SRAM3_SIZE 0x7000
+#define DP_SCRATCH_SIZE 0x1000
+#define DP_PARMMAP_ADDR 0x01FE /* offset into SRAM2 */
+#define DP_STARTUP_ADDR 0x01F8 /* offset into SRAM2 */
+
+/*
+** The shape of the Host Control area, at offset 0x7C00, Write Only
+*/
+struct s_Ctrl {
+ u8 DpCtl; /* 7C00 */
+ u8 Dp_Unused2_[127];
+ u8 DpIntSet; /* 7C80 */
+ u8 Dp_Unused3_[127];
+ u8 DpTpuReset; /* 7D00 */
+ u8 Dp_Unused4_[127];
+ u8 DpIntReset; /* 7D80 */
+ u8 Dp_Unused5_[127];
+};
+
+/*
+** The PROM data area on the host (0x7C00), Read Only
+*/
+struct s_Prom {
+ u16 DpSlxCode[2];
+ u16 DpRev;
+ u16 Dp_Unused6_;
+ u16 DpUniq[4];
+ u16 DpJahre;
+ u16 DpWoche;
+ u16 DpHwFeature[5];
+ u16 DpOemId;
+ u16 DpSiggy[16];
+};
+
+/*
+** Union of the Ctrl and Prom areas
+*/
+union u_CtrlProm { /* This is the control/PROM area (0x7C00) */
+ struct s_Ctrl DpCtrl;
+ struct s_Prom DpProm;
+};
+
+/*
+** The top end of memory!
+*/
+struct s_ParmMapS { /* Area containing Parm Map Pointer */
+ u8 Dp_Unused8_[DP_PARMMAP_ADDR];
+ u16 DpParmMapAd;
+};
+
+struct s_StartUpS {
+ u8 Dp_Unused9_[DP_STARTUP_ADDR];
+ u8 Dp_LongJump[0x4];
+ u8 Dp_Unused10_[2];
+ u8 Dp_ShortJump[0x2];
+};
+
+union u_Sram2ParmMap { /* This is the top of memory (0x7E00-0x7FFF) */
+ u8 DpSramMem[DP_SRAM2_SIZE];
+ struct s_ParmMapS DpParmMapS;
+ struct s_StartUpS DpStartUpS;
+};
+
+/*
+** This is the DP RAM overlay.
+*/
+struct DpRam {
+ u8 DpSram1[DP_SRAM1_SIZE]; /* 0000 - 7BFF */
+ union u_CtrlProm DpCtrlProm; /* 7C00 - 7DFF */
+ union u_Sram2ParmMap DpSram2ParmMap; /* 7E00 - 7FFF */
+ u8 DpScratch[DP_SCRATCH_SIZE]; /* 8000 - 8FFF */
+ u8 DpSram3[DP_SRAM3_SIZE]; /* 9000 - FFFF */
+};
+
+#define DpControl DpCtrlProm.DpCtrl.DpCtl
+#define DpSetInt DpCtrlProm.DpCtrl.DpIntSet
+#define DpResetTpu DpCtrlProm.DpCtrl.DpTpuReset
+#define DpResetInt DpCtrlProm.DpCtrl.DpIntReset
+
+#define DpSlx DpCtrlProm.DpProm.DpSlxCode
+#define DpRevision DpCtrlProm.DpProm.DpRev
+#define DpUnique DpCtrlProm.DpProm.DpUniq
+#define DpYear DpCtrlProm.DpProm.DpJahre
+#define DpWeek DpCtrlProm.DpProm.DpWoche
+#define DpSignature DpCtrlProm.DpProm.DpSiggy
+
+#define DpParmMapR DpSram2ParmMap.DpParmMapS.DpParmMapAd
+#define DpSram2 DpSram2ParmMap.DpSramMem
+
+#endif
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
new file mode 100644
index 0000000..5ab5167
--- /dev/null
+++ b/drivers/char/rio/cirrus.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+ ******* *******
+ ******* CIRRUS.H *******
+ ******* *******
+ ****************************************************************************
+
+ Author : Jeremy Rolls
+ Date : 3 Aug 1990
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _cirrus_h
+#define _cirrus_h 1
+
+/* Bit fields for particular registers shared with driver */
+
+/* COR1 - driver and RTA */
+#define RIOC_COR1_ODD 0x80 /* Odd parity */
+#define RIOC_COR1_EVEN 0x00 /* Even parity */
+#define RIOC_COR1_NOP 0x00 /* No parity */
+#define RIOC_COR1_FORCE 0x20 /* Force parity */
+#define RIOC_COR1_NORMAL 0x40 /* With parity */
+#define RIOC_COR1_1STOP 0x00 /* 1 stop bit */
+#define RIOC_COR1_15STOP 0x04 /* 1.5 stop bits */
+#define RIOC_COR1_2STOP 0x08 /* 2 stop bits */
+#define RIOC_COR1_5BITS 0x00 /* 5 data bits */
+#define RIOC_COR1_6BITS 0x01 /* 6 data bits */
+#define RIOC_COR1_7BITS 0x02 /* 7 data bits */
+#define RIOC_COR1_8BITS 0x03 /* 8 data bits */
+
+#define RIOC_COR1_HOST 0xef /* Safe host bits */
+
+/* RTA only */
+#define RIOC_COR1_CINPCK 0x00 /* Check parity of received characters */
+#define RIOC_COR1_CNINPCK 0x10 /* Don't check parity */
+
+/* COR2 bits for both RTA and driver use */
+#define RIOC_COR2_IXANY 0x80 /* IXANY - any character is XON */
+#define RIOC_COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
+#define RIOC_COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
+
+/* Additional driver bits */
+#define RIOC_COR2_HUPCL 0x20 /* Hang up on close */
+#define RIOC_COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
+#define RIOC_COR2_IXOFF 0x01 /* Enable rx software flow control */
+#define RIOC_COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
+
+/* RTA use only */
+#define RIOC_COR2_ETC 0x20 /* Embedded transmit options */
+#define RIOC_COR2_LOCAL 0x10 /* Local loopback mode */
+#define RIOC_COR2_REMOTE 0x08 /* Remote loopback mode */
+#define RIOC_COR2_HOST 0xc2 /* Safe host bits */
+
+/* COR3 - RTA use only */
+#define RIOC_COR3_SCDRNG 0x80 /* Enable special char detect for range */
+#define RIOC_COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
+#define RIOC_COR3_FCT 0x20 /* Flow control transparency */
+#define RIOC_COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
+#define RIOC_COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
+
+#define RIOC_COR3_THRESHOLD RIOC_COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
+
+#define RIOC_COR3_DEFAULT (RIOC_COR3_FCT | RIOC_COR3_THRESHOLD)
+ /* Default bits for COR3 */
+
+/* COR4 driver and RTA use */
+#define RIOC_COR4_IGNCR 0x80 /* Throw away CR's on input */
+#define RIOC_COR4_ICRNL 0x40 /* Map CR -> NL on input */
+#define RIOC_COR4_INLCR 0x20 /* Map NL -> CR on input */
+#define RIOC_COR4_IGNBRK 0x10 /* Ignore Break */
+#define RIOC_COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
+#define RIOC_COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
+
+
+/* COR4 driver only */
+#define RIOC_COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
+#define RIOC_COR4_PARMRK 0x02 /* PARMRK */
+
+#define RIOC_COR4_HOST 0xf8 /* Safe host bits */
+
+/* COR4 RTA only */
+#define RIOC_COR4_CIGNPAR 0x02 /* Thrown away bad characters */
+#define RIOC_COR4_CPARMRK 0x04 /* PARMRK characters */
+#define RIOC_COR4_CNPARMRK 0x03 /* Don't PARMRK */
+
+/* COR5 driver and RTA use */
+#define RIOC_COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
+#define RIOC_COR5_LNE 0x40 /* Enable LNEXT processing */
+#define RIOC_COR5_CMOE 0x20 /* Match good and errored characters */
+#define RIOC_COR5_ONLCR 0x02 /* NL -> CR NL on output */
+#define RIOC_COR5_OCRNL 0x01 /* CR -> NL on output */
+
+/*
+** Spare bits - these are not used in the CIRRUS registers, so we use
+** them to set various other features.
+*/
+/*
+** tstop and tbusy indication
+*/
+#define RIOC_COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
+/*
+** TAB3
+*/
+#define RIOC_COR5_TAB3 0x10 /* TAB3 mode */
+
+#define RIOC_COR5_HOST 0xc3 /* Safe host bits */
+
+/* CCSR */
+#define RIOC_CCSR_TXFLOFF 0x04 /* Tx is xoffed */
+
+/* MSVR1 */
+/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
+ RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
+ serial option.
+*/
+#define RIOC_MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
+#define RIOC_MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
+#define RIOC_MSVR1_RI 0x20 /* RI */
+#define RIOC_MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
+#define RIOC_MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
+/* Next two used to indicate state of tbusy and tstop to driver */
+#define RIOC_MSVR1_TSTOP 0x08 /* Set if port flow controlled */
+#define RIOC_MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
+
+#define RIOC_MSVR1_HOST 0xf3 /* The bits the host wants */
+
+/* Defines for the subscripts of a CONFIG packet */
+#define RIOC_CONFIG_COR1 1 /* Option register 1 */
+#define RIOC_CONFIG_COR2 2 /* Option register 2 */
+#define RIOC_CONFIG_COR4 3 /* Option register 4 */
+#define RIOC_CONFIG_COR5 4 /* Option register 5 */
+#define RIOC_CONFIG_TXXON 5 /* Tx XON character */
+#define RIOC_CONFIG_TXXOFF 6 /* Tx XOFF character */
+#define RIOC_CONFIG_RXXON 7 /* Rx XON character */
+#define RIOC_CONFIG_RXXOFF 8 /* Rx XOFF character */
+#define RIOC_CONFIG_LNEXT 9 /* LNEXT character */
+#define RIOC_CONFIG_TXBAUD 10 /* Tx baud rate */
+#define RIOC_CONFIG_RXBAUD 11 /* Rx baud rate */
+
+#define RIOC_PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
+
+/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
+ CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
+ be used
+*/
+#define RIOC_OPEN 0x00 /* Open a port */
+#define RIOC_CONFIG 0x01 /* Configure a port */
+#define RIOC_MOPEN 0x02 /* Modem open (block for DCD) */
+#define RIOC_CLOSE 0x03 /* Close a port */
+#define RIOC_WFLUSH (0x04 | RIOC_PRE_EMPTIVE) /* Write flush */
+#define RIOC_RFLUSH (0x05 | RIOC_PRE_EMPTIVE) /* Read flush */
+#define RIOC_RESUME (0x06 | RIOC_PRE_EMPTIVE) /* Resume if xoffed */
+#define RIOC_SBREAK 0x07 /* Start break */
+#define RIOC_EBREAK 0x08 /* End break */
+#define RIOC_SUSPEND (0x09 | RIOC_PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
+#define RIOC_FCLOSE (0x0a | RIOC_PRE_EMPTIVE) /* Force close */
+#define RIOC_XPRINT 0x0b /* Xprint packet */
+#define RIOC_MBIS (0x0c | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_MBIC (0x0d | RIOC_PRE_EMPTIVE) /* Clear modem lines */
+#define RIOC_MSET (0x0e | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
+#define RIOC_MGET (0x10 | RIOC_PRE_EMPTIVE) /* Force update of modem status */
+#define RIOC_MEMDUMP (0x11 | RIOC_PRE_EMPTIVE) /* Send back mem from addr supplied */
+#define RIOC_READ_REGISTER (0x12 | RIOC_PRE_EMPTIVE) /* Read CD1400 register (debug) */
+
+/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
+ use data[4] / data[3] to indicate current state and modem status respectively
+*/
+
+#define RIOC_COMPLETE (0x20 | RIOC_PRE_EMPTIVE)
+ /* Command complete */
+#define RIOC_BREAK_RECEIVED (0x21 | RIOC_PRE_EMPTIVE)
+ /* Break received */
+#define RIOC_MODEM_STATUS (0x22 | RIOC_PRE_EMPTIVE)
+ /* Change in modem status */
+
+/* "Command" packet that could go either way - handshake wake-up */
+#define RIOC_HANDSHAKE (0x23 | RIOC_PRE_EMPTIVE)
+ /* Wake-up to HOST / RTA */
+
+#endif
diff --git a/drivers/char/rio/cmdblk.h b/drivers/char/rio/cmdblk.h
new file mode 100644
index 0000000..9ed4f86
--- /dev/null
+++ b/drivers/char/rio/cmdblk.h
@@ -0,0 +1,53 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : cmdblk.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:09
+** Retrieved : 11/6/98 11:34:20
+**
+** ident @(#)cmdblk.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_cmdblk_h__
+#define __rio_cmdblk_h__
+
+/*
+** the structure of a command block, used to queue commands destined for
+** a rup.
+*/
+
+struct CmdBlk {
+ struct CmdBlk *NextP; /* Pointer to next command block */
+ struct PKT Packet; /* A packet, to copy to the rup */
+ /* The func to call to check if OK */
+ int (*PreFuncP) (unsigned long, struct CmdBlk *);
+ int PreArg; /* The arg for the func */
+ /* The func to call when completed */
+ int (*PostFuncP) (unsigned long, struct CmdBlk *);
+ int PostArg; /* The arg for the func */
+};
+
+#define NUM_RIO_CMD_BLKS (3 * (MAX_RUP * 4 + LINKS_PER_UNIT * 4))
+#endif
diff --git a/drivers/char/rio/cmdpkt.h b/drivers/char/rio/cmdpkt.h
new file mode 100644
index 0000000..c1e7a27
--- /dev/null
+++ b/drivers/char/rio/cmdpkt.h
@@ -0,0 +1,177 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : cmdpkt.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:09
+** Retrieved : 11/6/98 11:34:20
+**
+** ident @(#)cmdpkt.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifndef __rio_cmdpkt_h__
+#define __rio_cmdpkt_h__
+
+/*
+** overlays for the data area of a packet. Used in both directions
+** (to build a packet to send, and to interpret a packet that arrives)
+** and is very inconvenient for MIPS, so they appear as two separate
+** structures - those used for modifying/reading packets on the card
+** and those for modifying/reading packets in real memory, which have an _M
+** suffix.
+*/
+
+#define RTA_BOOT_DATA_SIZE (PKT_MAX_DATA_LEN-2)
+
+/*
+** The boot information packet looks like this:
+** This structure overlays a PktCmd->CmdData structure, and so starts
+** at Data[2] in the actual pkt!
+*/
+struct BootSequence {
+ u16 NumPackets;
+ u16 LoadBase;
+ u16 CodeSize;
+};
+
+#define BOOT_SEQUENCE_LEN 8
+
+struct SamTop {
+ u8 Unit;
+ u8 Link;
+};
+
+struct CmdHdr {
+ u8 PcCommand;
+ union {
+ u8 PcPhbNum;
+ u8 PcLinkNum;
+ u8 PcIDNum;
+ } U0;
+};
+
+
+struct PktCmd {
+ union {
+ struct {
+ struct CmdHdr CmdHdr;
+ struct BootSequence PcBootSequence;
+ } S1;
+ struct {
+ u16 PcSequence;
+ u8 PcBootData[RTA_BOOT_DATA_SIZE];
+ } S2;
+ struct {
+ u16 __crud__;
+ u8 PcUniqNum[4]; /* this is really a uint. */
+ u8 PcModuleTypes; /* what modules are fitted */
+ } S3;
+ struct {
+ struct CmdHdr CmdHdr;
+ u8 __undefined__;
+ u8 PcModemStatus;
+ u8 PcPortStatus;
+ u8 PcSubCommand; /* commands like mem or register dump */
+ u16 PcSubAddr; /* Address for command */
+ u8 PcSubData[64]; /* Date area for command */
+ } S4;
+ struct {
+ struct CmdHdr CmdHdr;
+ u8 PcCommandText[1];
+ u8 __crud__[20];
+ u8 PcIDNum2; /* It had to go somewhere! */
+ } S5;
+ struct {
+ struct CmdHdr CmdHdr;
+ struct SamTop Topology[LINKS_PER_UNIT];
+ } S6;
+ } U1;
+};
+
+struct PktCmd_M {
+ union {
+ struct {
+ struct {
+ u8 PcCommand;
+ union {
+ u8 PcPhbNum;
+ u8 PcLinkNum;
+ u8 PcIDNum;
+ } U0;
+ } CmdHdr;
+ struct {
+ u16 NumPackets;
+ u16 LoadBase;
+ u16 CodeSize;
+ } PcBootSequence;
+ } S1;
+ struct {
+ u16 PcSequence;
+ u8 PcBootData[RTA_BOOT_DATA_SIZE];
+ } S2;
+ struct {
+ u16 __crud__;
+ u8 PcUniqNum[4]; /* this is really a uint. */
+ u8 PcModuleTypes; /* what modules are fitted */
+ } S3;
+ struct {
+ u16 __cmd_hdr__;
+ u8 __undefined__;
+ u8 PcModemStatus;
+ u8 PcPortStatus;
+ u8 PcSubCommand;
+ u16 PcSubAddr;
+ u8 PcSubData[64];
+ } S4;
+ struct {
+ u16 __cmd_hdr__;
+ u8 PcCommandText[1];
+ u8 __crud__[20];
+ u8 PcIDNum2; /* Tacked on end */
+ } S5;
+ struct {
+ u16 __cmd_hdr__;
+ struct Top Topology[LINKS_PER_UNIT];
+ } S6;
+ } U1;
+};
+
+#define Command U1.S1.CmdHdr.PcCommand
+#define PhbNum U1.S1.CmdHdr.U0.PcPhbNum
+#define IDNum U1.S1.CmdHdr.U0.PcIDNum
+#define IDNum2 U1.S5.PcIDNum2
+#define LinkNum U1.S1.CmdHdr.U0.PcLinkNum
+#define Sequence U1.S2.PcSequence
+#define BootData U1.S2.PcBootData
+#define BootSequence U1.S1.PcBootSequence
+#define UniqNum U1.S3.PcUniqNum
+#define ModemStatus U1.S4.PcModemStatus
+#define PortStatus U1.S4.PcPortStatus
+#define SubCommand U1.S4.PcSubCommand
+#define SubAddr U1.S4.PcSubAddr
+#define SubData U1.S4.PcSubData
+#define CommandText U1.S5.PcCommandText
+#define RouteTopology U1.S6.Topology
+#define ModuleTypes U1.S3.PcModuleTypes
+
+#endif
diff --git a/drivers/char/rio/daemon.h b/drivers/char/rio/daemon.h
new file mode 100644
index 0000000..4af9032
--- /dev/null
+++ b/drivers/char/rio/daemon.h
@@ -0,0 +1,307 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : daemon.h
+** SID : 1.3
+** Last Modified : 11/6/98 11:34:09
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)daemon.h 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_daemon_h__
+#define __rio_daemon_h__
+
+
+/*
+** structures used on /dev/rio
+*/
+
+struct Error {
+ unsigned int Error;
+ unsigned int Entry;
+ unsigned int Other;
+};
+
+struct DownLoad {
+ char __user *DataP;
+ unsigned int Count;
+ unsigned int ProductCode;
+};
+
+/*
+** A few constants....
+*/
+#ifndef MAX_VERSION_LEN
+#define MAX_VERSION_LEN 256
+#endif
+
+#ifndef MAX_XP_CTRL_LEN
+#define MAX_XP_CTRL_LEN 16 /* ALSO IN PORT.H */
+#endif
+
+struct PortSetup {
+ unsigned int From; /* Set/Clear XP & IXANY Control from this port.... */
+ unsigned int To; /* .... to this port */
+ unsigned int XpCps; /* at this speed */
+ char XpOn[MAX_XP_CTRL_LEN]; /* this is the start string */
+ char XpOff[MAX_XP_CTRL_LEN]; /* this is the stop string */
+ u8 IxAny; /* enable/disable IXANY */
+ u8 IxOn; /* enable/disable IXON */
+ u8 Lock; /* lock port params */
+ u8 Store; /* store params across closes */
+ u8 Drain; /* close only when drained */
+};
+
+struct LpbReq {
+ unsigned int Host;
+ unsigned int Link;
+ struct LPB __user *LpbP;
+};
+
+struct RupReq {
+ unsigned int HostNum;
+ unsigned int RupNum;
+ struct RUP __user *RupP;
+};
+
+struct PortReq {
+ unsigned int SysPort;
+ struct Port __user *PortP;
+};
+
+struct StreamInfo {
+ unsigned int SysPort;
+ int RQueue;
+ int WQueue;
+};
+
+struct HostReq {
+ unsigned int HostNum;
+ struct Host __user *HostP;
+};
+
+struct HostDpRam {
+ unsigned int HostNum;
+ struct DpRam __user *DpRamP;
+};
+
+struct DebugCtrl {
+ unsigned int SysPort;
+ unsigned int Debug;
+ unsigned int Wait;
+};
+
+struct MapInfo {
+ unsigned int FirstPort; /* 8 ports, starting from this (tty) number */
+ unsigned int RtaUnique; /* reside on this RTA (unique number) */
+};
+
+struct MapIn {
+ unsigned int NumEntries; /* How many port sets are we mapping? */
+ struct MapInfo *MapInfoP; /* Pointer to (user space) info */
+};
+
+struct SendPack {
+ unsigned int PortNum;
+ unsigned char Len;
+ unsigned char Data[PKT_MAX_DATA_LEN];
+};
+
+struct SpecialRupCmd {
+ struct PKT Packet;
+ unsigned short Host;
+ unsigned short RupNum;
+};
+
+struct IdentifyRta {
+ unsigned long RtaUnique;
+ u8 ID;
+};
+
+struct KillNeighbour {
+ unsigned long UniqueNum;
+ u8 Link;
+};
+
+struct rioVersion {
+ char version[MAX_VERSION_LEN];
+ char relid[MAX_VERSION_LEN];
+ int buildLevel;
+ char buildDate[MAX_VERSION_LEN];
+};
+
+
+/*
+** RIOC commands are for the daemon type operations
+**
+** 09.12.1998 ARG - ESIL 0776 part fix
+** Definition for 'RIOC' also appears in rioioctl.h, so we'd better do a
+** #ifndef here first.
+** rioioctl.h also now has #define 'RIO_QUICK_CHECK' as this ioctl is now
+** allowed to be used by customers.
+*/
+#ifndef RIOC
+#define RIOC ('R'<<8)|('i'<<16)|('o'<<24)
+#endif
+
+/*
+** Boot stuff
+*/
+#define RIO_GET_TABLE (RIOC | 100)
+#define RIO_PUT_TABLE (RIOC | 101)
+#define RIO_ASSIGN_RTA (RIOC | 102)
+#define RIO_DELETE_RTA (RIOC | 103)
+#define RIO_HOST_FOAD (RIOC | 104)
+#define RIO_QUICK_CHECK (RIOC | 105)
+#define RIO_SIGNALS_ON (RIOC | 106)
+#define RIO_SIGNALS_OFF (RIOC | 107)
+#define RIO_CHANGE_NAME (RIOC | 108)
+#define RIO_DOWNLOAD (RIOC | 109)
+#define RIO_GET_LOG (RIOC | 110)
+#define RIO_SETUP_PORTS (RIOC | 111)
+#define RIO_ALL_MODEM (RIOC | 112)
+
+/*
+** card state, debug stuff
+*/
+#define RIO_NUM_HOSTS (RIOC | 120)
+#define RIO_HOST_LPB (RIOC | 121)
+#define RIO_HOST_RUP (RIOC | 122)
+#define RIO_HOST_PORT (RIOC | 123)
+#define RIO_PARMS (RIOC | 124)
+#define RIO_HOST_REQ (RIOC | 125)
+#define RIO_READ_CONFIG (RIOC | 126)
+#define RIO_SET_CONFIG (RIOC | 127)
+#define RIO_VERSID (RIOC | 128)
+#define RIO_FLAGS (RIOC | 129)
+#define RIO_SETDEBUG (RIOC | 130)
+#define RIO_GETDEBUG (RIOC | 131)
+#define RIO_READ_LEVELS (RIOC | 132)
+#define RIO_SET_FAST_BUS (RIOC | 133)
+#define RIO_SET_SLOW_BUS (RIOC | 134)
+#define RIO_SET_BYTE_MODE (RIOC | 135)
+#define RIO_SET_WORD_MODE (RIOC | 136)
+#define RIO_STREAM_INFO (RIOC | 137)
+#define RIO_START_POLLER (RIOC | 138)
+#define RIO_STOP_POLLER (RIOC | 139)
+#define RIO_LAST_ERROR (RIOC | 140)
+#define RIO_TICK (RIOC | 141)
+#define RIO_TOCK (RIOC | 241) /* I did this on purpose, you know. */
+#define RIO_SEND_PACKET (RIOC | 142)
+#define RIO_SET_BUSY (RIOC | 143)
+#define SPECIAL_RUP_CMD (RIOC | 144)
+#define RIO_FOAD_RTA (RIOC | 145)
+#define RIO_ZOMBIE_RTA (RIOC | 146)
+#define RIO_IDENTIFY_RTA (RIOC | 147)
+#define RIO_KILL_NEIGHBOUR (RIOC | 148)
+#define RIO_DEBUG_MEM (RIOC | 149)
+/*
+** 150 - 167 used..... See below
+*/
+#define RIO_GET_PORT_SETUP (RIOC | 168)
+#define RIO_RESUME (RIOC | 169)
+#define RIO_MESG (RIOC | 170)
+#define RIO_NO_MESG (RIOC | 171)
+#define RIO_WHAT_MESG (RIOC | 172)
+#define RIO_HOST_DPRAM (RIOC | 173)
+#define RIO_MAP_B50_TO_50 (RIOC | 174)
+#define RIO_MAP_B50_TO_57600 (RIOC | 175)
+#define RIO_MAP_B110_TO_110 (RIOC | 176)
+#define RIO_MAP_B110_TO_115200 (RIOC | 177)
+#define RIO_GET_PORT_PARAMS (RIOC | 178)
+#define RIO_SET_PORT_PARAMS (RIOC | 179)
+#define RIO_GET_PORT_TTY (RIOC | 180)
+#define RIO_SET_PORT_TTY (RIOC | 181)
+#define RIO_SYSLOG_ONLY (RIOC | 182)
+#define RIO_SYSLOG_CONS (RIOC | 183)
+#define RIO_CONS_ONLY (RIOC | 184)
+#define RIO_BLOCK_OPENS (RIOC | 185)
+
+/*
+** 02.03.1999 ARG - ESIL 0820 fix :
+** RIOBootMode is no longer use by the driver, so these ioctls
+** are now obsolete :
+**
+#define RIO_GET_BOOT_MODE (RIOC | 186)
+#define RIO_SET_BOOT_MODE (RIOC | 187)
+**
+*/
+
+#define RIO_MEM_DUMP (RIOC | 189)
+#define RIO_READ_REGISTER (RIOC | 190)
+#define RIO_GET_MODTYPE (RIOC | 191)
+#define RIO_SET_TIMER (RIOC | 192)
+#define RIO_READ_CHECK (RIOC | 196)
+#define RIO_WAITING_FOR_RESTART (RIOC | 197)
+#define RIO_BIND_RTA (RIOC | 198)
+#define RIO_GET_BINDINGS (RIOC | 199)
+#define RIO_PUT_BINDINGS (RIOC | 200)
+
+#define RIO_MAKE_DEV (RIOC | 201)
+#define RIO_MINOR (RIOC | 202)
+
+#define RIO_IDENTIFY_DRIVER (RIOC | 203)
+#define RIO_DISPLAY_HOST_CFG (RIOC | 204)
+
+
+/*
+** MAKE_DEV / MINOR stuff
+*/
+#define RIO_DEV_DIRECT 0x0000
+#define RIO_DEV_MODEM 0x0200
+#define RIO_DEV_XPRINT 0x0400
+#define RIO_DEV_MASK 0x0600
+
+/*
+** port management, xprint stuff
+*/
+#define rIOCN(N) (RIOC|(N))
+#define rIOCR(N,T) (RIOC|(N))
+#define rIOCW(N,T) (RIOC|(N))
+
+#define RIO_GET_XP_ON rIOCR(150,char[16]) /* start xprint string */
+#define RIO_SET_XP_ON rIOCW(151,char[16])
+#define RIO_GET_XP_OFF rIOCR(152,char[16]) /* finish xprint string */
+#define RIO_SET_XP_OFF rIOCW(153,char[16])
+#define RIO_GET_XP_CPS rIOCR(154,int) /* xprint CPS */
+#define RIO_SET_XP_CPS rIOCW(155,int)
+#define RIO_GET_IXANY rIOCR(156,int) /* ixany allowed? */
+#define RIO_SET_IXANY rIOCW(157,int)
+#define RIO_SET_IXANY_ON rIOCN(158) /* allow ixany */
+#define RIO_SET_IXANY_OFF rIOCN(159) /* disallow ixany */
+#define RIO_GET_MODEM rIOCR(160,int) /* port is modem/direct line? */
+#define RIO_SET_MODEM rIOCW(161,int)
+#define RIO_SET_MODEM_ON rIOCN(162) /* port is a modem */
+#define RIO_SET_MODEM_OFF rIOCN(163) /* port is direct */
+#define RIO_GET_IXON rIOCR(164,int) /* ixon allowed? */
+#define RIO_SET_IXON rIOCW(165,int)
+#define RIO_SET_IXON_ON rIOCN(166) /* allow ixon */
+#define RIO_SET_IXON_OFF rIOCN(167) /* disallow ixon */
+
+#define RIO_GET_SIVIEW ((('s')<<8) | 106) /* backwards compatible with SI */
+
+#define RIO_IOCTL_UNKNOWN -2
+
+#endif
diff --git a/drivers/char/rio/errors.h b/drivers/char/rio/errors.h
new file mode 100644
index 0000000..bdb0523
--- /dev/null
+++ b/drivers/char/rio/errors.h
@@ -0,0 +1,98 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : errors.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:10
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)errors.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_errors_h__
+#define __rio_errors_h__
+
+/*
+** error codes
+*/
+
+#define NOTHING_WRONG_AT_ALL 0
+#define BAD_CHARACTER_IN_NAME 1
+#define TABLE_ENTRY_ISNT_PROPERLY_NULL 2
+#define UNKNOWN_HOST_NUMBER 3
+#define ZERO_RTA_ID 4
+#define BAD_RTA_ID 5
+#define DUPLICATED_RTA_ID 6
+#define DUPLICATE_UNIQUE_NUMBER 7
+#define BAD_TTY_NUMBER 8
+#define TTY_NUMBER_IN_USE 9
+#define NAME_USED_TWICE 10
+#define HOST_ID_NOT_ZERO 11
+#define BOOT_IN_PROGRESS 12
+#define COPYIN_FAILED 13
+#define HOST_FILE_TOO_LARGE 14
+#define COPYOUT_FAILED 15
+#define NOT_SUPER_USER 16
+#define RIO_ALREADY_POLLING 17
+
+#define ID_NUMBER_OUT_OF_RANGE 18
+#define PORT_NUMBER_OUT_OF_RANGE 19
+#define HOST_NUMBER_OUT_OF_RANGE 20
+#define RUP_NUMBER_OUT_OF_RANGE 21
+#define TTY_NUMBER_OUT_OF_RANGE 22
+#define LINK_NUMBER_OUT_OF_RANGE 23
+
+#define HOST_NOT_RUNNING 24
+#define IOCTL_COMMAND_UNKNOWN 25
+#define RIO_SYSTEM_HALTED 26
+#define WAIT_FOR_DRAIN_BROKEN 27
+#define PORT_NOT_MAPPED_INTO_SYSTEM 28
+#define EXCLUSIVE_USE_SET 29
+#define WAIT_FOR_NOT_CLOSING_BROKEN 30
+#define WAIT_FOR_PORT_TO_OPEN_BROKEN 31
+#define WAIT_FOR_CARRIER_BROKEN 32
+#define WAIT_FOR_NOT_IN_USE_BROKEN 33
+#define WAIT_FOR_CAN_ADD_COMMAND_BROKEN 34
+#define WAIT_FOR_ADD_COMMAND_BROKEN 35
+#define WAIT_FOR_NOT_PARAM_BROKEN 36
+#define WAIT_FOR_RETRY_BROKEN 37
+#define HOST_HAS_ALREADY_BEEN_BOOTED 38
+#define UNIT_IS_IN_USE 39
+#define COULDNT_FIND_ENTRY 40
+#define RTA_UNIQUE_NUMBER_ZERO 41
+#define CLOSE_COMMAND_FAILED 42
+#define WAIT_FOR_CLOSE_BROKEN 43
+#define CPS_VALUE_OUT_OF_RANGE 44
+#define ID_ALREADY_IN_USE 45
+#define SIGNALS_ALREADY_SET 46
+#define NOT_RECEIVING_PROCESS 47
+#define RTA_NUMBER_WRONG 48
+#define NO_SUCH_PRODUCT 49
+#define HOST_SYSPORT_BAD 50
+#define ID_NOT_TENTATIVE 51
+#define XPRINT_CPS_OUT_OF_RANGE 52
+#define NOT_ENOUGH_CORE_FOR_PCI_COPY 53
+
+
+#endif /* __rio_errors_h__ */
diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h
new file mode 100644
index 0000000..078d44f
--- /dev/null
+++ b/drivers/char/rio/func.h
@@ -0,0 +1,143 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : func.h
+** SID : 1.3
+** Last Modified : 11/6/98 11:34:10
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)func.h 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __func_h_def
+#define __func_h_def
+
+#include <linux/kdev_t.h>
+
+/* rioboot.c */
+int RIOBootCodeRTA(struct rio_info *, struct DownLoad *);
+int RIOBootCodeHOST(struct rio_info *, struct DownLoad *);
+int RIOBootCodeUNKNOWN(struct rio_info *, struct DownLoad *);
+void msec_timeout(struct Host *);
+int RIOBootRup(struct rio_info *, unsigned int, struct Host *, struct PKT __iomem *);
+int RIOBootOk(struct rio_info *, struct Host *, unsigned long);
+int RIORtaBound(struct rio_info *, unsigned int);
+void rio_fill_host_slot(int, int, unsigned int, struct Host *);
+
+/* riocmd.c */
+int RIOFoadRta(struct Host *, struct Map *);
+int RIOZombieRta(struct Host *, struct Map *);
+int RIOCommandRta(struct rio_info *, unsigned long, int (*func) (struct Host *, struct Map *));
+int RIOIdentifyRta(struct rio_info *, void __user *);
+int RIOKillNeighbour(struct rio_info *, void __user *);
+int RIOSuspendBootRta(struct Host *, int, int);
+int RIOFoadWakeup(struct rio_info *);
+struct CmdBlk *RIOGetCmdBlk(void);
+void RIOFreeCmdBlk(struct CmdBlk *);
+int RIOQueueCmdBlk(struct Host *, unsigned int, struct CmdBlk *);
+void RIOPollHostCommands(struct rio_info *, struct Host *);
+int RIOWFlushMark(unsigned long, struct CmdBlk *);
+int RIORFlushEnable(unsigned long, struct CmdBlk *);
+int RIOUnUse(unsigned long, struct CmdBlk *);
+
+/* rioctrl.c */
+int riocontrol(struct rio_info *, dev_t, int, unsigned long, int);
+
+int RIOPreemptiveCmd(struct rio_info *, struct Port *, unsigned char);
+
+/* rioinit.c */
+void rioinit(struct rio_info *, struct RioHostInfo *);
+void RIOInitHosts(struct rio_info *, struct RioHostInfo *);
+void RIOISAinit(struct rio_info *, int);
+int RIODoAT(struct rio_info *, int, int);
+caddr_t RIOCheckForATCard(int);
+int RIOAssignAT(struct rio_info *, int, void __iomem *, int);
+int RIOBoardTest(unsigned long, void __iomem *, unsigned char, int);
+void RIOAllocDataStructs(struct rio_info *);
+void RIOSetupDataStructs(struct rio_info *);
+int RIODefaultName(struct rio_info *, struct Host *, unsigned int);
+struct rioVersion *RIOVersid(void);
+void RIOHostReset(unsigned int, struct DpRam __iomem *, unsigned int);
+
+/* riointr.c */
+void RIOTxEnable(char *);
+void RIOServiceHost(struct rio_info *, struct Host *);
+int riotproc(struct rio_info *, struct ttystatics *, int, int);
+
+/* rioparam.c */
+int RIOParam(struct Port *, int, int, int);
+int RIODelay(struct Port *PortP, int);
+int RIODelay_ni(struct Port *PortP, int);
+void ms_timeout(struct Port *);
+int can_add_transmit(struct PKT __iomem **, struct Port *);
+void add_transmit(struct Port *);
+void put_free_end(struct Host *, struct PKT __iomem *);
+int can_remove_receive(struct PKT __iomem **, struct Port *);
+void remove_receive(struct Port *);
+
+/* rioroute.c */
+int RIORouteRup(struct rio_info *, unsigned int, struct Host *, struct PKT __iomem *);
+void RIOFixPhbs(struct rio_info *, struct Host *, unsigned int);
+unsigned int GetUnitType(unsigned int);
+int RIOSetChange(struct rio_info *);
+int RIOFindFreeID(struct rio_info *, struct Host *, unsigned int *, unsigned int *);
+
+
+/* riotty.c */
+
+int riotopen(struct tty_struct *tty, struct file *filp);
+int riotclose(void *ptr);
+int riotioctl(struct rio_info *, struct tty_struct *, int, caddr_t);
+void ttyseth(struct Port *, struct ttystatics *, struct old_sgttyb *sg);
+
+/* riotable.c */
+int RIONewTable(struct rio_info *);
+int RIOApel(struct rio_info *);
+int RIODeleteRta(struct rio_info *, struct Map *);
+int RIOAssignRta(struct rio_info *, struct Map *);
+int RIOReMapPorts(struct rio_info *, struct Host *, struct Map *);
+int RIOChangeName(struct rio_info *, struct Map *);
+
+#if 0
+/* riodrvr.c */
+struct rio_info *rio_install(struct RioHostInfo *);
+int rio_uninstall(struct rio_info *);
+int rio_open(struct rio_info *, int, struct file *);
+int rio_close(struct rio_info *, struct file *);
+int rio_read(struct rio_info *, struct file *, char *, int);
+int rio_write(struct rio_info *, struct file *f, char *, int);
+int rio_ioctl(struct rio_info *, struct file *, int, char *);
+int rio_select(struct rio_info *, struct file *f, int, struct sel *);
+int rio_intr(char *);
+int rio_isr_thread(char *);
+struct rio_info *rio_info_store(int cmd, struct rio_info *p);
+#endif
+
+extern void rio_copy_to_card(void *from, void __iomem *to, int len);
+extern int rio_minor(struct tty_struct *tty);
+extern int rio_ismodem(struct tty_struct *tty);
+
+extern void rio_start_card_running(struct Host *HostP);
+
+#endif /* __func_h_def */
diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h
new file mode 100644
index 0000000..78f2454
--- /dev/null
+++ b/drivers/char/rio/host.h
@@ -0,0 +1,123 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : host.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:10
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)host.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_host_h__
+#define __rio_host_h__
+
+/*
+** the host structure - one per host card in the system.
+*/
+
+#define MAX_EXTRA_UNITS 64
+
+/*
+** Host data structure. This is used for the software equiv. of
+** the host.
+*/
+struct Host {
+ struct pci_dev *pdev;
+ unsigned char Type; /* RIO_EISA, RIO_MCA, ... */
+ unsigned char Ivec; /* POLLED or ivec number */
+ unsigned char Mode; /* Control stuff */
+ unsigned char Slot; /* Slot */
+ void __iomem *Caddr; /* KV address of DPRAM */
+ struct DpRam __iomem *CardP; /* KV address of DPRAM, with overlay */
+ unsigned long PaddrP; /* Phys. address of DPRAM */
+ char Name[MAX_NAME_LEN]; /* The name of the host */
+ unsigned int UniqueNum; /* host unique number */
+ spinlock_t HostLock; /* Lock structure for MPX */
+ unsigned int WorkToBeDone; /* set to true each interrupt */
+ unsigned int InIntr; /* Being serviced? */
+ unsigned int IntSrvDone; /* host's interrupt has been serviced */
+ void (*Copy) (void *, void __iomem *, int); /* copy func */
+ struct timer_list timer;
+ /*
+ ** I M P O R T A N T !
+ **
+ ** The rest of this data structure is cleared to zero after
+ ** a RIO_HOST_FOAD command.
+ */
+
+ unsigned long Flags; /* Whats going down */
+#define RC_WAITING 0
+#define RC_STARTUP 1
+#define RC_RUNNING 2
+#define RC_STUFFED 3
+#define RC_READY 7
+#define RUN_STATE 7
+/*
+** Boot mode applies to the way in which hosts in this system will
+** boot RTAs
+*/
+#define RC_BOOT_ALL 0x8 /* Boot all RTAs attached */
+#define RC_BOOT_OWN 0x10 /* Only boot RTAs bound to this system */
+#define RC_BOOT_NONE 0x20 /* Don't boot any RTAs (slave mode) */
+
+ struct Top Topology[LINKS_PER_UNIT]; /* one per link */
+ struct Map Mapping[MAX_RUP]; /* Mappings for host */
+ struct PHB __iomem *PhbP; /* Pointer to the PHB array */
+ unsigned short __iomem *PhbNumP; /* Ptr to Number of PHB's */
+ struct LPB __iomem *LinkStrP; /* Link Structure Array */
+ struct RUP __iomem *RupP; /* Sixteen real rups here */
+ struct PARM_MAP __iomem *ParmMapP; /* points to the parmmap */
+ unsigned int ExtraUnits[MAX_EXTRA_UNITS]; /* unknown things */
+ unsigned int NumExtraBooted; /* how many of the above */
+ /*
+ ** Twenty logical rups.
+ ** The first sixteen are the real Rup entries (above), the last four
+ ** are the link RUPs.
+ */
+ struct UnixRup UnixRups[MAX_RUP + LINKS_PER_UNIT];
+ int timeout_id; /* For calling 100 ms delays */
+ int timeout_sem; /* For calling 100 ms delays */
+ unsigned long locks; /* long req'd for set_bit --RR */
+ char ____end_marker____;
+};
+#define Control CardP->DpControl
+#define SetInt CardP->DpSetInt
+#define ResetTpu CardP->DpResetTpu
+#define ResetInt CardP->DpResetInt
+#define Signature CardP->DpSignature
+#define Sram1 CardP->DpSram1
+#define Sram2 CardP->DpSram2
+#define Sram3 CardP->DpSram3
+#define Scratch CardP->DpScratch
+#define __ParmMapR CardP->DpParmMapR
+#define SLX CardP->DpSlx
+#define Revision CardP->DpRevision
+#define Unique CardP->DpUnique
+#define Year CardP->DpYear
+#define Week CardP->DpWeek
+
+#define RIO_DUMBPARM 0x0860 /* what not to expect */
+
+#endif
diff --git a/drivers/char/rio/link.h b/drivers/char/rio/link.h
new file mode 100644
index 0000000..f3bf11a
--- /dev/null
+++ b/drivers/char/rio/link.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+ ******* *******
+ ******* L I N K
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra / Jeremy Rolls
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _link_h
+#define _link_h 1
+
+/*************************************************
+ * Define the Link Status stuff
+ ************************************************/
+/* Boot request stuff */
+#define BOOT_REQUEST ((ushort) 0) /* Request for a boot */
+#define BOOT_ABORT ((ushort) 1) /* Abort a boot */
+#define BOOT_SEQUENCE ((ushort) 2) /* Packet with the number of packets
+ and load address */
+#define BOOT_COMPLETED ((ushort) 3) /* Boot completed */
+
+
+struct LPB {
+ u16 link_number; /* Link Number */
+ u16 in_ch; /* Link In Channel */
+ u16 out_ch; /* Link Out Channel */
+ u8 attached_serial[4]; /* Attached serial number */
+ u8 attached_host_serial[4];
+ /* Serial number of Host who
+ booted the other end */
+ u16 descheduled; /* Currently Descheduled */
+ u16 state; /* Current state */
+ u16 send_poll; /* Send a Poll Packet */
+ u16 ltt_p; /* Process Descriptor */
+ u16 lrt_p; /* Process Descriptor */
+ u16 lrt_status; /* Current lrt status */
+ u16 ltt_status; /* Current ltt status */
+ u16 timeout; /* Timeout value */
+ u16 topology; /* Topology bits */
+ u16 mon_ltt;
+ u16 mon_lrt;
+ u16 WaitNoBoot; /* Secs to hold off booting */
+ u16 add_packet_list; /* Add packets to here */
+ u16 remove_packet_list; /* Send packets from here */
+
+ u16 lrt_fail_chan; /* Lrt's failure channel */
+ u16 ltt_fail_chan; /* Ltt's failure channel */
+
+ /* RUP structure for HOST to driver communications */
+ struct RUP rup;
+ struct RUP link_rup; /* RUP for the link (POLL,
+ topology etc.) */
+ u16 attached_link; /* Number of attached link */
+ u16 csum_errors; /* csum errors */
+ u16 num_disconnects; /* number of disconnects */
+ u16 num_sync_rcvd; /* # sync's received */
+ u16 num_sync_rqst; /* # sync requests */
+ u16 num_tx; /* Num pkts sent */
+ u16 num_rx; /* Num pkts received */
+ u16 module_attached; /* Module tpyes of attached */
+ u16 led_timeout; /* LED timeout */
+ u16 first_port; /* First port to service */
+ u16 last_port; /* Last port to service */
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/linux_compat.h b/drivers/char/rio/linux_compat.h
new file mode 100644
index 0000000..34c0d28
--- /dev/null
+++ b/drivers/char/rio/linux_compat.h
@@ -0,0 +1,77 @@
+/*
+ * (C) 2000 R.E.Wolff@BitWizard.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/interrupt.h>
+
+
+#define DEBUG_ALL
+
+struct ttystatics {
+ struct termios tm;
+};
+
+extern int rio_debug;
+
+#define RIO_DEBUG_INIT 0x000001
+#define RIO_DEBUG_BOOT 0x000002
+#define RIO_DEBUG_CMD 0x000004
+#define RIO_DEBUG_CTRL 0x000008
+#define RIO_DEBUG_INTR 0x000010
+#define RIO_DEBUG_PARAM 0x000020
+#define RIO_DEBUG_ROUTE 0x000040
+#define RIO_DEBUG_TABLE 0x000080
+#define RIO_DEBUG_TTY 0x000100
+#define RIO_DEBUG_FLOW 0x000200
+#define RIO_DEBUG_MODEMSIGNALS 0x000400
+#define RIO_DEBUG_PROBE 0x000800
+#define RIO_DEBUG_CLEANUP 0x001000
+#define RIO_DEBUG_IFLOW 0x002000
+#define RIO_DEBUG_PFE 0x004000
+#define RIO_DEBUG_REC 0x008000
+#define RIO_DEBUG_SPINLOCK 0x010000
+#define RIO_DEBUG_DELAY 0x020000
+#define RIO_DEBUG_MOD_COUNT 0x040000
+
+
+/* Copied over from riowinif.h . This is ugly. The winif file declares
+also much other stuff which is incompatible with the headers from
+the older driver. The older driver includes "brates.h" which shadows
+the definitions from Linux, and is incompatible... */
+
+/* RxBaud and TxBaud definitions... */
+#define RIO_B0 0x00 /* RTS / DTR signals dropped */
+#define RIO_B50 0x01 /* 50 baud */
+#define RIO_B75 0x02 /* 75 baud */
+#define RIO_B110 0x03 /* 110 baud */
+#define RIO_B134 0x04 /* 134.5 baud */
+#define RIO_B150 0x05 /* 150 baud */
+#define RIO_B200 0x06 /* 200 baud */
+#define RIO_B300 0x07 /* 300 baud */
+#define RIO_B600 0x08 /* 600 baud */
+#define RIO_B1200 0x09 /* 1200 baud */
+#define RIO_B1800 0x0A /* 1800 baud */
+#define RIO_B2400 0x0B /* 2400 baud */
+#define RIO_B4800 0x0C /* 4800 baud */
+#define RIO_B9600 0x0D /* 9600 baud */
+#define RIO_B19200 0x0E /* 19200 baud */
+#define RIO_B38400 0x0F /* 38400 baud */
+#define RIO_B56000 0x10 /* 56000 baud */
+#define RIO_B57600 0x11 /* 57600 baud */
+#define RIO_B64000 0x12 /* 64000 baud */
+#define RIO_B115200 0x13 /* 115200 baud */
+#define RIO_B2000 0x14 /* 2000 baud */
diff --git a/drivers/char/rio/map.h b/drivers/char/rio/map.h
new file mode 100644
index 0000000..8366978
--- /dev/null
+++ b/drivers/char/rio/map.h
@@ -0,0 +1,98 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : map.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:11
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)map.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_map_h__
+#define __rio_map_h__
+
+/*
+** mapping structure passed to and from the config.rio program to
+** determine the current topology of the world
+*/
+
+#define MAX_MAP_ENTRY 17
+#define TOTAL_MAP_ENTRIES (MAX_MAP_ENTRY*RIO_SLOTS)
+#define MAX_NAME_LEN 32
+
+struct Map {
+ unsigned int HostUniqueNum; /* Supporting hosts unique number */
+ unsigned int RtaUniqueNum; /* Unique number */
+ /*
+ ** The next two IDs must be swapped on big-endian architectures
+ ** when using a v2.04 /etc/rio/config with a v3.00 driver (when
+ ** upgrading for example).
+ */
+ unsigned short ID; /* ID used in the subnet */
+ unsigned short ID2; /* ID of 2nd block of 8 for 16 port */
+ unsigned long Flags; /* Booted, ID Given, Disconnected */
+ unsigned long SysPort; /* First tty mapped to this port */
+ struct Top Topology[LINKS_PER_UNIT]; /* ID connected to each link */
+ char Name[MAX_NAME_LEN]; /* Cute name by which RTA is known */
+};
+
+/*
+** Flag values:
+*/
+#define RTA_BOOTED 0x00000001
+#define RTA_NEWBOOT 0x00000010
+#define MSG_DONE 0x00000020
+#define RTA_INTERCONNECT 0x00000040
+#define RTA16_SECOND_SLOT 0x00000080
+#define BEEN_HERE 0x00000100
+#define SLOT_TENTATIVE 0x40000000
+#define SLOT_IN_USE 0x80000000
+
+/*
+** HostUniqueNum is the unique number from the host card that this RTA
+** is to be connected to.
+** RtaUniqueNum is the unique number of the RTA concerned. It will be ZERO
+** if the slot in the table is unused. If it is the same as the HostUniqueNum
+** then this slot represents a host card.
+** Flags contains current boot/route state info
+** SysPort is a value in the range 0-504, being the number of the first tty
+** on this RTA. Each RTA supports 8 ports. The SysPort value must be modulo 8.
+** SysPort 0-127 correspond to /dev/ttyr001 to /dev/ttyr128, with minor
+** numbers 0-127. SysPort 128-255 correspond to /dev/ttyr129 to /dev/ttyr256,
+** again with minor numbers 0-127, and so on for SysPorts 256-383 and 384-511
+** ID will be in the range 0-16 for a `known' RTA. ID will be 0xFFFF for an
+** unused slot/unknown ID etc.
+** The Topology array contains the ID of the unit connected to each of the
+** four links on this unit. The entry will be 0xFFFF if NOTHING is connected
+** to the link, or will be 0xFF00 if an UNKNOWN unit is connected to the link.
+** The Name field is a null-terminated string, upto 31 characters, containing
+** the 'cute' name that the sysadmin/users know the RTA by. It is permissible
+** for this string to contain any character in the range \040 to \176 inclusive.
+** In particular, ctrl sequences and DEL (0x7F, \177) are not allowed. The
+** special character '%' IS allowable, and needs no special action.
+**
+*/
+
+#endif
diff --git a/drivers/char/rio/param.h b/drivers/char/rio/param.h
new file mode 100644
index 0000000..7e9b628
--- /dev/null
+++ b/drivers/char/rio/param.h
@@ -0,0 +1,55 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : param.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:12
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)param.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_param_h__
+#define __rio_param_h__
+
+/*
+** the param command block, as used in OPEN and PARAM calls.
+*/
+
+struct phb_param {
+ u8 Cmd; /* It is very important that these line up */
+ u8 Cor1; /* with what is expected at the other end. */
+ u8 Cor2; /* to confirm that you've got it right, */
+ u8 Cor4; /* check with cirrus/cirrus.h */
+ u8 Cor5;
+ u8 TxXon; /* Transmit X-On character */
+ u8 TxXoff; /* Transmit X-Off character */
+ u8 RxXon; /* Receive X-On character */
+ u8 RxXoff; /* Receive X-Off character */
+ u8 LNext; /* Literal-next character */
+ u8 TxBaud; /* Transmit baudrate */
+ u8 RxBaud; /* Receive baudrate */
+};
+
+#endif
diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h
new file mode 100644
index 0000000..acc8fa4
--- /dev/null
+++ b/drivers/char/rio/parmmap.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+ ******* *******
+ ******* H O S T M E M O R Y M A P
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra / Jeremy Rolls
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+6/4/1991 jonb Made changes to accommodate Mips R3230 bus
+ ***************************************************************************/
+
+#ifndef _parmap_h
+#define _parmap_h
+
+typedef struct PARM_MAP PARM_MAP;
+
+struct PARM_MAP {
+ u16 phb_ptr; /* Pointer to the PHB array */
+ u16 phb_num_ptr; /* Ptr to Number of PHB's */
+ u16 free_list; /* Free List pointer */
+ u16 free_list_end; /* Free List End pointer */
+ u16 q_free_list_ptr; /* Ptr to Q_BUF variable */
+ u16 unit_id_ptr; /* Unit Id */
+ u16 link_str_ptr; /* Link Structure Array */
+ u16 bootloader_1; /* 1st Stage Boot Loader */
+ u16 bootloader_2; /* 2nd Stage Boot Loader */
+ u16 port_route_map_ptr; /* Port Route Map */
+ u16 route_ptr; /* Unit Route Map */
+ u16 map_present; /* Route Map present */
+ s16 pkt_num; /* Total number of packets */
+ s16 q_num; /* Total number of Q packets */
+ u16 buffers_per_port; /* Number of buffers per port */
+ u16 heap_size; /* Initial size of heap */
+ u16 heap_left; /* Current Heap left */
+ u16 error; /* Error code */
+ u16 tx_max; /* Max number of tx pkts per phb */
+ u16 rx_max; /* Max number of rx pkts per phb */
+ u16 rx_limit; /* For high / low watermarks */
+ s16 links; /* Links to use */
+ s16 timer; /* Interrupts per second */
+ u16 rups; /* Pointer to the RUPs */
+ u16 max_phb; /* Mostly for debugging */
+ u16 living; /* Just increments!! */
+ u16 init_done; /* Initialisation over */
+ u16 booting_link;
+ u16 idle_count; /* Idle time counter */
+ u16 busy_count; /* Busy counter */
+ u16 idle_control; /* Control Idle Process */
+ u16 tx_intr; /* TX interrupt pending */
+ u16 rx_intr; /* RX interrupt pending */
+ u16 rup_intr; /* RUP interrupt pending */
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/pci.h b/drivers/char/rio/pci.h
new file mode 100644
index 0000000..6032f91
--- /dev/null
+++ b/drivers/char/rio/pci.h
@@ -0,0 +1,72 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : pci.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:12
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)pci.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_pci_h__
+#define __rio_pci_h__
+
+/*
+** PCI stuff
+*/
+
+#define PCITpFastClock 0x80
+#define PCITpSlowClock 0x00
+#define PCITpFastLinks 0x40
+#define PCITpSlowLinks 0x00
+#define PCITpIntEnable 0x04
+#define PCITpIntDisable 0x00
+#define PCITpBusEnable 0x02
+#define PCITpBusDisable 0x00
+#define PCITpBootFromRam 0x01
+#define PCITpBootFromLink 0x00
+
+#define RIO_PCI_VENDOR 0x11CB
+#define RIO_PCI_DEVICE 0x8000
+#define RIO_PCI_BASE_CLASS 0x02
+#define RIO_PCI_SUB_CLASS 0x80
+#define RIO_PCI_PROG_IFACE 0x00
+
+#define RIO_PCI_RID 0x0008
+#define RIO_PCI_BADR0 0x0010
+#define RIO_PCI_INTLN 0x003C
+#define RIO_PCI_INTPIN 0x003D
+
+#define RIO_PCI_MEM_SIZE 65536
+
+#define RIO_PCI_TURBO_TP 0x80
+#define RIO_PCI_FAST_LINKS 0x40
+#define RIO_PCI_INT_ENABLE 0x04
+#define RIO_PCI_TP_BUS_ENABLE 0x02
+#define RIO_PCI_BOOT_FROM_RAM 0x01
+
+#define RIO_PCI_DEFAULT_MODE 0x05
+
+#endif /* __rio_pci_h__ */
diff --git a/drivers/char/rio/phb.h b/drivers/char/rio/phb.h
new file mode 100644
index 0000000..a4c48ae
--- /dev/null
+++ b/drivers/char/rio/phb.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+ ******* *******
+ ******* P H B H E A D E R *******
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra, Jeremy Rolls
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _phb_h
+#define _phb_h 1
+
+/*************************************************
+ * Handshake asserted. Deasserted by the LTT(s)
+ ************************************************/
+#define PHB_HANDSHAKE_SET ((ushort) 0x001) /* Set by LRT */
+
+#define PHB_HANDSHAKE_RESET ((ushort) 0x002) /* Set by ISR / driver */
+
+#define PHB_HANDSHAKE_FLAGS (PHB_HANDSHAKE_RESET | PHB_HANDSHAKE_SET)
+ /* Reset by ltt */
+
+
+/*************************************************
+ * Maximum number of PHB's
+ ************************************************/
+#define MAX_PHB ((ushort) 128) /* range 0-127 */
+
+/*************************************************
+ * Defines for the mode fields
+ ************************************************/
+#define TXPKT_INCOMPLETE 0x0001 /* Previous tx packet not completed */
+#define TXINTR_ENABLED 0x0002 /* Tx interrupt is enabled */
+#define TX_TAB3 0x0004 /* TAB3 mode */
+#define TX_OCRNL 0x0008 /* OCRNL mode */
+#define TX_ONLCR 0x0010 /* ONLCR mode */
+#define TX_SENDSPACES 0x0020 /* Send n spaces command needs
+ completing */
+#define TX_SENDNULL 0x0040 /* Escaping NULL needs completing */
+#define TX_SENDLF 0x0080 /* LF -> CR LF needs completing */
+#define TX_PARALLELBUG 0x0100 /* CD1400 LF -> CR LF bug on parallel
+ port */
+#define TX_HANGOVER (TX_SENDSPACES | TX_SENDLF | TX_SENDNULL)
+#define TX_DTRFLOW 0x0200 /* DTR tx flow control */
+#define TX_DTRFLOWED 0x0400 /* DTR is low - don't allow more data
+ into the FIFO */
+#define TX_DATAINFIFO 0x0800 /* There is data in the FIFO */
+#define TX_BUSY 0x1000 /* Data in FIFO, shift or holding regs */
+
+#define RX_SPARE 0x0001 /* SPARE */
+#define RXINTR_ENABLED 0x0002 /* Rx interrupt enabled */
+#define RX_ICRNL 0x0008 /* ICRNL mode */
+#define RX_INLCR 0x0010 /* INLCR mode */
+#define RX_IGNCR 0x0020 /* IGNCR mode */
+#define RX_CTSFLOW 0x0040 /* CTSFLOW enabled */
+#define RX_IXOFF 0x0080 /* IXOFF enabled */
+#define RX_CTSFLOWED 0x0100 /* CTSFLOW and CTS dropped */
+#define RX_IXOFFED 0x0200 /* IXOFF and xoff sent */
+#define RX_BUFFERED 0x0400 /* Try and pass on complete packets */
+
+#define PORT_ISOPEN 0x0001 /* Port open? */
+#define PORT_HUPCL 0x0002 /* Hangup on close? */
+#define PORT_MOPENPEND 0x0004 /* Modem open pending */
+#define PORT_ISPARALLEL 0x0008 /* Parallel port */
+#define PORT_BREAK 0x0010 /* Port on break */
+#define PORT_STATUSPEND 0x0020 /* Status packet pending */
+#define PORT_BREAKPEND 0x0040 /* Break packet pending */
+#define PORT_MODEMPEND 0x0080 /* Modem status packet pending */
+#define PORT_PARALLELBUG 0x0100 /* CD1400 LF -> CR LF bug on parallel
+ port */
+#define PORT_FULLMODEM 0x0200 /* Full modem signals */
+#define PORT_RJ45 0x0400 /* RJ45 connector - no RI signal */
+#define PORT_RESTRICTED 0x0600 /* Restricted connector - no RI / DTR */
+
+#define PORT_MODEMBITS 0x0600 /* Mask for modem fields */
+
+#define PORT_WCLOSE 0x0800 /* Waiting for close */
+#define PORT_HANDSHAKEFIX 0x1000 /* Port has H/W flow control fix */
+#define PORT_WASPCLOSED 0x2000 /* Port closed with PCLOSE */
+#define DUMPMODE 0x4000 /* Dump RTA mem */
+#define READ_REG 0x8000 /* Read CD1400 register */
+
+
+
+/**************************************************************************
+ * PHB Structure
+ * A few words.
+ *
+ * Normally Packets are added to the end of the list and removed from
+ * the start. The pointer tx_add points to a SPACE to put a Packet.
+ * The pointer tx_remove points to the next Packet to remove
+ *************************************************************************/
+
+struct PHB {
+ u8 source;
+ u8 handshake;
+ u8 status;
+ u16 timeout; /* Maximum of 1.9 seconds */
+ u8 link; /* Send down this link */
+ u8 destination;
+ u16 tx_start;
+ u16 tx_end;
+ u16 tx_add;
+ u16 tx_remove;
+
+ u16 rx_start;
+ u16 rx_end;
+ u16 rx_add;
+ u16 rx_remove;
+
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/pkt.h b/drivers/char/rio/pkt.h
new file mode 100644
index 0000000..a945816
--- /dev/null
+++ b/drivers/char/rio/pkt.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+ ******* *******
+ ******* P A C K E T H E A D E R F I L E
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra / Jeremy Rolls
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _pkt_h
+#define _pkt_h 1
+
+#define PKT_CMD_BIT ((ushort) 0x080)
+#define PKT_CMD_DATA ((ushort) 0x080)
+
+#define PKT_ACK ((ushort) 0x040)
+
+#define PKT_TGL ((ushort) 0x020)
+
+#define PKT_LEN_MASK ((ushort) 0x07f)
+
+#define DATA_WNDW ((ushort) 0x10)
+#define PKT_TTL_MASK ((ushort) 0x0f)
+
+#define PKT_MAX_DATA_LEN 72
+
+#define PKT_LENGTH sizeof(struct PKT)
+#define SYNC_PKT_LENGTH (PKT_LENGTH + 4)
+
+#define CONTROL_PKT_LEN_MASK PKT_LEN_MASK
+#define CONTROL_PKT_CMD_BIT PKT_CMD_BIT
+#define CONTROL_PKT_ACK (PKT_ACK << 8)
+#define CONTROL_PKT_TGL (PKT_TGL << 8)
+#define CONTROL_PKT_TTL_MASK (PKT_TTL_MASK << 8)
+#define CONTROL_DATA_WNDW (DATA_WNDW << 8)
+
+struct PKT {
+ u8 dest_unit; /* Destination Unit Id */
+ u8 dest_port; /* Destination POrt */
+ u8 src_unit; /* Source Unit Id */
+ u8 src_port; /* Source POrt */
+ u8 len;
+ u8 control;
+ u8 data[PKT_MAX_DATA_LEN];
+ /* Actual data :-) */
+ u16 csum; /* C-SUM */
+};
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/port.h b/drivers/char/rio/port.h
new file mode 100644
index 0000000..49cf6d1
--- /dev/null
+++ b/drivers/char/rio/port.h
@@ -0,0 +1,179 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : port.h
+** SID : 1.3
+** Last Modified : 11/6/98 11:34:12
+** Retrieved : 11/6/98 11:34:21
+**
+** ident @(#)port.h 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_port_h__
+#define __rio_port_h__
+
+/*
+** Port data structure
+*/
+struct Port {
+ struct gs_port gs;
+ int PortNum; /* RIO port no., 0-511 */
+ struct Host *HostP;
+ void __iomem *Caddr;
+ unsigned short HostPort; /* Port number on host card */
+ unsigned char RupNum; /* Number of RUP for port */
+ unsigned char ID2; /* Second ID of RTA for port */
+ unsigned long State; /* FLAGS for open & xopen */
+#define RIO_LOPEN 0x00001 /* Local open */
+#define RIO_MOPEN 0x00002 /* Modem open */
+#define RIO_WOPEN 0x00004 /* Waiting for open */
+#define RIO_CLOSING 0x00008 /* The port is being close */
+#define RIO_XPBUSY 0x00010 /* Transparent printer busy */
+#define RIO_BREAKING 0x00020 /* Break in progress */
+#define RIO_DIRECT 0x00040 /* Doing Direct output */
+#define RIO_EXCLUSIVE 0x00080 /* Stream open for exclusive use */
+#define RIO_NDELAY 0x00100 /* Stream is open FNDELAY */
+#define RIO_CARR_ON 0x00200 /* Stream has carrier present */
+#define RIO_XPWANTR 0x00400 /* Stream wanted by Xprint */
+#define RIO_RBLK 0x00800 /* Stream is read-blocked */
+#define RIO_BUSY 0x01000 /* Stream is BUSY for write */
+#define RIO_TIMEOUT 0x02000 /* Stream timeout in progress */
+#define RIO_TXSTOP 0x04000 /* Stream output is stopped */
+#define RIO_WAITFLUSH 0x08000 /* Stream waiting for flush */
+#define RIO_DYNOROD 0x10000 /* Drain failed */
+#define RIO_DELETED 0x20000 /* RTA has been deleted */
+#define RIO_ISSCANCODE 0x40000 /* This line is in scancode mode */
+#define RIO_USING_EUC 0x100000 /* Using extended Unix chars */
+#define RIO_CAN_COOK 0x200000 /* This line can do cooking */
+#define RIO_TRIAD_MODE 0x400000 /* Enable TRIAD special ops. */
+#define RIO_TRIAD_BLOCK 0x800000 /* Next read will block */
+#define RIO_TRIAD_FUNC 0x1000000 /* Seen a function key coming in */
+#define RIO_THROTTLE_RX 0x2000000 /* RX needs to be throttled. */
+
+ unsigned long Config; /* FLAGS for NOREAD.... */
+#define RIO_NOREAD 0x0001 /* Are not allowed to read port */
+#define RIO_NOWRITE 0x0002 /* Are not allowed to write port */
+#define RIO_NOXPRINT 0x0004 /* Are not allowed to xprint port */
+#define RIO_NOMASK 0x0007 /* All not allowed things */
+#define RIO_IXANY 0x0008 /* Port is allowed ixany */
+#define RIO_MODEM 0x0010 /* Stream is a modem device */
+#define RIO_IXON 0x0020 /* Port is allowed ixon */
+#define RIO_WAITDRAIN 0x0040 /* Wait for port to completely drain */
+#define RIO_MAP_50_TO_50 0x0080 /* Map 50 baud to 50 baud */
+#define RIO_MAP_110_TO_110 0x0100 /* Map 110 baud to 110 baud */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 prt fix
+** As LynxOS does not appear to support Hardware Flow Control .....
+** Define our own flow control flags in 'Config'.
+*/
+#define RIO_CTSFLOW 0x0200 /* RIO's own CTSFLOW flag */
+#define RIO_RTSFLOW 0x0400 /* RIO's own RTSFLOW flag */
+
+
+ struct PHB __iomem *PhbP; /* pointer to PHB for port */
+ u16 __iomem *TxAdd; /* Add packets here */
+ u16 __iomem *TxStart; /* Start of add array */
+ u16 __iomem *TxEnd; /* End of add array */
+ u16 __iomem *RxRemove; /* Remove packets here */
+ u16 __iomem *RxStart; /* Start of remove array */
+ u16 __iomem *RxEnd; /* End of remove array */
+ unsigned int RtaUniqueNum; /* Unique number of RTA */
+ unsigned short PortState; /* status of port */
+ unsigned short ModemState; /* status of modem lines */
+ unsigned long ModemLines; /* Modem bits sent to RTA */
+ unsigned char CookMode; /* who expands CR/LF? */
+ unsigned char ParamSem; /* Prevent write during param */
+ unsigned char Mapped; /* if port mapped onto host */
+ unsigned char SecondBlock; /* if port belongs to 2nd block
+ of 16 port RTA */
+ unsigned char InUse; /* how many pre-emptive cmds */
+ unsigned char Lock; /* if params locked */
+ unsigned char Store; /* if params stored across closes */
+ unsigned char FirstOpen; /* TRUE if first time port opened */
+ unsigned char FlushCmdBodge; /* if doing a (non)flush */
+ unsigned char MagicFlags; /* require intr processing */
+#define MAGIC_FLUSH 0x01 /* mirror of WflushFlag */
+#define MAGIC_REBOOT 0x02 /* RTA re-booted, re-open ports */
+#define MORE_OUTPUT_EYGOR 0x04 /* riotproc failed to empty clists */
+ unsigned char WflushFlag; /* 1 How many WFLUSHs active */
+/*
+** Transparent print stuff
+*/
+ struct Xprint {
+#ifndef MAX_XP_CTRL_LEN
+#define MAX_XP_CTRL_LEN 16 /* ALSO IN DAEMON.H */
+#endif
+ unsigned int XpCps;
+ char XpOn[MAX_XP_CTRL_LEN];
+ char XpOff[MAX_XP_CTRL_LEN];
+ unsigned short XpLen; /* strlen(XpOn)+strlen(XpOff) */
+ unsigned char XpActive;
+ unsigned char XpLastTickOk; /* TRUE if we can process */
+#define XP_OPEN 00001
+#define XP_RUNABLE 00002
+ struct ttystatics *XttyP;
+ } Xprint;
+ unsigned char RxDataStart;
+ unsigned char Cor2Copy; /* copy of COR2 */
+ char *Name; /* points to the Rta's name */
+ char *TxRingBuffer;
+ unsigned short TxBufferIn; /* New data arrives here */
+ unsigned short TxBufferOut; /* Intr removes data here */
+ unsigned short OldTxBufferOut; /* Indicates if draining */
+ int TimeoutId; /* Timeout ID */
+ unsigned int Debug;
+ unsigned char WaitUntilBooted; /* True if open should block */
+ unsigned int statsGather; /* True if gathering stats */
+ unsigned long txchars; /* Chars transmitted */
+ unsigned long rxchars; /* Chars received */
+ unsigned long opens; /* port open count */
+ unsigned long closes; /* port close count */
+ unsigned long ioctls; /* ioctl count */
+ unsigned char LastRxTgl; /* Last state of rx toggle bit */
+ spinlock_t portSem; /* Lock using this sem */
+ int MonitorTstate; /* Monitoring ? */
+ int timeout_id; /* For calling 100 ms delays */
+ int timeout_sem; /* For calling 100 ms delays */
+ int firstOpen; /* First time open ? */
+ char *p; /* save the global struc here .. */
+};
+
+struct ModuleInfo {
+ char *Name;
+ unsigned int Flags[4]; /* one per port on a module */
+};
+
+/*
+** This struct is required because trying to grab an entire Port structure
+** runs into problems with differing struct sizes between driver and config.
+*/
+struct PortParams {
+ unsigned int Port;
+ unsigned long Config;
+ unsigned long State;
+ struct ttystatics *TtyP;
+};
+
+#endif
diff --git a/drivers/char/rio/protsts.h b/drivers/char/rio/protsts.h
new file mode 100644
index 0000000..8ab7940
--- /dev/null
+++ b/drivers/char/rio/protsts.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+ ******* *******
+ ******* P R O T O C O L S T A T U S S T R U C T U R E *******
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra / Jeremy Rolls
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _protsts_h
+#define _protsts_h 1
+
+/*************************************************
+ * ACK bit. Last Packet received OK. Set by
+ * rxpkt to indicate that the Packet has been
+ * received OK and that the LTT must set the ACK
+ * bit in the next outward bound Packet
+ * and re-set by LTT's after xmit.
+ *
+ * Gets shoved into rx_status
+ ************************************************/
+#define PHB_RX_LAST_PKT_ACKED ((ushort) 0x080)
+
+/*******************************************************
+ * The Rx TOGGLE bit.
+ * Stuffed into rx_status by RXPKT
+ ******************************************************/
+#define PHB_RX_DATA_WNDW ((ushort) 0x040)
+
+/*******************************************************
+ * The Rx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into rx_status
+ ******************************************************/
+#define PHB_RX_TGL ((ushort) 0x2000)
+
+
+/*************************************************
+ * This bit is set by the LRT to indicate that
+ * an ACK (packet) must be returned.
+ *
+ * Gets shoved into tx_status
+ ************************************************/
+#define PHB_TX_SEND_PKT_ACK ((ushort) 0x08)
+
+/*************************************************
+ * Set by LTT to indicate that an ACK is required
+ *************************************************/
+#define PHB_TX_ACK_RQRD ((ushort) 0x01)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit.
+ * Stuffed into tx_status by RXPKT from the PKT WndW
+ * field. Looked by the LTT when the NEXT Packet
+ * is going to be sent.
+ ******************************************************/
+#define PHB_TX_DATA_WNDW ((ushort) 0x04)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into tx_status
+ ******************************************************/
+#define PHB_TX_TGL ((ushort) 0x02)
+
+/*******************************************************
+ * Request intr bit. Set when the queue has gone quiet
+ * and the PHB has requested an interrupt.
+ ******************************************************/
+#define PHB_TX_INTR ((ushort) 0x100)
+
+/*******************************************************
+ * SET if the PHB cannot send any more data down the
+ * Link
+ ******************************************************/
+#define PHB_TX_HANDSHAKE ((ushort) 0x010)
+
+
+#define RUP_SEND_WNDW ((ushort) 0x08) ;
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/rio.h b/drivers/char/rio/rio.h
new file mode 100644
index 0000000..1bf3622
--- /dev/null
+++ b/drivers/char/rio/rio.h
@@ -0,0 +1,208 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 1998 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rio.h
+** SID : 1.3
+** Last Modified : 11/6/98 11:34:13
+** Retrieved : 11/6/98 11:34:22
+**
+** ident @(#)rio.h 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_rio_h__
+#define __rio_rio_h__
+
+/*
+** Maximum numbers of things
+*/
+#define RIO_SLOTS 4 /* number of configuration slots */
+#define RIO_HOSTS 4 /* number of hosts that can be found */
+#define PORTS_PER_HOST 128 /* number of ports per host */
+#define LINKS_PER_UNIT 4 /* number of links from a host */
+#define RIO_PORTS (PORTS_PER_HOST * RIO_HOSTS) /* max. no. of ports */
+#define RTAS_PER_HOST (MAX_RUP) /* number of RTAs per host */
+#define PORTS_PER_RTA (PORTS_PER_HOST/RTAS_PER_HOST) /* ports on a rta */
+#define PORTS_PER_MODULE 4 /* number of ports on a plug-in module */
+ /* number of modules on an RTA */
+#define MODULES_PER_RTA (PORTS_PER_RTA/PORTS_PER_MODULE)
+#define MAX_PRODUCT 16 /* numbr of different product codes */
+#define MAX_MODULE_TYPES 16 /* number of different types of module */
+
+#define RIO_CONTROL_DEV 128 /* minor number of host/control device */
+#define RIO_INVALID_MAJOR 0 /* test first host card's major no for validity */
+
+/*
+** number of RTAs that can be bound to a master
+*/
+#define MAX_RTA_BINDINGS (MAX_RUP * RIO_HOSTS)
+
+/*
+** Unit types
+*/
+#define PC_RTA16 0x90000000
+#define PC_RTA8 0xe0000000
+#define TYPE_HOST 0
+#define TYPE_RTA8 1
+#define TYPE_RTA16 2
+
+/*
+** Flag values returned by functions
+*/
+
+#define RIO_FAIL -1
+
+/*
+** SysPort value for something that hasn't any ports
+*/
+#define NO_PORT 0xFFFFFFFF
+
+/*
+** Unit ID Of all hosts
+*/
+#define HOST_ID 0
+
+/*
+** Break bytes into nybles
+*/
+#define LONYBLE(X) ((X) & 0xF)
+#define HINYBLE(X) (((X)>>4) & 0xF)
+
+/*
+** Flag values passed into some functions
+*/
+#define DONT_SLEEP 0
+#define OK_TO_SLEEP 1
+
+#define DONT_PRINT 1
+#define DO_PRINT 0
+
+#define PRINT_TO_LOG_CONS 0
+#define PRINT_TO_CONS 1
+#define PRINT_TO_LOG 2
+
+/*
+** Timeout has trouble with times of less than 3 ticks...
+*/
+#define MIN_TIMEOUT 3
+
+/*
+** Generally useful constants
+*/
+
+#define HUNDRED_MS ((HZ/10)?(HZ/10):1)
+#define ONE_MEG 0x100000
+#define SIXTY_FOUR_K 0x10000
+
+#define RIO_AT_MEM_SIZE SIXTY_FOUR_K
+#define RIO_EISA_MEM_SIZE SIXTY_FOUR_K
+#define RIO_MCA_MEM_SIZE SIXTY_FOUR_K
+
+#define COOK_WELL 0
+#define COOK_MEDIUM 1
+#define COOK_RAW 2
+
+/*
+** Pointer manipulation stuff
+** RIO_PTR takes hostp->Caddr and the offset into the DP RAM area
+** and produces a UNIX caddr_t (pointer) to the object
+** RIO_OBJ takes hostp->Caddr and a UNIX pointer to an object and
+** returns the offset into the DP RAM area.
+*/
+#define RIO_PTR(C,O) (((unsigned char __iomem *)(C))+(0xFFFF&(O)))
+#define RIO_OFF(C,O) ((unsigned char __iomem *)(O)-(unsigned char __iomem *)(C))
+
+/*
+** How to convert from various different device number formats:
+** DEV is a dev number, as passed to open, close etc - NOT a minor
+** number!
+**/
+
+#define RIO_MODEM_MASK 0x1FF
+#define RIO_MODEM_BIT 0x200
+#define RIO_UNMODEM(DEV) (MINOR(DEV) & RIO_MODEM_MASK)
+#define RIO_ISMODEM(DEV) (MINOR(DEV) & RIO_MODEM_BIT)
+#define RIO_PORT(DEV,FIRST_MAJ) ( (MAJOR(DEV) - FIRST_MAJ) * PORTS_PER_HOST) \
+ + MINOR(DEV)
+#define CSUM(pkt_ptr) (((u16 *)(pkt_ptr))[0] + ((u16 *)(pkt_ptr))[1] + \
+ ((u16 *)(pkt_ptr))[2] + ((u16 *)(pkt_ptr))[3] + \
+ ((u16 *)(pkt_ptr))[4] + ((u16 *)(pkt_ptr))[5] + \
+ ((u16 *)(pkt_ptr))[6] + ((u16 *)(pkt_ptr))[7] + \
+ ((u16 *)(pkt_ptr))[8] + ((u16 *)(pkt_ptr))[9] )
+
+#define RIO_LINK_ENABLE 0x80FF /* FF is a hack, mainly for Mips, to */
+ /* prevent a really stupid race condition. */
+
+#define NOT_INITIALISED 0
+#define INITIALISED 1
+
+#define NOT_POLLING 0
+#define POLLING 1
+
+#define NOT_CHANGED 0
+#define CHANGED 1
+
+#define NOT_INUSE 0
+
+#define DISCONNECT 0
+#define CONNECT 1
+
+/* ------ Control Codes ------ */
+
+#define CONTROL '^'
+#define IFOAD ( CONTROL + 1 )
+#define IDENTIFY ( CONTROL + 2 )
+#define ZOMBIE ( CONTROL + 3 )
+#define UFOAD ( CONTROL + 4 )
+#define IWAIT ( CONTROL + 5 )
+
+#define IFOAD_MAGIC 0xF0AD /* of course */
+#define ZOMBIE_MAGIC (~0xDEAD) /* not dead -> zombie */
+#define UFOAD_MAGIC 0xD1E /* kill-your-neighbour */
+#define IWAIT_MAGIC 0xB1DE /* Bide your time */
+
+/* ------ Error Codes ------ */
+
+#define E_NO_ERROR ((ushort) 0)
+
+/* ------ Free Lists ------ */
+
+struct rio_free_list {
+ u16 next;
+ u16 prev;
+};
+
+/* NULL for card side linked lists */
+#define TPNULL ((ushort)(0x8000))
+/* We can add another packet to a transmit queue if the packet pointer pointed
+ * to by the TxAdd pointer has PKT_IN_USE clear in its address. */
+#define PKT_IN_USE 0x1
+
+/* ------ Topology ------ */
+
+struct Top {
+ u8 Unit;
+ u8 Link;
+};
+
+#endif /* __rio_h__ */
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
new file mode 100644
index 0000000..a8f68a3
--- /dev/null
+++ b/drivers/char/rio/rio_linux.c
@@ -0,0 +1,1212 @@
+
+/* rio_linux.c -- Linux driver for the Specialix RIO series cards.
+ *
+ *
+ * (C) 1999 R.E.Wolff@BitWizard.nl
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (rio.txt) first.
+ *
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ *
+ * */
+
+#include <linux/module.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+
+#include <linux/generic_serial.h>
+#include <asm/uaccess.h>
+
+#include "linux_compat.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "protsts.h"
+#include "rioboard.h"
+
+
+#include "rio_linux.h"
+
+/* I don't think that this driver can handle more than 512 ports on
+one machine. Specialix specifies max 4 boards in one machine. I don't
+know why. If you want to try anyway you'll have to increase the number
+of boards in rio.h. You'll have to allocate more majors if you need
+more than 512 ports.... */
+
+#ifndef RIO_NORMAL_MAJOR0
+/* This allows overriding on the compiler commandline, or in a "major.h"
+ include or something like that */
+#define RIO_NORMAL_MAJOR0 154
+#define RIO_NORMAL_MAJOR1 156
+#endif
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+#ifndef RIO_WINDOW_LEN
+#define RIO_WINDOW_LEN 0x10000
+#endif
+
+
+/* Configurable options:
+ (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef RIO_PARANOIA_CHECK
+
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 1000
+ Hz, but it is user configurable. I don't recommend going above 1000
+ Hz. The interrupt ratelimit might trigger if the interrupt is
+ shared with a very active other device.
+ undef this if you want to disable the check....
+*/
+#define IRQ_RATE_LIMIT 200
+
+
+/* These constants are derived from SCO Source */
+static struct Conf
+ RIOConf = {
+ /* locator */ "RIO Config here",
+ /* startuptime */ HZ * 2,
+ /* how long to wait for card to run */
+ /* slowcook */ 0,
+ /* TRUE -> always use line disc. */
+ /* intrpolltime */ 1,
+ /* The frequency of OUR polls */
+ /* breakinterval */ 25,
+ /* x10 mS XXX: units seem to be 1ms not 10! -- REW */
+ /* timer */ 10,
+ /* mS */
+ /* RtaLoadBase */ 0x7000,
+ /* HostLoadBase */ 0x7C00,
+ /* XpHz */ 5,
+ /* number of Xprint hits per second */
+ /* XpCps */ 120,
+ /* Xprint characters per second */
+ /* XpOn */ "\033d#",
+ /* start Xprint for a wyse 60 */
+ /* XpOff */ "\024",
+ /* end Xprint for a wyse 60 */
+ /* MaxXpCps */ 2000,
+ /* highest Xprint speed */
+ /* MinXpCps */ 10,
+ /* slowest Xprint speed */
+ /* SpinCmds */ 1,
+ /* non-zero for mega fast boots */
+ /* First Addr */ 0x0A0000,
+ /* First address to look at */
+ /* Last Addr */ 0xFF0000,
+ /* Last address looked at */
+ /* BufferSize */ 1024,
+ /* Bytes per port of buffering */
+ /* LowWater */ 256,
+ /* how much data left before wakeup */
+ /* LineLength */ 80,
+ /* how wide is the console? */
+ /* CmdTimeout */ HZ,
+ /* how long a close command may take */
+};
+
+
+
+
+/* Function prototypes */
+
+static void rio_disable_tx_interrupts(void *ptr);
+static void rio_enable_tx_interrupts(void *ptr);
+static void rio_disable_rx_interrupts(void *ptr);
+static void rio_enable_rx_interrupts(void *ptr);
+static int rio_get_CD(void *ptr);
+static void rio_shutdown_port(void *ptr);
+static int rio_set_real_termios(void *ptr);
+static void rio_hungup(void *ptr);
+static void rio_close(void *ptr);
+static int rio_chars_in_buffer(void *ptr);
+static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+static int rio_init_drivers(void);
+
+static void my_hd(void *addr, int len);
+
+static struct tty_driver *rio_driver, *rio_driver2;
+
+/* The name "p" is a bit non-descript. But that's what the rio-lynxos
+sources use all over the place. */
+struct rio_info *p;
+
+int rio_debug;
+
+
+/* You can have the driver poll your card.
+ - Set rio_poll to 1 to poll every timer tick (10ms on Intel).
+ This is used when the card cannot use an interrupt for some reason.
+*/
+static int rio_poll = 1;
+
+
+/* These are the only open spaces in my computer. Yours may have more
+ or less.... */
+static int rio_probe_addrs[] = { 0xc0000, 0xd0000, 0xe0000 };
+
+#define NR_RIO_ADDRS ARRAY_SIZE(rio_probe_addrs)
+
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts.
+ Some architectures may need more. -- Changed to LONG to
+ support up to 64 bits on 64bit architectures. -- REW 20/06/99 */
+static long rio_irqmask = -1;
+
+MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>");
+MODULE_DESCRIPTION("RIO driver");
+MODULE_LICENSE("GPL");
+module_param(rio_poll, int, 0);
+module_param(rio_debug, int, 0644);
+module_param(rio_irqmask, long, 0);
+
+static struct real_driver rio_real_driver = {
+ rio_disable_tx_interrupts,
+ rio_enable_tx_interrupts,
+ rio_disable_rx_interrupts,
+ rio_enable_rx_interrupts,
+ rio_get_CD,
+ rio_shutdown_port,
+ rio_set_real_termios,
+ rio_chars_in_buffer,
+ rio_close,
+ rio_hungup,
+ NULL
+};
+
+/*
+ * Firmware loader driver specific routines
+ *
+ */
+
+static const struct file_operations rio_fw_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = rio_fw_ioctl,
+};
+
+static struct miscdevice rio_fw_device = {
+ RIOCTL_MISC_MINOR, "rioctl", &rio_fw_fops
+};
+
+
+
+
+
+#ifdef RIO_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int rio_paranoia_check(struct rio_port const *port, char *name, const char *routine)
+{
+
+ static const char *badmagic = KERN_ERR "rio: Warning: bad rio port magic number for device %s in %s\n";
+ static const char *badinfo = KERN_ERR "rio: Warning: null rio port for device %s in %s\n";
+
+ if (!port) {
+ printk(badinfo, name, routine);
+ return 1;
+ }
+ if (port->magic != RIO_MAGIC) {
+ printk(badmagic, name, routine);
+ return 1;
+ }
+
+ return 0;
+}
+#else
+#define rio_paranoia_check(a,b,c) 0
+#endif
+
+
+#ifdef DEBUG
+static void my_hd(void *ad, int len)
+{
+ int i, j, ch;
+ unsigned char *addr = ad;
+
+ for (i = 0; i < len; i += 16) {
+ rio_dprintk(RIO_DEBUG_PARAM, "%08lx ", (unsigned long) addr + i);
+ for (j = 0; j < 16; j++) {
+ rio_dprintk(RIO_DEBUG_PARAM, "%02x %s", addr[j + i], (j == 7) ? " " : "");
+ }
+ for (j = 0; j < 16; j++) {
+ ch = addr[j + i];
+ rio_dprintk(RIO_DEBUG_PARAM, "%c", (ch < 0x20) ? '.' : ((ch > 0x7f) ? '.' : ch));
+ }
+ rio_dprintk(RIO_DEBUG_PARAM, "\n");
+ }
+}
+#else
+#define my_hd(ad,len) do{/* nothing*/ } while (0)
+#endif
+
+
+/* Delay a number of jiffies, allowing a signal to interrupt */
+int RIODelay(struct Port *PortP, int njiffies)
+{
+ func_enter();
+
+ rio_dprintk(RIO_DEBUG_DELAY, "delaying %d jiffies\n", njiffies);
+ msleep_interruptible(jiffies_to_msecs(njiffies));
+ func_exit();
+
+ if (signal_pending(current))
+ return RIO_FAIL;
+ else
+ return !RIO_FAIL;
+}
+
+
+/* Delay a number of jiffies, disallowing a signal to interrupt */
+int RIODelay_ni(struct Port *PortP, int njiffies)
+{
+ func_enter();
+
+ rio_dprintk(RIO_DEBUG_DELAY, "delaying %d jiffies (ni)\n", njiffies);
+ msleep(jiffies_to_msecs(njiffies));
+ func_exit();
+ return !RIO_FAIL;
+}
+
+void rio_copy_to_card(void *from, void __iomem *to, int len)
+{
+ rio_copy_toio(to, from, len);
+}
+
+int rio_minor(struct tty_struct *tty)
+{
+ return tty->index + (tty->driver == rio_driver) ? 0 : 256;
+}
+
+static int rio_set_real_termios(void *ptr)
+{
+ return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1);
+}
+
+
+static void rio_reset_interrupt(struct Host *HostP)
+{
+ func_enter();
+
+ switch (HostP->Type) {
+ case RIO_AT:
+ case RIO_MCA:
+ case RIO_PCI:
+ writeb(0xFF, &HostP->ResetInt);
+ }
+
+ func_exit();
+}
+
+
+static irqreturn_t rio_interrupt(int irq, void *ptr)
+{
+ struct Host *HostP;
+ func_enter();
+
+ HostP = ptr; /* &p->RIOHosts[(long)ptr]; */
+ rio_dprintk(RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
+
+ /* AAargh! The order in which to do these things is essential and
+ not trivial.
+
+ - hardware twiddling goes before "recursive". Otherwise when we
+ poll the card, and a recursive interrupt happens, we won't
+ ack the card, so it might keep on interrupting us. (especially
+ level sensitive interrupt systems like PCI).
+
+ - Rate limit goes before hardware twiddling. Otherwise we won't
+ catch a card that has gone bonkers.
+
+ - The "initialized" test goes after the hardware twiddling. Otherwise
+ the card will stick us in the interrupt routine again.
+
+ - The initialized test goes before recursive.
+ */
+
+ rio_dprintk(RIO_DEBUG_IFLOW, "rio: We've have noticed the interrupt\n");
+ if (HostP->Ivec == irq) {
+ /* Tell the card we've noticed the interrupt. */
+ rio_reset_interrupt(HostP);
+ }
+
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING)
+ return IRQ_HANDLED;
+
+ if (test_and_set_bit(RIO_BOARD_INTR_LOCK, &HostP->locks)) {
+ printk(KERN_ERR "Recursive interrupt! (host %p/irq%d)\n", ptr, HostP->Ivec);
+ return IRQ_HANDLED;
+ }
+
+ RIOServiceHost(p, HostP);
+
+ rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", ptr, HostP->Type);
+
+ clear_bit(RIO_BOARD_INTR_LOCK, &HostP->locks);
+ rio_dprintk(RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
+ func_exit();
+ return IRQ_HANDLED;
+}
+
+
+static void rio_pollfunc(unsigned long data)
+{
+ func_enter();
+
+ rio_interrupt(0, &p->RIOHosts[data]);
+ mod_timer(&p->RIOHosts[data].timer, jiffies + rio_poll);
+
+ func_exit();
+}
+
+
+/* ********************************************************************** *
+ * Here are the routines that actually *
+ * interface with the generic_serial driver *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the Specialix
+ cards. .... Hmm. Ok I figured it out. You don't. -- REW */
+
+static void rio_disable_tx_interrupts(void *ptr)
+{
+ func_enter();
+
+ /* port->gs.port.flags &= ~GS_TX_INTEN; */
+
+ func_exit();
+}
+
+
+static void rio_enable_tx_interrupts(void *ptr)
+{
+ struct Port *PortP = ptr;
+ /* int hn; */
+
+ func_enter();
+
+ /* hn = PortP->HostP - p->RIOHosts;
+
+ rio_dprintk (RIO_DEBUG_TTY, "Pushing host %d\n", hn);
+ rio_interrupt (-1,(void *) hn, NULL); */
+
+ RIOTxEnable((char *) PortP);
+
+ /*
+ * In general we cannot count on "tx empty" interrupts, although
+ * the interrupt routine seems to be able to tell the difference.
+ */
+ PortP->gs.port.flags &= ~GS_TX_INTEN;
+
+ func_exit();
+}
+
+
+static void rio_disable_rx_interrupts(void *ptr)
+{
+ func_enter();
+ func_exit();
+}
+
+static void rio_enable_rx_interrupts(void *ptr)
+{
+ /* struct rio_port *port = ptr; */
+ func_enter();
+ func_exit();
+}
+
+
+/* Jeez. Isn't this simple? */
+static int rio_get_CD(void *ptr)
+{
+ struct Port *PortP = ptr;
+ int rv;
+
+ func_enter();
+ rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0;
+
+ rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
+
+ func_exit();
+ return rv;
+}
+
+
+/* Jeez. Isn't this simple? Actually, we can sync with the actual port
+ by just pushing stuff into the queue going to the port... */
+static int rio_chars_in_buffer(void *ptr)
+{
+ func_enter();
+
+ func_exit();
+ return 0;
+}
+
+
+/* Nothing special here... */
+static void rio_shutdown_port(void *ptr)
+{
+ struct Port *PortP;
+
+ func_enter();
+
+ PortP = (struct Port *) ptr;
+ PortP->gs.port.tty = NULL;
+ func_exit();
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+ here. The whole linux serial drivers stuff needs to be redesigned.
+ My guess is that this is a hack to minimize the impact of a bug
+ elsewhere. Thinking about it some more. (try it sometime) Try
+ running minicom on a serial port that is driven by a modularized
+ driver. Have the modem hangup. Then remove the driver module. Then
+ exit minicom. I expect an "oops". -- REW */
+static void rio_hungup(void *ptr)
+{
+ struct Port *PortP;
+
+ func_enter();
+
+ PortP = (struct Port *) ptr;
+ PortP->gs.port.tty = NULL;
+
+ func_exit();
+}
+
+
+/* The standard serial_close would become shorter if you'd wrap it like
+ this.
+ rs_close (...){save_flags;cli;real_close();dec_use_count;restore_flags;}
+ */
+static void rio_close(void *ptr)
+{
+ struct Port *PortP;
+
+ func_enter();
+
+ PortP = (struct Port *) ptr;
+
+ riotclose(ptr);
+
+ if (PortP->gs.port.count) {
+ printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.port.count);
+ PortP->gs.port.count = 0;
+ }
+
+ PortP->gs.port.tty = NULL;
+ func_exit();
+}
+
+
+
+static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+ func_enter();
+
+ /* The "dev" argument isn't used. */
+ lock_kernel();
+ rc = riocontrol(p, 0, cmd, arg, capable(CAP_SYS_ADMIN));
+ unlock_kernel();
+
+ func_exit();
+ return rc;
+}
+
+extern int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg);
+
+static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int rc;
+ struct Port *PortP;
+ int ival;
+
+ func_enter();
+
+ PortP = (struct Port *) tty->driver_data;
+
+ rc = 0;
+ switch (cmd) {
+ case TIOCSSOFTCAR:
+ if ((rc = get_user(ival, (unsigned __user *) argp)) == 0) {
+ tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0);
+ }
+ break;
+ case TIOCGSERIAL:
+ rc = -EFAULT;
+ if (access_ok(VERIFY_WRITE, argp, sizeof(struct serial_struct)))
+ rc = gs_getserial(&PortP->gs, argp);
+ break;
+ case TCSBRK:
+ if (PortP->State & RIO_DELETED) {
+ rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
+ rc = -EIO;
+ } else {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) ==
+ RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
+ rc = -EIO;
+ }
+ }
+ break;
+ case TCSBRKP:
+ if (PortP->State & RIO_DELETED) {
+ rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
+ rc = -EIO;
+ } else {
+ int l;
+ l = arg ? arg * 100 : 250;
+ if (l > 255)
+ l = 255;
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2,
+ arg ? arg * 100 : 250) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
+ rc = -EIO;
+ }
+ }
+ break;
+ case TIOCSSERIAL:
+ rc = -EFAULT;
+ if (access_ok(VERIFY_READ, argp, sizeof(struct serial_struct)))
+ rc = gs_setserial(&PortP->gs, argp);
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+ func_exit();
+ return rc;
+}
+
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation.
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself. This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here. When we come to read characters from the
+ * rx buffers on the card (rio_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in rio_rx_throt[]).
+ * If it can't we simply don't remove chars from the cards buffer.
+ * When the tty layer can accept chars, we again note that here and when
+ * rio_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void rio_throttle(struct tty_struct *tty)
+{
+ struct Port *port = (struct Port *) tty->driver_data;
+
+ func_enter();
+ /* If the port is using any type of input flow
+ * control then throttle the port.
+ */
+
+ if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
+ port->State |= RIO_THROTTLE_RX;
+ }
+
+ func_exit();
+}
+
+
+static void rio_unthrottle(struct tty_struct *tty)
+{
+ struct Port *port = (struct Port *) tty->driver_data;
+
+ func_enter();
+ /* Always unthrottle even if flow control is not enabled on
+ * this port in case we disabled flow control while the port
+ * was throttled
+ */
+
+ port->State &= ~RIO_THROTTLE_RX;
+
+ func_exit();
+ return;
+}
+
+
+
+
+
+/* ********************************************************************** *
+ * Here are the initialization routines. *
+ * ********************************************************************** */
+
+
+static struct vpd_prom *get_VPD_PROM(struct Host *hp)
+{
+ static struct vpd_prom vpdp;
+ char *p;
+ int i;
+
+ func_enter();
+ rio_dprintk(RIO_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", hp->Caddr + RIO_VPD_ROM);
+
+ p = (char *) &vpdp;
+ for (i = 0; i < sizeof(struct vpd_prom); i++)
+ *p++ = readb(hp->Caddr + RIO_VPD_ROM + i * 2);
+ /* read_rio_byte (hp, RIO_VPD_ROM + i*2); */
+
+ /* Terminate the identifier string.
+ *** requires one extra byte in struct vpd_prom *** */
+ *p++ = 0;
+
+ if (rio_debug & RIO_DEBUG_PROBE)
+ my_hd((char *) &vpdp, 0x20);
+
+ func_exit();
+
+ return &vpdp;
+}
+
+static const struct tty_operations rio_ops = {
+ .open = riotopen,
+ .close = gs_close,
+ .write = gs_write,
+ .put_char = gs_put_char,
+ .flush_chars = gs_flush_chars,
+ .write_room = gs_write_room,
+ .chars_in_buffer = gs_chars_in_buffer,
+ .flush_buffer = gs_flush_buffer,
+ .ioctl = rio_ioctl,
+ .throttle = rio_throttle,
+ .unthrottle = rio_unthrottle,
+ .set_termios = gs_set_termios,
+ .stop = gs_stop,
+ .start = gs_start,
+ .hangup = gs_hangup,
+};
+
+static int rio_init_drivers(void)
+{
+ int error = -ENOMEM;
+
+ rio_driver = alloc_tty_driver(256);
+ if (!rio_driver)
+ goto out;
+ rio_driver2 = alloc_tty_driver(256);
+ if (!rio_driver2)
+ goto out1;
+
+ func_enter();
+
+ rio_driver->owner = THIS_MODULE;
+ rio_driver->driver_name = "specialix_rio";
+ rio_driver->name = "ttySR";
+ rio_driver->major = RIO_NORMAL_MAJOR0;
+ rio_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ rio_driver->subtype = SERIAL_TYPE_NORMAL;
+ rio_driver->init_termios = tty_std_termios;
+ rio_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ rio_driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(rio_driver, &rio_ops);
+
+ rio_driver2->owner = THIS_MODULE;
+ rio_driver2->driver_name = "specialix_rio";
+ rio_driver2->name = "ttySR";
+ rio_driver2->major = RIO_NORMAL_MAJOR1;
+ rio_driver2->type = TTY_DRIVER_TYPE_SERIAL;
+ rio_driver2->subtype = SERIAL_TYPE_NORMAL;
+ rio_driver2->init_termios = tty_std_termios;
+ rio_driver2->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ rio_driver2->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(rio_driver2, &rio_ops);
+
+ rio_dprintk(RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios);
+
+ if ((error = tty_register_driver(rio_driver)))
+ goto out2;
+ if ((error = tty_register_driver(rio_driver2)))
+ goto out3;
+ func_exit();
+ return 0;
+ out3:
+ tty_unregister_driver(rio_driver);
+ out2:
+ put_tty_driver(rio_driver2);
+ out1:
+ put_tty_driver(rio_driver);
+ out:
+ printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n", error);
+ return 1;
+}
+
+
+static void *ckmalloc(int size)
+{
+ void *p;
+
+ p = kzalloc(size, GFP_KERNEL);
+ return p;
+}
+
+
+
+static int rio_init_datastructures(void)
+{
+ int i;
+ struct Port *port;
+ func_enter();
+
+ /* Many drivers statically allocate the maximum number of ports
+ There is no reason not to allocate them dynamically. Is there? -- REW */
+ /* However, the RIO driver allows users to configure their first
+ RTA as the ports numbered 504-511. We therefore need to allocate
+ the whole range. :-( -- REW */
+
+#define RI_SZ sizeof(struct rio_info)
+#define HOST_SZ sizeof(struct Host)
+#define PORT_SZ sizeof(struct Port *)
+#define TMIO_SZ sizeof(struct termios *)
+ rio_dprintk(RIO_DEBUG_INIT, "getting : %Zd %Zd %Zd %Zd %Zd bytes\n", RI_SZ, RIO_HOSTS * HOST_SZ, RIO_PORTS * PORT_SZ, RIO_PORTS * TMIO_SZ, RIO_PORTS * TMIO_SZ);
+
+ if (!(p = ckmalloc(RI_SZ)))
+ goto free0;
+ if (!(p->RIOHosts = ckmalloc(RIO_HOSTS * HOST_SZ)))
+ goto free1;
+ if (!(p->RIOPortp = ckmalloc(RIO_PORTS * PORT_SZ)))
+ goto free2;
+ p->RIOConf = RIOConf;
+ rio_dprintk(RIO_DEBUG_INIT, "Got : %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
+
+#if 1
+ for (i = 0; i < RIO_PORTS; i++) {
+ port = p->RIOPortp[i] = ckmalloc(sizeof(struct Port));
+ if (!port) {
+ goto free6;
+ }
+ rio_dprintk(RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
+ port->PortNum = i;
+ port->gs.magic = RIO_MAGIC;
+ port->gs.close_delay = HZ / 2;
+ port->gs.closing_wait = 30 * HZ;
+ port->gs.rd = &rio_real_driver;
+ spin_lock_init(&port->portSem);
+ /*
+ * Initializing wait queue
+ */
+ init_waitqueue_head(&port->gs.port.open_wait);
+ init_waitqueue_head(&port->gs.port.close_wait);
+ }
+#else
+ /* We could postpone initializing them to when they are configured. */
+#endif
+
+
+
+ if (rio_debug & RIO_DEBUG_INIT) {
+ my_hd(&rio_real_driver, sizeof(rio_real_driver));
+ }
+
+
+ func_exit();
+ return 0;
+
+ free6:for (i--; i >= 0; i--)
+ kfree(p->RIOPortp[i]);
+/*free5:
+ free4:
+ free3:*/ kfree(p->RIOPortp);
+ free2:kfree(p->RIOHosts);
+ free1:
+ rio_dprintk(RIO_DEBUG_INIT, "Not enough memory! %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
+ kfree(p);
+ free0:
+ return -ENOMEM;
+}
+
+static void __exit rio_release_drivers(void)
+{
+ func_enter();
+ tty_unregister_driver(rio_driver2);
+ tty_unregister_driver(rio_driver);
+ put_tty_driver(rio_driver2);
+ put_tty_driver(rio_driver);
+ func_exit();
+}
+
+
+#ifdef CONFIG_PCI
+ /* This was written for SX, but applies to RIO too...
+ (including bugs....)
+
+ There is another bit besides Bit 17. Turning that bit off
+ (on boards shipped with the fix in the eeprom) results in a
+ hang on the next access to the card.
+ */
+
+ /********************************************************
+ * Setting bit 17 in the CNTRL register of the PLX 9050 *
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon *
+ * multiprocessor systems with the NX chipset. -- NV *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+ EEprom. As the bit is read/write for the CPU, we can fix it here,
+ if we detect that it isn't set correctly. -- REW */
+
+static void fix_rio_pci(struct pci_dev *pdev)
+{
+ unsigned long hwbase;
+ unsigned char __iomem *rebase;
+ unsigned int t;
+
+#define CNTRL_REG_OFFSET 0x50
+#define CNTRL_REG_GOODVALUE 0x18260000
+
+ hwbase = pci_resource_start(pdev, 0);
+ rebase = ioremap(hwbase, 0x80);
+ t = readl(rebase + CNTRL_REG_OFFSET);
+ if (t != CNTRL_REG_GOODVALUE) {
+ printk(KERN_DEBUG "rio: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE);
+ writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
+ }
+ iounmap(rebase);
+}
+#endif
+
+
+static int __init rio_init(void)
+{
+ int found = 0;
+ int i;
+ struct Host *hp;
+ int retval;
+ struct vpd_prom *vpdp;
+ int okboard;
+
+#ifdef CONFIG_PCI
+ struct pci_dev *pdev = NULL;
+ unsigned short tshort;
+#endif
+
+ func_enter();
+ rio_dprintk(RIO_DEBUG_INIT, "Initing rio module... (rio_debug=%d)\n", rio_debug);
+
+ if (abs((long) (&rio_debug) - rio_debug) < 0x10000) {
+ printk(KERN_WARNING "rio: rio_debug is an address, instead of a value. " "Assuming -1. Was %x/%p.\n", rio_debug, &rio_debug);
+ rio_debug = -1;
+ }
+
+ if (misc_register(&rio_fw_device) < 0) {
+ printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n");
+ return -EIO;
+ }
+
+ retval = rio_init_datastructures();
+ if (retval < 0) {
+ misc_deregister(&rio_fw_device);
+ return retval;
+ }
+#ifdef CONFIG_PCI
+ /* First look for the JET devices: */
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) {
+ u32 tint;
+
+ if (pci_enable_device(pdev))
+ continue;
+
+ /* Specialix has a whole bunch of cards with
+ 0x2000 as the device ID. They say its because
+ the standard requires it. Stupid standard. */
+ /* It seems that reading a word doesn't work reliably on 2.0.
+ Also, reading a non-aligned dword doesn't work. So we read the
+ whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+ ourselves */
+ pci_read_config_dword(pdev, 0x2c, &tint);
+ tshort = (tint >> 16) & 0xffff;
+ rio_dprintk(RIO_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+ if (tshort != 0x0100) {
+ rio_dprintk(RIO_DEBUG_PROBE, "But it's not a RIO card (%d)...\n", tshort);
+ continue;
+ }
+ rio_dprintk(RIO_DEBUG_PROBE, "cp1\n");
+
+ hp = &p->RIOHosts[p->RIONumHosts];
+ hp->PaddrP = pci_resource_start(pdev, 2);
+ hp->Ivec = pdev->irq;
+ if (((1 << hp->Ivec) & rio_irqmask) == 0)
+ hp->Ivec = 0;
+ hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+ hp->CardP = (struct DpRam __iomem *) hp->Caddr;
+ hp->Type = RIO_PCI;
+ hp->Copy = rio_copy_to_card;
+ hp->Mode = RIO_PCI_BOOT_FROM_RAM;
+ spin_lock_init(&hp->HostLock);
+ rio_reset_interrupt(hp);
+ rio_start_card_running(hp);
+
+ rio_dprintk(RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n", (void *) p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr);
+ if (RIOBoardTest(p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr, RIO_PCI, 0) == 0) {
+ rio_dprintk(RIO_DEBUG_INIT, "Done RIOBoardTest\n");
+ writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+ p->RIOHosts[p->RIONumHosts].UniqueNum =
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[0]) & 0xFF) << 0) |
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
+ rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+ fix_rio_pci(pdev);
+
+ p->RIOHosts[p->RIONumHosts].pdev = pdev;
+ pci_dev_get(pdev);
+
+ p->RIOLastPCISearch = 0;
+ p->RIONumHosts++;
+ found++;
+ } else {
+ iounmap(p->RIOHosts[p->RIONumHosts].Caddr);
+ p->RIOHosts[p->RIONumHosts].Caddr = NULL;
+ }
+ }
+
+ /* Then look for the older PCI card.... : */
+
+ /* These older PCI cards have problems (only byte-mode access is
+ supported), which makes them a bit awkward to support.
+ They also have problems sharing interrupts. Be careful.
+ (The driver now refuses to share interrupts for these
+ cards. This should be sufficient).
+ */
+
+ /* Then look for the older RIO/PCI devices: */
+ while ((pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) {
+ if (pci_enable_device(pdev))
+ continue;
+
+#ifdef CONFIG_RIO_OLDPCI
+ hp = &p->RIOHosts[p->RIONumHosts];
+ hp->PaddrP = pci_resource_start(pdev, 0);
+ hp->Ivec = pdev->irq;
+ if (((1 << hp->Ivec) & rio_irqmask) == 0)
+ hp->Ivec = 0;
+ hp->Ivec |= 0x8000; /* Mark as non-sharable */
+ hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+ hp->CardP = (struct DpRam __iomem *) hp->Caddr;
+ hp->Type = RIO_PCI;
+ hp->Copy = rio_copy_to_card;
+ hp->Mode = RIO_PCI_BOOT_FROM_RAM;
+ spin_lock_init(&hp->HostLock);
+
+ rio_dprintk(RIO_DEBUG_PROBE, "Ivec: %x\n", hp->Ivec);
+ rio_dprintk(RIO_DEBUG_PROBE, "Mode: %x\n", hp->Mode);
+
+ rio_reset_interrupt(hp);
+ rio_start_card_running(hp);
+ rio_dprintk(RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n", (void *) p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr);
+ if (RIOBoardTest(p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr, RIO_PCI, 0) == 0) {
+ writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+ p->RIOHosts[p->RIONumHosts].UniqueNum =
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[0]) & 0xFF) << 0) |
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
+ rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+ p->RIOHosts[p->RIONumHosts].pdev = pdev;
+ pci_dev_get(pdev);
+
+ p->RIOLastPCISearch = 0;
+ p->RIONumHosts++;
+ found++;
+ } else {
+ iounmap(p->RIOHosts[p->RIONumHosts].Caddr);
+ p->RIOHosts[p->RIONumHosts].Caddr = NULL;
+ }
+#else
+ printk(KERN_ERR "Found an older RIO PCI card, but the driver is not " "compiled to support it.\n");
+#endif
+ }
+#endif /* PCI */
+
+ /* Now probe for ISA cards... */
+ for (i = 0; i < NR_RIO_ADDRS; i++) {
+ hp = &p->RIOHosts[p->RIONumHosts];
+ hp->PaddrP = rio_probe_addrs[i];
+ /* There was something about the IRQs of these cards. 'Forget what.--REW */
+ hp->Ivec = 0;
+ hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+ hp->CardP = (struct DpRam __iomem *) hp->Caddr;
+ hp->Type = RIO_AT;
+ hp->Copy = rio_copy_to_card; /* AT card PCI???? - PVDL
+ * -- YES! this is now a normal copy. Only the
+ * old PCI card uses the special PCI copy.
+ * Moreover, the ISA card will work with the
+ * special PCI copy anyway. -- REW */
+ hp->Mode = 0;
+ spin_lock_init(&hp->HostLock);
+
+ vpdp = get_VPD_PROM(hp);
+ rio_dprintk(RIO_DEBUG_PROBE, "Got VPD ROM\n");
+ okboard = 0;
+ if ((strncmp(vpdp->identifier, RIO_ISA_IDENT, 16) == 0) || (strncmp(vpdp->identifier, RIO_ISA2_IDENT, 16) == 0) || (strncmp(vpdp->identifier, RIO_ISA3_IDENT, 16) == 0)) {
+ /* Board is present... */
+ if (RIOBoardTest(hp->PaddrP, hp->Caddr, RIO_AT, 0) == 0) {
+ /* ... and feeling fine!!!! */
+ rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+ if (RIOAssignAT(p, hp->PaddrP, hp->Caddr, 0)) {
+ rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, host%d uniqid = %x.\n", p->RIONumHosts, p->RIOHosts[p->RIONumHosts - 1].UniqueNum);
+ okboard++;
+ found++;
+ }
+ }
+
+ if (!okboard) {
+ iounmap(hp->Caddr);
+ hp->Caddr = NULL;
+ }
+ }
+ }
+
+
+ for (i = 0; i < p->RIONumHosts; i++) {
+ hp = &p->RIOHosts[i];
+ if (hp->Ivec) {
+ int mode = IRQF_SHARED;
+ if (hp->Ivec & 0x8000) {
+ mode = 0;
+ hp->Ivec &= 0x7fff;
+ }
+ rio_dprintk(RIO_DEBUG_INIT, "Requesting interrupt hp: %p rio_interrupt: %d Mode: %x\n", hp, hp->Ivec, hp->Mode);
+ retval = request_irq(hp->Ivec, rio_interrupt, mode, "rio", hp);
+ rio_dprintk(RIO_DEBUG_INIT, "Return value from request_irq: %d\n", retval);
+ if (retval) {
+ printk(KERN_ERR "rio: Cannot allocate irq %d.\n", hp->Ivec);
+ hp->Ivec = 0;
+ }
+ rio_dprintk(RIO_DEBUG_INIT, "Got irq %d.\n", hp->Ivec);
+ if (hp->Ivec != 0) {
+ rio_dprintk(RIO_DEBUG_INIT, "Enabling interrupts on rio card.\n");
+ hp->Mode |= RIO_PCI_INT_ENABLE;
+ } else
+ hp->Mode &= ~RIO_PCI_INT_ENABLE;
+ rio_dprintk(RIO_DEBUG_INIT, "New Mode: %x\n", hp->Mode);
+ rio_start_card_running(hp);
+ }
+ /* Init the timer "always" to make sure that it can safely be
+ deleted when we unload... */
+
+ setup_timer(&hp->timer, rio_pollfunc, i);
+ if (!hp->Ivec) {
+ rio_dprintk(RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", rio_poll);
+ mod_timer(&hp->timer, jiffies + rio_poll);
+ }
+ }
+
+ if (found) {
+ rio_dprintk(RIO_DEBUG_INIT, "rio: total of %d boards detected.\n", found);
+ rio_init_drivers();
+ } else {
+ /* deregister the misc device we created earlier */
+ misc_deregister(&rio_fw_device);
+ }
+
+ func_exit();
+ return found ? 0 : -EIO;
+}
+
+
+static void __exit rio_exit(void)
+{
+ int i;
+ struct Host *hp;
+
+ func_enter();
+
+ for (i = 0, hp = p->RIOHosts; i < p->RIONumHosts; i++, hp++) {
+ RIOHostReset(hp->Type, hp->CardP, hp->Slot);
+ if (hp->Ivec) {
+ free_irq(hp->Ivec, hp);
+ rio_dprintk(RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec);
+ }
+ /* It is safe/allowed to del_timer a non-active timer */
+ del_timer_sync(&hp->timer);
+ if (hp->Caddr)
+ iounmap(hp->Caddr);
+ if (hp->Type == RIO_PCI)
+ pci_dev_put(hp->pdev);
+ }
+
+ if (misc_deregister(&rio_fw_device) < 0) {
+ printk(KERN_INFO "rio: couldn't deregister control-device\n");
+ }
+
+
+ rio_dprintk(RIO_DEBUG_CLEANUP, "Cleaning up drivers\n");
+
+ rio_release_drivers();
+
+ /* Release dynamically allocated memory */
+ kfree(p->RIOPortp);
+ kfree(p->RIOHosts);
+ kfree(p);
+
+ func_exit();
+}
+
+module_init(rio_init);
+module_exit(rio_exit);
diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h
new file mode 100644
index 0000000..7f26cd7
--- /dev/null
+++ b/drivers/char/rio/rio_linux.h
@@ -0,0 +1,197 @@
+
+/*
+ * rio_linux.h
+ *
+ * Copyright (C) 1998,1999,2000 R.E.Wolff@BitWizard.nl
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * RIO serial driver.
+ *
+ * Version 1.0 -- July, 1999.
+ *
+ */
+
+#define RIO_NBOARDS 4
+#define RIO_PORTSPERBOARD 128
+#define RIO_NPORTS (RIO_NBOARDS * RIO_PORTSPERBOARD)
+
+#define MODEM_SUPPORT
+
+#ifdef __KERNEL__
+
+#define RIO_MAGIC 0x12345678
+
+
+struct vpd_prom {
+ unsigned short id;
+ char hwrev;
+ char hwass;
+ int uniqid;
+ char myear;
+ char mweek;
+ char hw_feature[5];
+ char oem_id;
+ char identifier[16];
+};
+
+
+#define RIO_DEBUG_ALL 0xffffffff
+
+#define O_OTHER(tty) \
+ ((O_OLCUC(tty)) ||\
+ (O_ONLCR(tty)) ||\
+ (O_OCRNL(tty)) ||\
+ (O_ONOCR(tty)) ||\
+ (O_ONLRET(tty)) ||\
+ (O_OFILL(tty)) ||\
+ (O_OFDEL(tty)) ||\
+ (O_NLDLY(tty)) ||\
+ (O_CRDLY(tty)) ||\
+ (O_TABDLY(tty)) ||\
+ (O_BSDLY(tty)) ||\
+ (O_VTDLY(tty)) ||\
+ (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty) \
+ ((I_INLCR(tty)) ||\
+ (I_IGNCR(tty)) ||\
+ (I_ICRNL(tty)) ||\
+ (I_IUCLC(tty)) ||\
+ (L_ISIG(tty)))
+
+
+#endif /* __KERNEL__ */
+
+
+#define RIO_BOARD_INTR_LOCK 1
+
+
+#ifndef RIOCTL_MISC_MINOR
+/* Allow others to gather this into "major.h" or something like that */
+#define RIOCTL_MISC_MINOR 169
+#endif
+
+
+/* Allow us to debug "in the field" without requiring clients to
+ recompile.... */
+#if 1
+#define rio_spin_lock_irqsave(sem, flags) do { \
+ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \
+ sem, __FILE__, __LINE__);\
+ spin_lock_irqsave(sem, flags);\
+ } while (0)
+
+#define rio_spin_unlock_irqrestore(sem, flags) do { \
+ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\
+ sem, __FILE__, __LINE__);\
+ spin_unlock_irqrestore(sem, flags);\
+ } while (0)
+
+#define rio_spin_lock(sem) do { \
+ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\
+ sem, __FILE__, __LINE__);\
+ spin_lock(sem);\
+ } while (0)
+
+#define rio_spin_unlock(sem) do { \
+ rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlock: %p %s:%d\n",\
+ sem, __FILE__, __LINE__);\
+ spin_unlock(sem);\
+ } while (0)
+#else
+#define rio_spin_lock_irqsave(sem, flags) \
+ spin_lock_irqsave(sem, flags)
+
+#define rio_spin_unlock_irqrestore(sem, flags) \
+ spin_unlock_irqrestore(sem, flags)
+
+#define rio_spin_lock(sem) \
+ spin_lock(sem)
+
+#define rio_spin_unlock(sem) \
+ spin_unlock(sem)
+
+#endif
+
+
+
+#ifdef CONFIG_RIO_OLDPCI
+static inline void __iomem *rio_memcpy_toio(void __iomem *dummy, void __iomem *dest, void *source, int n)
+{
+ char __iomem *dst = dest;
+ char *src = source;
+
+ while (n--) {
+ writeb(*src++, dst++);
+ (void) readb(dummy);
+ }
+
+ return dest;
+}
+
+static inline void __iomem *rio_copy_toio(void __iomem *dest, void *source, int n)
+{
+ char __iomem *dst = dest;
+ char *src = source;
+
+ while (n--)
+ writeb(*src++, dst++);
+
+ return dest;
+}
+
+
+static inline void *rio_memcpy_fromio(void *dest, void __iomem *source, int n)
+{
+ char *dst = dest;
+ char __iomem *src = source;
+
+ while (n--)
+ *dst++ = readb(src++);
+
+ return dest;
+}
+
+#else
+#define rio_memcpy_toio(dummy,dest,source,n) memcpy_toio(dest, source, n)
+#define rio_copy_toio memcpy_toio
+#define rio_memcpy_fromio memcpy_fromio
+#endif
+
+#define DEBUG 1
+
+
+/*
+ This driver can spew a whole lot of debugging output at you. If you
+ need maximum performance, you should disable the DEBUG define. To
+ aid in debugging in the field, I'm leaving the compile-time debug
+ features enabled, and disable them "runtime". That allows me to
+ instruct people with problems to enable debugging without requiring
+ them to recompile...
+*/
+
+#ifdef DEBUG
+#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0)
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __func__)
+#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __func__)
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__func__, port->line)
+#else
+#define rio_dprintk(f, str...) /* nothing */
+#define func_enter()
+#define func_exit()
+#define func_enter2()
+#endif
diff --git a/drivers/char/rio/rioboard.h b/drivers/char/rio/rioboard.h
new file mode 100644
index 0000000..2522300
--- /dev/null
+++ b/drivers/char/rio/rioboard.h
@@ -0,0 +1,275 @@
+/************************************************************************/
+/* */
+/* Title : RIO Host Card Hardware Definitions */
+/* */
+/* Author : N.P.Vassallo */
+/* */
+/* Creation : 26th April 1999 */
+/* */
+/* Version : 1.0.0 */
+/* */
+/* Copyright : (c) Specialix International Ltd. 1999 *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * */
+/* Description : Prototypes, structures and definitions */
+/* describing the RIO board hardware */
+/* */
+/************************************************************************/
+
+#ifndef _rioboard_h /* If RIOBOARD.H not already defined */
+#define _rioboard_h 1
+
+/*****************************************************************************
+*********************** ***********************
+*********************** Hardware Control Registers ***********************
+*********************** ***********************
+*****************************************************************************/
+
+/* Hardware Registers... */
+
+#define RIO_REG_BASE 0x7C00 /* Base of control registers */
+
+#define RIO_CONFIG RIO_REG_BASE + 0x0000 /* WRITE: Configuration Register */
+#define RIO_INTSET RIO_REG_BASE + 0x0080 /* WRITE: Interrupt Set */
+#define RIO_RESET RIO_REG_BASE + 0x0100 /* WRITE: Host Reset */
+#define RIO_INTRESET RIO_REG_BASE + 0x0180 /* WRITE: Interrupt Reset */
+
+#define RIO_VPD_ROM RIO_REG_BASE + 0x0000 /* READ: Vital Product Data ROM */
+#define RIO_INTSTAT RIO_REG_BASE + 0x0080 /* READ: Interrupt Status (Jet boards only) */
+#define RIO_RESETSTAT RIO_REG_BASE + 0x0100 /* READ: Reset Status (Jet boards only) */
+
+/* RIO_VPD_ROM definitions... */
+#define VPD_SLX_ID1 0x00 /* READ: Specialix Identifier #1 */
+#define VPD_SLX_ID2 0x01 /* READ: Specialix Identifier #2 */
+#define VPD_HW_REV 0x02 /* READ: Hardware Revision */
+#define VPD_HW_ASSEM 0x03 /* READ: Hardware Assembly Level */
+#define VPD_UNIQUEID4 0x04 /* READ: Unique Identifier #4 */
+#define VPD_UNIQUEID3 0x05 /* READ: Unique Identifier #3 */
+#define VPD_UNIQUEID2 0x06 /* READ: Unique Identifier #2 */
+#define VPD_UNIQUEID1 0x07 /* READ: Unique Identifier #1 */
+#define VPD_MANU_YEAR 0x08 /* READ: Year Of Manufacture (0 = 1970) */
+#define VPD_MANU_WEEK 0x09 /* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define VPD_HWFEATURE1 0x0A /* READ: Hardware Feature Byte 1 */
+#define VPD_HWFEATURE2 0x0B /* READ: Hardware Feature Byte 2 */
+#define VPD_HWFEATURE3 0x0C /* READ: Hardware Feature Byte 3 */
+#define VPD_HWFEATURE4 0x0D /* READ: Hardware Feature Byte 4 */
+#define VPD_HWFEATURE5 0x0E /* READ: Hardware Feature Byte 5 */
+#define VPD_OEMID 0x0F /* READ: OEM Identifier */
+#define VPD_IDENT 0x10 /* READ: Identifier string (16 bytes) */
+#define VPD_IDENT_LEN 0x10
+
+/* VPD ROM Definitions... */
+#define SLX_ID1 0x4D
+#define SLX_ID2 0x98
+
+#define PRODUCT_ID(a) ((a>>4)&0xF) /* Use to obtain Product ID from VPD_UNIQUEID1 */
+
+#define ID_SX_ISA 0x2
+#define ID_RIO_EISA 0x3
+#define ID_SX_PCI 0x5
+#define ID_SX_EISA 0x7
+#define ID_RIO_RTA16 0x9
+#define ID_RIO_ISA 0xA
+#define ID_RIO_MCA 0xB
+#define ID_RIO_SBUS 0xC
+#define ID_RIO_PCI 0xD
+#define ID_RIO_RTA8 0xE
+
+/* Transputer bootstrap definitions... */
+
+#define BOOTLOADADDR (0x8000 - 6)
+#define BOOTINDICATE (0x8000 - 2)
+
+/* Firmware load position... */
+
+#define FIRMWARELOADADDR 0x7C00 /* Firmware is loaded _before_ this address */
+
+/*****************************************************************************
+***************************** *****************************
+***************************** RIO (Rev1) ISA *****************************
+***************************** *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_ISA_IDENT "JBJGPGGHINSMJPJR"
+
+#define RIO_ISA_CFG_BOOTRAM 0x01 /* Boot from RAM, else Link */
+#define RIO_ISA_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_ISA_CFG_IRQMASK 0x30 /* Interrupt mask */
+#define RIO_ISA_CFG_IRQ12 0x10 /* Interrupt Level 12 */
+#define RIO_ISA_CFG_IRQ11 0x20 /* Interrupt Level 11 */
+#define RIO_ISA_CFG_IRQ9 0x30 /* Interrupt Level 9 */
+#define RIO_ISA_CFG_LINK20 0x40 /* 20Mbps link, else 10Mbps */
+#define RIO_ISA_CFG_WAITSTATE0 0x80 /* 0 waitstates, else 1 */
+
+/*****************************************************************************
+***************************** *****************************
+***************************** RIO (Rev2) ISA *****************************
+***************************** *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_ISA2_IDENT "JBJGPGGHINSMJPJR"
+
+#define RIO_ISA2_CFG_BOOTRAM 0x01 /* Boot from RAM, else Link */
+#define RIO_ISA2_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_ISA2_CFG_INTENABLE 0x04 /* Interrupt enable, else disable */
+#define RIO_ISA2_CFG_16BIT 0x08 /* 16bit mode, else 8bit */
+#define RIO_ISA2_CFG_IRQMASK 0x30 /* Interrupt mask */
+#define RIO_ISA2_CFG_IRQ15 0x00 /* Interrupt Level 15 */
+#define RIO_ISA2_CFG_IRQ12 0x10 /* Interrupt Level 12 */
+#define RIO_ISA2_CFG_IRQ11 0x20 /* Interrupt Level 11 */
+#define RIO_ISA2_CFG_IRQ9 0x30 /* Interrupt Level 9 */
+#define RIO_ISA2_CFG_LINK20 0x40 /* 20Mbps link, else 10Mbps */
+#define RIO_ISA2_CFG_WAITSTATE0 0x80 /* 0 waitstates, else 1 */
+
+/*****************************************************************************
+***************************** ******************************
+***************************** RIO (Jet) ISA ******************************
+***************************** ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_ISA3_IDENT "JET HOST BY KEV#"
+
+#define RIO_ISA3_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_ISA3_CFG_INTENABLE 0x04 /* Interrupt enable, else disable */
+#define RIO_ISA32_CFG_IRQMASK 0xF30 /* Interrupt mask */
+#define RIO_ISA3_CFG_IRQ15 0xF0 /* Interrupt Level 15 */
+#define RIO_ISA3_CFG_IRQ12 0xC0 /* Interrupt Level 12 */
+#define RIO_ISA3_CFG_IRQ11 0xB0 /* Interrupt Level 11 */
+#define RIO_ISA3_CFG_IRQ10 0xA0 /* Interrupt Level 10 */
+#define RIO_ISA3_CFG_IRQ9 0x90 /* Interrupt Level 9 */
+
+/*****************************************************************************
+********************************* ********************************
+********************************* RIO MCA ********************************
+********************************* ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_MCA_IDENT "JBJGPGGHINSMJPJR"
+
+#define RIO_MCA_CFG_BOOTRAM 0x01 /* Boot from RAM, else Link */
+#define RIO_MCA_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_MCA_CFG_LINK20 0x40 /* 20Mbps link, else 10Mbps */
+
+/*****************************************************************************
+******************************** ********************************
+******************************** RIO EISA ********************************
+******************************** ********************************
+*****************************************************************************/
+
+/* EISA Configuration Space Definitions... */
+#define EISA_PRODUCT_ID1 0xC80
+#define EISA_PRODUCT_ID2 0xC81
+#define EISA_PRODUCT_NUMBER 0xC82
+#define EISA_REVISION_NUMBER 0xC83
+#define EISA_CARD_ENABLE 0xC84
+#define EISA_VPD_UNIQUEID4 0xC88 /* READ: Unique Identifier #4 */
+#define EISA_VPD_UNIQUEID3 0xC8A /* READ: Unique Identifier #3 */
+#define EISA_VPD_UNIQUEID2 0xC90 /* READ: Unique Identifier #2 */
+#define EISA_VPD_UNIQUEID1 0xC92 /* READ: Unique Identifier #1 */
+#define EISA_VPD_MANU_YEAR 0xC98 /* READ: Year Of Manufacture (0 = 1970) */
+#define EISA_VPD_MANU_WEEK 0xC9A /* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define EISA_MEM_ADDR_23_16 0xC00
+#define EISA_MEM_ADDR_31_24 0xC01
+#define EISA_RIO_CONFIG 0xC02 /* WRITE: Configuration Register */
+#define EISA_RIO_INTSET 0xC03 /* WRITE: Interrupt Set */
+#define EISA_RIO_INTRESET 0xC03 /* READ: Interrupt Reset */
+
+/* Control Register Definitions... */
+#define RIO_EISA_CFG_BOOTRAM 0x01 /* Boot from RAM, else Link */
+#define RIO_EISA_CFG_LINK20 0x02 /* 20Mbps link, else 10Mbps */
+#define RIO_EISA_CFG_BUSENABLE 0x04 /* Enable processor bus */
+#define RIO_EISA_CFG_PROCRUN 0x08 /* Processor running, else reset */
+#define RIO_EISA_CFG_IRQMASK 0xF0 /* Interrupt mask */
+#define RIO_EISA_CFG_IRQ15 0xF0 /* Interrupt Level 15 */
+#define RIO_EISA_CFG_IRQ14 0xE0 /* Interrupt Level 14 */
+#define RIO_EISA_CFG_IRQ12 0xC0 /* Interrupt Level 12 */
+#define RIO_EISA_CFG_IRQ11 0xB0 /* Interrupt Level 11 */
+#define RIO_EISA_CFG_IRQ10 0xA0 /* Interrupt Level 10 */
+#define RIO_EISA_CFG_IRQ9 0x90 /* Interrupt Level 9 */
+#define RIO_EISA_CFG_IRQ7 0x70 /* Interrupt Level 7 */
+#define RIO_EISA_CFG_IRQ6 0x60 /* Interrupt Level 6 */
+#define RIO_EISA_CFG_IRQ5 0x50 /* Interrupt Level 5 */
+#define RIO_EISA_CFG_IRQ4 0x40 /* Interrupt Level 4 */
+#define RIO_EISA_CFG_IRQ3 0x30 /* Interrupt Level 3 */
+
+/*****************************************************************************
+******************************** ********************************
+******************************** RIO SBus ********************************
+******************************** ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_SBUS_IDENT "JBPGK#\0\0\0\0\0\0\0\0\0\0"
+
+#define RIO_SBUS_CFG_BOOTRAM 0x01 /* Boot from RAM, else Link */
+#define RIO_SBUS_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_SBUS_CFG_INTENABLE 0x04 /* Interrupt enable, else disable */
+#define RIO_SBUS_CFG_IRQMASK 0x38 /* Interrupt mask */
+#define RIO_SBUS_CFG_IRQNONE 0x00 /* No Interrupt */
+#define RIO_SBUS_CFG_IRQ7 0x38 /* Interrupt Level 7 */
+#define RIO_SBUS_CFG_IRQ6 0x30 /* Interrupt Level 6 */
+#define RIO_SBUS_CFG_IRQ5 0x28 /* Interrupt Level 5 */
+#define RIO_SBUS_CFG_IRQ4 0x20 /* Interrupt Level 4 */
+#define RIO_SBUS_CFG_IRQ3 0x18 /* Interrupt Level 3 */
+#define RIO_SBUS_CFG_IRQ2 0x10 /* Interrupt Level 2 */
+#define RIO_SBUS_CFG_IRQ1 0x08 /* Interrupt Level 1 */
+#define RIO_SBUS_CFG_LINK20 0x40 /* 20Mbps link, else 10Mbps */
+#define RIO_SBUS_CFG_PROC25 0x80 /* 25Mhz processor clock, else 20Mhz */
+
+/*****************************************************************************
+********************************* ********************************
+********************************* RIO PCI ********************************
+********************************* ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_PCI_IDENT "ECDDPGJGJHJRGSK#"
+
+#define RIO_PCI_CFG_BOOTRAM 0x01 /* Boot from RAM, else Link */
+#define RIO_PCI_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_PCI_CFG_INTENABLE 0x04 /* Interrupt enable, else disable */
+#define RIO_PCI_CFG_LINK20 0x40 /* 20Mbps link, else 10Mbps */
+#define RIO_PCI_CFG_PROC25 0x80 /* 25Mhz processor clock, else 20Mhz */
+
+/* PCI Definitions... */
+#define SPX_VENDOR_ID 0x11CB /* Assigned by the PCI SIG */
+#define SPX_DEVICE_ID 0x8000 /* RIO bridge boards */
+#define SPX_PLXDEVICE_ID 0x2000 /* PLX bridge boards */
+#define SPX_SUB_VENDOR_ID SPX_VENDOR_ID /* Same as vendor id */
+#define RIO_SUB_SYS_ID 0x0800 /* RIO PCI board */
+
+/*****************************************************************************
+***************************** ******************************
+***************************** RIO (Jet) PCI ******************************
+***************************** ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define RIO_PCI2_IDENT "JET HOST BY KEV#"
+
+#define RIO_PCI2_CFG_BUSENABLE 0x02 /* Enable processor bus */
+#define RIO_PCI2_CFG_INTENABLE 0x04 /* Interrupt enable, else disable */
+
+/* PCI Definitions... */
+#define RIO2_SUB_SYS_ID 0x0100 /* RIO (Jet) PCI board */
+
+#endif /*_rioboard_h */
+
+/* End of RIOBOARD.H */
diff --git a/drivers/char/rio/rioboot.c b/drivers/char/rio/rioboot.c
new file mode 100644
index 0000000..d956dd3
--- /dev/null
+++ b/drivers/char/rio/rioboot.c
@@ -0,0 +1,1113 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioboot.c
+** SID : 1.3
+** Last Modified : 11/6/98 10:33:36
+** Retrieved : 11/6/98 10:33:48
+**
+** ident @(#)rioboot.c 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/serial.h>
+#include <linux/vmalloc.h>
+#include <linux/generic_serial.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+
+static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP);
+
+static const unsigned char RIOAtVec2Ctrl[] = {
+ /* 0 */ INTERRUPT_DISABLE,
+ /* 1 */ INTERRUPT_DISABLE,
+ /* 2 */ INTERRUPT_DISABLE,
+ /* 3 */ INTERRUPT_DISABLE,
+ /* 4 */ INTERRUPT_DISABLE,
+ /* 5 */ INTERRUPT_DISABLE,
+ /* 6 */ INTERRUPT_DISABLE,
+ /* 7 */ INTERRUPT_DISABLE,
+ /* 8 */ INTERRUPT_DISABLE,
+ /* 9 */ IRQ_9 | INTERRUPT_ENABLE,
+ /* 10 */ INTERRUPT_DISABLE,
+ /* 11 */ IRQ_11 | INTERRUPT_ENABLE,
+ /* 12 */ IRQ_12 | INTERRUPT_ENABLE,
+ /* 13 */ INTERRUPT_DISABLE,
+ /* 14 */ INTERRUPT_DISABLE,
+ /* 15 */ IRQ_15 | INTERRUPT_ENABLE
+};
+
+/**
+ * RIOBootCodeRTA - Load RTA boot code
+ * @p: RIO to load
+ * @rbp: Download descriptor
+ *
+ * Called when the user process initiates booting of the card firmware.
+ * Lads the firmware
+ */
+
+int RIOBootCodeRTA(struct rio_info *p, struct DownLoad * rbp)
+{
+ int offset;
+
+ func_enter();
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Data at user address %p\n", rbp->DataP);
+
+ /*
+ ** Check that we have set asside enough memory for this
+ */
+ if (rbp->Count > SIXTY_FOUR_K) {
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n");
+ p->RIOError.Error = HOST_FILE_TOO_LARGE;
+ func_exit();
+ return -ENOMEM;
+ }
+
+ if (p->RIOBooting) {
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n");
+ p->RIOError.Error = BOOT_IN_PROGRESS;
+ func_exit();
+ return -EBUSY;
+ }
+
+ /*
+ ** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary,
+ ** so calculate how far we have to move the data up the buffer
+ ** to achieve this.
+ */
+ offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % RTA_BOOT_DATA_SIZE;
+
+ /*
+ ** Be clean, and clear the 'unused' portion of the boot buffer,
+ ** because it will (eventually) be part of the Rta run time environment
+ ** and so should be zeroed.
+ */
+ memset(p->RIOBootPackets, 0, offset);
+
+ /*
+ ** Copy the data from user space into the array
+ */
+
+ if (copy_from_user(((u8 *)p->RIOBootPackets) + offset, rbp->DataP, rbp->Count)) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Bad data copy from user space\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ func_exit();
+ return -EFAULT;
+ }
+
+ /*
+ ** Make sure that our copy of the size includes that offset we discussed
+ ** earlier.
+ */
+ p->RIONumBootPkts = (rbp->Count + offset) / RTA_BOOT_DATA_SIZE;
+ p->RIOBootCount = rbp->Count;
+
+ func_exit();
+ return 0;
+}
+
+/**
+ * rio_start_card_running - host card start
+ * @HostP: The RIO to kick off
+ *
+ * Start a RIO processor unit running. Encapsulates the knowledge
+ * of the card type.
+ */
+
+void rio_start_card_running(struct Host *HostP)
+{
+ switch (HostP->Type) {
+ case RIO_AT:
+ rio_dprintk(RIO_DEBUG_BOOT, "Start ISA card running\n");
+ writeb(BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode | RIOAtVec2Ctrl[HostP->Ivec & 0xF], &HostP->Control);
+ break;
+ case RIO_PCI:
+ /*
+ ** PCI is much the same as MCA. Everything is once again memory
+ ** mapped, so we are writing to memory registers instead of io
+ ** ports.
+ */
+ rio_dprintk(RIO_DEBUG_BOOT, "Start PCI card running\n");
+ writeb(PCITpBootFromRam | PCITpBusEnable | HostP->Mode, &HostP->Control);
+ break;
+ default:
+ rio_dprintk(RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type);
+ break;
+ }
+ return;
+}
+
+/*
+** Load in the host boot code - load it directly onto all halted hosts
+** of the correct type.
+**
+** Put your rubber pants on before messing with this code - even the magic
+** numbers have trouble understanding what they are doing here.
+*/
+
+int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp)
+{
+ struct Host *HostP;
+ u8 __iomem *Cad;
+ PARM_MAP __iomem *ParmMapP;
+ int RupN;
+ int PortN;
+ unsigned int host;
+ u8 __iomem *StartP;
+ u8 __iomem *DestP;
+ int wait_count;
+ u16 OldParmMap;
+ u16 offset; /* It is very important that this is a u16 */
+ u8 *DownCode = NULL;
+ unsigned long flags;
+
+ HostP = NULL; /* Assure the compiler we've initialized it */
+
+
+ /* Walk the hosts */
+ for (host = 0; host < p->RIONumHosts; host++) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Attempt to boot host %d\n", host);
+ HostP = &p->RIOHosts[host];
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);
+
+ /* Don't boot hosts already running */
+ if ((HostP->Flags & RUN_STATE) != RC_WAITING) {
+ rio_dprintk(RIO_DEBUG_BOOT, "%s %d already running\n", "Host", host);
+ continue;
+ }
+
+ /*
+ ** Grab a pointer to the card (ioremapped)
+ */
+ Cad = HostP->Caddr;
+
+ /*
+ ** We are going to (try) and load in rbp->Count bytes.
+ ** The last byte will reside at p->RIOConf.HostLoadBase-1;
+ ** Therefore, we need to start copying at address
+ ** (caddr+p->RIOConf.HostLoadBase-rbp->Count)
+ */
+ StartP = &Cad[p->RIOConf.HostLoadBase - rbp->Count];
+
+ rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for host is %p\n", Cad);
+ rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for download is %p\n", StartP);
+ rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase);
+ rio_dprintk(RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count);
+
+ /* Make sure it fits */
+ if (p->RIOConf.HostLoadBase < rbp->Count) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Bin too large\n");
+ p->RIOError.Error = HOST_FILE_TOO_LARGE;
+ func_exit();
+ return -EFBIG;
+ }
+ /*
+ ** Ensure that the host really is stopped.
+ ** Disable it's external bus & twang its reset line.
+ */
+ RIOHostReset(HostP->Type, HostP->CardP, HostP->Slot);
+
+ /*
+ ** Copy the data directly from user space to the SRAM.
+ ** This ain't going to be none too clever if the download
+ ** code is bigger than this segment.
+ */
+ rio_dprintk(RIO_DEBUG_BOOT, "Copy in code\n");
+
+ /* Buffer to local memory as we want to use I/O space and
+ some cards only do 8 or 16 bit I/O */
+
+ DownCode = vmalloc(rbp->Count);
+ if (!DownCode) {
+ p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;
+ func_exit();
+ return -ENOMEM;
+ }
+ if (copy_from_user(DownCode, rbp->DataP, rbp->Count)) {
+ kfree(DownCode);
+ p->RIOError.Error = COPYIN_FAILED;
+ func_exit();
+ return -EFAULT;
+ }
+ HostP->Copy(DownCode, StartP, rbp->Count);
+ vfree(DownCode);
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Copy completed\n");
+
+ /*
+ ** S T O P !
+ **
+ ** Upto this point the code has been fairly rational, and possibly
+ ** even straight forward. What follows is a pile of crud that will
+ ** magically turn into six bytes of transputer assembler. Normally
+ ** you would expect an array or something, but, being me, I have
+ ** chosen [been told] to use a technique whereby the startup code
+ ** will be correct if we change the loadbase for the code. Which
+ ** brings us onto another issue - the loadbase is the *end* of the
+ ** code, not the start.
+ **
+ ** If I were you I wouldn't start from here.
+ */
+
+ /*
+ ** We now need to insert a short boot section into
+ ** the memory at the end of Sram2. This is normally (de)composed
+ ** of the last eight bytes of the download code. The
+ ** download has been assembled/compiled to expect to be
+ ** loaded from 0x7FFF downwards. We have loaded it
+ ** at some other address. The startup code goes into the small
+ ** ram window at Sram2, in the last 8 bytes, which are really
+ ** at addresses 0x7FF8-0x7FFF.
+ **
+ ** If the loadbase is, say, 0x7C00, then we need to branch to
+ ** address 0x7BFE to run the host.bin startup code. We assemble
+ ** this jump manually.
+ **
+ ** The two byte sequence 60 08 is loaded into memory at address
+ ** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0,
+ ** which adds '0' to the .O register, complements .O, and then shifts
+ ** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will
+ ** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new
+ ** location. Now, the branch starts from the value of .PC (or .IP or
+ ** whatever the bloody register is called on this chip), and the .PC
+ ** will be pointing to the location AFTER the branch, in this case
+ ** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8.
+ **
+ ** A long branch is coded at 0x7FF8. This consists of loading a four
+ ** byte offset into .O using nfix (as above) and pfix operators. The
+ ** pfix operates in exactly the same way as the nfix operator, but
+ ** without the complement operation. The offset, of course, must be
+ ** relative to the address of the byte AFTER the branch instruction,
+ ** which will be (urm) 0x7FFC, so, our final destination of the branch
+ ** (loadbase-2), has to be reached from here. Imagine that the loadbase
+ ** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which
+ ** is the first byte of the initial two byte short local branch of the
+ ** download code).
+ **
+ ** To code a jump from 0x7FFC (which is where the branch will start
+ ** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)=
+ ** 0x7BFE.
+ ** This will be coded as four bytes:
+ ** 60 2C 20 02
+ ** being nfix .O+0
+ ** pfix .O+C
+ ** pfix .O+0
+ ** jump .O+2
+ **
+ ** The nfix operator is used, so that the startup code will be
+ ** compatible with the whole Tp family. (lies, damn lies, it'll never
+ ** work in a month of Sundays).
+ **
+ ** The nfix nyble is the 1s complement of the nyble value you
+ ** want to load - in this case we wanted 'F' so we nfix loaded '0'.
+ */
+
+
+ /*
+ ** Dest points to the top 8 bytes of Sram2. The Tp jumps
+ ** to 0x7FFE at reset time, and starts executing. This is
+ ** a short branch to 0x7FF8, where a long branch is coded.
+ */
+
+ DestP = &Cad[0x7FF8]; /* <<<---- READ THE ABOVE COMMENTS */
+
+#define NFIX(N) (0x60 | (N)) /* .O = (~(.O + N))<<4 */
+#define PFIX(N) (0x20 | (N)) /* .O = (.O + N)<<4 */
+#define JUMP(N) (0x00 | (N)) /* .PC = .PC + .O */
+
+ /*
+ ** 0x7FFC is the address of the location following the last byte of
+ ** the four byte jump instruction.
+ ** READ THE ABOVE COMMENTS
+ **
+ ** offset is (TO-FROM) % MEMSIZE, but with compound buggering about.
+ ** Memsize is 64K for this range of Tp, so offset is a short (unsigned,
+ ** cos I don't understand 2's complement).
+ */
+ offset = (p->RIOConf.HostLoadBase - 2) - 0x7FFC;
+
+ writeb(NFIX(((unsigned short) (~offset) >> (unsigned short) 12) & 0xF), DestP);
+ writeb(PFIX((offset >> 8) & 0xF), DestP + 1);
+ writeb(PFIX((offset >> 4) & 0xF), DestP + 2);
+ writeb(JUMP(offset & 0xF), DestP + 3);
+
+ writeb(NFIX(0), DestP + 6);
+ writeb(JUMP(8), DestP + 7);
+
+ rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase);
+ rio_dprintk(RIO_DEBUG_BOOT, "startup offset is 0x%x\n", offset);
+
+ /*
+ ** Flag what is going on
+ */
+ HostP->Flags &= ~RUN_STATE;
+ HostP->Flags |= RC_STARTUP;
+
+ /*
+ ** Grab a copy of the current ParmMap pointer, so we
+ ** can tell when it has changed.
+ */
+ OldParmMap = readw(&HostP->__ParmMapR);
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n", OldParmMap);
+
+ /*
+ ** And start it running (I hope).
+ ** As there is nothing dodgy or obscure about the
+ ** above code, this is guaranteed to work every time.
+ */
+ rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);
+
+ rio_start_card_running(HostP);
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Set control port\n");
+
+ /*
+ ** Now, wait for upto five seconds for the Tp to setup the parmmap
+ ** pointer:
+ */
+ for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && (readw(&HostP->__ParmMapR) == OldParmMap); wait_count++) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n", wait_count, readw(&HostP->__ParmMapR));
+ mdelay(100);
+
+ }
+
+ /*
+ ** If the parmmap pointer is unchanged, then the host code
+ ** has crashed & burned in a really spectacular way
+ */
+ if (readw(&HostP->__ParmMapR) == OldParmMap) {
+ rio_dprintk(RIO_DEBUG_BOOT, "parmmap 0x%x\n", readw(&HostP->__ParmMapR));
+ rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n");
+ HostP->Flags &= ~RUN_STATE;
+ HostP->Flags |= RC_STUFFED;
+ RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
+ continue;
+ }
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Running 0x%x\n", readw(&HostP->__ParmMapR));
+
+ /*
+ ** Well, the board thought it was OK, and setup its parmmap
+ ** pointer. For the time being, we will pretend that this
+ ** board is running, and check out what the error flag says.
+ */
+
+ /*
+ ** Grab a 32 bit pointer to the parmmap structure
+ */
+ ParmMapP = (PARM_MAP __iomem *) RIO_PTR(Cad, readw(&HostP->__ParmMapR));
+ rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);
+ ParmMapP = (PARM_MAP __iomem *)(Cad + readw(&HostP->__ParmMapR));
+ rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);
+
+ /*
+ ** The links entry should be 0xFFFF; we set it up
+ ** with a mask to say how many PHBs to use, and
+ ** which links to use.
+ */
+ if (readw(&ParmMapP->links) != 0xFFFF) {
+ rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);
+ rio_dprintk(RIO_DEBUG_BOOT, "Links = 0x%x\n", readw(&ParmMapP->links));
+ HostP->Flags &= ~RUN_STATE;
+ HostP->Flags |= RC_STUFFED;
+ RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
+ continue;
+ }
+
+ writew(RIO_LINK_ENABLE, &ParmMapP->links);
+
+ /*
+ ** now wait for the card to set all the parmmap->XXX stuff
+ ** this is a wait of upto two seconds....
+ */
+ rio_dprintk(RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n", p->RIOConf.StartupTime);
+ HostP->timeout_id = 0;
+ for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && !readw(&ParmMapP->init_done); wait_count++) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Waiting for init_done\n");
+ mdelay(100);
+ }
+ rio_dprintk(RIO_DEBUG_BOOT, "OK! init_done!\n");
+
+ if (readw(&ParmMapP->error) != E_NO_ERROR || !readw(&ParmMapP->init_done)) {
+ rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);
+ rio_dprintk(RIO_DEBUG_BOOT, "Timedout waiting for init_done\n");
+ HostP->Flags &= ~RUN_STATE;
+ HostP->Flags |= RC_STUFFED;
+ RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
+ continue;
+ }
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Got init_done\n");
+
+ /*
+ ** It runs! It runs!
+ */
+ rio_dprintk(RIO_DEBUG_BOOT, "Host ID %x Running\n", HostP->UniqueNum);
+
+ /*
+ ** set the time period between interrupts.
+ */
+ writew(p->RIOConf.Timer, &ParmMapP->timer);
+
+ /*
+ ** Translate all the 16 bit pointers in the __ParmMapR into
+ ** 32 bit pointers for the driver in ioremap space.
+ */
+ HostP->ParmMapP = ParmMapP;
+ HostP->PhbP = (struct PHB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_ptr));
+ HostP->RupP = (struct RUP __iomem *) RIO_PTR(Cad, readw(&ParmMapP->rups));
+ HostP->PhbNumP = (unsigned short __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_num_ptr));
+ HostP->LinkStrP = (struct LPB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->link_str_ptr));
+
+ /*
+ ** point the UnixRups at the real Rups
+ */
+ for (RupN = 0; RupN < MAX_RUP; RupN++) {
+ HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN];
+ HostP->UnixRups[RupN].Id = RupN + 1;
+ HostP->UnixRups[RupN].BaseSysPort = NO_PORT;
+ spin_lock_init(&HostP->UnixRups[RupN].RupLock);
+ }
+
+ for (RupN = 0; RupN < LINKS_PER_UNIT; RupN++) {
+ HostP->UnixRups[RupN + MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup;
+ HostP->UnixRups[RupN + MAX_RUP].Id = 0;
+ HostP->UnixRups[RupN + MAX_RUP].BaseSysPort = NO_PORT;
+ spin_lock_init(&HostP->UnixRups[RupN + MAX_RUP].RupLock);
+ }
+
+ /*
+ ** point the PortP->Phbs at the real Phbs
+ */
+ for (PortN = p->RIOFirstPortsMapped; PortN < p->RIOLastPortsMapped + PORTS_PER_RTA; PortN++) {
+ if (p->RIOPortp[PortN]->HostP == HostP) {
+ struct Port *PortP = p->RIOPortp[PortN];
+ struct PHB __iomem *PhbP;
+ /* int oldspl; */
+
+ if (!PortP->Mapped)
+ continue;
+
+ PhbP = &HostP->PhbP[PortP->HostPort];
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ PortP->PhbP = PhbP;
+
+ PortP->TxAdd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_add));
+ PortP->TxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_start));
+ PortP->TxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_end));
+ PortP->RxRemove = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_remove));
+ PortP->RxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_start));
+ PortP->RxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_end));
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ /*
+ ** point the UnixRup at the base SysPort
+ */
+ if (!(PortN % PORTS_PER_RTA))
+ HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN;
+ }
+ }
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Set the card running... \n");
+ /*
+ ** last thing - show the world that everything is in place
+ */
+ HostP->Flags &= ~RUN_STATE;
+ HostP->Flags |= RC_RUNNING;
+ }
+ /*
+ ** MPX always uses a poller. This is actually patched into the system
+ ** configuration and called directly from each clock tick.
+ **
+ */
+ p->RIOPolling = 1;
+
+ p->RIOSystemUp++;
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec);
+ func_exit();
+ return 0;
+}
+
+
+
+/**
+ * RIOBootRup - Boot an RTA
+ * @p: rio we are working with
+ * @Rup: Rup number
+ * @HostP: host object
+ * @PacketP: packet to use
+ *
+ * If we have successfully processed this boot, then
+ * return 1. If we havent, then return 0.
+ */
+
+int RIOBootRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem *PacketP)
+{
+ struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data;
+ struct PktCmd_M *PktReplyP;
+ struct CmdBlk *CmdBlkP;
+ unsigned int sequence;
+
+ /*
+ ** If we haven't been told what to boot, we can't boot it.
+ */
+ if (p->RIONumBootPkts == 0) {
+ rio_dprintk(RIO_DEBUG_BOOT, "No RTA code to download yet\n");
+ return 0;
+ }
+
+ /*
+ ** Special case of boot completed - if we get one of these then we
+ ** don't need a command block. For all other cases we do, so handle
+ ** this first and then get a command block, then handle every other
+ ** case, relinquishing the command block if disaster strikes!
+ */
+ if ((readb(&PacketP->len) & PKT_CMD_BIT) && (readb(&PktCmdP->Command) == BOOT_COMPLETED))
+ return RIOBootComplete(p, HostP, Rup, PktCmdP);
+
+ /*
+ ** Try to allocate a command block. This is in kernel space
+ */
+ if (!(CmdBlkP = RIOGetCmdBlk())) {
+ rio_dprintk(RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n");
+ return 0;
+ }
+
+ /*
+ ** Fill in the default info on the command block
+ */
+ CmdBlkP->Packet.dest_unit = Rup < (unsigned short) MAX_RUP ? Rup : 0;
+ CmdBlkP->Packet.dest_port = BOOT_RUP;
+ CmdBlkP->Packet.src_unit = 0;
+ CmdBlkP->Packet.src_port = BOOT_RUP;
+
+ CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+ PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;
+
+ /*
+ ** process COMMANDS on the boot rup!
+ */
+ if (readb(&PacketP->len) & PKT_CMD_BIT) {
+ /*
+ ** We only expect one type of command - a BOOT_REQUEST!
+ */
+ if (readb(&PktCmdP->Command) != BOOT_REQUEST) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %Zd\n", readb(&PktCmdP->Command), Rup, HostP - p->RIOHosts);
+ RIOFreeCmdBlk(CmdBlkP);
+ return 1;
+ }
+
+ /*
+ ** Build a Boot Sequence command block
+ **
+ ** We no longer need to use "Boot Mode", we'll always allow
+ ** boot requests - the boot will not complete if the device
+ ** appears in the bindings table.
+ **
+ ** We'll just (always) set the command field in packet reply
+ ** to allow an attempted boot sequence :
+ */
+ PktReplyP->Command = BOOT_SEQUENCE;
+
+ PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts;
+ PktReplyP->BootSequence.LoadBase = p->RIOConf.RtaLoadBase;
+ PktReplyP->BootSequence.CodeSize = p->RIOBootCount;
+
+ CmdBlkP->Packet.len = BOOT_SEQUENCE_LEN | PKT_CMD_BIT;
+
+ memcpy((void *) &CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN], "BOOT", 4);
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Boot RTA on Host %Zd Rup %d - %d (0x%x) packets to 0x%x\n", HostP - p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, p->RIOConf.RtaLoadBase);
+
+ /*
+ ** If this host is in slave mode, send the RTA an invalid boot
+ ** sequence command block to force it to kill the boot. We wait
+ ** for half a second before sending this packet to prevent the RTA
+ ** attempting to boot too often. The master host should then grab
+ ** the RTA and make it its own.
+ */
+ p->RIOBooting++;
+ RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+ return 1;
+ }
+
+ /*
+ ** It is a request for boot data.
+ */
+ sequence = readw(&PktCmdP->Sequence);
+
+ rio_dprintk(RIO_DEBUG_BOOT, "Boot block %d on Host %Zd Rup%d\n", sequence, HostP - p->RIOHosts, Rup);
+
+ if (sequence >= p->RIONumBootPkts) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, p->RIONumBootPkts);
+ }
+
+ PktReplyP->Sequence = sequence;
+ memcpy(PktReplyP->BootData, p->RIOBootPackets[p->RIONumBootPkts - sequence - 1], RTA_BOOT_DATA_SIZE);
+ CmdBlkP->Packet.len = PKT_MAX_DATA_LEN;
+ RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+ return 1;
+}
+
+/**
+ * RIOBootComplete - RTA boot is done
+ * @p: RIO we are working with
+ * @HostP: Host structure
+ * @Rup: RUP being used
+ * @PktCmdP: Packet command that was used
+ *
+ * This function is called when an RTA been booted.
+ * If booted by a host, HostP->HostUniqueNum is the booting host.
+ * If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA.
+ * RtaUniq is the booted RTA.
+ */
+
+static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP)
+{
+ struct Map *MapP = NULL;
+ struct Map *MapP2 = NULL;
+ int Flag;
+ int found;
+ int host, rta;
+ int EmptySlot = -1;
+ int entry, entry2;
+ char *MyType, *MyName;
+ unsigned int MyLink;
+ unsigned short RtaType;
+ u32 RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24);
+
+ p->RIOBooting = 0;
+
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting);
+
+ /*
+ ** Determine type of unit (16/8 port RTA).
+ */
+
+ RtaType = GetUnitType(RtaUniq);
+ if (Rup >= (unsigned short) MAX_RUP)
+ rio_dprintk(RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", HostP->Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A');
+ else
+ rio_dprintk(RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", HostP->Mapping[Rup].Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A');
+
+ rio_dprintk(RIO_DEBUG_BOOT, "UniqNum is 0x%x\n", RtaUniq);
+
+ if (RtaUniq == 0x00000000 || RtaUniq == 0xffffffff) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n");
+ return 1;
+ }
+
+ /*
+ ** If this RTA has just booted an RTA which doesn't belong to this
+ ** system, or the system is in slave mode, do not attempt to create
+ ** a new table entry for it.
+ */
+
+ if (!RIOBootOk(p, HostP, RtaUniq)) {
+ MyLink = readb(&PktCmdP->LinkNum);
+ if (Rup < (unsigned short) MAX_RUP) {
+ /*
+ ** RtaUniq was clone booted (by this RTA). Instruct this RTA
+ ** to hold off further attempts to boot on this link for 30
+ ** seconds.
+ */
+ if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) {
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", 'A' + MyLink);
+ }
+ } else
+ /*
+ ** RtaUniq was booted by this host. Set the booting link
+ ** to hold off for 30 seconds to give another unit a
+ ** chance to boot it.
+ */
+ writew(30, &HostP->LinkStrP[MyLink].WaitNoBoot);
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum);
+ return 1;
+ }
+
+ /*
+ ** Check for a SLOT_IN_USE entry for this RTA attached to the
+ ** current host card in the driver table.
+ **
+ ** If it exists, make a note that we have booted it. Other parts of
+ ** the driver are interested in this information at a later date,
+ ** in particular when the booting RTA asks for an ID for this unit,
+ ** we must have set the BOOTED flag, and the NEWBOOT flag is used
+ ** to force an open on any ports that where previously open on this
+ ** unit.
+ */
+ for (entry = 0; entry < MAX_RUP; entry++) {
+ unsigned int sysport;
+
+ if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) {
+ HostP->Mapping[entry].Flags |= RTA_BOOTED | RTA_NEWBOOT;
+ if ((sysport = HostP->Mapping[entry].SysPort) != NO_PORT) {
+ if (sysport < p->RIOFirstPortsBooted)
+ p->RIOFirstPortsBooted = sysport;
+ if (sysport > p->RIOLastPortsBooted)
+ p->RIOLastPortsBooted = sysport;
+ /*
+ ** For a 16 port RTA, check the second bank of 8 ports
+ */
+ if (RtaType == TYPE_RTA16) {
+ entry2 = HostP->Mapping[entry].ID2 - 1;
+ HostP->Mapping[entry2].Flags |= RTA_BOOTED | RTA_NEWBOOT;
+ sysport = HostP->Mapping[entry2].SysPort;
+ if (sysport < p->RIOFirstPortsBooted)
+ p->RIOFirstPortsBooted = sysport;
+ if (sysport > p->RIOLastPortsBooted)
+ p->RIOLastPortsBooted = sysport;
+ }
+ }
+ if (RtaType == TYPE_RTA16)
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", entry + 1, entry2 + 1);
+ else
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given ID %d\n", entry + 1);
+ return 1;
+ }
+ }
+
+ rio_dprintk(RIO_DEBUG_BOOT, "RTA not configured for this host\n");
+
+ if (Rup >= (unsigned short) MAX_RUP) {
+ /*
+ ** It was a host that did the booting
+ */
+ MyType = "Host";
+ MyName = HostP->Name;
+ } else {
+ /*
+ ** It was an RTA that did the booting
+ */
+ MyType = "RTA";
+ MyName = HostP->Mapping[Rup].Name;
+ }
+ MyLink = readb(&PktCmdP->LinkNum);
+
+ /*
+ ** There is no SLOT_IN_USE entry for this RTA attached to the current
+ ** host card in the driver table.
+ **
+ ** Check for a SLOT_TENTATIVE entry for this RTA attached to the
+ ** current host card in the driver table.
+ **
+ ** If we find one, then we re-use that slot.
+ */
+ for (entry = 0; entry < MAX_RUP; entry++) {
+ if ((HostP->Mapping[entry].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) {
+ if (RtaType == TYPE_RTA16) {
+ entry2 = HostP->Mapping[entry].ID2 - 1;
+ if ((HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq))
+ rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", entry, entry2);
+ else
+ continue;
+ } else
+ rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n", entry);
+ if (!p->RIONoMessage)
+ printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A');
+ return 1;
+ }
+ }
+
+ /*
+ ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+ ** attached to the current host card in the driver table.
+ **
+ ** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another
+ ** host for this RTA in the driver table.
+ **
+ ** For a SLOT_IN_USE entry on another host, we need to delete the RTA
+ ** entry from the other host and add it to this host (using some of
+ ** the functions from table.c which do this).
+ ** For a SLOT_TENTATIVE entry on another host, we must cope with the
+ ** following scenario:
+ **
+ ** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry
+ ** in table)
+ ** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE
+ ** entries)
+ ** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE)
+ ** + Unplug RTA and plug back into host A.
+ ** + Configure RTA on host A. We now have the same RTA configured
+ ** with different ports on two different hosts.
+ */
+ rio_dprintk(RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq);
+ found = 0;
+ Flag = 0; /* Convince the compiler this variable is initialized */
+ for (host = 0; !found && (host < p->RIONumHosts); host++) {
+ for (rta = 0; rta < MAX_RUP; rta++) {
+ if ((p->RIOHosts[host].Mapping[rta].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (p->RIOHosts[host].Mapping[rta].RtaUniqueNum == RtaUniq)) {
+ Flag = p->RIOHosts[host].Mapping[rta].Flags;
+ MapP = &p->RIOHosts[host].Mapping[rta];
+ if (RtaType == TYPE_RTA16) {
+ MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1];
+ rio_dprintk(RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", rta + 1, MapP->ID2, p->RIOHosts[host].Name);
+ } else
+ rio_dprintk(RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", rta + 1, p->RIOHosts[host].Name);
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ /*
+ ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+ ** attached to the current host card in the driver table.
+ **
+ ** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on
+ ** another host for this RTA in the driver table...
+ **
+ ** Check for a SLOT_IN_USE entry for this RTA in the config table.
+ */
+ if (!MapP) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n", RtaUniq);
+ for (rta = 0; rta < TOTAL_MAP_ENTRIES; rta++) {
+ rio_dprintk(RIO_DEBUG_BOOT, "Check table entry %d (%x)", rta, p->RIOSavedTable[rta].RtaUniqueNum);
+
+ if ((p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq)) {
+ MapP = &p->RIOSavedTable[rta];
+ Flag = p->RIOSavedTable[rta].Flags;
+ if (RtaType == TYPE_RTA16) {
+ for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES; entry2++) {
+ if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq)
+ break;
+ }
+ MapP2 = &p->RIOSavedTable[entry2];
+ rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", rta, entry2);
+ } else
+ rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta);
+ break;
+ }
+ }
+ }
+
+ /*
+ ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+ ** attached to the current host card in the driver table.
+ **
+ ** We may have found a SLOT_IN_USE entry on another host for this
+ ** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry
+ ** on another host for this RTA in the driver table.
+ **
+ ** Check the driver table for room to fit this newly discovered RTA.
+ ** RIOFindFreeID() first looks for free slots and if it does not
+ ** find any free slots it will then attempt to oust any
+ ** tentative entry in the table.
+ */
+ EmptySlot = 1;
+ if (RtaType == TYPE_RTA16) {
+ if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0) {
+ RIODefaultName(p, HostP, entry);
+ rio_fill_host_slot(entry, entry2, RtaUniq, HostP);
+ EmptySlot = 0;
+ }
+ } else {
+ if (RIOFindFreeID(p, HostP, &entry, NULL) == 0) {
+ RIODefaultName(p, HostP, entry);
+ rio_fill_host_slot(entry, 0, RtaUniq, HostP);
+ EmptySlot = 0;
+ }
+ }
+
+ /*
+ ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+ ** attached to the current host card in the driver table.
+ **
+ ** If we found a SLOT_IN_USE entry on another host for this
+ ** RTA in the config or driver table, and there are enough free
+ ** slots in the driver table, then we need to move it over and
+ ** delete it from the other host.
+ ** If we found a SLOT_TENTATIVE entry on another host for this
+ ** RTA in the driver table, just delete the other host entry.
+ */
+ if (EmptySlot == 0) {
+ if (MapP) {
+ if (Flag & SLOT_IN_USE) {
+ rio_dprintk(RIO_DEBUG_BOOT, "This RTA configured on another host - move entry to current host (1)\n");
+ HostP->Mapping[entry].SysPort = MapP->SysPort;
+ memcpy(HostP->Mapping[entry].Name, MapP->Name, MAX_NAME_LEN);
+ HostP->Mapping[entry].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT;
+ RIOReMapPorts(p, HostP, &HostP->Mapping[entry]);
+ if (HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted)
+ p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort;
+ if (HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted)
+ p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort;
+ rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) MapP->SysPort, MapP->Name);
+ } else {
+ rio_dprintk(RIO_DEBUG_BOOT, "This RTA has a tentative entry on another host - delete that entry (1)\n");
+ HostP->Mapping[entry].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT;
+ }
+ if (RtaType == TYPE_RTA16) {
+ if (Flag & SLOT_IN_USE) {
+ HostP->Mapping[entry2].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+ HostP->Mapping[entry2].SysPort = MapP2->SysPort;
+ /*
+ ** Map second block of ttys for 16 port RTA
+ */
+ RIOReMapPorts(p, HostP, &HostP->Mapping[entry2]);
+ if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted)
+ p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort;
+ if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted)
+ p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort;
+ rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) HostP->Mapping[entry2].SysPort, HostP->Mapping[entry].Name);
+ } else
+ HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+ memset(MapP2, 0, sizeof(struct Map));
+ }
+ memset(MapP, 0, sizeof(struct Map));
+ if (!p->RIONoMessage)
+ printk("An orphaned RTA has been adopted by %s '%s' (%c).\n", MyType, MyName, MyLink + 'A');
+ } else if (!p->RIONoMessage)
+ printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A');
+ RIOSetChange(p);
+ return 1;
+ }
+
+ /*
+ ** There is no room in the driver table to make an entry for the
+ ** booted RTA. Keep a note of its Uniq Num in the overflow table,
+ ** so we can ignore it's ID requests.
+ */
+ if (!p->RIONoMessage)
+ printk("The RTA connected to %s '%s' (%c) cannot be configured. You cannot configure more than 128 ports to one host card.\n", MyType, MyName, MyLink + 'A');
+ for (entry = 0; entry < HostP->NumExtraBooted; entry++) {
+ if (HostP->ExtraUnits[entry] == RtaUniq) {
+ /*
+ ** already got it!
+ */
+ return 1;
+ }
+ }
+ /*
+ ** If there is room, add the unit to the list of extras
+ */
+ if (HostP->NumExtraBooted < MAX_EXTRA_UNITS)
+ HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq;
+ return 1;
+}
+
+
+/*
+** If the RTA or its host appears in the RIOBindTab[] structure then
+** we mustn't boot the RTA and should return 0.
+** This operation is slightly different from the other drivers for RIO
+** in that this is designed to work with the new utilities
+** not config.rio and is FAR SIMPLER.
+** We no longer support the RIOBootMode variable. It is all done from the
+** "boot/noboot" field in the rio.cf file.
+*/
+int RIOBootOk(struct rio_info *p, struct Host *HostP, unsigned long RtaUniq)
+{
+ int Entry;
+ unsigned int HostUniq = HostP->UniqueNum;
+
+ /*
+ ** Search bindings table for RTA or its parent.
+ ** If it exists, return 0, else 1.
+ */
+ for (Entry = 0; (Entry < MAX_RTA_BINDINGS) && (p->RIOBindTab[Entry] != 0); Entry++) {
+ if ((p->RIOBindTab[Entry] == HostUniq) || (p->RIOBindTab[Entry] == RtaUniq))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Make an empty slot tentative. If this is a 16 port RTA, make both
+** slots tentative, and the second one RTA_SECOND_SLOT as well.
+*/
+
+void rio_fill_host_slot(int entry, int entry2, unsigned int rta_uniq, struct Host *host)
+{
+ int link;
+
+ rio_dprintk(RIO_DEBUG_BOOT, "rio_fill_host_slot(%d, %d, 0x%x...)\n", entry, entry2, rta_uniq);
+
+ host->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE);
+ host->Mapping[entry].SysPort = NO_PORT;
+ host->Mapping[entry].RtaUniqueNum = rta_uniq;
+ host->Mapping[entry].HostUniqueNum = host->UniqueNum;
+ host->Mapping[entry].ID = entry + 1;
+ host->Mapping[entry].ID2 = 0;
+ if (entry2) {
+ host->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE | RTA16_SECOND_SLOT);
+ host->Mapping[entry2].SysPort = NO_PORT;
+ host->Mapping[entry2].RtaUniqueNum = rta_uniq;
+ host->Mapping[entry2].HostUniqueNum = host->UniqueNum;
+ host->Mapping[entry2].Name[0] = '\0';
+ host->Mapping[entry2].ID = entry2 + 1;
+ host->Mapping[entry2].ID2 = entry + 1;
+ host->Mapping[entry].ID2 = entry2 + 1;
+ }
+ /*
+ ** Must set these up, so that utilities show
+ ** topology of 16 port RTAs correctly
+ */
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ host->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT;
+ host->Mapping[entry].Topology[link].Link = NO_LINK;
+ if (entry2) {
+ host->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT;
+ host->Mapping[entry2].Topology[link].Link = NO_LINK;
+ }
+ }
+}
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
new file mode 100644
index 0000000..01f2654
--- /dev/null
+++ b/drivers/char/rio/riocmd.c
@@ -0,0 +1,938 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** ported from the existing SCO driver source
+**
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : riocmd.c
+** SID : 1.2
+** Last Modified : 11/6/98 10:33:41
+** Retrieved : 11/6/98 10:33:49
+**
+** ident @(#)riocmd.c 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+
+
+static struct IdentifyRta IdRta;
+static struct KillNeighbour KillUnit;
+
+int RIOFoadRta(struct Host *HostP, struct Map *MapP)
+{
+ struct CmdBlk *CmdBlkP;
+
+ rio_dprintk(RIO_DEBUG_CMD, "FOAD RTA\n");
+
+ CmdBlkP = RIOGetCmdBlk();
+
+ if (!CmdBlkP) {
+ rio_dprintk(RIO_DEBUG_CMD, "FOAD RTA: GetCmdBlk failed\n");
+ return -ENXIO;
+ }
+
+ CmdBlkP->Packet.dest_unit = MapP->ID;
+ CmdBlkP->Packet.dest_port = BOOT_RUP;
+ CmdBlkP->Packet.src_unit = 0;
+ CmdBlkP->Packet.src_port = BOOT_RUP;
+ CmdBlkP->Packet.len = 0x84;
+ CmdBlkP->Packet.data[0] = IFOAD;
+ CmdBlkP->Packet.data[1] = 0;
+ CmdBlkP->Packet.data[2] = IFOAD_MAGIC & 0xFF;
+ CmdBlkP->Packet.data[3] = (IFOAD_MAGIC >> 8) & 0xFF;
+
+ if (RIOQueueCmdBlk(HostP, MapP->ID - 1, CmdBlkP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CMD, "FOAD RTA: Failed to queue foad command\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+int RIOZombieRta(struct Host *HostP, struct Map *MapP)
+{
+ struct CmdBlk *CmdBlkP;
+
+ rio_dprintk(RIO_DEBUG_CMD, "ZOMBIE RTA\n");
+
+ CmdBlkP = RIOGetCmdBlk();
+
+ if (!CmdBlkP) {
+ rio_dprintk(RIO_DEBUG_CMD, "ZOMBIE RTA: GetCmdBlk failed\n");
+ return -ENXIO;
+ }
+
+ CmdBlkP->Packet.dest_unit = MapP->ID;
+ CmdBlkP->Packet.dest_port = BOOT_RUP;
+ CmdBlkP->Packet.src_unit = 0;
+ CmdBlkP->Packet.src_port = BOOT_RUP;
+ CmdBlkP->Packet.len = 0x84;
+ CmdBlkP->Packet.data[0] = ZOMBIE;
+ CmdBlkP->Packet.data[1] = 0;
+ CmdBlkP->Packet.data[2] = ZOMBIE_MAGIC & 0xFF;
+ CmdBlkP->Packet.data[3] = (ZOMBIE_MAGIC >> 8) & 0xFF;
+
+ if (RIOQueueCmdBlk(HostP, MapP->ID - 1, CmdBlkP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CMD, "ZOMBIE RTA: Failed to queue zombie command\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+int RIOCommandRta(struct rio_info *p, unsigned long RtaUnique, int (*func) (struct Host * HostP, struct Map * MapP))
+{
+ unsigned int Host;
+
+ rio_dprintk(RIO_DEBUG_CMD, "Command RTA 0x%lx func %p\n", RtaUnique, func);
+
+ if (!RtaUnique)
+ return (0);
+
+ for (Host = 0; Host < p->RIONumHosts; Host++) {
+ unsigned int Rta;
+ struct Host *HostP = &p->RIOHosts[Host];
+
+ for (Rta = 0; Rta < RTAS_PER_HOST; Rta++) {
+ struct Map *MapP = &HostP->Mapping[Rta];
+
+ if (MapP->RtaUniqueNum == RtaUnique) {
+ uint Link;
+
+ /*
+ ** now, lets just check we have a route to it...
+ ** IF the routing stuff is working, then one of the
+ ** topology entries for this unit will have a legit
+ ** route *somewhere*. We care not where - if its got
+ ** any connections, we can get to it.
+ */
+ for (Link = 0; Link < LINKS_PER_UNIT; Link++) {
+ if (MapP->Topology[Link].Unit <= (u8) MAX_RUP) {
+ /*
+ ** Its worth trying the operation...
+ */
+ return (*func) (HostP, MapP);
+ }
+ }
+ }
+ }
+ }
+ return -ENXIO;
+}
+
+
+int RIOIdentifyRta(struct rio_info *p, void __user * arg)
+{
+ unsigned int Host;
+
+ if (copy_from_user(&IdRta, arg, sizeof(IdRta))) {
+ rio_dprintk(RIO_DEBUG_CMD, "RIO_IDENTIFY_RTA copy failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+
+ for (Host = 0; Host < p->RIONumHosts; Host++) {
+ unsigned int Rta;
+ struct Host *HostP = &p->RIOHosts[Host];
+
+ for (Rta = 0; Rta < RTAS_PER_HOST; Rta++) {
+ struct Map *MapP = &HostP->Mapping[Rta];
+
+ if (MapP->RtaUniqueNum == IdRta.RtaUnique) {
+ uint Link;
+ /*
+ ** now, lets just check we have a route to it...
+ ** IF the routing stuff is working, then one of the
+ ** topology entries for this unit will have a legit
+ ** route *somewhere*. We care not where - if its got
+ ** any connections, we can get to it.
+ */
+ for (Link = 0; Link < LINKS_PER_UNIT; Link++) {
+ if (MapP->Topology[Link].Unit <= (u8) MAX_RUP) {
+ /*
+ ** Its worth trying the operation...
+ */
+ struct CmdBlk *CmdBlkP;
+
+ rio_dprintk(RIO_DEBUG_CMD, "IDENTIFY RTA\n");
+
+ CmdBlkP = RIOGetCmdBlk();
+
+ if (!CmdBlkP) {
+ rio_dprintk(RIO_DEBUG_CMD, "IDENTIFY RTA: GetCmdBlk failed\n");
+ return -ENXIO;
+ }
+
+ CmdBlkP->Packet.dest_unit = MapP->ID;
+ CmdBlkP->Packet.dest_port = BOOT_RUP;
+ CmdBlkP->Packet.src_unit = 0;
+ CmdBlkP->Packet.src_port = BOOT_RUP;
+ CmdBlkP->Packet.len = 0x84;
+ CmdBlkP->Packet.data[0] = IDENTIFY;
+ CmdBlkP->Packet.data[1] = 0;
+ CmdBlkP->Packet.data[2] = IdRta.ID;
+
+ if (RIOQueueCmdBlk(HostP, MapP->ID - 1, CmdBlkP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CMD, "IDENTIFY RTA: Failed to queue command\n");
+ return -EIO;
+ }
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ return -ENOENT;
+}
+
+
+int RIOKillNeighbour(struct rio_info *p, void __user * arg)
+{
+ uint Host;
+ uint ID;
+ struct Host *HostP;
+ struct CmdBlk *CmdBlkP;
+
+ rio_dprintk(RIO_DEBUG_CMD, "KILL HOST NEIGHBOUR\n");
+
+ if (copy_from_user(&KillUnit, arg, sizeof(KillUnit))) {
+ rio_dprintk(RIO_DEBUG_CMD, "RIO_KILL_NEIGHBOUR copy failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+
+ if (KillUnit.Link > 3)
+ return -ENXIO;
+
+ CmdBlkP = RIOGetCmdBlk();
+
+ if (!CmdBlkP) {
+ rio_dprintk(RIO_DEBUG_CMD, "UFOAD: GetCmdBlk failed\n");
+ return -ENXIO;
+ }
+
+ CmdBlkP->Packet.dest_unit = 0;
+ CmdBlkP->Packet.src_unit = 0;
+ CmdBlkP->Packet.dest_port = BOOT_RUP;
+ CmdBlkP->Packet.src_port = BOOT_RUP;
+ CmdBlkP->Packet.len = 0x84;
+ CmdBlkP->Packet.data[0] = UFOAD;
+ CmdBlkP->Packet.data[1] = KillUnit.Link;
+ CmdBlkP->Packet.data[2] = UFOAD_MAGIC & 0xFF;
+ CmdBlkP->Packet.data[3] = (UFOAD_MAGIC >> 8) & 0xFF;
+
+ for (Host = 0; Host < p->RIONumHosts; Host++) {
+ ID = 0;
+ HostP = &p->RIOHosts[Host];
+
+ if (HostP->UniqueNum == KillUnit.UniqueNum) {
+ if (RIOQueueCmdBlk(HostP, RTAS_PER_HOST + KillUnit.Link, CmdBlkP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CMD, "UFOAD: Failed queue command\n");
+ return -EIO;
+ }
+ return 0;
+ }
+
+ for (ID = 0; ID < RTAS_PER_HOST; ID++) {
+ if (HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum) {
+ CmdBlkP->Packet.dest_unit = ID + 1;
+ if (RIOQueueCmdBlk(HostP, ID, CmdBlkP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CMD, "UFOAD: Failed queue command\n");
+ return -EIO;
+ }
+ return 0;
+ }
+ }
+ }
+ RIOFreeCmdBlk(CmdBlkP);
+ return -ENXIO;
+}
+
+int RIOSuspendBootRta(struct Host *HostP, int ID, int Link)
+{
+ struct CmdBlk *CmdBlkP;
+
+ rio_dprintk(RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link);
+
+ CmdBlkP = RIOGetCmdBlk();
+
+ if (!CmdBlkP) {
+ rio_dprintk(RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: GetCmdBlk failed\n");
+ return -ENXIO;
+ }
+
+ CmdBlkP->Packet.dest_unit = ID;
+ CmdBlkP->Packet.dest_port = BOOT_RUP;
+ CmdBlkP->Packet.src_unit = 0;
+ CmdBlkP->Packet.src_port = BOOT_RUP;
+ CmdBlkP->Packet.len = 0x84;
+ CmdBlkP->Packet.data[0] = IWAIT;
+ CmdBlkP->Packet.data[1] = Link;
+ CmdBlkP->Packet.data[2] = IWAIT_MAGIC & 0xFF;
+ CmdBlkP->Packet.data[3] = (IWAIT_MAGIC >> 8) & 0xFF;
+
+ if (RIOQueueCmdBlk(HostP, ID - 1, CmdBlkP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: Failed to queue iwait command\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+int RIOFoadWakeup(struct rio_info *p)
+{
+ int port;
+ struct Port *PortP;
+ unsigned long flags;
+
+ for (port = 0; port < RIO_PORTS; port++) {
+ PortP = p->RIOPortp[port];
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->Config = 0;
+ PortP->State = 0;
+ PortP->InUse = NOT_INUSE;
+ PortP->PortState = 0;
+ PortP->FlushCmdBodge = 0;
+ PortP->ModemLines = 0;
+ PortP->ModemState = 0;
+ PortP->CookMode = 0;
+ PortP->ParamSem = 0;
+ PortP->Mapped = 0;
+ PortP->WflushFlag = 0;
+ PortP->MagicFlags = 0;
+ PortP->RxDataStart = 0;
+ PortP->TxBufferIn = 0;
+ PortP->TxBufferOut = 0;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ }
+ return (0);
+}
+
+/*
+** Incoming command on the COMMAND_RUP to be processed.
+*/
+static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struct PKT __iomem *PacketP)
+{
+ struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *)PacketP->data;
+ struct Port *PortP;
+ struct UnixRup *UnixRupP;
+ unsigned short SysPort;
+ unsigned short ReportedModemStatus;
+ unsigned short rup;
+ unsigned short subCommand;
+ unsigned long flags;
+
+ func_enter();
+
+ /*
+ ** 16 port RTA note:
+ ** Command rup packets coming from the RTA will have pkt->data[1] (which
+ ** translates to PktCmdP->PhbNum) set to the host port number for the
+ ** particular unit. To access the correct BaseSysPort for a 16 port RTA,
+ ** we can use PhbNum to get the rup number for the appropriate 8 port
+ ** block (for the first block, this should be equal to 'Rup').
+ */
+ rup = readb(&PktCmdP->PhbNum) / (unsigned short) PORTS_PER_RTA;
+ UnixRupP = &HostP->UnixRups[rup];
+ SysPort = UnixRupP->BaseSysPort + (readb(&PktCmdP->PhbNum) % (unsigned short) PORTS_PER_RTA);
+ rio_dprintk(RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort);
+
+ if (UnixRupP->BaseSysPort == NO_PORT) {
+ rio_dprintk(RIO_DEBUG_CMD, "OBSCURE ERROR!\n");
+ rio_dprintk(RIO_DEBUG_CMD, "Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n");
+ rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
+ rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup);
+
+ if (Rup < (unsigned short) MAX_RUP) {
+ rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
+ } else
+ rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
+
+ rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Destination 0x%x:0x%x\n", readb(&PacketP->dest_unit), readb(&PacketP->dest_port));
+ rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Source 0x%x:0x%x\n", readb(&PacketP->src_unit), readb(&PacketP->src_port));
+ rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Length 0x%x (%d)\n", readb(&PacketP->len), readb(&PacketP->len));
+ rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Control 0x%x (%d)\n", readb(&PacketP->control), readb(&PacketP->control));
+ rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Check 0x%x (%d)\n", readw(&PacketP->csum), readw(&PacketP->csum));
+ rio_dprintk(RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, " "Command Code 0x%x\n", readb(&PktCmdP->PhbNum), readb(&PktCmdP->Command));
+ return 1;
+ }
+ PortP = p->RIOPortp[SysPort];
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ switch (readb(&PktCmdP->Command)) {
+ case RIOC_BREAK_RECEIVED:
+ rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n");
+ /* If the current line disc. is not multi-threading and
+ the current processor is not the default, reset rup_intr
+ and return 0 to ensure that the command packet is
+ not freed. */
+ /* Call tmgr HANGUP HERE */
+ /* Fix this later when every thing works !!!! RAMRAJ */
+ gs_got_break(&PortP->gs);
+ break;
+
+ case RIOC_COMPLETE:
+ rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts);
+ subCommand = 1;
+ switch (readb(&PktCmdP->SubCommand)) {
+ case RIOC_MEMDUMP:
+ rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr));
+ break;
+ case RIOC_READ_REGISTER:
+ rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr));
+ p->CdRegister = (readb(&PktCmdP->ModemStatus) & RIOC_MSVR1_HOST);
+ break;
+ default:
+ subCommand = 0;
+ break;
+ }
+ if (subCommand)
+ break;
+ rio_dprintk(RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", readb(&PktCmdP->PortStatus), PortP->PortState);
+ if (PortP->PortState != readb(&PktCmdP->PortStatus)) {
+ rio_dprintk(RIO_DEBUG_CMD, "Mark status & wakeup\n");
+ PortP->PortState = readb(&PktCmdP->PortStatus);
+ /* What should we do here ...
+ wakeup( &PortP->PortState );
+ */
+ } else
+ rio_dprintk(RIO_DEBUG_CMD, "No change\n");
+
+ /* FALLTHROUGH */
+ case RIOC_MODEM_STATUS:
+ /*
+ ** Knock out the tbusy and tstop bits, as these are not relevant
+ ** to the check for modem status change (they're just there because
+ ** it's a convenient place to put them!).
+ */
+ ReportedModemStatus = readb(&PktCmdP->ModemStatus);
+ if ((PortP->ModemState & RIOC_MSVR1_HOST) ==
+ (ReportedModemStatus & RIOC_MSVR1_HOST)) {
+ rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState);
+ /*
+ ** Update ModemState just in case tbusy or tstop states have
+ ** changed.
+ */
+ PortP->ModemState = ReportedModemStatus;
+ } else {
+ rio_dprintk(RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", PortP->ModemState, ReportedModemStatus);
+ PortP->ModemState = ReportedModemStatus;
+#ifdef MODEM_SUPPORT
+ if (PortP->Mapped) {
+ /***********************************************************\
+ *************************************************************
+ *** ***
+ *** M O D E M S T A T E C H A N G E ***
+ *** ***
+ *************************************************************
+ \***********************************************************/
+ /*
+ ** If the device is a modem, then check the modem
+ ** carrier.
+ */
+ if (PortP->gs.port.tty == NULL)
+ break;
+ if (PortP->gs.port.tty->termios == NULL)
+ break;
+
+ if (!(PortP->gs.port.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) {
+
+ rio_dprintk(RIO_DEBUG_CMD, "Is there a Carrier?\n");
+ /*
+ ** Is there a carrier?
+ */
+ if (PortP->ModemState & RIOC_MSVR1_CD) {
+ /*
+ ** Has carrier just appeared?
+ */
+ if (!(PortP->State & RIO_CARR_ON)) {
+ rio_dprintk(RIO_DEBUG_CMD, "Carrier just came up.\n");
+ PortP->State |= RIO_CARR_ON;
+ /*
+ ** wakeup anyone in WOPEN
+ */
+ if (PortP->State & (PORT_ISOPEN | RIO_WOPEN))
+ wake_up_interruptible(&PortP->gs.port.open_wait);
+ }
+ } else {
+ /*
+ ** Has carrier just dropped?
+ */
+ if (PortP->State & RIO_CARR_ON) {
+ if (PortP->State & (PORT_ISOPEN | RIO_WOPEN | RIO_MOPEN))
+ tty_hangup(PortP->gs.port.tty);
+ PortP->State &= ~RIO_CARR_ON;
+ rio_dprintk(RIO_DEBUG_CMD, "Carrirer just went down\n");
+ }
+ }
+ }
+ }
+#endif
+ }
+ break;
+
+ default:
+ rio_dprintk(RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %Zd\n", readb(&PktCmdP->Command), HostP - p->RIOHosts);
+ break;
+ }
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+ func_exit();
+
+ return 1;
+}
+
+/*
+** The command mechanism:
+** Each rup has a chain of commands associated with it.
+** This chain is maintained by routines in this file.
+** Periodically we are called and we run a quick check of all the
+** active chains to determine if there is a command to be executed,
+** and if the rup is ready to accept it.
+**
+*/
+
+/*
+** Allocate an empty command block.
+*/
+struct CmdBlk *RIOGetCmdBlk(void)
+{
+ struct CmdBlk *CmdBlkP;
+
+ CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
+ return CmdBlkP;
+}
+
+/*
+** Return a block to the head of the free list.
+*/
+void RIOFreeCmdBlk(struct CmdBlk *CmdBlkP)
+{
+ kfree(CmdBlkP);
+}
+
+/*
+** attach a command block to the list of commands to be performed for
+** a given rup.
+*/
+int RIOQueueCmdBlk(struct Host *HostP, uint Rup, struct CmdBlk *CmdBlkP)
+{
+ struct CmdBlk **Base;
+ struct UnixRup *UnixRupP;
+ unsigned long flags;
+
+ if (Rup >= (unsigned short) (MAX_RUP + LINKS_PER_UNIT)) {
+ rio_dprintk(RIO_DEBUG_CMD, "Illegal rup number %d in RIOQueueCmdBlk\n", Rup);
+ RIOFreeCmdBlk(CmdBlkP);
+ return RIO_FAIL;
+ }
+
+ UnixRupP = &HostP->UnixRups[Rup];
+
+ rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+ /*
+ ** If the RUP is currently inactive, then put the request
+ ** straight on the RUP....
+ */
+ if ((UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP)
+ : 1)) {
+ rio_dprintk(RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n", CmdBlkP->Packet.data[0]);
+
+ /*
+ ** Whammy! blat that pack!
+ */
+ HostP->Copy(&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->txpkt)), sizeof(struct PKT));
+
+ /*
+ ** place command packet on the pending position.
+ */
+ UnixRupP->CmdPendingP = CmdBlkP;
+
+ /*
+ ** set the command register
+ */
+ writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol);
+
+ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+ return 0;
+ }
+ rio_dprintk(RIO_DEBUG_CMD, "RUP active - en-queing\n");
+
+ if (UnixRupP->CmdsWaitingP != NULL)
+ rio_dprintk(RIO_DEBUG_CMD, "Rup active - command waiting\n");
+ if (UnixRupP->CmdPendingP != NULL)
+ rio_dprintk(RIO_DEBUG_CMD, "Rup active - command pending\n");
+ if (readw(&UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE)
+ rio_dprintk(RIO_DEBUG_CMD, "Rup active - command rup not ready\n");
+
+ Base = &UnixRupP->CmdsWaitingP;
+
+ rio_dprintk(RIO_DEBUG_CMD, "First try to queue cmdblk %p at %p\n", CmdBlkP, Base);
+
+ while (*Base) {
+ rio_dprintk(RIO_DEBUG_CMD, "Command cmdblk %p here\n", *Base);
+ Base = &((*Base)->NextP);
+ rio_dprintk(RIO_DEBUG_CMD, "Now try to queue cmd cmdblk %p at %p\n", CmdBlkP, Base);
+ }
+
+ rio_dprintk(RIO_DEBUG_CMD, "Will queue cmdblk %p at %p\n", CmdBlkP, Base);
+
+ *Base = CmdBlkP;
+
+ CmdBlkP->NextP = NULL;
+
+ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+ return 0;
+}
+
+/*
+** Here we go - if there is an empty rup, fill it!
+** must be called at splrio() or higher.
+*/
+void RIOPollHostCommands(struct rio_info *p, struct Host *HostP)
+{
+ struct CmdBlk *CmdBlkP;
+ struct UnixRup *UnixRupP;
+ struct PKT __iomem *PacketP;
+ unsigned short Rup;
+ unsigned long flags;
+
+
+ Rup = MAX_RUP + LINKS_PER_UNIT;
+
+ do { /* do this loop for each RUP */
+ /*
+ ** locate the rup we are processing & lock it
+ */
+ UnixRupP = &HostP->UnixRups[--Rup];
+
+ spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+ /*
+ ** First check for incoming commands:
+ */
+ if (readw(&UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE) {
+ int FreeMe;
+
+ PacketP = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->rxpkt));
+
+ switch (readb(&PacketP->dest_port)) {
+ case BOOT_RUP:
+ rio_dprintk(RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", readb(&PacketP->len) & 0x80 ? "Command" : "Data", readb(&PacketP->data[0]));
+ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+ FreeMe = RIOBootRup(p, Rup, HostP, PacketP);
+ rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+ break;
+
+ case COMMAND_RUP:
+ /*
+ ** Free the RUP lock as loss of carrier causes a
+ ** ttyflush which will (eventually) call another
+ ** routine that uses the RUP lock.
+ */
+ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+ FreeMe = RIOCommandRup(p, Rup, HostP, PacketP);
+ if (readb(&PacketP->data[5]) == RIOC_MEMDUMP) {
+ rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6])));
+ rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 32);
+ }
+ rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+ break;
+
+ case ROUTE_RUP:
+ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+ FreeMe = RIORouteRup(p, Rup, HostP, PacketP);
+ rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+ break;
+
+ default:
+ rio_dprintk(RIO_DEBUG_CMD, "Unknown RUP %d\n", readb(&PacketP->dest_port));
+ FreeMe = 1;
+ break;
+ }
+
+ if (FreeMe) {
+ rio_dprintk(RIO_DEBUG_CMD, "Free processed incoming command packet\n");
+ put_free_end(HostP, PacketP);
+
+ writew(RX_RUP_INACTIVE, &UnixRupP->RupP->rxcontrol);
+
+ if (readw(&UnixRupP->RupP->handshake) == PHB_HANDSHAKE_SET) {
+ rio_dprintk(RIO_DEBUG_CMD, "Handshake rup %d\n", Rup);
+ writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &UnixRupP->RupP->handshake);
+ }
+ }
+ }
+
+ /*
+ ** IF a command was running on the port,
+ ** and it has completed, then tidy it up.
+ */
+ if ((CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */
+ (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) {
+ /*
+ ** we are idle.
+ ** there is a command in pending.
+ ** Therefore, this command has finished.
+ ** So, wakeup whoever is waiting for it (and tell them
+ ** what happened).
+ */
+ if (CmdBlkP->Packet.dest_port == BOOT_RUP)
+ rio_dprintk(RIO_DEBUG_CMD, "Free Boot %s Command Block '%x'\n", CmdBlkP->Packet.len & 0x80 ? "Command" : "Data", CmdBlkP->Packet.data[0]);
+
+ rio_dprintk(RIO_DEBUG_CMD, "Command %p completed\n", CmdBlkP);
+
+ /*
+ ** Clear the Rup lock to prevent mutual exclusion.
+ */
+ if (CmdBlkP->PostFuncP) {
+ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+ (*CmdBlkP->PostFuncP) (CmdBlkP->PostArg, CmdBlkP);
+ rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+ }
+
+ /*
+ ** ....clear the pending flag....
+ */
+ UnixRupP->CmdPendingP = NULL;
+
+ /*
+ ** ....and return the command block to the freelist.
+ */
+ RIOFreeCmdBlk(CmdBlkP);
+ }
+
+ /*
+ ** If there is a command for this rup, and the rup
+ ** is idle, then process the command
+ */
+ if ((CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */
+ (UnixRupP->CmdPendingP == NULL) && (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) {
+ /*
+ ** if the pre-function is non-zero, call it.
+ ** If it returns RIO_FAIL then don't
+ ** send this command yet!
+ */
+ if (!(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP) : 1)) {
+ rio_dprintk(RIO_DEBUG_CMD, "Not ready to start command %p\n", CmdBlkP);
+ } else {
+ rio_dprintk(RIO_DEBUG_CMD, "Start new command %p Cmd byte is 0x%x\n", CmdBlkP, CmdBlkP->Packet.data[0]);
+ /*
+ ** Whammy! blat that pack!
+ */
+ HostP->Copy(&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->txpkt)), sizeof(struct PKT));
+
+ /*
+ ** remove the command from the rup command queue...
+ */
+ UnixRupP->CmdsWaitingP = CmdBlkP->NextP;
+
+ /*
+ ** ...and place it on the pending position.
+ */
+ UnixRupP->CmdPendingP = CmdBlkP;
+
+ /*
+ ** set the command register
+ */
+ writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol);
+
+ /*
+ ** the command block will be freed
+ ** when the command has been processed.
+ */
+ }
+ }
+ spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+ } while (Rup);
+}
+
+int RIOWFlushMark(unsigned long iPortP, struct CmdBlk *CmdBlkP)
+{
+ struct Port *PortP = (struct Port *) iPortP;
+ unsigned long flags;
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->WflushFlag++;
+ PortP->MagicFlags |= MAGIC_FLUSH;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return RIOUnUse(iPortP, CmdBlkP);
+}
+
+int RIORFlushEnable(unsigned long iPortP, struct CmdBlk *CmdBlkP)
+{
+ struct Port *PortP = (struct Port *) iPortP;
+ struct PKT __iomem *PacketP;
+ unsigned long flags;
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ while (can_remove_receive(&PacketP, PortP)) {
+ remove_receive(PortP);
+ put_free_end(PortP->HostP, PacketP);
+ }
+
+ if (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET) {
+ /*
+ ** MAGIC! (Basically, handshake the RX buffer, so that
+ ** the RTAs upstream can be re-enabled.)
+ */
+ rio_dprintk(RIO_DEBUG_CMD, "Util: Set RX handshake bit\n");
+ writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake);
+ }
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return RIOUnUse(iPortP, CmdBlkP);
+}
+
+int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP)
+{
+ struct Port *PortP = (struct Port *) iPortP;
+ unsigned long flags;
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ rio_dprintk(RIO_DEBUG_CMD, "Decrement in use count for port\n");
+
+ if (PortP->InUse) {
+ if (--PortP->InUse != NOT_INUSE) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return 0;
+ }
+ }
+ /*
+ ** While PortP->InUse is set (i.e. a preemptive command has been sent to
+ ** the RTA and is awaiting completion), any transmit data is prevented from
+ ** being transferred from the write queue into the transmit packets
+ ** (add_transmit) and no furthur transmit interrupt will be sent for that
+ ** data. The next interrupt will occur up to 500ms later (RIOIntr is called
+ ** twice a second as a saftey measure). This was the case when kermit was
+ ** used to send data into a RIO port. After each packet was sent, TCFLSH
+ ** was called to flush the read queue preemptively. PortP->InUse was
+ ** incremented, thereby blocking the 6 byte acknowledgement packet
+ ** transmitted back. This acknowledgment hung around for 500ms before
+ ** being sent, thus reducing input performance substantially!.
+ ** When PortP->InUse becomes NOT_INUSE, we must ensure that any data
+ ** hanging around in the transmit buffer is sent immediately.
+ */
+ writew(1, &PortP->HostP->ParmMapP->tx_intr);
+ /* What to do here ..
+ wakeup( (caddr_t)&(PortP->InUse) );
+ */
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return 0;
+}
+
+/*
+**
+** How to use this file:
+**
+** To send a command down a rup, you need to allocate a command block, fill
+** in the packet information, fill in the command number, fill in the pre-
+** and post- functions and arguments, and then add the command block to the
+** queue of command blocks for the port in question. When the port is idle,
+** then the pre-function will be called. If this returns RIO_FAIL then the
+** command will be re-queued and tried again at a later date (probably in one
+** clock tick). If the pre-function returns NOT RIO_FAIL, then the command
+** packet will be queued on the RUP, and the txcontrol field set to the
+** command number. When the txcontrol field has changed from being the
+** command number, then the post-function will be called, with the argument
+** specified earlier, a pointer to the command block, and the value of
+** txcontrol.
+**
+** To allocate a command block, call RIOGetCmdBlk(). This returns a pointer
+** to the command block structure allocated, or NULL if there aren't any.
+** The block will have been zeroed for you.
+**
+** The structure has the following fields:
+**
+** struct CmdBlk
+** {
+** struct CmdBlk *NextP; ** Pointer to next command block **
+** struct PKT Packet; ** A packet, to copy to the rup **
+** int (*PreFuncP)(); ** The func to call to check if OK **
+** int PreArg; ** The arg for the func **
+** int (*PostFuncP)(); ** The func to call when completed **
+** int PostArg; ** The arg for the func **
+** };
+**
+** You need to fill in ALL fields EXCEPT NextP, which is used to link the
+** blocks together either on the free list or on the Rup list.
+**
+** Packet is an actual packet structure to be filled in with the packet
+** information associated with the command. You need to fill in everything,
+** as the command processor doesn't process the command packet in any way.
+**
+** The PreFuncP is called before the packet is enqueued on the host rup.
+** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must
+** return !RIO_FAIL to have the packet queued on the rup, and RIO_FAIL
+** if the packet is NOT to be queued.
+**
+** The PostFuncP is called when the command has completed. It is called
+** as (*PostFuncP)(PostArg, CmdBlkP, txcontrol);. PostFuncP is not expected
+** to return a value. PostFuncP does NOT need to free the command block,
+** as this happens automatically after PostFuncP returns.
+**
+** Once the command block has been filled in, it is attached to the correct
+** queue by calling RIOQueueCmdBlk( HostP, Rup, CmdBlkP ) where HostP is
+** a pointer to the struct Host, Rup is the NUMBER of the rup (NOT a pointer
+** to it!), and CmdBlkP is the pointer to the command block allocated using
+** RIOGetCmdBlk().
+**
+*/
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
new file mode 100644
index 0000000..eecee0f
--- /dev/null
+++ b/drivers/char/rio/rioctrl.c
@@ -0,0 +1,1503 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioctrl.c
+** SID : 1.3
+** Last Modified : 11/6/98 10:33:42
+** Retrieved : 11/6/98 10:33:49
+**
+** ident @(#)rioctrl.c 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+static struct LpbReq LpbReq;
+static struct RupReq RupReq;
+static struct PortReq PortReq;
+static struct HostReq HostReq; /* oh really? global? and no locking? */
+static struct HostDpRam HostDpRam;
+static struct DebugCtrl DebugCtrl;
+static struct Map MapEnt;
+static struct PortSetup PortSetup;
+static struct DownLoad DownLoad;
+static struct SendPack SendPack;
+/* static struct StreamInfo StreamInfo; */
+/* static char modemtable[RIO_PORTS]; */
+static struct SpecialRupCmd SpecialRupCmd;
+static struct PortParams PortParams;
+static struct portStats portStats;
+
+static struct SubCmdStruct {
+ ushort Host;
+ ushort Rup;
+ ushort Port;
+ ushort Addr;
+} SubCmd;
+
+struct PortTty {
+ uint port;
+ struct ttystatics Tty;
+};
+
+static struct PortTty PortTty;
+typedef struct ttystatics TERMIO;
+
+/*
+** This table is used when the config.rio downloads bin code to the
+** driver. We index the table using the product code, 0-F, and call
+** the function pointed to by the entry, passing the information
+** about the boot.
+** The RIOBootCodeUNKNOWN entry is there to politely tell the calling
+** process to bog off.
+*/
+static int
+ (*RIOBootTable[MAX_PRODUCT]) (struct rio_info *, struct DownLoad *) = {
+ /* 0 */ RIOBootCodeHOST,
+ /* Host Card */
+ /* 1 */ RIOBootCodeRTA,
+ /* RTA */
+};
+
+#define drv_makedev(maj, min) ((((uint) maj & 0xff) << 8) | ((uint) min & 0xff))
+
+static int copy_from_io(void __user *to, void __iomem *from, size_t size)
+{
+ void *buf = kmalloc(size, GFP_KERNEL);
+ int res = -ENOMEM;
+ if (buf) {
+ rio_memcpy_fromio(buf, from, size);
+ res = copy_to_user(to, buf, size);
+ kfree(buf);
+ }
+ return res;
+}
+
+int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su)
+{
+ uint Host; /* leave me unsigned! */
+ uint port; /* and me! */
+ struct Host *HostP;
+ ushort loop;
+ int Entry;
+ struct Port *PortP;
+ struct PKT __iomem *PacketP;
+ int retval = 0;
+ unsigned long flags;
+ void __user *argp = (void __user *)arg;
+
+ func_enter();
+
+ /* Confuse the compiler to think that we've initialized these */
+ Host = 0;
+ PortP = NULL;
+
+ rio_dprintk(RIO_DEBUG_CTRL, "control ioctl cmd: 0x%x arg: %p\n", cmd, argp);
+
+ switch (cmd) {
+ /*
+ ** RIO_SET_TIMER
+ **
+ ** Change the value of the host card interrupt timer.
+ ** If the host card number is -1 then all host cards are changed
+ ** otherwise just the specified host card will be changed.
+ */
+ case RIO_SET_TIMER:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_TIMER to %ldms\n", arg);
+ {
+ int host, value;
+ host = (arg >> 16) & 0x0000FFFF;
+ value = arg & 0x0000ffff;
+ if (host == -1) {
+ for (host = 0; host < p->RIONumHosts; host++) {
+ if (p->RIOHosts[host].Flags == RC_RUNNING) {
+ writew(value, &p->RIOHosts[host].ParmMapP->timer);
+ }
+ }
+ } else if (host >= p->RIONumHosts) {
+ return -EINVAL;
+ } else {
+ if (p->RIOHosts[host].Flags == RC_RUNNING) {
+ writew(value, &p->RIOHosts[host].ParmMapP->timer);
+ }
+ }
+ }
+ return 0;
+
+ case RIO_FOAD_RTA:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_FOAD_RTA\n");
+ return RIOCommandRta(p, arg, RIOFoadRta);
+
+ case RIO_ZOMBIE_RTA:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_ZOMBIE_RTA\n");
+ return RIOCommandRta(p, arg, RIOZombieRta);
+
+ case RIO_IDENTIFY_RTA:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_IDENTIFY_RTA\n");
+ return RIOIdentifyRta(p, argp);
+
+ case RIO_KILL_NEIGHBOUR:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_KILL_NEIGHBOUR\n");
+ return RIOKillNeighbour(p, argp);
+
+ case SPECIAL_RUP_CMD:
+ {
+ struct CmdBlk *CmdBlkP;
+
+ rio_dprintk(RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD\n");
+ if (copy_from_user(&SpecialRupCmd, argp, sizeof(SpecialRupCmd))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD copy failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ CmdBlkP = RIOGetCmdBlk();
+ if (!CmdBlkP) {
+ rio_dprintk(RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD GetCmdBlk failed\n");
+ return -ENXIO;
+ }
+ CmdBlkP->Packet = SpecialRupCmd.Packet;
+ if (SpecialRupCmd.Host >= p->RIONumHosts)
+ SpecialRupCmd.Host = 0;
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue special rup command for host %d rup %d\n", SpecialRupCmd.Host, SpecialRupCmd.RupNum);
+ if (RIOQueueCmdBlk(&p->RIOHosts[SpecialRupCmd.Host], SpecialRupCmd.RupNum, CmdBlkP) == RIO_FAIL) {
+ printk(KERN_WARNING "rio: FAILED TO QUEUE SPECIAL RUP COMMAND\n");
+ }
+ return 0;
+ }
+
+ case RIO_DEBUG_MEM:
+ return -EPERM;
+
+ case RIO_ALL_MODEM:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_ALL_MODEM\n");
+ p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+ return -EINVAL;
+
+ case RIO_GET_TABLE:
+ /*
+ ** Read the routing table from the device driver to user space
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_TABLE\n");
+
+ if ((retval = RIOApel(p)) != 0)
+ return retval;
+
+ if (copy_to_user(argp, p->RIOConnectTable, TOTAL_MAP_ENTRIES * sizeof(struct Map))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_TABLE copy failed\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+
+ {
+ int entry;
+ rio_dprintk(RIO_DEBUG_CTRL, "*****\nMAP ENTRIES\n");
+ for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
+ if ((p->RIOConnectTable[entry].ID == 0) && (p->RIOConnectTable[entry].HostUniqueNum == 0) && (p->RIOConnectTable[entry].RtaUniqueNum == 0))
+ continue;
+
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Flags = 0x%x\n", entry, (int) p->RIOConnectTable[entry].Flags);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.SysPort = 0x%x\n", entry, (int) p->RIOConnectTable[entry].SysPort);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link);
+ rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name);
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "*****\nEND MAP ENTRIES\n");
+ }
+ p->RIOQuickCheck = NOT_CHANGED; /* a table has been gotten */
+ return 0;
+
+ case RIO_PUT_TABLE:
+ /*
+ ** Write the routing table to the device driver from user space
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_TABLE\n");
+
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_TABLE !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&p->RIOConnectTable[0], argp, TOTAL_MAP_ENTRIES * sizeof(struct Map))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_TABLE copy failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+/*
+***********************************
+ {
+ int entry;
+ rio_dprint(RIO_DEBUG_CTRL, ("*****\nMAP ENTRIES\n") );
+ for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ )
+ {
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Flags = 0x%x\n", entry, p->RIOConnectTable[entry].Flags ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.SysPort = 0x%x\n", entry, p->RIOConnectTable[entry].SysPort ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[0].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[0].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[1].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[1].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[2].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[2].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[3].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Top[4].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) );
+ rio_dprint(RIO_DEBUG_CTRL, ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) );
+ }
+ rio_dprint(RIO_DEBUG_CTRL, ("*****\nEND MAP ENTRIES\n") );
+ }
+***********************************
+*/
+ return RIONewTable(p);
+
+ case RIO_GET_BINDINGS:
+ /*
+ ** Send bindings table, containing unique numbers of RTAs owned
+ ** by this system to user space
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_BINDINGS\n");
+
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_BINDINGS !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_to_user(argp, p->RIOBindTab, (sizeof(ulong) * MAX_RTA_BINDINGS))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_BINDINGS copy failed\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+
+ case RIO_PUT_BINDINGS:
+ /*
+ ** Receive a bindings table, containing unique numbers of RTAs owned
+ ** by this system
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS\n");
+
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&p->RIOBindTab[0], argp, (sizeof(ulong) * MAX_RTA_BINDINGS))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS copy failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+
+ case RIO_BIND_RTA:
+ {
+ int EmptySlot = -1;
+ /*
+ ** Bind this RTA to host, so that it will be booted by
+ ** host in 'boot owned RTAs' mode.
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_BIND_RTA\n");
+
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_BIND_RTA !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ for (Entry = 0; Entry < MAX_RTA_BINDINGS; Entry++) {
+ if ((EmptySlot == -1) && (p->RIOBindTab[Entry] == 0L))
+ EmptySlot = Entry;
+ else if (p->RIOBindTab[Entry] == arg) {
+ /*
+ ** Already exists - delete
+ */
+ p->RIOBindTab[Entry] = 0L;
+ rio_dprintk(RIO_DEBUG_CTRL, "Removing Rta %ld from p->RIOBindTab\n", arg);
+ return 0;
+ }
+ }
+ /*
+ ** Dosen't exist - add
+ */
+ if (EmptySlot != -1) {
+ p->RIOBindTab[EmptySlot] = arg;
+ rio_dprintk(RIO_DEBUG_CTRL, "Adding Rta %lx to p->RIOBindTab\n", arg);
+ } else {
+ rio_dprintk(RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %lx not added\n", arg);
+ return -ENOMEM;
+ }
+ return 0;
+ }
+
+ case RIO_RESUME:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME\n");
+ port = arg;
+ if ((port < 0) || (port > 511)) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Bad port number %d\n", port);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ PortP = p->RIOPortp[port];
+ if (!PortP->Mapped) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not mapped\n", port);
+ p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+ return -EINVAL;
+ }
+ if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not open\n", port);
+ return -EINVAL;
+ }
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RIOC_RESUME) ==
+ RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME failed\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return -EBUSY;
+ } else {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Port %d resumed\n", port);
+ PortP->State |= RIO_BUSY;
+ }
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_ASSIGN_RTA:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA\n");
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&MapEnt, argp, sizeof(MapEnt))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Copy from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ return RIOAssignRta(p, &MapEnt);
+
+ case RIO_CHANGE_NAME:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_CHANGE_NAME\n");
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_CHANGE_NAME !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&MapEnt, argp, sizeof(MapEnt))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Copy from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ return RIOChangeName(p, &MapEnt);
+
+ case RIO_DELETE_RTA:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_DELETE_RTA\n");
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_DELETE_RTA !Root\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&MapEnt, argp, sizeof(MapEnt))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Copy from data space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ return RIODeleteRta(p, &MapEnt);
+
+ case RIO_QUICK_CHECK:
+ if (copy_to_user(argp, &p->RIORtaDisCons, sizeof(unsigned int))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+
+ case RIO_LAST_ERROR:
+ if (copy_to_user(argp, &p->RIOError, sizeof(struct Error)))
+ return -EFAULT;
+ return 0;
+
+ case RIO_GET_LOG:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_LOG\n");
+ return -EINVAL;
+
+ case RIO_GET_MODTYPE:
+ if (copy_from_user(&port, argp, sizeof(unsigned int))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Get module type for port %d\n", port);
+ if (port < 0 || port > 511) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Bad port number %d\n", port);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ PortP = (p->RIOPortp[port]);
+ if (!PortP->Mapped) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Port %d not mapped\n", port);
+ p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+ return -EINVAL;
+ }
+ /*
+ ** Return module type of port
+ */
+ port = PortP->HostP->UnixRups[PortP->RupNum].ModTypes;
+ if (copy_to_user(argp, &port, sizeof(unsigned int))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return (0);
+ case RIO_BLOCK_OPENS:
+ rio_dprintk(RIO_DEBUG_CTRL, "Opens block until booted\n");
+ for (Entry = 0; Entry < RIO_PORTS; Entry++) {
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ p->RIOPortp[Entry]->WaitUntilBooted = 1;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ }
+ return 0;
+
+ case RIO_SETUP_PORTS:
+ rio_dprintk(RIO_DEBUG_CTRL, "Setup ports\n");
+ if (copy_from_user(&PortSetup, argp, sizeof(PortSetup))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "EFAULT");
+ return -EFAULT;
+ }
+ if (PortSetup.From > PortSetup.To || PortSetup.To >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ rio_dprintk(RIO_DEBUG_CTRL, "ENXIO");
+ return -ENXIO;
+ }
+ if (PortSetup.XpCps > p->RIOConf.MaxXpCps || PortSetup.XpCps < p->RIOConf.MinXpCps) {
+ p->RIOError.Error = XPRINT_CPS_OUT_OF_RANGE;
+ rio_dprintk(RIO_DEBUG_CTRL, "EINVAL");
+ return -EINVAL;
+ }
+ if (!p->RIOPortp) {
+ printk(KERN_ERR "rio: No p->RIOPortp array!\n");
+ rio_dprintk(RIO_DEBUG_CTRL, "No p->RIOPortp array!\n");
+ return -EIO;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "entering loop (%d %d)!\n", PortSetup.From, PortSetup.To);
+ for (loop = PortSetup.From; loop <= PortSetup.To; loop++) {
+ rio_dprintk(RIO_DEBUG_CTRL, "in loop (%d)!\n", loop);
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "after loop (%d)!\n", loop);
+ rio_dprintk(RIO_DEBUG_CTRL, "Retval:%x\n", retval);
+ return retval;
+
+ case RIO_GET_PORT_SETUP:
+ rio_dprintk(RIO_DEBUG_CTRL, "Get port setup\n");
+ if (copy_from_user(&PortSetup, argp, sizeof(PortSetup))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (PortSetup.From >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+
+ port = PortSetup.To = PortSetup.From;
+ PortSetup.IxAny = (p->RIOPortp[port]->Config & RIO_IXANY) ? 1 : 0;
+ PortSetup.IxOn = (p->RIOPortp[port]->Config & RIO_IXON) ? 1 : 0;
+ PortSetup.Drain = (p->RIOPortp[port]->Config & RIO_WAITDRAIN) ? 1 : 0;
+ PortSetup.Store = p->RIOPortp[port]->Store;
+ PortSetup.Lock = p->RIOPortp[port]->Lock;
+ PortSetup.XpCps = p->RIOPortp[port]->Xprint.XpCps;
+ memcpy(PortSetup.XpOn, p->RIOPortp[port]->Xprint.XpOn, MAX_XP_CTRL_LEN);
+ memcpy(PortSetup.XpOff, p->RIOPortp[port]->Xprint.XpOff, MAX_XP_CTRL_LEN);
+ PortSetup.XpOn[MAX_XP_CTRL_LEN - 1] = '\0';
+ PortSetup.XpOff[MAX_XP_CTRL_LEN - 1] = '\0';
+
+ if (copy_to_user(argp, &PortSetup, sizeof(PortSetup))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_GET_PORT_PARAMS:
+ rio_dprintk(RIO_DEBUG_CTRL, "Get port params\n");
+ if (copy_from_user(&PortParams, argp, sizeof(struct PortParams))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (PortParams.Port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ PortP = (p->RIOPortp[PortParams.Port]);
+ PortParams.Config = PortP->Config;
+ PortParams.State = PortP->State;
+ rio_dprintk(RIO_DEBUG_CTRL, "Port %d\n", PortParams.Port);
+
+ if (copy_to_user(argp, &PortParams, sizeof(struct PortParams))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_GET_PORT_TTY:
+ rio_dprintk(RIO_DEBUG_CTRL, "Get port tty\n");
+ if (copy_from_user(&PortTty, argp, sizeof(struct PortTty))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (PortTty.port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+
+ rio_dprintk(RIO_DEBUG_CTRL, "Port %d\n", PortTty.port);
+ PortP = (p->RIOPortp[PortTty.port]);
+ if (copy_to_user(argp, &PortTty, sizeof(struct PortTty))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_SET_PORT_TTY:
+ if (copy_from_user(&PortTty, argp, sizeof(struct PortTty))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Set port %d tty\n", PortTty.port);
+ if (PortTty.port >= (ushort) RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ PortP = (p->RIOPortp[PortTty.port]);
+ RIOParam(PortP, RIOC_CONFIG, PortP->State & RIO_MODEM,
+ OK_TO_SLEEP);
+ return retval;
+
+ case RIO_SET_PORT_PARAMS:
+ rio_dprintk(RIO_DEBUG_CTRL, "Set port params\n");
+ if (copy_from_user(&PortParams, argp, sizeof(PortParams))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (PortParams.Port >= (ushort) RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ PortP = (p->RIOPortp[PortParams.Port]);
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->Config = PortParams.Config;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_GET_PORT_STATS:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_PORT_STATS\n");
+ if (copy_from_user(&portStats, argp, sizeof(struct portStats))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ PortP = (p->RIOPortp[portStats.port]);
+ portStats.gather = PortP->statsGather;
+ portStats.txchars = PortP->txchars;
+ portStats.rxchars = PortP->rxchars;
+ portStats.opens = PortP->opens;
+ portStats.closes = PortP->closes;
+ portStats.ioctls = PortP->ioctls;
+ if (copy_to_user(argp, &portStats, sizeof(struct portStats))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_RESET_PORT_STATS:
+ port = arg;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESET_PORT_STATS\n");
+ if (port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ PortP = (p->RIOPortp[port]);
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->txchars = 0;
+ PortP->rxchars = 0;
+ PortP->opens = 0;
+ PortP->closes = 0;
+ PortP->ioctls = 0;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_GATHER_PORT_STATS:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GATHER_PORT_STATS\n");
+ if (copy_from_user(&portStats, argp, sizeof(struct portStats))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ PortP = (p->RIOPortp[portStats.port]);
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->statsGather = portStats.gather;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_READ_CONFIG:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_CONFIG\n");
+ if (copy_to_user(argp, &p->RIOConf, sizeof(struct Conf))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_SET_CONFIG:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_CONFIG\n");
+ if (!su) {
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&p->RIOConf, argp, sizeof(struct Conf))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ /*
+ ** move a few value around
+ */
+ for (Host = 0; Host < p->RIONumHosts; Host++)
+ if ((p->RIOHosts[Host].Flags & RUN_STATE) == RC_RUNNING)
+ writew(p->RIOConf.Timer, &p->RIOHosts[Host].ParmMapP->timer);
+ return retval;
+
+ case RIO_START_POLLER:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_START_POLLER\n");
+ return -EINVAL;
+
+ case RIO_STOP_POLLER:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_STOP_POLLER\n");
+ if (!su) {
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ p->RIOPolling = NOT_POLLING;
+ return retval;
+
+ case RIO_SETDEBUG:
+ case RIO_GETDEBUG:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SETDEBUG/RIO_GETDEBUG\n");
+ if (copy_from_user(&DebugCtrl, argp, sizeof(DebugCtrl))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (DebugCtrl.SysPort == NO_PORT) {
+ if (cmd == RIO_SETDEBUG) {
+ if (!su) {
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ p->rio_debug = DebugCtrl.Debug;
+ p->RIODebugWait = DebugCtrl.Wait;
+ rio_dprintk(RIO_DEBUG_CTRL, "Set global debug to 0x%x set wait to 0x%x\n", p->rio_debug, p->RIODebugWait);
+ } else {
+ rio_dprintk(RIO_DEBUG_CTRL, "Get global debug 0x%x wait 0x%x\n", p->rio_debug, p->RIODebugWait);
+ DebugCtrl.Debug = p->rio_debug;
+ DebugCtrl.Wait = p->RIODebugWait;
+ if (copy_to_user(argp, &DebugCtrl, sizeof(DebugCtrl))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", DebugCtrl.SysPort);
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ }
+ } else if (DebugCtrl.SysPort >= RIO_PORTS && DebugCtrl.SysPort != NO_PORT) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", DebugCtrl.SysPort);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ } else if (cmd == RIO_SETDEBUG) {
+ if (!su) {
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ p->RIOPortp[DebugCtrl.SysPort]->Debug = DebugCtrl.Debug;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SETDEBUG 0x%x\n", p->RIOPortp[DebugCtrl.SysPort]->Debug);
+ } else {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GETDEBUG 0x%x\n", p->RIOPortp[DebugCtrl.SysPort]->Debug);
+ DebugCtrl.Debug = p->RIOPortp[DebugCtrl.SysPort]->Debug;
+ if (copy_to_user(argp, &DebugCtrl, sizeof(DebugCtrl))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_GETDEBUG: Bad copy to user space\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ }
+ return retval;
+
+ case RIO_VERSID:
+ /*
+ ** Enquire about the release and version.
+ ** We return MAX_VERSION_LEN bytes, being a
+ ** textual null terminated string.
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_VERSID\n");
+ if (copy_to_user(argp, RIOVersid(), sizeof(struct rioVersion))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_VERSID: Bad copy to user space (host=%d)\n", Host);
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_NUM_HOSTS:
+ /*
+ ** Enquire as to the number of hosts located
+ ** at init time.
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_NUM_HOSTS\n");
+ if (copy_to_user(argp, &p->RIONumHosts, sizeof(p->RIONumHosts))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_NUM_HOSTS: Bad copy to user space\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_HOST_FOAD:
+ /*
+ ** Kill host. This may not be in the final version...
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_FOAD %ld\n", arg);
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_FOAD: Not super user\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ p->RIOHalted = 1;
+ p->RIOSystemUp = 0;
+
+ for (Host = 0; Host < p->RIONumHosts; Host++) {
+ (void) RIOBoardTest(p->RIOHosts[Host].PaddrP, p->RIOHosts[Host].Caddr, p->RIOHosts[Host].Type, p->RIOHosts[Host].Slot);
+ memset(&p->RIOHosts[Host].Flags, 0, ((char *) &p->RIOHosts[Host].____end_marker____) - ((char *) &p->RIOHosts[Host].Flags));
+ p->RIOHosts[Host].Flags = RC_WAITING;
+ }
+ RIOFoadWakeup(p);
+ p->RIONumBootPkts = 0;
+ p->RIOBooting = 0;
+ printk("HEEEEELP!\n");
+
+ for (loop = 0; loop < RIO_PORTS; loop++) {
+ spin_lock_init(&p->RIOPortp[loop]->portSem);
+ p->RIOPortp[loop]->InUse = NOT_INUSE;
+ }
+
+ p->RIOSystemUp = 0;
+ return retval;
+
+ case RIO_DOWNLOAD:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD\n");
+ if (!su) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Not super user\n");
+ p->RIOError.Error = NOT_SUPER_USER;
+ return -EPERM;
+ }
+ if (copy_from_user(&DownLoad, argp, sizeof(DownLoad))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Copy in from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Copied in download code for product code 0x%x\n", DownLoad.ProductCode);
+
+ /*
+ ** It is important that the product code is an unsigned object!
+ */
+ if (DownLoad.ProductCode > MAX_PRODUCT) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Bad product code %d passed\n", DownLoad.ProductCode);
+ p->RIOError.Error = NO_SUCH_PRODUCT;
+ return -ENXIO;
+ }
+ /*
+ ** do something!
+ */
+ retval = (*(RIOBootTable[DownLoad.ProductCode])) (p, &DownLoad);
+ /* <-- Panic */
+ p->RIOHalted = 0;
+ /*
+ ** and go back, content with a job well completed.
+ */
+ return retval;
+
+ case RIO_PARMS:
+ {
+ unsigned int host;
+
+ if (copy_from_user(&host, argp, sizeof(host))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Copy in from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ /*
+ ** Fetch the parmmap
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PARMS\n");
+ if (copy_from_io(argp, p->RIOHosts[host].ParmMapP, sizeof(PARM_MAP))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_PARMS: Copy out to user space failed\n");
+ return -EFAULT;
+ }
+ }
+ return retval;
+
+ case RIO_HOST_REQ:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ\n");
+ if (copy_from_user(&HostReq, argp, sizeof(HostReq))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Copy in from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (HostReq.HostNum >= p->RIONumHosts) {
+ p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Illegal host number %d\n", HostReq.HostNum);
+ return -ENXIO;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Request for host %d\n", HostReq.HostNum);
+
+ if (copy_to_user(HostReq.HostP, &p->RIOHosts[HostReq.HostNum], sizeof(struct Host))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Bad copy to user space\n");
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_HOST_DPRAM:
+ rio_dprintk(RIO_DEBUG_CTRL, "Request for DPRAM\n");
+ if (copy_from_user(&HostDpRam, argp, sizeof(HostDpRam))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Copy in from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (HostDpRam.HostNum >= p->RIONumHosts) {
+ p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Illegal host number %d\n", HostDpRam.HostNum);
+ return -ENXIO;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Request for host %d\n", HostDpRam.HostNum);
+
+ if (p->RIOHosts[HostDpRam.HostNum].Type == RIO_PCI) {
+ int off;
+ /* It's hardware like this that really gets on my tits. */
+ static unsigned char copy[sizeof(struct DpRam)];
+ for (off = 0; off < sizeof(struct DpRam); off++)
+ copy[off] = readb(p->RIOHosts[HostDpRam.HostNum].Caddr + off);
+ if (copy_to_user(HostDpRam.DpRamP, copy, sizeof(struct DpRam))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n");
+ return -EFAULT;
+ }
+ } else if (copy_from_io(HostDpRam.DpRamP, p->RIOHosts[HostDpRam.HostNum].Caddr, sizeof(struct DpRam))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n");
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_SET_BUSY:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_BUSY\n");
+ if (arg > 511) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_BUSY: Bad port number %ld\n", arg);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ p->RIOPortp[arg]->State |= RIO_BUSY;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_HOST_PORT:
+ /*
+ ** The daemon want port information
+ ** (probably for debug reasons)
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT\n");
+ if (copy_from_user(&PortReq, argp, sizeof(PortReq))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT: Copy in from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+
+ if (PortReq.SysPort >= RIO_PORTS) { /* SysPort is unsigned */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT: Illegal port number %d\n", PortReq.SysPort);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Request for port %d\n", PortReq.SysPort);
+ if (copy_to_user(PortReq.PortP, p->RIOPortp[PortReq.SysPort], sizeof(struct Port))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT: Bad copy to user space\n");
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_HOST_RUP:
+ /*
+ ** The daemon want rup information
+ ** (probably for debug reasons)
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP\n");
+ if (copy_from_user(&RupReq, argp, sizeof(RupReq))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Copy in from user space failed\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (RupReq.HostNum >= p->RIONumHosts) { /* host is unsigned */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal host number %d\n", RupReq.HostNum);
+ p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ if (RupReq.RupNum >= MAX_RUP + LINKS_PER_UNIT) { /* eek! */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal rup number %d\n", RupReq.RupNum);
+ p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ HostP = &p->RIOHosts[RupReq.HostNum];
+
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Host %d not running\n", RupReq.HostNum);
+ p->RIOError.Error = HOST_NOT_RUNNING;
+ return -EIO;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Request for rup %d from host %d\n", RupReq.RupNum, RupReq.HostNum);
+
+ if (copy_from_io(RupReq.RupP, HostP->UnixRups[RupReq.RupNum].RupP, sizeof(struct RUP))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Bad copy to user space\n");
+ return -EFAULT;
+ }
+ return retval;
+
+ case RIO_HOST_LPB:
+ /*
+ ** The daemon want lpb information
+ ** (probably for debug reasons)
+ */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB\n");
+ if (copy_from_user(&LpbReq, argp, sizeof(LpbReq))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy from user space\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (LpbReq.Host >= p->RIONumHosts) { /* host is unsigned */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal host number %d\n", LpbReq.Host);
+ p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+ if (LpbReq.Link >= LINKS_PER_UNIT) { /* eek! */
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal link number %d\n", LpbReq.Link);
+ p->RIOError.Error = LINK_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ HostP = &p->RIOHosts[LpbReq.Host];
+
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Host %d not running\n", LpbReq.Host);
+ p->RIOError.Error = HOST_NOT_RUNNING;
+ return -EIO;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Request for lpb %d from host %d\n", LpbReq.Link, LpbReq.Host);
+
+ if (copy_from_io(LpbReq.LpbP, &HostP->LinkStrP[LpbReq.Link], sizeof(struct LPB))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy to user space\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return retval;
+
+ /*
+ ** Here 3 IOCTL's that allow us to change the way in which
+ ** rio logs errors. send them just to syslog or send them
+ ** to both syslog and console or send them to just the console.
+ **
+ ** See RioStrBuf() in util.c for the other half.
+ */
+ case RIO_SYSLOG_ONLY:
+ p->RIOPrintLogState = PRINT_TO_LOG; /* Just syslog */
+ return 0;
+
+ case RIO_SYSLOG_CONS:
+ p->RIOPrintLogState = PRINT_TO_LOG_CONS; /* syslog and console */
+ return 0;
+
+ case RIO_CONS_ONLY:
+ p->RIOPrintLogState = PRINT_TO_CONS; /* Just console */
+ return 0;
+
+ case RIO_SIGNALS_ON:
+ if (p->RIOSignalProcess) {
+ p->RIOError.Error = SIGNALS_ALREADY_SET;
+ return -EBUSY;
+ }
+ /* FIXME: PID tracking */
+ p->RIOSignalProcess = current->pid;
+ p->RIOPrintDisabled = DONT_PRINT;
+ return retval;
+
+ case RIO_SIGNALS_OFF:
+ if (p->RIOSignalProcess != current->pid) {
+ p->RIOError.Error = NOT_RECEIVING_PROCESS;
+ return -EPERM;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "Clear signal process to zero\n");
+ p->RIOSignalProcess = 0;
+ return retval;
+
+ case RIO_SET_BYTE_MODE:
+ for (Host = 0; Host < p->RIONumHosts; Host++)
+ if (p->RIOHosts[Host].Type == RIO_AT)
+ p->RIOHosts[Host].Mode &= ~WORD_OPERATION;
+ return retval;
+
+ case RIO_SET_WORD_MODE:
+ for (Host = 0; Host < p->RIONumHosts; Host++)
+ if (p->RIOHosts[Host].Type == RIO_AT)
+ p->RIOHosts[Host].Mode |= WORD_OPERATION;
+ return retval;
+
+ case RIO_SET_FAST_BUS:
+ for (Host = 0; Host < p->RIONumHosts; Host++)
+ if (p->RIOHosts[Host].Type == RIO_AT)
+ p->RIOHosts[Host].Mode |= FAST_AT_BUS;
+ return retval;
+
+ case RIO_SET_SLOW_BUS:
+ for (Host = 0; Host < p->RIONumHosts; Host++)
+ if (p->RIOHosts[Host].Type == RIO_AT)
+ p->RIOHosts[Host].Mode &= ~FAST_AT_BUS;
+ return retval;
+
+ case RIO_MAP_B50_TO_50:
+ case RIO_MAP_B50_TO_57600:
+ case RIO_MAP_B110_TO_110:
+ case RIO_MAP_B110_TO_115200:
+ rio_dprintk(RIO_DEBUG_CTRL, "Baud rate mapping\n");
+ port = arg;
+ if (port < 0 || port > 511) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", port);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ switch (cmd) {
+ case RIO_MAP_B50_TO_50:
+ p->RIOPortp[port]->Config |= RIO_MAP_50_TO_50;
+ break;
+ case RIO_MAP_B50_TO_57600:
+ p->RIOPortp[port]->Config &= ~RIO_MAP_50_TO_50;
+ break;
+ case RIO_MAP_B110_TO_110:
+ p->RIOPortp[port]->Config |= RIO_MAP_110_TO_110;
+ break;
+ case RIO_MAP_B110_TO_115200:
+ p->RIOPortp[port]->Config &= ~RIO_MAP_110_TO_110;
+ break;
+ }
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_STREAM_INFO:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_STREAM_INFO\n");
+ return -EINVAL;
+
+ case RIO_SEND_PACKET:
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SEND_PACKET\n");
+ if (copy_from_user(&SendPack, argp, sizeof(SendPack))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_SEND_PACKET: Bad copy from user space\n");
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ if (SendPack.PortNum >= 128) {
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -ENXIO;
+ }
+
+ PortP = p->RIOPortp[SendPack.PortNum];
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ if (!can_add_transmit(&PacketP, PortP)) {
+ p->RIOError.Error = UNIT_IS_IN_USE;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return -ENOSPC;
+ }
+
+ for (loop = 0; loop < (ushort) (SendPack.Len & 127); loop++)
+ writeb(SendPack.Data[loop], &PacketP->data[loop]);
+
+ writeb(SendPack.Len, &PacketP->len);
+
+ add_transmit(PortP);
+ /*
+ ** Count characters transmitted for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->txchars += (SendPack.Len & 127);
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+
+ case RIO_NO_MESG:
+ if (su)
+ p->RIONoMessage = 1;
+ return su ? 0 : -EPERM;
+
+ case RIO_MESG:
+ if (su)
+ p->RIONoMessage = 0;
+ return su ? 0 : -EPERM;
+
+ case RIO_WHAT_MESG:
+ if (copy_to_user(argp, &p->RIONoMessage, sizeof(p->RIONoMessage))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_WHAT_MESG: Bad copy to user space\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+
+ case RIO_MEM_DUMP:
+ if (copy_from_user(&SubCmd, argp, sizeof(struct SubCmdStruct))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP host %d rup %d addr %x\n", SubCmd.Host, SubCmd.Rup, SubCmd.Addr);
+
+ if (SubCmd.Rup >= MAX_RUP + LINKS_PER_UNIT) {
+ p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ if (SubCmd.Host >= p->RIONumHosts) {
+ p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ port = p->RIOHosts[SubCmd.Host].UnixRups[SubCmd.Rup].BaseSysPort;
+
+ PortP = p->RIOPortp[port];
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ if (RIOPreemptiveCmd(p, PortP, RIOC_MEMDUMP) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return -EBUSY;
+ } else
+ PortP->State |= RIO_BUSY;
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (copy_to_user(argp, p->RIOMemDump, MEMDUMP_SIZE)) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP copy failed\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+
+ case RIO_TICK:
+ if (arg >= p->RIONumHosts)
+ return -EINVAL;
+ rio_dprintk(RIO_DEBUG_CTRL, "Set interrupt for host %ld\n", arg);
+ writeb(0xFF, &p->RIOHosts[arg].SetInt);
+ return 0;
+
+ case RIO_TOCK:
+ if (arg >= p->RIONumHosts)
+ return -EINVAL;
+ rio_dprintk(RIO_DEBUG_CTRL, "Clear interrupt for host %ld\n", arg);
+ writeb(0xFF, &p->RIOHosts[arg].ResetInt);
+ return 0;
+
+ case RIO_READ_CHECK:
+ /* Check reads for pkts with data[0] the same */
+ p->RIOReadCheck = !p->RIOReadCheck;
+ if (copy_to_user(argp, &p->RIOReadCheck, sizeof(unsigned int))) {
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+
+ case RIO_READ_REGISTER:
+ if (copy_from_user(&SubCmd, argp, sizeof(struct SubCmdStruct))) {
+ p->RIOError.Error = COPYIN_FAILED;
+ return -EFAULT;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER host %d rup %d port %d reg %x\n", SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr);
+
+ if (SubCmd.Port > 511) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", SubCmd.Port);
+ p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ if (SubCmd.Rup >= MAX_RUP + LINKS_PER_UNIT) {
+ p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ if (SubCmd.Host >= p->RIONumHosts) {
+ p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ port = p->RIOHosts[SubCmd.Host].UnixRups[SubCmd.Rup].BaseSysPort + SubCmd.Port;
+ PortP = p->RIOPortp[port];
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ if (RIOPreemptiveCmd(p, PortP, RIOC_READ_REGISTER) ==
+ RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return -EBUSY;
+ } else
+ PortP->State |= RIO_BUSY;
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (copy_to_user(argp, &p->CdRegister, sizeof(unsigned int))) {
+ rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER copy failed\n");
+ p->RIOError.Error = COPYOUT_FAILED;
+ return -EFAULT;
+ }
+ return 0;
+ /*
+ ** rio_make_dev: given port number (0-511) ORed with port type
+ ** (RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT) return dev_t
+ ** value to pass to mknod to create the correct device node.
+ */
+ case RIO_MAKE_DEV:
+ {
+ unsigned int port = arg & RIO_MODEM_MASK;
+ unsigned int ret;
+
+ switch (arg & RIO_DEV_MASK) {
+ case RIO_DEV_DIRECT:
+ ret = drv_makedev(MAJOR(dev), port);
+ rio_dprintk(RIO_DEBUG_CTRL, "Makedev direct 0x%x is 0x%x\n", port, ret);
+ return ret;
+ case RIO_DEV_MODEM:
+ ret = drv_makedev(MAJOR(dev), (port | RIO_MODEM_BIT));
+ rio_dprintk(RIO_DEBUG_CTRL, "Makedev modem 0x%x is 0x%x\n", port, ret);
+ return ret;
+ case RIO_DEV_XPRINT:
+ ret = drv_makedev(MAJOR(dev), port);
+ rio_dprintk(RIO_DEBUG_CTRL, "Makedev printer 0x%x is 0x%x\n", port, ret);
+ return ret;
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "MAKE Device is called\n");
+ return -EINVAL;
+ }
+ /*
+ ** rio_minor: given a dev_t from a stat() call, return
+ ** the port number (0-511) ORed with the port type
+ ** ( RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT )
+ */
+ case RIO_MINOR:
+ {
+ dev_t dv;
+ int mino;
+ unsigned long ret;
+
+ dv = (dev_t) (arg);
+ mino = RIO_UNMODEM(dv);
+
+ if (RIO_ISMODEM(dv)) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Minor for device 0x%x: modem %d\n", dv, mino);
+ ret = mino | RIO_DEV_MODEM;
+ } else {
+ rio_dprintk(RIO_DEBUG_CTRL, "Minor for device 0x%x: direct %d\n", dv, mino);
+ ret = mino | RIO_DEV_DIRECT;
+ }
+ return ret;
+ }
+ }
+ rio_dprintk(RIO_DEBUG_CTRL, "INVALID DAEMON IOCTL 0x%x\n", cmd);
+ p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+
+ func_exit();
+ return -EINVAL;
+}
+
+/*
+** Pre-emptive commands go on RUPs and are only one byte long.
+*/
+int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
+{
+ struct CmdBlk *CmdBlkP;
+ struct PktCmd_M *PktCmdP;
+ int Ret;
+ ushort rup;
+ int port;
+
+ if (PortP->State & RIO_DELETED) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Preemptive command to deleted RTA ignored\n");
+ return RIO_FAIL;
+ }
+
+ if ((PortP->InUse == (typeof(PortP->InUse))-1) ||
+ !(CmdBlkP = RIOGetCmdBlk())) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block "
+ "for command %d on port %d\n", Cmd, PortP->PortNum);
+ return RIO_FAIL;
+ }
+
+ rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n",
+ CmdBlkP, PortP->InUse);
+
+ PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0];
+
+ CmdBlkP->Packet.src_unit = 0;
+ if (PortP->SecondBlock)
+ rup = PortP->ID2;
+ else
+ rup = PortP->RupNum;
+ CmdBlkP->Packet.dest_unit = rup;
+ CmdBlkP->Packet.src_port = COMMAND_RUP;
+ CmdBlkP->Packet.dest_port = COMMAND_RUP;
+ CmdBlkP->Packet.len = PKT_CMD_BIT | 2;
+ CmdBlkP->PostFuncP = RIOUnUse;
+ CmdBlkP->PostArg = (unsigned long) PortP;
+ PktCmdP->Command = Cmd;
+ port = PortP->HostPort % (ushort) PORTS_PER_RTA;
+ /*
+ ** Index ports 8-15 for 2nd block of 16 port RTA.
+ */
+ if (PortP->SecondBlock)
+ port += (ushort) PORTS_PER_RTA;
+ PktCmdP->PhbNum = port;
+
+ switch (Cmd) {
+ case RIOC_MEMDUMP:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p "
+ "(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
+ PktCmdP->SubCommand = RIOC_MEMDUMP;
+ PktCmdP->SubAddr = SubCmd.Addr;
+ break;
+ case RIOC_FCLOSE:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n",
+ CmdBlkP);
+ break;
+ case RIOC_READ_REGISTER:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) "
+ "command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
+ PktCmdP->SubCommand = RIOC_READ_REGISTER;
+ PktCmdP->SubAddr = SubCmd.Addr;
+ break;
+ case RIOC_RESUME:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n",
+ CmdBlkP);
+ break;
+ case RIOC_RFLUSH:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n",
+ CmdBlkP);
+ CmdBlkP->PostFuncP = RIORFlushEnable;
+ break;
+ case RIOC_SUSPEND:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n",
+ CmdBlkP);
+ break;
+
+ case RIOC_MGET:
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n",
+ CmdBlkP);
+ break;
+
+ case RIOC_MSET:
+ case RIOC_MBIC:
+ case RIOC_MBIS:
+ CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command "
+ "blk %p\n", CmdBlkP);
+ break;
+
+ case RIOC_WFLUSH:
+ /*
+ ** If we have queued up the maximum number of Write flushes
+ ** allowed then we should not bother sending any more to the
+ ** RTA.
+ */
+ if (PortP->WflushFlag == (typeof(PortP->WflushFlag))-1) {
+ rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, "
+ "WflushFlag about to wrap!");
+ RIOFreeCmdBlk(CmdBlkP);
+ return (RIO_FAIL);
+ } else {
+ rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command "
+ "blk %p\n", CmdBlkP);
+ CmdBlkP->PostFuncP = RIOWFlushMark;
+ }
+ break;
+ }
+
+ PortP->InUse++;
+
+ Ret = RIOQueueCmdBlk(PortP->HostP, rup, CmdBlkP);
+
+ return Ret;
+}
diff --git a/drivers/char/rio/riodrvr.h b/drivers/char/rio/riodrvr.h
new file mode 100644
index 0000000..0907e71
--- /dev/null
+++ b/drivers/char/rio/riodrvr.h
@@ -0,0 +1,138 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : riodrvr.h
+** SID : 1.3
+** Last Modified : 11/6/98 09:22:46
+** Retrieved : 11/6/98 09:22:46
+**
+** ident @(#)riodrvr.h 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __riodrvr_h
+#define __riodrvr_h
+
+#include <asm/param.h> /* for HZ */
+
+#define MEMDUMP_SIZE 32
+#define MOD_DISABLE (RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT)
+
+
+struct rio_info {
+ int mode; /* Intr or polled, word/byte */
+ spinlock_t RIOIntrSem; /* Interrupt thread sem */
+ int current_chan; /* current channel */
+ int RIOFailed; /* Not initialised ? */
+ int RIOInstallAttempts; /* no. of rio-install() calls */
+ int RIOLastPCISearch; /* status of last search */
+ int RIONumHosts; /* Number of RIO Hosts */
+ struct Host *RIOHosts; /* RIO Host values */
+ struct Port **RIOPortp; /* RIO port values */
+/*
+** 02.03.1999 ARG - ESIL 0820 fix
+** We no longer use RIOBootMode
+**
+ int RIOBootMode; * RIO boot mode *
+**
+*/
+ int RIOPrintDisabled; /* RIO printing disabled ? */
+ int RIOPrintLogState; /* RIO printing state ? */
+ int RIOPolling; /* Polling ? */
+/*
+** 09.12.1998 ARG - ESIL 0776 part fix
+** The 'RIO_QUICK_CHECK' ioctl was using RIOHalted.
+** The fix for this ESIL introduces another member (RIORtaDisCons) here to be
+** updated in RIOConCon() - to keep track of RTA connections/disconnections.
+** 'RIO_QUICK_CHECK' now returns the value of RIORtaDisCons.
+*/
+ int RIOHalted; /* halted ? */
+ int RIORtaDisCons; /* RTA connections/disconnections */
+ unsigned int RIOReadCheck; /* Rio read check */
+ unsigned int RIONoMessage; /* To display message or not */
+ unsigned int RIONumBootPkts; /* how many packets for an RTA */
+ unsigned int RIOBootCount; /* size of RTA code */
+ unsigned int RIOBooting; /* count of outstanding boots */
+ unsigned int RIOSystemUp; /* Booted ?? */
+ unsigned int RIOCounting; /* for counting interrupts */
+ unsigned int RIOIntCount; /* # of intr since last check */
+ unsigned int RIOTxCount; /* number of xmit intrs */
+ unsigned int RIORxCount; /* number of rx intrs */
+ unsigned int RIORupCount; /* number of rup intrs */
+ int RIXTimer;
+ int RIOBufferSize; /* Buffersize */
+ int RIOBufferMask; /* Buffersize */
+
+ int RIOFirstMajor; /* First host card's major no */
+
+ unsigned int RIOLastPortsMapped; /* highest port number known */
+ unsigned int RIOFirstPortsMapped; /* lowest port number known */
+
+ unsigned int RIOLastPortsBooted; /* highest port number running */
+ unsigned int RIOFirstPortsBooted; /* lowest port number running */
+
+ unsigned int RIOLastPortsOpened; /* highest port number running */
+ unsigned int RIOFirstPortsOpened; /* lowest port number running */
+
+ /* Flag to say that the topology information has been changed. */
+ unsigned int RIOQuickCheck;
+ unsigned int CdRegister; /* ??? */
+ int RIOSignalProcess; /* Signalling process */
+ int rio_debug; /* To debug ... */
+ int RIODebugWait; /* For what ??? */
+ int tpri; /* Thread prio */
+ int tid; /* Thread id */
+ unsigned int _RIO_Polled; /* Counter for polling */
+ unsigned int _RIO_Interrupted; /* Counter for interrupt */
+ int intr_tid; /* iointset return value */
+ int TxEnSem; /* TxEnable Semaphore */
+
+
+ struct Error RIOError; /* to Identify what went wrong */
+ struct Conf RIOConf; /* Configuration ??? */
+ struct ttystatics channel[RIO_PORTS]; /* channel information */
+ char RIOBootPackets[1 + (SIXTY_FOUR_K / RTA_BOOT_DATA_SIZE)]
+ [RTA_BOOT_DATA_SIZE];
+ struct Map RIOConnectTable[TOTAL_MAP_ENTRIES];
+ struct Map RIOSavedTable[TOTAL_MAP_ENTRIES];
+
+ /* RTA to host binding table for master/slave operation */
+ unsigned long RIOBindTab[MAX_RTA_BINDINGS];
+ /* RTA memory dump variable */
+ unsigned char RIOMemDump[MEMDUMP_SIZE];
+ struct ModuleInfo RIOModuleTypes[MAX_MODULE_TYPES];
+
+};
+
+
+#ifdef linux
+#define debug(x) printk x
+#else
+#define debug(x) kkprintf x
+#endif
+
+
+
+#define RIO_RESET_INT 0x7d80
+
+#endif /* __riodrvr.h */
diff --git a/drivers/char/rio/rioinfo.h b/drivers/char/rio/rioinfo.h
new file mode 100644
index 0000000..42ff1e7
--- /dev/null
+++ b/drivers/char/rio/rioinfo.h
@@ -0,0 +1,92 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioinfo.h
+** SID : 1.2
+** Last Modified : 11/6/98 14:07:49
+** Retrieved : 11/6/98 14:07:50
+**
+** ident @(#)rioinfo.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rioinfo_h
+#define __rioinfo_h
+
+/*
+** Host card data structure
+*/
+struct RioHostInfo {
+ long location; /* RIO Card Base I/O address */
+ long vector; /* RIO Card IRQ vector */
+ int bus; /* ISA/EISA/MCA/PCI */
+ int mode; /* pointer to host mode - INTERRUPT / POLLED */
+ struct old_sgttyb
+ *Sg; /* pointer to default term characteristics */
+};
+
+
+/* Mode in rio device info */
+#define INTERRUPTED_MODE 0x01 /* Interrupt is generated */
+#define POLLED_MODE 0x02 /* No interrupt */
+#define AUTO_MODE 0x03 /* Auto mode */
+
+#define WORD_ACCESS_MODE 0x10 /* Word Access Mode */
+#define BYTE_ACCESS_MODE 0x20 /* Byte Access Mode */
+
+
+/* Bus type that RIO supports */
+#define ISA_BUS 0x01 /* The card is ISA */
+#define EISA_BUS 0x02 /* The card is EISA */
+#define MCA_BUS 0x04 /* The card is MCA */
+#define PCI_BUS 0x08 /* The card is PCI */
+
+/*
+** 11.11.1998 ARG - ESIL ???? part fix
+** Moved definition for 'CHAN' here from rioinfo.c (it is now
+** called 'DEF_TERM_CHARACTERISTICS').
+*/
+
+#define DEF_TERM_CHARACTERISTICS \
+{ \
+ B19200, B19200, /* input and output speed */ \
+ 'H' - '@', /* erase char */ \
+ -1, /* 2nd erase char */ \
+ 'U' - '@', /* kill char */ \
+ ECHO | CRMOD, /* mode */ \
+ 'C' - '@', /* interrupt character */ \
+ '\\' - '@', /* quit char */ \
+ 'Q' - '@', /* start char */ \
+ 'S' - '@', /* stop char */ \
+ 'D' - '@', /* EOF */ \
+ -1, /* brk */ \
+ (LCRTBS | LCRTERA | LCRTKIL | LCTLECH), /* local mode word */ \
+ 'Z' - '@', /* process stop */ \
+ 'Y' - '@', /* delayed stop */ \
+ 'R' - '@', /* reprint line */ \
+ 'O' - '@', /* flush output */ \
+ 'W' - '@', /* word erase */ \
+ 'V' - '@' /* literal next char */ \
+}
+
+#endif /* __rioinfo_h */
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c
new file mode 100644
index 0000000..be0ba40
--- /dev/null
+++ b/drivers/char/rio/rioinit.c
@@ -0,0 +1,422 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioinit.c
+** SID : 1.3
+** Last Modified : 11/6/98 10:33:43
+** Retrieved : 11/6/98 10:33:49
+**
+** ident @(#)rioinit.c 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "rio_linux.h"
+
+int RIOPCIinit(struct rio_info *p, int Mode);
+
+static int RIOScrub(int, u8 __iomem *, int);
+
+
+/**
+** RIOAssignAT :
+**
+** Fill out the fields in the p->RIOHosts structure now we know we know
+** we have a board present.
+**
+** bits < 0 indicates 8 bit operation requested,
+** bits > 0 indicates 16 bit operation.
+*/
+
+int RIOAssignAT(struct rio_info *p, int Base, void __iomem *virtAddr, int mode)
+{
+ int bits;
+ struct DpRam __iomem *cardp = (struct DpRam __iomem *)virtAddr;
+
+ if ((Base < ONE_MEG) || (mode & BYTE_ACCESS_MODE))
+ bits = BYTE_OPERATION;
+ else
+ bits = WORD_OPERATION;
+
+ /*
+ ** Board has passed its scrub test. Fill in all the
+ ** transient stuff.
+ */
+ p->RIOHosts[p->RIONumHosts].Caddr = virtAddr;
+ p->RIOHosts[p->RIONumHosts].CardP = virtAddr;
+
+ /*
+ ** Revision 01 AT host cards don't support WORD operations,
+ */
+ if (readb(&cardp->DpRevision) == 01)
+ bits = BYTE_OPERATION;
+
+ p->RIOHosts[p->RIONumHosts].Type = RIO_AT;
+ p->RIOHosts[p->RIONumHosts].Copy = rio_copy_to_card;
+ /* set this later */
+ p->RIOHosts[p->RIONumHosts].Slot = -1;
+ p->RIOHosts[p->RIONumHosts].Mode = SLOW_LINKS | SLOW_AT_BUS | bits;
+ writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | p->RIOHosts[p->RIONumHosts].Mode | INTERRUPT_DISABLE ,
+ &p->RIOHosts[p->RIONumHosts].Control);
+ writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+ writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | p->RIOHosts[p->RIONumHosts].Mode | INTERRUPT_DISABLE,
+ &p->RIOHosts[p->RIONumHosts].Control);
+ writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+ p->RIOHosts[p->RIONumHosts].UniqueNum =
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)|
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)|
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)|
+ ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24);
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+ p->RIONumHosts++;
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Tests Passed at 0x%x\n", Base);
+ return(1);
+}
+
+static u8 val[] = {
+#ifdef VERY_LONG_TEST
+ 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+ 0xa5, 0xff, 0x5a, 0x00, 0xff, 0xc9, 0x36,
+#endif
+ 0xff, 0x00, 0x00 };
+
+#define TEST_END sizeof(val)
+
+/*
+** RAM test a board.
+** Nothing too complicated, just enough to check it out.
+*/
+int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, int slot)
+{
+ struct DpRam __iomem *DpRam = caddr;
+ void __iomem *ram[4];
+ int size[4];
+ int op, bank;
+ int nbanks;
+
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Reset host type=%d, DpRam=%p, slot=%d\n",
+ type, DpRam, slot);
+
+ RIOHostReset(type, DpRam, slot);
+
+ /*
+ ** Scrub the memory. This comes in several banks:
+ ** DPsram1 - 7000h bytes
+ ** DPsram2 - 200h bytes
+ ** DPsram3 - 7000h bytes
+ ** scratch - 1000h bytes
+ */
+
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Setup ram/size arrays\n");
+
+ size[0] = DP_SRAM1_SIZE;
+ size[1] = DP_SRAM2_SIZE;
+ size[2] = DP_SRAM3_SIZE;
+ size[3] = DP_SCRATCH_SIZE;
+
+ ram[0] = DpRam->DpSram1;
+ ram[1] = DpRam->DpSram2;
+ ram[2] = DpRam->DpSram3;
+ nbanks = (type == RIO_PCI) ? 3 : 4;
+ if (nbanks == 4)
+ ram[3] = DpRam->DpScratch;
+
+
+ if (nbanks == 3) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Memory: %p(0x%x), %p(0x%x), %p(0x%x)\n",
+ ram[0], size[0], ram[1], size[1], ram[2], size[2]);
+ } else {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: %p(0x%x), %p(0x%x), %p(0x%x), %p(0x%x)\n",
+ ram[0], size[0], ram[1], size[1], ram[2], size[2], ram[3], size[3]);
+ }
+
+ /*
+ ** This scrub operation will test for crosstalk between
+ ** banks. TEST_END is a magic number, and relates to the offset
+ ** within the 'val' array used by Scrub.
+ */
+ for (op=0; op<TEST_END; op++) {
+ for (bank=0; bank<nbanks; bank++) {
+ if (RIOScrub(op, ram[bank], size[bank]) == RIO_FAIL) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: RIOScrub band %d, op %d failed\n",
+ bank, op);
+ return RIO_FAIL;
+ }
+ }
+ }
+
+ rio_dprintk (RIO_DEBUG_INIT, "Test completed\n");
+ return 0;
+}
+
+
+/*
+** Scrub an area of RAM.
+** Define PRETEST and POSTTEST for a more thorough checking of the
+** state of the memory.
+** Call with op set to an index into the above 'val' array to determine
+** which value will be written into memory.
+** Call with op set to zero means that the RAM will not be read and checked
+** before it is written.
+** Call with op not zero and the RAM will be read and compared with val[op-1]
+** to check that the data from the previous phase was retained.
+*/
+
+static int RIOScrub(int op, u8 __iomem *ram, int size)
+{
+ int off;
+ unsigned char oldbyte;
+ unsigned char newbyte;
+ unsigned char invbyte;
+ unsigned short oldword;
+ unsigned short newword;
+ unsigned short invword;
+ unsigned short swapword;
+
+ if (op) {
+ oldbyte = val[op-1];
+ oldword = oldbyte | (oldbyte<<8);
+ } else
+ oldbyte = oldword = 0; /* Tell the compiler we've initilalized them. */
+ newbyte = val[op];
+ newword = newbyte | (newbyte<<8);
+ invbyte = ~newbyte;
+ invword = invbyte | (invbyte<<8);
+
+ /*
+ ** Check that the RAM contains the value that should have been left there
+ ** by the previous test (not applicable for pass zero)
+ */
+ if (op) {
+ for (off=0; off<size; off++) {
+ if (readb(ram + off) != oldbyte) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Pre Check 1: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, readb(ram + off));
+ return RIO_FAIL;
+ }
+ }
+ for (off=0; off<size; off+=2) {
+ if (readw(ram + off) != oldword) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Pre Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,oldword, readw(ram + off));
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Pre Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram+off+1));
+ return RIO_FAIL;
+ }
+ }
+ }
+
+ /*
+ ** Now write the INVERSE of the test data into every location, using
+ ** BYTE write operations, first checking before each byte is written
+ ** that the location contains the old value still, and checking after
+ ** the write that the location contains the data specified - this is
+ ** the BYTE read/write test.
+ */
+ for (off=0; off<size; off++) {
+ if (op && (readb(ram + off) != oldbyte)) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Pre Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, readb(ram + off));
+ return RIO_FAIL;
+ }
+ writeb(invbyte, ram + off);
+ if (readb(ram + off) != invbyte) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Inv Check: BYTE at offset 0x%x should have been=%x, was=%x\n", off, invbyte, readb(ram + off));
+ return RIO_FAIL;
+ }
+ }
+
+ /*
+ ** now, use WORD operations to write the test value into every location,
+ ** check as before that the location contains the previous test value
+ ** before overwriting, and that it contains the data value written
+ ** afterwards.
+ ** This is the WORD operation test.
+ */
+ for (off=0; off<size; off+=2) {
+ if (readw(ram + off) != invword) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Inv Check: WORD at offset 0x%x should have been=%x, was=%x\n", off, invword, readw(ram + off));
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Inv Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram+off+1));
+ return RIO_FAIL;
+ }
+
+ writew(newword, ram + off);
+ if ( readw(ram + off) != newword ) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 1: WORD at offset 0x%x should have been=%x, was=%x\n", off, newword, readw(ram + off));
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram + off + 1));
+ return RIO_FAIL;
+ }
+ }
+
+ /*
+ ** now run through the block of memory again, first in byte mode
+ ** then in word mode, and check that all the locations contain the
+ ** required test data.
+ */
+ for (off=0; off<size; off++) {
+ if (readb(ram + off) != newbyte) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Byte Check: BYTE at offset 0x%x should have been=%x, was=%x\n", off, newbyte, readb(ram + off));
+ return RIO_FAIL;
+ }
+ }
+
+ for (off=0; off<size; off+=2) {
+ if (readw(ram + off) != newword ) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 2: WORD at offset 0x%x should have been=%x, was=%x\n", off, newword, readw(ram + off));
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 2: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram + off + 1));
+ return RIO_FAIL;
+ }
+ }
+
+ /*
+ ** time to check out byte swapping errors
+ */
+ swapword = invbyte | (newbyte << 8);
+
+ for (off=0; off<size; off+=2) {
+ writeb(invbyte, &ram[off]);
+ writeb(newbyte, &ram[off+1]);
+ }
+
+ for ( off=0; off<size; off+=2 ) {
+ if (readw(ram + off) != swapword) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 1: WORD at offset 0x%x should have been=%x, was=%x\n", off, swapword, readw(ram + off));
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram + off + 1));
+ return RIO_FAIL;
+ }
+ writew(~swapword, ram + off);
+ }
+
+ for (off=0; off<size; off+=2) {
+ if (readb(ram + off) != newbyte) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off, newbyte, readb(ram + off));
+ return RIO_FAIL;
+ }
+ if (readb(ram + off + 1) != invbyte) {
+ rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off+1, invbyte, readb(ram + off + 1));
+ return RIO_FAIL;
+ }
+ writew(newword, ram + off);
+ }
+ return 0;
+}
+
+
+int RIODefaultName(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
+{
+ memcpy(HostP->Mapping[UnitId].Name, "UNKNOWN RTA X-XX", 17);
+ HostP->Mapping[UnitId].Name[12]='1'+(HostP-p->RIOHosts);
+ if ((UnitId+1) > 9) {
+ HostP->Mapping[UnitId].Name[14]='0'+((UnitId+1)/10);
+ HostP->Mapping[UnitId].Name[15]='0'+((UnitId+1)%10);
+ }
+ else {
+ HostP->Mapping[UnitId].Name[14]='1'+UnitId;
+ HostP->Mapping[UnitId].Name[15]=0;
+ }
+ return 0;
+}
+
+#define RIO_RELEASE "Linux"
+#define RELEASE_ID "1.0"
+
+static struct rioVersion stVersion;
+
+struct rioVersion *RIOVersid(void)
+{
+ strlcpy(stVersion.version, "RIO driver for linux V1.0",
+ sizeof(stVersion.version));
+ strlcpy(stVersion.buildDate, __DATE__,
+ sizeof(stVersion.buildDate));
+
+ return &stVersion;
+}
+
+void RIOHostReset(unsigned int Type, struct DpRam __iomem *DpRamP, unsigned int Slot)
+{
+ /*
+ ** Reset the Tpu
+ */
+ rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: type 0x%x", Type);
+ switch ( Type ) {
+ case RIO_AT:
+ rio_dprintk (RIO_DEBUG_INIT, " (RIO_AT)\n");
+ writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION |
+ SLOW_LINKS | SLOW_AT_BUS, &DpRamP->DpControl);
+ writeb(0xFF, &DpRamP->DpResetTpu);
+ udelay(3);
+ rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n");
+ writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE |
+ BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS, &DpRamP->DpControl);
+ writeb(0xFF, &DpRamP->DpResetTpu);
+ udelay(3);
+ break;
+ case RIO_PCI:
+ rio_dprintk (RIO_DEBUG_INIT, " (RIO_PCI)\n");
+ writeb(RIO_PCI_BOOT_FROM_RAM, &DpRamP->DpControl);
+ writeb(0xFF, &DpRamP->DpResetInt);
+ writeb(0xFF, &DpRamP->DpResetTpu);
+ udelay(100);
+ break;
+ default:
+ rio_dprintk (RIO_DEBUG_INIT, " (UNKNOWN)\n");
+ break;
+ }
+ return;
+}
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
new file mode 100644
index 0000000..71f8760
--- /dev/null
+++ b/drivers/char/rio/riointr.c
@@ -0,0 +1,646 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : riointr.c
+** SID : 1.2
+** Last Modified : 11/6/98 10:33:44
+** Retrieved : 11/6/98 10:33:49
+**
+** ident @(#)riointr.c 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+#include <linux/delay.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+static void RIOReceive(struct rio_info *, struct Port *);
+
+
+static char *firstchars(char *p, int nch)
+{
+ static char buf[2][128];
+ static int t = 0;
+ t = !t;
+ memcpy(buf[t], p, nch);
+ buf[t][nch] = 0;
+ return buf[t];
+}
+
+
+#define INCR( P, I ) ((P) = (((P)+(I)) & p->RIOBufferMask))
+/* Enable and start the transmission of packets */
+void RIOTxEnable(char *en)
+{
+ struct Port *PortP;
+ struct rio_info *p;
+ struct tty_struct *tty;
+ int c;
+ struct PKT __iomem *PacketP;
+ unsigned long flags;
+
+ PortP = (struct Port *) en;
+ p = (struct rio_info *) PortP->p;
+ tty = PortP->gs.port.tty;
+
+
+ rio_dprintk(RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", PortP->PortNum, PortP->gs.xmit_cnt);
+
+ if (!PortP->gs.xmit_cnt)
+ return;
+
+
+ /* This routine is an order of magnitude simpler than the specialix
+ version. One of the disadvantages is that this version will send
+ an incomplete packet (usually 64 bytes instead of 72) once for
+ every 4k worth of data. Let's just say that this won't influence
+ performance significantly..... */
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ while (can_add_transmit(&PacketP, PortP)) {
+ c = PortP->gs.xmit_cnt;
+ if (c > PKT_MAX_DATA_LEN)
+ c = PKT_MAX_DATA_LEN;
+
+ /* Don't copy past the end of the source buffer */
+ if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail)
+ c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail;
+
+ {
+ int t;
+ t = (c > 10) ? 10 : c;
+
+ rio_dprintk(RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n", PortP->PortNum, c, firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail, t), firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail + c - t, t));
+ }
+ /* If for one reason or another, we can't copy more data,
+ we're done! */
+ if (c == 0)
+ break;
+
+ rio_memcpy_toio(PortP->HostP->Caddr, PacketP->data, PortP->gs.xmit_buf + PortP->gs.xmit_tail, c);
+ /* udelay (1); */
+
+ writeb(c, &(PacketP->len));
+ if (!(PortP->State & RIO_DELETED)) {
+ add_transmit(PortP);
+ /*
+ ** Count chars tx'd for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->txchars += c;
+ }
+ PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE - 1);
+ PortP->gs.xmit_cnt -= c;
+ }
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+ if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN))
+ tty_wakeup(PortP->gs.port.tty);
+
+}
+
+
+/*
+** RIO Host Service routine. Does all the work traditionally associated with an
+** interrupt.
+*/
+static int RupIntr;
+static int RxIntr;
+static int TxIntr;
+
+void RIOServiceHost(struct rio_info *p, struct Host *HostP)
+{
+ rio_spin_lock(&HostP->HostLock);
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+ static int t = 0;
+ rio_spin_unlock(&HostP->HostLock);
+ if ((t++ % 200) == 0)
+ rio_dprintk(RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int) HostP->Flags);
+ return;
+ }
+ rio_spin_unlock(&HostP->HostLock);
+
+ if (readw(&HostP->ParmMapP->rup_intr)) {
+ writew(0, &HostP->ParmMapP->rup_intr);
+ p->RIORupCount++;
+ RupIntr++;
+ rio_dprintk(RIO_DEBUG_INTR, "rio: RUP interrupt on host %Zd\n", HostP - p->RIOHosts);
+ RIOPollHostCommands(p, HostP);
+ }
+
+ if (readw(&HostP->ParmMapP->rx_intr)) {
+ int port;
+
+ writew(0, &HostP->ParmMapP->rx_intr);
+ p->RIORxCount++;
+ RxIntr++;
+
+ rio_dprintk(RIO_DEBUG_INTR, "rio: RX interrupt on host %Zd\n", HostP - p->RIOHosts);
+ /*
+ ** Loop through every port. If the port is mapped into
+ ** the system ( i.e. has /dev/ttyXXXX associated ) then it is
+ ** worth checking. If the port isn't open, grab any packets
+ ** hanging on its receive queue and stuff them on the free
+ ** list; check for commands on the way.
+ */
+ for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {
+ struct Port *PortP = p->RIOPortp[port];
+ struct tty_struct *ttyP;
+ struct PKT __iomem *PacketP;
+
+ /*
+ ** not mapped in - most of the RIOPortp[] information
+ ** has not been set up!
+ ** Optimise: ports come in bundles of eight.
+ */
+ if (!PortP->Mapped) {
+ port += 7;
+ continue; /* with the next port */
+ }
+
+ /*
+ ** If the host board isn't THIS host board, check the next one.
+ ** optimise: ports come in bundles of eight.
+ */
+ if (PortP->HostP != HostP) {
+ port += 7;
+ continue;
+ }
+
+ /*
+ ** Let us see - is the port open? If not, then don't service it.
+ */
+ if (!(PortP->PortState & PORT_ISOPEN)) {
+ continue;
+ }
+
+ /*
+ ** find corresponding tty structure. The process of mapping
+ ** the ports puts these here.
+ */
+ ttyP = PortP->gs.port.tty;
+
+ /*
+ ** Lock the port before we begin working on it.
+ */
+ rio_spin_lock(&PortP->portSem);
+
+ /*
+ ** Process received data if there is any.
+ */
+ if (can_remove_receive(&PacketP, PortP))
+ RIOReceive(p, PortP);
+
+ /*
+ ** If there is no data left to be read from the port, and
+ ** it's handshake bit is set, then we must clear the handshake,
+ ** so that that downstream RTA is re-enabled.
+ */
+ if (!can_remove_receive(&PacketP, PortP) && (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET)) {
+ /*
+ ** MAGIC! ( Basically, handshake the RX buffer, so that
+ ** the RTAs upstream can be re-enabled. )
+ */
+ rio_dprintk(RIO_DEBUG_INTR, "Set RX handshake bit\n");
+ writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake);
+ }
+ rio_spin_unlock(&PortP->portSem);
+ }
+ }
+
+ if (readw(&HostP->ParmMapP->tx_intr)) {
+ int port;
+
+ writew(0, &HostP->ParmMapP->tx_intr);
+
+ p->RIOTxCount++;
+ TxIntr++;
+ rio_dprintk(RIO_DEBUG_INTR, "rio: TX interrupt on host %Zd\n", HostP - p->RIOHosts);
+
+ /*
+ ** Loop through every port.
+ ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX
+ ** associated ) then it is worth checking.
+ */
+ for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {
+ struct Port *PortP = p->RIOPortp[port];
+ struct tty_struct *ttyP;
+ struct PKT __iomem *PacketP;
+
+ /*
+ ** not mapped in - most of the RIOPortp[] information
+ ** has not been set up!
+ */
+ if (!PortP->Mapped) {
+ port += 7;
+ continue; /* with the next port */
+ }
+
+ /*
+ ** If the host board isn't running, then its data structures
+ ** are no use to us - continue quietly.
+ */
+ if (PortP->HostP != HostP) {
+ port += 7;
+ continue; /* with the next port */
+ }
+
+ /*
+ ** Let us see - is the port open? If not, then don't service it.
+ */
+ if (!(PortP->PortState & PORT_ISOPEN)) {
+ continue;
+ }
+
+ rio_dprintk(RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port);
+ /*
+ ** Lock the port before we begin working on it.
+ */
+ rio_spin_lock(&PortP->portSem);
+
+ /*
+ ** If we can't add anything to the transmit queue, then
+ ** we need do none of this processing.
+ */
+ if (!can_add_transmit(&PacketP, PortP)) {
+ rio_dprintk(RIO_DEBUG_INTR, "Can't add to port, so skipping.\n");
+ rio_spin_unlock(&PortP->portSem);
+ continue;
+ }
+
+ /*
+ ** find corresponding tty structure. The process of mapping
+ ** the ports puts these here.
+ */
+ ttyP = PortP->gs.port.tty;
+ /* If ttyP is NULL, the port is getting closed. Forget about it. */
+ if (!ttyP) {
+ rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n");
+ rio_spin_unlock(&PortP->portSem);
+ continue;
+ }
+ /*
+ ** If there is more room available we start up the transmit
+ ** data process again. This can be direct I/O, if the cookmode
+ ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the
+ ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch
+ ** characters via the line discipline. We must always call
+ ** the line discipline,
+ ** so that user input characters can be echoed correctly.
+ **
+ ** ++++ Update +++++
+ ** With the advent of double buffering, we now see if
+ ** TxBufferOut-In is non-zero. If so, then we copy a packet
+ ** to the output place, and set it going. If this empties
+ ** the buffer, then we must issue a wakeup( ) on OUT.
+ ** If it frees space in the buffer then we must issue
+ ** a wakeup( ) on IN.
+ **
+ ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we
+ ** have to send a WFLUSH command down the PHB, to mark the
+ ** end point of a WFLUSH. We also need to clear out any
+ ** data from the double buffer! ( note that WflushFlag is a
+ ** *count* of the number of WFLUSH commands outstanding! )
+ **
+ ** ++++ And there's more!
+ ** If an RTA is powered off, then on again, and rebooted,
+ ** whilst it has ports open, then we need to re-open the ports.
+ ** ( reasonable enough ). We can't do this when we spot the
+ ** re-boot, in interrupt time, because the queue is probably
+ ** full. So, when we come in here, we need to test if any
+ ** ports are in this condition, and re-open the port before
+ ** we try to send any more data to it. Now, the re-booted
+ ** RTA will be discarding packets from the PHB until it
+ ** receives this open packet, but don't worry tooo much
+ ** about that. The one thing that is interesting is the
+ ** combination of this effect and the WFLUSH effect!
+ */
+ /* For now don't handle RTA reboots. -- REW.
+ Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */
+ if (PortP->MagicFlags) {
+ if (PortP->MagicFlags & MAGIC_REBOOT) {
+ /*
+ ** well, the RTA has been rebooted, and there is room
+ ** on its queue to add the open packet that is required.
+ **
+ ** The messy part of this line is trying to decide if
+ ** we need to call the Param function as a tty or as
+ ** a modem.
+ ** DONT USE CLOCAL AS A TEST FOR THIS!
+ **
+ ** If we can't param the port, then move on to the
+ ** next port.
+ */
+ PortP->InUse = NOT_INUSE;
+
+ rio_spin_unlock(&PortP->portSem);
+ if (RIOParam(PortP, RIOC_OPEN, ((PortP->Cor2Copy & (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) == (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL)
+ continue; /* with next port */
+ rio_spin_lock(&PortP->portSem);
+ PortP->MagicFlags &= ~MAGIC_REBOOT;
+ }
+
+ /*
+ ** As mentioned above, this is a tacky hack to cope
+ ** with WFLUSH
+ */
+ if (PortP->WflushFlag) {
+ rio_dprintk(RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n");
+
+ if (PortP->InUse)
+ rio_dprintk(RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n");
+ }
+
+ while (PortP->WflushFlag && can_add_transmit(&PacketP, PortP) && (PortP->InUse == NOT_INUSE)) {
+ int p;
+ struct PktCmd __iomem *PktCmdP;
+
+ rio_dprintk(RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n");
+ /*
+ ** make it look just like a WFLUSH command
+ */
+ PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0];
+
+ writeb(RIOC_WFLUSH, &PktCmdP->Command);
+
+ p = PortP->HostPort % (u16) PORTS_PER_RTA;
+
+ /*
+ ** If second block of ports for 16 port RTA, add 8
+ ** to index 8-15.
+ */
+ if (PortP->SecondBlock)
+ p += PORTS_PER_RTA;
+
+ writeb(p, &PktCmdP->PhbNum);
+
+ /*
+ ** to make debuggery easier
+ */
+ writeb('W', &PacketP->data[2]);
+ writeb('F', &PacketP->data[3]);
+ writeb('L', &PacketP->data[4]);
+ writeb('U', &PacketP->data[5]);
+ writeb('S', &PacketP->data[6]);
+ writeb('H', &PacketP->data[7]);
+ writeb(' ', &PacketP->data[8]);
+ writeb('0' + PortP->WflushFlag, &PacketP->data[9]);
+ writeb(' ', &PacketP->data[10]);
+ writeb(' ', &PacketP->data[11]);
+ writeb('\0', &PacketP->data[12]);
+
+ /*
+ ** its two bytes long!
+ */
+ writeb(PKT_CMD_BIT | 2, &PacketP->len);
+
+ /*
+ ** queue it!
+ */
+ if (!(PortP->State & RIO_DELETED)) {
+ add_transmit(PortP);
+ /*
+ ** Count chars tx'd for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->txchars += 2;
+ }
+
+ if (--(PortP->WflushFlag) == 0) {
+ PortP->MagicFlags &= ~MAGIC_FLUSH;
+ }
+
+ rio_dprintk(RIO_DEBUG_INTR, "Wflush count now stands at %d\n", PortP->WflushFlag);
+ }
+ if (PortP->MagicFlags & MORE_OUTPUT_EYGOR) {
+ if (PortP->MagicFlags & MAGIC_FLUSH) {
+ PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
+ } else {
+ if (!can_add_transmit(&PacketP, PortP)) {
+ rio_spin_unlock(&PortP->portSem);
+ continue;
+ }
+ rio_spin_unlock(&PortP->portSem);
+ RIOTxEnable((char *) PortP);
+ rio_spin_lock(&PortP->portSem);
+ PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
+ }
+ }
+ }
+
+
+ /*
+ ** If we can't add anything to the transmit queue, then
+ ** we need do none of the remaining processing.
+ */
+ if (!can_add_transmit(&PacketP, PortP)) {
+ rio_spin_unlock(&PortP->portSem);
+ continue;
+ }
+
+ rio_spin_unlock(&PortP->portSem);
+ RIOTxEnable((char *) PortP);
+ }
+ }
+}
+
+/*
+** Routine for handling received data for tty drivers
+*/
+static void RIOReceive(struct rio_info *p, struct Port *PortP)
+{
+ struct tty_struct *TtyP;
+ unsigned short transCount;
+ struct PKT __iomem *PacketP;
+ register unsigned int DataCnt;
+ unsigned char __iomem *ptr;
+ unsigned char *buf;
+ int copied = 0;
+
+ static int intCount, RxIntCnt;
+
+ /*
+ ** The receive data process is to remove packets from the
+ ** PHB until there aren't any more or the current cblock
+ ** is full. When this occurs, there will be some left over
+ ** data in the packet, that we must do something with.
+ ** As we haven't unhooked the packet from the read list
+ ** yet, we can just leave the packet there, having first
+ ** made a note of how far we got. This means that we need
+ ** a pointer per port saying where we start taking the
+ ** data from - this will normally be zero, but when we
+ ** run out of space it will be set to the offset of the
+ ** next byte to copy from the packet data area. The packet
+ ** length field is decremented by the number of bytes that
+ ** we successfully removed from the packet. When this reaches
+ ** zero, we reset the offset pointer to be zero, and free
+ ** the packet from the front of the queue.
+ */
+
+ intCount++;
+
+ TtyP = PortP->gs.port.tty;
+ if (!TtyP) {
+ rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n");
+ return;
+ }
+
+ if (PortP->State & RIO_THROTTLE_RX) {
+ rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n");
+ return;
+ }
+
+ if (PortP->State & RIO_DELETED) {
+ while (can_remove_receive(&PacketP, PortP)) {
+ remove_receive(PortP);
+ put_free_end(PortP->HostP, PacketP);
+ }
+ } else {
+ /*
+ ** loop, just so long as:
+ ** i ) there's some data ( i.e. can_remove_receive )
+ ** ii ) we haven't been blocked
+ ** iii ) there's somewhere to put the data
+ ** iv ) we haven't outstayed our welcome
+ */
+ transCount = 1;
+ while (can_remove_receive(&PacketP, PortP)
+ && transCount) {
+ RxIntCnt++;
+
+ /*
+ ** check that it is not a command!
+ */
+ if (readb(&PacketP->len) & PKT_CMD_BIT) {
+ rio_dprintk(RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n");
+ /* rio_dprint(RIO_DEBUG_INTR, (" sysport = %d\n", p->RIOPortp->PortNum)); */
+ rio_dprintk(RIO_DEBUG_INTR, " dest_unit = %d\n", readb(&PacketP->dest_unit));
+ rio_dprintk(RIO_DEBUG_INTR, " dest_port = %d\n", readb(&PacketP->dest_port));
+ rio_dprintk(RIO_DEBUG_INTR, " src_unit = %d\n", readb(&PacketP->src_unit));
+ rio_dprintk(RIO_DEBUG_INTR, " src_port = %d\n", readb(&PacketP->src_port));
+ rio_dprintk(RIO_DEBUG_INTR, " len = %d\n", readb(&PacketP->len));
+ rio_dprintk(RIO_DEBUG_INTR, " control = %d\n", readb(&PacketP->control));
+ rio_dprintk(RIO_DEBUG_INTR, " csum = %d\n", readw(&PacketP->csum));
+ rio_dprintk(RIO_DEBUG_INTR, " data bytes: ");
+ for (DataCnt = 0; DataCnt < PKT_MAX_DATA_LEN; DataCnt++)
+ rio_dprintk(RIO_DEBUG_INTR, "%d\n", readb(&PacketP->data[DataCnt]));
+ remove_receive(PortP);
+ put_free_end(PortP->HostP, PacketP);
+ continue; /* with next packet */
+ }
+
+ /*
+ ** How many characters can we move 'upstream' ?
+ **
+ ** Determine the minimum of the amount of data
+ ** available and the amount of space in which to
+ ** put it.
+ **
+ ** 1. Get the packet length by masking 'len'
+ ** for only the length bits.
+ ** 2. Available space is [buffer size] - [space used]
+ **
+ ** Transfer count is the minimum of packet length
+ ** and available space.
+ */
+
+ transCount = tty_buffer_request_room(TtyP, readb(&PacketP->len) & PKT_LEN_MASK);
+ rio_dprintk(RIO_DEBUG_REC, "port %d: Copy %d bytes\n", PortP->PortNum, transCount);
+ /*
+ ** To use the following 'kkprintfs' for debugging - change the '#undef'
+ ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the
+ ** driver).
+ */
+ ptr = (unsigned char __iomem *) PacketP->data + PortP->RxDataStart;
+
+ tty_prepare_flip_string(TtyP, &buf, transCount);
+ rio_memcpy_fromio(buf, ptr, transCount);
+ PortP->RxDataStart += transCount;
+ writeb(readb(&PacketP->len)-transCount, &PacketP->len);
+ copied += transCount;
+
+
+
+ if (readb(&PacketP->len) == 0) {
+ /*
+ ** If we have emptied the packet, then we can
+ ** free it, and reset the start pointer for
+ ** the next packet.
+ */
+ remove_receive(PortP);
+ put_free_end(PortP->HostP, PacketP);
+ PortP->RxDataStart = 0;
+ }
+ }
+ }
+ if (copied) {
+ rio_dprintk(RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied);
+ tty_flip_buffer_push(TtyP);
+ }
+
+ return;
+}
+
diff --git a/drivers/char/rio/rioioctl.h b/drivers/char/rio/rioioctl.h
new file mode 100644
index 0000000..e8af5b3
--- /dev/null
+++ b/drivers/char/rio/rioioctl.h
@@ -0,0 +1,57 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioioctl.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:13
+** Retrieved : 11/6/98 11:34:22
+**
+** ident @(#)rioioctl.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rioioctl_h__
+#define __rioioctl_h__
+
+/*
+** RIO device driver - user ioctls and associated structures.
+*/
+
+struct portStats {
+ int port;
+ int gather;
+ unsigned long txchars;
+ unsigned long rxchars;
+ unsigned long opens;
+ unsigned long closes;
+ unsigned long ioctls;
+};
+
+#define RIOC ('R'<<8)|('i'<<16)|('o'<<24)
+
+#define RIO_QUICK_CHECK (RIOC | 105)
+#define RIO_GATHER_PORT_STATS (RIOC | 193)
+#define RIO_RESET_PORT_STATS (RIOC | 194)
+#define RIO_GET_PORT_STATS (RIOC | 195)
+
+#endif /* __rioioctl_h__ */
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c
new file mode 100644
index 0000000..d687c17
--- /dev/null
+++ b/drivers/char/rio/rioparam.c
@@ -0,0 +1,664 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioparam.c
+** SID : 1.3
+** Last Modified : 11/6/98 10:33:45
+** Retrieved : 11/6/98 10:33:50
+**
+** ident @(#)rioparam.c 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+
+
+
+/*
+** The Scam, based on email from jeremyr@bugs.specialix.co.uk....
+**
+** To send a command on a particular port, you put a packet with the
+** command bit set onto the port. The command bit is in the len field,
+** and gets ORed in with the actual byte count.
+**
+** When you send a packet with the command bit set the first
+** data byte (data[0]) is interpreted as the command to execute.
+** It also governs what data structure overlay should accompany the packet.
+** Commands are defined in cirrus/cirrus.h
+**
+** If you want the command to pre-emt data already on the queue for the
+** port, set the pre-emptive bit in conjunction with the command bit.
+** It is not defined what will happen if you set the preemptive bit
+** on a packet that is NOT a command.
+**
+** Pre-emptive commands should be queued at the head of the queue using
+** add_start(), whereas normal commands and data are enqueued using
+** add_end().
+**
+** Most commands do not use the remaining bytes in the data array. The
+** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and
+** OPEN are currently analogous). With these three commands the following
+** 11 data bytes are all used to pass config information such as baud rate etc.
+** The fields are also defined in cirrus.h. Some contain straightforward
+** information such as the transmit XON character. Two contain the transmit and
+** receive baud rates respectively. For most baud rates there is a direct
+** mapping between the rates defined in <sys/termio.h> and the byte in the
+** packet. There are additional (non UNIX-standard) rates defined in
+** /u/dos/rio/cirrus/h/brates.h.
+**
+** The rest of the data fields contain approximations to the Cirrus registers
+** that are used to program number of bits etc. Each registers bit fields is
+** defined in cirrus.h.
+**
+** NB. Only use those bits that are defined as being driver specific
+** or common to the RTA and the driver.
+**
+** All commands going from RTA->Host will be dealt with by the Host code - you
+** will never see them. As with the SI there will be three fields to look out
+** for in each phb (not yet defined - needs defining a.s.a.p).
+**
+** modem_status - current state of handshake pins.
+**
+** port_status - current port status - equivalent to hi_stat for SI, indicates
+** if port is IDLE_OPEN, IDLE_CLOSED etc.
+**
+** break_status - bit X set if break has been received.
+**
+** Happy hacking.
+**
+*/
+
+/*
+** RIOParam is used to open or configure a port. You pass it a PortP,
+** which will have a tty struct attached to it. You also pass a command,
+** either OPEN or CONFIG. The port's setup is taken from the t_ fields
+** of the tty struct inside the PortP, and the port is either opened
+** or re-configured. You must also tell RIOParam if the device is a modem
+** device or not (i.e. top bit of minor number set or clear - take special
+** care when deciding on this!).
+** RIOParam neither flushes nor waits for drain, and is NOT preemptive.
+**
+** RIOParam assumes it will be called at splrio(), and also assumes
+** that CookMode is set correctly in the port structure.
+**
+** NB. for MPX
+** tty lock must NOT have been previously acquired.
+*/
+int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
+{
+ struct tty_struct *TtyP;
+ int retval;
+ struct phb_param __iomem *phb_param_ptr;
+ struct PKT __iomem *PacketP;
+ int res;
+ u8 Cor1 = 0, Cor2 = 0, Cor4 = 0, Cor5 = 0;
+ u8 TxXon = 0, TxXoff = 0, RxXon = 0, RxXoff = 0;
+ u8 LNext = 0, TxBaud = 0, RxBaud = 0;
+ int retries = 0xff;
+ unsigned long flags;
+
+ func_enter();
+
+ TtyP = PortP->gs.port.tty;
+
+ rio_dprintk(RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP);
+
+ if (!TtyP) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Can't call rioparam with null tty.\n");
+
+ func_exit();
+
+ return RIO_FAIL;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ if (cmd == RIOC_OPEN) {
+ /*
+ ** If the port is set to store or lock the parameters, and it is
+ ** paramed with OPEN, we want to restore the saved port termio, but
+ ** only if StoredTermio has been saved, i.e. NOT 1st open after reboot.
+ */
+ }
+
+ /*
+ ** wait for space
+ */
+ while (!(res = can_add_transmit(&PacketP, PortP)) || (PortP->InUse != NOT_INUSE)) {
+ if (retries-- <= 0) {
+ break;
+ }
+ if (PortP->InUse != NOT_INUSE) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Port IN_USE for pre-emptive command\n");
+ }
+
+ if (!res) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Port has no space on transmit queue\n");
+ }
+
+ if (SleepFlag != OK_TO_SLEEP) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ func_exit();
+
+ return RIO_FAIL;
+ }
+
+ rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ retval = RIODelay(PortP, HUNDRED_MS);
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ if (retval == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit broken by signal\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ func_exit();
+ return -EINTR;
+ }
+ if (PortP->State & RIO_DELETED) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ func_exit();
+ return 0;
+ }
+ }
+
+ if (!res) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ func_exit();
+
+ return RIO_FAIL;
+ }
+
+ rio_dprintk(RIO_DEBUG_PARAM, "can_add_transmit() returns %x\n", res);
+ rio_dprintk(RIO_DEBUG_PARAM, "Packet is %p\n", PacketP);
+
+ phb_param_ptr = (struct phb_param __iomem *) PacketP->data;
+
+
+ switch (TtyP->termios->c_cflag & CSIZE) {
+ case CS5:
+ {
+ rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n");
+ Cor1 |= RIOC_COR1_5BITS;
+ break;
+ }
+ case CS6:
+ {
+ rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n");
+ Cor1 |= RIOC_COR1_6BITS;
+ break;
+ }
+ case CS7:
+ {
+ rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n");
+ Cor1 |= RIOC_COR1_7BITS;
+ break;
+ }
+ case CS8:
+ {
+ rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n");
+ Cor1 |= RIOC_COR1_8BITS;
+ break;
+ }
+ }
+
+ if (TtyP->termios->c_cflag & CSTOPB) {
+ rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n");
+ Cor1 |= RIOC_COR1_2STOP;
+ } else {
+ rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n");
+ Cor1 |= RIOC_COR1_1STOP;
+ }
+
+ if (TtyP->termios->c_cflag & PARENB) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n");
+ Cor1 |= RIOC_COR1_NORMAL;
+ } else {
+ rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n");
+ Cor1 |= RIOC_COR1_NOP;
+ }
+ if (TtyP->termios->c_cflag & PARODD) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n");
+ Cor1 |= RIOC_COR1_ODD;
+ } else {
+ rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n");
+ Cor1 |= RIOC_COR1_EVEN;
+ }
+
+ /*
+ ** COR 2
+ */
+ if (TtyP->termios->c_iflag & IXON) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n");
+ Cor2 |= RIOC_COR2_IXON;
+ } else {
+ if (PortP->Config & RIO_IXON) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n");
+ Cor2 |= RIOC_COR2_IXON;
+ } else
+ rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n");
+ }
+
+ if (TtyP->termios->c_iflag & IXANY) {
+ if (PortP->Config & RIO_IXANY) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n");
+ Cor2 |= RIOC_COR2_IXANY;
+ } else
+ rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n");
+ }
+
+ if (TtyP->termios->c_iflag & IXOFF) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n");
+ Cor2 |= RIOC_COR2_IXOFF;
+ }
+
+ if (TtyP->termios->c_cflag & HUPCL) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n");
+ Cor2 |= RIOC_COR2_HUPCL;
+ }
+
+ if (C_CRTSCTS(TtyP)) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n");
+ Cor2 |= RIOC_COR2_CTSFLOW;
+ Cor2 |= RIOC_COR2_RTSFLOW;
+ } else {
+ rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n");
+ Cor2 &= ~RIOC_COR2_CTSFLOW;
+ Cor2 &= ~RIOC_COR2_RTSFLOW;
+ }
+
+
+ if (TtyP->termios->c_cflag & CLOCAL) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Local line\n");
+ } else {
+ rio_dprintk(RIO_DEBUG_PARAM, "Possible Modem line\n");
+ }
+
+ /*
+ ** COR 4 (there is no COR 3)
+ */
+ if (TtyP->termios->c_iflag & IGNBRK) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n");
+ Cor4 |= RIOC_COR4_IGNBRK;
+ }
+ if (!(TtyP->termios->c_iflag & BRKINT)) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n");
+ Cor4 |= RIOC_COR4_NBRKINT;
+ } else {
+ rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on break condition\n");
+ }
+
+ if (TtyP->termios->c_iflag & INLCR) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n");
+ Cor4 |= RIOC_COR4_INLCR;
+ }
+
+ if (TtyP->termios->c_iflag & IGNCR) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n");
+ Cor4 |= RIOC_COR4_IGNCR;
+ }
+
+ if (TtyP->termios->c_iflag & ICRNL) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n");
+ Cor4 |= RIOC_COR4_ICRNL;
+ }
+ if (TtyP->termios->c_iflag & IGNPAR) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n");
+ Cor4 |= RIOC_COR4_IGNPAR;
+ }
+ if (TtyP->termios->c_iflag & PARMRK) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n");
+ Cor4 |= RIOC_COR4_PARMRK;
+ }
+
+ /*
+ ** Set the RAISEMOD flag to ensure that the modem lines are raised
+ ** on reception of a config packet.
+ ** The download code handles the zero baud condition.
+ */
+ Cor4 |= RIOC_COR4_RAISEMOD;
+
+ /*
+ ** COR 5
+ */
+
+ Cor5 = RIOC_COR5_CMOE;
+
+ /*
+ ** Set to monitor tbusy/tstop (or not).
+ */
+
+ if (PortP->MonitorTstate)
+ Cor5 |= RIOC_COR5_TSTATE_ON;
+ else
+ Cor5 |= RIOC_COR5_TSTATE_OFF;
+
+ /*
+ ** Could set LNE here if you wanted LNext processing. SVR4 will use it.
+ */
+ if (TtyP->termios->c_iflag & ISTRIP) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n");
+ if (!(PortP->State & RIO_TRIAD_MODE)) {
+ Cor5 |= RIOC_COR5_ISTRIP;
+ }
+ }
+
+ if (TtyP->termios->c_oflag & ONLCR) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n");
+ if (PortP->CookMode == COOK_MEDIUM)
+ Cor5 |= RIOC_COR5_ONLCR;
+ }
+ if (TtyP->termios->c_oflag & OCRNL) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n");
+ if (PortP->CookMode == COOK_MEDIUM)
+ Cor5 |= RIOC_COR5_OCRNL;
+ }
+ if ((TtyP->termios->c_oflag & TABDLY) == TAB3) {
+ rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n");
+ if (PortP->CookMode == COOK_MEDIUM)
+ Cor5 |= RIOC_COR5_TAB3;
+ }
+
+ /*
+ ** Flow control bytes.
+ */
+ TxXon = TtyP->termios->c_cc[VSTART];
+ TxXoff = TtyP->termios->c_cc[VSTOP];
+ RxXon = TtyP->termios->c_cc[VSTART];
+ RxXoff = TtyP->termios->c_cc[VSTOP];
+ /*
+ ** LNEXT byte
+ */
+ LNext = 0;
+
+ /*
+ ** Baud rate bytes
+ */
+ rio_dprintk(RIO_DEBUG_PARAM, "Mapping of rx/tx baud %x (%x)\n", TtyP->termios->c_cflag, CBAUD);
+
+ switch (TtyP->termios->c_cflag & CBAUD) {
+#define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break
+ e(50);
+ e(75);
+ e(110);
+ e(134);
+ e(150);
+ e(200);
+ e(300);
+ e(600);
+ e(1200);
+ e(1800);
+ e(2400);
+ e(4800);
+ e(9600);
+ e(19200);
+ e(38400);
+ e(57600);
+ e(115200); /* e(230400);e(460800); e(921600); */
+ }
+
+ rio_dprintk(RIO_DEBUG_PARAM, "tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud);
+
+
+ /*
+ ** Leftovers
+ */
+ if (TtyP->termios->c_cflag & CREAD)
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable receiver\n");
+#ifdef RCV1EN
+ if (TtyP->termios->c_cflag & RCV1EN)
+ rio_dprintk(RIO_DEBUG_PARAM, "RCV1EN (?)\n");
+#endif
+#ifdef XMT1EN
+ if (TtyP->termios->c_cflag & XMT1EN)
+ rio_dprintk(RIO_DEBUG_PARAM, "XMT1EN (?)\n");
+#endif
+ if (TtyP->termios->c_lflag & ISIG)
+ rio_dprintk(RIO_DEBUG_PARAM, "Input character signal generating enabled\n");
+ if (TtyP->termios->c_lflag & ICANON)
+ rio_dprintk(RIO_DEBUG_PARAM, "Canonical input: erase and kill enabled\n");
+ if (TtyP->termios->c_lflag & XCASE)
+ rio_dprintk(RIO_DEBUG_PARAM, "Canonical upper/lower presentation\n");
+ if (TtyP->termios->c_lflag & ECHO)
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable input echo\n");
+ if (TtyP->termios->c_lflag & ECHOE)
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable echo erase\n");
+ if (TtyP->termios->c_lflag & ECHOK)
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable echo kill\n");
+ if (TtyP->termios->c_lflag & ECHONL)
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable echo newline\n");
+ if (TtyP->termios->c_lflag & NOFLSH)
+ rio_dprintk(RIO_DEBUG_PARAM, "Disable flush after interrupt or quit\n");
+#ifdef TOSTOP
+ if (TtyP->termios->c_lflag & TOSTOP)
+ rio_dprintk(RIO_DEBUG_PARAM, "Send SIGTTOU for background output\n");
+#endif
+#ifdef XCLUDE
+ if (TtyP->termios->c_lflag & XCLUDE)
+ rio_dprintk(RIO_DEBUG_PARAM, "Exclusive use of this line\n");
+#endif
+ if (TtyP->termios->c_iflag & IUCLC)
+ rio_dprintk(RIO_DEBUG_PARAM, "Map uppercase to lowercase on input\n");
+ if (TtyP->termios->c_oflag & OPOST)
+ rio_dprintk(RIO_DEBUG_PARAM, "Enable output post-processing\n");
+ if (TtyP->termios->c_oflag & OLCUC)
+ rio_dprintk(RIO_DEBUG_PARAM, "Map lowercase to uppercase on output\n");
+ if (TtyP->termios->c_oflag & ONOCR)
+ rio_dprintk(RIO_DEBUG_PARAM, "No carriage return output at column 0\n");
+ if (TtyP->termios->c_oflag & ONLRET)
+ rio_dprintk(RIO_DEBUG_PARAM, "Newline performs carriage return function\n");
+ if (TtyP->termios->c_oflag & OFILL)
+ rio_dprintk(RIO_DEBUG_PARAM, "Use fill characters for delay\n");
+ if (TtyP->termios->c_oflag & OFDEL)
+ rio_dprintk(RIO_DEBUG_PARAM, "Fill character is DEL\n");
+ if (TtyP->termios->c_oflag & NLDLY)
+ rio_dprintk(RIO_DEBUG_PARAM, "Newline delay set\n");
+ if (TtyP->termios->c_oflag & CRDLY)
+ rio_dprintk(RIO_DEBUG_PARAM, "Carriage return delay set\n");
+ if (TtyP->termios->c_oflag & TABDLY)
+ rio_dprintk(RIO_DEBUG_PARAM, "Tab delay set\n");
+ /*
+ ** These things are kind of useful in a later life!
+ */
+ PortP->Cor2Copy = Cor2;
+
+ if (PortP->State & RIO_DELETED) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ func_exit();
+
+ return RIO_FAIL;
+ }
+
+ /*
+ ** Actually write the info into the packet to be sent
+ */
+ writeb(cmd, &phb_param_ptr->Cmd);
+ writeb(Cor1, &phb_param_ptr->Cor1);
+ writeb(Cor2, &phb_param_ptr->Cor2);
+ writeb(Cor4, &phb_param_ptr->Cor4);
+ writeb(Cor5, &phb_param_ptr->Cor5);
+ writeb(TxXon, &phb_param_ptr->TxXon);
+ writeb(RxXon, &phb_param_ptr->RxXon);
+ writeb(TxXoff, &phb_param_ptr->TxXoff);
+ writeb(RxXoff, &phb_param_ptr->RxXoff);
+ writeb(LNext, &phb_param_ptr->LNext);
+ writeb(TxBaud, &phb_param_ptr->TxBaud);
+ writeb(RxBaud, &phb_param_ptr->RxBaud);
+
+ /*
+ ** Set the length/command field
+ */
+ writeb(12 | PKT_CMD_BIT, &PacketP->len);
+
+ /*
+ ** The packet is formed - now, whack it off
+ ** to its final destination:
+ */
+ add_transmit(PortP);
+ /*
+ ** Count characters transmitted for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->txchars += 12;
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+ rio_dprintk(RIO_DEBUG_PARAM, "add_transmit returned.\n");
+ /*
+ ** job done.
+ */
+ func_exit();
+
+ return 0;
+}
+
+
+/*
+** We can add another packet to a transmit queue if the packet pointer pointed
+** to by the TxAdd pointer has PKT_IN_USE clear in its address.
+*/
+int can_add_transmit(struct PKT __iomem **PktP, struct Port *PortP)
+{
+ struct PKT __iomem *tp;
+
+ *PktP = tp = (struct PKT __iomem *) RIO_PTR(PortP->Caddr, readw(PortP->TxAdd));
+
+ return !((unsigned long) tp & PKT_IN_USE);
+}
+
+/*
+** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
+** and then move the TxAdd pointer along one position to point to the next
+** packet pointer. You must wrap the pointer from the end back to the start.
+*/
+void add_transmit(struct Port *PortP)
+{
+ if (readw(PortP->TxAdd) & PKT_IN_USE) {
+ rio_dprintk(RIO_DEBUG_PARAM, "add_transmit: Packet has been stolen!");
+ }
+ writew(readw(PortP->TxAdd) | PKT_IN_USE, PortP->TxAdd);
+ PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : PortP->TxAdd + 1;
+ writew(RIO_OFF(PortP->Caddr, PortP->TxAdd), &PortP->PhbP->tx_add);
+}
+
+/****************************************
+ * Put a packet onto the end of the
+ * free list
+ ****************************************/
+void put_free_end(struct Host *HostP, struct PKT __iomem *PktP)
+{
+ struct rio_free_list __iomem *tmp_pointer;
+ unsigned short old_end, new_end;
+ unsigned long flags;
+
+ rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+ /*************************************************
+ * Put a packet back onto the back of the free list
+ *
+ ************************************************/
+
+ rio_dprintk(RIO_DEBUG_PFE, "put_free_end(PktP=%p)\n", PktP);
+
+ if ((old_end = readw(&HostP->ParmMapP->free_list_end)) != TPNULL) {
+ new_end = RIO_OFF(HostP->Caddr, PktP);
+ tmp_pointer = (struct rio_free_list __iomem *) RIO_PTR(HostP->Caddr, old_end);
+ writew(new_end, &tmp_pointer->next);
+ writew(old_end, &((struct rio_free_list __iomem *) PktP)->prev);
+ writew(TPNULL, &((struct rio_free_list __iomem *) PktP)->next);
+ writew(new_end, &HostP->ParmMapP->free_list_end);
+ } else { /* First packet on the free list this should never happen! */
+ rio_dprintk(RIO_DEBUG_PFE, "put_free_end(): This should never happen\n");
+ writew(RIO_OFF(HostP->Caddr, PktP), &HostP->ParmMapP->free_list_end);
+ tmp_pointer = (struct rio_free_list __iomem *) PktP;
+ writew(TPNULL, &tmp_pointer->prev);
+ writew(TPNULL, &tmp_pointer->next);
+ }
+ rio_dprintk(RIO_DEBUG_CMD, "Before unlock: %p\n", &HostP->HostLock);
+ rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+}
+
+/*
+** can_remove_receive(PktP,P) returns non-zero if PKT_IN_USE is set
+** for the next packet on the queue. It will also set PktP to point to the
+** relevant packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
+** then can_remove_receive() returns 0.
+*/
+int can_remove_receive(struct PKT __iomem **PktP, struct Port *PortP)
+{
+ if (readw(PortP->RxRemove) & PKT_IN_USE) {
+ *PktP = (struct PKT __iomem *) RIO_PTR(PortP->Caddr, readw(PortP->RxRemove) & ~PKT_IN_USE);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+** To remove a packet from the receive queue you clear its PKT_IN_USE bit,
+** and then bump the pointers. Once the pointers get to the end, they must
+** be wrapped back to the start.
+*/
+void remove_receive(struct Port *PortP)
+{
+ writew(readw(PortP->RxRemove) & ~PKT_IN_USE, PortP->RxRemove);
+ PortP->RxRemove = (PortP->RxRemove == PortP->RxEnd) ? PortP->RxStart : PortP->RxRemove + 1;
+ writew(RIO_OFF(PortP->Caddr, PortP->RxRemove), &PortP->PhbP->rx_remove);
+}
diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c
new file mode 100644
index 0000000..706c2a2
--- /dev/null
+++ b/drivers/char/rio/rioroute.c
@@ -0,0 +1,1040 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : rioroute.c
+** SID : 1.3
+** Last Modified : 11/6/98 10:33:46
+** Retrieved : 11/6/98 10:33:50
+**
+** ident @(#)rioroute.c 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+
+static int RIOCheckIsolated(struct rio_info *, struct Host *, unsigned int);
+static int RIOIsolate(struct rio_info *, struct Host *, unsigned int);
+static int RIOCheck(struct Host *, unsigned int);
+static void RIOConCon(struct rio_info *, struct Host *, unsigned int, unsigned int, unsigned int, unsigned int, int);
+
+
+/*
+** Incoming on the ROUTE_RUP
+** I wrote this while I was tired. Forgive me.
+*/
+int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem * PacketP)
+{
+ struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data;
+ struct PktCmd_M *PktReplyP;
+ struct CmdBlk *CmdBlkP;
+ struct Port *PortP;
+ struct Map *MapP;
+ struct Top *TopP;
+ int ThisLink, ThisLinkMin, ThisLinkMax;
+ int port;
+ int Mod, Mod1, Mod2;
+ unsigned short RtaType;
+ unsigned int RtaUniq;
+ unsigned int ThisUnit, ThisUnit2; /* 2 ids to accommodate 16 port RTA */
+ unsigned int OldUnit, NewUnit, OldLink, NewLink;
+ char *MyType, *MyName;
+ int Lies;
+ unsigned long flags;
+
+ /*
+ ** Is this unit telling us it's current link topology?
+ */
+ if (readb(&PktCmdP->Command) == ROUTE_TOPOLOGY) {
+ MapP = HostP->Mapping;
+
+ /*
+ ** The packet can be sent either by the host or by an RTA.
+ ** If it comes from the host, then we need to fill in the
+ ** Topology array in the host structure. If it came in
+ ** from an RTA then we need to fill in the Mapping structure's
+ ** Topology array for the unit.
+ */
+ if (Rup >= (unsigned short) MAX_RUP) {
+ ThisUnit = HOST_ID;
+ TopP = HostP->Topology;
+ MyType = "Host";
+ MyName = HostP->Name;
+ ThisLinkMin = ThisLinkMax = Rup - MAX_RUP;
+ } else {
+ ThisUnit = Rup + 1;
+ TopP = HostP->Mapping[Rup].Topology;
+ MyType = "RTA";
+ MyName = HostP->Mapping[Rup].Name;
+ ThisLinkMin = 0;
+ ThisLinkMax = LINKS_PER_UNIT - 1;
+ }
+
+ /*
+ ** Lies will not be tolerated.
+ ** If any pair of links claim to be connected to the same
+ ** place, then ignore this packet completely.
+ */
+ Lies = 0;
+ for (ThisLink = ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) {
+ /*
+ ** it won't lie about network interconnect, total disconnects
+ ** and no-IDs. (or at least, it doesn't *matter* if it does)
+ */
+ if (readb(&PktCmdP->RouteTopology[ThisLink].Unit) > (unsigned short) MAX_RUP)
+ continue;
+
+ for (NewLink = ThisLinkMin; NewLink < ThisLink; NewLink++) {
+ if ((readb(&PktCmdP->RouteTopology[ThisLink].Unit) == readb(&PktCmdP->RouteTopology[NewLink].Unit)) && (readb(&PktCmdP->RouteTopology[ThisLink].Link) == readb(&PktCmdP->RouteTopology[NewLink].Link))) {
+ Lies++;
+ }
+ }
+ }
+
+ if (Lies) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n", Lies);
+ rio_dprintk(RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n",
+ readb(&PktCmdP->RouteTopology[0].Unit),
+ 'A' + readb(&PktCmdP->RouteTopology[0].Link),
+ readb(&PktCmdP->RouteTopology[1].Unit),
+ 'A' + readb(&PktCmdP->RouteTopology[1].Link), readb(&PktCmdP->RouteTopology[2].Unit), 'A' + readb(&PktCmdP->RouteTopology[2].Link), readb(&PktCmdP->RouteTopology[3].Unit), 'A' + readb(&PktCmdP->RouteTopology[3].Link));
+ return 1;
+ }
+
+ /*
+ ** now, process each link.
+ */
+ for (ThisLink = ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) {
+ /*
+ ** this is what it was connected to
+ */
+ OldUnit = TopP[ThisLink].Unit;
+ OldLink = TopP[ThisLink].Link;
+
+ /*
+ ** this is what it is now connected to
+ */
+ NewUnit = readb(&PktCmdP->RouteTopology[ThisLink].Unit);
+ NewLink = readb(&PktCmdP->RouteTopology[ThisLink].Link);
+
+ if (OldUnit != NewUnit || OldLink != NewLink) {
+ /*
+ ** something has changed!
+ */
+
+ if (NewUnit > MAX_RUP && NewUnit != ROUTE_DISCONNECT && NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, NewLink);
+ } else {
+ /*
+ ** put the new values in
+ */
+ TopP[ThisLink].Unit = NewUnit;
+ TopP[ThisLink].Link = NewLink;
+
+ RIOSetChange(p);
+
+ if (OldUnit <= MAX_RUP) {
+ /*
+ ** If something has become bust, then re-enable them messages
+ */
+ if (!p->RIONoMessage)
+ RIOConCon(p, HostP, ThisUnit, ThisLink, OldUnit, OldLink, DISCONNECT);
+ }
+
+ if ((NewUnit <= MAX_RUP) && !p->RIONoMessage)
+ RIOConCon(p, HostP, ThisUnit, ThisLink, NewUnit, NewLink, CONNECT);
+
+ if (NewUnit == ROUTE_NO_ID)
+ rio_dprintk(RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", MyType, MyName, 'A' + ThisLink);
+
+ if (NewUnit == ROUTE_INTERCONNECT) {
+ if (!p->RIONoMessage)
+ printk(KERN_DEBUG "rio: %s '%s' (%c) is connected to another network.\n", MyType, MyName, 'A' + ThisLink);
+ }
+
+ /*
+ ** perform an update for 'the other end', so that these messages
+ ** only appears once. Only disconnect the other end if it is pointing
+ ** at us!
+ */
+ if (OldUnit == HOST_ID) {
+ if (HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink + 'A');
+ HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT;
+ HostP->Topology[OldLink].Link = NO_LINK;
+ } else {
+ rio_dprintk(RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A');
+ }
+ } else if (OldUnit <= MAX_RUP) {
+ if (HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit - 1].Topology[OldLink].Link == ThisLink) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A');
+ HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit = ROUTE_DISCONNECT;
+ HostP->Mapping[OldUnit - 1].Topology[OldLink].Link = NO_LINK;
+ } else {
+ rio_dprintk(RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A');
+ }
+ }
+ if (NewUnit == HOST_ID) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", NewLink + 'A', MyName, ThisLink + 'A');
+ HostP->Topology[NewLink].Unit = ThisUnit;
+ HostP->Topology[NewLink].Link = ThisLink;
+ } else if (NewUnit <= MAX_RUP) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", HostP->Mapping[NewUnit - 1].Name, NewLink + 'A', MyName, ThisLink + 'A');
+ HostP->Mapping[NewUnit - 1].Topology[NewLink].Unit = ThisUnit;
+ HostP->Mapping[NewUnit - 1].Topology[NewLink].Link = ThisLink;
+ }
+ }
+ RIOSetChange(p);
+ RIOCheckIsolated(p, HostP, OldUnit);
+ }
+ }
+ return 1;
+ }
+
+ /*
+ ** The only other command we recognise is a route_request command
+ */
+ if (readb(&PktCmdP->Command) != ROUTE_REQUEST) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %p ROUTE_RUP\n", readb(&PktCmdP->Command), Rup, HostP);
+ return 1;
+ }
+
+ RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24);
+
+ /*
+ ** Determine if 8 or 16 port RTA
+ */
+ RtaType = GetUnitType(RtaUniq);
+
+ rio_dprintk(RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq);
+
+ Mod = readb(&PktCmdP->ModuleTypes);
+ Mod1 = LONYBLE(Mod);
+ if (RtaType == TYPE_RTA16) {
+ /*
+ ** Only one ident is set for a 16 port RTA. To make compatible
+ ** with 8 port, set 2nd ident in Mod2 to the same as Mod1.
+ */
+ Mod2 = Mod1;
+ rio_dprintk(RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", p->RIOModuleTypes[Mod1].Name);
+ } else {
+ Mod2 = HINYBLE(Mod);
+ rio_dprintk(RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name);
+ }
+
+ /*
+ ** try to unhook a command block from the command free list.
+ */
+ if (!(CmdBlkP = RIOGetCmdBlk())) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n");
+ return 0;
+ }
+
+ /*
+ ** Fill in the default info on the command block
+ */
+ CmdBlkP->Packet.dest_unit = Rup;
+ CmdBlkP->Packet.dest_port = ROUTE_RUP;
+ CmdBlkP->Packet.src_unit = HOST_ID;
+ CmdBlkP->Packet.src_port = ROUTE_RUP;
+ CmdBlkP->Packet.len = PKT_CMD_BIT | 1;
+ CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+ PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;
+
+ if (!RIOBootOk(p, HostP, RtaUniq)) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", RtaUniq);
+ PktReplyP->Command = ROUTE_FOAD;
+ memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
+ RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+ return 1;
+ }
+
+ /*
+ ** Check to see if the RTA is configured for this host
+ */
+ for (ThisUnit = 0; ThisUnit < MAX_RUP; ThisUnit++) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n",
+ ThisUnit, HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use" : "Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative" : "Not Tentative", HostP->Mapping[ThisUnit].RtaUniqueNum);
+
+ /*
+ ** We have an entry for it.
+ */
+ if ((HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq)) {
+ if (RtaType == TYPE_RTA16) {
+ ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1;
+ rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", RtaUniq, ThisUnit, ThisUnit2);
+ } else
+ rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", RtaUniq, ThisUnit);
+ /*
+ ** If we have no knowledge of booting it, then the host has
+ ** been re-booted, and so we must kill the RTA, so that it
+ ** will be booted again (potentially with new bins)
+ ** and it will then re-ask for an ID, which we will service.
+ */
+ if ((HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED)) {
+ if (!(HostP->Mapping[ThisUnit].Flags & MSG_DONE)) {
+ if (!p->RIONoMessage)
+ printk(KERN_DEBUG "rio: RTA '%s' is being updated.\n", HostP->Mapping[ThisUnit].Name);
+ HostP->Mapping[ThisUnit].Flags |= MSG_DONE;
+ }
+ PktReplyP->Command = ROUTE_FOAD;
+ memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
+ RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+ return 1;
+ }
+
+ /*
+ ** Send the ID (entry) to this RTA. The ID number is implicit as
+ ** the offset into the table. It is worth noting at this stage
+ ** that offset zero in the table contains the entries for the
+ ** RTA with ID 1!!!!
+ */
+ PktReplyP->Command = ROUTE_ALLOCATE;
+ PktReplyP->IDNum = ThisUnit + 1;
+ if (RtaType == TYPE_RTA16) {
+ if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE)
+ /*
+ ** Adjust the phb and tx pkt dest_units for 2nd block of 8
+ ** only if the RTA has ports associated (SLOT_IN_USE)
+ */
+ RIOFixPhbs(p, HostP, ThisUnit2);
+ PktReplyP->IDNum2 = ThisUnit2 + 1;
+ rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2);
+ } else {
+ PktReplyP->IDNum2 = ROUTE_NO_ID;
+ rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum);
+ }
+ memcpy(PktReplyP->CommandText, "RT_ALLOCAT", 10);
+
+ RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+
+ /*
+ ** If this is a freshly booted RTA, then we need to re-open
+ ** the ports, if any where open, so that data may once more
+ ** flow around the system!
+ */
+ if ((HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT)) {
+ /*
+ ** look at the ports associated with this beast and
+ ** see if any where open. If they was, then re-open
+ ** them, using the info from the tty flags.
+ */
+ for (port = 0; port < PORTS_PER_RTA; port++) {
+ PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort];
+ if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->MagicFlags |= MAGIC_REBOOT;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ }
+ }
+ if (RtaType == TYPE_RTA16) {
+ for (port = 0; port < PORTS_PER_RTA; port++) {
+ PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort];
+ if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->MagicFlags |= MAGIC_REBOOT;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ }
+ }
+ }
+ }
+
+ /*
+ ** keep a copy of the module types!
+ */
+ HostP->UnixRups[ThisUnit].ModTypes = Mod;
+ if (RtaType == TYPE_RTA16)
+ HostP->UnixRups[ThisUnit2].ModTypes = Mod;
+
+ /*
+ ** If either of the modules on this unit is read-only or write-only
+ ** or none-xprint, then we need to transfer that info over to the
+ ** relevant ports.
+ */
+ if (HostP->Mapping[ThisUnit].SysPort != NO_PORT) {
+ for (port = 0; port < PORTS_PER_MODULE; port++) {
+ p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+ p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
+ p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+ p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+ }
+ if (RtaType == TYPE_RTA16) {
+ for (port = 0; port < PORTS_PER_MODULE; port++) {
+ p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+ p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
+ p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+ p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+ }
+ }
+ }
+
+ /*
+ ** Job done, get on with the interrupts!
+ */
+ return 1;
+ }
+ }
+ /*
+ ** There is no table entry for this RTA at all.
+ **
+ ** Lets check to see if we actually booted this unit - if not,
+ ** then we reset it and it will go round the loop of being booted
+ ** we can then worry about trying to fit it into the table.
+ */
+ for (ThisUnit = 0; ThisUnit < HostP->NumExtraBooted; ThisUnit++)
+ if (HostP->ExtraUnits[ThisUnit] == RtaUniq)
+ break;
+ if (ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS) {
+ /*
+ ** if the unit wasn't in the table, and the table wasn't full, then
+ ** we reset the unit, because we didn't boot it.
+ ** However, if the table is full, it could be that we did boot
+ ** this unit, and so we won't reboot it, because it isn't really
+ ** all that disasterous to keep the old bins in most cases. This
+ ** is a rather tacky feature, but we are on the edge of reallity
+ ** here, because the implication is that someone has connected
+ ** 16+MAX_EXTRA_UNITS onto one host.
+ */
+ static int UnknownMesgDone = 0;
+
+ if (!UnknownMesgDone) {
+ if (!p->RIONoMessage)
+ printk(KERN_DEBUG "rio: One or more unknown RTAs are being updated.\n");
+ UnknownMesgDone = 1;
+ }
+
+ PktReplyP->Command = ROUTE_FOAD;
+ memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
+ } else {
+ /*
+ ** we did boot it (as an extra), and there may now be a table
+ ** slot free (because of a delete), so we will try to make
+ ** a tentative entry for it, so that the configurator can see it
+ ** and fill in the details for us.
+ */
+ if (RtaType == TYPE_RTA16) {
+ if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) {
+ RIODefaultName(p, HostP, ThisUnit);
+ rio_fill_host_slot(ThisUnit, ThisUnit2, RtaUniq, HostP);
+ }
+ } else {
+ if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) {
+ RIODefaultName(p, HostP, ThisUnit);
+ rio_fill_host_slot(ThisUnit, 0, RtaUniq, HostP);
+ }
+ }
+ PktReplyP->Command = ROUTE_USED;
+ memcpy(PktReplyP->CommandText, "RT_USED", 7);
+ }
+ RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+ return 1;
+}
+
+
+void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit)
+{
+ unsigned short link, port;
+ struct Port *PortP;
+ unsigned long flags;
+ int PortN = HostP->Mapping[unit].SysPort;
+
+ rio_dprintk(RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN);
+
+ if (PortN != -1) {
+ unsigned short dest_unit = HostP->Mapping[unit].ID2;
+
+ /*
+ ** Get the link number used for the 1st 8 phbs on this unit.
+ */
+ PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort];
+
+ link = readw(&PortP->PhbP->link);
+
+ for (port = 0; port < PORTS_PER_RTA; port++, PortN++) {
+ unsigned short dest_port = port + 8;
+ u16 __iomem *TxPktP;
+ struct PKT __iomem *Pkt;
+
+ PortP = p->RIOPortp[PortN];
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ /*
+ ** If RTA is not powered on, the tx packets will be
+ ** unset, so go no further.
+ */
+ if (!PortP->TxStart) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ break;
+ }
+
+ /*
+ ** For the second slot of a 16 port RTA, the driver needs to
+ ** sort out the phb to port mappings. The dest_unit for this
+ ** group of 8 phbs is set to the dest_unit of the accompanying
+ ** 8 port block. The dest_port of the second unit is set to
+ ** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port
+ ** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6
+ ** (being the second map ID) will be sent to dest_unit 5, port
+ ** 14. When this RTA is deleted, dest_unit for ID 6 will be
+ ** restored, and the dest_port will be reduced by 8.
+ ** Transmit packets also have a destination field which needs
+ ** adjusting in the same manner.
+ ** Note that the unit/port bytes in 'dest' are swapped.
+ ** We also need to adjust the phb and rup link numbers for the
+ ** second block of 8 ttys.
+ */
+ for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
+ /*
+ ** *TxPktP is the pointer to the transmit packet on the host
+ ** card. This needs to be translated into a 32 bit pointer
+ ** so it can be accessed from the driver.
+ */
+ Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(TxPktP));
+
+ /*
+ ** If the packet is used, reset it.
+ */
+ Pkt = (struct PKT __iomem *) ((unsigned long) Pkt & ~PKT_IN_USE);
+ writeb(dest_unit, &Pkt->dest_unit);
+ writeb(dest_port, &Pkt->dest_port);
+ }
+ rio_dprintk(RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", readw(&PortP->PhbP->destination) & 0xff, (readw(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port);
+ writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination);
+ writew(link, &PortP->PhbP->link);
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ }
+ /*
+ ** Now make sure the range of ports to be serviced includes
+ ** the 2nd 8 on this 16 port RTA.
+ */
+ if (link > 3)
+ return;
+ if (((unit * 8) + 7) > readw(&HostP->LinkStrP[link].last_port)) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7);
+ writew((unit * 8) + 7, &HostP->LinkStrP[link].last_port);
+ }
+ }
+}
+
+/*
+** Check to see if the new disconnection has isolated this unit.
+** If it has, then invalidate all its link information, and tell
+** the world about it. This is done to ensure that the configurator
+** only gets up-to-date information about what is going on.
+*/
+static int RIOCheckIsolated(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
+{
+ unsigned long flags;
+ rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+ if (RIOCheck(HostP, UnitId)) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Unit %d is NOT isolated\n", UnitId);
+ rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+ return (0);
+ }
+
+ RIOIsolate(p, HostP, UnitId);
+ RIOSetChange(p);
+ rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+ return 1;
+}
+
+/*
+** Invalidate all the link interconnectivity of this unit, and of
+** all the units attached to it. This will mean that the entire
+** subnet will re-introduce itself.
+*/
+static int RIOIsolate(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
+{
+ unsigned int link, unit;
+
+ UnitId--; /* this trick relies on the Unit Id being UNSIGNED! */
+
+ if (UnitId >= MAX_RUP) /* dontcha just lurv unsigned maths! */
+ return (0);
+
+ if (HostP->Mapping[UnitId].Flags & BEEN_HERE)
+ return (0);
+
+ HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+ if (p->RIOPrintDisabled == DO_PRINT)
+ rio_dprintk(RIO_DEBUG_ROUTE, "RIOMesgIsolated %s", HostP->Mapping[UnitId].Name);
+
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ unit = HostP->Mapping[UnitId].Topology[link].Unit;
+ HostP->Mapping[UnitId].Topology[link].Unit = ROUTE_DISCONNECT;
+ HostP->Mapping[UnitId].Topology[link].Link = NO_LINK;
+ RIOIsolate(p, HostP, unit);
+ }
+ HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+ return 1;
+}
+
+static int RIOCheck(struct Host *HostP, unsigned int UnitId)
+{
+ unsigned char link;
+
+/* rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */
+ rio_dprintk(RIO_DEBUG_ROUTE, "RIOCheck : UnitID = %d\n", UnitId);
+
+ if (UnitId == HOST_ID) {
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */
+ return 1;
+ }
+
+ UnitId--;
+
+ if (UnitId >= MAX_RUP) {
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d - ignored.\n", UnitId)); */
+ return 0;
+ }
+
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ if (HostP->Mapping[UnitId].Topology[link].Unit == HOST_ID) {
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected directly to host via link (%c).\n",
+ UnitId, 'A'+link)); */
+ return 1;
+ }
+ }
+
+ if (HostP->Mapping[UnitId].Flags & BEEN_HERE) {
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Been to Unit %d before - ignoring\n", UnitId)); */
+ return 0;
+ }
+
+ HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d check link (%c)\n", UnitId,'A'+link)); */
+ if (RIOCheck(HostP, HostP->Mapping[UnitId].Topology[link].Unit)) {
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected to something that knows the host via link (%c)\n", UnitId,link+'A')); */
+ HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+ return 1;
+ }
+ }
+
+ HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+
+ /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */
+
+ return 0;
+}
+
+/*
+** Returns the type of unit (host, 16/8 port RTA)
+*/
+
+unsigned int GetUnitType(unsigned int Uniq)
+{
+ switch ((Uniq >> 28) & 0xf) {
+ case RIO_AT:
+ case RIO_MCA:
+ case RIO_EISA:
+ case RIO_PCI:
+ rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: Host\n");
+ return (TYPE_HOST);
+ case RIO_RTA_16:
+ rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: 16 port RTA\n");
+ return (TYPE_RTA16);
+ case RIO_RTA:
+ rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: 8 port RTA\n");
+ return (TYPE_RTA8);
+ default:
+ rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: Unrecognised\n");
+ return (99);
+ }
+}
+
+int RIOSetChange(struct rio_info *p)
+{
+ if (p->RIOQuickCheck != NOT_CHANGED)
+ return (0);
+ p->RIOQuickCheck = CHANGED;
+ if (p->RIOSignalProcess) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Send SIG-HUP");
+ /*
+ psignal( RIOSignalProcess, SIGHUP );
+ */
+ }
+ return (0);
+}
+
+static void RIOConCon(struct rio_info *p,
+ struct Host *HostP,
+ unsigned int FromId,
+ unsigned int FromLink,
+ unsigned int ToId,
+ unsigned int ToLink,
+ int Change)
+{
+ char *FromName;
+ char *FromType;
+ char *ToName;
+ char *ToType;
+ unsigned int tp;
+
+/*
+** 15.10.1998 ARG - ESIL 0759
+** (Part) fix for port being trashed when opened whilst RTA "disconnected"
+**
+** What's this doing in here anyway ?
+** It was causing the port to be 'unmapped' if opened whilst RTA "disconnected"
+**
+** 09.12.1998 ARG - ESIL 0776 - part fix
+** Okay, We've found out what this was all about now !
+** Someone had botched this to use RIOHalted to indicated the number of RTAs
+** 'disconnected'. The value in RIOHalted was then being used in the
+** 'RIO_QUICK_CHECK' ioctl. A none zero value indicating that a least one RTA
+** is 'disconnected'. The change was put in to satisfy a customer's needs.
+** Having taken this bit of code out 'RIO_QUICK_CHECK' now no longer works for
+** the customer.
+**
+ if (Change == CONNECT) {
+ if (p->RIOHalted) p->RIOHalted --;
+ }
+ else {
+ p->RIOHalted ++;
+ }
+**
+** So - we need to implement it slightly differently - a new member of the
+** rio_info struct - RIORtaDisCons (RIO RTA connections) keeps track of RTA
+** connections and disconnections.
+*/
+ if (Change == CONNECT) {
+ if (p->RIORtaDisCons)
+ p->RIORtaDisCons--;
+ } else {
+ p->RIORtaDisCons++;
+ }
+
+ if (p->RIOPrintDisabled == DONT_PRINT)
+ return;
+
+ if (FromId > ToId) {
+ tp = FromId;
+ FromId = ToId;
+ ToId = tp;
+ tp = FromLink;
+ FromLink = ToLink;
+ ToLink = tp;
+ }
+
+ FromName = FromId ? HostP->Mapping[FromId - 1].Name : HostP->Name;
+ FromType = FromId ? "RTA" : "HOST";
+ ToName = ToId ? HostP->Mapping[ToId - 1].Name : HostP->Name;
+ ToType = ToId ? "RTA" : "HOST";
+
+ rio_dprintk(RIO_DEBUG_ROUTE, "Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A' + FromLink, ToType, ToName, 'A' + ToLink, (Change == CONNECT) ? "established" : "disconnected");
+ printk(KERN_DEBUG "rio: Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A' + FromLink, ToType, ToName, 'A' + ToLink, (Change == CONNECT) ? "established" : "disconnected");
+}
+
+/*
+** RIORemoveFromSavedTable :
+**
+** Delete and RTA entry from the saved table given to us
+** by the configuration program.
+*/
+static int RIORemoveFromSavedTable(struct rio_info *p, struct Map *pMap)
+{
+ int entry;
+
+ /*
+ ** We loop for all entries even after finding an entry and
+ ** zeroing it because we may have two entries to delete if
+ ** it's a 16 port RTA.
+ */
+ for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
+ if (p->RIOSavedTable[entry].RtaUniqueNum == pMap->RtaUniqueNum) {
+ memset(&p->RIOSavedTable[entry], 0, sizeof(struct Map));
+ }
+ }
+ return 0;
+}
+
+
+/*
+** RIOCheckDisconnected :
+**
+** Scan the unit links to and return zero if the unit is completely
+** disconnected.
+*/
+static int RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit)
+{
+ int link;
+
+
+ rio_dprintk(RIO_DEBUG_ROUTE, "RIOFreeDisconnect unit %d\n", unit);
+ /*
+ ** If the slot is tentative and does not belong to the
+ ** second half of a 16 port RTA then scan to see if
+ ** is disconnected.
+ */
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ if (HostP->Mapping[unit].Topology[link].Unit != ROUTE_DISCONNECT)
+ break;
+ }
+
+ /*
+ ** If not all links are disconnected then we can forget about it.
+ */
+ if (link < LINKS_PER_UNIT)
+ return 1;
+
+#ifdef NEED_TO_FIX_THIS
+ /* Ok so all the links are disconnected. But we may have only just
+ ** made this slot tentative and not yet received a topology update.
+ ** Lets check how long ago we made it tentative.
+ */
+ rio_dprintk(RIO_DEBUG_ROUTE, "Just about to check LBOLT on entry %d\n", unit);
+ if (drv_getparm(LBOLT, (ulong_t *) & current_time))
+ rio_dprintk(RIO_DEBUG_ROUTE, "drv_getparm(LBOLT,....) Failed.\n");
+
+ elapse_time = current_time - TentTime[unit];
+ rio_dprintk(RIO_DEBUG_ROUTE, "elapse %d = current %d - tent %d (%d usec)\n", elapse_time, current_time, TentTime[unit], drv_hztousec(elapse_time));
+ if (drv_hztousec(elapse_time) < WAIT_TO_FINISH) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Skipping slot %d, not timed out yet %d\n", unit, drv_hztousec(elapse_time));
+ return 1;
+ }
+#endif
+
+ /*
+ ** We have found an usable slot.
+ ** If it is half of a 16 port RTA then delete the other half.
+ */
+ if (HostP->Mapping[unit].ID2 != 0) {
+ int nOther = (HostP->Mapping[unit].ID2) - 1;
+
+ rio_dprintk(RIO_DEBUG_ROUTE, "RioFreedis second slot %d.\n", nOther);
+ memset(&HostP->Mapping[nOther], 0, sizeof(struct Map));
+ }
+ RIORemoveFromSavedTable(p, &HostP->Mapping[unit]);
+
+ return 0;
+}
+
+
+/*
+** RIOFindFreeID :
+**
+** This function scans the given host table for either one
+** or two free unit ID's.
+*/
+
+int RIOFindFreeID(struct rio_info *p, struct Host *HostP, unsigned int * pID1, unsigned int * pID2)
+{
+ int unit, tempID;
+
+ /*
+ ** Initialise the ID's to MAX_RUP.
+ ** We do this to make the loop for setting the ID's as simple as
+ ** possible.
+ */
+ *pID1 = MAX_RUP;
+ if (pID2 != NULL)
+ *pID2 = MAX_RUP;
+
+ /*
+ ** Scan all entries of the host mapping table for free slots.
+ ** We scan for free slots first and then if that is not successful
+ ** we start all over again looking for tentative slots we can re-use.
+ */
+ for (unit = 0; unit < MAX_RUP; unit++) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Scanning unit %d\n", unit);
+ /*
+ ** If the flags are zero then the slot is empty.
+ */
+ if (HostP->Mapping[unit].Flags == 0) {
+ rio_dprintk(RIO_DEBUG_ROUTE, " This slot is empty.\n");
+ /*
+ ** If we haven't allocated the first ID then do it now.
+ */
+ if (*pID1 == MAX_RUP) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Make tentative entry for first unit %d\n", unit);
+ *pID1 = unit;
+
+ /*
+ ** If the second ID is not needed then we can return
+ ** now.
+ */
+ if (pID2 == NULL)
+ return 0;
+ } else {
+ /*
+ ** Allocate the second slot and return.
+ */
+ rio_dprintk(RIO_DEBUG_ROUTE, "Make tentative entry for second unit %d\n", unit);
+ *pID2 = unit;
+ return 0;
+ }
+ }
+ }
+
+ /*
+ ** If we manage to come out of the free slot loop then we
+ ** need to start all over again looking for tentative slots
+ ** that we can re-use.
+ */
+ rio_dprintk(RIO_DEBUG_ROUTE, "Starting to scan for tentative slots\n");
+ for (unit = 0; unit < MAX_RUP; unit++) {
+ if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) || (HostP->Mapping[unit].Flags == 0)) && !(HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT)) {
+ rio_dprintk(RIO_DEBUG_ROUTE, " Slot %d looks promising.\n", unit);
+
+ if (unit == *pID1) {
+ rio_dprintk(RIO_DEBUG_ROUTE, " No it isn't, its the 1st half\n");
+ continue;
+ }
+
+ /*
+ ** Slot is Tentative or Empty, but not a tentative second
+ ** slot of a 16 porter.
+ ** Attempt to free up this slot (and its parnter if
+ ** it is a 16 port slot. The second slot will become
+ ** empty after a call to RIOFreeDisconnected so thats why
+ ** we look for empty slots above as well).
+ */
+ if (HostP->Mapping[unit].Flags != 0)
+ if (RIOFreeDisconnected(p, HostP, unit) != 0)
+ continue;
+ /*
+ ** If we haven't allocated the first ID then do it now.
+ */
+ if (*pID1 == MAX_RUP) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Grab tentative entry for first unit %d\n", unit);
+ *pID1 = unit;
+
+ /*
+ ** Clear out this slot now that we intend to use it.
+ */
+ memset(&HostP->Mapping[unit], 0, sizeof(struct Map));
+
+ /*
+ ** If the second ID is not needed then we can return
+ ** now.
+ */
+ if (pID2 == NULL)
+ return 0;
+ } else {
+ /*
+ ** Allocate the second slot and return.
+ */
+ rio_dprintk(RIO_DEBUG_ROUTE, "Grab tentative/empty entry for second unit %d\n", unit);
+ *pID2 = unit;
+
+ /*
+ ** Clear out this slot now that we intend to use it.
+ */
+ memset(&HostP->Mapping[unit], 0, sizeof(struct Map));
+
+ /* At this point under the right(wrong?) conditions
+ ** we may have a first unit ID being higher than the
+ ** second unit ID. This is a bad idea if we are about
+ ** to fill the slots with a 16 port RTA.
+ ** Better check and swap them over.
+ */
+
+ if (*pID1 > *pID2) {
+ rio_dprintk(RIO_DEBUG_ROUTE, "Swapping IDS %d %d\n", *pID1, *pID2);
+ tempID = *pID1;
+ *pID1 = *pID2;
+ *pID2 = tempID;
+ }
+ return 0;
+ }
+ }
+ }
+
+ /*
+ ** If we manage to get to the end of the second loop then we
+ ** can give up and return a failure.
+ */
+ return 1;
+}
+
+
+/*
+** The link switch scenario.
+**
+** Rta Wun (A) is connected to Tuw (A).
+** The tables are all up to date, and the system is OK.
+**
+** If Wun (A) is now moved to Wun (B) before Wun (A) can
+** become disconnected, then the follow happens:
+**
+** Tuw (A) spots the change of unit:link at the other end
+** of its link and Tuw sends a topology packet reflecting
+** the change: Tuw (A) now disconnected from Wun (A), and
+** this is closely followed by a packet indicating that
+** Tuw (A) is now connected to Wun (B).
+**
+** Wun (B) will spot that it has now become connected, and
+** Wun will send a topology packet, which indicates that
+** both Wun (A) and Wun (B) is connected to Tuw (A).
+**
+** Eventually Wun (A) realises that it is now disconnected
+** and Wun will send out a topology packet indicating that
+** Wun (A) is now disconnected.
+*/
diff --git a/drivers/char/rio/riospace.h b/drivers/char/rio/riospace.h
new file mode 100644
index 0000000..ffb31d4
--- /dev/null
+++ b/drivers/char/rio/riospace.h
@@ -0,0 +1,154 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : riospace.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:13
+** Retrieved : 11/6/98 11:34:22
+**
+** ident @(#)riospace.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_riospace_h__
+#define __rio_riospace_h__
+
+#define RIO_LOCATOR_LEN 16
+#define MAX_RIO_BOARDS 4
+
+/*
+** DONT change this file. At all. Unless you can rebuild the entire
+** device driver, which you probably can't, then the rest of the
+** driver won't see any changes you make here. So don't make any.
+** In particular, it won't be able to see changes to RIO_SLOTS
+*/
+
+struct Conf {
+ char Locator[24];
+ unsigned int StartupTime;
+ unsigned int SlowCook;
+ unsigned int IntrPollTime;
+ unsigned int BreakInterval;
+ unsigned int Timer;
+ unsigned int RtaLoadBase;
+ unsigned int HostLoadBase;
+ unsigned int XpHz;
+ unsigned int XpCps;
+ char *XpOn;
+ char *XpOff;
+ unsigned int MaxXpCps;
+ unsigned int MinXpCps;
+ unsigned int SpinCmds;
+ unsigned int FirstAddr;
+ unsigned int LastAddr;
+ unsigned int BufferSize;
+ unsigned int LowWater;
+ unsigned int LineLength;
+ unsigned int CmdTime;
+};
+
+/*
+** Board types - these MUST correspond to product codes!
+*/
+#define RIO_EMPTY 0x0
+#define RIO_EISA 0x3
+#define RIO_RTA_16 0x9
+#define RIO_AT 0xA
+#define RIO_MCA 0xB
+#define RIO_PCI 0xD
+#define RIO_RTA 0xE
+
+/*
+** Board data structure. This is used for configuration info
+*/
+struct Brd {
+ unsigned char Type; /* RIO_EISA, RIO_MCA, RIO_AT, RIO_EMPTY... */
+ unsigned char Ivec; /* POLLED or ivec number */
+ unsigned char Mode; /* Control stuff, see below */
+};
+
+struct Board {
+ char Locator[RIO_LOCATOR_LEN];
+ int NumSlots;
+ struct Brd Boards[MAX_RIO_BOARDS];
+};
+
+#define BOOT_FROM_LINK 0x00
+#define BOOT_FROM_RAM 0x01
+#define EXTERNAL_BUS_OFF 0x00
+#define EXTERNAL_BUS_ON 0x02
+#define INTERRUPT_DISABLE 0x00
+#define INTERRUPT_ENABLE 0x04
+#define BYTE_OPERATION 0x00
+#define WORD_OPERATION 0x08
+#define POLLED INTERRUPT_DISABLE
+#define IRQ_15 (0x00 | INTERRUPT_ENABLE)
+#define IRQ_12 (0x10 | INTERRUPT_ENABLE)
+#define IRQ_11 (0x20 | INTERRUPT_ENABLE)
+#define IRQ_9 (0x30 | INTERRUPT_ENABLE)
+#define SLOW_LINKS 0x00
+#define FAST_LINKS 0x40
+#define SLOW_AT_BUS 0x00
+#define FAST_AT_BUS 0x80
+#define SLOW_PCI_TP 0x00
+#define FAST_PCI_TP 0x80
+/*
+** Debug levels
+*/
+#define DBG_NONE 0x00000000
+
+#define DBG_INIT 0x00000001
+#define DBG_OPEN 0x00000002
+#define DBG_CLOSE 0x00000004
+#define DBG_IOCTL 0x00000008
+
+#define DBG_READ 0x00000010
+#define DBG_WRITE 0x00000020
+#define DBG_INTR 0x00000040
+#define DBG_PROC 0x00000080
+
+#define DBG_PARAM 0x00000100
+#define DBG_CMD 0x00000200
+#define DBG_XPRINT 0x00000400
+#define DBG_POLL 0x00000800
+
+#define DBG_DAEMON 0x00001000
+#define DBG_FAIL 0x00002000
+#define DBG_MODEM 0x00004000
+#define DBG_LIST 0x00008000
+
+#define DBG_ROUTE 0x00010000
+#define DBG_UTIL 0x00020000
+#define DBG_BOOT 0x00040000
+#define DBG_BUFFER 0x00080000
+
+#define DBG_MON 0x00100000
+#define DBG_SPECIAL 0x00200000
+#define DBG_VPIX 0x00400000
+#define DBG_FLUSH 0x00800000
+
+#define DBG_QENABLE 0x01000000
+
+#define DBG_ALWAYS 0x80000000
+
+#endif /* __rio_riospace_h__ */
diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c
new file mode 100644
index 0000000..3d15802
--- /dev/null
+++ b/drivers/char/rio/riotable.c
@@ -0,0 +1,941 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : riotable.c
+** SID : 1.2
+** Last Modified : 11/6/98 10:33:47
+** Retrieved : 11/6/98 10:33:50
+**
+** ident @(#)riotable.c 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "protsts.h"
+
+/*
+** A configuration table has been loaded. It is now up to us
+** to sort it out and use the information contained therein.
+*/
+int RIONewTable(struct rio_info *p)
+{
+ int Host, Host1, Host2, NameIsUnique, Entry, SubEnt;
+ struct Map *MapP;
+ struct Map *HostMapP;
+ struct Host *HostP;
+
+ char *cptr;
+
+ /*
+ ** We have been sent a new table to install. We need to break
+ ** it down into little bits and spread it around a bit to see
+ ** what we have got.
+ */
+ /*
+ ** Things to check:
+ ** (things marked 'xx' aren't checked any more!)
+ ** (1) That there are no booted Hosts/RTAs out there.
+ ** (2) That the names are properly formed
+ ** (3) That blank entries really are.
+ ** xx (4) That hosts mentioned in the table actually exist. xx
+ ** (5) That the IDs are unique (per host).
+ ** (6) That host IDs are zero
+ ** (7) That port numbers are valid
+ ** (8) That port numbers aren't duplicated
+ ** (9) That names aren't duplicated
+ ** xx (10) That hosts that actually exist are mentioned in the table. xx
+ */
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(1)\n");
+ if (p->RIOSystemUp) { /* (1) */
+ p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED;
+ return -EBUSY;
+ }
+
+ p->RIOError.Error = NOTHING_WRONG_AT_ALL;
+ p->RIOError.Entry = -1;
+ p->RIOError.Other = -1;
+
+ for (Entry = 0; Entry < TOTAL_MAP_ENTRIES; Entry++) {
+ MapP = &p->RIOConnectTable[Entry];
+ if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(2)\n");
+ cptr = MapP->Name; /* (2) */
+ cptr[MAX_NAME_LEN - 1] = '\0';
+ if (cptr[0] == '\0') {
+ memcpy(MapP->Name, MapP->RtaUniqueNum ? "RTA NN" : "HOST NN", 8);
+ MapP->Name[5] = '0' + Entry / 10;
+ MapP->Name[6] = '0' + Entry % 10;
+ }
+ while (*cptr) {
+ if (*cptr < ' ' || *cptr > '~') {
+ p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ cptr++;
+ }
+ }
+
+ /*
+ ** If the entry saved was a tentative entry then just forget
+ ** about it.
+ */
+ if (MapP->Flags & SLOT_TENTATIVE) {
+ MapP->HostUniqueNum = 0;
+ MapP->RtaUniqueNum = 0;
+ continue;
+ }
+
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(3)\n");
+ if (!MapP->RtaUniqueNum && !MapP->HostUniqueNum) { /* (3) */
+ if (MapP->ID || MapP->SysPort || MapP->Flags) {
+ rio_dprintk(RIO_DEBUG_TABLE, "%s pretending to be empty but isn't\n", MapP->Name);
+ p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "!RIO: Daemon: test (3) passes\n");
+ continue;
+ }
+
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(4)\n");
+ for (Host = 0; Host < p->RIONumHosts; Host++) { /* (4) */
+ if (p->RIOHosts[Host].UniqueNum == MapP->HostUniqueNum) {
+ HostP = &p->RIOHosts[Host];
+ /*
+ ** having done the lookup, we don't really want to do
+ ** it again, so hang the host number in a safe place
+ */
+ MapP->Topology[0].Unit = Host;
+ break;
+ }
+ }
+
+ if (Host >= p->RIONumHosts) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RTA %s has unknown host unique number 0x%x\n", MapP->Name, MapP->HostUniqueNum);
+ MapP->HostUniqueNum = 0;
+ /* MapP->RtaUniqueNum = 0; */
+ /* MapP->ID = 0; */
+ /* MapP->Flags = 0; */
+ /* MapP->SysPort = 0; */
+ /* MapP->Name[0] = 0; */
+ continue;
+ }
+
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(5)\n");
+ if (MapP->RtaUniqueNum) { /* (5) */
+ if (!MapP->ID) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an ID of zero!\n", MapP->Name);
+ p->RIOError.Error = ZERO_RTA_ID;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ if (MapP->ID > MAX_RUP) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an invalid ID %d\n", MapP->Name, MapP->ID);
+ p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ for (SubEnt = 0; SubEnt < Entry; SubEnt++) {
+ if (MapP->HostUniqueNum == p->RIOConnectTable[SubEnt].HostUniqueNum && MapP->ID == p->RIOConnectTable[SubEnt].ID) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Dupl. ID number allocated to RTA %s and RTA %s\n", MapP->Name, p->RIOConnectTable[SubEnt].Name);
+ p->RIOError.Error = DUPLICATED_RTA_ID;
+ p->RIOError.Entry = Entry;
+ p->RIOError.Other = SubEnt;
+ return -ENXIO;
+ }
+ /*
+ ** If the RtaUniqueNum is the same, it may be looking at both
+ ** entries for a 16 port RTA, so check the ids
+ */
+ if ((MapP->RtaUniqueNum == p->RIOConnectTable[SubEnt].RtaUniqueNum)
+ && (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n", MapP->Name);
+ rio_dprintk(RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n", p->RIOConnectTable[SubEnt].Name);
+ p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER;
+ p->RIOError.Entry = Entry;
+ p->RIOError.Other = SubEnt;
+ return -ENXIO;
+ }
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(7a)\n");
+ /* (7a) */
+ if ((MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "TTY Port number %d-RTA %s is not a multiple of %d!\n", (int) MapP->SysPort, MapP->Name, PORTS_PER_RTA);
+ p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(7b)\n");
+ /* (7b) */
+ if ((MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "TTY Port number %d for RTA %s is too big\n", (int) MapP->SysPort, MapP->Name);
+ p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ for (SubEnt = 0; SubEnt < Entry; SubEnt++) {
+ if (p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT)
+ continue;
+ if (p->RIOConnectTable[SubEnt].RtaUniqueNum) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(8)\n");
+ /* (8) */
+ if ((MapP->SysPort != NO_PORT) && (MapP->SysPort == p->RIOConnectTable[SubEnt].SysPort)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RTA %s:same TTY port # as RTA %s (%d)\n", MapP->Name, p->RIOConnectTable[SubEnt].Name, (int) MapP->SysPort);
+ p->RIOError.Error = TTY_NUMBER_IN_USE;
+ p->RIOError.Entry = Entry;
+ p->RIOError.Other = SubEnt;
+ return -ENXIO;
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(9)\n");
+ if (strcmp(MapP->Name, p->RIOConnectTable[SubEnt].Name) == 0 && !(MapP->Flags & RTA16_SECOND_SLOT)) { /* (9) */
+ rio_dprintk(RIO_DEBUG_TABLE, "RTA name %s used twice\n", MapP->Name);
+ p->RIOError.Error = NAME_USED_TWICE;
+ p->RIOError.Entry = Entry;
+ p->RIOError.Other = SubEnt;
+ return -ENXIO;
+ }
+ }
+ }
+ } else { /* (6) */
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(6)\n");
+ if (MapP->ID) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIO:HOST %s has been allocated ID that isn't zero!\n", MapP->Name);
+ p->RIOError.Error = HOST_ID_NOT_ZERO;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ if (MapP->SysPort != NO_PORT) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIO: HOST %s has been allocated port numbers!\n", MapP->Name);
+ p->RIOError.Error = HOST_SYSPORT_BAD;
+ p->RIOError.Entry = Entry;
+ return -ENXIO;
+ }
+ }
+ }
+
+ /*
+ ** wow! if we get here then it's a goody!
+ */
+
+ /*
+ ** Zero the (old) entries for each host...
+ */
+ for (Host = 0; Host < RIO_HOSTS; Host++) {
+ for (Entry = 0; Entry < MAX_RUP; Entry++) {
+ memset(&p->RIOHosts[Host].Mapping[Entry], 0, sizeof(struct Map));
+ }
+ memset(&p->RIOHosts[Host].Name[0], 0, sizeof(p->RIOHosts[Host].Name));
+ }
+
+ /*
+ ** Copy in the new table entries
+ */
+ for (Entry = 0; Entry < TOTAL_MAP_ENTRIES; Entry++) {
+ rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: Copy table for Host entry %d\n", Entry);
+ MapP = &p->RIOConnectTable[Entry];
+
+ /*
+ ** Now, if it is an empty slot ignore it!
+ */
+ if (MapP->HostUniqueNum == 0)
+ continue;
+
+ /*
+ ** we saved the host number earlier, so grab it back
+ */
+ HostP = &p->RIOHosts[MapP->Topology[0].Unit];
+
+ /*
+ ** If it is a host, then we only need to fill in the name field.
+ */
+ if (MapP->ID == 0) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Host entry found. Name %s\n", MapP->Name);
+ memcpy(HostP->Name, MapP->Name, MAX_NAME_LEN);
+ continue;
+ }
+
+ /*
+ ** Its an RTA entry, so fill in the host mapping entries for it
+ ** and the port mapping entries. Notice that entry zero is for
+ ** ID one.
+ */
+ HostMapP = &HostP->Mapping[MapP->ID - 1];
+
+ if (MapP->Flags & SLOT_IN_USE) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Rta entry found. Name %s\n", MapP->Name);
+ /*
+ ** structure assign, then sort out the bits we shouldn't have done
+ */
+ *HostMapP = *MapP;
+
+ HostMapP->Flags = SLOT_IN_USE;
+ if (MapP->Flags & RTA16_SECOND_SLOT)
+ HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+ RIOReMapPorts(p, HostP, HostMapP);
+ } else {
+ rio_dprintk(RIO_DEBUG_TABLE, "TENTATIVE Rta entry found. Name %s\n", MapP->Name);
+ }
+ }
+
+ for (Entry = 0; Entry < TOTAL_MAP_ENTRIES; Entry++) {
+ p->RIOSavedTable[Entry] = p->RIOConnectTable[Entry];
+ }
+
+ for (Host = 0; Host < p->RIONumHosts; Host++) {
+ for (SubEnt = 0; SubEnt < LINKS_PER_UNIT; SubEnt++) {
+ p->RIOHosts[Host].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+ p->RIOHosts[Host].Topology[SubEnt].Link = NO_LINK;
+ }
+ for (Entry = 0; Entry < MAX_RUP; Entry++) {
+ for (SubEnt = 0; SubEnt < LINKS_PER_UNIT; SubEnt++) {
+ p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+ p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Link = NO_LINK;
+ }
+ }
+ if (!p->RIOHosts[Host].Name[0]) {
+ memcpy(p->RIOHosts[Host].Name, "HOST 1", 7);
+ p->RIOHosts[Host].Name[5] += Host;
+ }
+ /*
+ ** Check that default name assigned is unique.
+ */
+ Host1 = Host;
+ NameIsUnique = 0;
+ while (!NameIsUnique) {
+ NameIsUnique = 1;
+ for (Host2 = 0; Host2 < p->RIONumHosts; Host2++) {
+ if (Host2 == Host)
+ continue;
+ if (strcmp(p->RIOHosts[Host].Name, p->RIOHosts[Host2].Name)
+ == 0) {
+ NameIsUnique = 0;
+ Host1++;
+ if (Host1 >= p->RIONumHosts)
+ Host1 = 0;
+ p->RIOHosts[Host].Name[5] = '1' + Host1;
+ }
+ }
+ }
+ /*
+ ** Rename host if name already used.
+ */
+ if (Host1 != Host) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Default name %s already used\n", p->RIOHosts[Host].Name);
+ memcpy(p->RIOHosts[Host].Name, "HOST 1", 7);
+ p->RIOHosts[Host].Name[5] += Host1;
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "Assigning default name %s\n", p->RIOHosts[Host].Name);
+ }
+ return 0;
+}
+
+/*
+** User process needs the config table - build it from first
+** principles.
+**
+* FIXME: SMP locking
+*/
+int RIOApel(struct rio_info *p)
+{
+ int Host;
+ int link;
+ int Rup;
+ int Next = 0;
+ struct Map *MapP;
+ struct Host *HostP;
+ unsigned long flags;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Generating a table to return to config.rio\n");
+
+ memset(&p->RIOConnectTable[0], 0, sizeof(struct Map) * TOTAL_MAP_ENTRIES);
+
+ for (Host = 0; Host < RIO_HOSTS; Host++) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Processing host %d\n", Host);
+ HostP = &p->RIOHosts[Host];
+ rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+ MapP = &p->RIOConnectTable[Next++];
+ MapP->HostUniqueNum = HostP->UniqueNum;
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+ rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+ continue;
+ }
+ MapP->RtaUniqueNum = 0;
+ MapP->ID = 0;
+ MapP->Flags = SLOT_IN_USE;
+ MapP->SysPort = NO_PORT;
+ for (link = 0; link < LINKS_PER_UNIT; link++)
+ MapP->Topology[link] = HostP->Topology[link];
+ memcpy(MapP->Name, HostP->Name, MAX_NAME_LEN);
+ for (Rup = 0; Rup < MAX_RUP; Rup++) {
+ if (HostP->Mapping[Rup].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) {
+ p->RIOConnectTable[Next] = HostP->Mapping[Rup];
+ if (HostP->Mapping[Rup].Flags & SLOT_IN_USE)
+ p->RIOConnectTable[Next].Flags |= SLOT_IN_USE;
+ if (HostP->Mapping[Rup].Flags & SLOT_TENTATIVE)
+ p->RIOConnectTable[Next].Flags |= SLOT_TENTATIVE;
+ if (HostP->Mapping[Rup].Flags & RTA16_SECOND_SLOT)
+ p->RIOConnectTable[Next].Flags |= RTA16_SECOND_SLOT;
+ Next++;
+ }
+ }
+ rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+ }
+ return 0;
+}
+
+/*
+** config.rio has taken a dislike to one of the gross maps entries.
+** if the entry is suitably inactive, then we can gob on it and remove
+** it from the table.
+*/
+int RIODeleteRta(struct rio_info *p, struct Map *MapP)
+{
+ int host, entry, port, link;
+ int SysPort;
+ struct Host *HostP;
+ struct Map *HostMapP;
+ struct Port *PortP;
+ int work_done = 0;
+ unsigned long lock_flags, sem_flags;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n", MapP->HostUniqueNum, MapP->RtaUniqueNum);
+
+ for (host = 0; host < p->RIONumHosts; host++) {
+ HostP = &p->RIOHosts[host];
+
+ rio_spin_lock_irqsave(&HostP->HostLock, lock_flags);
+
+ if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+ rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
+ continue;
+ }
+
+ for (entry = 0; entry < MAX_RUP; entry++) {
+ if (MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum) {
+ HostMapP = &HostP->Mapping[entry];
+ rio_dprintk(RIO_DEBUG_TABLE, "Found entry offset %d on host %s\n", entry, HostP->Name);
+
+ /*
+ ** Check all four links of the unit are disconnected
+ */
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ if (HostMapP->Topology[link].Unit != ROUTE_DISCONNECT) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n");
+ p->RIOError.Error = UNIT_IS_IN_USE;
+ rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
+ return -EBUSY;
+ }
+ }
+ /*
+ ** Slot has been allocated, BUT not booted/routed/
+ ** connected/selected or anything else-ed
+ */
+ SysPort = HostMapP->SysPort;
+
+ if (SysPort != NO_PORT) {
+ for (port = SysPort; port < SysPort + PORTS_PER_RTA; port++) {
+ PortP = p->RIOPortp[port];
+ rio_dprintk(RIO_DEBUG_TABLE, "Unmap port\n");
+
+ rio_spin_lock_irqsave(&PortP->portSem, sem_flags);
+
+ PortP->Mapped = 0;
+
+ if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Gob on port\n");
+ PortP->TxBufferIn = PortP->TxBufferOut = 0;
+ /* What should I do
+ wakeup( &PortP->TxBufferIn );
+ wakeup( &PortP->TxBufferOut);
+ */
+ PortP->InUse = NOT_INUSE;
+ /* What should I do
+ wakeup( &PortP->InUse );
+ signal(PortP->TtyP->t_pgrp,SIGKILL);
+ ttyflush(PortP->TtyP,(FREAD|FWRITE));
+ */
+ PortP->State |= RIO_CLOSING | RIO_DELETED;
+ }
+
+ /*
+ ** For the second slot of a 16 port RTA, the
+ ** driver needs to reset the changes made to
+ ** the phb to port mappings in RIORouteRup.
+ */
+ if (PortP->SecondBlock) {
+ u16 dest_unit = HostMapP->ID;
+ u16 dest_port = port - SysPort;
+ u16 __iomem *TxPktP;
+ struct PKT __iomem *Pkt;
+
+ for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
+ /*
+ ** *TxPktP is the pointer to the
+ ** transmit packet on the host card.
+ ** This needs to be translated into
+ ** a 32 bit pointer so it can be
+ ** accessed from the driver.
+ */
+ Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&*TxPktP));
+ rio_dprintk(RIO_DEBUG_TABLE, "Tx packet (%x) destination: Old %x:%x New %x:%x\n", readw(TxPktP), readb(&Pkt->dest_unit), readb(&Pkt->dest_port), dest_unit, dest_port);
+ writew(dest_unit, &Pkt->dest_unit);
+ writew(dest_port, &Pkt->dest_port);
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "Port %d phb destination: Old %x:%x New %x:%x\n", port, readb(&PortP->PhbP->destination) & 0xff, (readb(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port);
+ writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination);
+ }
+ rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags);
+ }
+ }
+ rio_dprintk(RIO_DEBUG_TABLE, "Entry nulled.\n");
+ memset(HostMapP, 0, sizeof(struct Map));
+ work_done++;
+ }
+ }
+ rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
+ }
+
+ /* XXXXX lock me up */
+ for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
+ if (p->RIOSavedTable[entry].RtaUniqueNum == MapP->RtaUniqueNum) {
+ memset(&p->RIOSavedTable[entry], 0, sizeof(struct Map));
+ work_done++;
+ }
+ if (p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum) {
+ memset(&p->RIOConnectTable[entry], 0, sizeof(struct Map));
+ work_done++;
+ }
+ }
+ if (work_done)
+ return 0;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Couldn't find entry to be deleted\n");
+ p->RIOError.Error = COULDNT_FIND_ENTRY;
+ return -ENXIO;
+}
+
+int RIOAssignRta(struct rio_info *p, struct Map *MapP)
+{
+ int host;
+ struct Map *HostMapP;
+ char *sptr;
+ int link;
+
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Assign entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum, MapP->RtaUniqueNum, MapP->ID, (int) MapP->SysPort);
+
+ if ((MapP->ID != (u16) - 1) && ((int) MapP->ID < (int) 1 || (int) MapP->ID > MAX_RUP)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Bad ID in map entry!\n");
+ p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ if (MapP->RtaUniqueNum == 0) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Rta Unique number zero!\n");
+ p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO;
+ return -EINVAL;
+ }
+ if ((MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Port %d not multiple of %d!\n", (int) MapP->SysPort, PORTS_PER_RTA);
+ p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+ if ((MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS)) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Port %d not valid!\n", (int) MapP->SysPort);
+ p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ /*
+ ** Copy the name across to the map entry.
+ */
+ MapP->Name[MAX_NAME_LEN - 1] = '\0';
+ sptr = MapP->Name;
+ while (*sptr) {
+ if (*sptr < ' ' || *sptr > '~') {
+ rio_dprintk(RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n");
+ p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+ return -EINVAL;
+ }
+ sptr++;
+ }
+
+ for (host = 0; host < p->RIONumHosts; host++) {
+ if (MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum) {
+ if ((p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING) {
+ p->RIOError.Error = HOST_NOT_RUNNING;
+ return -ENXIO;
+ }
+
+ /*
+ ** Now we have a host we need to allocate an ID
+ ** if the entry does not already have one.
+ */
+ if (MapP->ID == (u16) - 1) {
+ int nNewID;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Attempting to get a new ID for rta \"%s\"\n", MapP->Name);
+ /*
+ ** The idea here is to allow RTA's to be assigned
+ ** before they actually appear on the network.
+ ** This allows the addition of RTA's without having
+ ** to plug them in.
+ ** What we do is:
+ ** - Find a free ID and allocate it to the RTA.
+ ** - If this map entry is the second half of a
+ ** 16 port entry then find the other half and
+ ** make sure the 2 cross reference each other.
+ */
+ if (RIOFindFreeID(p, &p->RIOHosts[host], &nNewID, NULL) != 0) {
+ p->RIOError.Error = COULDNT_FIND_ENTRY;
+ return -EBUSY;
+ }
+ MapP->ID = (u16) nNewID + 1;
+ rio_dprintk(RIO_DEBUG_TABLE, "Allocated ID %d for this new RTA.\n", MapP->ID);
+ HostMapP = &p->RIOHosts[host].Mapping[nNewID];
+ HostMapP->RtaUniqueNum = MapP->RtaUniqueNum;
+ HostMapP->HostUniqueNum = MapP->HostUniqueNum;
+ HostMapP->ID = MapP->ID;
+ for (link = 0; link < LINKS_PER_UNIT; link++) {
+ HostMapP->Topology[link].Unit = ROUTE_DISCONNECT;
+ HostMapP->Topology[link].Link = NO_LINK;
+ }
+ if (MapP->Flags & RTA16_SECOND_SLOT) {
+ int unit;
+
+ for (unit = 0; unit < MAX_RUP; unit++)
+ if (p->RIOHosts[host].Mapping[unit].RtaUniqueNum == MapP->RtaUniqueNum)
+ break;
+ if (unit == MAX_RUP) {
+ p->RIOError.Error = COULDNT_FIND_ENTRY;
+ return -EBUSY;
+ }
+ HostMapP->Flags |= RTA16_SECOND_SLOT;
+ HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID;
+ p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID;
+ rio_dprintk(RIO_DEBUG_TABLE, "Cross referenced id %d to ID %d.\n", MapP->ID, p->RIOHosts[host].Mapping[unit].ID);
+ }
+ }
+
+ HostMapP = &p->RIOHosts[host].Mapping[MapP->ID - 1];
+
+ if (HostMapP->Flags & SLOT_IN_USE) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Map table slot for ID %d is already in use.\n", MapP->ID);
+ p->RIOError.Error = ID_ALREADY_IN_USE;
+ return -EBUSY;
+ }
+
+ /*
+ ** Assign the sys ports and the name, and mark the slot as
+ ** being in use.
+ */
+ HostMapP->SysPort = MapP->SysPort;
+ if ((MapP->Flags & RTA16_SECOND_SLOT) == 0)
+ memcpy(HostMapP->Name, MapP->Name, MAX_NAME_LEN);
+ HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED;
+#ifdef NEED_TO_FIX
+ RIO_SV_BROADCAST(p->RIOHosts[host].svFlags[MapP->ID - 1]);
+#endif
+ if (MapP->Flags & RTA16_SECOND_SLOT)
+ HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+ RIOReMapPorts(p, &p->RIOHosts[host], HostMapP);
+ /*
+ ** Adjust 2nd block of 8 phbs
+ */
+ if (MapP->Flags & RTA16_SECOND_SLOT)
+ RIOFixPhbs(p, &p->RIOHosts[host], HostMapP->ID - 1);
+
+ if (HostMapP->SysPort != NO_PORT) {
+ if (HostMapP->SysPort < p->RIOFirstPortsBooted)
+ p->RIOFirstPortsBooted = HostMapP->SysPort;
+ if (HostMapP->SysPort > p->RIOLastPortsBooted)
+ p->RIOLastPortsBooted = HostMapP->SysPort;
+ }
+ if (MapP->Flags & RTA16_SECOND_SLOT)
+ rio_dprintk(RIO_DEBUG_TABLE, "Second map of RTA %s added to configuration\n", p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name);
+ else
+ rio_dprintk(RIO_DEBUG_TABLE, "RTA %s added to configuration\n", MapP->Name);
+ return 0;
+ }
+ }
+ p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+ rio_dprintk(RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum);
+ return -ENXIO;
+}
+
+
+int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP)
+{
+ struct Port *PortP;
+ unsigned int SubEnt;
+ unsigned int HostPort;
+ unsigned int SysPort;
+ u16 RtaType;
+ unsigned long flags;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Mapping sysport %d to id %d\n", (int) HostMapP->SysPort, HostMapP->ID);
+
+ /*
+ ** We need to tell the UnixRups which sysport the rup corresponds to
+ */
+ HostP->UnixRups[HostMapP->ID - 1].BaseSysPort = HostMapP->SysPort;
+
+ if (HostMapP->SysPort == NO_PORT)
+ return (0);
+
+ RtaType = GetUnitType(HostMapP->RtaUniqueNum);
+ rio_dprintk(RIO_DEBUG_TABLE, "Mapping sysport %d-%d\n", (int) HostMapP->SysPort, (int) HostMapP->SysPort + PORTS_PER_RTA - 1);
+
+ /*
+ ** now map each of its eight ports
+ */
+ for (SubEnt = 0; SubEnt < PORTS_PER_RTA; SubEnt++) {
+ rio_dprintk(RIO_DEBUG_TABLE, "subent = %d, HostMapP->SysPort = %d\n", SubEnt, (int) HostMapP->SysPort);
+ SysPort = HostMapP->SysPort + SubEnt; /* portnumber within system */
+ /* portnumber on host */
+
+ HostPort = (HostMapP->ID - 1) * PORTS_PER_RTA + SubEnt;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp);
+ PortP = p->RIOPortp[SysPort];
+ rio_dprintk(RIO_DEBUG_TABLE, "Map port\n");
+
+ /*
+ ** Point at all the real neat data structures
+ */
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ PortP->HostP = HostP;
+ PortP->Caddr = HostP->Caddr;
+
+ /*
+ ** The PhbP cannot be filled in yet
+ ** unless the host has been booted
+ */
+ if ((HostP->Flags & RUN_STATE) == RC_RUNNING) {
+ struct PHB __iomem *PhbP = PortP->PhbP = &HostP->PhbP[HostPort];
+ PortP->TxAdd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_add));
+ PortP->TxStart = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_start));
+ PortP->TxEnd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_end));
+ PortP->RxRemove = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_remove));
+ PortP->RxStart = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_start));
+ PortP->RxEnd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_end));
+ } else
+ PortP->PhbP = NULL;
+
+ /*
+ ** port related flags
+ */
+ PortP->HostPort = HostPort;
+ /*
+ ** For each part of a 16 port RTA, RupNum is ID - 1.
+ */
+ PortP->RupNum = HostMapP->ID - 1;
+ if (HostMapP->Flags & RTA16_SECOND_SLOT) {
+ PortP->ID2 = HostMapP->ID2 - 1;
+ PortP->SecondBlock = 1;
+ } else {
+ PortP->ID2 = 0;
+ PortP->SecondBlock = 0;
+ }
+ PortP->RtaUniqueNum = HostMapP->RtaUniqueNum;
+
+ /*
+ ** If the port was already mapped then thats all we need to do.
+ */
+ if (PortP->Mapped) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ continue;
+ } else
+ HostMapP->Flags &= ~RTA_NEWBOOT;
+
+ PortP->State = 0;
+ PortP->Config = 0;
+ /*
+ ** Check out the module type - if it is special (read only etc.)
+ ** then we need to set flags in the PortP->Config.
+ ** Note: For 16 port RTA, all ports are of the same type.
+ */
+ if (RtaType == TYPE_RTA16) {
+ PortP->Config |= p->RIOModuleTypes[HostP->UnixRups[HostMapP->ID - 1].ModTypes].Flags[SubEnt % PORTS_PER_MODULE];
+ } else {
+ if (SubEnt < PORTS_PER_MODULE)
+ PortP->Config |= p->RIOModuleTypes[LONYBLE(HostP->UnixRups[HostMapP->ID - 1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+ else
+ PortP->Config |= p->RIOModuleTypes[HINYBLE(HostP->UnixRups[HostMapP->ID - 1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+ }
+
+ /*
+ ** more port related flags
+ */
+ PortP->PortState = 0;
+ PortP->ModemLines = 0;
+ PortP->ModemState = 0;
+ PortP->CookMode = COOK_WELL;
+ PortP->ParamSem = 0;
+ PortP->FlushCmdBodge = 0;
+ PortP->WflushFlag = 0;
+ PortP->MagicFlags = 0;
+ PortP->Lock = 0;
+ PortP->Store = 0;
+ PortP->FirstOpen = 1;
+
+ /*
+ ** Buffers 'n things
+ */
+ PortP->RxDataStart = 0;
+ PortP->Cor2Copy = 0;
+ PortP->Name = &HostMapP->Name[0];
+ PortP->statsGather = 0;
+ PortP->txchars = 0;
+ PortP->rxchars = 0;
+ PortP->opens = 0;
+ PortP->closes = 0;
+ PortP->ioctls = 0;
+ if (PortP->TxRingBuffer)
+ memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
+ else if (p->RIOBufferSize) {
+ PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL);
+ }
+ PortP->TxBufferOut = 0;
+ PortP->TxBufferIn = 0;
+ PortP->Debug = 0;
+ /*
+ ** LastRxTgl stores the state of the rx toggle bit for this
+ ** port, to be compared with the state of the next pkt received.
+ ** If the same, we have received the same rx pkt from the RTA
+ ** twice. Initialise to a value not equal to PHB_RX_TGL or 0.
+ */
+ PortP->LastRxTgl = ~(u8) PHB_RX_TGL;
+
+ /*
+ ** and mark the port as usable
+ */
+ PortP->Mapped = 1;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ }
+ if (HostMapP->SysPort < p->RIOFirstPortsMapped)
+ p->RIOFirstPortsMapped = HostMapP->SysPort;
+ if (HostMapP->SysPort > p->RIOLastPortsMapped)
+ p->RIOLastPortsMapped = HostMapP->SysPort;
+
+ return 0;
+}
+
+int RIOChangeName(struct rio_info *p, struct Map *MapP)
+{
+ int host;
+ struct Map *HostMapP;
+ char *sptr;
+
+ rio_dprintk(RIO_DEBUG_TABLE, "Change name entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum, MapP->RtaUniqueNum, MapP->ID, (int) MapP->SysPort);
+
+ if (MapP->ID > MAX_RUP) {
+ rio_dprintk(RIO_DEBUG_TABLE, "Bad ID in map entry!\n");
+ p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ MapP->Name[MAX_NAME_LEN - 1] = '\0';
+ sptr = MapP->Name;
+
+ while (*sptr) {
+ if (*sptr < ' ' || *sptr > '~') {
+ rio_dprintk(RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n");
+ p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+ return -EINVAL;
+ }
+ sptr++;
+ }
+
+ for (host = 0; host < p->RIONumHosts; host++) {
+ if (MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum) {
+ if ((p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING) {
+ p->RIOError.Error = HOST_NOT_RUNNING;
+ return -ENXIO;
+ }
+ if (MapP->ID == 0) {
+ memcpy(p->RIOHosts[host].Name, MapP->Name, MAX_NAME_LEN);
+ return 0;
+ }
+
+ HostMapP = &p->RIOHosts[host].Mapping[MapP->ID - 1];
+
+ if (HostMapP->RtaUniqueNum != MapP->RtaUniqueNum) {
+ p->RIOError.Error = RTA_NUMBER_WRONG;
+ return -ENXIO;
+ }
+ memcpy(HostMapP->Name, MapP->Name, MAX_NAME_LEN);
+ return 0;
+ }
+ }
+ p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+ rio_dprintk(RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum);
+ return -ENXIO;
+}
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
new file mode 100644
index 0000000..2fb49e8
--- /dev/null
+++ b/drivers/char/rio/riotty.c
@@ -0,0 +1,654 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : riotty.c
+** SID : 1.3
+** Last Modified : 11/6/98 10:33:47
+** Retrieved : 11/6/98 10:33:50
+**
+** ident @(#)riotty.c 1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#define __EXPLICIT_DEF_H__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+
+static void RIOClearUp(struct Port *PortP);
+
+/* Below belongs in func.h */
+int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg);
+
+
+extern struct rio_info *p;
+
+
+int riotopen(struct tty_struct *tty, struct file *filp)
+{
+ unsigned int SysPort;
+ int repeat_this = 250;
+ struct Port *PortP; /* pointer to the port structure */
+ unsigned long flags;
+ int retval = 0;
+
+ func_enter();
+
+ /* Make sure driver_data is NULL in case the rio isn't booted jet. Else gs_close
+ is going to oops.
+ */
+ tty->driver_data = NULL;
+
+ SysPort = rio_minor(tty);
+
+ if (p->RIOFailed) {
+ rio_dprintk(RIO_DEBUG_TTY, "System initialisation failed\n");
+ func_exit();
+ return -ENXIO;
+ }
+
+ rio_dprintk(RIO_DEBUG_TTY, "port open SysPort %d (mapped:%d)\n", SysPort, p->RIOPortp[SysPort]->Mapped);
+
+ /*
+ ** Validate that we have received a legitimate request.
+ ** Currently, just check that we are opening a port on
+ ** a host card that actually exists, and that the port
+ ** has been mapped onto a host.
+ */
+ if (SysPort >= RIO_PORTS) { /* out of range ? */
+ rio_dprintk(RIO_DEBUG_TTY, "Illegal port number %d\n", SysPort);
+ func_exit();
+ return -ENXIO;
+ }
+
+ /*
+ ** Grab pointer to the port stucture
+ */
+ PortP = p->RIOPortp[SysPort]; /* Get control struc */
+ rio_dprintk(RIO_DEBUG_TTY, "PortP: %p\n", PortP);
+ if (!PortP->Mapped) { /* we aren't mapped yet! */
+ /*
+ ** The system doesn't know which RTA this port
+ ** corresponds to.
+ */
+ rio_dprintk(RIO_DEBUG_TTY, "port not mapped into system\n");
+ func_exit();
+ return -ENXIO;
+ }
+
+ tty->driver_data = PortP;
+
+ PortP->gs.port.tty = tty;
+ PortP->gs.port.count++;
+
+ rio_dprintk(RIO_DEBUG_TTY, "%d bytes in tx buffer\n", PortP->gs.xmit_cnt);
+
+ retval = gs_init_port(&PortP->gs);
+ if (retval) {
+ PortP->gs.port.count--;
+ return -ENXIO;
+ }
+ /*
+ ** If the host hasn't been booted yet, then
+ ** fail
+ */
+ if ((PortP->HostP->Flags & RUN_STATE) != RC_RUNNING) {
+ rio_dprintk(RIO_DEBUG_TTY, "Host not running\n");
+ func_exit();
+ return -ENXIO;
+ }
+
+ /*
+ ** If the RTA has not booted yet and the user has choosen to block
+ ** until the RTA is present then we must spin here waiting for
+ ** the RTA to boot.
+ */
+ /* I find the above code a bit hairy. I find the below code
+ easier to read and shorter. Now, if it works too that would
+ be great... -- REW
+ */
+ rio_dprintk(RIO_DEBUG_TTY, "Checking if RTA has booted... \n");
+ while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) {
+ if (!PortP->WaitUntilBooted) {
+ rio_dprintk(RIO_DEBUG_TTY, "RTA never booted\n");
+ func_exit();
+ return -ENXIO;
+ }
+
+ /* Under Linux you'd normally use a wait instead of this
+ busy-waiting. I'll stick with the old implementation for
+ now. --REW
+ */
+ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_TTY, "RTA_wait_for_boot: EINTR in delay \n");
+ func_exit();
+ return -EINTR;
+ }
+ if (repeat_this-- <= 0) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n");
+ func_exit();
+ return -EIO;
+ }
+ }
+ rio_dprintk(RIO_DEBUG_TTY, "RTA has been booted\n");
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ if (p->RIOHalted) {
+ goto bombout;
+ }
+
+ /*
+ ** If the port is in the final throws of being closed,
+ ** we should wait here (politely), waiting
+ ** for it to finish, so that it doesn't close us!
+ */
+ while ((PortP->State & RIO_CLOSING) && !p->RIOHalted) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n");
+ if (repeat_this-- <= 0) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ retval = -EINTR;
+ goto bombout;
+ }
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ retval = -EINTR;
+ goto bombout;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ }
+
+ if (!PortP->Mapped) {
+ rio_dprintk(RIO_DEBUG_TTY, "Port unmapped while closing!\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ retval = -ENXIO;
+ func_exit();
+ return retval;
+ }
+
+ if (p->RIOHalted) {
+ goto bombout;
+ }
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,
+** we need to make sure that the flags are clear when the port is opened.
+*/
+ /* Uh? Suppose I turn these on and then another process opens
+ the port again? The flags get cleared! Not good. -- REW */
+ if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+ PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW);
+ }
+
+ if (!(PortP->firstOpen)) { /* First time ? */
+ rio_dprintk(RIO_DEBUG_TTY, "First open for this port\n");
+
+
+ PortP->firstOpen++;
+ PortP->CookMode = 0; /* XXX RIOCookMode(tp); */
+ PortP->InUse = NOT_INUSE;
+
+ /* Tentative fix for bug PR27. Didn't work. */
+ /* PortP->gs.xmit_cnt = 0; */
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+ /* Someone explain to me why this delay/config is
+ here. If I read the docs correctly the "open"
+ command piggybacks the parameters immediately.
+ -- REW */
+ RIOParam(PortP, RIOC_OPEN, 1, OK_TO_SLEEP); /* Open the port */
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ /*
+ ** wait for the port to be not closed.
+ */
+ while (!(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for PORT_ISOPEN-currently %x\n", PortP->PortState);
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n");
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ func_exit();
+ return -EINTR;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ }
+
+ if (p->RIOHalted) {
+ retval = -EIO;
+ bombout:
+ /* RIOClearUp( PortP ); */
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return retval;
+ }
+ rio_dprintk(RIO_DEBUG_TTY, "PORT_ISOPEN found\n");
+ }
+ rio_dprintk(RIO_DEBUG_TTY, "Modem - test for carrier\n");
+ /*
+ ** ACTION
+ ** insert test for carrier here. -- ???
+ ** I already see that test here. What's the deal? -- REW
+ */
+ if ((PortP->gs.port.tty->termios->c_cflag & CLOCAL) ||
+ (PortP->ModemState & RIOC_MSVR1_CD)) {
+ rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort);
+ /*
+ tp->tm.c_state |= CARR_ON;
+ wakeup((caddr_t) &tp->tm.c_canq);
+ */
+ PortP->State |= RIO_CARR_ON;
+ wake_up_interruptible(&PortP->gs.port.open_wait);
+ } else { /* no carrier - wait for DCD */
+ /*
+ while (!(PortP->gs.port.tty->termios->c_state & CARR_ON) &&
+ !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted )
+ */
+ while (!(PortP->State & RIO_CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted) {
+ rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n", SysPort);
+ /*
+ PortP->gs.port.tty->termios->c_state |= WOPEN;
+ */
+ PortP->State |= RIO_WOPEN;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ /*
+ ** ACTION: verify that this is a good thing
+ ** to do here. -- ???
+ ** I think it's OK. -- REW
+ */
+ rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ /*
+ tp->tm.c_state &= ~WOPEN;
+ */
+ PortP->State &= ~RIO_WOPEN;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ func_exit();
+ return -EINTR;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ }
+ PortP->State &= ~RIO_WOPEN;
+ }
+ if (p->RIOHalted)
+ goto bombout;
+ rio_dprintk(RIO_DEBUG_TTY, "Setting RIO_MOPEN\n");
+ PortP->State |= RIO_MOPEN;
+
+ if (p->RIOHalted)
+ goto bombout;
+
+ rio_dprintk(RIO_DEBUG_TTY, "high level open done\n");
+
+ /*
+ ** Count opens for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->opens++;
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ rio_dprintk(RIO_DEBUG_TTY, "Returning from open\n");
+ func_exit();
+ return 0;
+}
+
+/*
+** RIOClose the port.
+** The operating system thinks that this is last close for the device.
+** As there are two interfaces to the port (Modem and tty), we need to
+** check that both are closed before we close the device.
+*/
+int riotclose(void *ptr)
+{
+ struct Port *PortP = ptr; /* pointer to the port structure */
+ int deleted = 0;
+ int try = -1; /* Disable the timeouts by setting them to -1 */
+ int repeat_this = -1; /* Congrats to those having 15 years of
+ uptime! (You get to break the driver.) */
+ unsigned long end_time;
+ struct tty_struct *tty;
+ unsigned long flags;
+ int rv = 0;
+
+ rio_dprintk(RIO_DEBUG_TTY, "port close SysPort %d\n", PortP->PortNum);
+
+ /* PortP = p->RIOPortp[SysPort]; */
+ rio_dprintk(RIO_DEBUG_TTY, "Port is at address %p\n", PortP);
+ /* tp = PortP->TtyP; *//* Get tty */
+ tty = PortP->gs.port.tty;
+ rio_dprintk(RIO_DEBUG_TTY, "TTY is at address %p\n", tty);
+
+ if (PortP->gs.closing_wait)
+ end_time = jiffies + PortP->gs.closing_wait;
+ else
+ end_time = jiffies + MAX_SCHEDULE_TIMEOUT;
+
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ /*
+ ** Setting this flag will make any process trying to open
+ ** this port block until we are complete closing it.
+ */
+ PortP->State |= RIO_CLOSING;
+
+ if ((PortP->State & RIO_DELETED)) {
+ rio_dprintk(RIO_DEBUG_TTY, "Close on deleted RTA\n");
+ deleted = 1;
+ }
+
+ if (p->RIOHalted) {
+ RIOClearUp(PortP);
+ rv = -EIO;
+ goto close_end;
+ }
+
+ rio_dprintk(RIO_DEBUG_TTY, "Clear bits\n");
+ /*
+ ** clear the open bits for this device
+ */
+ PortP->State &= ~RIO_MOPEN;
+ PortP->State &= ~RIO_CARR_ON;
+ PortP->ModemState &= ~RIOC_MSVR1_CD;
+ /*
+ ** If the device was open as both a Modem and a tty line
+ ** then we need to wimp out here, as the port has not really
+ ** been finally closed (gee, whizz!) The test here uses the
+ ** bit for the OTHER mode of operation, to see if THAT is
+ ** still active!
+ */
+ if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+ /*
+ ** The port is still open for the other task -
+ ** return, pretending that we are still active.
+ */
+ rio_dprintk(RIO_DEBUG_TTY, "Channel %d still open !\n", PortP->PortNum);
+ PortP->State &= ~RIO_CLOSING;
+ if (PortP->firstOpen)
+ PortP->firstOpen--;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return -EIO;
+ }
+
+ rio_dprintk(RIO_DEBUG_TTY, "Closing down - everything must go!\n");
+
+ PortP->State &= ~RIO_DYNOROD;
+
+ /*
+ ** This is where we wait for the port
+ ** to drain down before closing. Bye-bye....
+ ** (We never meant to do this)
+ */
+ rio_dprintk(RIO_DEBUG_TTY, "Timeout 1 starts\n");
+
+ if (!deleted)
+ while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted && (PortP->TxBufferIn != PortP->TxBufferOut)) {
+ if (repeat_this-- <= 0) {
+ rv = -EINTR;
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ goto close_end;
+ }
+ rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (RIODelay_ni(PortP, HUNDRED_MS * 10) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
+ rv = -EINTR;
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ goto close_end;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ }
+
+ PortP->TxBufferIn = PortP->TxBufferOut = 0;
+ repeat_this = 0xff;
+
+ PortP->InUse = 0;
+ if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+ /*
+ ** The port has been re-opened for the other task -
+ ** return, pretending that we are still active.
+ */
+ rio_dprintk(RIO_DEBUG_TTY, "Channel %d re-open!\n", PortP->PortNum);
+ PortP->State &= ~RIO_CLOSING;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (PortP->firstOpen)
+ PortP->firstOpen--;
+ return -EIO;
+ }
+
+ if (p->RIOHalted) {
+ RIOClearUp(PortP);
+ goto close_end;
+ }
+
+ /* Can't call RIOShortCommand with the port locked. */
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+ if (RIOShortCommand(p, PortP, RIOC_CLOSE, 1, 0) == RIO_FAIL) {
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ goto close_end;
+ }
+
+ if (!deleted)
+ while (try && (PortP->PortState & PORT_ISOPEN)) {
+ try--;
+ if (time_after(jiffies, end_time)) {
+ rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n");
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ break;
+ }
+ rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN);
+
+ if (p->RIOHalted) {
+ RIOClearUp(PortP);
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ goto close_end;
+ }
+ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+ rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+ break;
+ }
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try);
+
+ /* RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,** we need to make sure that the flags are clear when the port is opened.
+*/
+ PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW);
+
+ /*
+ ** Count opens for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->closes++;
+
+close_end:
+ /* XXX: Why would a "DELETED" flag be reset here? I'd have
+ thought that a "deleted" flag means that the port was
+ permanently gone, but here we can make it reappear by it
+ being in close during the "deletion".
+ */
+ PortP->State &= ~(RIO_CLOSING | RIO_DELETED);
+ if (PortP->firstOpen)
+ PortP->firstOpen--;
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ rio_dprintk(RIO_DEBUG_TTY, "Return from close\n");
+ return rv;
+}
+
+
+
+static void RIOClearUp(struct Port *PortP)
+{
+ rio_dprintk(RIO_DEBUG_TTY, "RIOHalted set\n");
+ PortP->Config = 0; /* Direct semaphore */
+ PortP->PortState = 0;
+ PortP->firstOpen = 0;
+ PortP->FlushCmdBodge = 0;
+ PortP->ModemState = PortP->CookMode = 0;
+ PortP->Mapped = 0;
+ PortP->WflushFlag = 0;
+ PortP->MagicFlags = 0;
+ PortP->RxDataStart = 0;
+ PortP->TxBufferIn = 0;
+ PortP->TxBufferOut = 0;
+}
+
+/*
+** Put a command onto a port.
+** The PortPointer, command, length and arg are passed.
+** The len is the length *inclusive* of the command byte,
+** and so for a command that takes no data, len==1.
+** The arg is a single byte, and is only used if len==2.
+** Other values of len aren't allowed, and will cause
+** a panic.
+*/
+int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg)
+{
+ struct PKT __iomem *PacketP;
+ int retries = 20; /* at 10 per second -> 2 seconds */
+ unsigned long flags;
+
+ rio_dprintk(RIO_DEBUG_TTY, "entering shortcommand.\n");
+
+ if (PortP->State & RIO_DELETED) {
+ rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n");
+ return RIO_FAIL;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+ /*
+ ** If the port is in use for pre-emptive command, then wait for it to
+ ** be free again.
+ */
+ while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting for not in use (%d)\n", retries);
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (retries-- <= 0) {
+ return RIO_FAIL;
+ }
+ if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
+ return RIO_FAIL;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ }
+ if (PortP->State & RIO_DELETED) {
+ rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n");
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return RIO_FAIL;
+ }
+
+ while (!can_add_transmit(&PacketP, PortP) && !p->RIOHalted) {
+ rio_dprintk(RIO_DEBUG_TTY, "Waiting to add short command to queue (%d)\n", retries);
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ if (retries-- <= 0) {
+ rio_dprintk(RIO_DEBUG_TTY, "out of tries. Failing\n");
+ return RIO_FAIL;
+ }
+ if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
+ return RIO_FAIL;
+ }
+ rio_spin_lock_irqsave(&PortP->portSem, flags);
+ }
+
+ if (p->RIOHalted) {
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return RIO_FAIL;
+ }
+
+ /*
+ ** set the command byte and the argument byte
+ */
+ writeb(command, &PacketP->data[0]);
+
+ if (len == 2)
+ writeb(arg, &PacketP->data[1]);
+
+ /*
+ ** set the length of the packet and set the command bit.
+ */
+ writeb(PKT_CMD_BIT | len, &PacketP->len);
+
+ add_transmit(PortP);
+ /*
+ ** Count characters transmitted for port statistics reporting
+ */
+ if (PortP->statsGather)
+ PortP->txchars += len;
+
+ rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+ return p->RIOHalted ? RIO_FAIL : ~RIO_FAIL;
+}
+
+
diff --git a/drivers/char/rio/route.h b/drivers/char/rio/route.h
new file mode 100644
index 0000000..20ed73f
--- /dev/null
+++ b/drivers/char/rio/route.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+ ******* *******
+ ******* R O U T E H E A D E R
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra / Jeremy Rolls
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _route_h
+#define _route_h
+
+#define MAX_LINKS 4
+#define MAX_NODES 17 /* Maximum nodes in a subnet */
+#define NODE_BYTES ((MAX_NODES / 8) + 1) /* Number of bytes needed for
+ 1 bit per node */
+#define ROUTE_DATA_SIZE (NODE_BYTES + 2) /* Number of bytes for complete
+ info about cost etc. */
+#define ROUTES_PER_PACKET ((PKT_MAX_DATA_LEN -2)/ ROUTE_DATA_SIZE)
+ /* Number of nodes we can squeeze
+ into one packet */
+#define MAX_TOPOLOGY_PACKETS (MAX_NODES / ROUTES_PER_PACKET + 1)
+/************************************************
+ * Define the types of command for the ROUTE RUP.
+ ************************************************/
+#define ROUTE_REQUEST 0 /* Request an ID */
+#define ROUTE_FOAD 1 /* Kill the RTA */
+#define ROUTE_ALREADY 2 /* ID given already */
+#define ROUTE_USED 3 /* All ID's used */
+#define ROUTE_ALLOCATE 4 /* Here it is */
+#define ROUTE_REQ_TOP 5 /* I bet you didn't expect....
+ the Topological Inquisition */
+#define ROUTE_TOPOLOGY 6 /* Topology request answered FD */
+/*******************************************************************
+ * Define the Route Map Structure
+ *
+ * The route map gives a pointer to a Link Structure to use.
+ * This allows Disconnected Links to be checked quickly
+ ******************************************************************/
+typedef struct COST_ROUTE COST_ROUTE;
+struct COST_ROUTE {
+ unsigned char cost; /* Cost down this link */
+ unsigned char route[NODE_BYTES]; /* Nodes thorough this route */
+};
+
+typedef struct ROUTE_STR ROUTE_STR;
+struct ROUTE_STR {
+ COST_ROUTE cost_route[MAX_LINKS];
+ /* cost / route for this link */
+ ushort favoured; /* favoured link */
+};
+
+
+#define NO_LINK (short) 5 /* Link unattached */
+#define ROUTE_NO_ID (short) 100 /* No Id */
+#define ROUTE_DISCONNECT (ushort) 0xff /* Not connected */
+#define ROUTE_INTERCONNECT (ushort) 0x40 /* Sub-net interconnect */
+
+
+#define SYNC_RUP (ushort) 255
+#define COMMAND_RUP (ushort) 254
+#define ERROR_RUP (ushort) 253
+#define POLL_RUP (ushort) 252
+#define BOOT_RUP (ushort) 251
+#define ROUTE_RUP (ushort) 250
+#define STATUS_RUP (ushort) 249
+#define POWER_RUP (ushort) 248
+
+#define HIGHEST_RUP (ushort) 255 /* Set to Top one */
+#define LOWEST_RUP (ushort) 248 /* Set to bottom one */
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/rup.h b/drivers/char/rio/rup.h
new file mode 100644
index 0000000..4ae90cb
--- /dev/null
+++ b/drivers/char/rio/rup.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ ******* *******
+ ******* R U P S T R U C T U R E
+ ******* *******
+ ****************************************************************************
+
+ Author : Ian Nandhra
+ Date :
+
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Version : 0.01
+
+
+ Mods
+ ----------------------------------------------------------------------------
+ Date By Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rup_h
+#define _rup_h 1
+
+#define MAX_RUP ((short) 16)
+#define PKTS_PER_RUP ((short) 2) /* They are always used in pairs */
+
+/*************************************************
+ * Define all the packet request stuff
+ ************************************************/
+#define TX_RUP_INACTIVE 0 /* Nothing to transmit */
+#define TX_PACKET_READY 1 /* Transmit packet ready */
+#define TX_LOCK_RUP 2 /* Transmit side locked */
+
+#define RX_RUP_INACTIVE 0 /* Nothing received */
+#define RX_PACKET_READY 1 /* Packet received */
+
+#define RUP_NO_OWNER 0xff /* RUP not owned by any process */
+
+struct RUP {
+ u16 txpkt; /* Outgoing packet */
+ u16 rxpkt; /* Incoming packet */
+ u16 link; /* Which link to send down? */
+ u8 rup_dest_unit[2]; /* Destination unit */
+ u16 handshake; /* For handshaking */
+ u16 timeout; /* Timeout */
+ u16 status; /* Status */
+ u16 txcontrol; /* Transmit control */
+ u16 rxcontrol; /* Receive control */
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/char/rio/unixrup.h b/drivers/char/rio/unixrup.h
new file mode 100644
index 0000000..7abf0cb
--- /dev/null
+++ b/drivers/char/rio/unixrup.h
@@ -0,0 +1,51 @@
+/*
+** -----------------------------------------------------------------------------
+**
+** Perle Specialix driver for Linux
+** Ported from existing RIO Driver for SCO sources.
+ *
+ * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** Module : unixrup.h
+** SID : 1.2
+** Last Modified : 11/6/98 11:34:20
+** Retrieved : 11/6/98 11:34:22
+**
+** ident @(#)unixrup.h 1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_unixrup_h__
+#define __rio_unixrup_h__
+
+/*
+** UnixRup data structure. This contains pointers to actual RUPs on the
+** host card, and all the command/boot control stuff.
+*/
+struct UnixRup {
+ struct CmdBlk *CmdsWaitingP; /* Commands waiting to be done */
+ struct CmdBlk *CmdPendingP; /* The command currently being sent */
+ struct RUP __iomem *RupP; /* the Rup to send it to */
+ unsigned int Id; /* Id number */
+ unsigned int BaseSysPort; /* SysPort of first tty on this RTA */
+ unsigned int ModTypes; /* Modules on this RTA */
+ spinlock_t RupLock; /* Lock structure for MPX */
+ /* struct lockb RupLock; *//* Lock structure for MPX */
+};
+
+#endif /* __rio_unixrup_h__ */
OpenPOWER on IntegriCloud