diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-17 02:20:36 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-17 02:20:36 +0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/rio | |
download | linux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.xz |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/rio')
77 files changed, 21235 insertions, 0 deletions
diff --git a/drivers/char/rio/Makefile b/drivers/char/rio/Makefile new file mode 100644 index 000000000000..bce2bd1204ed --- /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 riopcicopy.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 000000000000..0b397e1c8f1c --- /dev/null +++ b/drivers/char/rio/board.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 : 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__ + +#ifdef SCCS_LABELS +static char *_board_h_sccs_ = "@(#)board.h 1.2"; +#endif + +/* +** 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 +{ + BYTE DpCtl; /* 7C00 */ + BYTE Dp_Unused2_[127]; + BYTE DpIntSet; /* 7C80 */ + BYTE Dp_Unused3_[127]; + BYTE DpTpuReset; /* 7D00 */ + BYTE Dp_Unused4_[127]; + BYTE DpIntReset; /* 7D80 */ + BYTE Dp_Unused5_[127]; +}; + +/* +** The PROM data area on the host (0x7C00), Read Only +*/ +struct s_Prom +{ + WORD DpSlxCode[2]; + WORD DpRev; + WORD Dp_Unused6_; + WORD DpUniq[4]; + WORD DpJahre; + WORD DpWoche; + WORD DpHwFeature[5]; + WORD DpOemId; + WORD 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 */ +{ + BYTE Dp_Unused8_[DP_PARMMAP_ADDR]; + WORD DpParmMapAd; +}; + +struct s_StartUpS +{ + BYTE Dp_Unused9_[DP_STARTUP_ADDR]; + BYTE Dp_LongJump[0x4]; + BYTE Dp_Unused10_[2]; + BYTE Dp_ShortJump[0x2]; +}; + +union u_Sram2ParmMap /* This is the top of memory (0x7E00-0x7FFF) */ +{ + BYTE DpSramMem[DP_SRAM2_SIZE]; + struct s_ParmMapS DpParmMapS; + struct s_StartUpS DpStartUpS; +}; + +/* +** This is the DP RAM overlay. +*/ +struct DpRam +{ + BYTE DpSram1[DP_SRAM1_SIZE]; /* 0000 - 7BFF */ + union u_CtrlProm DpCtrlProm; /* 7C00 - 7DFF */ + union u_Sram2ParmMap DpSram2ParmMap; /* 7E00 - 7FFF */ + BYTE DpScratch[DP_SCRATCH_SIZE]; /* 8000 - 8FFF */ + BYTE 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/bootpkt.h b/drivers/char/rio/bootpkt.h new file mode 100644 index 000000000000..c329aeb7c871 --- /dev/null +++ b/drivers/char/rio/bootpkt.h @@ -0,0 +1,62 @@ + + +/**************************************************************************** + ******* ******* + ******* B O O T P A C K E T H E A D E R F I L 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 _pkt_h +#define _pkt_h 1 + +#ifndef lint +#ifdef SCCS +static char *_rio_bootpkt_h_sccs = "@(#)bootpkt.h 1.1" ; +#endif +#endif + + /************************************************* + * Overlayed onto the Data fields of a regular + * Packet + ************************************************/ +typedef struct BOOT_PKT BOOT_PKT ; +struct BOOT_PKT { + short seq_num ; + char data[10] ; + } ; + + +#endif + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/brates.h b/drivers/char/rio/brates.h new file mode 100644 index 000000000000..bd4fc84ec6cf --- /dev/null +++ b/drivers/char/rio/brates.h @@ -0,0 +1,107 @@ +/**************************************************************************** + ******* ******* + ******* BRATES.H ******* + ******* ******* + **************************************************************************** + + Author : Jeremy Rolls + Date : 1 Nov 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 _brates_h +#ifndef lint +/* static char * _brates_h_sccs = "@(#)brates.h 1.4"; */ +#endif +#define _brates_h 1 +/* List of baud rate defines. Most are borrowed from /usr/include/sys/termio.h +*/ +#ifndef INKERNEL + +#define B0 0x00 +#define B50 0x01 +#define B75 0x02 +#define B110 0x03 +#define B134 0x04 +#define B150 0x05 +#define B200 0x06 +#define B300 0x07 +#define B600 0x08 +#define B1200 0x09 +#define B1800 0x0a +#define B2400 0x0b +#define B4800 0x0c +#define B9600 0x0d +#define B19200 0x0e +#define B38400 0x0f + +#endif + +/* +** The following baudrates may or may not be defined +** on various UNIX systems. +** If they are not then we define them. +** If they are then we do not define them ;-) +** +** This is appalling that we use same definitions as UNIX +** for our own download code as there is no garuntee that +** B57600 will be defined as 0x11 by a UNIX system.... +** Arghhhhh!!!!!!!!!!!!!! +*/ +#if !defined(B56000) +#define B56000 0x10 +#endif + +#if !defined(B57600) +#define B57600 0x11 +#endif + +#if !defined(B64000) +#define B64000 0x12 +#endif + +#if !defined(B115200) +#define B115200 0x13 +#endif + + +#if !defined(B2000) +#define B2000 0x14 +#endif + + +#define MAX_RATE B2000 + +struct baud_rate /* Tag for baud rates */ +{ + /* short host_rate,*/ /* As passed by the driver */ + short divisor, /* The divisor */ + prescaler; /* The pre-scaler */ +}; + +#endif diff --git a/drivers/char/rio/chan.h b/drivers/char/rio/chan.h new file mode 100644 index 000000000000..5b306543328f --- /dev/null +++ b/drivers/char/rio/chan.h @@ -0,0 +1,33 @@ +/* + * + * (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. +*/ +#ifndef _chan_h +#define _chan_h + +#ifndef lint +#ifdef SCCS +static char *_rio_chan_h_sccs = "@(#)chan.h 1.1" ; +#endif +#endif + +#define Link0 0 +#define Link1 1 +#define Link2 2 +#define Link3 3 + +#endif diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h new file mode 100644 index 000000000000..cf056a990f18 --- /dev/null +++ b/drivers/char/rio/cirrus.h @@ -0,0 +1,463 @@ +/**************************************************************************** + ******* ******* + ******* 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 +#ifndef lint +/* static char* _cirrus_h_sccs = "@(#)cirrus.h 1.16"; */ +#endif +#define _cirrus_h 1 + +#ifdef RTA +#define TO_UART RX +#define TO_DRIVER TX +#endif + +#ifdef HOST +#define TO_UART TX +#define TO_DRIVER RX +#endif +#ifdef RTA +/* Miscellaneous defines for CIRRUS addresses and related logic for + interrupts etc. +*/ +#define MAP(a) ((short *)(cirrus_base + (a))) +#define outp(a,b) (*MAP (a) =(b)) +#define inp(a) ((*MAP (a)) & 0xff) +#define CIRRUS_FIRST (short*)0x7300 +#define CIRRUS_SECOND (short*)0x7200 +#define CIRRUS_THIRD (short*)0x7100 +#define CIRRUS_FOURTH (short*)0x7000 +#define PORTS_ON_CIRRUS 4 +#define CIRRUS_FIFO_SIZE 12 +#define SPACE 0x20 +#define TAB 0x09 +#define LINE_FEED 0x0a +#define CARRIAGE_RETURN 0x0d +#define BACKSPACE 0x08 +#define SPACES_IN_TABS 8 +#define SEND_ESCAPE 0x00 +#define START_BREAK 0x81 +#define TIMER_TICK 0x82 +#define STOP_BREAK 0x83 +#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH))) +#define txack1 ((short *)0x7104) +#define rxack1 ((short *)0x7102) +#define mdack1 ((short *)0x7106) +#define txack2 ((short *)0x7006) +#define rxack2 ((short *)0x7004) +#define mdack2 ((short *)0x7100) +#define int_latch ((short *) 0x7800) +#define int_status ((short *) 0x7c00) +#define tx1_pending 0x20 +#define rx1_pending 0x10 +#define md1_pending 0x40 +#define tx2_pending 0x02 +#define rx2_pending 0x01 +#define md2_pending 0x40 +#define module1_bits 0x07 +#define module1_modern 0x08 +#define module2_bits 0x70 +#define module2_modern 0x80 +#define module_blank 0xf +#define rs232_d25 0x0 +#define rs232_rj45 0x1 +#define rs422_d25 0x3 +#define parallel 0x5 + +#define CLK0 0x00 +#define CLK1 0x01 +#define CLK2 0x02 +#define CLK3 0x03 +#define CLK4 0x04 + +#define CIRRUS_REVC 0x42 +#define CIRRUS_REVE 0x44 + +#define TURNON 1 +#define TURNOFF 0 + +/* The list of CIRRUS registers. + NB. These registers are relative values on 8 bit boundaries whereas + on the RTA's the CIRRUS registers are on word boundaries. Use pointer + arithmetic (short *) to obtain the real addresses required */ +#define ccr 0x05 /* Channel Command Register */ +#define ier 0x06 /* Interrupt Enable Register */ +#define cor1 0x08 /* Channel Option Register 1 */ +#define cor2 0x09 /* Channel Option Register 2 */ +#define cor3 0x0a /* Channel Option Register 3 */ +#define cor4 0x1e /* Channel Option Register 4 */ +#define cor5 0x1f /* Channel Option Register 5 */ + +#define ccsr 0x0b /* Channel Control Status Register */ +#define rdcr 0x0e /* Receive Data Count Register */ +#define tdcr 0x12 /* Transmit Data Count Register */ +#define mcor1 0x15 /* Modem Change Option Register 1 */ +#define mcor2 0x16 /* Modem Change Option Regsiter 2 */ + +#define livr 0x18 /* Local Interrupt Vector Register */ +#define schr1 0x1a /* Special Character Register 1 */ +#define schr2 0x1b /* Special Character Register 2 */ +#define schr3 0x1c /* Special Character Register 3 */ +#define schr4 0x1d /* Special Character Register 4 */ + +#define rtr 0x20 /* Receive Timer Register */ +#define rtpr 0x21 /* Receive Timeout Period Register */ +#define lnc 0x24 /* Lnext character */ + +#define rivr 0x43 /* Receive Interrupt Vector Register */ +#define tivr 0x42 /* Transmit Interrupt Vector Register */ +#define mivr 0x41 /* Modem Interrupt Vector Register */ +#define gfrcr 0x40 /* Global Firmware Revision code Reg */ +#define ricr 0x44 /* Receive Interrupting Channel Reg */ +#define ticr 0x45 /* Transmit Interrupting Channel Reg */ +#define micr 0x46 /* Modem Interrupting Channel Register */ + +#define gcr 0x4b /* Global configuration register*/ +#define misr 0x4c /* Modem interrupt status register */ + +#define rbusr 0x59 +#define tbusr 0x5a +#define mbusr 0x5b + +#define eoir 0x60 /* End Of Interrupt Register */ +#define rdsr 0x62 /* Receive Data / Status Register */ +#define tdr 0x63 /* Transmit Data Register */ +#define svrr 0x67 /* Service Request Register */ + +#define car 0x68 /* Channel Access Register */ +#define mir 0x69 /* Modem Interrupt Register */ +#define tir 0x6a /* Transmit Interrupt Register */ +#define rir 0x6b /* Receive Interrupt Register */ +#define msvr1 0x6c /* Modem Signal Value Register 1 */ +#define msvr2 0x6d /* Modem Signal Value Register 2*/ +#define psvr 0x6f /* Printer Signal Value Register*/ + +#define tbpr 0x72 /* Transmit Baud Rate Period Register */ +#define tcor 0x76 /* Transmit Clock Option Register */ + +#define rbpr 0x78 /* Receive Baud Rate Period Register */ +#define rber 0x7a /* Receive Baud Rate Extension Register */ +#define rcor 0x7c /* Receive Clock Option Register*/ +#define ppr 0x7e /* Prescalar Period Register */ + +/* Misc registers used for forcing the 1400 out of its reset woes */ +#define airl 0x6d +#define airm 0x6e +#define airh 0x6f +#define btcr 0x66 +#define mtcr 0x6c +#define tber 0x74 + +#endif /* #ifdef RTA */ + + +/* Bit fields for particular registers */ + +/* GCR */ +#define GCR_SERIAL 0x00 /* Configure as serial channel */ +#define GCR_PARALLEL 0x80 /* Configure as parallel channel */ + +/* RDSR - when status read from FIFO */ +#define RDSR_BREAK 0x08 /* Break received */ +#define RDSR_TIMEOUT 0x80 /* No new data timeout */ +#define RDSR_SC1 0x10 /* Special char 1 (tx XON) matched */ +#define RDSR_SC2 0x20 /* Special char 2 (tx XOFF) matched */ +#define RDSR_SC12_MASK 0x30 /* Mask for special chars 1 and 2 */ + +/* PPR */ +#define PPR_DEFAULT 0x31 /* Default value - for a 25Mhz clock gives + a timeout period of 1ms */ + +/* LIVR */ +#define LIVR_EXCEPTION 0x07 /* Receive exception interrupt */ + +/* CCR */ +#define CCR_RESET 0x80 /* Reset channel */ +#define CCR_CHANGE 0x4e /* COR's have changed - NB always change all + COR's */ +#define CCR_WFLUSH 0x82 /* Flush transmit FIFO and TSR / THR */ + +#define CCR_SENDSC1 0x21 /* Send special character one */ +#define CCR_SENDSC2 0x22 /* Send special character two */ +#define CCR_SENDSC3 0x23 /* Send special character three */ +#define CCR_SENDSC4 0x24 /* Send special character four */ + +#define CCR_TENABLE 0x18 /* Enable transmitter */ +#define CCR_TDISABLE 0x14 /* Disable transmitter */ +#define CCR_RENABLE 0x12 /* Enable receiver */ +#define CCR_RDISABLE 0x11 /* Disable receiver */ + +#define CCR_READY 0x00 /* CCR is ready for another command */ + +/* CCSR */ +#define CCSR_TXENABLE 0x08 /* Transmitter enable */ +#define CCSR_RXENABLE 0x80 /* Receiver enable */ +#define CCSR_TXFLOWOFF 0x04 /* Transmit flow off */ +#define CCSR_TXFLOWON 0x02 /* Transmit flow on */ + +/* SVRR */ +#define SVRR_RECEIVE 0x01 /* Receive interrupt pending */ +#define SVRR_TRANSMIT 0x02 /* Transmit interrupt pending */ +#define SVRR_MODEM 0x04 /* Modem interrupt pending */ + +/* CAR */ +#define CAR_PORTS 0x03 /* Bit fields for ports */ + +/* IER */ +#define IER_MODEM 0x80 /* Change in modem status */ +#define IER_RECEIVE 0x10 /* Good data / data exception */ +#define IER_TRANSMITR 0x04 /* Transmit ready (FIFO empty) */ +#define IER_TRANSMITE 0x02 /* Transmit empty */ +#define IER_TIMEOUT 0x01 /* Timeout on no data */ + +#define IER_DEFAULT 0x94 /* Default values */ +#define IER_PARALLEL 0x84 /* Default for Parallel */ +#define IER_EMPTY 0x92 /* Transmitter empty rather than ready */ + +/* COR1 - Driver only */ +#define COR1_INPCK 0x10 /* Check parity of received characters */ + +/* COR1 - driver and RTA */ +#define COR1_ODD 0x80 /* Odd parity */ +#define COR1_EVEN 0x00 /* Even parity */ +#define COR1_NOP 0x00 /* No parity */ +#define COR1_FORCE 0x20 /* Force parity */ +#define COR1_NORMAL 0x40 /* With parity */ +#define COR1_1STOP 0x00 /* 1 stop bit */ +#define COR1_15STOP 0x04 /* 1.5 stop bits */ +#define COR1_2STOP 0x08 /* 2 stop bits */ +#define COR1_5BITS 0x00 /* 5 data bits */ +#define COR1_6BITS 0x01 /* 6 data bits */ +#define COR1_7BITS 0x02 /* 7 data bits */ +#define COR1_8BITS 0x03 /* 8 data bits */ + +#define COR1_HOST 0xef /* Safe host bits */ + +/* RTA only */ +#define COR1_CINPCK 0x00 /* Check parity of received characters */ +#define COR1_CNINPCK 0x10 /* Don't check parity */ + +/* COR2 bits for both RTA and driver use */ +#define COR2_IXANY 0x80 /* IXANY - any character is XON */ +#define COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */ +#define COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */ + +/* Additional driver bits */ +#define COR2_HUPCL 0x20 /* Hang up on close */ +#define COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */ +#define COR2_IXOFF 0x01 /* Enable rx software flow control */ +#define COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */ + +/* RTA use only */ +#define COR2_ETC 0x20 /* Embedded transmit options */ +#define COR2_LOCAL 0x10 /* Local loopback mode */ +#define COR2_REMOTE 0x08 /* Remote loopback mode */ +#define COR2_HOST 0xc2 /* Safe host bits */ + +/* COR3 - RTA use only */ +#define COR3_SCDRNG 0x80 /* Enable special char detect for range */ +#define COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */ +#define COR3_FCT 0x20 /* Flow control transparency */ +#define COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */ +#define COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */ +#define COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */ +#define COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */ +#define COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */ + +#define COR3_THRESHOLD COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */ + +#define COR3_DEFAULT (COR3_FCT | COR3_THRESHOLD) + /* Default bits for COR3 */ + +/* COR4 driver and RTA use */ +#define COR4_IGNCR 0x80 /* Throw away CR's on input */ +#define COR4_ICRNL 0x40 /* Map CR -> NL on input */ +#define COR4_INLCR 0x20 /* Map NL -> CR on input */ +#define COR4_IGNBRK 0x10 /* Ignore Break */ +#define COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */ +#define COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */ + + +/* COR4 driver only */ +#define COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */ +#define COR4_PARMRK 0x02 /* PARMRK */ + +#define COR4_HOST 0xf8 /* Safe host bits */ + +/* COR4 RTA only */ +#define COR4_CIGNPAR 0x02 /* Thrown away bad characters */ +#define COR4_CPARMRK 0x04 /* PARMRK characters */ +#define COR4_CNPARMRK 0x03 /* Don't PARMRK */ + +/* COR5 driver and RTA use */ +#define COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */ +#define COR5_LNE 0x40 /* Enable LNEXT processing */ +#define COR5_CMOE 0x20 /* Match good and errored characters */ +#define COR5_ONLCR 0x02 /* NL -> CR NL on output */ +#define 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 COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */ +#define COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */ +/* +** TAB3 +*/ +#define COR5_TAB3 0x10 /* TAB3 mode */ + +#define COR5_HOST 0xc3 /* Safe host bits */ + +/* CCSR */ +#define 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 MSVR1_CD 0x80 /* CD (DSR on Cirrus) */ +#define MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */ +#define MSVR1_RI 0x20 /* RI */ +#define MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */ +#define MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */ +/* Next two used to indicate state of tbusy and tstop to driver */ +#define MSVR1_TSTOP 0x08 /* Set if port flow controlled */ +#define MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */ + +#define MSVR1_HOST 0xf3 /* The bits the host wants */ + +/* MSVR2 */ +#define MSVR2_DSR 0x02 /* DSR output pin (DTR on Cirrus) */ + +/* MCOR */ +#define MCOR_CD 0x80 /* CD (DSR on Cirrus) */ +#define MCOR_RTS 0x40 /* RTS (CTS on Cirrus) */ +#define MCOR_RI 0x20 /* RI */ +#define MCOR_DTR 0x10 /* DTR (CD on Cirrus) */ + +#define MCOR_DEFAULT (MCOR_CD | MCOR_RTS | MCOR_RI | MCOR_DTR) +#define MCOR_FULLMODEM MCOR_DEFAULT +#define MCOR_RJ45 (MCOR_CD | MCOR_RTS | MCOR_DTR) +#define MCOR_RESTRICTED (MCOR_CD | MCOR_RTS) + +/* More MCOR - H/W Handshake (flowcontrol) stuff */ +#define MCOR_THRESH8 0x08 /* eight characters then we stop */ +#define MCOR_THRESH9 0x09 /* nine characters then we stop */ +#define MCOR_THRESH10 0x0A /* ten characters then we stop */ +#define MCOR_THRESH11 0x0B /* eleven characters then we stop */ + +#define MCOR_THRESHBITS 0x0F /* mask for ANDing out the above */ + +#define MCOR_THRESHOLD MCOR_THRESH9 /* MUST BE GREATER THAN COR3_THRESHOLD */ + + +/* RTPR */ +#define RTPR_DEFAULT 0x02 /* Default */ + + +/* Defines for the subscripts of a CONFIG packet */ +#define CONFIG_COR1 1 /* Option register 1 */ +#define CONFIG_COR2 2 /* Option register 2 */ +#define CONFIG_COR4 3 /* Option register 4 */ +#define CONFIG_COR5 4 /* Option register 5 */ +#define CONFIG_TXXON 5 /* Tx XON character */ +#define CONFIG_TXXOFF 6 /* Tx XOFF character */ +#define CONFIG_RXXON 7 /* Rx XON character */ +#define CONFIG_RXXOFF 8 /* Rx XOFF character */ +#define CONFIG_LNEXT 9 /* LNEXT character */ +#define CONFIG_TXBAUD 10 /* Tx baud rate */ +#define CONFIG_RXBAUD 11 /* Rx baud rate */ + +/* Port status stuff */ +#define IDLE_CLOSED 0 /* Closed */ +#define IDLE_OPEN 1 /* Idle open */ +#define IDLE_BREAK 2 /* Idle on break */ + +/* Subscript of MODEM STATUS packet */ +#define MODEM_VALUE 3 /* Current values of handshake pins */ +/* Subscript of SBREAK packet */ +#define BREAK_LENGTH 1 /* Length of a break in slices of 0.01 seconds + 0 = stay on break until an EBREAK command + is sent */ + + +#define 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 OPEN 0x00 /* Open a port */ +#define CONFIG 0x01 /* Configure a port */ +#define MOPEN 0x02 /* Modem open (block for DCD) */ +#define CLOSE 0x03 /* Close a port */ +#define WFLUSH (0x04 | PRE_EMPTIVE) /* Write flush */ +#define RFLUSH (0x05 | PRE_EMPTIVE) /* Read flush */ +#define RESUME (0x06 | PRE_EMPTIVE) /* Resume if xoffed */ +#define SBREAK 0x07 /* Start break */ +#define EBREAK 0x08 /* End break */ +#define SUSPEND (0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */ +#define FCLOSE (0x0a | PRE_EMPTIVE) /* Force close */ +#define XPRINT 0x0b /* Xprint packet */ +#define MBIS (0x0c | PRE_EMPTIVE) /* Set modem lines */ +#define MBIC (0x0d | PRE_EMPTIVE) /* Clear modem lines */ +#define MSET (0x0e | PRE_EMPTIVE) /* Set modem lines */ +#define PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */ +#define MGET (0x10 | PRE_EMPTIVE) /* Force update of modem status */ +#define MEMDUMP (0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */ +#define READ_REGISTER (0x12 | 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 COMPLETE (0x20 | PRE_EMPTIVE) + /* Command complete */ +#define BREAK_RECEIVED (0x21 | PRE_EMPTIVE) + /* Break received */ +#define MODEM_STATUS (0x22 | PRE_EMPTIVE) + /* Change in modem status */ + +/* "Command" packet that could go either way - handshake wake-up */ +#define HANDSHAKE (0x23 | PRE_EMPTIVE) + /* Wake-up to HOST / RTA */ + +#endif diff --git a/drivers/char/rio/cmd.h b/drivers/char/rio/cmd.h new file mode 100644 index 000000000000..c369edaea2b3 --- /dev/null +++ b/drivers/char/rio/cmd.h @@ -0,0 +1,84 @@ + + +/**************************************************************************** + ******* ******* + ******* C O M M A N D P A C K E T H E A D E R S + ******* ******* + **************************************************************************** + + 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 _cmd_h +#define _cmd_h + +#ifndef lint +#ifdef SCCS +static char *_rio_cmd_h_sccs = "@(#)cmd.h 1.1" ; +#endif +#endif + + +#define PRE_EMPTIVE_CMD 0x80 +#define INLINE_CMD ~PRE_EMPTIVE_CMD + +#define CMD_IGNORE_PKT ( (ushort) 0) +#define CMD_STATUS_REQ ( (ushort) 1) +#define CMD_UNIT_STATUS_REQ ( (ushort) 2) /* Is this needed ??? */ +#define CMD_CONF_PORT ( (ushort) 3) +#define CMD_CONF_UNIT ( (ushort) 4) +#define CMD_ROUTE_MAP_REQ ( (ushort) 5) +#define CMD_FLUSH_TX ( (ushort) 6) +#define CMD_FLUSH_RX ( (ushort) 7) +#define CMD_PARTION_PORT ( (ushort) 8) +#define CMD_RESET_PORT ( (ushort) 0x0a) +#define CMD_BOOT_UNIT ( (ushort) 0x0b) +#define CMD_FOUND_UNIT ( (ushort) 0x0c) +#define CMD_ATTACHED_RTA_2 ( (ushort) 0x0d) +#define CMD_PROVIDE_BOOT ( (ushort) 0x0e) +#define CMD_CIRRUS ( (ushort) 0x0f) + +#define FORM_STATUS_PKT ( (ushort) 1 ) +#define FORM_POLL_PKT ( (ushort) 2 ) +#define FORM_LINK_STATUS_PKT ( (ushort) 3 ) + + +#define CMD_DATA_PORT ( (ushort) 1 ) +#define CMD_DATA ( (ushort) 2 ) + +#define CMD_TX_PART ( (ushort) 2 ) +#define CMD_RX_PART ( (ushort) 3 ) +#define CMD_RX_LIMIT ( (ushort) 4 ) + +#endif + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/cmdblk.h b/drivers/char/rio/cmdblk.h new file mode 100644 index 000000000000..2b8efbdbee1c --- /dev/null +++ b/drivers/char/rio/cmdblk.h @@ -0,0 +1,60 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +#ifndef lint +static char *_cmdblk_h_sccs_ = "@(#)cmdblk.h 1.2"; +#endif +#endif + +/* +** 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)(int, struct CmdBlk *); + int PreArg; /* The arg for the func */ + /* The func to call when completed */ + int (*PostFuncP)(int, 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 000000000000..46befd354f20 --- /dev/null +++ b/drivers/char/rio/cmdpkt.h @@ -0,0 +1,206 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +#ifndef lint +static char *_cmdpkt_h_sccs_ = "@(#)cmdpkt.h 1.2"; +#endif +#endif + +/* +** 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 +{ + WORD NumPackets; + WORD LoadBase; + WORD CodeSize; +}; + +#define BOOT_SEQUENCE_LEN 8 + +struct SamTop +{ + BYTE Unit; + BYTE Link; +}; + +struct CmdHdr +{ + BYTE PcCommand; + union + { + BYTE PcPhbNum; + BYTE PcLinkNum; + BYTE PcIDNum; + } U0; +}; + + +struct PktCmd +{ + union + { + struct + { + struct CmdHdr CmdHdr; + struct BootSequence PcBootSequence; + } S1; + struct + { + WORD PcSequence; + BYTE PcBootData[RTA_BOOT_DATA_SIZE]; + } S2; + struct + { + WORD __crud__; + BYTE PcUniqNum[4]; /* this is really a uint. */ + BYTE PcModuleTypes; /* what modules are fitted */ + } S3; + struct + { + struct CmdHdr CmdHdr; + BYTE __undefined__; + BYTE PcModemStatus; + BYTE PcPortStatus; + BYTE PcSubCommand; /* commands like mem or register dump */ + WORD PcSubAddr; /* Address for command */ + BYTE PcSubData[64]; /* Date area for command */ + } S4; + struct + { + struct CmdHdr CmdHdr; + BYTE PcCommandText[1]; + BYTE __crud__[20]; + BYTE 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 + { + uchar PcCommand; + union + { + uchar PcPhbNum; + uchar PcLinkNum; + uchar PcIDNum; + } U0; + } CmdHdr; + struct + { + ushort NumPackets; + ushort LoadBase; + ushort CodeSize; + } PcBootSequence; + } S1; + struct + { + ushort PcSequence; + uchar PcBootData[RTA_BOOT_DATA_SIZE]; + } S2; + struct + { + ushort __crud__; + uchar PcUniqNum[4]; /* this is really a uint. */ + uchar PcModuleTypes; /* what modules are fitted */ + } S3; + struct + { + ushort __cmd_hdr__; + uchar __undefined__; + uchar PcModemStatus; + uchar PcPortStatus; + uchar PcSubCommand; + ushort PcSubAddr; + uchar PcSubData[64]; + } S4; + struct + { + ushort __cmd_hdr__; + uchar PcCommandText[1]; + uchar __crud__[20]; + uchar PcIDNum2; /* Tacked on end */ + } S5; + struct + { + ushort __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/control.h b/drivers/char/rio/control.h new file mode 100644 index 000000000000..1712f6261dd1 --- /dev/null +++ b/drivers/char/rio/control.h @@ -0,0 +1,62 @@ + + +/**************************************************************************** + ******* ******* + ******* C O N T R O L P A C K E T H E A D E R S + ******* ******* + **************************************************************************** + + Author : Jon Brawn + 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 _control_h +#define _control_h + +#ifndef lint +/* static char *_rio_control_h_sccs = "@(#)control.h 1.4"; */ +#endif + +#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 */ + +#endif + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/daemon.h b/drivers/char/rio/daemon.h new file mode 100644 index 000000000000..62dba0e68b3e --- /dev/null +++ b/drivers/char/rio/daemon.h @@ -0,0 +1,334 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +#ifndef lint +static char *_daemon_h_sccs_ = "@(#)daemon.h 1.3"; +#endif +#endif + + +/* +** structures used on /dev/rio +*/ + +struct Error +{ + uint Error; + uint Entry; + uint Other; +}; + +struct DownLoad +{ + char *DataP; + uint Count; + uint 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 +{ + uint From; /* Set/Clear XP & IXANY Control from this port.... */ + uint To; /* .... to this port */ + uint 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 */ + uchar IxAny; /* enable/disable IXANY */ + uchar IxOn; /* enable/disable IXON */ + uchar Lock; /* lock port params */ + uchar Store; /* store params across closes */ + uchar Drain; /* close only when drained */ +}; + +struct LpbReq +{ + uint Host; + uint Link; + struct LPB *LpbP; +}; + +struct RupReq +{ + uint HostNum; + uint RupNum; + struct RUP *RupP; +}; + +struct PortReq +{ + uint SysPort; + struct Port *PortP; +}; + +struct StreamInfo +{ + uint SysPort; +#if 0 + queue_t RQueue; + queue_t WQueue; +#else + int RQueue; + int WQueue; +#endif +}; + +struct HostReq +{ + uint HostNum; + struct Host *HostP; +}; + +struct HostDpRam +{ + uint HostNum; + struct DpRam *DpRamP; +}; + +struct DebugCtrl +{ + uint SysPort; + uint Debug; + uint Wait; +}; + +struct MapInfo +{ + uint FirstPort; /* 8 ports, starting from this (tty) number */ + uint RtaUnique; /* reside on this RTA (unique number) */ +}; + +struct MapIn +{ + uint 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 +{ + ulong RtaUnique; + uchar ID; +}; + +struct KillNeighbour +{ + ulong UniqueNum; + uchar 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/data.h b/drivers/char/rio/data.h new file mode 100644 index 000000000000..dabc2d1fa40f --- /dev/null +++ b/drivers/char/rio/data.h @@ -0,0 +1,40 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : data.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:09 +** Retrieved : 11/6/98 11:34:21 +** +** ident @(#)data.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_datadex__ +#define __rio_datadex__ + +#ifndef lint +static char *_data_h_sccs_ = "@(#)data.h 1.2"; +#endif + +#endif diff --git a/drivers/char/rio/debug.h b/drivers/char/rio/debug.h new file mode 100644 index 000000000000..b6e0d0935552 --- /dev/null +++ b/drivers/char/rio/debug.h @@ -0,0 +1,39 @@ +/* +** File: debug.h +** +** Author: David Dix +** +** Created: 12th March 1993 +** +** Last modified: 93/04/27 +** + * + * (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. +*/ + +#ifndef _debug_h_ +#define _debug_h_ + + +#if defined(DCIRRUS) +#define DBPACKET(pkt, opt, str, chn) debug_packet((pkt), (opt), (str), (chn)) +#else +#define DBPACKET(pkt, opt, str, c) +#endif /* DCIRRUS */ + + +#endif /* _debug_h_ */ diff --git a/drivers/char/rio/defaults.h b/drivers/char/rio/defaults.h new file mode 100644 index 000000000000..2e7309e27622 --- /dev/null +++ b/drivers/char/rio/defaults.h @@ -0,0 +1,59 @@ + +/**************************************************************************** + ******* ******* + ******* D E F A U L T S + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS +static char *_rio_defaults_h_sccs = "@(#)defaults.h 1.1" ; +#endif +#endif + + +#define MILLISECOND (int) (1000/64) /* 15.625 low ticks */ +#define SECOND (int) 15625 /* Low priority ticks */ + +#ifdef RTA +#define RX_LIMIT (ushort) 3 +#endif +#ifdef HOST +#define RX_LIMIT (ushort) 1 +#endif + +#define LINK_TIMEOUT (int) (POLL_PERIOD / 2) + + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/eisa.h b/drivers/char/rio/eisa.h new file mode 100644 index 000000000000..59371b0528b0 --- /dev/null +++ b/drivers/char/rio/eisa.h @@ -0,0 +1,104 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : eisa.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:10 +** Retrieved : 11/6/98 11:34:21 +** +** ident @(#)eisa.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_eisa_h__ +#define __rio_eisa_h__ + +#ifdef SCCS_LABELS +#ifndef lint +static char *_eisa_h_sccs_ = "@(#)eisa.h 1.2"; +#endif +#endif + +/* +** things to do with the EISA bus +*/ + +#define RIO_EISA_STRING_ADDRESS 0xfffd9 /* where EISA is stored */ + +#define RIO_MAX_EISA_SLOTS 16 /* how many EISA slots? */ + +#define RIO_EISA_IDENT 0x984D /* Specialix */ +#define RIO_EISA_PRODUCT_CODE 0x14 /* Code 14 */ +#define RIO_EISA_ENABLE_BIT 0x01 /* To enable card */ + +#define EISA_MEMORY_BASE_LO 0xC00 /* A16-A23 */ +#define EISA_MEMORY_BASE_HI 0xC01 /* A24-A31 */ +#define EISA_INTERRUPT_VEC 0xC02 /* see below */ +#define EISA_CONTROL_PORT 0xC02 /* see below */ +#define EISA_INTERRUPT_RESET 0xC03 /* read to clear IRQ */ + +#define EISA_PRODUCT_IDENT_LO 0xC80 /* where RIO_EISA_IDENT is */ +#define EISA_PRODUCT_IDENT_HI 0xC81 +#define EISA_PRODUCT_NUMBER 0xC82 /* where PROD_CODE is */ +#define EISA_REVISION_NUMBER 0xC83 /* revision (1dp) */ +#define EISA_ENABLE 0xC84 /* set LSB to enable card */ +#define EISA_UNIQUE_NUM_0 0xC88 /* vomit */ +#define EISA_UNIQUE_NUM_1 0xC8A +#define EISA_UNIQUE_NUM_2 0xC90 /* bit strangely arranged */ +#define EISA_UNIQUE_NUM_3 0xC92 +#define EISA_MANUF_YEAR 0xC98 /* when */ +#define EISA_MANUF_WEEK 0xC9A /* more when */ + +#define EISA_TP_BOOT_FROM_RAM 0x01 +#define EISA_TP_BOOT_FROM_LINK 0x00 +#define EISA_TP_FAST_LINKS 0x02 +#define EISA_TP_SLOW_LINKS 0x00 +#define EISA_TP_BUS_ENABLE 0x04 +#define EISA_TP_BUS_DISABLE 0x00 +#define EISA_TP_RUN 0x08 +#define EISA_TP_RESET 0x00 +#define EISA_POLLED 0x00 +#define EISA_IRQ_3 0x30 +#define EISA_IRQ_4 0x40 +#define EISA_IRQ_5 0x50 +#define EISA_IRQ_6 0x60 +#define EISA_IRQ_7 0x70 +#define EISA_IRQ_9 0x90 +#define EISA_IRQ_10 0xA0 +#define EISA_IRQ_11 0xB0 +#define EISA_IRQ_12 0xC0 +#define EISA_IRQ_14 0xE0 +#define EISA_IRQ_15 0xF0 + +#define EISA_INTERRUPT_MASK 0xF0 +#define EISA_CONTROL_MASK 0x0F + +#define RIO_EISA_DEFAULT_MODE EISA_TP_SLOW_LINKS + +#define RIOEisaToIvec(X) (uchar )((uchar)((X) & EISA_INTERRUPT_MASK)>>4) + +#define INBZ(z,x) inb(((z)<<12) | (x)) +#define OUTBZ(z,x,y) outb((((z)<<12) | (x)), y) + +#endif /* __rio_eisa_h__ */ diff --git a/drivers/char/rio/enable.h b/drivers/char/rio/enable.h new file mode 100644 index 000000000000..8e9a419e15b0 --- /dev/null +++ b/drivers/char/rio/enable.h @@ -0,0 +1,50 @@ +/**************************************************************************** + ******* ******* + ******* E N A B L E H E A D E R S + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS +static char *_rio_enable_h_sccs = "@(#)enable.h 1.1" ; +#endif +#endif + + +#define ENABLE_LTT TRUE +#define ENABLE_LRT TRUE + + +/*********** end of file ***********/ + + diff --git a/drivers/char/rio/error.h b/drivers/char/rio/error.h new file mode 100644 index 000000000000..229438e355f2 --- /dev/null +++ b/drivers/char/rio/error.h @@ -0,0 +1,85 @@ + +/**************************************************************************** + ******* ******* + ******* E R R O R H E A D E R F I L 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 lint +/* static char *_rio_error_h_sccs = "@(#)error.h 1.3"; */ +#endif + +#define E_NO_ERROR ((ushort) 0) +#define E_PROCESS_NOT_INIT ((ushort) 1) +#define E_LINK_TIMEOUT ((ushort) 2) +#define E_NO_ROUTE ((ushort) 3) +#define E_CONFUSED ((ushort) 4) +#define E_HOME ((ushort) 5) +#define E_CSUM_FAIL ((ushort) 6) +#define E_DISCONNECTED ((ushort) 7) +#define E_BAD_RUP ((ushort) 8) +#define E_NO_VIRGIN ((ushort) 9) +#define E_BOOT_RUP_BUSY ((ushort) 10) + + + + /************************************************* + * Parsed to mem_halt() + ************************************************/ +#define E_CHANALLOC ((ushort) 0x80) +#define E_POLL_ALLOC ((ushort) 0x81) +#define E_LTTWAKE ((ushort) 0x82) +#define E_LTT_ALLOC ((ushort) 0x83) +#define E_LRT_ALLOC ((ushort) 0x84) +#define E_CIRRUS ((ushort) 0x85) +#define E_MONITOR ((ushort) 0x86) +#define E_PHB_ALLOC ((ushort) 0x87) +#define E_ARRAY_ALLOC ((ushort) 0x88) +#define E_QBUF_ALLOC ((ushort) 0x89) +#define E_PKT_ALLOC ((ushort) 0x8a) +#define E_GET_TX_Q_BUF ((ushort) 0x8b) +#define E_GET_RX_Q_BUF ((ushort) 0x8c) +#define E_MEM_OUT ((ushort) 0x8d) +#define E_MMU_INIT ((ushort) 0x8e) +#define E_LTT_INIT ((ushort) 0x8f) +#define E_LRT_INIT ((ushort) 0x90) +#define E_LINK_RUN ((ushort) 0x91) +#define E_MONITOR_ALLOC ((ushort) 0x92) +#define E_MONITOR_INIT ((ushort) 0x93) +#define E_POLL_INIT ((ushort) 0x94) + + +/*********** end of file ***********/ + + + diff --git a/drivers/char/rio/errors.h b/drivers/char/rio/errors.h new file mode 100644 index 000000000000..f920b9f3e2bd --- /dev/null +++ b/drivers/char/rio/errors.h @@ -0,0 +1,104 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +#ifndef lint +static char *_errors_h_sccs_ = "@(#)errors.h 1.2"; +#endif +#endif + +/* +** 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/formpkt.h b/drivers/char/rio/formpkt.h new file mode 100644 index 000000000000..a8b65ae0de90 --- /dev/null +++ b/drivers/char/rio/formpkt.h @@ -0,0 +1,154 @@ + + +/**************************************************************************** + ******* ******* + ******* F O R M P A C K E T H E A D E R F I L 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 _formpkt_h +#define _formpkt_h 1 + +#ifndef lint +#ifdef SCCS +static char *_rio_formpkt_h_sccs = "@(#)formpkt.h 1.1" ; +#endif +#endif + +typedef struct FORM_BOOT_PKT_1 FORM_BOOT_PKT_1 ; +struct FORM_BOOT_PKT_1 { + ushort pkt_number ; + ushort pkt_total ; + ushort boot_top ; + } ; + +typedef struct FORM_BOOT_PKT_2 FORM_BOOT_PKT_2 ; +struct FORM_BOOT_PKT_2 { + ushort pkt_number ; + char boot_data[10] ; + } ; + + +typedef struct FORM_ATTACH_RTA FORM_ATTACH_RTA ; +struct FORM_ATTACH_RTA { + char cmd_code ; + char booter_serial[4] ; + char booter_link ; + char bootee_serial[4] ; + char bootee_link ; + } ; + + +typedef struct FORM_BOOT_ID FORM_BOOT_ID ; +struct FORM_BOOT_ID { + char cmd_code ; + char bootee_serial[4] ; + char bootee_prod_id ; + char bootee_link ; + } ; + + + +typedef struct FORM_ROUTE_1 FORM_ROUTE_1 ; +struct FORM_ROUTE_1 { + char cmd_code ; + char pkt_number ; + char total_in_sequence ; + char unit_id ; + char host_unit_id ; + } ; + +typedef struct FORM_ROUTE_2 FORM_ROUTE_2 ; +struct FORM_ROUTE_2 { + char cmd_code ; + char pkt_number ; + char total_in_sequence ; + char route_data[9] ; + } ; + +typedef struct FORM_ROUTE_REQ FORM_ROUTE_REQ ; +struct FORM_ROUTE_REQ { + char cmd_code ; + char pkt_number ; + char total_in_sequence ; + char route_data[10] ; + } ; + + +typedef struct FORM_ERROR FORM_ERROR ; +struct FORM_ERROR { + char cmd_code ; + char error_code ; + + } ; + +typedef struct FORM_STATUS FORM_STATUS ; +struct FORM_STATUS { + char cmd_code ; + char status_code ; + char last_packet_valid ; + char tx_buffer ; + char rx_buffer ; + char port_status ; + char phb_status ; + } ; + + +typedef struct FORM_LINK_STATUS FORM_LINK_STATUS ; +struct FORM_LINK_STATUS { + char cmd_code ; + char status_code ; + char link_number ; + ushort rx_errors ; + ushort tx_errors ; + ushort csum_errors ; + ushort disconnects ; + } ; + + + +typedef struct FORM_PARTITION FORM_PARTITION ; +struct FORM_PARTITION { + char cmd_code ; + char status_code ; + char port_number ; + char tx_max ; + char rx_max ; + char rx_limit ; + } ; + + +#endif + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h new file mode 100644 index 000000000000..e8f3860f4726 --- /dev/null +++ b/drivers/char/rio/func.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 : 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> + +#ifdef SCCS_LABELS +#ifndef lint +static char *_func_h_sccs_ = "@(#)func.h 1.3"; +#endif +#endif + +/* rioboot.c */ +int RIOBootCodeRTA(struct rio_info *, struct DownLoad *); +int RIOBootCodeHOST(struct rio_info *, register struct DownLoad *); +int RIOBootCodeUNKNOWN(struct rio_info *, struct DownLoad *); +void msec_timeout(struct Host *); +int RIOBootRup(struct rio_info *, uint, struct Host *, struct PKT *); +int RIOBootOk(struct rio_info *,struct Host *, ulong); +int RIORtaBound(struct rio_info *, uint); +void FillSlot(int, int, uint, struct Host *); + +/* riocmd.c */ +int RIOFoadRta(struct Host *, struct Map *); +int RIOZombieRta(struct Host *, struct Map *); +int RIOCommandRta(struct rio_info *, uint, int (* func)( struct Host *, + struct Map *)); +int RIOIdentifyRta(struct rio_info *, caddr_t); +int RIOKillNeighbour(struct rio_info *, caddr_t); +int RIOSuspendBootRta(struct Host *, int, int); +int RIOFoadWakeup(struct rio_info *); +struct CmdBlk * RIOGetCmdBlk(void); +void RIOFreeCmdBlk(struct CmdBlk *); +int RIOQueueCmdBlk(struct Host *, uint, struct CmdBlk *); +void RIOPollHostCommands(struct rio_info *, struct Host *); +int RIOWFlushMark(int, struct CmdBlk *); +int RIORFlushEnable(int, struct CmdBlk *); +int RIOUnUse(int, struct CmdBlk *); +void ShowPacket(uint, struct PKT *); + +/* rioctrl.c */ +int copyin(int, caddr_t, int); +int riocontrol(struct rio_info *, dev_t,int,caddr_t,int); +int RIOPreemptiveCmd(struct rio_info *,struct Port *,uchar); + +/* 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, caddr_t, int); +int RIOBoardTest(paddr_t, caddr_t, uchar, int); +void RIOAllocDataStructs(struct rio_info *); +void RIOSetupDataStructs(struct rio_info *); +int RIODefaultName(struct rio_info *, struct Host *, uint); +struct rioVersion * RIOVersid(void); +int RIOMapin(paddr_t, int, caddr_t *); +void RIOMapout(paddr_t, long, caddr_t); +void RIOHostReset(uint, volatile struct DpRam *, uint); + +/* riointr.c */ +void RIOTxEnable(char *); +void RIOServiceHost(struct rio_info *, struct Host *, int); +int riotproc(struct rio_info *, register 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 **, struct Port *); +void add_transmit(struct Port *); +void put_free_end(struct Host *, struct PKT *); +int can_remove_receive(struct PKT **, struct Port *); +void remove_receive(struct Port *); + +/* rioroute.c */ +int RIORouteRup(struct rio_info *, uint, struct Host *, struct PKT *); +void RIOFixPhbs(struct rio_info *, struct Host *, uint); +uint GetUnitType(uint); +int RIOSetChange(struct rio_info *); +int RIOFindFreeID(struct rio_info *, struct Host *, uint *, uint *); + + +/* riotty.c */ + +int riotopen(struct tty_struct * tty, struct file * filp); +int riotclose(void *ptr); +int riotioctl(struct rio_info *, struct tty_struct *, register int, register 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(register 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 int rio_pcicopy(char *src, char *dst, int n); +extern int rio_minor (struct tty_struct *tty); +extern int rio_ismodem (struct tty_struct *tty); +extern void rio_udelay (int usecs); + +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 000000000000..4c65963870a4 --- /dev/null +++ b/drivers/char/rio/host.h @@ -0,0 +1,134 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +#ifndef lint +static char *_host_h_sccs_ = "@(#)host.h 1.2"; +#endif +#endif + +/* +** 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 +{ + uchar Type; /* RIO_EISA, RIO_MCA, ... */ + uchar Ivec; /* POLLED or ivec number */ + uchar Mode; /* Control stuff */ + uchar Slot; /* Slot */ + volatile caddr_t Caddr; /* KV address of DPRAM */ + volatile struct DpRam *CardP; /* KV address of DPRAM, with overlay */ + paddr_t PaddrP; /* Phys. address of DPRAM */ + char Name[MAX_NAME_LEN]; /* The name of the host */ + uint UniqueNum; /* host unique number */ + spinlock_t HostLock; /* Lock structure for MPX */ + /*struct pci_devinfo PciDevInfo; *//* PCI Bus/Device/Function stuff */ + /*struct lockb HostLock; *//* Lock structure for MPX */ + uint WorkToBeDone; /* set to true each interrupt */ + uint InIntr; /* Being serviced? */ + uint IntSrvDone;/* host's interrupt has been serviced */ + int (*Copy)( caddr_t, caddr_t, 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. + */ + + ulong Flags; /* Whats going down */ +#define RC_WAITING 0 +#define RC_STARTUP 1 +#define RC_RUNNING 2 +#define RC_STUFFED 3 +#define RC_SOMETHING 4 +#define RC_SOMETHING_NEW 5 +#define RC_SOMETHING_ELSE 6 +#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 *PhbP; /* Pointer to the PHB array */ + ushort *PhbNumP; /* Ptr to Number of PHB's */ + struct LPB *LinkStrP ; /* Link Structure Array */ + struct RUP *RupP; /* Sixteen real rups here */ + struct PARM_MAP *ParmMapP; /* points to the parmmap */ + uint ExtraUnits[MAX_EXTRA_UNITS]; /* unknown things */ + uint 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 */ + 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/hosthw.h b/drivers/char/rio/hosthw.h new file mode 100644 index 000000000000..f6f31ece6e32 --- /dev/null +++ b/drivers/char/rio/hosthw.h @@ -0,0 +1,57 @@ +/**************************************************************************** + ******* ******* + ******* H O S T H A R D W A 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 lint +#ifdef SCCS_LABELS +static char *_rio_hosthw_h_sccs = "@(#)hosthw.h 1.2" ; +#endif +#endif + +#define SET_OTHER_INTERRUPT ( (volatile u_short *) 0x7c80 ) +#define SET_EISA_INTERRUPT ( (volatile u_short *) 0x7ef0 ) + +#define EISA_HOST 0x30 +#define AT_HOST 0xa0 +#define MCA_HOST 0xb0 +#define PCI_HOST 0xd0 + +#define PRODUCT_MASK 0xf0 + + +/*********** end of file ***********/ + + diff --git a/drivers/char/rio/link.h b/drivers/char/rio/link.h new file mode 100644 index 000000000000..972250348f4a --- /dev/null +++ b/drivers/char/rio/link.h @@ -0,0 +1,188 @@ +/**************************************************************************** + ******* ******* + ******* 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 + +#ifndef lint +#ifdef SCCS_LABELS +/* static char *_rio_link_h_sccs = "@(#)link.h 1.15"; */ +#endif +#endif + + + +/************************************************* + * Define the Link Status stuff + ************************************************/ +#define LRT_ACTIVE ((ushort) 0x01) +#define LRT_SPARE1 ((ushort) 0x02) +#define INTRO_RCVD ((ushort) 0x04) +#define FORCED_DISCONNECT ((ushort) 0x08) +#define LRT_SPARE2 ((ushort) 0x80) + +#define TOP_OF_RTA_RAM ((ushort) 0x7000) +#define HOST_SERIAL_POINTER (unsigned char **) (TOP_OF_RTA_RAM - 2 * sizeof (ushort)) + +/* Flags for ltt_status */ +#define WAITING_ACK (ushort) 0x0001 +#define DATA_SENT (ushort) 0x0002 +#define WAITING_RUP (ushort) 0x0004 +#define WAITING_RETRY (ushort) 0x0008 +#define WAITING_TOPOLOGY (ushort) 0x0010 +#define SEND_SYNC (ushort) 0x0020 +#define FOAD_THIS_LINK (ushort) 0x0040 +#define REQUEST_SYNC (ushort) 0x0080 +#define REMOTE_DYING (ushort) 0x0100 +#define DIE_NOW (ushort) 0x0200 + +/* 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 */ + +/* States that a link can be in */ +#define LINK_DISCONNECTED ((ushort) 0) /* Disconnected */ +#define LINK_BOOT1 ((ushort) 1) /* Trying to send 1st stage boot */ +#define LINK_BOOT2 ((ushort) 2) /* Trying to send 2nd stage boot */ +#define LINK_BOOT2WAIT ((ushort) 3) /* Waiting for selftest results */ +#define LINK_BOOT3 ((ushort) 4) /* Trying to send 3rd stage boots */ +#define LINK_SYNC ((ushort) 5) /* Syncing */ + +#define LINK_INTRO ((ushort) 10) /* Introductory packet */ +#define LINK_SUPPLYID ((ushort) 11) /* Trying to supply an ID */ +#define LINK_TOPOLOGY ((ushort) 12) /* Send a topology update */ +#define LINK_REQUESTID ((ushort) 13) /* Waiting for an ID */ +#define LINK_CONNECTED ((ushort) 14) /* Connected */ + +#define LINK_INTERCONNECT ((ushort) 20) /* Subnets interconnected */ + +#define LINK_SPARE ((ushort) 40) + +/* +** Set the default timeout for link communications. +*/ +#define LINKTIMEOUT (400 * MILLISECOND) + +/* +** LED stuff +*/ +#if defined(RTA) +#define LED_OFF ((ushort) 0) /* LED off */ +#define LED_RED ((ushort) 1) /* LED Red */ +#define LED_GREEN ((ushort) 2) /* LED Green */ +#define LED_ORANGE ((ushort) 4) /* LED Orange */ +#define LED_1TO8_OPEN ((ushort) 1) /* Port 1->8 LED on */ +#define LED_9TO16_OPEN ((ushort) 2) /* Port 9->16 LED on */ +#define LED_SET_COLOUR(colour) (link->led = (colour)) +#define LED_OR_COLOUR(colour) (link->led |= (colour)) +#define LED_TIMEOUT(time) (link->led_timeout = RioTimePlus(RioTime(),(time))) +#else +#define LED_SET_COLOUR(colour) +#define LED_OR_COLOUR(colour) +#define LED_TIMEOUT(time) +#endif /* RTA */ + +struct LPB { + WORD link_number ; /* Link Number */ + Channel_ptr in_ch ; /* Link In Channel */ + Channel_ptr out_ch ; /* Link Out Channel */ +#ifdef RTA + uchar stat_led ; /* Port open leds */ + uchar led ; /* True, light led! */ +#endif + BYTE attached_serial[4]; /* Attached serial number */ + BYTE attached_host_serial[4]; + /* Serial number of Host who + booted the other end */ + WORD descheduled ; /* Currently Descheduled */ + WORD state; /* Current state */ + WORD send_poll ; /* Send a Poll Packet */ + Process_ptr ltt_p ; /* Process Descriptor */ + Process_ptr lrt_p ; /* Process Descriptor */ + WORD lrt_status ; /* Current lrt status */ + WORD ltt_status ; /* Current ltt status */ + WORD timeout ; /* Timeout value */ + WORD topology; /* Topology bits */ + WORD mon_ltt ; + WORD mon_lrt ; + WORD WaitNoBoot ; /* Secs to hold off booting */ + PKT_ptr add_packet_list; /* Add packets to here */ + PKT_ptr remove_packet_list; /* Send packets from here */ +#ifdef RTA +#ifdef DCIRRUS +#define QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1) +#else +#define QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1) +#endif + PKT_ptr_ptr rd_add ; /* Add a new Packet here */ + Q_BUF_ptr rd_add_qb; /* Pointer to the add Q buf */ + PKT_ptr_ptr rd_add_st_qbb ; /* Pointer to start of the Q's buf */ + PKT_ptr_ptr rd_add_end_qbb ; /* Pointer to the end of the Q's buf */ + PKT_ptr_ptr rd_remove ; /* Remove a Packet here */ + Q_BUF_ptr rd_remove_qb ; /* Pointer to the remove Q buf */ + PKT_ptr_ptr rd_remove_st_qbb ; /* Pointer to the start of the Q buf */ + PKT_ptr_ptr rd_remove_end_qbb ; /* Pointer to the end of the Q buf */ + ushort pkts_in_q ; /* Packets in queue */ +#endif + + Channel_ptr lrt_fail_chan ; /* Lrt's failure channel */ + Channel_ptr ltt_fail_chan ; /* Ltt's failure channel */ + +#if defined (HOST) || defined (INKERNEL) + /* RUP structure for HOST to driver communications */ + struct RUP rup ; +#endif + struct RUP link_rup; /* RUP for the link (POLL, + topology etc.) */ + WORD attached_link ; /* Number of attached link */ + WORD csum_errors ; /* csum errors */ + WORD num_disconnects ; /* number of disconnects */ + WORD num_sync_rcvd ; /* # sync's received */ + WORD num_sync_rqst ; /* # sync requests */ + WORD num_tx ; /* Num pkts sent */ + WORD num_rx ; /* Num pkts received */ + WORD module_attached; /* Module tpyes of attached */ + WORD led_timeout; /* LED timeout */ + WORD first_port; /* First port to service */ + WORD 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 000000000000..d53843abe02d --- /dev/null +++ b/drivers/char/rio/linux_compat.h @@ -0,0 +1,122 @@ +/* + * (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 disable(oldspl) save_flags (oldspl) +#define restore(oldspl) restore_flags (oldspl) + +#define sysbrk(x) kmalloc ((x),in_interrupt()? GFP_ATOMIC : GFP_KERNEL) +#define sysfree(p,size) kfree ((p)) + +#define WBYTE(p,v) writeb(v, &p) +#define RBYTE(p) readb (&p) +#define WWORD(p,v) writew(v, &p) +#define RWORD(p) readw(&p) +#define WINDW(p,v) writew(v, p) +#define RINDW(p) readw(p) + +#define DEBUG_ALL + +#define cprintf printk + +#ifdef __KERNEL__ +#define INKERNEL +#endif + +struct ttystatics { + struct termios tm; +}; + +#define bzero(d, n) memset((d), 0, (n)) +#define bcopy(src, dest, n) memcpy ((dest), (src), (n)) + +#define SEM_SIGIGNORE 0x1234 + +#ifdef DEBUG_SEM +#define swait(a,b) printk ("waiting: " __FILE__ " line %d\n", __LINE__) +#define ssignal(sem) printk ("signalling: " __FILE__ " line %d\n", __LINE__) + +#define sreset(sem) printk ("sreset: " __FILE__ "\n") +#define sem_init(sem,v) printk ("sreset: " __FILE__ "\n") +#endif + + +#define getpid() (current->pid) + +#define QSIZE SERIAL_XMIT_SIZE + +#define pseterr(errno) return (- errno) + +#define V_CBAUD CBAUD + +/* For one reason or another rioboot.c uses delay instead of RIODelay. */ +#define delay(x,y) RIODelay(NULL, y) + +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/list.h b/drivers/char/rio/list.h new file mode 100644 index 000000000000..a4f7f1f56255 --- /dev/null +++ b/drivers/char/rio/list.h @@ -0,0 +1,196 @@ +/**************************************************************************** + ******* ******* + ******* L I S T ******* + ******* ******* + **************************************************************************** + + Author : Jeremy Rolls. + Date : 04-Nov-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 _list_h +#define _list_h 1 + +#ifdef SCCS_LABELS +#ifndef lint +static char *_rio_list_h_sccs = "@(#)list.h 1.9" ; +#endif +#endif + +#define PKT_IN_USE 0x1 + +#ifdef INKERNEL + +#define ZERO_PTR (ushort) 0x8000 +#define CaD PortP->Caddr + +/* +** 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. +*/ + +#ifndef linux +#if defined( MIPS ) && !defined( MIPSEISA ) +/* May the shoes of the Devil dance on your grave for creating this */ +#define can_add_transmit(PacketP,PortP) \ + (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \ + & (PKT_IN_USE<<2))) + +#elif defined(MIPSEISA) || defined(nx6000) || \ + defined(drs6000) || defined(UWsparc) + +#define can_add_transmit(PacketP,PortP) \ + (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \ + & PKT_IN_USE)) + +#else +#define can_add_transmit(PacketP,PortP) \ + (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \ + & PKT_IN_USE)) +#endif + +/* +** 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. +*/ +#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc) +# define add_transmit(PortP) \ + WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\ + if (PortP->TxAdd == PortP->TxEnd)\ + PortP->TxAdd = PortP->TxStart;\ + else\ + PortP->TxAdd++;\ + WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd)); +#elif defined(AIX) +# define add_transmit(PortP) \ + {\ + register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\ + WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\ + if (PortP->TxAddO == PortP->TxEndO )\ + PortP->TxAddO = PortP->TxStartO;\ + else\ + PortP->TxAddO += sizeof(ushort);\ + WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\ + } +#else +# define add_transmit(PortP) \ + *PortP->TxAdd |= PKT_IN_USE;\ + if (PortP->TxAdd == PortP->TxEnd)\ + PortP->TxAdd = PortP->TxStart;\ + else\ + PortP->TxAdd++;\ + PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd); +#endif + +/* +** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set +** for the next packet on the queue. It will also set PacketP 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. +*/ +#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc) +# define can_remove_receive(PacketP,PortP) \ + ((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \ + (PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0) +#elif defined(AIX) +# define can_remove_receive(PacketP,PortP) \ + ((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \ + (PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0) +#else +# define can_remove_receive(PacketP,PortP) \ + ((*PortP->RxRemove & PKT_IN_USE) ? \ + (PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0) +#endif + + +/* +** Will God see it within his heart to forgive us for this thing that +** we have created? 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. +*/ +#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc) +# define remove_receive(PortP) \ + WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\ + if (PortP->RxRemove == PortP->RxEnd)\ + PortP->RxRemove = PortP->RxStart;\ + else\ + PortP->RxRemove++;\ + WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove)); +#elif defined(AIX) +# define remove_receive(PortP) \ + {\ + register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\ + WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\ + if (PortP->RxRemoveO == PortP->RxEndO)\ + PortP->RxRemoveO = PortP->RxStartO;\ + else\ + PortP->RxRemoveO += sizeof(ushort);\ + WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\ + } +#else +# define remove_receive(PortP) \ + *PortP->RxRemove &= ~PKT_IN_USE;\ + if (PortP->RxRemove == PortP->RxEnd)\ + PortP->RxRemove = PortP->RxStart;\ + else\ + PortP->RxRemove++;\ + PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove); +#endif +#endif + + +#else /* !IN_KERNEL */ + +#define ZERO_PTR NULL + + +#ifdef HOST +/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE)) */ +#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\ + if (phb->tx_remove == phb->tx_end)\ + phb->tx_remove = phb->tx_start;\ + else\ + phb->tx_remove++; +#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE) +#define add_receive(pkt,phb) *phb->rx_add = pkt;\ + *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\ + if (phb->rx_add == phb->rx_end)\ + phb->rx_add = phb->rx_start;\ + else\ + phb->rx_add++; +#endif +#endif + +#ifdef RTA +#define splx(oldspl) if ((oldspl) == 0) spl0() +#endif + +#endif /* ifndef _list.h */ +/*********** end of file ***********/ diff --git a/drivers/char/rio/lrt.h b/drivers/char/rio/lrt.h new file mode 100644 index 000000000000..bbac8fa18fee --- /dev/null +++ b/drivers/char/rio/lrt.h @@ -0,0 +1,55 @@ +/**************************************************************************** + ******* ******* + ******* L R T + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS_LABELS +static char *_rio_lrt_h_sccs = "@(#)lrt.h 1.1" ; +#endif +#endif + + +#ifdef DCIRRUS +#define LRT_STACK (unsigned short) 600 +#else +#define LRT_STACK (ushort) 200 +#endif + + + +/*********** end of file ***********/ + + + diff --git a/drivers/char/rio/ltt.h b/drivers/char/rio/ltt.h new file mode 100644 index 000000000000..f27dcecf03ca --- /dev/null +++ b/drivers/char/rio/ltt.h @@ -0,0 +1,55 @@ +/**************************************************************************** + ******* ******* + ******* L T T + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS_LABELS +static char *_rio_ltt_h_sccs = "@(#)ltt.h 1.1" ; +#endif +#endif + +#ifdef DCIRRUS +#define LTT_STACK (unsigned short) 600 +#else +#define LTT_STACK (ushort) 200 +#endif + + + + +/*********** end of file ***********/ + + + diff --git a/drivers/char/rio/lttwake.h b/drivers/char/rio/lttwake.h new file mode 100644 index 000000000000..fe17d0ee4933 --- /dev/null +++ b/drivers/char/rio/lttwake.h @@ -0,0 +1,53 @@ + + + +/**************************************************************************** + ******* ******* + ******* L T T W A K E U P H E A D E R + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS_LABELS +static char *_rio_lttwake_h_sccs = "@(#)lttwake.h 1.1" ; +#endif +#endif + +#define LTT_WAKEUP_STACK 500 +#define LTT_WAKEUP_INTERVAL (int) (500 * MILLISECOND) + + +/*********** end of file ***********/ + + + diff --git a/drivers/char/rio/map.h b/drivers/char/rio/map.h new file mode 100644 index 000000000000..400645a1ff28 --- /dev/null +++ b/drivers/char/rio/map.h @@ -0,0 +1,103 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_map_h_sccs_ = "@(#)map.h 1.2"; +#endif + +/* +** 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 +{ + uint HostUniqueNum; /* Supporting hosts unique number */ + uint 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). + */ + ushort ID; /* ID used in the subnet */ + ushort ID2; /* ID of 2nd block of 8 for 16 port */ + ulong Flags; /* Booted, ID Given, Disconnected */ + ulong 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/mca.h b/drivers/char/rio/mca.h new file mode 100644 index 000000000000..08a327e473af --- /dev/null +++ b/drivers/char/rio/mca.h @@ -0,0 +1,73 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : mca.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:11 +** Retrieved : 11/6/98 11:34:21 +** +** ident @(#)mca.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_mca_h__ +#define __rio_mca_h__ + +#ifdef SCCS_LABELS +static char *_mca_h_sccs_ = "@(#)mca.h 1.2"; +#endif + +/* +** Micro Channel stuff +*/ + +#define McaMaxSlots 8 +#define McaSlotSelect 0x96 +#define McaSlotEnable 0x08 +#define McaIdLow 0x100 +#define McaIdHigh 0x101 +#define McaIrqEnable 0x102 +#define McaMemory 0x103 +#define McaRIOId 0x6a5c +#define McaIrq9 0x00 +#define McaIrq3 0x02 +#define McaIrq4 0x04 +#define McaIrq7 0x06 +#define McaIrq10 0x08 +#define McaIrq11 0x0A +#define McaIrq12 0x0C +#define McaIrq15 0x0E +#define McaIrqMask 0x0E +#define McaCardEnable 0x01 +#define McaAddress(X) (((X)&0xFF)<<16) + +#define McaTpFastLinks 0x40 +#define McaTpSlowLinks 0x00 +#define McaTpBootFromRam 0x01 +#define McaTpBootFromLink 0x00 +#define McaTpBusEnable 0x02 +#define McaTpBusDisable 0x00 + +#define RIO_MCA_DEFAULT_MODE SLOW_LINKS + +#endif /* __rio_mca_h__ */ diff --git a/drivers/char/rio/mesg.h b/drivers/char/rio/mesg.h new file mode 100644 index 000000000000..9cf6c0bacea4 --- /dev/null +++ b/drivers/char/rio/mesg.h @@ -0,0 +1,41 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : mesg.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:12 +** Retrieved : 11/6/98 11:34:21 +** +** ident @(#)mesg.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_mesg_h__ +#define __rio_mesg_h__ + +#ifdef SCCS_LABELS +static char *_mesg_h_sccs_ = "@(#)mesg.h 1.2"; +#endif + + +#endif /* __rio_mesg_h__ */ diff --git a/drivers/char/rio/param.h b/drivers/char/rio/param.h new file mode 100644 index 000000000000..2dc30b9aab37 --- /dev/null +++ b/drivers/char/rio/param.h @@ -0,0 +1,61 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_param_h_sccs_ = "@(#)param.h 1.2"; +#endif + + +/* +** the param command block, as used in OPEN and PARAM calls. +*/ + +struct phb_param +{ + BYTE Cmd; /* It is very important that these line up */ + BYTE Cor1; /* with what is expected at the other end. */ + BYTE Cor2; /* to confirm that you've got it right, */ + BYTE Cor4; /* check with cirrus/cirrus.h */ + BYTE Cor5; + BYTE TxXon; /* Transmit X-On character */ + BYTE TxXoff; /* Transmit X-Off character */ + BYTE RxXon; /* Receive X-On character */ + BYTE RxXoff; /* Receive X-Off character */ + BYTE LNext; /* Literal-next character */ + BYTE TxBaud; /* Transmit baudrate */ + BYTE RxBaud; /* Receive baudrate */ +}; + +#endif diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h new file mode 100644 index 000000000000..46f99dfdac8d --- /dev/null +++ b/drivers/char/rio/parmmap.h @@ -0,0 +1,96 @@ +/**************************************************************************** + ******* ******* + ******* 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 + + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_parmmap_h_sccs = "@(#)parmmap.h 1.4"; */ +#endif +#endif + +typedef struct PARM_MAP PARM_MAP ; + +struct PARM_MAP +{ +PHB_ptr phb_ptr ; /* Pointer to the PHB array */ +WORD_ptr phb_num_ptr ; /* Ptr to Number of PHB's */ +FREE_LIST_ptr free_list; /* Free List pointer */ +FREE_LIST_ptr free_list_end; /* Free List End pointer */ +Q_BUF_ptr_ptr q_free_list_ptr ; /* Ptr to Q_BUF variable */ +BYTE_ptr unit_id_ptr ; /* Unit Id */ +LPB_ptr link_str_ptr ; /* Link Structure Array */ +BYTE_ptr bootloader_1 ; /* 1st Stage Boot Loader */ +BYTE_ptr bootloader_2 ; /* 2nd Stage Boot Loader */ +WORD_ptr port_route_map_ptr ; /* Port Route Map */ +ROUTE_STR_ptr route_ptr ; /* Unit Route Map */ +NUMBER_ptr map_present ; /* Route Map present */ +NUMBER pkt_num ; /* Total number of packets */ +NUMBER q_num ; /* Total number of Q packets */ +WORD buffers_per_port ; /* Number of buffers per port */ +WORD heap_size ; /* Initial size of heap */ +WORD heap_left ; /* Current Heap left */ +WORD error ; /* Error code */ +WORD tx_max; /* Max number of tx pkts per phb */ +WORD rx_max; /* Max number of rx pkts per phb */ +WORD rx_limit; /* For high / low watermarks */ +NUMBER links ; /* Links to use */ +NUMBER timer ; /* Interrupts per second */ +RUP_ptr rups ; /* Pointer to the RUPs */ +WORD max_phb ; /* Mostly for debugging */ +WORD living ; /* Just increments!! */ +WORD init_done ; /* Initialisation over */ +WORD booting_link ; +WORD idle_count ; /* Idle time counter */ +WORD busy_count ; /* Busy counter */ +WORD idle_control ; /* Control Idle Process */ +#if defined(HOST) || defined(INKERNEL) +WORD tx_intr; /* TX interrupt pending */ +WORD rx_intr; /* RX interrupt pending */ +WORD rup_intr; /* RUP interrupt pending */ +#endif +#if defined(RTA) +WORD dying_count; /* Count of processes dead */ +#endif +} ; + +#endif + +/*********** end of file ***********/ + + diff --git a/drivers/char/rio/pci.h b/drivers/char/rio/pci.h new file mode 100644 index 000000000000..dc635bd25194 --- /dev/null +++ b/drivers/char/rio/pci.h @@ -0,0 +1,76 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_pci_h_sccs_ = "@(#)pci.h 1.2"; +#endif + +/* +** 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 000000000000..e1483a0e30bd --- /dev/null +++ b/drivers/char/rio/phb.h @@ -0,0 +1,293 @@ +/**************************************************************************** + ******* ******* + ******* 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 + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_phb_h_sccs = "@(#)phb.h 1.12"; */ +#endif +#endif + + + /************************************************* + * Set the LIMIT values. + ************************************************/ +#ifdef RTA +#define RX_LIMIT (ushort) 3 +#endif +#ifdef HOST +#define RX_LIMIT (ushort) 1 +#endif + + +/************************************************* + * 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 + ************************************************/ +#if defined (HOST) || defined (INKERNEL) +#define MAX_PHB ((ushort) 128) /* range 0-127 */ +#else +#define MAX_PHB ((ushort) 8) /* range 0-7 */ +#endif + +/************************************************* + * 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 + *************************************************************************/ +#ifndef INKERNEL +#define src_unit u2.s2.unit +#define src_port u2.s2.port +#define dest_unit u1.s1.unit +#define dest_port u1.s1.port +#endif +#ifdef HOST +#define tx_start u3.s1.tx_start_ptr_ptr +#define tx_add u3.s1.tx_add_ptr_ptr +#define tx_end u3.s1.tx_end_ptr_ptr +#define tx_remove u3.s1.tx_remove_ptr_ptr +#define rx_start u4.s1.rx_start_ptr_ptr +#define rx_add u4.s1.rx_add_ptr_ptr +#define rx_end u4.s1.rx_end_ptr_ptr +#define rx_remove u4.s1.rx_remove_ptr_ptr +#endif +typedef struct PHB PHB ; +struct PHB { +#ifdef RTA + ushort port; +#endif +#ifdef INKERNEL + WORD source; +#else + union + { + ushort source; /* Complete source */ + struct + { + unsigned char unit; /* Source unit */ + unsigned char port; /* Source port */ + } s2; + } u2; +#endif + WORD handshake ; + WORD status ; + NUMBER timeout ; /* Maximum of 1.9 seconds */ + WORD link ; /* Send down this link */ +#ifdef INKERNEL + WORD destination; +#else + union + { + ushort destination; /* Complete destination */ + struct + { + unsigned char unit; /* Destination unit */ + unsigned char port; /* Destination port */ + } s1; + } u1; +#endif +#ifdef RTA + ushort tx_pkts_added; + ushort tx_pkts_removed; + Q_BUF_ptr tx_q_start ; /* Start of the Q list chain */ + short num_tx_q_bufs ; /* Number of Q buffers in the chain */ + PKT_ptr_ptr tx_add ; /* Add a new Packet here */ + Q_BUF_ptr tx_add_qb; /* Pointer to the add Q buf */ + PKT_ptr_ptr tx_add_st_qbb ; /* Pointer to start of the Q's buf */ + PKT_ptr_ptr tx_add_end_qbb ; /* Pointer to the end of the Q's buf */ + PKT_ptr_ptr tx_remove ; /* Remove a Packet here */ + Q_BUF_ptr tx_remove_qb ; /* Pointer to the remove Q buf */ + PKT_ptr_ptr tx_remove_st_qbb ; /* Pointer to the start of the Q buf */ + PKT_ptr_ptr tx_remove_end_qbb ; /* Pointer to the end of the Q buf */ +#endif +#ifdef INKERNEL + PKT_ptr_ptr tx_start ; + PKT_ptr_ptr tx_end ; + PKT_ptr_ptr tx_add ; + PKT_ptr_ptr tx_remove ; +#endif +#ifdef HOST + union + { + struct + { + PKT_ptr_ptr tx_start_ptr_ptr; + PKT_ptr_ptr tx_end_ptr_ptr; + PKT_ptr_ptr tx_add_ptr_ptr; + PKT_ptr_ptr tx_remove_ptr_ptr; + } s1; + struct + { + ushort * tx_start_ptr; + ushort * tx_end_ptr; + ushort * tx_add_ptr; + ushort * tx_remove_ptr; + } s2; + } u3; +#endif + +#ifdef RTA + ushort rx_pkts_added; + ushort rx_pkts_removed; + Q_BUF_ptr rx_q_start ; /* Start of the Q list chain */ + short num_rx_q_bufs ; /* Number of Q buffers in the chain */ + PKT_ptr_ptr rx_add ; /* Add a new Packet here */ + Q_BUF_ptr rx_add_qb ; /* Pointer to the add Q buf */ + PKT_ptr_ptr rx_add_st_qbb ; /* Pointer to start of the Q's buf */ + PKT_ptr_ptr rx_add_end_qbb ; /* Pointer to the end of the Q's buf */ + PKT_ptr_ptr rx_remove ; /* Remove a Packet here */ + Q_BUF_ptr rx_remove_qb ; /* Pointer to the remove Q buf */ + PKT_ptr_ptr rx_remove_st_qbb ; /* Pointer to the start of the Q buf */ + PKT_ptr_ptr rx_remove_end_qbb ; /* Pointer to the end of the Q buf */ +#endif +#ifdef INKERNEL + PKT_ptr_ptr rx_start ; + PKT_ptr_ptr rx_end ; + PKT_ptr_ptr rx_add ; + PKT_ptr_ptr rx_remove ; +#endif +#ifdef HOST + union + { + struct + { + PKT_ptr_ptr rx_start_ptr_ptr; + PKT_ptr_ptr rx_end_ptr_ptr; + PKT_ptr_ptr rx_add_ptr_ptr; + PKT_ptr_ptr rx_remove_ptr_ptr; + } s1; + struct + { + ushort * rx_start_ptr; + ushort * rx_end_ptr; + ushort * rx_add_ptr; + ushort * rx_remove_ptr; + } s2; + } u4; +#endif + +#ifdef RTA /* some fields for the remotes */ + ushort flush_count; /* Count of write flushes */ + ushort txmode; /* Modes for tx */ + ushort rxmode; /* Modes for rx */ + ushort portmode; /* Generic modes */ + ushort column; /* TAB3 column count */ + ushort tx_subscript; /* (TX) Subscript into data field */ + ushort rx_subscript; /* (RX) Subscript into data field */ + PKT_ptr rx_incomplete; /* Hold an incomplete packet here */ + ushort modem_bits; /* Modem bits to mask */ + ushort lastModem; /* Modem control lines. */ + ushort addr; /* Address for sub commands */ + ushort MonitorTstate; /* TRUE if monitoring tstop */ +#endif + + } ; + +#endif + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/pkt.h b/drivers/char/rio/pkt.h new file mode 100644 index 000000000000..66bb2ff0f694 --- /dev/null +++ b/drivers/char/rio/pkt.h @@ -0,0 +1,120 @@ +/**************************************************************************** + ******* ******* + ******* 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 + + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_pkt_h_sccs = "@(#)pkt.h 1.8"; */ +#endif +#endif + +#define MAX_TTL 0xf +#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 { +#ifdef INKERNEL + BYTE dest_unit ; /* Destination Unit Id */ + BYTE dest_port ; /* Destination POrt */ + BYTE src_unit ; /* Source Unit Id */ + BYTE src_port ; /* Source POrt */ +#else + union + { + ushort destination; /* Complete destination */ + struct + { + unsigned char unit; /* Destination unit */ + unsigned char port; /* Destination port */ + } s1; + } u1; + union + { + ushort source; /* Complete source */ + struct + { + unsigned char unit; /* Source unit */ + unsigned char port; /* Source port */ + } s2; + } u2; +#endif +#ifdef INKERNEL + BYTE len ; + BYTE control; +#else + union + { + ushort control; + struct + { + unsigned char len; + unsigned char control; + } s3; + } u3; +#endif + BYTE data[PKT_MAX_DATA_LEN] ; + /* Actual data :-) */ + WORD csum ; /* C-SUM */ + } ; +#endif + +/*********** end of file ***********/ + + diff --git a/drivers/char/rio/poll.h b/drivers/char/rio/poll.h new file mode 100644 index 000000000000..d9b8e983e175 --- /dev/null +++ b/drivers/char/rio/poll.h @@ -0,0 +1,76 @@ +/**************************************************************************** + ******* ******* + ******* P O L L + ******* ******* + **************************************************************************** + + 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 _poll_h +#define _poll_h + +#ifndef lint +#ifdef SCCS_LABELS +static char *_rio_poll_h_sccs = "@(#)poll.h 1.2" ; +#endif +#endif + + +#ifdef HOST +#define POLL_STACK 100 +#endif +#ifdef RTA +#define POLL_STACK 200 +#endif + +#define POLL_PERIOD (int) SECOND + +/* The various poll commands */ +#define POLL_POLL 0 /* We are connected and happy.. */ +#define POLL_INTRO 1 /* Introduction packet */ +#define POLL_TOPOLOGY 2 /* Topology update */ +#define POLL_ASSIGN 3 /* ID assign */ +#define POLL_FOAD 4 /* F*** Off And Die */ +#define POLL_LMD 5 /* Let Me Die */ +#define POLL_DYB 6 /* Die You Ba***** */ + +/* The way data fields are split up for POLL packets */ +#define POLL_HOST_SERIAL 2 /* Host who booted me */ +#define POLL_MY_SERIAL 6 /* My serial number */ +#define POLL_YOUR_ID 1 /* Your ID number */ +#define POLL_TOPOLOGY_FIELDS 2 /* Topology maps */ + +#endif + +/*********** end of file ***********/ + + + diff --git a/drivers/char/rio/port.h b/drivers/char/rio/port.h new file mode 100644 index 000000000000..8506af06aa9f --- /dev/null +++ b/drivers/char/rio/port.h @@ -0,0 +1,245 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_port_h_sccs_ = "@(#)port.h 1.3"; +#endif + + +#undef VPIX + + +/* +** the port data structure - one per port in the system +*/ + +#ifdef STATS +struct RIOStats +{ + /* + ** interrupt statistics + */ + uint BreakIntCnt; + uint ModemOffCnt; + uint ModemOnCnt; + uint RxIntCnt; + uint TxIntCnt; + /* + ** throughput statistics + */ + uint RxCharCnt; + uint RxPktCnt; + uint RxSaveCnt; + uint TxCharCnt; + uint TxPktCnt; + /* + ** driver entry statistics + */ + uint CloseCnt; + uint IoctlCnt; + uint OpenCnt; + uint ReadCnt; + uint WriteCnt; + /* + ** proc statistics + */ + uint BlockCnt; + uint OutputCnt; + uint ResumeCnt; + uint RflushCnt; + uint SuspendCnt; + uint TbreakCnt; + uint TimeoutCnt; + uint UnblockCnt; + uint WflushCnt; + uint WFBodgeCnt; +}; +#endif + +/* +** Port data structure +*/ +struct Port +{ + struct gs_port gs; + int PortNum; /* RIO port no., 0-511 */ + struct Host *HostP; + volatile caddr_t Caddr; + ushort HostPort; /* Port number on host card */ + uchar RupNum; /* Number of RUP for port */ + uchar ID2; /* Second ID of RTA for port */ + ulong 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. */ + + ulong 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 *PhbP; /* pointer to PHB for port */ + WORD *TxAdd; /* Add packets here */ + WORD *TxStart; /* Start of add array */ + WORD *TxEnd; /* End of add array */ + WORD *RxRemove; /* Remove packets here */ + WORD *RxStart; /* Start of remove array */ + WORD *RxEnd; /* End of remove array */ + uint RtaUniqueNum; /* Unique number of RTA */ + ushort PortState; /* status of port */ + ushort ModemState; /* status of modem lines */ + ulong ModemLines; /* Modem bits sent to RTA */ + uchar CookMode; /* who expands CR/LF? */ + uchar ParamSem; /* Prevent write during param */ + uchar Mapped; /* if port mapped onto host */ + uchar SecondBlock; /* if port belongs to 2nd block + of 16 port RTA */ + uchar InUse; /* how many pre-emptive cmds */ + uchar Lock; /* if params locked */ + uchar Store; /* if params stored across closes */ + uchar FirstOpen; /* TRUE if first time port opened */ + uchar FlushCmdBodge; /* if doing a (non)flush */ + uchar 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 */ + uchar 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 + uint XpCps; + char XpOn[MAX_XP_CTRL_LEN]; + char XpOff[MAX_XP_CTRL_LEN]; + ushort XpLen; /* strlen(XpOn)+strlen(XpOff) */ + uchar XpActive; + uchar XpLastTickOk; /* TRUE if we can process */ +#define XP_OPEN 00001 +#define XP_RUNABLE 00002 + struct ttystatics *XttyP; + } Xprint; +#ifdef VPIX + v86_t *StashP; + uint IntMask; + struct termss VpixSs; + uchar ModemStatusReg; /* Modem status register */ +#endif + uchar RxDataStart; + uchar Cor2Copy; /* copy of COR2 */ + char *Name; /* points to the Rta's name */ +#ifdef STATS + struct RIOStats Stat; /* ports statistics */ +#endif + char *TxRingBuffer; + ushort TxBufferIn; /* New data arrives here */ + ushort TxBufferOut; /* Intr removes data here */ + ushort OldTxBufferOut; /* Indicates if draining */ + int TimeoutId; /* Timeout ID */ + uint Debug; + uchar WaitUntilBooted; /* True if open should block */ + uint statsGather; /* True if gathering stats */ + ulong txchars; /* Chars transmitted */ + ulong rxchars; /* Chars received */ + ulong opens; /* port open count */ + ulong closes; /* port close count */ + ulong ioctls; /* ioctl count */ + uchar 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; + uint Flags[4]; /* one per port on a module */ +}; +#endif + +/* +** 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 { + uint Port; + ulong Config; + ulong State; + struct ttystatics *TtyP; +}; diff --git a/drivers/char/rio/proto.h b/drivers/char/rio/proto.h new file mode 100644 index 000000000000..ddff0ef84e3a --- /dev/null +++ b/drivers/char/rio/proto.h @@ -0,0 +1,244 @@ +/* + * + * (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. + */ +#ifndef _prototypes_h +#define _prototypes_h + + +/* +** boot.c +*/ +void init_boot( char *p, short stage); + +/* +** disconct.c +*/ +void kill_boot ( LPB *link ); +void disconnected( LPB *link ); +short boot_3( LPB *link, PKT *pkt ); +short send_3_pkt( LPB *link, PKT *pkt); + +/* +** error.c +*/ +void du_error(void); + +/* +** formpkt.c +*/ +ushort sum_it( PKT *pkt ) ; +void form_rup_pkt( RUP *form_rup, PKT *pkt ); +void form_poll_pkt ( int type, LPB *link, int node ); +void form_route_pkt ( int type, PKT *pkt, LPB *link ); + +/* +** idle.c +*/ +void idle( Process *idle_p ); + +/* +** init.c +*/ +void general_init(void); +void mem_halt( int error); + +/* +** linkinit.c +*/ +void initlink( u_short number, LPB *link); +void runlink( LPB *link); + +/* +** list.c +*/ +PKT *get_free_start(void); +void put_free_start( PKT *pkt); + +#ifdef HOST +int can_remove_transmit ( PKT **pkt, PKT *pointer ); +#endif + +#ifdef RTA +int spl7 ( void ); +int spl0 ( void ); +Q_BUF *get_free_q( void ); +PKT *get_free_end(void); +int add_end( PKT *pkt, PHB *phb, int type); +unsigned short free_packets( PHB *phb, int type); +int can_remove_start( PKT **pkt, PHB *phb, int type); +int can_add_start( PHB *phb, int type); +int can_add_end( PHB *phb, int type); +void put_free_end( PKT *pkt); +int remove_start( PKT **pkt, PHB *phb, int type); +#endif + +/* +** Lrt.c +*/ +void lrt( Process *lrt_p, LPB *link ); + +#ifdef RTA +void set_led_red ( LPB *link ); +#endif + +/* +** ltt.c +*/ +void ltt( Process *ltt_p, LPB *link, PHB *phb_ptr[] ); +void send_poll ( LPB *link ); +void request_id ( LPB *link ); +void send_topology_update ( LPB *link ); +void send_topology ( LPB *link ); +void supply_id ( LPB *link ); + +#ifdef RTA +void redirect_queue ( LPB *link, ushort flush ); +int obtain_rup ( int rup_number, PKT **pkt_address, LPB *link ); +#endif + +#ifdef TESTING_PERF +int consume_cpu( void ); +#endif + +/* +** lttwake.c +*/ +#ifdef HOST +void ltt_wakeup( Process *ltt_wakeup_p ); +#endif + +/* +** mapgen.c +*/ +void generate_id_map( short mapping, ROUTE_STR route[] ); +void gen_map( int mapping, int looking_at, int come_from, ROUTE_STR route[], int link, int *ttl ); +void adjust_ttl( int mapping, int looking_at, int come_from, ROUTE_STR route[], int link, int *ttl); +void init_sys_map(void); + +/* +** mmu.c +*/ +char *rio_malloc( unsigned int amount); +char *rio_calloc( unsigned int num, unsigned int size); +ERROR rio_mmu_init( uint total_mem ); + +/* +** partn.c +*/ +void partition_tx( struct PHB *phb, u_short tx_size, u_short rx_size, u_short rx_limit); + +/* +** poll.c +*/ +void tx_poll( Process *tx_poll_p); + +/* +** process.c +*/ +int get_proc_space( Process **pd, int **pws, int wssize); + +/* +** readrom.c +*/ +void read_serial_number(char *buf); + +/* +** rio.c +*/ +int main( void ); + +/* +** route.c +*/ +void route_update ( PKT *pkt, LPB *link); + +/* +** rtainit.c +*/ +#if defined(RTA) +void rta_init(ushort RtaType); +#endif /* defined(RTA) */ + +/* +** rupboot.c +*/ +void rup_boot( PKT *pkt, RUP *this_rup, LPB *link); + +#ifdef RTA +void kill_your_neighbour( int link_to_kill ); +#endif + +/* +** rupcmd.c +*/ +void rup_command( PKT *pkt, struct RUP *this_rup, LPB *link); + +/* +** ruperr.c +*/ +void rup_error( PKT *pkt, RUP *this_rup, LPB *link ); +void illegal_cmd( PKT *src_pkt ); + +/* +** ruppoll.c +*/ +void rup_poll( PKT *pkt, RUP *this_rup, LPB *link ); + +/* +** ruppower.c +*/ +void rup_power( PKT *pkt, RUP *this_rup, LPB *link ); + +/* +** ruprm.c +*/ +void rup_route_map( PKT *pkt, RUP *this_rup, LPB *link); + +/* +** rupstat.c +*/ +void rup_status( PKT *pkt, RUP *this_rup, LPB *link); + +/* +** rupsync.c +*/ +void rup_sync( PKT *pkt); + +/* +** rxpkt.c +*/ +ERROR rx_pkt( PKT_ptr_ptr pkt_address, LPB *link); + +/* +** sendsts.c +*/ +void send_status( PKT *requesting_pkt, RUP *this_rup); + +/* +** serial.c +*/ +void assign_serial ( char *ser_in, char *ser_out); +int cmp_serial ( char *ser_1, char *ser_2); + +/* +** txpkt.c +*/ +ERROR tx_pkt( PKT *pkt, LPB *link); +short send_sync( LPB *link); + +#endif /* _prototypes_h */ diff --git a/drivers/char/rio/protsts.h b/drivers/char/rio/protsts.h new file mode 100644 index 000000000000..848111ac9380 --- /dev/null +++ b/drivers/char/rio/protsts.h @@ -0,0 +1,119 @@ +/**************************************************************************** + ******* ******* + ******* 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 + + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_protsts_h_sccs = "@(#)protsts.h 1.4"; */ +#endif +#endif + +/************************************************* + * 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/qbuf.h b/drivers/char/rio/qbuf.h new file mode 100644 index 000000000000..1fce02f8fcfc --- /dev/null +++ b/drivers/char/rio/qbuf.h @@ -0,0 +1,67 @@ + +/**************************************************************************** + ******* ******* + ******* Q U E U E B U F F E R S T R U C T U R E S + ******* ******* + **************************************************************************** + + 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 _qbuf_h +#define _qbuf_h 1 + +#ifndef lint +#ifdef SCCS_LABELS +static char *_rio_qbuf_h_sccs = "@(#)qbuf.h 1.1" ; +#endif +#endif + + + +#ifdef HOST +#define PKTS_PER_BUFFER 1 +#else +#define PKTS_PER_BUFFER (220 / PKT_LENGTH) +#endif + +typedef struct Q_BUF Q_BUF ; +struct Q_BUF { + Q_BUF_ptr next ; + Q_BUF_ptr prev ; + PKT_ptr buf[PKTS_PER_BUFFER] ; + } ; + + +#endif + + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/rio.h b/drivers/char/rio/rio.h new file mode 100644 index 000000000000..13a9931958b1 --- /dev/null +++ b/drivers/char/rio/rio.h @@ -0,0 +1,294 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_rio_h_sccs_ = "@(#)rio.h 1.3"; +#endif + +/* +** 30.09.1998 ARG - +** Introduced driver version and host card type strings +*/ +#define RIO_DRV_STR "Specialix RIO Driver" +#define RIO_AT_HOST_STR "ISA" +#define RIO_PCI_HOST_STR "PCI" + + +/* +** rio_info_store() commands (arbitary values) : +*/ +#define RIO_INFO_PUT 0xA4B3C2D1 +#define RIO_INFO_GET 0xF1E2D3C4 + + +/* +** anything that I couldn't cram in somewhere else +*/ +/* +#ifndef RIODEBUG +#define debug +#else +#define debug rioprint +#endif +*/ + + +/* +** 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 +#define RIO_SUCCESS 0 +#define COPYFAIL -1 /* copy[in|out] failed */ + +/* +** 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 HALF_A_SECOND ((HZ)>>1) +#define A_SECOND (HZ) +#define HUNDRED_HZ ((HZ/100)?(HZ/100):1) +#define FIFTY_HZ ((HZ/50)?(HZ/50):1) +#define TWENTY_HZ ((HZ/20)?(HZ/20):1) +#define TEN_HZ ((HZ/10)?(HZ/10):1) +#define FIVE_HZ ((HZ/5)?(HZ/5):1) +#define HUNDRED_MS TEN_HZ +#define FIFTY_MS TWENTY_HZ +#define TWENTY_MS FIFTY_HZ +#define TEN_MS HUNDRED_HZ +#define TWO_SECONDS ((A_SECOND)*2) +#define FIVE_SECONDS ((A_SECOND)*5) +#define TEN_SECONDS ((A_SECOND)*10) +#define FIFTEEN_SECONDS ((A_SECOND)*15) +#define TWENTY_SECONDS ((A_SECOND)*20) +#define HALF_A_MINUTE (A_MINUTE>>1) +#define A_MINUTE (A_SECOND*60) +#define FIVE_MINUTES (A_MINUTE*5) +#define QUARTER_HOUR (A_MINUTE*15) +#define HALF_HOUR (A_MINUTE*30) +#define HOUR (A_MINUTE*60) + +#define SIXTEEN_MEG 0x1000000 +#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 POLL_VECTOR 0x100 + +#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) (((caddr_t)(C))+(0xFFFF&(O))) +#define RIO_OFF(C,O) ((int)(O)-(int)(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! +** +** Note: LynxOS only gives us 8 bits for the device minor number, +** so all this crap here to deal with 'modem' bits etc. is +** just a load of irrelevant old bunkum! +** This however does not stop us needing to define a value +** for RIO_MODEMOFFSET which is required by the 'riomkdev' +** utility in the New Config Utilities suite. +*/ +/* 0-511: direct 512-1023: modem */ +#define RIO_MODEMOFFSET 0x200 /* doesn't mean anything */ +#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 splrio spltty + +#define RIO_IPL 5 +#define RIO_PRI (PZERO+10) +#define RIO_CLOSE_PRI PZERO-1 /* uninterruptible sleeps for close */ + +typedef struct DbInf +{ + uint Flag; + char Name[8]; +} DbInf; + +#ifndef TRUE +#define TRUE (1==1) +#endif +#ifndef FALSE +#define FALSE (!TRUE) +#endif + +#define CSUM(pkt_ptr) (((ushort *)(pkt_ptr))[0] + ((ushort *)(pkt_ptr))[1] + \ + ((ushort *)(pkt_ptr))[2] + ((ushort *)(pkt_ptr))[3] + \ + ((ushort *)(pkt_ptr))[4] + ((ushort *)(pkt_ptr))[5] + \ + ((ushort *)(pkt_ptr))[6] + ((ushort *)(pkt_ptr))[7] + \ + ((ushort *)(pkt_ptr))[8] + ((ushort *)(pkt_ptr))[9] ) + +/* +** This happy little macro copies SIZE bytes of data from FROM to TO +** quite well. SIZE must be a constant. +*/ +#define CCOPY( FROM, TO, SIZE ) { *(struct s { char data[SIZE]; } *)(TO) = *(struct s *)(FROM); } + +/* +** increment a buffer pointer modulo the size of the buffer... +*/ +#define BUMP( P, I ) ((P) = (((P)+(I)) & RIOBufferMask)) + +#define INIT_PACKET( PK, PP ) \ +{ \ + *((uint *)PK) = PP->PacketInfo; \ +} + +#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 + + +/* +** Machine types - these must NOT overlap with product codes 0-15 +*/ +#define RIO_MIPS_R3230 31 +#define RIO_MIPS_R4030 32 + +#define RIO_IO_UNKNOWN -2 + +#undef MODERN +#define ERROR( E ) do { u.u_error = E; return OPENFAIL } while ( 0 ) + +/* Defines for MPX line discipline routines */ + +#define DIST_LINESW_OPEN 0x01 +#define DIST_LINESW_CLOSE 0x02 +#define DIST_LINESW_READ 0x04 +#define DIST_LINESW_WRITE 0x08 +#define DIST_LINESW_IOCTL 0x10 +#define DIST_LINESW_INPUT 0x20 +#define DIST_LINESW_OUTPUT 0x40 +#define DIST_LINESW_MDMINT 0x80 + +#endif /* __rio_h__ */ diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c new file mode 100644 index 000000000000..a91ae271cf0a --- /dev/null +++ b/drivers/char/rio/rio_linux.c @@ -0,0 +1,1380 @@ + +/* 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. + * + * Revision history: + * $Log: rio.c,v $ + * Revision 1.1 1999/07/11 10:13:54 wolff + * Initial revision + * + * */ + +#include <linux/module.h> +#include <linux/config.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> + +#if BITS_PER_LONG != 32 +# error FIXME: this driver only works on 32-bit platforms +#endif + +#include "linux_compat.h" +#include "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" +#include "param.h" +#include "list.h" +#include "sam.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 + +#if 0 +/* Not implemented */ +/* + * The following defines are mostly for testing purposes. But if you need + * some nice reporting in your syslog, you can define them also. + */ +#define RIO_REPORT_FIFO +#define RIO_REPORT_OVERRUN +#endif + + +/* 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 int rio_fw_ioctl (struct inode *inode, 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 (sizeof(rio_probe_addrs)/sizeof (int)) + + +/* 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 */ +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 struct file_operations rio_fw_fops = { + .owner = THIS_MODULE, + .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, "%08x ", (int) 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; +} + + +int rio_minor(struct tty_struct *tty) +{ + return tty->index + (tty->driver == rio_driver) ? 0 : 256; +} + + +int rio_ismodem(struct tty_struct *tty) +{ + return 1; +} + + +void rio_udelay (int usecs) +{ + udelay (usecs); +} + +static int rio_set_real_termios (void *ptr) +{ + int rv, modem; + struct tty_struct *tty; + func_enter(); + + tty = ((struct Port *)ptr)->gs.tty; + + modem = rio_ismodem(tty); + + rv = RIOParam( (struct Port *) ptr, CONFIG, modem, 1); + + func_exit (); + + return rv; +} + + +static void rio_reset_interrupt (struct Host *HostP) +{ + func_enter(); + + switch( HostP->Type ) { + case RIO_AT: + case RIO_MCA: + case RIO_PCI: + WBYTE(HostP->ResetInt , 0xff); + } + + func_exit(); +} + + +static irqreturn_t rio_interrupt (int irq, void *ptr, struct pt_regs *regs) +{ + struct Host *HostP; + func_enter (); + + HostP = (struct Host*)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. + + - Rate limit goes before "recursive". Otherwise a series of + recursive calls will hang the machine in the interrupt routine. + + - 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. + */ + + + +#ifdef IRQ_RATE_LIMIT + /* Aaargh! I'm ashamed. This costs more lines-of-code than the + actual interrupt routine!. (Well, used to when I wrote that comment) */ + { + static int lastjif; + static int nintr=0; + + if (lastjif == jiffies) { + if (++nintr > IRQ_RATE_LIMIT) { + free_irq (HostP->Ivec, ptr); + printk (KERN_ERR "rio: Too many interrupts. Turning off interrupt %d.\n", + HostP->Ivec); + } + } else { + lastjif = jiffies; + nintr = 0; + } + } +#endif + 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 %d/irq%d)\n", + (int) ptr, HostP->Ivec); + return IRQ_HANDLED; + } + + RIOServiceHost(p, HostP, irq); + + rio_dprintk ( RIO_DEBUG_IFLOW, "riointr() doing host %d type %d\n", + (int) 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], NULL); + p->RIOHosts[data].timer.expires = jiffies + rio_poll; + add_timer (&p->RIOHosts[data].timer); + + 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.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.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 & 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.tty = NULL; +#if 0 + port->gs.flags &= ~ GS_ACTIVE; + if (!port->gs.tty) { + rio_dprintk (RIO_DBUG_TTY, "No tty.\n"); + return; + } + if (!port->gs.tty->termios) { + rio_dprintk (RIO_DEBUG_TTY, "No termios.\n"); + return; + } + if (port->gs.tty->termios->c_cflag & HUPCL) { + rio_setsignals (port, 0, 0); + } +#endif + + 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.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.count) { + printk (KERN_ERR "WARNING port count:%d\n", PortP->gs.count); + PortP->gs.count = 0; + } + + PortP->gs.tty = NULL; + func_exit (); +} + + + +static int rio_fw_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + func_enter(); + + /* The "dev" argument isn't used. */ + rc = riocontrol (p, 0, cmd, (void *)arg, capable(CAP_SYS_ADMIN)); + + 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) +{ + int rc; + struct Port *PortP; + int ival; + + func_enter(); + + PortP = (struct Port *)tty->driver_data; + + rc = 0; + switch (cmd) { +#if 0 + case TIOCGSOFTCAR: + rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), + (unsigned int *) arg); + break; +#endif + case TIOCSSOFTCAR: + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { + tty->termios->c_cflag = + (tty->termios->c_cflag & ~CLOCAL) | + (ival ? CLOCAL : 0); + } + break; + case TIOCGSERIAL: + rc = -EFAULT; + if (access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct))) + rc = gs_getserial(&PortP->gs, (struct serial_struct *) arg); + 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, 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, 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, (void *) arg, + sizeof(struct serial_struct))) + rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg); + break; +#if 0 + /* + * note: these IOCTLs no longer reach here. Use + * tiocmset/tiocmget driver methods instead. The + * #if 0 disablement predates this comment. + */ + case TIOCMGET: + rc = -EFAULT; + if (access_ok(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int))) { + rc = 0; + ival = rio_getsignals(port); + put_user(ival, (unsigned int *) arg); + } + break; + case TIOCMBIS: + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { + rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), + ((ival & TIOCM_RTS) ? 1 : -1)); + } + break; + case TIOCMBIC: + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { + rio_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), + ((ival & TIOCM_RTS) ? 0 : -1)); + } + break; + case TIOCMSET: + if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { + rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), + ((ival & TIOCM_RTS) ? 1 : 0)); + } + break; +#endif + 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 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 = kmalloc(size, GFP_KERNEL); + if (p) + memset(p, 0, size); + 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 : %d %d %d %d %d 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.open_wait); + init_waitqueue_head(&port->gs.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 int hwbase; + unsigned long rebase; + unsigned int t; + +#define CNTRL_REG_OFFSET 0x50 +#define CNTRL_REG_GOODVALUE 0x18260000 + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase); + hwbase &= PCI_BASE_ADDRESS_MEM_MASK; + rebase = (ulong) 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((char*) 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 int tint; + 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_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, + pdev))) { + 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 */ + /* I don't know why the define doesn't work, constant 0x2c does --REW */ + 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"); + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint); + + hp = &p->RIOHosts[p->RIONumHosts]; + hp->PaddrP = tint & PCI_BASE_ADDRESS_MEM_MASK; + 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 *) hp->Caddr; + hp->Type = RIO_PCI; + hp->Copy = rio_pcicopy; + 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 ) == RIO_SUCCESS) { + rio_dprintk (RIO_DEBUG_INIT, "Done RIOBoardTest\n"); + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff); + p->RIOHosts[p->RIONumHosts].UniqueNum = + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0]) &0xFF)<< 0)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1]) &0xFF)<< 8)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2]) &0xFF)<<16)| + ((RBYTE(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->RIOLastPCISearch = RIO_SUCCESS; + p->RIONumHosts++; + found++; + } else { + iounmap((char*) (p->RIOHosts[p->RIONumHosts].Caddr)); + } + } + + /* 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_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_RIO, + pdev))) { + if (pci_enable_device(pdev)) continue; + +#ifdef CONFIG_RIO_OLDPCI + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &tint); + + hp = &p->RIOHosts[p->RIONumHosts]; + hp->PaddrP = tint & PCI_BASE_ADDRESS_MEM_MASK; + 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 *) hp->Caddr; + hp->Type = RIO_PCI; + hp->Copy = rio_pcicopy; + 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 ) == RIO_SUCCESS) { + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff); + p->RIOHosts[p->RIONumHosts].UniqueNum = + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0]) &0xFF)<< 0)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1]) &0xFF)<< 8)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2]) &0xFF)<<16)| + ((RBYTE(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->RIOLastPCISearch = RIO_SUCCESS; + p->RIONumHosts++; + found++; + } else { + iounmap((char*) (p->RIOHosts[p->RIONumHosts].Caddr)); + } +#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 *) hp->Caddr; + hp->Type = RIO_AT; + hp->Copy = rio_pcicopy; /* 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) == RIO_SUCCESS) { + /* ... 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 ((char*) (hp->Caddr)); + } + } + + + for (i=0;i<p->RIONumHosts;i++) { + hp = &p->RIOHosts[i]; + if (hp->Ivec) { + int mode = SA_SHIRQ; + 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... */ + + init_timer (&hp->timer); + if (!hp->Ivec) { + rio_dprintk (RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", + rio_poll); + hp->timer.data = i; + hp->timer.function = rio_pollfunc; + hp->timer.expires = jiffies + rio_poll; + add_timer (&hp->timer); + } + } + + 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 (&hp->timer); + } + + 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); + +/* + * Anybody who knows why this doesn't work for me, please tell me -- REW. + * Snatched from scsi.c (fixed one spelling error): + * Overrides for Emacs so that we follow Linus' tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local Variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ + diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h new file mode 100644 index 000000000000..1fba19d5b66a --- /dev/null +++ b/drivers/char/rio/rio_linux.h @@ -0,0 +1,187 @@ + +/* + * 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. + * + */ +#include <linux/config.h> + +#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 *rio_memcpy_toio (void *dummy, void *dest, void *source, int n) +{ + char *dst = dest; + char *src = source; + + while (n--) { + writeb (*src++, dst++); + (void) readb (dummy); + } + + return dest; +} + + +static inline void *rio_memcpy_fromio (void *dest, void *source, int n) +{ + char *dst = dest; + char *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_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", __FUNCTION__) +#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __FUNCTION__) +#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__FUNCTION__, 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 000000000000..cc6ac6a98f65 --- /dev/null +++ b/drivers/char/rio/rioboard.h @@ -0,0 +1,281 @@ +/************************************************************************/ +/* */ +/* 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 */ +/* */ +/************************************************************************/ + +/* History... + +1.0.0 26/04/99 NPV Creation. + +*/ + +#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 000000000000..a8be11dfcba3 --- /dev/null +++ b/drivers/char/rio/rioboot.c @@ -0,0 +1,1360 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ + +#ifdef SCCS_LABELS +static char *_rioboot_c_sccs_ = "@(#)rioboot.c 1.3"; +#endif + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/string.h> +#include <asm/semaphore.h> + + +#include <linux/termios.h> +#include <linux/serial.h> + +#include <linux/generic_serial.h> + + + +#include "linux_compat.h" +#include "rio_linux.h" +#include "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" + +static int RIOBootComplete( struct rio_info *p, struct Host *HostP, uint Rup, struct PktCmd *PktCmdP ); + +static uchar +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 +}; + +/* +** Load in the RTA boot code. +*/ +int +RIOBootCodeRTA(p, rbp) +struct rio_info * p; +struct DownLoad * rbp; +{ + int offset; + + func_enter (); + + /* Linux doesn't allow you to disable interrupts during a + "copyin". (Crash when a pagefault occurs). */ + /* disable(oldspl); */ + + rio_dprintk (RIO_DEBUG_BOOT, "Data at user address 0x%x\n",(int)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; + /* restore(oldspl); */ + 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; + /* restore(oldspl); */ + 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. + */ + bzero( (caddr_t)p->RIOBootPackets, offset ); + + /* + ** Copy the data from user space. + */ + + if ( copyin((int)rbp->DataP,((caddr_t)(p->RIOBootPackets))+offset, + rbp->Count) ==COPYFAIL ) { + rio_dprintk (RIO_DEBUG_BOOT, "Bad data copy from user space\n"); + p->RIOError.Error = COPYIN_FAILED; + /* restore(oldspl); */ + 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; + + /* restore(oldspl); */ + func_exit(); + return 0; +} + +void rio_start_card_running (struct Host * HostP) +{ + func_enter (); + + switch ( HostP->Type ) { + case RIO_AT: + rio_dprintk (RIO_DEBUG_BOOT, "Start ISA card running\n"); + WBYTE(HostP->Control, + BOOT_FROM_RAM | EXTERNAL_BUS_ON + | HostP->Mode + | RIOAtVec2Ctrl[HostP->Ivec & 0xF] ); + break; + +#ifdef FUTURE_RELEASE + case RIO_MCA: + /* + ** MCA handles IRQ vectors differently, so we don't write + ** them to this register. + */ + rio_dprintk (RIO_DEBUG_BOOT, "Start MCA card running\n"); + WBYTE(HostP->Control, McaTpBootFromRam | McaTpBusEnable | HostP->Mode); + break; + + case RIO_EISA: + /* + ** EISA is totally different and expects OUTBZs to turn it on. + */ + rio_dprintk (RIO_DEBUG_BOOT, "Start EISA card running\n"); + OUTBZ( HostP->Slot, EISA_CONTROL_PORT, HostP->Mode | RIOEisaVec2Ctrl[HostP->Ivec] | EISA_TP_RUN | EISA_TP_BUS_ENABLE | EISA_TP_BOOT_FROM_RAM ); + break; +#endif + + 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"); + WBYTE(HostP->Control, PCITpBootFromRam | PCITpBusEnable | HostP->Mode); + break; + default: + rio_dprintk (RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type); + break; + } +/* + printk (KERN_INFO "Done with starting the card\n"); + func_exit (); +*/ + 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(p, rbp) +struct rio_info * p; +register struct DownLoad *rbp; +{ + register struct Host *HostP; + register caddr_t Cad; + register PARM_MAP *ParmMapP; + register int RupN; + int PortN; + uint host; + caddr_t StartP; + BYTE *DestP; + int wait_count; + ushort OldParmMap; + ushort offset; /* It is very important that this is a ushort */ + /* uint byte; */ + caddr_t DownCode = NULL; + unsigned long flags; + + HostP = NULL; /* Assure the compiler we've initialized it */ + 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); + + + if ( (HostP->Flags & RUN_STATE) != RC_WAITING ) { + rio_dprintk (RIO_DEBUG_BOOT, "%s %d already running\n","Host",host); + continue; + } + + /* + ** Grab a 32 bit pointer to the card. + */ + 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 = (caddr_t)&Cad[p->RIOConf.HostLoadBase-rbp->Count]; + + rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for host is 0x%x\n", (int)Cad ); + rio_dprintk (RIO_DEBUG_BOOT, "kernel virtual address for download is 0x%x\n", (int)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); + + 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, (struct DpRam *)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"); + + /* + ** PCI hostcard can't cope with 32 bit accesses and so need to copy + ** data to a local buffer, and then dripfeed the card. + */ + if ( HostP->Type == RIO_PCI ) { + /* int offset; */ + + DownCode = sysbrk(rbp->Count); + if ( !DownCode ) { + rio_dprintk (RIO_DEBUG_BOOT, "No system memory available\n"); + p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY; + func_exit (); + return -ENOMEM; + } + bzero(DownCode, rbp->Count); + + if ( copyin((int)rbp->DataP,DownCode,rbp->Count)==COPYFAIL ) { + rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); + sysfree( DownCode, rbp->Count ); + p->RIOError.Error = COPYIN_FAILED; + func_exit (); + return -EFAULT; + } + + HostP->Copy( DownCode, StartP, rbp->Count ); + + sysfree( DownCode, rbp->Count ); + } + else if ( copyin((int)rbp->DataP,StartP,rbp->Count)==COPYFAIL ) { + rio_dprintk (RIO_DEBUG_BOOT, "Bad copyin of host data\n"); + p->RIOError.Error = COPYIN_FAILED; + func_exit (); + return -EFAULT; + } + + 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 = (BYTE *)&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; + WBYTE( DestP[0] , NFIX(((ushort)(~offset) >> (ushort)12) & 0xF) ); + WBYTE( DestP[1] , PFIX(( offset >> 8) & 0xF) ); + WBYTE( DestP[2] , PFIX(( offset >> 4) & 0xF) ); + WBYTE( DestP[3] , JUMP( offset & 0xF) ); + + WBYTE( DestP[6] , NFIX(0) ); + WBYTE( DestP[7] , JUMP(8) ); + + 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 = RWORD(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)&& + (RWORD(HostP->__ParmMapR)==OldParmMap); wait_count++ ) { + rio_dprintk (RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n",wait_count,RWORD(HostP->__ParmMapR)); + delay(HostP, HUNDRED_MS); + + } + + /* + ** If the parmmap pointer is unchanged, then the host code + ** has crashed & burned in a really spectacular way + */ + if ( RWORD(HostP->__ParmMapR) == OldParmMap ) { + rio_dprintk (RIO_DEBUG_BOOT, "parmmap 0x%x\n", RWORD(HostP->__ParmMapR)); + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n"); + +#define HOST_DISABLE \ + HostP->Flags &= ~RUN_STATE; \ + HostP->Flags |= RC_STUFFED; \ + RIOHostReset( HostP->Type, (struct DpRam *)HostP->CardP, HostP->Slot );\ + continue + + HOST_DISABLE; + } + + rio_dprintk (RIO_DEBUG_BOOT, "Running 0x%x\n", RWORD(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 *)RIO_PTR(Cad,RWORD(HostP->__ParmMapR)); + rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)ParmMapP); + ParmMapP = (PARM_MAP *)((unsigned long)Cad + + (unsigned long)((RWORD((HostP->__ParmMapR))) & 0xFFFF)); + rio_dprintk (RIO_DEBUG_BOOT, "ParmMapP : %x\n", (int)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 ( (RWORD(ParmMapP->links) & 0xFFFF) != 0xFFFF ) { + rio_dprintk (RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name); + rio_dprintk (RIO_DEBUG_BOOT, "Links = 0x%x\n",RWORD(ParmMapP->links)); + HOST_DISABLE; + } + + WWORD(ParmMapP->links , RIO_LINK_ENABLE); + + /* + ** 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) && + !RWORD(ParmMapP->init_done); wait_count++ ) { + rio_dprintk (RIO_DEBUG_BOOT, "Waiting for init_done\n"); + delay(HostP, HUNDRED_MS); + } + rio_dprintk (RIO_DEBUG_BOOT, "OK! init_done!\n"); + + if (RWORD(ParmMapP->error) != E_NO_ERROR || + !RWORD(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"); + HOST_DISABLE; + } + + 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. + */ + WWORD(ParmMapP->timer, (short)p->RIOConf.Timer ); + + /* + ** Translate all the 16 bit pointers in the __ParmMapR into + ** 32 bit pointers for the driver. + */ + HostP->ParmMapP = ParmMapP; + HostP->PhbP = (PHB*)RIO_PTR(Cad,RWORD(ParmMapP->phb_ptr)); + HostP->RupP = (RUP*)RIO_PTR(Cad,RWORD(ParmMapP->rups)); + HostP->PhbNumP = (ushort*)RIO_PTR(Cad,RWORD(ParmMapP->phb_num_ptr)); + HostP->LinkStrP = (LPB*)RIO_PTR(Cad,RWORD(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 *PhbP; + /* int oldspl; */ + + if ( !PortP->Mapped ) + continue; + + PhbP = &HostP->PhbP[PortP->HostPort]; + rio_spin_lock_irqsave(&PortP->portSem, flags); + + PortP->PhbP = PhbP; + + PortP->TxAdd = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_add)); + PortP->TxStart = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_start)); + PortP->TxEnd = (WORD *)RIO_PTR(Cad,RWORD(PhbP->tx_end)); + PortP->RxRemove = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_remove)); + PortP->RxStart = (WORD *)RIO_PTR(Cad,RWORD(PhbP->rx_start)); + PortP->RxEnd = (WORD *)RIO_PTR(Cad,RWORD(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; +} + + + +/* +** Boot an RTA. If we have successfully processed this boot, then +** return 1. If we havent, then return 0. +*/ +int +RIOBootRup( p, Rup, HostP, PacketP) +struct rio_info * p; +uint Rup; +struct Host *HostP; +struct PKT *PacketP; +{ + struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data; + struct PktCmd_M *PktReplyP; + struct CmdBlk *CmdBlkP; + uint sequence; + +#ifdef CHECK + CheckHost(Host); + CheckRup(Rup); + CheckHostP(HostP); + CheckPacketP(PacketP); +#endif + + /* + ** 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; + } + + /* rio_dprint(RIO_DEBUG_BOOT, NULL,DBG_BOOT,"Incoming command packet\n"); */ + /* ShowPacket( DBG_BOOT, PacketP ); */ + + /* + ** 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 ( (RBYTE(PacketP->len) & PKT_CMD_BIT) && + (RBYTE(PktCmdP->Command)==BOOT_COMPLETED) ) + return RIOBootComplete(p, HostP, Rup, PktCmdP ); + + /* + ** try to unhook a command block from the command free list. + */ + 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 < (ushort)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 ( RBYTE(PacketP->len) & PKT_CMD_BIT ) { + /* + ** We only expect one type of command - a BOOT_REQUEST! + */ + if ( RBYTE(PktCmdP->Command) != BOOT_REQUEST ) { + rio_dprintk (RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %d\n", + PktCmdP->Command,Rup,HostP-p->RIOHosts); + ShowPacket( DBG_BOOT, PacketP ); + RIOFreeCmdBlk( CmdBlkP ); + return 1; + } + + /* + ** Build a Boot Sequence command block + ** + ** 02.03.1999 ARG - ESIL 0820 fix + ** 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. + ** So, this conditional is not required ... + ** + if (p->RIOBootMode == RC_BOOT_NONE) + ** + ** If the system is in slave mode, and a boot request is + ** received, set command to BOOT_ABORT so that the boot + ** will not complete. + ** + PktReplyP->Command = BOOT_ABORT; + else + ** + ** 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; + + bcopy("BOOT",(void *)&CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN],4); + + rio_dprintk (RIO_DEBUG_BOOT, "Boot RTA on Host %d 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 = RWORD(PktCmdP->Sequence); + + rio_dprintk (RIO_DEBUG_BOOT, "Boot block %d on Host %d 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); + ShowPacket( DBG_BOOT, PacketP ); + } + + PktReplyP->Sequence = sequence; + + bcopy( p->RIOBootPackets[ p->RIONumBootPkts - sequence - 1 ], + PktReplyP->BootData, RTA_BOOT_DATA_SIZE ); + + CmdBlkP->Packet.len = PKT_MAX_DATA_LEN; + ShowPacket( DBG_BOOT, &CmdBlkP->Packet ); + RIOQueueCmdBlk( HostP, Rup, CmdBlkP ); + return 1; +} + +/* +** 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, uint Rup, struct PktCmd *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; + uint MyLink; + ushort RtaType; + uint RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) + + (RBYTE(PktCmdP->UniqNum[1]) << 8) + + (RBYTE(PktCmdP->UniqNum[2]) << 16) + + (RBYTE(PktCmdP->UniqNum[3]) << 24); + + /* Was RIOBooting-- . That's bad. If an RTA sends two of them, the + driver will never think that the RTA has booted... -- REW */ + 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 >= (ushort)MAX_RUP ) { + rio_dprintk (RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", + HostP->Name, 8 * RtaType, RBYTE(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, + RBYTE(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 TRUE; + } + + /* + ** 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 = RBYTE(PktCmdP->LinkNum); + if (Rup < (ushort) 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. + */ + WWORD(HostP->LinkStrP[MyLink].WaitNoBoot, 30); + } + 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 TRUE; + } + + /* + ** 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++ ) + { + uint sysport; + + if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && + (HostP->Mapping[entry].RtaUniqueNum==RtaUniq)) + { + HostP->Mapping[entry].Flags |= RTA_BOOTED|RTA_NEWBOOT; +#if NEED_TO_FIX + RIO_SV_BROADCAST(HostP->svFlags[entry]); +#endif + 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; +#if NEED_TO_FIX + RIO_SV_BROADCAST(HostP->svFlags[entry2]); +#endif + 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 TRUE; + } + } + + rio_dprintk (RIO_DEBUG_BOOT, "RTA not configured for this host\n"); + + if ( Rup >= (ushort)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; + } +#ifdef CHECK + CheckString(MyType); + CheckString(MyName); +#endif + + MyLink = RBYTE(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) + cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A'); + return TRUE; + } + } + + /* + ** 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); + FillSlot(entry, entry2, RtaUniq, HostP); + EmptySlot = 0; + } + } + else + { + if (RIOFindFreeID(p, HostP, &entry, NULL) == 0) + { + RIODefaultName(p, HostP, entry); + FillSlot(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; + CCOPY( MapP->Name, HostP->Mapping[entry].Name, MAX_NAME_LEN ); + HostP->Mapping[entry].Flags = + SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT; +#if NEED_TO_FIX + RIO_SV_BROADCAST(HostP->svFlags[entry]); +#endif + 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 NEED_TO_FIX + RIO_SV_BROADCAST(HostP->svFlags[entry]); +#endif + } + if (RtaType == TYPE_RTA16) + { + if (Flag & SLOT_IN_USE) + { + HostP->Mapping[entry2].Flags = SLOT_IN_USE | + RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT; +#if NEED_TO_FIX + RIO_SV_BROADCAST(HostP->svFlags[entry2]); +#endif + 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; +#if NEED_TO_FIX + RIO_SV_BROADCAST(HostP->svFlags[entry2]); +#endif + bzero( (caddr_t)MapP2, sizeof(struct Map) ); + } + bzero( (caddr_t)MapP, sizeof(struct Map) ); + if (! p->RIONoMessage) + cprintf("An orphaned RTA has been adopted by %s '%s' (%c).\n",MyType,MyName,MyLink+'A'); + } + else if (! p->RIONoMessage) + cprintf("RTA connected to %s '%s' (%c) not configured.\n",MyType,MyName,MyLink+'A'); + RIOSetChange(p); + return TRUE; + } + + /* + ** 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) + cprintf("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 TRUE; + } + } + /* + ** If there is room, add the unit to the list of extras + */ + if ( HostP->NumExtraBooted < MAX_EXTRA_UNITS ) + HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq; + return TRUE; +} + + +/* +** If the RTA or its host appears in the RIOBindTab[] structure then +** we mustn't boot the RTA and should return FALSE. +** 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(p, HostP, RtaUniq) +struct rio_info * p; +struct Host * HostP; +ulong RtaUniq; +{ + int Entry; + uint 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 +FillSlot(entry, entry2, RtaUniq, HostP) +int entry; +int entry2; +uint RtaUniq; +struct Host *HostP; +{ + int link; + + rio_dprintk (RIO_DEBUG_BOOT, "FillSlot(%d, %d, 0x%x...)\n", entry, entry2, RtaUniq); + + HostP->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE); + HostP->Mapping[entry].SysPort = NO_PORT; + HostP->Mapping[entry].RtaUniqueNum = RtaUniq; + HostP->Mapping[entry].HostUniqueNum = HostP->UniqueNum; + HostP->Mapping[entry].ID = entry + 1; + HostP->Mapping[entry].ID2 = 0; + if (entry2) { + HostP->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | + SLOT_TENTATIVE | RTA16_SECOND_SLOT); + HostP->Mapping[entry2].SysPort = NO_PORT; + HostP->Mapping[entry2].RtaUniqueNum = RtaUniq; + HostP->Mapping[entry2].HostUniqueNum = HostP->UniqueNum; + HostP->Mapping[entry2].Name[0] = '\0'; + HostP->Mapping[entry2].ID = entry2 + 1; + HostP->Mapping[entry2].ID2 = entry + 1; + HostP->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++ ) { + HostP->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT; + HostP->Mapping[entry].Topology[link].Link = NO_LINK; + if (entry2) { + HostP->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT; + HostP->Mapping[entry2].Topology[link].Link = NO_LINK; + } + } +} + +#if 0 +/* + Function: This function is to disable the disk interrupt + Returns : Nothing +*/ +void +disable_interrupt(vector) +int vector; +{ + int ps; + int val; + + disable(ps); + if (vector > 40) { + val = 1 << (vector - 40); + __outb(S8259+1, __inb(S8259+1) | val); + } + else { + val = 1 << (vector - 32); + __outb(M8259+1, __inb(M8259+1) | val); + } + restore(ps); +} + +/* + Function: This function is to enable the disk interrupt + Returns : Nothing +*/ +void +enable_interrupt(vector) +int vector; +{ + int ps; + int val; + + disable(ps); + if (vector > 40) { + val = 1 << (vector - 40); + val = ~val; + __outb(S8259+1, __inb(S8259+1) & val); + } + else { + val = 1 << (vector - 32); + val = ~val; + __outb(M8259+1, __inb(M8259+1) & val); + } + restore(ps); +} +#endif diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c new file mode 100644 index 000000000000..533085ec6f1b --- /dev/null +++ b/drivers/char/rio/riocmd.c @@ -0,0 +1,1041 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_riocmd_c_sccs_ = "@(#)riocmd.c 1.2"; +#endif + +#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/semaphore.h> + +#include <linux/termios.h> +#include <linux/serial.h> + +#include <linux/generic_serial.h> + +#include "linux_compat.h" +#include "rio_linux.h" +#include "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.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, uint RtaUnique, + int (* func)(struct Host *HostP, struct Map *MapP)) +{ + uint Host; + + rio_dprintk (RIO_DEBUG_CMD, "Command RTA 0x%x func 0x%x\n", RtaUnique, (int)func); + + if ( !RtaUnique ) + return(0); + + for ( Host = 0; Host < p->RIONumHosts; Host++ ) { + uint 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 <= (uchar)MAX_RUP ) { + /* + ** Its worth trying the operation... + */ + return (*func)( HostP, MapP ); + } + } + } + } + } + return -ENXIO; +} + + +int +RIOIdentifyRta(struct rio_info *p, caddr_t arg) +{ + uint Host; + + if ( copyin( (int)arg, (caddr_t)&IdRta, sizeof(IdRta) ) == COPYFAIL ) { + 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++ ) { + uint 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 <= (uchar)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, caddr_t arg) +{ + uint Host; + uint ID; + struct Host *HostP; + struct CmdBlk *CmdBlkP; + + rio_dprintk (RIO_DEBUG_CMD, "KILL HOST NEIGHBOUR\n"); + + if ( copyin( (int)arg, (caddr_t)&KillUnit, sizeof(KillUnit) ) == COPYFAIL ) { + 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; + register 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, PKT *PacketP) +{ + struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data; + struct Port *PortP; + struct UnixRup *UnixRupP; + ushort SysPort; + ushort ReportedModemStatus; + ushort rup; + ushort subCommand; + unsigned long flags; + + func_enter (); + +#ifdef CHECK + CheckHost( Host ); + CheckHostP( HostP ); + CheckPacketP( PacketP ); +#endif + + /* + ** 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 = RBYTE(PktCmdP->PhbNum) / (ushort)PORTS_PER_RTA; + UnixRupP = &HostP->UnixRups[rup]; + SysPort = UnixRupP->BaseSysPort + + (RBYTE(PktCmdP->PhbNum) % (ushort)PORTS_PER_RTA); + rio_dprintk (RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort); + +#ifdef CHECK + CheckRup( rup ); + CheckUnixRupP( UnixRupP ); +#endif + 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 %d, name ``%s''\n", + HostP-p->RIOHosts, HostP->Name ); + rio_dprintk (RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); + + if ( Rup >= (ushort)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", + PacketP->dest_unit, PacketP->dest_port ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Source 0x%x:0x%x\n", + PacketP->src_unit, PacketP->src_port ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Length 0x%x (%d)\n", PacketP->len,PacketP->len ); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Control 0x%x (%d)\n", PacketP->control, PacketP->control); + rio_dprintk (RIO_DEBUG_CMD, "PACKET information: Check 0x%x (%d)\n", PacketP->csum, PacketP->csum ); + rio_dprintk (RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, " + "Command Code 0x%x\n", PktCmdP->PhbNum, PktCmdP->Command ); + return TRUE; + } + +#ifdef CHECK + CheckSysPort( SysPort ); +#endif + PortP = p->RIOPortp[ SysPort ]; + rio_spin_lock_irqsave(&PortP->portSem, flags); + switch( RBYTE(PktCmdP->Command) ) { + case 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 FALSE 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 COMPLETE: + rio_dprintk (RIO_DEBUG_CMD, "Command complete on phb %d host %d\n", + RBYTE(PktCmdP->PhbNum), HostP-p->RIOHosts); + subCommand = 1; + switch (RBYTE(PktCmdP->SubCommand)) { + case MEMDUMP : + rio_dprintk (RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", + RBYTE(PktCmdP->SubCommand), RWORD(PktCmdP->SubAddr)); + break; + case READ_REGISTER : + rio_dprintk (RIO_DEBUG_CMD, "Read register (0x%x)\n", RWORD(PktCmdP->SubAddr)); + p->CdRegister = (RBYTE(PktCmdP->ModemStatus) & MSVR1_HOST); + break; + default : + subCommand = 0; + break; + } + if (subCommand) + break; + rio_dprintk (RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", + RBYTE(PktCmdP->PortStatus),PortP->PortState); + if (PortP->PortState != RBYTE(PktCmdP->PortStatus)) { + rio_dprintk (RIO_DEBUG_CMD, "Mark status & wakeup\n"); + PortP->PortState = RBYTE(PktCmdP->PortStatus); + /* What should we do here ... + wakeup( &PortP->PortState ); + */ + } else + rio_dprintk (RIO_DEBUG_CMD, "No change\n"); + + /* FALLTHROUGH */ + case 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 = RBYTE(PktCmdP->ModemStatus); + if ((PortP->ModemState & MSVR1_HOST) == + (ReportedModemStatus & 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.tty == NULL) + break; + if (PortP->gs.tty->termios == NULL) + break; + + if (!(PortP->gs.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 & 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.open_wait); +#ifdef STATS + PortP->Stat.ModemOnCnt++; +#endif + } + } else { + /* + ** Has carrier just dropped? + */ + if (PortP->State & RIO_CARR_ON) { + if (PortP->State & (PORT_ISOPEN|RIO_WOPEN|RIO_MOPEN)) + tty_hangup (PortP->gs.tty); + PortP->State &= ~RIO_CARR_ON; + rio_dprintk (RIO_DEBUG_CMD, "Carrirer just went down\n"); +#ifdef STATS + PortP->Stat.ModemOffCnt++; +#endif + } + } + } + } +#endif + } + break; + + default: + rio_dprintk (RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %d\n", + RBYTE(PktCmdP->Command),HostP-p->RIOHosts); + break; + } + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + + func_exit (); + + return TRUE; +} +/* +** 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 = (struct CmdBlk *)sysbrk(sizeof(struct CmdBlk)); + if (CmdBlkP) + bzero(CmdBlkP, sizeof(struct CmdBlk)); + + return CmdBlkP; +} + +/* +** Return a block to the head of the free list. +*/ +void +RIOFreeCmdBlk(struct CmdBlk *CmdBlkP) +{ + sysfree((void *)CmdBlkP, sizeof(struct CmdBlk)); +} + +/* +** 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; + +#ifdef CHECK + CheckHostP( HostP ); + CheckRup( Rup ); + CheckCmdBlkP( CmdBlkP ); +#endif + if ( Rup >= (ushort)(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) && + (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE ) && + (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg,CmdBlkP) + :TRUE)) { + 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( (caddr_t)&CmdBlkP->Packet, + RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt ), sizeof(PKT) ); + + /* + ** place command packet on the pending position. + */ + UnixRupP->CmdPendingP = CmdBlkP; + + /* + ** set the command register + */ + WWORD(UnixRupP->RupP->txcontrol , TX_PACKET_READY); + + rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); + + return RIO_SUCCESS; + } + 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 ( RWORD(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 0x%x at 0x%x\n", (int)CmdBlkP,(int)Base); + + while ( *Base ) { + rio_dprintk (RIO_DEBUG_CMD, "Command cmdblk 0x%x here\n", (int)(*Base)); + Base = &((*Base)->NextP); + rio_dprintk (RIO_DEBUG_CMD, "Now try to queue cmd cmdblk 0x%x at 0x%x\n", + (int)CmdBlkP,(int)Base); + } + + rio_dprintk (RIO_DEBUG_CMD, "Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base); + + *Base = CmdBlkP; + + CmdBlkP->NextP = NULL; + + rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); + + return RIO_SUCCESS; +} + +/* +** 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) +{ + register struct CmdBlk *CmdBlkP; + register struct UnixRup *UnixRupP; + struct PKT *PacketP; + ushort 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 ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) { + int FreeMe; + + PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt)); + + ShowPacket( DBG_CMD, PacketP ); + + switch ( RBYTE(PacketP->dest_port) ) { + case BOOT_RUP: + rio_dprintk (RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", + RBYTE(PacketP->len) & 0x80 ? "Command":"Data", + RBYTE(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 (PacketP->data[5] == MEMDUMP) { + rio_dprintk (RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", + *(ushort *) &(PacketP->data[6])); + HostP->Copy( (caddr_t)&(PacketP->data[8]), + (caddr_t)p->RIOMemDump, 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", RBYTE(PacketP->dest_port)); + FreeMe = 1; + break; + } + + if ( FreeMe ) { + rio_dprintk (RIO_DEBUG_CMD, "Free processed incoming command packet\n"); + put_free_end(HostP,PacketP); + + WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE); + + if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) { + rio_dprintk (RIO_DEBUG_CMD, "Handshake rup %d\n",Rup); + WWORD(UnixRupP->RupP->handshake, + PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); + } + } + } + + /* + ** IF a command was running on the port, + ** and it has completed, then tidy it up. + */ + if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ + (RWORD(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 0x%x completed\n",(int)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) && + (RWORD(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! + */ +#ifdef CHECK + CheckCmdBlkP (CmdBlkP); +#endif + if ( !(CmdBlkP->PreFuncP ? + (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) { + rio_dprintk (RIO_DEBUG_CMD, "Not ready to start command 0x%x\n",(int)CmdBlkP); + } + else { + rio_dprintk (RIO_DEBUG_CMD, "Start new command 0x%x Cmd byte is 0x%x\n", + (int)CmdBlkP, CmdBlkP->Packet.data[0]); + /* + ** Whammy! blat that pack! + */ +#ifdef CHECK + CheckPacketP ((PKT *)RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt)); +#endif + HostP->Copy( (caddr_t)&CmdBlkP->Packet, + RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(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 + */ + WWORD(UnixRupP->RupP->txcontrol,TX_PACKET_READY); + + /* + ** the command block will be freed + ** when the command has been processed. + */ + } + } + spin_unlock_irqrestore(&UnixRupP->RupLock, flags); + } while ( Rup ); +} + +int +RIOWFlushMark(int iPortP, struct CmdBlk *CmdBlkP) +{ + struct Port * PortP = (struct Port *)iPortP; + unsigned long flags; + + rio_spin_lock_irqsave(&PortP->portSem, flags); +#ifdef CHECK + CheckPortP( PortP ); +#endif + PortP->WflushFlag++; + PortP->MagicFlags |= MAGIC_FLUSH; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return RIOUnUse( iPortP, CmdBlkP ); +} + +int +RIORFlushEnable(int iPortP, struct CmdBlk *CmdBlkP) +{ + struct Port * PortP = (struct Port *)iPortP; + PKT *PacketP; + unsigned long flags; + + rio_spin_lock_irqsave(&PortP->portSem, flags); + + while ( can_remove_receive(&PacketP, PortP) ) { + remove_receive(PortP); + ShowPacket(DBG_PROC, PacketP ); + put_free_end( PortP->HostP, PacketP ); + } + + if ( RWORD(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"); + WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); + } + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return RIOUnUse( iPortP, CmdBlkP ); +} + +int +RIOUnUse(int iPortP, struct CmdBlk *CmdBlkP) +{ + struct Port * PortP = (struct Port *)iPortP; + unsigned long flags; + + rio_spin_lock_irqsave(&PortP->portSem, flags); + +#ifdef CHECK + CheckPortP( PortP ); +#endif + 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. + */ + WWORD(PortP->HostP->ParmMapP->tx_intr, 1); + /* What to do here .. + wakeup( (caddr_t)&(PortP->InUse) ); + */ + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; +} + +void +ShowPacket(uint Flags, struct PKT *PacketP) +{ +} + +/* +** +** 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 processore 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 000000000000..b4d1a23e27e4 --- /dev/null +++ b/drivers/char/rio/rioctrl.c @@ -0,0 +1,1869 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_rioctrl_c_sccs_ = "@(#)rioctrl.c 1.3"; +#endif + + +#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/semaphore.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 "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" + + +static struct LpbReq LpbReq; +static struct RupReq RupReq; +static struct PortReq PortReq; +static struct HostReq HostReq; +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)) + +int copyin (int arg, caddr_t dp, int siz) +{ + int rv; + + rio_dprintk (RIO_DEBUG_CTRL, "Copying %d bytes from user %p to %p.\n", siz, (void *)arg, dp); + rv = copy_from_user (dp, (void *)arg, siz); + if (rv) return COPYFAIL; + else return rv; +} + +static int copyout (caddr_t dp, int arg, int siz) +{ + int rv; + + rio_dprintk (RIO_DEBUG_CTRL, "Copying %d bytes to user %p from %p.\n", siz, (void *)arg, dp); + rv = copy_to_user ((void *)arg, dp, siz); + if (rv) return COPYFAIL; + else return rv; +} + +int +riocontrol(p, dev, cmd, arg, su) +struct rio_info * p; +dev_t dev; +int cmd; +caddr_t arg; +int su; +{ + uint Host; /* leave me unsigned! */ + uint port; /* and me! */ + struct Host *HostP; + ushort loop; + int Entry; + struct Port *PortP; + PKT *PacketP; + int retval = 0; + unsigned long flags; + + 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: 0x%x\n", cmd, (int)arg); + + 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 %dms\n", (uint)arg); + { + int host, value; + host = (uint)arg >> 16; + value = (uint)arg & 0x0000ffff; + if (host == -1) { + for (host = 0; host < p->RIONumHosts; host++) { + if (p->RIOHosts[host].Flags == RC_RUNNING) { + WWORD(p->RIOHosts[host].ParmMapP->timer , value); + } + } + } else if (host >= p->RIONumHosts) { + return -EINVAL; + } else { + if ( p->RIOHosts[host].Flags == RC_RUNNING ) { + WWORD(p->RIOHosts[host].ParmMapP->timer , value); + } + } + } + return 0; + + case RIO_IDENTIFY_DRIVER: + /* + ** 15.10.1998 ARG - ESIL 0760 part fix + ** Added driver ident string output. + ** +#ifndef __THIS_RELEASE__ +#warning Driver Version string not defined ! +#endif + cprintf("%s %s %s %s\n", + RIO_DRV_STR, + __THIS_RELEASE__, + __DATE__, __TIME__ ); + + return 0; + + case RIO_DISPLAY_HOST_CFG: + ** + ** 15.10.1998 ARG - ESIL 0760 part fix + ** Added driver host card ident string output. + ** + ** Note that the only types currently supported + ** are ISA and PCI. Also this driver does not + ** (yet) distinguish between the Old PCI card + ** and the Jet PCI card. In fact I think this + ** driver only supports JET PCI ! + ** + + for (Host = 0; Host < p->RIONumHosts; Host++) + { + HostP = &(p->RIOHosts[Host]); + + switch ( HostP->Type ) + { + case RIO_AT : + strcpy( host_type, RIO_AT_HOST_STR ); + break; + + case RIO_PCI : + strcpy( host_type, RIO_PCI_HOST_STR ); + break; + + default : + strcpy( host_type, "Unknown" ); + break; + } + + cprintf( + "RIO Host %d - Type:%s Addr:%X IRQ:%d\n", + Host, host_type, + (uint)HostP->PaddrP, + (int)HostP->Ivec - 32 ); + } + return 0; + ** + */ + + case RIO_FOAD_RTA: + rio_dprintk (RIO_DEBUG_CTRL, "RIO_FOAD_RTA\n"); + return RIOCommandRta(p, (uint)arg, RIOFoadRta); + + case RIO_ZOMBIE_RTA: + rio_dprintk (RIO_DEBUG_CTRL, "RIO_ZOMBIE_RTA\n"); + return RIOCommandRta(p, (uint)arg, RIOZombieRta); + + case RIO_IDENTIFY_RTA: + rio_dprintk (RIO_DEBUG_CTRL, "RIO_IDENTIFY_RTA\n"); + return RIOIdentifyRta(p, arg); + + case RIO_KILL_NEIGHBOUR: + rio_dprintk (RIO_DEBUG_CTRL, "RIO_KILL_NEIGHBOUR\n"); + return RIOKillNeighbour(p, arg); + + case SPECIAL_RUP_CMD: + { + struct CmdBlk *CmdBlkP; + + rio_dprintk (RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD\n"); + if (copyin((int)arg, (caddr_t)&SpecialRupCmd, + sizeof(SpecialRupCmd)) == COPYFAIL ) { + 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) { + cprintf("FAILED TO QUEUE SPECIAL RUP COMMAND\n"); + } + return 0; + } + + case RIO_DEBUG_MEM: +#ifdef DEBUG_MEM_SUPPORT +RIO_DEBUG_CTRL, if (su) + return rio_RIODebugMemory(RIO_DEBUG_CTRL, arg); + else +#endif + 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 (copyout((caddr_t)p->RIOConnectTable, (int)arg, + TOTAL_MAP_ENTRIES*sizeof(struct Map)) == COPYFAIL) { + 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 ( copyin((int)arg, (caddr_t)&p->RIOConnectTable[0], + TOTAL_MAP_ENTRIES*sizeof(struct Map) ) == COPYFAIL ) { + 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 (copyout((caddr_t) p->RIOBindTab, (int)arg, + (sizeof(ulong) * MAX_RTA_BINDINGS)) == COPYFAIL ) { + 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 (copyin((int)arg, (caddr_t)&p->RIOBindTab[0], + (sizeof(ulong) * MAX_RTA_BINDINGS))==COPYFAIL ) { + 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] == (int) arg) { + /* + ** Already exists - delete + */ + p->RIOBindTab[Entry] = 0L; + rio_dprintk (RIO_DEBUG_CTRL, "Removing Rta %x from p->RIOBindTab\n", + (int) arg); + return 0; + } + } + /* + ** Dosen't exist - add + */ + if (EmptySlot != -1) { + p->RIOBindTab[EmptySlot] = (int) arg; + rio_dprintk (RIO_DEBUG_CTRL, "Adding Rta %x to p->RIOBindTab\n", + (int) arg); + } + else { + rio_dprintk (RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %x not added\n", + (int) arg); + return -ENOMEM; + } + return 0; + } + + case RIO_RESUME : + rio_dprintk (RIO_DEBUG_CTRL, "RIO_RESUME\n"); + port = (uint) 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]), 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 (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) + == COPYFAIL) { + 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 (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) + == COPYFAIL) { + 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 (copyin((int)arg, (caddr_t)&MapEnt, sizeof(MapEnt)) + == COPYFAIL ) { + 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: + /* + ** 09.12.1998 ARG - ESIL 0776 part fix + ** A customer was using this to get the RTAs + ** connect/disconnect status. + ** RIOConCon() had been botched use RIOHalted + ** to keep track of RTA connections and + ** disconnections. That has been changed and + ** RIORtaDisCons in the rio_info struct now + ** does the job. So we need to return the value + ** of RIORtaCons instead of RIOHalted. + ** + if (copyout((caddr_t)&p->RIOHalted,(int)arg, + sizeof(uint))==COPYFAIL) { + ** + */ + + if (copyout((caddr_t)&p->RIORtaDisCons,(int)arg, + sizeof(uint))==COPYFAIL) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return 0; + + case RIO_LAST_ERROR: + if (copyout((caddr_t)&p->RIOError, (int)arg, + sizeof(struct Error)) ==COPYFAIL ) + return -EFAULT; + return 0; + + case RIO_GET_LOG: + rio_dprintk (RIO_DEBUG_CTRL, "RIO_GET_LOG\n"); +#ifdef LOGGING + RIOGetLog(arg); + return 0; +#else + return -EINVAL; +#endif + + case RIO_GET_MODTYPE: + if ( copyin( (int)arg, (caddr_t)&port, + sizeof(uint)) == COPYFAIL ) + { + 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 (copyout((caddr_t)&port, (int)arg, + sizeof(uint)) == COPYFAIL) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return(0); + /* + ** 02.03.1999 ARG - ESIL 0820 fix + ** We are no longer using "Boot Mode", so these ioctls + ** are not required : + ** + case RIO_GET_BOOT_MODE : + rio_dprint(RIO_DEBUG_CTRL, ("Get boot mode - %x\n", p->RIOBootMode)); + ** + ** Return boot state of system - BOOT_ALL, BOOT_OWN or BOOT_NONE + ** + if (copyout((caddr_t)&p->RIOBootMode, (int)arg, + sizeof(p->RIOBootMode)) == COPYFAIL) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return(0); + + case RIO_SET_BOOT_MODE : + p->RIOBootMode = (uint) arg; + rio_dprint(RIO_DEBUG_CTRL, ("Set boot mode to 0x%x\n", p->RIOBootMode)); + return(0); + ** + ** End ESIL 0820 fix + */ + + 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 (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) + == COPYFAIL ) { + 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 ) { + cprintf("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); +#if 0 + PortP = p->RIOPortp[loop]; + if ( !PortP->TtyP ) + PortP->TtyP = &p->channel[loop]; + + rio_spin_lock_irqsave(&PortP->portSem, flags); + if ( PortSetup.IxAny ) + PortP->Config |= RIO_IXANY; + else + PortP->Config &= ~RIO_IXANY; + if ( PortSetup.IxOn ) + PortP->Config |= RIO_IXON; + else + PortP->Config &= ~RIO_IXON; + + /* + ** If the port needs to wait for all a processes output + ** to drain before closing then this flag will be set. + */ + if (PortSetup.Drain) { + PortP->Config |= RIO_WAITDRAIN; + } else { + PortP->Config &= ~RIO_WAITDRAIN; + } + /* + ** Store settings if locking or unlocking port or if the + ** port is not locked, when setting the store option. + */ + if (PortP->Mapped && + ((PortSetup.Lock && !PortP->Lock) || + (!PortP->Lock && + (PortSetup.Store && !PortP->Store)))) { + PortP->StoredTty.iflag = PortP->TtyP->tm.c_iflag; + PortP->StoredTty.oflag = PortP->TtyP->tm.c_oflag; + PortP->StoredTty.cflag = PortP->TtyP->tm.c_cflag; + PortP->StoredTty.lflag = PortP->TtyP->tm.c_lflag; + PortP->StoredTty.line = PortP->TtyP->tm.c_line; + bcopy(PortP->TtyP->tm.c_cc, PortP->StoredTty.cc, + NCC + 5); + } + PortP->Lock = PortSetup.Lock; + PortP->Store = PortSetup.Store; + PortP->Xprint.XpCps = PortSetup.XpCps; + bcopy(PortSetup.XpOn,PortP->Xprint.XpOn,MAX_XP_CTRL_LEN); + bcopy(PortSetup.XpOff,PortP->Xprint.XpOff,MAX_XP_CTRL_LEN); + PortP->Xprint.XpOn[MAX_XP_CTRL_LEN-1] = '\0'; + PortP->Xprint.XpOff[MAX_XP_CTRL_LEN-1] = '\0'; + PortP->Xprint.XpLen = RIOStrlen(PortP->Xprint.XpOn)+ + RIOStrlen(PortP->Xprint.XpOff); + rio_spin_unlock_irqrestore( &PortP->portSem , flags); +#endif + } + 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 (copyin((int)arg, (caddr_t)&PortSetup, sizeof(PortSetup)) + == COPYFAIL ) { + 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; + bcopy(p->RIOPortp[port]->Xprint.XpOn, PortSetup.XpOn, + MAX_XP_CTRL_LEN); + bcopy(p->RIOPortp[port]->Xprint.XpOff, PortSetup.XpOff, + MAX_XP_CTRL_LEN); + PortSetup.XpOn[MAX_XP_CTRL_LEN-1] = '\0'; + PortSetup.XpOff[MAX_XP_CTRL_LEN-1] = '\0'; + + if ( copyout((caddr_t)&PortSetup,(int)arg,sizeof(PortSetup)) + ==COPYFAIL ) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return retval; + + case RIO_GET_PORT_PARAMS : + rio_dprintk (RIO_DEBUG_CTRL, "Get port params\n"); + if (copyin( (int)arg, (caddr_t)&PortParams, + sizeof(struct PortParams)) == COPYFAIL) { + 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 (copyout((caddr_t)&PortParams, (int)arg, + sizeof(struct PortParams)) == COPYFAIL ) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return retval; + + case RIO_GET_PORT_TTY : + rio_dprintk (RIO_DEBUG_CTRL, "Get port tty\n"); + if (copyin((int)arg, (caddr_t)&PortTty, sizeof(struct PortTty)) + == COPYFAIL) { + 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 0 + PortTty.Tty.tm.c_iflag = PortP->TtyP->tm.c_iflag; + PortTty.Tty.tm.c_oflag = PortP->TtyP->tm.c_oflag; + PortTty.Tty.tm.c_cflag = PortP->TtyP->tm.c_cflag; + PortTty.Tty.tm.c_lflag = PortP->TtyP->tm.c_lflag; +#endif + if (copyout((caddr_t)&PortTty, (int)arg, + sizeof(struct PortTty)) == COPYFAIL) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return retval; + + case RIO_SET_PORT_TTY : + if (copyin((int)arg, (caddr_t)&PortTty, + sizeof(struct PortTty)) == COPYFAIL) { + 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]); +#if 0 + rio_spin_lock_irqsave(&PortP->portSem, flags); + PortP->TtyP->tm.c_iflag = PortTty.Tty.tm.c_iflag; + PortP->TtyP->tm.c_oflag = PortTty.Tty.tm.c_oflag; + PortP->TtyP->tm.c_cflag = PortTty.Tty.tm.c_cflag; + PortP->TtyP->tm.c_lflag = PortTty.Tty.tm.c_lflag; + rio_spin_unlock_irqrestore( &PortP->portSem , flags); +#endif + + RIOParam(PortP, 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 ( copyin((int)arg, (caddr_t)&PortParams, sizeof(PortParams)) + == COPYFAIL ) { + 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 ( copyin((int)arg, (caddr_t)&portStats, + sizeof(struct portStats)) == COPYFAIL ) { + p->RIOError.Error = COPYIN_FAILED; + return -EFAULT; + } + if ( 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 ( copyout((caddr_t)&portStats, (int)arg, + sizeof(struct portStats)) == COPYFAIL ) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return retval; + + case RIO_RESET_PORT_STATS : + port = (uint) 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 ( copyin( (int)arg, (caddr_t)&portStats, + sizeof(struct portStats)) == COPYFAIL ) { + p->RIOError.Error = COPYIN_FAILED; + return -EFAULT; + } + if ( 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; + +#ifdef DEBUG_SUPPORTED + case RIO_READ_LEVELS: + { + int num; + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_LEVELS\n"); + for ( num=0; RIODbInf[num].Flag; num++ ) ; + rio_dprintk (RIO_DEBUG_CTRL, "%d levels to copy\n",num); + if (copyout((caddr_t)RIODbInf,(int)arg, + sizeof(struct DbInf)*(num+1))==COPYFAIL) { + rio_dprintk (RIO_DEBUG_CTRL, "ReadLevels Copy failed\n"); + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + rio_dprintk (RIO_DEBUG_CTRL, "%d levels to copied\n",num); + return retval; + } +#endif + + case RIO_READ_CONFIG: + rio_dprintk (RIO_DEBUG_CTRL, "RIO_READ_CONFIG\n"); + if (copyout((caddr_t)&p->RIOConf, (int)arg, + sizeof(struct Conf)) ==COPYFAIL ) { + 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 ( copyin((int)arg, (caddr_t)&p->RIOConf, sizeof(struct Conf) ) + ==COPYFAIL ) { + 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 ) + WWORD(p->RIOHosts[Host].ParmMapP->timer , + p->RIOConf.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 ( copyin( (int)arg, (caddr_t)&DebugCtrl, sizeof(DebugCtrl) ) + ==COPYFAIL ) { + 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 ( copyout((caddr_t)&DebugCtrl,(int)arg, + sizeof(DebugCtrl)) == COPYFAIL ) { + 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 ( copyout((caddr_t)&DebugCtrl,(int)arg, + sizeof(DebugCtrl))==COPYFAIL ) { + 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 ( copyout( (caddr_t)RIOVersid(), + (int)arg, + sizeof(struct rioVersion) ) == COPYFAIL ) + { + 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; + + /* + ** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ** !! commented out previous 'RIO_VERSID' functionality !! + ** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + ** + case RIO_VERSID: + ** + ** Enquire about the release and version. + ** We return MAX_VERSION_LEN bytes, being a textual null + ** terminated string. + ** + rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID\n")); + if (copyout((caddr_t)RIOVersid(), + (int)arg, MAX_VERSION_LEN ) == COPYFAIL ) { + rio_dprint(RIO_DEBUG_CTRL, ("RIO_VERSID: Bad copy to user space\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 (copyout((caddr_t)&p->RIONumHosts, (int)arg, + sizeof(p->RIONumHosts) )==COPYFAIL ) { + 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 %d\n", (int)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 ); + bzero( (caddr_t)&p->RIOHosts[Host].Flags, + ((int)&p->RIOHosts[Host].____end_marker____) - + ((int)&p->RIOHosts[Host].Flags) ); + p->RIOHosts[Host].Flags = RC_WAITING; +#if 0 + RIOSetupDataStructs(p); +#endif + } + RIOFoadWakeup(p); + p->RIONumBootPkts = 0; + p->RIOBooting = 0; + +#ifdef RINGBUFFER_SUPPORT + for( loop=0; loop<RIO_PORTS; loop++ ) + if ( p->RIOPortp[loop]->TxRingBuffer ) + sysfree((void *)p->RIOPortp[loop]->TxRingBuffer, + RIOBufferSize ); +#endif +#if 0 + bzero((caddr_t)&p->RIOPortp[0],RIO_PORTS*sizeof(struct Port)); +#else + printk ("HEEEEELP!\n"); +#endif + + for( loop=0; loop<RIO_PORTS; loop++ ) { +#if 0 + p->RIOPortp[loop]->TtyP = &p->channel[loop]; +#endif + + 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 ( copyin((int)arg, (caddr_t)&DownLoad, + sizeof(DownLoad) )==COPYFAIL ) { + 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: + { + uint host; + + if (copyin((int)arg, (caddr_t)&host, + sizeof(host) ) == COPYFAIL ) { + 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 ( copyout( (caddr_t)p->RIOHosts[host].ParmMapP, + (int)arg, sizeof(PARM_MAP) )==COPYFAIL ) { + 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 (copyin((int)arg, (caddr_t)&HostReq, + sizeof(HostReq) )==COPYFAIL ) { + 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 (copyout((caddr_t)&p->RIOHosts[HostReq.HostNum], + (int)HostReq.HostP,sizeof(struct Host) ) == COPYFAIL) { + 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 ( copyin( (int)arg, (caddr_t)&HostDpRam, + sizeof(HostDpRam) )==COPYFAIL ) { + 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] = p->RIOHosts[HostDpRam.HostNum].Caddr[off]; + if ( copyout( (caddr_t)copy, (int)HostDpRam.DpRamP, + sizeof(struct DpRam) ) == COPYFAIL ) { + p->RIOError.Error = COPYOUT_FAILED; + rio_dprintk (RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n"); + return -EFAULT; + } + } + else if (copyout((caddr_t)p->RIOHosts[HostDpRam.HostNum].Caddr, + (int)HostDpRam.DpRamP, + sizeof(struct DpRam) ) == COPYFAIL ) { + 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 ( (int)arg < 0 || (int)arg > 511 ) { + rio_dprintk (RIO_DEBUG_CTRL, "RIO_SET_BUSY: Bad port number %d\n",(int)arg); + p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE; + return -EINVAL; + } + rio_spin_lock_irqsave(&PortP->portSem, flags); + p->RIOPortp[(int)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 ( copyin((int)arg, (caddr_t)&PortReq, + sizeof(PortReq) )==COPYFAIL ) { + 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 (copyout((caddr_t)p->RIOPortp[PortReq.SysPort], + (int)PortReq.PortP, + sizeof(struct Port) ) == COPYFAIL) { + 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 (copyin((int)arg, (caddr_t)&RupReq, + sizeof(RupReq) )==COPYFAIL ) { + 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 (copyout((caddr_t)HostP->UnixRups[RupReq.RupNum].RupP, + (int)RupReq.RupP,sizeof(struct RUP) ) == COPYFAIL) { + 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 (copyin((int)arg, (caddr_t)&LpbReq, + sizeof(LpbReq) )==COPYFAIL ) { + 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 (copyout((caddr_t)&HostP->LinkStrP[LpbReq.Link], + (int)LpbReq.LpbP,sizeof(struct LPB) ) == COPYFAIL) { + 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; + } + p->RIOSignalProcess = getpid(); + p->RIOPrintDisabled = DONT_PRINT; + return retval; + + case RIO_SIGNALS_OFF: + if ( p->RIOSignalProcess != getpid() ) { + 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 = (uint) 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 ( copyin( (int)arg, (caddr_t)&SendPack, + sizeof(SendPack) )==COPYFAIL ) { + 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++ ) + WBYTE(PacketP->data[loop], SendPack.Data[loop] ); + + WBYTE(PacketP->len, SendPack.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 ( copyout( (caddr_t)&p->RIONoMessage, (int)arg, + sizeof(p->RIONoMessage) )==COPYFAIL ) { + 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 (copyin((int)arg, (caddr_t)&SubCmd, + sizeof(struct SubCmdStruct)) == COPYFAIL) { + 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, 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 ( copyout( (caddr_t)p->RIOMemDump, (int)arg, + MEMDUMP_SIZE) == COPYFAIL ) { + rio_dprintk (RIO_DEBUG_CTRL, "RIO_MEM_DUMP copy failed\n"); + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return 0; + + case RIO_TICK: + if ((int)arg < 0 || (int)arg >= p->RIONumHosts) + return -EINVAL; + rio_dprintk (RIO_DEBUG_CTRL, "Set interrupt for host %d\n", (int)arg); + WBYTE(p->RIOHosts[(int)arg].SetInt , 0xff); + return 0; + + case RIO_TOCK: + if ((int)arg < 0 || (int)arg >= p->RIONumHosts) + return -EINVAL; + rio_dprintk (RIO_DEBUG_CTRL, "Clear interrupt for host %d\n", (int)arg); + WBYTE((p->RIOHosts[(int)arg].ResetInt) , 0xff); + return 0; + + case RIO_READ_CHECK: + /* Check reads for pkts with data[0] the same */ + p->RIOReadCheck = !p->RIOReadCheck; + if (copyout((caddr_t)&p->RIOReadCheck,(int)arg, + sizeof(uint))== COPYFAIL) { + p->RIOError.Error = COPYOUT_FAILED; + return -EFAULT; + } + return 0; + + case RIO_READ_REGISTER : + if (copyin((int)arg, (caddr_t)&SubCmd, + sizeof(struct SubCmdStruct)) == COPYFAIL) { + 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, 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 (copyout((caddr_t)&p->CdRegister, (int)arg, + sizeof(uint)) == COPYFAIL ) { + 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: + { + uint port = (uint)arg & RIO_MODEM_MASK; + + switch ( (uint)arg & RIO_DEV_MASK ) { + case RIO_DEV_DIRECT: + arg = (caddr_t)drv_makedev(MAJOR(dev), port); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev direct 0x%x is 0x%x\n",port, (int)arg); + return (int)arg; + case RIO_DEV_MODEM: + arg = (caddr_t)drv_makedev(MAJOR(dev), (port|RIO_MODEM_BIT) ); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev modem 0x%x is 0x%x\n",port, (int)arg); + return (int)arg; + case RIO_DEV_XPRINT: + arg = (caddr_t)drv_makedev(MAJOR(dev), port); + rio_dprintk (RIO_DEBUG_CTRL, "Makedev printer 0x%x is 0x%x\n",port, (int)arg); + return (int)arg; + } + 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; + + dv = (dev_t)((int)arg); + mino = RIO_UNMODEM(dv); + + if ( RIO_ISMODEM(dv) ) { + rio_dprintk (RIO_DEBUG_CTRL, "Minor for device 0x%x: modem %d\n", dv, mino); + arg = (caddr_t)(mino | RIO_DEV_MODEM); + } + else { + rio_dprintk (RIO_DEBUG_CTRL, "Minor for device 0x%x: direct %d\n", dv, mino); + arg = (caddr_t)(mino | RIO_DEV_DIRECT); + } + return (int)arg; + } + } + 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(p, PortP, Cmd) +struct rio_info * p; +struct Port *PortP; +uchar Cmd; +{ + struct CmdBlk *CmdBlkP; + struct PktCmd_M *PktCmdP; + int Ret; + ushort rup; + int port; + +#ifdef CHECK + CheckPortP( PortP ); +#endif + + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_CTRL, "Preemptive command to deleted RTA ignored\n"); + return RIO_FAIL; + } + + if (((int)((char)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 0x%x - InUse now %d\n", + (int)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 = (int)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 MEMDUMP: + rio_dprintk (RIO_DEBUG_CTRL, "Queue MEMDUMP command blk 0x%x (addr 0x%x)\n", + (int)CmdBlkP, (int)SubCmd.Addr); + PktCmdP->SubCommand = MEMDUMP; + PktCmdP->SubAddr = SubCmd.Addr; + break; + case FCLOSE: + rio_dprintk (RIO_DEBUG_CTRL, "Queue FCLOSE command blk 0x%x\n",(int)CmdBlkP); + break; + case READ_REGISTER: + rio_dprintk (RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) command blk 0x%x\n", + (int)SubCmd.Addr, (int)CmdBlkP); + PktCmdP->SubCommand = READ_REGISTER; + PktCmdP->SubAddr = SubCmd.Addr; + break; + case RESUME: + rio_dprintk (RIO_DEBUG_CTRL, "Queue RESUME command blk 0x%x\n",(int)CmdBlkP); + break; + case RFLUSH: + rio_dprintk (RIO_DEBUG_CTRL, "Queue RFLUSH command blk 0x%x\n",(int)CmdBlkP); + CmdBlkP->PostFuncP = RIORFlushEnable; + break; + case SUSPEND: + rio_dprintk (RIO_DEBUG_CTRL, "Queue SUSPEND command blk 0x%x\n",(int)CmdBlkP); + break; + + case MGET : + rio_dprintk (RIO_DEBUG_CTRL, "Queue MGET command blk 0x%x\n", (int)CmdBlkP); + break; + + case MSET : + case MBIC : + case MBIS : + CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; + rio_dprintk (RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command blk 0x%x\n", (int)CmdBlkP); + break; + + case 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 ((int)((char)PortP->WflushFlag) == (int)-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 0x%x\n", + (int)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 000000000000..bc38ac5dfbde --- /dev/null +++ b/drivers/char/rio/riodrvr.h @@ -0,0 +1,144 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 */ + +#ifdef SCCS_LABELS +static char *_riodrvr_h_sccs_ = "@(#)riodrvr.h 1.3"; +#endif + +#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 */ + uint RIOReadCheck; /* Rio read check */ + uint RIONoMessage; /* To display message or not */ + uint RIONumBootPkts; /* how many packets for an RTA */ + uint RIOBootCount; /* size of RTA code */ + uint RIOBooting; /* count of outstanding boots */ + uint RIOSystemUp; /* Booted ?? */ + uint RIOCounting; /* for counting interrupts */ + uint RIOIntCount; /* # of intr since last check */ + uint RIOTxCount; /* number of xmit intrs */ + uint RIORxCount; /* number of rx intrs */ + uint RIORupCount; /* number of rup intrs */ + int RIXTimer; + int RIOBufferSize; /* Buffersize */ + int RIOBufferMask; /* Buffersize */ + + int RIOFirstMajor; /* First host card's major no */ + + uint RIOLastPortsMapped; /* highest port number known */ + uint RIOFirstPortsMapped; /* lowest port number known */ + + uint RIOLastPortsBooted; /* highest port number running */ + uint RIOFirstPortsBooted; /* lowest port number running */ + + uint RIOLastPortsOpened; /* highest port number running */ + uint RIOFirstPortsOpened; /* lowest port number running */ + + /* Flag to say that the topology information has been changed. */ + uint RIOQuickCheck; + uint CdRegister; /* ??? */ + int RIOSignalProcess; /* Signalling process */ + int rio_debug; /* To debug ... */ + int RIODebugWait; /* For what ??? */ + int tpri; /* Thread prio */ + int tid; /* Thread id */ + uint _RIO_Polled; /* Counter for polling */ + uint _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 */ + ulong RIOBindTab[MAX_RTA_BINDINGS]; + /* RTA memory dump variable */ + uchar 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 +#define WRBYTE(x,y) *(volatile unsigned char *)((x)) = \ + (unsigned char)(y) + +#endif /* __riodrvr.h */ diff --git a/drivers/char/rio/rioinfo.h b/drivers/char/rio/rioinfo.h new file mode 100644 index 000000000000..e08421c9558e --- /dev/null +++ b/drivers/char/rio/rioinfo.h @@ -0,0 +1,96 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 + +#ifdef SCCS_LABELS +static char *_rioinfo_h_sccs_ = "@(#)rioinfo.h 1.2"; +#endif + +/* +** 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 000000000000..dca941ed10cf --- /dev/null +++ b/drivers/char/rio/rioinit.c @@ -0,0 +1,1617 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3"; +#endif + +#include <linux/config.h> +#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/semaphore.h> +#include <asm/uaccess.h> + +#include <linux/termios.h> +#include <linux/serial.h> + +#include <linux/generic_serial.h> + + +#include "linux_compat.h" +#include "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" +#include "rio_linux.h" + +#undef bcopy +#define bcopy rio_pcicopy + +int RIOPCIinit(struct rio_info *p, int Mode); + +#if 0 +static void RIOAllocateInterrupts(struct rio_info *); +static int RIOReport(struct rio_info *); +static void RIOStopInterrupts(struct rio_info *, int, int); +#endif + +static int RIOScrub(int, BYTE *, int); + +#if 0 +extern int rio_intr(); + +/* +** Init time code. +*/ +void +rioinit( p, info ) +struct rio_info * p; +struct RioHostInfo * info; +{ + /* + ** Multi-Host card support - taking the easy way out - sorry ! + ** We allocate and set up the Host and Port structs when the + ** driver is called to 'install' the first host. + ** We check for this first 'call' by testing the RIOPortp pointer. + */ + if ( !p->RIOPortp ) + { + rio_dprintk (RIO_DEBUG_INIT, "Allocating and setting up driver data structures\n"); + + RIOAllocDataStructs(p); /* allocate host/port structs */ + RIOSetupDataStructs(p); /* setup topology structs */ + } + + RIOInitHosts( p, info ); /* hunt down the hardware */ + + RIOAllocateInterrupts(p); /* allocate interrupts */ + RIOReport(p); /* show what we found */ +} + +/* +** Initialise the Cards +*/ +void +RIOInitHosts(p, info) +struct rio_info * p; +struct RioHostInfo * info; +{ +/* +** 15.10.1998 ARG - ESIL 0762 part fix +** If there is no ISA card definition - we always look for PCI cards. +** As we currently only support one host card this lets an ISA card +** definition take precedence over PLUG and PLAY. +** No ISA card - we are PLUG and PLAY with PCI. +*/ + + /* + ** Note - for PCI both these will be zero, that's okay because + ** RIOPCIInit() fills them in if a card is found. + */ + p->RIOHosts[p->RIONumHosts].Ivec = info->vector; + p->RIOHosts[p->RIONumHosts].PaddrP = info->location; + + /* + ** Check that we are able to accommodate another host + */ + if ( p->RIONumHosts >= RIO_HOSTS ) + { + p->RIOFailed++; + return; + } + + if ( info->bus & ISA_BUS ) + { + rio_dprintk (RIO_DEBUG_INIT, "initialising card %d (ISA)\n", p->RIONumHosts); + RIOISAinit(p, p->mode); + } + else + { + rio_dprintk (RIO_DEBUG_INIT, "initialising card %d (PCI)\n", p->RIONumHosts); + RIOPCIinit(p, RIO_PCI_DEFAULT_MODE); + } + + rio_dprintk (RIO_DEBUG_INIT, "Total hosts initialised so far : %d\n", p->RIONumHosts); + + +#ifdef FUTURE_RELEASE + if (p->bus & EISA_BUS) + /* EISA card */ + RIOEISAinit(p, RIO_EISA_DEFAULT_MODE); + + if (p->bus & MCA_BUS) + /* MCA card */ + RIOMCAinit(p, RIO_MCA_DEFAULT_MODE); +#endif +} + +/* +** go through memory for an AT host that we pass in the device info +** structure and initialise +*/ +void +RIOISAinit(p, mode) +struct rio_info * p; +int mode; +{ + + /* XXX Need to implement this. */ +#if 0 + p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec, + (int (*)())rio_intr, (char*)p->RIONumHosts); + + rio_dprintk (RIO_DEBUG_INIT, "Set interrupt handler, intr_tid = 0x%x\n", p->intr_tid ); + + if (RIODoAT(p, p->RIOHosts[p->RIONumHosts].PaddrP, mode)) { + return; + } + else { + rio_dprintk (RIO_DEBUG_INIT, "RIODoAT failed\n"); + p->RIOFailed++; + } +#endif + +} + +/* +** RIODoAT : +** +** Map in a boards physical address, check that the board is there, +** test the board and if everything is okay assign the board an entry +** in the Rio Hosts structure. +*/ +int +RIODoAT(p, Base, mode) +struct rio_info * p; +int Base; +int mode; +{ +#define FOUND 1 +#define NOT_FOUND 0 + + caddr_t cardAddr; + + /* + ** Check to see if we actually have a board at this physical address. + */ + if ((cardAddr = RIOCheckForATCard(Base)) != 0) { + /* + ** Now test the board to see if it is working. + */ + if (RIOBoardTest(Base, cardAddr, RIO_AT, 0) == RIO_SUCCESS) { + /* + ** Fill out a slot in the Rio host structure. + */ + if (RIOAssignAT(p, Base, cardAddr, mode)) { + return(FOUND); + } + } + RIOMapout(Base, RIO_AT_MEM_SIZE, cardAddr); + } + return(NOT_FOUND); +} + +caddr_t +RIOCheckForATCard(Base) +int Base; +{ + int off; + struct DpRam *cardp; /* (Points at the host) */ + caddr_t virtAddr; + unsigned char RIOSigTab[24]; +/* +** Table of values to search for as prom signature of a host card +*/ + strcpy(RIOSigTab, "JBJGPGGHINSMJPJR"); + + /* + ** Hey! Yes, You reading this code! Yo, grab a load a this: + ** + ** IF the card is using WORD MODE rather than BYTE MODE + ** then it will occupy 128K of PHYSICAL memory area. So, + ** you might think that the following Mapin is wrong. Well, + ** it isn't, because the SECOND 64K of occupied space is an + ** EXACT COPY of the FIRST 64K. (good?), so, we need only + ** map it in in one 64K block. + */ + if (RIOMapin(Base, RIO_AT_MEM_SIZE, &virtAddr) == -1) { + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Couldn't map the board in!\n"); + return((caddr_t)0); + } + + /* + ** virtAddr points to the DP ram of the system. + ** We now cast this to a pointer to a RIO Host, + ** and have a rummage about in the PROM. + */ + cardp = (struct DpRam *)virtAddr; + + for (off=0; RIOSigTab[off]; off++) { + if ((RBYTE(cardp->DpSignature[off]) & 0xFF) != RIOSigTab[off]) { + /* + ** Signature mismatch - card not at this address + */ + RIOMapout(Base, RIO_AT_MEM_SIZE, virtAddr); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Couldn't match the signature 0x%x 0x%x!\n", + (int)cardp, off); + return((caddr_t)0); + } + } + + /* + ** If we get here then we must have found a valid board so return + ** its virtual address. + */ + return(virtAddr); +} +#endif + +/** +** 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(p, Base, virtAddr, mode) +struct rio_info * p; +int Base; +caddr_t virtAddr; +int mode; +{ + int bits; + struct DpRam *cardp = (struct DpRam *)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 = (struct DpRam *)virtAddr; + + /* + ** Revision 01 AT host cards don't support WORD operations, + */ + if ( RBYTE(cardp->DpRevision) == 01 ) + bits = BYTE_OPERATION; + + p->RIOHosts[p->RIONumHosts].Type = RIO_AT; + p->RIOHosts[p->RIONumHosts].Copy = bcopy; + /* set this later */ + p->RIOHosts[p->RIONumHosts].Slot = -1; + p->RIOHosts[p->RIONumHosts].Mode = SLOW_LINKS | SLOW_AT_BUS | bits; + WBYTE(p->RIOHosts[p->RIONumHosts].Control, + BOOT_FROM_RAM | EXTERNAL_BUS_OFF | + p->RIOHosts[p->RIONumHosts].Mode | + INTERRUPT_DISABLE ); + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff); + WBYTE(p->RIOHosts[p->RIONumHosts].Control, + BOOT_FROM_RAM | EXTERNAL_BUS_OFF | + p->RIOHosts[p->RIONumHosts].Mode | + INTERRUPT_DISABLE ); + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff); + p->RIOHosts[p->RIONumHosts].UniqueNum = + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)| + ((RBYTE(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); +} +#if 0 +#ifdef FUTURE_RELEASE +int RIOMCAinit(int Mode) +{ + uchar SlotNumber; + caddr_t Caddr; + uint Paddr; + uint Ivec; + int Handle; + int ret = 0; + + /* + ** Valid mode information for MCA cards + ** is only FAST LINKS + */ + Mode = (Mode & FAST_LINKS) ? McaTpFastLinks : McaTpSlowLinks; + rio_dprintk (RIO_DEBUG_INIT, "RIOMCAinit(%d)\n",Mode); + + + /* + ** Check out each of the slots + */ + for (SlotNumber = 0; SlotNumber < McaMaxSlots; SlotNumber++) { + /* + ** Enable the slot we want to talk to + */ + outb( McaSlotSelect, SlotNumber | McaSlotEnable ); + + /* + ** Read the ID word from the slot + */ + if (((inb(McaIdHigh)<< 8)|inb(McaIdLow)) == McaRIOId) + { + rio_dprintk (RIO_DEBUG_INIT, "Potential MCA card in slot %d\n", SlotNumber); + + /* + ** Card appears to be a RIO MCA card! + */ + RIOMachineType |= (1<<RIO_MCA); + + /* + ** Just check we haven't found too many wonderful objects + */ + if ( RIONumHosts >= RIO_HOSTS ) + { + Rprintf(RIOMesgTooManyCards); + return(ret); + } + + /* + ** McaIrqEnable contains the interrupt vector, and a card + ** enable bit. + */ + Ivec = inb(McaIrqEnable); + + rio_dprintk (RIO_DEBUG_INIT, "Ivec is %x\n", Ivec); + + switch ( Ivec & McaIrqMask ) + { + case McaIrq9: + rio_dprintk (RIO_DEBUG_INIT, "IRQ9\n"); + break; + case McaIrq3: + rio_dprintk (RIO_DEBUG_INIT, "IRQ3\n"); + break; + case McaIrq4: + rio_dprintk (RIO_DEBUG_INIT, "IRQ4\n"); + break; + case McaIrq7: + rio_dprintk (RIO_DEBUG_INIT, "IRQ7\n"); + break; + case McaIrq10: + rio_dprintk (RIO_DEBUG_INIT, "IRQ10\n"); + break; + case McaIrq11: + rio_dprintk (RIO_DEBUG_INIT, "IRQ11\n"); + break; + case McaIrq12: + rio_dprintk (RIO_DEBUG_INIT, "IRQ12\n"); + break; + case McaIrq15: + rio_dprintk (RIO_DEBUG_INIT, "IRQ15\n"); + break; + } + + /* + ** If the card enable bit isn't set, then set it! + */ + if ((Ivec & McaCardEnable) != McaCardEnable) { + rio_dprintk (RIO_DEBUG_INIT, "McaCardEnable not set - setting!\n"); + outb(McaIrqEnable,Ivec|McaCardEnable); + } else + rio_dprintk (RIO_DEBUG_INIT, "McaCardEnable already set\n"); + + /* + ** Convert the IRQ enable mask into something useful + */ + Ivec = RIOMcaToIvec[Ivec & McaIrqMask]; + + /* + ** Find the physical address + */ + rio_dprintk (RIO_DEBUG_INIT, "inb(McaMemory) is %x\n", inb(McaMemory)); + Paddr = McaAddress(inb(McaMemory)); + + rio_dprintk (RIO_DEBUG_INIT, "MCA card has Ivec %d Addr %x\n", Ivec, Paddr); + + if ( Paddr != 0 ) + { + + /* + ** Tell the memory mapper that we want to talk to it + */ + Handle = RIOMapin( Paddr, RIO_MCA_MEM_SIZE, &Caddr ); + + if ( Handle == -1 ) { + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at %x\n", RIO_MCA_MEM_SIZE, Paddr; + continue; + } + + rio_dprintk (RIO_DEBUG_INIT, "Board mapped to vaddr 0x%x\n", Caddr); + + /* + ** And check that it is actually there! + */ + if ( RIOBoardTest( Paddr,Caddr,RIO_MCA,SlotNumber ) == RIO_SUCCESS ) + { + rio_dprintk (RIO_DEBUG_INIT, "Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", + SlotNumber, RIO_MCA, Paddr, Caddr, Mode); + + /* + ** Board has passed its scrub test. Fill in all the + ** transient stuff. + */ + p->RIOHosts[RIONumHosts].Slot = SlotNumber; + p->RIOHosts[RIONumHosts].Ivec = Ivec; + p->RIOHosts[RIONumHosts].Type = RIO_MCA; + p->RIOHosts[RIONumHosts].Copy = bcopy; + p->RIOHosts[RIONumHosts].PaddrP = Paddr; + p->RIOHosts[RIONumHosts].Caddr = Caddr; + p->RIOHosts[RIONumHosts].CardP = (struct DpRam *)Caddr; + p->RIOHosts[RIONumHosts].Mode = Mode; + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt , 0xff); + p->RIOHosts[RIONumHosts].UniqueNum = + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[0])&0xFF)<<0)| + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[1])&0xFF)<<8)| + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[2])&0xFF)<<16)| + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[3])&0xFF)<<24); + RIONumHosts++; + ret++; + } + else + { + /* + ** It failed the test, so ignore it. + */ + rio_dprintk (RIO_DEBUG_INIT, "TEST FAILED\n"); + RIOMapout(Paddr, RIO_MCA_MEM_SIZE, Caddr ); + } + } + else + { + rio_dprintk (RIO_DEBUG_INIT, "Slot %d - Paddr zero!\n", SlotNumber); + } + } + else + { + rio_dprintk (RIO_DEBUG_INIT, "Slot %d NOT RIO\n", SlotNumber); + } + } + /* + ** Now we have checked all the slots, turn off the MCA slot selector + */ + outb(McaSlotSelect,0); + rio_dprintk (RIO_DEBUG_INIT, "Slot %d NOT RIO\n", SlotNumber); + return ret; +} + +int RIOEISAinit( int Mode ) +{ + static int EISADone = 0; + uint Paddr; + int PollIntMixMsgDone = 0; + caddr_t Caddr; + ushort Ident; + uchar EisaSlot; + uchar Ivec; + int ret = 0; + + /* + ** The only valid mode information for EISA hosts is fast or slow + ** links. + */ + Mode = (Mode & FAST_LINKS) ? EISA_TP_FAST_LINKS : EISA_TP_SLOW_LINKS; + + if ( EISADone ) + { + rio_dprintk (RIO_DEBUG_INIT, "RIOEISAinit() - already done, return.\n"); + return(0); + } + + EISADone++; + + rio_dprintk (RIO_DEBUG_INIT, "RIOEISAinit()\n"); + + + /* + ** First check all cards to see if ANY are set for polled mode operation. + ** If so, set ALL to polled. + */ + + for ( EisaSlot=1; EisaSlot<=RIO_MAX_EISA_SLOTS; EisaSlot++ ) + { + Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) | + INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO); + + if ( Ident == RIO_EISA_IDENT ) + { + rio_dprintk (RIO_DEBUG_INIT, "Found Specialix product\n"); + + if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE ) + { + rio_dprintk (RIO_DEBUG_INIT, "Not Specialix RIO - Product number %x\n", + INBZ(EisaSlot, EISA_PRODUCT_NUMBER)); + continue; /* next slot */ + } + /* + ** Its a Specialix RIO! + */ + rio_dprintk (RIO_DEBUG_INIT, "RIO Revision %d\n", + INBZ(EisaSlot, EISA_REVISION_NUMBER)); + + RIOMachineType |= (1<<RIO_EISA); + + /* + ** Just check we haven't found too many wonderful objects + */ + if ( RIONumHosts >= RIO_HOSTS ) + { + Rprintf(RIOMesgTooManyCards); + return 0; + } + + /* + ** Ensure that the enable bit is set! + */ + OUTBZ( EisaSlot, EISA_ENABLE, RIO_EISA_ENABLE_BIT ); + + /* + ** EISA_INTERRUPT_VEC contains the interrupt vector. + */ + Ivec = INBZ(EisaSlot,EISA_INTERRUPT_VEC); + +#ifdef RIODEBUG + switch ( Ivec & EISA_INTERRUPT_MASK ) + { + case EISA_IRQ_3: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 3\n"); + break; + case EISA_IRQ_4: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 4\n"); + break; + case EISA_IRQ_5: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 5\n"); + break; + case EISA_IRQ_6: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 6\n"); + break; + case EISA_IRQ_7: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 7\n"); + break; + case EISA_IRQ_9: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 9\n"); + break; + case EISA_IRQ_10: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 10\n"); + break; + case EISA_IRQ_11: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 11\n"); + break; + case EISA_IRQ_12: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 12\n"); + break; + case EISA_IRQ_14: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 14\n"); + break; + case EISA_IRQ_15: + rio_dprintk (RIO_DEBUG_INIT, "EISA IRQ 15\n"); + break; + case EISA_POLLED: + rio_dprintk (RIO_DEBUG_INIT, "EISA POLLED\n"); + break; + default: + rio_dprintk (RIO_DEBUG_INIT, NULL,DBG_INIT|DBG_FAIL,"Shagged interrupt number!\n"); + Ivec &= EISA_CONTROL_MASK; + } +#endif + + if ( (Ivec & EISA_INTERRUPT_MASK) == + EISA_POLLED ) + { + RIOWillPoll = 1; + break; /* From EisaSlot loop */ + } + } + } + + /* + ** Do it all again now we know whether to change all cards to polled + ** mode or not + */ + + for ( EisaSlot=1; EisaSlot<=RIO_MAX_EISA_SLOTS; EisaSlot++ ) + { + Ident = (INBZ(EisaSlot,EISA_PRODUCT_IDENT_HI)<<8) | + INBZ(EisaSlot,EISA_PRODUCT_IDENT_LO); + + if ( Ident == RIO_EISA_IDENT ) + { + if ( INBZ(EisaSlot,EISA_PRODUCT_NUMBER) != RIO_EISA_PRODUCT_CODE ) + continue; /* next slot */ + + /* + ** Its a Specialix RIO! + */ + + /* + ** Ensure that the enable bit is set! + */ + OUTBZ( EisaSlot, EISA_ENABLE, RIO_EISA_ENABLE_BIT ); + + /* + ** EISA_INTERRUPT_VEC contains the interrupt vector. + */ + Ivec = INBZ(EisaSlot,EISA_INTERRUPT_VEC); + + if ( RIOWillPoll ) + { + /* + ** If we are going to operate in polled mode, but this + ** board is configured to be interrupt driven, display + ** the message explaining the situation to the punter, + ** assuming we haven't already done so. + */ + + if ( !PollIntMixMsgDone && + (Ivec & EISA_INTERRUPT_MASK) != EISA_POLLED ) + { + Rprintf(RIOMesgAllPolled); + PollIntMixMsgDone = 1; + } + + /* + ** Ungraciously ignore whatever the board reports as its + ** interrupt vector... + */ + + Ivec &= ~EISA_INTERRUPT_MASK; + + /* + ** ...and force it to dance to the poll tune. + */ + + Ivec |= EISA_POLLED; + } + + /* + ** Convert the IRQ enable mask into something useful (0-15) + */ + Ivec = RIOEisaToIvec(Ivec); + + rio_dprintk (RIO_DEBUG_INIT, "EISA host in slot %d has Ivec 0x%x\n", + EisaSlot, Ivec); + + /* + ** Find the physical address + */ + Paddr = (INBZ(EisaSlot,EISA_MEMORY_BASE_HI)<<24) | + (INBZ(EisaSlot,EISA_MEMORY_BASE_LO)<<16); + + rio_dprintk (RIO_DEBUG_INIT, "EISA card has Ivec %d Addr %x\n", Ivec, Paddr); + + if ( Paddr == 0 ) + { + rio_dprintk (RIO_DEBUG_INIT, + "Board in slot %d configured for address zero!\n", EisaSlot); + continue; + } + + /* + ** Tell the memory mapper that we want to talk to it + */ + rio_dprintk (RIO_DEBUG_INIT, "About to map EISA card \n"); + + if (RIOMapin( Paddr, RIO_EISA_MEM_SIZE, &Caddr) == -1) { + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at %x\n", + RIO_EISA_MEM_SIZE,Paddr); + continue; + } + + rio_dprintk (RIO_DEBUG_INIT, "Board mapped to vaddr 0x%x\n", Caddr); + + /* + ** And check that it is actually there! + */ + if ( RIOBoardTest( Paddr,Caddr,RIO_EISA,EisaSlot) == RIO_SUCCESS ) + { + rio_dprintk (RIO_DEBUG_INIT, "Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, + "Slot %d. Ivec %d. Type %d. Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", + EisaSlot,Ivec,RIO_EISA,Paddr,Caddr,Mode); + + /* + ** Board has passed its scrub test. Fill in all the + ** transient stuff. + */ + p->RIOHosts[RIONumHosts].Slot = EisaSlot; + p->RIOHosts[RIONumHosts].Ivec = Ivec; + p->RIOHosts[RIONumHosts].Type = RIO_EISA; + p->RIOHosts[RIONumHosts].Copy = bcopy; + p->RIOHosts[RIONumHosts].PaddrP = Paddr; + p->RIOHosts[RIONumHosts].Caddr = Caddr; + p->RIOHosts[RIONumHosts].CardP = (struct DpRam *)Caddr; + p->RIOHosts[RIONumHosts].Mode = Mode; + /* + ** because the EISA prom is mapped into IO space, we + ** need to copy the unqiue number into the memory area + ** that it would have occupied, so that the download + ** code can determine its ID and card type. + */ + WBYTE(p->RIOHosts[RIONumHosts].Unique[0],INBZ(EisaSlot,EISA_UNIQUE_NUM_0)); + WBYTE(p->RIOHosts[RIONumHosts].Unique[1],INBZ(EisaSlot,EISA_UNIQUE_NUM_1)); + WBYTE(p->RIOHosts[RIONumHosts].Unique[2],INBZ(EisaSlot,EISA_UNIQUE_NUM_2)); + WBYTE(p->RIOHosts[RIONumHosts].Unique[3],INBZ(EisaSlot,EISA_UNIQUE_NUM_3)); + p->RIOHosts[RIONumHosts].UniqueNum = + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[0])&0xFF)<<0)| + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[1])&0xFF)<<8)| + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[2])&0xFF)<<16)| + ((RBYTE(p->RIOHosts[RIONumHosts].Unique[3])&0xFF)<<24); + INBZ(EisaSlot,EISA_INTERRUPT_RESET); + RIONumHosts++; + ret++; + } + else + { + /* + ** It failed the test, so ignore it. + */ + rio_dprintk (RIO_DEBUG_INIT, "TEST FAILED\n"); + + RIOMapout(Paddr, RIO_EISA_MEM_SIZE, Caddr ); + } + } + } + if (RIOMachineType & RIO_EISA) + return ret+1; + return ret; +} +#endif + + +#ifndef linux + +#define CONFIG_ADDRESS 0xcf8 +#define CONFIG_DATA 0xcfc +#define FORWARD_REG 0xcfa + + +static int +read_config(int bus_number, int device_num, int r_number) +{ + unsigned int cav; + unsigned int val; + +/* + Build config_address_value: + + 31 24 23 16 15 11 10 8 7 0 + ------------------------------------------------------ + |1| 0000000 | bus_number | device # | 000 | register | + ------------------------------------------------------ +*/ + + cav = r_number & 0xff; + cav |= ((device_num & 0x1f) << 11); + cav |= ((bus_number & 0xff) << 16); + cav |= 0x80000000; /* Enable bit */ + outpd(CONFIG_ADDRESS,cav); + val = inpd(CONFIG_DATA); + outpd(CONFIG_ADDRESS,0); + return val; +} + +static +write_config(bus_number,device_num,r_number,val) +{ + unsigned int cav; + +/* + Build config_address_value: + + 31 24 23 16 15 11 10 8 7 0 + ------------------------------------------------------ + |1| 0000000 | bus_number | device # | 000 | register | + ------------------------------------------------------ +*/ + + cav = r_number & 0xff; + cav |= ((device_num & 0x1f) << 11); + cav |= ((bus_number & 0xff) << 16); + cav |= 0x80000000; /* Enable bit */ + outpd(CONFIG_ADDRESS, cav); + outpd(CONFIG_DATA, val); + outpd(CONFIG_ADDRESS, 0); + return val; +} +#else +/* XXX Implement these... */ +static int +read_config(int bus_number, int device_num, int r_number) +{ + return 0; +} + +static int +write_config(int bus_number, int device_num, int r_number) +{ + return 0; +} + +#endif + +int +RIOPCIinit(p, Mode) +struct rio_info *p; +int Mode; +{ + #define MAX_PCI_SLOT 32 + #define RIO_PCI_JET_CARD 0x200011CB + + static int slot; /* count of machine's PCI slots searched so far */ + caddr_t Caddr; /* Virtual address of the current PCI host card. */ + unsigned char Ivec; /* interrupt vector for the current PCI host */ + unsigned long Paddr; /* Physical address for the current PCI host */ + int Handle; /* Handle to Virtual memory allocated for current PCI host */ + + + rio_dprintk (RIO_DEBUG_INIT, "Search for a RIO PCI card - start at slot %d\n", slot); + + /* + ** Initialise the search status + */ + p->RIOLastPCISearch = RIO_FAIL; + + while ( (slot < MAX_PCI_SLOT) & (p->RIOLastPCISearch != RIO_SUCCESS) ) + { + rio_dprintk (RIO_DEBUG_INIT, "Currently testing slot %d\n", slot); + + if (read_config(0,slot,0) == RIO_PCI_JET_CARD) { + p->RIOHosts[p->RIONumHosts].Ivec = 0; + Paddr = read_config(0,slot,0x18); + Paddr = Paddr - (Paddr & 0x1); /* Mask off the io bit */ + + if ( (Paddr == 0) || ((Paddr & 0xffff0000) == 0xffff0000) ) { + rio_dprintk (RIO_DEBUG_INIT, "Goofed up slot\n"); /* what! */ + slot++; + continue; + } + + p->RIOHosts[p->RIONumHosts].PaddrP = Paddr; + Ivec = (read_config(0,slot,0x3c) & 0xff); + + rio_dprintk (RIO_DEBUG_INIT, "PCI Host at 0x%x, Intr %d\n", (int)Paddr, Ivec); + + Handle = RIOMapin( Paddr, RIO_PCI_MEM_SIZE, &Caddr ); + if (Handle == -1) { + rio_dprintk (RIO_DEBUG_INIT, "Couldn't map %d bytes at 0x%x\n", RIO_PCI_MEM_SIZE, (int)Paddr); + slot++; + continue; + } + p->RIOHosts[p->RIONumHosts].Ivec = Ivec + 32; + p->intr_tid = iointset(p->RIOHosts[p->RIONumHosts].Ivec, + (int (*)())rio_intr, (char *)p->RIONumHosts); + if (RIOBoardTest( Paddr, Caddr, RIO_PCI, 0 ) == RIO_SUCCESS) { + rio_dprintk (RIO_DEBUG_INIT, ("Board has passed test\n"); + rio_dprintk (RIO_DEBUG_INIT, ("Paddr 0x%x. Caddr 0x%x. Mode 0x%x.\n", Paddr, Caddr, Mode); + + /* + ** Board has passed its scrub test. Fill in all the + ** transient stuff. + */ + p->RIOHosts[p->RIONumHosts].Slot = 0; + p->RIOHosts[p->RIONumHosts].Ivec = Ivec + 32; + p->RIOHosts[p->RIONumHosts].Type = RIO_PCI; + p->RIOHosts[p->RIONumHosts].Copy = rio_pcicopy; + p->RIOHosts[p->RIONumHosts].PaddrP = Paddr; + p->RIOHosts[p->RIONumHosts].Caddr = Caddr; + p->RIOHosts[p->RIONumHosts].CardP = (struct DpRam *)Caddr; + p->RIOHosts[p->RIONumHosts].Mode = Mode; + +#if 0 + WBYTE(p->RIOHosts[p->RIONumHosts].Control, + BOOT_FROM_RAM | EXTERNAL_BUS_OFF | + p->RIOHosts[p->RIONumHosts].Mode | + INTERRUPT_DISABLE ); + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff); + WBYTE(p->RIOHosts[p->RIONumHosts].Control, + BOOT_FROM_RAM | EXTERNAL_BUS_OFF | + p->RIOHosts[p->RIONumHosts].Mode | + INTERRUPT_DISABLE ); + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt,0xff); +#else + WBYTE(p->RIOHosts[p->RIONumHosts].ResetInt, 0xff); +#endif + p->RIOHosts[p->RIONumHosts].UniqueNum = + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)| + ((RBYTE(p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24); + + rio_dprintk (RIO_DEBUG_INIT, "Unique no 0x%x.\n", + p->RIOHosts[p->RIONumHosts].UniqueNum); + + p->RIOLastPCISearch = RIO_SUCCESS; + p->RIONumHosts++; + } + } + slot++; + } + + if ( slot >= MAX_PCI_SLOT ) { + rio_dprintk (RIO_DEBUG_INIT, "All %d PCI slots have tested for RIO cards !!!\n", + MAX_PCI_SLOT); + } + + + /* + ** I don't think we want to do this anymore + ** + + if (!p->RIOLastPCISearch == RIO_FAIL ) { + p->RIOFailed++; + } + + ** + */ +} + +#ifdef FUTURE_RELEASE +void riohalt( void ) +{ + int host; + for ( host=0; host<p->RIONumHosts; host++ ) + { + rio_dprintk (RIO_DEBUG_INIT, "Stop host %d\n", host); + (void)RIOBoardTest( p->RIOHosts[host].PaddrP, p->RIOHosts[host].Caddr, p->RIOHosts[host].Type,p->RIOHosts[host].Slot ); + } +} +#endif +#endif + +static uchar 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(paddr, caddr, type, slot) +paddr_t paddr; +caddr_t caddr; +uchar type; +int slot; +{ + struct DpRam *DpRam = (struct DpRam *)caddr; + char *ram[4]; + int size[4]; + int op, bank; + int nbanks; + + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Reset host type=%d, DpRam=0x%x, slot=%d\n", + type,(int)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] = (char *)&DpRam->DpSram1[0]; + ram[1] = (char *)&DpRam->DpSram2[0]; + ram[2] = (char *)&DpRam->DpSram3[0]; + nbanks = (type == RIO_PCI) ? 3 : 4; + if (nbanks == 4) + ram[3] = (char *)&DpRam->DpScratch[0]; + + + if (nbanks == 3) { + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Memory: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", + (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2]); + } else { + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x), 0x%x(0x%x)\n", + (int)ram[0], size[0], (int)ram[1], size[1], (int)ram[2], size[2], (int)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, (BYTE *)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 RIO_SUCCESS; +} + + +/* +** 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 compated with val[op-1] +** to check that the data from the previous phase was retained. +*/ +static int +RIOScrub(op, ram, size) +int op; +BYTE * 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 (RBYTE(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, RBYTE(ram[off])); + return RIO_FAIL; + } + } + for (off=0; off<size; off+=2) { + if (*(ushort *)&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,*(ushort *)&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, RBYTE(ram[off]), off+1, RBYTE(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 && (RBYTE(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, RBYTE(ram[off])); + return RIO_FAIL; + } + WBYTE(ram[off],invbyte); + if (RBYTE(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, RBYTE(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 (*(ushort *)&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, *(ushort *)&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, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); + return RIO_FAIL; + } + + *(ushort *)&ram[off] = newword; + if ( *(ushort *)&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, *(ushort *)&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, RBYTE(ram[off]), off+1, RBYTE(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 (RBYTE(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, RBYTE(ram[off])); + return RIO_FAIL; + } + } + + for (off=0; off<size; off+=2) { + if ( *(ushort *)&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, *(ushort *)&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, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); + return RIO_FAIL; + } + } + + /* + ** time to check out byte swapping errors + */ + swapword = invbyte | (newbyte << 8); + + for (off=0; off<size; off+=2) { + WBYTE(ram[off],invbyte); + WBYTE(ram[off+1],newbyte); + } + + for ( off=0; off<size; off+=2 ) { + if (*(ushort *)&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, *((ushort *)&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, RBYTE(ram[off]), off+1, RBYTE(ram[off+1])); + return RIO_FAIL; + } + *((ushort *)&ram[off]) = ~swapword; + } + + for (off=0; off<size; off+=2) { + if (RBYTE(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, RBYTE(ram[off])); + return RIO_FAIL; + } + if (RBYTE(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, RBYTE(ram[off+1])); + return RIO_FAIL; + } + *((ushort *)&ram[off]) = newword; + } + return RIO_SUCCESS; +} + +/* +** try to ensure that every host is either in polled mode +** or is in interrupt mode. Only allow interrupt mode if +** all hosts can interrupt (why?) +** and force into polled mode if told to. Patch up the +** interrupt vector & salute The Queen when you've done. +*/ +#if 0 +static void +RIOAllocateInterrupts(p) +struct rio_info * p; +{ + int Host; + + /* + ** Easy case - if we have been told to poll, then we poll. + */ + if (p->mode & POLLED_MODE) { + RIOStopInterrupts(p, 0, 0); + return; + } + + /* + ** check - if any host has been set to polled mode, then all must be. + */ + for (Host=0; Host<p->RIONumHosts; Host++) { + if ( (p->RIOHosts[Host].Type != RIO_AT) && + (p->RIOHosts[Host].Ivec == POLLED) ) { + RIOStopInterrupts(p, 1, Host ); + return; + } + } + for (Host=0; Host<p->RIONumHosts; Host++) { + if (p->RIOHosts[Host].Type == RIO_AT) { + if ( (p->RIOHosts[Host].Ivec - 32) == 0) { + RIOStopInterrupts(p, 2, Host ); + return; + } + } + } +} + +/* +** something has decided that we can't be doing with these +** new-fangled interrupt thingies. Set everything up to just +** poll. +*/ +static void +RIOStopInterrupts(p, Reason, Host) +struct rio_info * p; +int Reason; +int Host; +{ +#ifdef FUTURE_RELEASE + switch (Reason) { + case 0: /* forced into polling by rio_polled */ + break; + case 1: /* SCU has set 'Host' into polled mode */ + break; + case 2: /* there aren't enough interrupt vectors for 'Host' */ + break; + } +#endif + + for (Host=0; Host<p->RIONumHosts; Host++ ) { + struct Host *HostP = &p->RIOHosts[Host]; + + switch (HostP->Type) { + case RIO_AT: + /* + ** The AT host has it's interrupts disabled by clearing the + ** int_enable bit. + */ + HostP->Mode &= ~INTERRUPT_ENABLE; + HostP->Ivec = POLLED; + break; +#ifdef FUTURE_RELEASE + case RIO_EISA: + /* + ** The EISA host has it's interrupts disabled by setting the + ** Ivec to zero + */ + HostP->Ivec = POLLED; + break; +#endif + case RIO_PCI: + /* + ** The PCI host has it's interrupts disabled by clearing the + ** int_enable bit, like a regular host card. + */ + HostP->Mode &= ~RIO_PCI_INT_ENABLE; + HostP->Ivec = POLLED; + break; +#ifdef FUTURE_RELEASE + case RIO_MCA: + /* + ** There's always one, isn't there? + ** The MCA host card cannot have it's interrupts disabled. + */ + RIOPatchVec(HostP); + break; +#endif + } + } +} + +/* +** This function is called at init time to setup the data structures. +*/ +void +RIOAllocDataStructs(p) +struct rio_info * p; +{ + int port, + host, + tm; + + p->RIOPortp = (struct Port *)sysbrk(RIO_PORTS * sizeof(struct Port)); + if (!p->RIOPortp) { + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: No memory for port structures\n"); + p->RIOFailed++; + return; + } + bzero( p->RIOPortp, sizeof(struct Port) * RIO_PORTS ); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: allocated and cleared memory for port structs\n"); + rio_dprintk (RIO_DEBUG_INIT, "First RIO port struct @0x%x, size=0x%x bytes\n", + (int)p->RIOPortp, sizeof(struct Port)); + + for( port=0; port<RIO_PORTS; port++ ) { + p->RIOPortp[port].PortNum = port; + p->RIOPortp[port].TtyP = &p->channel[port]; + sreset (p->RIOPortp[port].InUse); /* Let the first guy uses it */ + p->RIOPortp[port].portSem = -1; /* Let the first guy takes it */ + p->RIOPortp[port].ParamSem = -1; /* Let the first guy takes it */ + p->RIOPortp[port].timeout_id = 0; /* Let the first guy takes it */ + } + + p->RIOHosts = (struct Host *)sysbrk(RIO_HOSTS * sizeof(struct Host)); + if (!p->RIOHosts) { + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: No memory for host structures\n"); + p->RIOFailed++; + return; + } + bzero(p->RIOHosts, sizeof(struct Host)*RIO_HOSTS); + rio_dprintk (RIO_DEBUG_INIT, "RIO-init: allocated and cleared memory for host structs\n"); + rio_dprintk (RIO_DEBUG_INIT, "First RIO host struct @0x%x, size=0x%x bytes\n", + (int)p->RIOHosts, sizeof(struct Host)); + + for( host=0; host<RIO_HOSTS; host++ ) { + spin_lock_init (&p->RIOHosts[host].HostLock); + p->RIOHosts[host].timeout_id = 0; /* Let the first guy takes it */ + } + /* + ** check that the buffer size is valid, round down to the next power of + ** two if necessary; if the result is zero, then, hey, no double buffers. + */ + for ( tm = 1; tm && tm <= p->RIOConf.BufferSize; tm <<= 1 ) + ; + tm >>= 1; + p->RIOBufferSize = tm; + p->RIOBufferMask = tm ? tm - 1 : 0; +} + +/* +** this function gets called whenever the data structures need to be +** re-setup, for example, after a riohalt (why did I ever invent it?) +*/ +void +RIOSetupDataStructs(p) +struct rio_info * p; +{ + int host, entry, rup; + + for ( host=0; host<RIO_HOSTS; host++ ) { + struct Host *HostP = &p->RIOHosts[host]; + for ( entry=0; entry<LINKS_PER_UNIT; entry++ ) { + HostP->Topology[entry].Unit = ROUTE_DISCONNECT; + HostP->Topology[entry].Link = NO_LINK; + } + bcopy("HOST X", HostP->Name, 7); + HostP->Name[5] = '1'+host; + for (rup=0; rup<(MAX_RUP + LINKS_PER_UNIT); rup++) { + if (rup < MAX_RUP) { + for (entry=0; entry<LINKS_PER_UNIT; entry++ ) { + HostP->Mapping[rup].Topology[entry].Unit = ROUTE_DISCONNECT; + HostP->Mapping[rup].Topology[entry].Link = NO_LINK; + } + RIODefaultName(p, HostP, rup); + } + spin_lock_init(&HostP->UnixRups[rup].RupLock); + } + } +} +#endif + +int +RIODefaultName(p, HostP, UnitId) +struct rio_info * p; +struct Host * HostP; +uint UnitId; +{ +#ifdef CHECK + CheckHost( Host ); + CheckUnitId( UnitId ); +#endif + bcopy("UNKNOWN RTA X-XX",HostP->Mapping[UnitId].Name,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" + +#if 0 +static int +RIOReport(p) +struct rio_info * p; +{ + char * RIORelease = RIO_RELEASE; + char * RIORelID = RELEASE_ID; + int host; + + rio_dprintk (RIO_DEBUG_INIT, "RIO : Release: %s ID: %s\n", RIORelease, RIORelID); + + if ( p->RIONumHosts==0 ) { + rio_dprintk (RIO_DEBUG_INIT, "\nNo Hosts configured\n"); + return(0); + } + + for ( host=0; host < p->RIONumHosts; host++ ) { + struct Host *HostP = &p->RIOHosts[host]; + switch ( HostP->Type ) { + case RIO_AT: + rio_dprintk (RIO_DEBUG_INIT, "AT BUS : found the card at 0x%x\n", HostP->PaddrP); + } + } + return 0; +} +#endif + +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; +} + +#if 0 +int +RIOMapin(paddr, size, vaddr) +paddr_t paddr; +int size; +caddr_t * vaddr; +{ + *vaddr = (caddr_t)permap( (long)paddr, size); + return ((int)*vaddr); +} + +void +RIOMapout(paddr, size, vaddr) +paddr_t paddr; +long size; +caddr_t vaddr; +{ +} +#endif + + +void +RIOHostReset(Type, DpRamP, Slot) +uint Type; +volatile struct DpRam *DpRamP; +uint 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"); + WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | + INTERRUPT_DISABLE | BYTE_OPERATION | + SLOW_LINKS | SLOW_AT_BUS); + WBYTE(DpRamP->DpResetTpu, 0xFF); + rio_udelay (3); + + rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); + WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | + INTERRUPT_DISABLE | BYTE_OPERATION | + SLOW_LINKS | SLOW_AT_BUS); + WBYTE(DpRamP->DpResetTpu, 0xFF); + rio_udelay (3); + break; +#ifdef FUTURE_RELEASE + case RIO_EISA: + /* + ** Bet this doesn't work! + */ + OUTBZ( Slot, EISA_CONTROL_PORT, + EISA_TP_RUN | EISA_TP_BUS_DISABLE | + EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM ); + OUTBZ( Slot, EISA_CONTROL_PORT, + EISA_TP_RESET | EISA_TP_BUS_DISABLE | + EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM ); + suspend( 3 ); + OUTBZ( Slot, EISA_CONTROL_PORT, + EISA_TP_RUN | EISA_TP_BUS_DISABLE | + EISA_TP_SLOW_LINKS | EISA_TP_BOOT_FROM_RAM ); + break; + case RIO_MCA: + WBYTE(DpRamP->DpControl , McaTpBootFromRam | McaTpBusDisable ); + WBYTE(DpRamP->DpResetTpu , 0xFF ); + suspend( 3 ); + WBYTE(DpRamP->DpControl , McaTpBootFromRam | McaTpBusDisable ); + WBYTE(DpRamP->DpResetTpu , 0xFF ); + suspend( 3 ); + break; +#endif + case RIO_PCI: + rio_dprintk (RIO_DEBUG_INIT, " (RIO_PCI)\n"); + DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; + DpRamP->DpResetInt = 0xFF; + DpRamP->DpResetTpu = 0xFF; + rio_udelay (100); + /* for (i=0; i<6000; i++); */ + /* suspend( 3 ); */ + break; +#ifdef FUTURE_RELEASE + default: + Rprintf(RIOMesgNoSupport,Type,DpRamP,Slot); + return; +#endif + + 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 000000000000..e42e7b50bf6b --- /dev/null +++ b/drivers/char/rio/riointr.c @@ -0,0 +1,951 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_riointr_c_sccs_ = "@(#)riointr.c 1.2"; +#endif + + +#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/semaphore.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 "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.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(en) +char * en; +{ + struct Port * PortP; + struct rio_info *p; + struct tty_struct* tty; + int c; + struct PKT * PacketP; + unsigned long flags; + + PortP = (struct Port *)en; + p = (struct rio_info *)PortP->p; + tty = PortP->gs.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, (caddr_t)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)) { + rio_dprintk (RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", + (int)(PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), + PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); + if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + PortP->gs.tty->ldisc.write_wakeup) + (PortP->gs.tty->ldisc.write_wakeup)(PortP->gs.tty); + rio_dprintk (RIO_DEBUG_INTR, "(%d/%d)\n", + PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); + wake_up_interruptible(&PortP->gs.tty->write_wait); + } + +} + + +/* +** RIO Host Service routine. Does all the work traditionally associated with an +** interrupt. +*/ +static int RupIntr; +static int RxIntr; +static int TxIntr; +void +RIOServiceHost(p, HostP, From) +struct rio_info * p; +struct Host *HostP; +int From; +{ + 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 ( RWORD( HostP->ParmMapP->rup_intr ) ) { + WWORD( HostP->ParmMapP->rup_intr , 0 ); + p->RIORupCount++; + RupIntr++; + rio_dprintk (RIO_DEBUG_INTR, "rio: RUP interrupt on host %d\n", HostP-p->RIOHosts); + RIOPollHostCommands(p, HostP ); + } + + if ( RWORD( HostP->ParmMapP->rx_intr ) ) { + int port; + + WWORD( HostP->ParmMapP->rx_intr , 0 ); + p->RIORxCount++; + RxIntr++; + + rio_dprintk (RIO_DEBUG_INTR, "rio: RX interrupt on host %d\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 *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.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 ) && + ( RWORD( 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"); + WWORD( PortP->PhbP->handshake, + PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET ); + } + rio_spin_unlock(&PortP->portSem); + } + } + + if ( RWORD( HostP->ParmMapP->tx_intr ) ) { + int port; + + WWORD( HostP->ParmMapP->tx_intr , 0); + + p->RIOTxCount++; + TxIntr++; + rio_dprintk (RIO_DEBUG_INTR, "rio: TX interrupt on host %d\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 *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.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 1 + 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, OPEN, ((PortP->Cor2Copy & + (COR2_RTSFLOW|COR2_CTSFLOW ) )== + (COR2_RTSFLOW|COR2_CTSFLOW ) ) ? + TRUE : FALSE, DONT_SLEEP ) == RIO_FAIL ) { + continue; /* with next port */ + } + rio_spin_lock(&PortP->portSem); + PortP->MagicFlags &= ~MAGIC_REBOOT; + } +#endif + + /* + ** 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 *PktCmdP; + + rio_dprintk (RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n"); + /* + ** make it look just like a WFLUSH command + */ + PktCmdP = ( struct PktCmd * )&PacketP->data[0]; + + WBYTE( PktCmdP->Command , WFLUSH ); + + p = PortP->HostPort % ( ushort )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; + + WBYTE( PktCmdP->PhbNum, p ); + + /* + ** to make debuggery easier + */ + WBYTE( PacketP->data[ 2], 'W' ); + WBYTE( PacketP->data[ 3], 'F' ); + WBYTE( PacketP->data[ 4], 'L' ); + WBYTE( PacketP->data[ 5], 'U' ); + WBYTE( PacketP->data[ 6], 'S' ); + WBYTE( PacketP->data[ 7], 'H' ); + WBYTE( PacketP->data[ 8], ' ' ); + WBYTE( PacketP->data[ 9], '0'+PortP->WflushFlag ); + WBYTE( PacketP->data[10], ' ' ); + WBYTE( PacketP->data[11], ' ' ); + WBYTE( PacketP->data[12], '\0' ); + + /* + ** its two bytes long! + */ + WBYTE( PacketP->len , PKT_CMD_BIT | 2 ); + + /* + ** 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 clist drivers. +** NB: Called with the tty locked. The spl from the lockb( ) is passed. +** we return the ttySpl level that we re-locked at. +*/ +static void +RIOReceive(p, PortP) +struct rio_info * p; +struct Port * PortP; +{ + struct tty_struct *TtyP; + register ushort transCount; + struct PKT *PacketP; + register uint DataCnt; + uchar * ptr; + 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 succesfully 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.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) + { +#ifdef STATS + PortP->Stat.RxIntCnt++; +#endif /* STATS */ + RxIntCnt++; + + /* + ** check that it is not a command! + */ + if ( 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", PacketP->dest_unit); + rio_dprintk (RIO_DEBUG_INTR, " dest_port = %d\n", PacketP->dest_port); + rio_dprintk (RIO_DEBUG_INTR, " src_unit = %d\n", PacketP->src_unit); + rio_dprintk (RIO_DEBUG_INTR, " src_port = %d\n", PacketP->src_port); + rio_dprintk (RIO_DEBUG_INTR, " len = %d\n", PacketP->len); + rio_dprintk (RIO_DEBUG_INTR, " control = %d\n", PacketP->control); + rio_dprintk (RIO_DEBUG_INTR, " csum = %d\n", 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", 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 = min_t(unsigned int, PacketP->len & PKT_LEN_MASK, + TTY_FLIPBUF_SIZE - TtyP->flip.count); + 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). + */ +#undef ___DEBUG_IT___ +#ifdef ___DEBUG_IT___ + kkprintf("I:%d R:%d P:%d Q:%d C:%d F:%x ", + intCount, + RxIntCnt, + PortP->PortNum, + TtyP->rxqueue.count, + transCount, + TtyP->flags ); +#endif + ptr = (uchar *) PacketP->data + PortP->RxDataStart; + + rio_memcpy_fromio (TtyP->flip.char_buf_ptr, ptr, transCount); + memset(TtyP->flip.flag_buf_ptr, TTY_NORMAL, transCount); + +#ifdef STATS + /* + ** keep a count for statistical purposes + */ + PortP->Stat.RxCharCnt += transCount; +#endif + PortP->RxDataStart += transCount; + PacketP->len -= transCount; + copied += transCount; + TtyP->flip.count += transCount; + TtyP->flip.char_buf_ptr += transCount; + TtyP->flip.flag_buf_ptr += transCount; + + +#ifdef ___DEBUG_IT___ + kkprintf("T:%d L:%d\n", DataCnt, PacketP->len ); +#endif + + if ( 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; +#ifdef STATS + /* + ** more lies ( oops, I mean statistics ) + */ + PortP->Stat.RxPktCnt++; +#endif /* STATS */ + } + } + } + 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; +} + +#ifdef FUTURE_RELEASE +/* +** The proc routine called by the line discipline to do the work for it. +** The proc routine works hand in hand with the interrupt routine. +*/ +int +riotproc(p, tp, cmd, port) +struct rio_info * p; +register struct ttystatics *tp; +int cmd; +int port; +{ + register struct Port *PortP; + int SysPort; + struct PKT *PacketP; + + SysPort = port; /* Believe me, it works. */ + + if ( SysPort < 0 || SysPort >= RIO_PORTS ) { + rio_dprintk (RIO_DEBUG_INTR, "Illegal port %d derived from TTY in riotproc()\n",SysPort); + return 0; + } + PortP = p->RIOPortp[SysPort]; + + if ((uint)PortP->PhbP < (uint)PortP->Caddr || + (uint)PortP->PhbP >= (uint)PortP->Caddr+SIXTY_FOUR_K ) { + rio_dprintk (RIO_DEBUG_INTR, "RIO: NULL or BAD PhbP on sys port %d in proc routine\n", + SysPort); + rio_dprintk (RIO_DEBUG_INTR, " PortP = 0x%x\n",PortP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->PhbP = 0x%x\n",PortP->PhbP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->Caddr = 0x%x\n",PortP->PhbP); + rio_dprintk (RIO_DEBUG_INTR, " PortP->HostPort = 0x%x\n",PortP->HostPort); + return 0; + } + + switch(cmd) { + case T_WFLUSH: + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH\n"); + /* + ** Because of the spooky way the RIO works, we don't need + ** to issue a flush command on any of the SET*F commands, + ** as that causes trouble with getty and login, which issue + ** these commands to incur a READ flush, and rely on the fact + ** that the line discipline does a wait for drain for them. + ** As the rio doesn't wait for drain, the write flush would + ** destroy the Password: prompt. This isn't very friendly, so + ** here we only issue a WFLUSH command if we are in the interrupt + ** routine, or we aren't executing a SET*F command. + */ + if ( PortP->HostP->InIntr || !PortP->FlushCmdBodge ) { + /* + ** form a wflush packet - 1 byte long, no data + */ + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_INTR, "WFLUSH on deleted RTA\n"); + } + else { + if ( RIOPreemptiveCmd(p, PortP, WFLUSH ) == RIO_FAIL ) { + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command failed\n"); + } + else + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command\n"); + } + /* + ** WFLUSH operation - flush the data! + */ + PortP->TxBufferIn = PortP->TxBufferOut = 0; + } + else { + rio_dprintk (RIO_DEBUG_INTR, "T_WFLUSH Command ignored\n"); + } + /* + ** sort out the line discipline + */ + if (PortP->CookMode == COOK_WELL) + goto start; + break; + + case T_RESUME: + rio_dprintk (RIO_DEBUG_INTR, "T_RESUME\n"); + /* + ** send pre-emptive resume packet + */ + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_INTR, "RESUME on deleted RTA\n"); + } + else { + if ( RIOPreemptiveCmd(p, PortP, RESUME ) == RIO_FAIL ) { + rio_dprintk (RIO_DEBUG_INTR, "T_RESUME Command failed\n"); + } + } + /* + ** and re-start the sender software! + */ + if (PortP->CookMode == COOK_WELL) + goto start; + break; + + case T_TIME: + rio_dprintk (RIO_DEBUG_INTR, "T_TIME\n"); + /* + ** T_TIME is called when xDLY is set in oflags and + ** the line discipline timeout has expired. It's + ** function in life is to clear the TIMEOUT flag + ** and to re-start output to the port. + */ + /* + ** Fall through and re-start output + */ + case T_OUTPUT: +start: + if ( PortP->MagicFlags & MAGIC_FLUSH ) { + PortP->MagicFlags |= MORE_OUTPUT_EYGOR; + return 0; + } + RIOTxEnable((char *)PortP); + PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR; + /*rio_dprint(RIO_DEBUG_INTR, PortP,DBG_PROC,"T_OUTPUT finished\n");*/ + break; + + case T_SUSPEND: + rio_dprintk (RIO_DEBUG_INTR, "T_SUSPEND\n"); + /* + ** send a suspend pre-emptive packet. + */ + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_INTR, "SUSPEND deleted RTA\n"); + } + else { + if ( RIOPreemptiveCmd(p, PortP, SUSPEND ) == RIO_FAIL ) { + rio_dprintk (RIO_DEBUG_INTR, "T_SUSPEND Command failed\n"); + } + } + /* + ** done! + */ + break; + + case T_BLOCK: + rio_dprintk (RIO_DEBUG_INTR, "T_BLOCK\n"); + break; + + case T_RFLUSH: + rio_dprintk (RIO_DEBUG_INTR, "T_RFLUSH\n"); + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_INTR, "RFLUSH on deleted RTA\n"); + PortP->RxDataStart = 0; + } + else { + if ( RIOPreemptiveCmd( p, PortP, RFLUSH ) == RIO_FAIL ) { + rio_dprintk (RIO_DEBUG_INTR, "T_RFLUSH Command failed\n"); + return 0; + } + PortP->RxDataStart = 0; + while ( can_remove_receive(&PacketP, PortP) ) { + remove_receive(PortP); + ShowPacket(DBG_PROC, PacketP ); + put_free_end(PortP->HostP, PacketP ); + } + if ( PortP->PhbP->handshake == PHB_HANDSHAKE_SET ) { + /* + ** MAGIC! + */ + rio_dprintk (RIO_DEBUG_INTR, "Set receive handshake bit\n"); + PortP->PhbP->handshake |= PHB_HANDSHAKE_RESET; + } + } + break; + /* FALLTHROUGH */ + case T_UNBLOCK: + rio_dprintk (RIO_DEBUG_INTR, "T_UNBLOCK\n"); + /* + ** If there is any data to receive set a timeout to service it. + */ + RIOReceive(p, PortP); + break; + + case T_BREAK: + rio_dprintk (RIO_DEBUG_INTR, "T_BREAK\n"); + /* + ** Send a break command. For Sys V + ** this is a timed break, so we + ** send a SBREAK[time] packet + */ + /* + ** Build a BREAK command + */ + if ( PortP->State & RIO_DELETED ) { + rio_dprintk (RIO_DEBUG_INTR, "BREAK on deleted RTA\n"); + } + else { + if (RIOShortCommand(PortP,SBREAK,2, + p->RIOConf.BreakInterval)==RIO_FAIL) { + rio_dprintk (RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); + } + } + + /* + ** done! + */ + break; + + case T_INPUT: + rio_dprintk (RIO_DEBUG_INTR, "Proc T_INPUT called - I don't know what to do!\n"); + break; + case T_PARM: + rio_dprintk (RIO_DEBUG_INTR, "Proc T_PARM called - I don't know what to do!\n"); + break; + + case T_SWTCH: + rio_dprintk (RIO_DEBUG_INTR, "Proc T_SWTCH called - I don't know what to do!\n"); + break; + + default: + rio_dprintk (RIO_DEBUG_INTR, "Proc UNKNOWN command %d\n",cmd); + } + /* + ** T_OUTPUT returns without passing through this point! + */ + /*rio_dprint(RIO_DEBUG_INTR, PortP,DBG_PROC,"riotproc done\n");*/ + return(0); +} +#endif diff --git a/drivers/char/rio/rioioctl.h b/drivers/char/rio/rioioctl.h new file mode 100644 index 000000000000..c3d679733c9a --- /dev/null +++ b/drivers/char/rio/rioioctl.h @@ -0,0 +1,103 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_rioioctl_h_sccs_ = "@(#)rioioctl.h 1.2"; +#endif + +/* +** RIO device driver - user ioctls and associated structures. +*/ + +struct portStats { + int port; + int gather; + ulong txchars; + ulong rxchars; + ulong opens; + ulong closes; + ulong ioctls; +}; + + +#define rIOC ('r'<<8) +#define TCRIOSTATE (rIOC | 1) +#define TCRIOXPON (rIOC | 2) +#define TCRIOXPOFF (rIOC | 3) +#define TCRIOXPCPS (rIOC | 4) +#define TCRIOXPRINT (rIOC | 5) +#define TCRIOIXANYON (rIOC | 6) +#define TCRIOIXANYOFF (rIOC | 7) +#define TCRIOIXONON (rIOC | 8) +#define TCRIOIXONOFF (rIOC | 9) +#define TCRIOMBIS (rIOC | 10) +#define TCRIOMBIC (rIOC | 11) +#define TCRIOTRIAD (rIOC | 12) +#define TCRIOTSTATE (rIOC | 13) + +/* +** 15.10.1998 ARG - ESIL 0761 part fix +** Add RIO ioctls for manipulating RTS and CTS flow control, (as LynxOS +** appears to not support hardware flow control). +*/ +#define TCRIOCTSFLOWEN (rIOC | 14) /* enable CTS flow control */ +#define TCRIOCTSFLOWDIS (rIOC | 15) /* disable CTS flow control */ +#define TCRIORTSFLOWEN (rIOC | 16) /* enable RTS flow control */ +#define TCRIORTSFLOWDIS (rIOC | 17) /* disable RTS flow control */ + +/* +** 09.12.1998 ARG - ESIL 0776 part fix +** Definition for 'RIOC' also appears in daemon.h, so we'd better do a +** #ifndef here first. +** 'RIO_QUICK_CHECK' also #define'd here as this ioctl is now +** allowed to be used by customers. +** +** 05.02.1999 ARG - +** This is what I've decied to do with ioctls etc., which are intended to be +** invoked from users applications : +** Anything that needs to be defined here will be removed from daemon.h, that +** way it won't end up having to be defined/maintained in two places. The only +** consequence of this is that this file should now be #include'd by daemon.h +** +** 'stats' ioctls now #define'd here as they are to be used by customers. +*/ +#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/riolocks.h b/drivers/char/rio/riolocks.h new file mode 100644 index 000000000000..0e0cdacebe0b --- /dev/null +++ b/drivers/char/rio/riolocks.h @@ -0,0 +1,43 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : riolocks.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:13 +** Retrieved : 11/6/98 11:34:22 +** +** ident @(#)riolocks.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_riolocks_h__ +#define __rio_riolocks_h__ + +#ifdef SCCS_LABELS +static char *_riolocks_h_sccs_ = "@(#)riolocks.h 1.2"; +#endif + +#define LOCKB(lk) lockb(lk); +#define UNLOCKB(lk, oldspl) unlockb(lk, oldspl); + +#endif diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c new file mode 100644 index 000000000000..f10916326ecc --- /dev/null +++ b/drivers/char/rio/rioparam.c @@ -0,0 +1,744 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ + +#ifdef SCCS_LABELS +static char *_rioparam_c_sccs_ = "@(#)rioparam.c 1.3"; +#endif + +#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/semaphore.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 "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" +#include "param.h" +#include "list.h" +#include "sam.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, then the first +** data byte ( data[0] ) is interpretted 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 analagous). 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(PortP, cmd, Modem, SleepFlag) +struct Port *PortP; +int cmd; +int Modem; +int SleepFlag; +{ + register struct tty_struct *TtyP; + int retval; + register struct phb_param *phb_param_ptr; + PKT *PacketP; + int res; + uchar Cor1=0, Cor2=0, Cor4=0, Cor5=0; + uchar TxXon=0, TxXoff=0, RxXon=0, RxXoff=0; + uchar LNext=0, TxBaud=0, RxBaud=0; + int retries = 0xff; + unsigned long flags; + + func_enter (); + + TtyP = PortP->gs.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 == 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. + */ +#if 0 + if (PortP->FirstOpen) { + PortP->StoredTty.iflag = TtyP->tm.c_iflag; + PortP->StoredTty.oflag = TtyP->tm.c_oflag; + PortP->StoredTty.cflag = TtyP->tm.c_cflag; + PortP->StoredTty.lflag = TtyP->tm.c_lflag; + PortP->StoredTty.line = TtyP->tm.c_line; + for (i = 0; i < NCC + 5; i++) + PortP->StoredTty.cc[i] = TtyP->tm.c_cc[i]; + PortP->FirstOpen = 0; + } + else if (PortP->Store || PortP->Lock) { + rio_dprintk (RIO_DEBUG_PARAM, "OPEN: Restoring stored/locked params\n"); + TtyP->tm.c_iflag = PortP->StoredTty.iflag; + TtyP->tm.c_oflag = PortP->StoredTty.oflag; + TtyP->tm.c_cflag = PortP->StoredTty.cflag; + TtyP->tm.c_lflag = PortP->StoredTty.lflag; + TtyP->tm.c_line = PortP->StoredTty.line; + for (i = 0; i < NCC + 5; i++) + TtyP->tm.c_cc[i] = PortP->StoredTty.cc[i]; + } +#endif + } + + /* + ** 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); + pseterr(EINTR); + func_exit(); + + return RIO_FAIL; + } + if ( PortP->State & RIO_DELETED ) { + rio_spin_unlock_irqrestore( &PortP->portSem, flags); + func_exit (); + + return RIO_SUCCESS; + } + } + + 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 0x%x\n",(int) PacketP); + + phb_param_ptr = (struct phb_param *)PacketP->data; + + +#if 0 + /* + ** COR 1 + */ + if ( TtyP->tm.c_iflag & INPCK ) { + rio_dprintk (RIO_DEBUG_PARAM, "Parity checking on input enabled\n"); + Cor1 |= COR1_INPCK; + } +#endif + + switch ( TtyP->termios->c_cflag & CSIZE ) { + case CS5: + { + rio_dprintk (RIO_DEBUG_PARAM, "5 bit data\n"); + Cor1 |= COR1_5BITS; + break; + } + case CS6: + { + rio_dprintk (RIO_DEBUG_PARAM, "6 bit data\n"); + Cor1 |= COR1_6BITS; + break; + } + case CS7: + { + rio_dprintk (RIO_DEBUG_PARAM, "7 bit data\n"); + Cor1 |= COR1_7BITS; + break; + } + case CS8: + { + rio_dprintk (RIO_DEBUG_PARAM, "8 bit data\n"); + Cor1 |= COR1_8BITS; + break; + } + } + + if ( TtyP->termios->c_cflag & CSTOPB ) { + rio_dprintk (RIO_DEBUG_PARAM, "2 stop bits\n"); + Cor1 |= COR1_2STOP; + } + else { + rio_dprintk (RIO_DEBUG_PARAM, "1 stop bit\n"); + Cor1 |= COR1_1STOP; + } + + if ( TtyP->termios->c_cflag & PARENB ) { + rio_dprintk (RIO_DEBUG_PARAM, "Enable parity\n"); + Cor1 |= COR1_NORMAL; + } + else { + rio_dprintk (RIO_DEBUG_PARAM, "Disable parity\n"); + Cor1 |= COR1_NOP; + } + if ( TtyP->termios->c_cflag & PARODD ) { + rio_dprintk (RIO_DEBUG_PARAM, "Odd parity\n"); + Cor1 |= COR1_ODD; + } + else { + rio_dprintk (RIO_DEBUG_PARAM, "Even parity\n"); + Cor1 |= COR1_EVEN; + } + + /* + ** COR 2 + */ + if ( TtyP->termios->c_iflag & IXON ) { + rio_dprintk (RIO_DEBUG_PARAM, "Enable start/stop output control\n"); + Cor2 |= COR2_IXON; + } + else { + if ( PortP->Config & RIO_IXON ) { + rio_dprintk (RIO_DEBUG_PARAM, "Force enable start/stop output control\n"); + Cor2 |= 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 |= 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 |= COR2_IXOFF; + } + + if ( TtyP->termios->c_cflag & HUPCL ) { + rio_dprintk (RIO_DEBUG_PARAM, "Hangup on last close\n"); + Cor2 |= COR2_HUPCL; + } + + if ( C_CRTSCTS (TtyP)) { + rio_dprintk (RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n"); + Cor2 |= COR2_CTSFLOW; + Cor2 |= COR2_RTSFLOW; + } else { + rio_dprintk (RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n"); + Cor2 &= ~COR2_CTSFLOW; + Cor2 &= ~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 |= COR4_IGNBRK; + } + if ( !(TtyP->termios->c_iflag & BRKINT) ) { + rio_dprintk (RIO_DEBUG_PARAM, "Break generates NULL condition\n"); + Cor4 |= 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 |= COR4_INLCR; + } + + if ( TtyP->termios->c_iflag & IGNCR ) { + rio_dprintk (RIO_DEBUG_PARAM, "Ignore carriage return on input\n"); + Cor4 |= COR4_IGNCR; + } + + if ( TtyP->termios->c_iflag & ICRNL ) { + rio_dprintk (RIO_DEBUG_PARAM, "Map carriage return to newline on input\n"); + Cor4 |= COR4_ICRNL; + } + if ( TtyP->termios->c_iflag & IGNPAR ) { + rio_dprintk (RIO_DEBUG_PARAM, "Ignore characters with parity errors\n"); + Cor4 |= COR4_IGNPAR; + } + if ( TtyP->termios->c_iflag & PARMRK ) { + rio_dprintk (RIO_DEBUG_PARAM, "Mark parity errors\n"); + Cor4 |= 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 |= COR4_RAISEMOD; + + /* + ** COR 5 + */ + + Cor5 = COR5_CMOE; + + /* + ** Set to monitor tbusy/tstop (or not). + */ + + if (PortP->MonitorTstate) + Cor5 |= COR5_TSTATE_ON; + else + Cor5 |= 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 |= 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 |= 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 |= 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 |= 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); */ + } + + /* XXX MIssing conversion table. XXX */ + /* (TtyP->termios->c_cflag & V_CBAUD); */ + + 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 0 + if ( TtyP->termios->c_cflag & LOBLK ) + rio_dprintk (RIO_DEBUG_PARAM, "LOBLK - JCL output blocks when not current\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"); +#if 0 + if ( TtyP->termios->c_oflag & BSDLY ) + rio_dprintk (RIO_DEBUG_PARAM, "Back-space delay set\n"); + if ( TtyP->termios->c_oflag & VTDLY ) + rio_dprintk (RIO_DEBUG_PARAM, "Vertical tab delay set\n"); + if ( TtyP->termios->c_oflag & FFDLY ) + rio_dprintk (RIO_DEBUG_PARAM, "Form-feed delay set\n"); +#endif + /* + ** 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 + */ + WBYTE(phb_param_ptr->Cmd, cmd); + WBYTE(phb_param_ptr->Cor1, Cor1); + WBYTE(phb_param_ptr->Cor2, Cor2); + WBYTE(phb_param_ptr->Cor4, Cor4); + WBYTE(phb_param_ptr->Cor5, Cor5); + WBYTE(phb_param_ptr->TxXon, TxXon); + WBYTE(phb_param_ptr->RxXon, RxXon); + WBYTE(phb_param_ptr->TxXoff, TxXoff); + WBYTE(phb_param_ptr->RxXoff, RxXoff); + WBYTE(phb_param_ptr->LNext, LNext); + WBYTE(phb_param_ptr->TxBaud, TxBaud); + WBYTE(phb_param_ptr->RxBaud, RxBaud); + + /* + ** Set the length/command field + */ + WBYTE(PacketP->len , 12 | PKT_CMD_BIT); + + /* + ** 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 RIO_SUCCESS; +} + + +/* +** 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(PktP, PortP) +PKT **PktP; +struct Port *PortP; +{ + register PKT *tp; + + *PktP = tp = (PKT *)RIO_PTR(PortP->Caddr,RWORD(*PortP->TxAdd)); + + return !((uint)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(PortP) +struct Port *PortP; +{ + if (RWORD(*PortP->TxAdd) & PKT_IN_USE) { + rio_dprintk (RIO_DEBUG_PARAM, "add_transmit: Packet has been stolen!"); + } + WWORD( *(ushort *)PortP->TxAdd, RWORD(*PortP->TxAdd) | PKT_IN_USE); + PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : + PortP->TxAdd + 1; + WWORD( PortP->PhbP->tx_add , RIO_OFF(PortP->Caddr,PortP->TxAdd) ); +} + +/**************************************** + * Put a packet onto the end of the + * free list + ****************************************/ +void +put_free_end(HostP, PktP) +struct Host *HostP; +PKT *PktP; +{ + FREE_LIST *tmp_pointer; + ushort 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=%x)\n",(int)PktP); + + if ((old_end=RWORD(HostP->ParmMapP->free_list_end)) != TPNULL) { + new_end = RIO_OFF(HostP->Caddr,PktP); + tmp_pointer = (FREE_LIST *)RIO_PTR(HostP->Caddr,old_end); + WWORD(tmp_pointer->next , new_end ); + WWORD(((FREE_LIST *)PktP)->prev , old_end); + WWORD(((FREE_LIST *)PktP)->next , TPNULL); + WWORD(HostP->ParmMapP->free_list_end, new_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"); + WWORD(HostP->ParmMapP->free_list_end , RIO_OFF(HostP->Caddr,PktP)); + tmp_pointer = (FREE_LIST *)PktP; + WWORD(tmp_pointer->prev , TPNULL); + WWORD(tmp_pointer->next , TPNULL); + } + 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(PktP, PortP) +PKT **PktP; +struct Port *PortP; +{ + if ( RWORD(*PortP->RxRemove) & PKT_IN_USE) { + *PktP = (PKT *)RIO_PTR(PortP->Caddr, + RWORD(*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(PortP) +struct Port *PortP; +{ + WWORD( *PortP->RxRemove, RWORD(*PortP->RxRemove) & ~PKT_IN_USE ); + PortP->RxRemove = (PortP->RxRemove == PortP->RxEnd) ? PortP->RxStart : + PortP->RxRemove + 1; + WWORD( PortP->PhbP->rx_remove , RIO_OFF(PortP->Caddr, PortP->RxRemove) ); +} diff --git a/drivers/char/rio/riopcicopy.c b/drivers/char/rio/riopcicopy.c new file mode 100644 index 000000000000..2ea99a60aa32 --- /dev/null +++ b/drivers/char/rio/riopcicopy.c @@ -0,0 +1,8 @@ + +/* Yeah. We have copyright on this one. Sure. */ + +void rio_pcicopy( char *from, char *to, int amount) +{ + while ( amount-- ) + *to++ = *from++; +} diff --git a/drivers/char/rio/rioroute.c b/drivers/char/rio/rioroute.c new file mode 100644 index 000000000000..106b31f48a21 --- /dev/null +++ b/drivers/char/rio/rioroute.c @@ -0,0 +1,1238 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_rioroute_c_sccs_ = "@(#)rioroute.c 1.3"; +#endif + +#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/semaphore.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 "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" +#include "param.h" +#include "list.h" +#include "sam.h" + +static int RIOCheckIsolated(struct rio_info *, struct Host *, uint); +static int RIOIsolate(struct rio_info *, struct Host *, uint); +static int RIOCheck(struct Host *, uint); +static void RIOConCon(struct rio_info *, struct Host *, uint, uint, uint, uint, int); + + +/* +** Incoming on the ROUTE_RUP +** I wrote this while I was tired. Forgive me. +*/ +int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP ) +{ + struct PktCmd *PktCmdP = (struct PktCmd *)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; + ushort RtaType; + uint RtaUniq; + uint ThisUnit, ThisUnit2; /* 2 ids to accommodate 16 port RTA */ + uint OldUnit, NewUnit, OldLink, NewLink; + char *MyType, *MyName; + int Lies; + unsigned long flags; + +#ifdef STACK + RIOStackCheck("RIORouteRup"); +#endif +#ifdef CHECK + CheckPacketP(PacketP); + CheckHostP(HostP); + CheckRup(Rup); + CheckHost(Host); +#endif + /* + ** Is this unit telling us it's current link topology? + */ + if ( RBYTE(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 >= (ushort)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 ( RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) > (ushort)MAX_RUP ) + continue; + + for ( NewLink=ThisLinkMin; NewLink < ThisLink; NewLink++ ) + { + if ( (RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) == + RBYTE(PktCmdP->RouteTopology[NewLink].Unit)) && + (RBYTE(PktCmdP->RouteTopology[ThisLink].Link) == + RBYTE(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", + RBYTE(PktCmdP->RouteTopology[0].Unit), + 'A'+RBYTE(PktCmdP->RouteTopology[0].Link), + RBYTE(PktCmdP->RouteTopology[1].Unit), + 'A'+RBYTE(PktCmdP->RouteTopology[1].Link), + RBYTE(PktCmdP->RouteTopology[2].Unit), + 'A'+RBYTE(PktCmdP->RouteTopology[2].Link), + RBYTE(PktCmdP->RouteTopology[3].Unit), + 'A'+RBYTE(PktCmdP->RouteTopology[3].Link)); + return TRUE; + } + + /* + ** 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 = RBYTE(PktCmdP->RouteTopology[ThisLink].Unit); + NewLink = RBYTE(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) + cprintf("%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 TRUE; + } + + /* + ** The only other command we recognise is a route_request command + */ + if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST ) + { + rio_dprintk (RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %d ROUTE_RUP\n", + RBYTE(PktCmdP->Command),Rup,(int)HostP); + return TRUE; + } + + RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) + + (RBYTE(PktCmdP->UniqNum[1]) << 8) + + (RBYTE(PktCmdP->UniqNum[2]) << 16) + + (RBYTE(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 = RBYTE(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); + } + + if ( RtaUniq == 0xffffffff ) + { + ShowPacket( DBG_SPECIAL, PacketP ); + } + + /* + ** 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; + HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7); + RIOQueueCmdBlk(HostP, Rup, CmdBlkP); + return TRUE; + } + + /* + ** 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 ) + cprintf("RTA '%s' is being updated.\n",HostP->Mapping[ThisUnit].Name); + HostP->Mapping[ThisUnit].Flags |= MSG_DONE; + } + PktReplyP->Command = ROUTE_FOAD; + HostP->Copy("RT_FOAD",PktReplyP->CommandText,7); + RIOQueueCmdBlk(HostP, Rup, CmdBlkP); + return TRUE; + } + + /* + ** 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); + } + HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,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 TRUE; + } + } + /* + ** 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) + cprintf("One or more unknown RTAs are being updated.\n"); + UnknownMesgDone = 1; + } + + PktReplyP->Command = ROUTE_FOAD; + HostP->Copy("RT_FOAD",PktReplyP->CommandText,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); + FillSlot(ThisUnit, ThisUnit2, RtaUniq, HostP); + } + } + else + { + if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) + { + RIODefaultName(p, HostP, ThisUnit); + FillSlot(ThisUnit, 0, RtaUniq, HostP); + } + } + PktReplyP->Command = ROUTE_USED; + HostP->Copy("RT_USED",PktReplyP->CommandText,7); + } + RIOQueueCmdBlk( HostP, Rup, CmdBlkP); + return TRUE; +} + + +void +RIOFixPhbs(p, HostP, unit) +struct rio_info *p; +struct Host *HostP; +uint unit; +{ + ushort 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) { + ushort 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 = RWORD(PortP->PhbP->link); + + for (port = 0; port < PORTS_PER_RTA; port++, PortN++) { + ushort dest_port = port + 8; +#if 0 + uint PktInt; +#endif + WORD *TxPktP; + PKT *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 == 0) { + 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 = (PKT *) RIO_PTR(HostP->Caddr,RINDW(TxPktP)); + + /* + ** If the packet is used, reset it. + */ + Pkt = (PKT *)((uint)Pkt & ~PKT_IN_USE); + WBYTE(Pkt->dest_unit, dest_unit); + WBYTE(Pkt->dest_port, dest_port); + } + rio_dprintk (RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", + RWORD(PortP->PhbP->destination) & 0xff, + (RWORD(PortP->PhbP->destination) >> 8) & 0xff, + dest_unit, dest_port); + WWORD(PortP->PhbP->destination, dest_unit + (dest_port << 8)); + WWORD(PortP->PhbP->link, 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) > RWORD(HostP->LinkStrP[link].last_port)) { + rio_dprintk (RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7); + WWORD(HostP->LinkStrP[link].last_port, (unit * 8) + 7); + } + } +} + +/* +** 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(p, HostP, UnitId) +struct rio_info * p; +struct Host *HostP; +uint UnitId; +{ + unsigned long flags; + rio_spin_lock_irqsave(&HostP->HostLock, flags); + +#ifdef CHECK + CheckHostP( HostP ); + CheckUnitId( UnitId ); +#endif + 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(p, HostP, UnitId) +struct rio_info * p; +struct Host * HostP; +uint UnitId; +{ + uint link, unit; + +#ifdef CHECK + CheckHostP( HostP ); + CheckUnitId( UnitId ); +#endif + 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(HostP, UnitId) +struct Host *HostP; +uint UnitId; +{ + unsigned char link; + +#ifdef CHECK + CheckHostP( HostP ); + CheckUnitId( UnitId ); +#endif +/* 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) +*/ + +uint +GetUnitType(Uniq) +uint 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(p) +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(p, HostP, FromId, FromLink, ToId, ToLink, Change) +struct rio_info * p; +struct Host *HostP; +uint FromId; +uint FromLink; +uint ToId; +uint 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"); + cprintf("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) + { + bzero((caddr_t)&p->RIOSavedTable[entry], 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; + +#if 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 *) ¤t_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); + bzero((caddr_t)&HostP->Mapping[nOther], 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, uint *pID1, uint *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. + */ + bzero(&HostP->Mapping[unit], 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. + */ + bzero(&HostP->Mapping[unit], 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 000000000000..32b09b0f23aa --- /dev/null +++ b/drivers/char/rio/riospace.h @@ -0,0 +1,161 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_riospace_h_sccs_ = "@(#)riospace.h 1.2"; +#endif + +#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 000000000000..8fb26ad2aa12 --- /dev/null +++ b/drivers/char/rio/riotable.c @@ -0,0 +1,1044 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_riotable_c_sccs_ = "@(#)riotable.c 1.2"; +#endif + +#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/semaphore.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 "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" +#include "param.h" +#include "list.h" +#include "sam.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(p) +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' ) { + bcopy(MapP->RtaUniqueNum?"RTA NN":"HOST NN",MapP->Name,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++ ) { + bzero((caddr_t)&p->RIOHosts[Host].Mapping[Entry], + sizeof(struct Map)); + } + bzero((caddr_t)&p->RIOHosts[Host].Name[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); + bcopy(MapP->Name,HostP->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] ) { + bcopy("HOST 1",p->RIOHosts[Host].Name,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); + bcopy("HOST 1",p->RIOHosts[Host].Name,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. +*/ +int +RIOApel(p) +struct rio_info * p; +{ + int Host; + int link; + int Rup; + int Next = 0; + struct Map *MapP; + struct Host *HostP; + long oldspl; + + disable(oldspl); /* strange but true! */ + + rio_dprintk (RIO_DEBUG_TABLE, "Generating a table to return to config.rio\n"); + + bzero((caddr_t)&p->RIOConnectTable[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]; + MapP = &p->RIOConnectTable[Next++]; + MapP->HostUniqueNum = HostP->UniqueNum; + if ( (HostP->Flags & RUN_STATE) != RC_RUNNING ) + 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]; + bcopy(HostP->Name,MapP->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++; + } + } + } + restore(oldspl); + 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(p, MapP) +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) { + ushort dest_unit = HostMapP->ID; + ushort dest_port = port - SysPort; + WORD *TxPktP; + PKT *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 = (PKT *) RIO_PTR(HostP->Caddr, + RWORD(*TxPktP)); + rio_dprintk (RIO_DEBUG_TABLE, + "Tx packet (%x) destination: Old %x:%x New %x:%x\n", + *TxPktP, Pkt->dest_unit, + Pkt->dest_port, dest_unit, dest_port); + WWORD(Pkt->dest_unit, dest_unit); + WWORD(Pkt->dest_port, dest_port); + } + rio_dprintk (RIO_DEBUG_TABLE, + "Port %d phb destination: Old %x:%x New %x:%x\n", + port, PortP->PhbP->destination & 0xff, + (PortP->PhbP->destination >> 8) & 0xff, + dest_unit, dest_port); + WWORD(PortP->PhbP->destination, + dest_unit + (dest_port << 8)); + } + rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags); + } + } + rio_dprintk (RIO_DEBUG_TABLE, "Entry nulled.\n"); + bzero((char *)HostMapP,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 ) { + bzero((char *)&p->RIOSavedTable[entry],sizeof(struct Map)); + work_done++; + } + if ( p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum ) { + bzero((char *)&p->RIOConnectTable[entry],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 != (ushort)-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 == (ushort)-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 = (ushort)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) + CCOPY( MapP->Name, HostMapP->Name, MAX_NAME_LEN ); + HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED; +#if 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(p, HostP, HostMapP) +struct rio_info * p; +struct Host *HostP; +struct Map *HostMapP; +{ + register struct Port *PortP; + uint SubEnt; + uint HostPort; + uint SysPort; + ushort RtaType; + unsigned long flags; + +#ifdef CHECK + CheckHostP( HostP ); + CheckHostMapP( HostMapP ); +#endif + + 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]; +#if 0 + PortP->TtyP = &p->channel[SysPort]; +#endif + 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 *PhbP = PortP->PhbP = &HostP->PhbP[HostPort]; + PortP->TxAdd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_add)); + PortP->TxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_start)); + PortP->TxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->tx_end)); + PortP->RxRemove=(WORD *)RIO_PTR(HostP->Caddr, + RWORD(PhbP->rx_remove)); + PortP->RxStart =(WORD *)RIO_PTR(HostP->Caddr,RWORD(PhbP->rx_start)); + PortP->RxEnd =(WORD *)RIO_PTR(HostP->Caddr,RWORD(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 = TRUE; + } + else { + PortP->ID2 = 0; + PortP->SecondBlock = FALSE; + } + 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]; +#ifdef STATS + bzero( (caddr_t)&PortP->Stat, sizeof(struct RIOStats) ); +#endif + PortP->statsGather = 0; + PortP->txchars = 0; + PortP->rxchars = 0; + PortP->opens = 0; + PortP->closes = 0; + PortP->ioctls = 0; + if ( PortP->TxRingBuffer ) + bzero( PortP->TxRingBuffer, p->RIOBufferSize ); + else if ( p->RIOBufferSize ) { + PortP->TxRingBuffer = sysbrk(p->RIOBufferSize); + bzero( PortP->TxRingBuffer, p->RIOBufferSize ); + } + 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 = ~(uchar)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(p, MapP) +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 ) { + CCOPY( MapP->Name, p->RIOHosts[host].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; + } + CCOPY( MapP->Name, HostMapP->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/riotime.h b/drivers/char/rio/riotime.h new file mode 100644 index 000000000000..66d52bc0549b --- /dev/null +++ b/drivers/char/rio/riotime.h @@ -0,0 +1,63 @@ +/**************************************************************************** + ******* ******* + ******* T I M E + ******* ******* + **************************************************************************** + + Author : 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 _riotime_h +#define _riotime_h 1 + +#ifndef lint +#ifdef SCCS +static char *_rio_riotime_h_sccs = "@(#)riotime.h 1.1" ; +#endif +#endif + +#define TWO_POWER_FIFTEEN (ushort)32768 +#define RioTime() riotime +#define RioTimeAfter(time1,time2) ((ushort)time1 - (ushort)time2) < TWO_POWER_FIFTEEN +#define RioTimePlus(time1,time2) ((ushort)time1 + (ushort)time2) + +/************************************** + * Convert a RIO tick (1/10th second) + * into transputer low priority ticks + *************************************/ +#define RioTimeToLow(time) (time*(100000 / 64)) +#define RioLowToTime(time) ((time*64)/100000) + +#define RIOTENTHSECOND (ushort)1 +#define RIOSECOND (ushort)(RIOTENTHSECOND * 10) +#endif + +/*********** end of file ***********/ diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c new file mode 100644 index 000000000000..db655002671f --- /dev/null +++ b/drivers/char/rio/riotty.c @@ -0,0 +1,1376 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 +** +** ----------------------------------------------------------------------------- +*/ +#ifdef SCCS_LABELS +static char *_riotty_c_sccs_ = "@(#)riotty.c 1.3"; +#endif + + +#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/semaphore.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 "typdef.h" +#include "pkt.h" +#include "daemon.h" +#include "rio.h" +#include "riospace.h" +#include "top.h" +#include "cmdpkt.h" +#include "map.h" +#include "riotypes.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 "error.h" +#include "phb.h" +#include "link.h" +#include "cmdblk.h" +#include "route.h" +#include "control.h" +#include "cirrus.h" +#include "rioioctl.h" +#include "param.h" +#include "list.h" +#include "sam.h" + +#if 0 +static void ttyseth_pv(struct Port *, struct ttystatics *, + struct termios *sg, int); +#endif + +static void RIOClearUp(struct Port *PortP); +int RIOShortCommand(struct rio_info *p, struct Port *PortP, + int command, int len, int arg); + +#if 0 +static int RIOCookMode(struct ttystatics *); +#endif + +extern int conv_vb[]; /* now defined in ttymgr.c */ +extern int conv_bv[]; /* now defined in ttymgr.c */ + +/* +** 16.09.1998 ARG - Fix to build riotty.k.o for Modular Kernel Support +** +** ep.def.h is necessary for Modular Kernel Support +** DO NOT place any kernel 'extern's after this line +** or this source file will not build riotty.k.o +*/ +#ifdef uLYNX +#include <ep.def.h> +#endif + +#ifdef NEED_THIS2 +static struct old_sgttyb +default_sg = +{ + 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 + + +extern struct rio_info *p; + + +int +riotopen(struct tty_struct * tty, struct file * filp) +{ + register uint SysPort; + int Modem; + 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); + Modem = rio_ismodem(tty); + + if ( p->RIOFailed ) { + rio_dprintk (RIO_DEBUG_TTY, "System initialisation failed\n"); + pseterr(ENXIO); + func_exit (); + return -ENXIO; + } + + rio_dprintk (RIO_DEBUG_TTY, "port open SysPort %d (%s) (mapped:%d)\n", + SysPort, Modem ? "Modem" : "tty", + 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); + pseterr(ENXIO); + 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 (); + pseterr(ENXIO); + return -ENXIO; + } + + tty->driver_data = PortP; + + PortP->gs.tty = tty; + PortP->gs.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.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"); + pseterr(ENXIO); + 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. + */ +#if 0 + if (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { + if (PortP->WaitUntilBooted) { + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot\n"); + do { + if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); + func_exit (); + return -EINTR; + } + if (repeat_this -- <= 0) { + rio_dprintk (RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); + RIOPreemptiveCmd(p, PortP, FCLOSE ); + pseterr(EINTR); + func_exit (); + return -EIO; + } + } while(!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)); + rio_dprintk (RIO_DEBUG_TTY, "RTA has been booted\n"); + } else { + rio_dprintk (RIO_DEBUG_TTY, "RTA never booted\n"); + pseterr(ENXIO); + func_exit (); + return 0; + } + } +#else + /* 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"); +#endif +#if 0 + tp = PortP->TtyP; /* get tty struct */ +#endif + rio_spin_lock_irqsave(&PortP->portSem, flags); + if ( p->RIOHalted ) { + goto bombout; + } +#if 0 + retval = gs_init_port(&PortP->gs); + if (retval){ + func_exit (); + return retval; + } +#endif + + /* + ** 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, 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); +#ifdef NEED_THIS + ttyseth(PortP, tp, (struct old_sgttyb *)&default_sg); +#endif + + /* 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,OPEN,Modem,OK_TO_SLEEP); /* Open the port */ +#if 0 + /* This delay of 1 second was annoying. I removed it. -- REW */ + RIODelay(PortP, HUNDRED_MS*10); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); /* Config the port */ +#endif + 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); +/* +** 15.10.1998 ARG - ESIL 0759 +** (Part) fix for port being trashed when opened whilst RTA "disconnected" +** Take out the limited wait - now wait for ever or until user +** bangs us out. +** + if (repeat_this -- <= 0) { + rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish timed out.\n")); + RIOPreemptiveCmd(p, PortP, FCLOSE ); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return -EINTR; + } +** +*/ + 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, 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"); + } + +#ifdef MODEM_SUPPORT + if (Modem) { + 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.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & 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.open_wait); + } + else /* no carrier - wait for DCD */ + { + /* + while (!(PortP->gs.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.tty->termios->c_state |= WOPEN; + */ + PortP->State |= RIO_WOPEN; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + if (RIODelay (PortP, HUNDRED_MS) == RIO_FAIL) +#if 0 + if ( sleep((caddr_t)&tp->tm.c_canqo, TTIPRI|PCATCH)) +#endif + { + /* + ** 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, FCLOSE ); + /* + tp->tm.c_state &= ~WOPEN; + */ + PortP->State &= ~RIO_WOPEN; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + func_exit (); + return -EINTR; + } + } + PortP->State &= ~RIO_WOPEN; + } + if ( p->RIOHalted ) + goto bombout; + rio_dprintk (RIO_DEBUG_TTY, "Setting RIO_MOPEN\n"); + PortP->State |= RIO_MOPEN; + } + else +#endif + { + /* + ** ACTION + ** Direct line open - force carrier (will probably mean + ** that sleeping Modem line fubar) + */ + PortP->State |= RIO_LOPEN; + } + + if ( p->RIOHalted ) { + goto bombout; + } + + rio_dprintk (RIO_DEBUG_TTY, "high level open done\n"); + +#ifdef STATS + PortP->Stat.OpenCnt++; +#endif + /* + ** 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) +{ +#if 0 + register uint SysPort = dev; + struct ttystatics *tp; /* pointer to our ttystruct */ +#endif + 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.) */ + long end_time; + struct tty_struct * tty; + unsigned long flags; + int Modem; + 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 0x%x\n",(int)PortP); + /* tp = PortP->TtyP;*/ /* Get tty */ + tty = PortP->gs.tty; + rio_dprintk (RIO_DEBUG_TTY, "TTY is at address 0x%x\n",(int)tty); + + if (PortP->gs.closing_wait) + end_time = jiffies + PortP->gs.closing_wait; + else + end_time = jiffies + MAX_SCHEDULE_TIMEOUT; + + Modem = rio_ismodem(tty); +#if 0 + /* What F.CKING cache? Even then, a higly idle multiprocessor, + system with large caches this won't work . Better find out when + this doesn't work asap, and fix the cause. -- REW */ + + RIODelay(PortP, HUNDRED_MS*10); /* To flush the cache */ +#endif + 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 &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN); + PortP->State &= ~RIO_CARR_ON; + PortP->ModemState &= ~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) ) { + cprintf("Need to flush the ttyport\n"); + if (repeat_this -- <= 0) { + rv = -EINTR; + rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); + RIOPreemptiveCmd(p, PortP, 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, CLOSE, 1, 0) == RIO_FAIL) { + RIOPreemptiveCmd(p, PortP,FCLOSE); + 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,FCLOSE); + break; + } + rio_dprintk (RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", + PortP->PortState & PORT_ISOPEN); + + if ( p->RIOHalted ) { + RIOClearUp( PortP ); + goto close_end; + } + if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { + rio_dprintk (RIO_DEBUG_TTY, "RTA EINTR in delay \n"); + RIOPreemptiveCmd(p, PortP,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, 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); + + +#ifdef STATS + PortP->Stat.CloseCnt++; +#endif + /* + ** 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; +} + + +/* +** decide if we need to use the line discipline. +** This routine can return one of three values: +** COOK_RAW if no processing has to be done by the line discipline or the card +** COOK_WELL if the line discipline must be used to do the processing +** COOK_MEDIUM if the card can do all the processing necessary. +*/ +#if 0 +static int +RIOCookMode(struct ttystatics *tp) +{ + /* + ** We can't handle tm.c_mstate != 0 on SCO + ** We can't handle mapping + ** We can't handle non-ttwrite line disc. + ** We can't handle lflag XCASE + ** We can handle oflag OPOST & (OCRNL, ONLCR, TAB3) + */ + +#ifdef CHECK + CheckTtyP( tp ); +#endif + if (!(tp->tm.c_oflag & OPOST)) /* No post processing */ + return COOK_RAW; /* Raw mode o/p */ + + if ( tp->tm.c_lflag & XCASE ) + return COOK_WELL; /* Use line disc */ + + if (tp->tm.c_oflag & ~(OPOST | ONLCR | OCRNL | TAB3 ) ) + return COOK_WELL; /* Use line disc for strange modes */ + + if ( tp->tm.c_oflag == OPOST ) /* If only OPOST is set, do RAW */ + return COOK_RAW; + + /* + ** So, we need to output process! + */ + return COOK_MEDIUM; +} +#endif + +static void +RIOClearUp(PortP) +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) +{ + PKT *PacketP; + int retries = 20; /* at 10 per second -> 2 seconds */ + unsigned long flags; + + rio_dprintk (RIO_DEBUG_TTY, "entering shortcommand.\n"); +#ifdef CHECK + CheckPortP( PortP ); + if ( len < 1 || len > 2 ) + cprintf(("STUPID LENGTH %d\n",len)); +#endif + + 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 + */ + WBYTE(PacketP->data[0] , command); + + if ( len==2 ) + WBYTE(PacketP->data[1] , arg); + + /* + ** set the length of the packet and set the command bit. + */ + WBYTE(PacketP->len , PKT_CMD_BIT | 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; +} + + +#if 0 +/* +** This is an ioctl interface. This is the twentieth century. You know what +** its all about. +*/ +int +riotioctl(struct rio_info *p, struct tty_struct *tty, int cmd, caddr_t arg) +{ + register struct Port *PortP; + register struct ttystatics *tp; + int current; + int ParamSemIncremented = 0; + int old_oflag, old_cflag, old_iflag, changed, oldcook; + int i; + unsigned char sio_regs[5]; /* Here be magic */ + short vpix_cflag; + short divisor; + int baud; + uint SysPort = rio_minor(tty); + int Modem = rio_ismodem(tty); + int ioctl_processed; + + rio_dprintk (RIO_DEBUG_TTY, "port ioctl SysPort %d command 0x%x argument 0x%x %s\n", + SysPort, cmd, arg, Modem?"Modem":"tty") ; + + if ( SysPort >= RIO_PORTS ) { + rio_dprintk (RIO_DEBUG_TTY, "Bad port number %d\n", SysPort); + return -ENXIO; + } + + PortP = p->RIOPortp[SysPort]; + tp = PortP->TtyP; + + rio_spin_lock_irqsave(&PortP->portSem, flags); + +#ifdef STATS + PortP->Stat.IoctlCnt++; +#endif + + if ( PortP->State & RIO_DELETED ) { + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return -EIO; + } + + + if ( p->RIOHalted ) { + RIOClearUp( PortP ); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return -EIO; + } + + /* + ** Count ioctls for port statistics reporting + */ + if (PortP->statsGather) + PortP->ioctls++; + + /* + ** Specialix RIO Ioctl calls + */ + switch (cmd) { + + case TCRIOTRIAD: + if ( arg ) + PortP->State |= RIO_TRIAD_MODE; + else + PortP->State &= ~RIO_TRIAD_MODE; + /* + ** Normally, when istrip is set on a port, a config is + ** sent to the RTA instructing the CD1400 to do the + ** stripping. In TRIAD mode, the interrupt receive routine + ** must do the stripping instead, since it has to detect + ** an 8 bit function key sequence. If istrip is set with + ** TRIAD mode on(off), and 8 bit data is being read by + ** the port, the user then turns TRIAD mode off(on), the RTA + ** must be reconfigured (not) to do the stripping. + ** Hence we call RIOParam here. + */ + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); + return 0; + + case TCRIOTSTATE: + rio_dprintk (RIO_DEBUG_TTY, "tbusy/tstop monitoring %sabled\n", + arg ? "en" : "dis"); + /* MonitorTstate = 0 ;*/ + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOParam(PortP, CONFIG, Modem, OK_TO_SLEEP); + return 0; + + case TCRIOSTATE: /* current state of Modem input pins */ + rio_dprintk (RIO_DEBUG_TTY, "TCRIOSTATE\n"); + if (RIOPreemptiveCmd(p, PortP, MGET) == RIO_FAIL) + rio_dprintk (RIO_DEBUG_TTY, "TCRIOSTATE command failed\n"); + PortP->State |= RIO_BUSY; + current = PortP->ModemState; + if ( copyout((caddr_t)¤t, (int)arg, + sizeof(current))==COPYFAIL ) { + rio_dprintk (RIO_DEBUG_TTY, "Copyout failed\n"); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EFAULT); + } + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOMBIS: /* Set modem lines */ + case TCRIOMBIC: /* Clear modem lines */ + rio_dprintk (RIO_DEBUG_TTY, "TCRIOMBIS/TCRIOMBIC\n"); + if (cmd == TCRIOMBIS) { + uint state; + state = (uint)arg; + PortP->ModemState |= (ushort)state; + PortP->ModemLines = (ulong) arg; + if (RIOPreemptiveCmd(p, PortP, MBIS) == RIO_FAIL) + rio_dprintk (RIO_DEBUG_TTY, + "TCRIOMBIS command failed\n"); + } + else { + uint state; + + state = (uint)arg; + PortP->ModemState &= ~(ushort)state; + PortP->ModemLines = (ulong) arg; + if (RIOPreemptiveCmd(p, PortP, MBIC) == RIO_FAIL) + rio_dprintk (RIO_DEBUG_TTY, "TCRIOMBIC command failed\n"); + } + PortP->State |= RIO_BUSY; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOXPON: /* set Xprint ON string */ + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPON\n"); + if ( copyin((int)arg, (caddr_t)PortP->Xprint.XpOn, + MAX_XP_CTRL_LEN)==COPYFAIL ) { + rio_dprintk (RIO_DEBUG_TTY, "Copyin failed\n"); + PortP->Xprint.XpOn[0] = '\0'; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EFAULT); + } + PortP->Xprint.XpOn[MAX_XP_CTRL_LEN-1] = '\0'; + PortP->Xprint.XpLen = strlen(PortP->Xprint.XpOn)+ + strlen(PortP->Xprint.XpOff); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOXPOFF: /* set Xprint OFF string */ + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPOFF\n"); + if ( copyin( (int)arg, (caddr_t)PortP->Xprint.XpOff, + MAX_XP_CTRL_LEN)==COPYFAIL ) { + rio_dprintk (RIO_DEBUG_TTY, "Copyin failed\n"); + PortP->Xprint.XpOff[0] = '\0'; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EFAULT); + } + PortP->Xprint.XpOff[MAX_XP_CTRL_LEN-1] = '\0'; + PortP->Xprint.XpLen = strlen(PortP->Xprint.XpOn)+ + strlen(PortP->Xprint.XpOff); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOXPCPS: /* set Xprint CPS string */ + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPCPS\n"); + if ( (uint)arg > p->RIOConf.MaxXpCps || + (uint)arg < p->RIOConf.MinXpCps ) { + rio_dprintk (RIO_DEBUG_TTY, "%d CPS out of range\n",arg); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EINVAL); + return 0; + } + PortP->Xprint.XpCps = (uint)arg; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOXPRINT: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOXPRINT\n"); + if ( copyout((caddr_t)&PortP->Xprint, (int)arg, + sizeof(struct Xprint))==COPYFAIL ) { + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EFAULT); + } + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOIXANYON: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXANYON\n"); + PortP->Config |= RIO_IXANY; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOIXANYOFF: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXANYOFF\n"); + PortP->Config &= ~RIO_IXANY; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOIXONON: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXONON\n"); + PortP->Config |= RIO_IXON; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + + case TCRIOIXONOFF: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOIXONOFF\n"); + PortP->Config &= ~RIO_IXON; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; + +/* +** 15.10.1998 ARG - ESIL 0761 part fix +** Added support for CTS and RTS flow control ioctls : +*/ + case TCRIOCTSFLOWEN: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOCTSFLOWEN\n"); + PortP->Config |= RIO_CTSFLOW; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); + return 0; + + case TCRIOCTSFLOWDIS: + rio_dprintk (RIO_DEBUG_TTY, "TCRIOCTSFLOWDIS\n"); + PortP->Config &= ~RIO_CTSFLOW; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); + return 0; + + case TCRIORTSFLOWEN: + rio_dprintk (RIO_DEBUG_TTY, "TCRIORTSFLOWEN\n"); + PortP->Config |= RIO_RTSFLOW; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); + return 0; + + case TCRIORTSFLOWDIS: + rio_dprintk (RIO_DEBUG_TTY, "TCRIORTSFLOWDIS\n"); + PortP->Config &= ~RIO_RTSFLOW; + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); + return 0; + +/* end ESIL 0761 part fix */ + + } + + + /* Lynx IOCTLS */ + switch (cmd) { + case TIOCSETP: + case TIOCSETN: + case OTIOCSETP: + case OTIOCSETN: + ioctl_processed++; + ttyseth(PortP, tp, (struct old_sgttyb *)arg); + break; + case TCSETA: + case TCSETAW: + case TCSETAF: + ioctl_processed++; + rio_dprintk (RIO_DEBUG_TTY, "NON POSIX ioctl\n"); + ttyseth_pv(PortP, tp, (struct termios *)arg, 0); + break; + case TCSETAP: /* posix tcsetattr() */ + case TCSETAWP: /* posix tcsetattr() */ + case TCSETAFP: /* posix tcsetattr() */ + rio_dprintk (RIO_DEBUG_TTY, "NON POSIX SYSV ioctl\n"); + ttyseth_pv(PortP, tp, (struct termios *)arg, 1); + ioctl_processed++; + break; + } + + /* + ** If its any of the commands that require the port to be in the + ** non-busy state wait until all output has drained + */ + if (!ioctl_processed) + switch(cmd) { + case TCSETAW: + case TCSETAF: + case TCSETA: + case TCSBRK: +#define OLD_POSIX ('x' << 8) +#define OLD_POSIX_SETA (OLD_POSIX | 2) +#define OLD_POSIX_SETAW (OLD_POSIX | 3) +#define OLD_POSIX_SETAF (OLD_POSIX | 4) +#define NEW_POSIX (('i' << 24) | ('X' << 16)) +#define NEW_POSIX_SETA (NEW_POSIX | 2) +#define NEW_POSIX_SETAW (NEW_POSIX | 3) +#define NEW_POSIX_SETAF (NEW_POSIX | 4) + case OLD_POSIX_SETA: + case OLD_POSIX_SETAW: + case OLD_POSIX_SETAF: + case NEW_POSIX_SETA: + case NEW_POSIX_SETAW: + case NEW_POSIX_SETAF: +#ifdef TIOCSETP + case TIOCSETP: +#endif + case TIOCSETD: + case TIOCSETN: + rio_dprintk (RIO_DEBUG_TTY, "wait for non-BUSY, semaphore set\n"); + /* + ** Wait for drain here, at least as far as the double buffer + ** being empty. + */ + /* XXX Does the above comment mean that this has + still to be implemented? -- REW */ + /* XXX Is the locking OK together with locking + in txenable? (Deadlock?) -- REW */ + + RIOTxEnable((char *)PortP); + break; + default: + break; + } + + old_cflag = tp->tm.c_cflag; + old_iflag = tp->tm.c_iflag; + old_oflag = tp->tm.c_oflag; + oldcook = PortP->CookMode; + + if ( p->RIOHalted ) { + RIOClearUp( PortP ); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EIO); + return 0; + } + + PortP->FlushCmdBodge = 0; + + /* + ** If the port is locked, and it is reconfigured, we want + ** to restore the state of the tty structure so the change is NOT + ** made. + */ + if (PortP->Lock) { + tp->tm.c_iflag = PortP->StoredTty.iflag; + tp->tm.c_oflag = PortP->StoredTty.oflag; + tp->tm.c_cflag = PortP->StoredTty.cflag; + tp->tm.c_lflag = PortP->StoredTty.lflag; + tp->tm.c_line = PortP->StoredTty.line; + for (i = 0; i < NCC + 1; i++) + tp->tm.c_cc[i] = PortP->StoredTty.cc[i]; + } + else { + /* + ** If the port is set to store the parameters, and it is + ** reconfigured, we want to save the current tty struct so it + ** may be restored on the next open. + */ + if (PortP->Store) { + PortP->StoredTty.iflag = tp->tm.c_iflag; + PortP->StoredTty.oflag = tp->tm.c_oflag; + PortP->StoredTty.cflag = tp->tm.c_cflag; + PortP->StoredTty.lflag = tp->tm.c_lflag; + PortP->StoredTty.line = tp->tm.c_line; + for (i = 0; i < NCC + 1; i++) + PortP->StoredTty.cc[i] = tp->tm.c_cc[i]; + } + } + + changed = (tp->tm.c_cflag != old_cflag) || + (tp->tm.c_iflag != old_iflag) || + (tp->tm.c_oflag != old_oflag); + + PortP->CookMode = RIOCookMode(tp); /* Set new cooking mode */ + + rio_dprintk (RIO_DEBUG_TTY, "RIOIoctl changed %d newcook %d oldcook %d\n", + changed,PortP->CookMode,oldcook); + +#ifdef MODEM_SUPPORT + /* + ** kludge to force CARR_ON if CLOCAL set + */ + if ((tp->tm.c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) { + tp->tm.c_state |= CARR_ON; + wakeup ((caddr_t)&tp->tm.c_canq); + } +#endif + + if ( p->RIOHalted ) { + RIOClearUp( PortP ); + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + pseterr(EIO); + return 0; + } + /* + ** Re-configure if modes or cooking have changed + */ + if (changed || oldcook != PortP->CookMode || (ioctl_processed)) { + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + rio_dprintk (RIO_DEBUG_TTY, "Ioctl changing the PORT settings\n"); + RIOParam(PortP,CONFIG,Modem,OK_TO_SLEEP); + rio_spin_lock_irqsave(&PortP->portSem, flags); + } + + if (p->RIOHalted) { + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + RIOClearUp( PortP ); + pseterr(EIO); + return 0; + } + rio_spin_unlock_irqrestore(&PortP->portSem, flags); + return 0; +} + +/* + ttyseth -- set hardware dependent tty settings +*/ +void +ttyseth(PortP, s, sg) +struct Port * PortP; +struct ttystatics * s; +struct old_sgttyb *sg; +{ + struct old_sgttyb * tsg; + struct termios *tp = &s->tm; + + tsg = &s->sg; + + if (sg->sg_flags & (EVENP|ODDP)) { + tp->c_cflag &= PARENB; + if (sg->sg_flags & EVENP) { + if (sg->sg_flags & ODDP) { + tp->c_cflag &= V_CS7; + tp->c_cflag &= ~PARENB; + } + else { + tp->c_cflag &= V_CS7; + tp->c_cflag &= PARENB; + tp->c_cflag &= PARODD; + } + } + else if (sg->sg_flags & ODDP) { + tp->c_cflag &= V_CS7; + tp->c_cflag &= PARENB; + tp->c_cflag &= PARODD; + } + else { + tp->c_cflag &= V_CS7; + tp->c_cflag &= PARENB; + } + } +/* + * Use ispeed as the desired speed. Most implementations don't handle + * separate input and output speeds very well. If the RIO handles this, + * I will have to use separate sets of flags to store them in the + * Port structure. + */ + if ( !sg->sg_ospeed ) + sg->sg_ospeed = sg->sg_ispeed; + else + sg->sg_ispeed = sg->sg_ospeed; + if (sg->sg_ispeed > V_EXTB ) + sg->sg_ispeed = V_EXTB; + if (sg->sg_ispeed < V_B0) + sg->sg_ispeed = V_B0; + *tsg = *sg; + tp->c_cflag = (tp->c_cflag & ~V_CBAUD) | conv_bv[(int)sg->sg_ispeed]; +} + +/* + ttyseth_pv -- set hardware dependent tty settings using either the + POSIX termios structure or the System V termio structure. + sysv = 0 => (POSIX): struct termios *sg + sysv != 0 => (System V): struct termio *sg +*/ +static void +ttyseth_pv(PortP, s, sg, sysv) +struct Port *PortP; +struct ttystatics *s; +struct termios *sg; +int sysv; +{ + int speed; + unsigned char csize; + unsigned char cread; + unsigned int lcr_flags; + int ps; + + if (sysv) { + /* sg points to a System V termio structure */ + csize = ((struct termio *)sg)->c_cflag & CSIZE; + cread = ((struct termio *)sg)->c_cflag & CREAD; + speed = conv_vb[((struct termio *)sg)->c_cflag & V_CBAUD]; + } + else { + /* sg points to a POSIX termios structure */ + csize = sg->c_cflag & CSIZE; + cread = sg->c_cflag & CREAD; + speed = conv_vb[sg->c_cflag & V_CBAUD]; + } + if (s->sg.sg_ispeed != speed || s->sg.sg_ospeed != speed) { + s->sg.sg_ispeed = speed; + s->sg.sg_ospeed = speed; + s->tm.c_cflag = (s->tm.c_cflag & ~V_CBAUD) | + conv_bv[(int)s->sg.sg_ispeed]; + } +} +#endif diff --git a/drivers/char/rio/riotypes.h b/drivers/char/rio/riotypes.h new file mode 100644 index 000000000000..1c7c42c638f0 --- /dev/null +++ b/drivers/char/rio/riotypes.h @@ -0,0 +1,135 @@ +/**************************************************************************** + ******* ******* + ******* R I O T Y P E S + ******* ******* + **************************************************************************** + + Author : Jon Brawn + 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 _riotypes_h +#define _riotypes_h 1 + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_riotypes_h_sccs = "@(#)riotypes.h 1.10"; */ +#endif +#endif + +#ifdef INKERNEL + +#if !defined(MIPSAT) +typedef unsigned short NUMBER_ptr; +typedef unsigned short WORD_ptr; +typedef unsigned short BYTE_ptr; +typedef unsigned short char_ptr; +typedef unsigned short Channel_ptr; +typedef unsigned short FREE_LIST_ptr_ptr; +typedef unsigned short FREE_LIST_ptr; +typedef unsigned short LPB_ptr; +typedef unsigned short Process_ptr; +typedef unsigned short PHB_ptr; +typedef unsigned short PKT_ptr; +typedef unsigned short PKT_ptr_ptr; +typedef unsigned short Q_BUF_ptr; +typedef unsigned short Q_BUF_ptr_ptr; +typedef unsigned short ROUTE_STR_ptr; +typedef unsigned short RUP_ptr; +typedef unsigned short short_ptr; +typedef unsigned short u_short_ptr; +typedef unsigned short ushort_ptr; +#else +/* MIPSAT types */ +typedef char RIO_POINTER[8]; +typedef RIO_POINTER NUMBER_ptr; +typedef RIO_POINTER WORD_ptr; +typedef RIO_POINTER BYTE_ptr; +typedef RIO_POINTER char_ptr; +typedef RIO_POINTER Channel_ptr; +typedef RIO_POINTER FREE_LIST_ptr_ptr; +typedef RIO_POINTER FREE_LIST_ptr; +typedef RIO_POINTER LPB_ptr; +typedef RIO_POINTER Process_ptr; +typedef RIO_POINTER PHB_ptr; +typedef RIO_POINTER PKT_ptr; +typedef RIO_POINTER PKT_ptr_ptr; +typedef RIO_POINTER Q_BUF_ptr; +typedef RIO_POINTER Q_BUF_ptr_ptr; +typedef RIO_POINTER ROUTE_STR_ptr; +typedef RIO_POINTER RUP_ptr; +typedef RIO_POINTER short_ptr; +typedef RIO_POINTER u_short_ptr; +typedef RIO_POINTER ushort_ptr; +#endif + +#else /* not INKERNEL */ +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef short NUMBER; +typedef short *NUMBER_ptr; +typedef unsigned short *WORD_ptr; +typedef unsigned char *BYTE_ptr; +typedef unsigned char uchar ; +typedef unsigned short ushort ; +typedef unsigned int uint ; +typedef unsigned long ulong ; +typedef unsigned char u_char ; +typedef unsigned short u_short ; +typedef unsigned int u_int ; +typedef unsigned long u_long ; +typedef unsigned short ERROR ; +typedef unsigned long ID ; +typedef char *char_ptr; +typedef Channel *Channel_ptr; +typedef struct FREE_LIST *FREE_LIST_ptr; +typedef struct FREE_LIST **FREE_LIST_ptr_ptr; +typedef struct LPB *LPB_ptr; +typedef struct Process *Process_ptr; +typedef struct PHB *PHB_ptr; +typedef struct PKT *PKT_ptr; +typedef struct PKT **PKT_ptr_ptr; +typedef struct Q_BUF *Q_BUF_ptr; +typedef struct Q_BUF **Q_BUF_ptr_ptr; +typedef struct ROUTE_STR *ROUTE_STR_ptr; +typedef struct RUP *RUP_ptr; +typedef short *short_ptr; +typedef u_short *u_short_ptr; +typedef ushort *ushort_ptr; +typedef struct PKT PKT; +typedef struct LPB LPB; +typedef struct RUP RUP; +#endif + + +#endif /* __riotypes__ */ + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/riowinif.h b/drivers/char/rio/riowinif.h new file mode 100644 index 000000000000..18a4f147edc2 --- /dev/null +++ b/drivers/char/rio/riowinif.h @@ -0,0 +1,1335 @@ +/************************************************************************/ +/* */ +/* Title : RIO Shared Memory Window Inteface */ +/* */ +/* Author : N.P.Vassallo */ +/* */ +/* Creation : 7th June 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 RIO host card shared memory */ +/* window interface structures: */ +/* PARMMAP */ +/* RUP */ +/* PHB */ +/* LPB */ +/* PKT */ +/* */ +/************************************************************************/ + +/* History... + +1.0.0 07/06/99 NPV Creation. (based on PARMMAP.H) + +*/ + +#ifndef _riowinif_h /* If RIOWINDIF.H not already defined */ +#define _riowinif_h 1 + +/***************************************************************************** +******************************** ********************************* +******************************** General ********************************* +******************************** ********************************* +*****************************************************************************/ + +#define TPNULL ((_u16)(0x8000)) + +/***************************************************************************** +******************************** ******************************** +******************************** PARM_MAP ******************************** +******************************** ******************************** +*****************************************************************************/ + +/* The PARM_MAP structure defines global values relating to the Host Card / RTA + and is the main structure from which all other structures are referenced. */ + +typedef struct _PARM_MAP +{ + _u16 phb_ptr; /* 0x00 Pointer to the PHB array */ + _u16 phb_num_ptr; /* 0x02 Ptr to Number of PHB's */ + _u16 free_list; /* 0x04 Free List pointer */ + _u16 free_list_end; /* 0x06 Free List End pointer */ + _u16 q_free_list_ptr; /* 0x08 Ptr to Q_BUF variable */ + _u16 unit_id_ptr; /* 0x0A Unit Id */ + _u16 link_str_ptr; /* 0x0C Link Structure Array */ + _u16 bootloader_1; /* 0x0E 1st Stage Boot Loader */ + _u16 bootloader_2; /* 0x10 2nd Stage Boot Loader */ + _u16 port_route_map_ptr; /* 0x12 Port Route Map */ + _u16 route_ptr; /* 0x14 Route Map */ + _u16 map_present; /* 0x16 Route Map present */ + _u16 pkt_num; /* 0x18 Total number of packets */ + _u16 q_num; /* 0x1A Total number of Q packets */ + _u16 buffers_per_port; /* 0x1C Number of buffers per port */ + _u16 heap_size; /* 0x1E Initial size of heap */ + _u16 heap_left; /* 0x20 Current Heap left */ + _u16 error; /* 0x22 Error code */ + _u16 tx_max; /* 0x24 Max number of tx pkts per phb */ + _u16 rx_max; /* 0x26 Max number of rx pkts per phb */ + _u16 rx_limit; /* 0x28 For high / low watermarks */ + _u16 links; /* 0x2A Links to use */ + _u16 timer; /* 0x2C Interrupts per second */ + _u16 rups; /* 0x2E Pointer to the RUPs */ + _u16 max_phb; /* 0x30 Mostly for debugging */ + _u16 living; /* 0x32 Just increments!! */ + _u16 init_done; /* 0x34 Initialisation over */ + _u16 booting_link; /* 0x36 */ + _u16 idle_count; /* 0x38 Idle time counter */ + _u16 busy_count; /* 0x3A Busy counter */ + _u16 idle_control; /* 0x3C Control Idle Process */ + _u16 tx_intr; /* 0x3E TX interrupt pending */ + _u16 rx_intr; /* 0x40 RX interrupt pending */ + _u16 rup_intr; /* 0x42 RUP interrupt pending */ + +} PARM_MAP; + +/* Same thing again, but defined as offsets... */ + +#define PM_phb_ptr 0x00 /* 0x00 Pointer to the PHB array */ +#define PM_phb_num_ptr 0x02 /* 0x02 Ptr to Number of PHB's */ +#define PM_free_list 0x04 /* 0x04 Free List pointer */ +#define PM_free_list_end 0x06 /* 0x06 Free List End pointer */ +#define PM_q_free_list_ptr 0x08 /* 0x08 Ptr to Q_BUF variable */ +#define PM_unit_id_ptr 0x0A /* 0x0A Unit Id */ +#define PM_link_str_ptr 0x0C /* 0x0C Link Structure Array */ +#define PM_bootloader_1 0x0E /* 0x0E 1st Stage Boot Loader */ +#define PM_bootloader_2 0x10 /* 0x10 2nd Stage Boot Loader */ +#define PM_port_route_map_ptr 0x12 /* 0x12 Port Route Map */ +#define PM_route_ptr 0x14 /* 0x14 Route Map */ +#define PM_map_present 0x16 /* 0x16 Route Map present */ +#define PM_pkt_num 0x18 /* 0x18 Total number of packets */ +#define PM_q_num 0x1A /* 0x1A Total number of Q packets */ +#define PM_buffers_per_port 0x1C /* 0x1C Number of buffers per port */ +#define PM_heap_size 0x1E /* 0x1E Initial size of heap */ +#define PM_heap_left 0x20 /* 0x20 Current Heap left */ +#define PM_error 0x22 /* 0x22 Error code */ +#define PM_tx_max 0x24 /* 0x24 Max number of tx pkts per phb */ +#define PM_rx_max 0x26 /* 0x26 Max number of rx pkts per phb */ +#define PM_rx_limit 0x28 /* 0x28 For high / low watermarks */ +#define PM_links 0x2A /* 0x2A Links to use */ +#define PM_timer 0x2C /* 0x2C Interrupts per second */ +#define PM_rups 0x2E /* 0x2E Pointer to the RUPs */ +#define PM_max_phb 0x30 /* 0x30 Mostly for debugging */ +#define PM_living 0x32 /* 0x32 Just increments!! */ +#define PM_init_done 0x34 /* 0x34 Initialisation over */ +#define PM_booting_link 0x36 /* 0x36 */ +#define PM_idle_count 0x38 /* 0x38 Idle time counter */ +#define PM_busy_count 0x3A /* 0x3A Busy counter */ +#define PM_idle_control 0x3C /* 0x3C Control Idle Process */ +#define PM_tx_intr 0x3E /* 0x4E TX interrupt pending */ +#define PM_rx_intr 0x40 /* 0x40 RX interrupt pending */ +#define PM_rup_intr 0x42 /* 0x42 RUP interrupt pending */ +#define sizeof_PARM_MAP 0x44 /* structure size = 0x44 */ + +/* PARM_MAP.error definitions... */ +#define E_NO_ERROR 0x00 +#define E_PROCESS_NOT_INIT 0x01 +#define E_LINK_TIMEOUT 0x02 +#define E_NO_ROUTE 0x03 +#define E_CONFUSED 0x04 +#define E_HOME 0x05 +#define E_CSUM_FAIL 0x06 +#define E_DISCONNECTED 0x07 +#define E_BAD_RUP 0x08 +#define E_NO_VIRGIN 0x09 +#define E_BOOT_RUP_BUSY 0x10 +#define E_CHANALLOC 0x80 +#define E_POLL_ALLOC 0x81 +#define E_LTTWAKE 0x82 +#define E_LTT_ALLOC 0x83 +#define E_LRT_ALLOC 0x84 +#define E_CIRRUS 0x85 +#define E_MONITOR 0x86 +#define E_PHB_ALLOC 0x87 +#define E_ARRAY_ALLOC 0x88 +#define E_QBUF_ALLOC 0x89 +#define E_PKT_ALLOC 0x8a +#define E_GET_TX_Q_BUF 0x8b +#define E_GET_RX_Q_BUF 0x8c +#define E_MEM_OUT 0x8d +#define E_MMU_INIT 0x8e +#define E_LTT_INIT 0x8f +#define E_LRT_INIT 0x90 +#define E_LINK_RUN 0x91 +#define E_MONITOR_ALLOC 0x92 +#define E_MONITOR_INIT 0x93 +#define E_POLL_INIT 0x94 + +/* PARM_MAP.links definitions... */ +#define RIO_LINK_ENABLE 0x80FF + +/***************************************************************************** +********************************** *********************************** +********************************** RUP *********************************** +********************************** *********************************** +*****************************************************************************/ + +/* The RUP (Remote Unit Port) structure relates to the Remote Terminal Adapters + attached to the system and there is normally an array of MAX_RUPS (=16) structures + in a host card, defined by PARM_MAP->rup. */ + +typedef struct _RUP +{ + _u16 txpkt; /* 0x00 Outgoing packet */ + _u16 rxpkt; /* 0x02 ncoming packet */ + _u16 link; /* 0x04 Which link to send packet down ? */ + _u8 rup_dest_unit[2]; /* 0x06 Destination Unit */ + _u16 handshake; /* 0x08 Handshaking */ + _u16 timeout; /* 0x0A Timeout */ + _u16 status; /* 0x0C Status */ + _u16 txcontrol; /* 0x0E Transmit control */ + _u16 rxcontrol; /* 0x10 Receive control */ + +} RUP; + +/* Same thing again, but defined as offsets... */ + +#define RUP_txpkt 0x00 /* 0x00 Outgoing packet */ +#define RUP_rxpkt 0x02 /* 0x02 Incoming packet */ +#define RUP_link 0x04 /* 0x04 Which link to send packet down ? */ +#define RUP_rup_dest_unit 0x06 /* 0x06 Destination Unit */ +#define RUP_handshake 0x08 /* 0x08 Handshaking */ +#define RUP_timeout 0x0A /* 0x0A Timeout */ +#define RUP_status 0x0C /* 0x0C Status */ +#define RUP_txcontrol 0x0E /* 0x0E Transmit control */ +#define RUP_rxcontrol 0x10 /* 0x10 Receive control */ +#define sizeof_RUP 0x12 /* structure size = 0x12 */ + +#define MAX_RUP 16 + +/* RUP.txcontrol definitions... */ +#define TX_RUP_INACTIVE 0 /* Nothing to transmit */ +#define TX_PACKET_READY 1 /* Transmit packet ready */ +#define TX_LOCK_RUP 2 /* Transmit side locked */ + +/* RUP.txcontrol definitions... */ +#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 */ + +/***************************************************************************** +********************************** *********************************** +********************************** PHB *********************************** +********************************** *********************************** +*****************************************************************************/ + +/* The PHB (Port Header Block) structure relates to the serial ports attached + to the system and there is normally an array of MAX_PHBS (=128) structures + in a host card, defined by PARM_MAP->phb_ptr and PARM_MAP->phb_num_ptr. */ + +typedef struct _PHB +{ + _u16 source; /* 0x00 Location of the PHB in the host card */ + _u16 handshake; /* 0x02 Used to manage receive packet flow control */ + _u16 status; /* 0x04 Internal port transmit/receive status */ + _u16 timeout; /* 0x06 Time period to wait for an ACK */ + _u16 link; /* 0x08 The host link associated with the PHB */ + _u16 destination; /* 0x0A Location of the remote port on the network */ + + _u16 tx_start; /* 0x0C first entry in the packet array for transmit packets */ + _u16 tx_end; /* 0x0E last entry in the packet array for transmit packets */ + _u16 tx_add; /* 0x10 position in the packet array for new transmit packets */ + _u16 tx_remove; /* 0x12 current position in the packet pointer array */ + + _u16 rx_start; /* 0x14 first entry in the packet array for receive packets */ + _u16 rx_end; /* 0x16 last entry in the packet array for receive packets */ + _u16 rx_add; /* 0x18 position in the packet array for new receive packets */ + _u16 rx_remove; /* 0x1A current position in the packet pointer array */ + +} PHB; + +/* Same thing again, but defined as offsets... */ + +#define PHB_source 0x00 /* 0x00 Location of the PHB in the host card */ +#define PHB_handshake 0x02 /* 0x02 Used to manage receive packet flow control */ +#define PHB_status 0x04 /* 0x04 Internal port transmit/receive status */ +#define PHB_timeout 0x06 /* 0x06 Time period to wait for an ACK */ +#define PHB_link 0x08 /* 0x08 The host link associated with the PHB */ +#define PHB_destination 0x0A /* 0x0A Location of the remote port on the network */ +#define PHB_tx_start 0x0C /* 0x0C first entry in the packet array for transmit packets */ +#define PHB_tx_end 0x0E /* 0x0E last entry in the packet array for transmit packets */ +#define PHB_tx_add 0x10 /* 0x10 position in the packet array for new transmit packets */ +#define PHB_tx_remove 0x12 /* 0x12 current position in the packet pointer array */ +#define PHB_rx_start 0x14 /* 0x14 first entry in the packet array for receive packets */ +#define PHB_rx_end 0x16 /* 0x16 last entry in the packet array for receive packets */ +#define PHB_rx_add 0x18 /* 0x18 position in the packet array for new receive packets */ +#define PHB_rx_remove 0x1A /* 0x1A current position in the packet pointer array */ +#define sizeof_PHB 0x1C /* structure size = 0x1C */ + +/* PHB.handshake definitions... */ +#define PHB_HANDSHAKE_SET 0x0001 /* Set by LRT */ +#define PHB_HANDSHAKE_RESET 0x0002 /* Set by ISR / driver */ +#define PHB_HANDSHAKE_FLAGS (PHB_HANDSHAKE_RESET|PHB_HANDSHAKE_SET) + /* Reset by ltt */ + +#define MAX_PHB 128 /* range 0-127 */ + +/***************************************************************************** +********************************** *********************************** +********************************** LPB *********************************** +********************************** *********************************** +*****************************************************************************/ + +/* The LPB (Link Parameter Block) structure relates to a RIO Network Link + and there is normally an array of MAX_LINKS (=4) structures in a host card, + defined by PARM_MAP->link_str_ptr. */ + +typedef struct _LPB +{ + _u16 link_number; /* 0x00 Link Number */ + _u16 in_ch; /* 0x02 Link In Channel */ + _u16 out_ch; /* 0x04 Link Out Channel */ + _u8 attached_serial[4]; /* 0x06 Attached serial number */ + _u8 attached_host_serial[4];/* 0x0A Serial number of Host who booted other end */ + _u16 descheduled; /* 0x0E Currently Descheduled */ + _u16 state; /* 0x10 Current state */ + _u16 send_poll; /* 0x12 Send a Poll Packet */ + _u16 ltt_p; /* 0x14 Process Descriptor */ + _u16 lrt_p; /* 0x16 Process Descriptor */ + _u16 lrt_status; /* 0x18 Current lrt status */ + _u16 ltt_status; /* 0x1A Current ltt status */ + _u16 timeout; /* 0x1C Timeout value */ + _u16 topology; /* 0x1E Topology bits */ + _u16 mon_ltt; /* 0x20 */ + _u16 mon_lrt; /* 0x22 */ + _u16 num_pkts; /* 0x24 */ + _u16 add_packet_list; /* 0x26 Add packets to here */ + _u16 remove_packet_list; /* 0x28 Send packets from here */ + + _u16 lrt_fail_chan; /* 0x2A Lrt's failure channel */ + _u16 ltt_fail_chan; /* 0x2C Ltt's failure channel */ + + RUP rup; /* 0x2E RUP structure for HOST to driver comms */ + RUP link_rup; /* 0x40 RUP for the link (POLL, topology etc.) */ + _u16 attached_link; /* 0x52 Number of attached link */ + _u16 csum_errors; /* 0x54 csum errors */ + _u16 num_disconnects; /* 0x56 number of disconnects */ + _u16 num_sync_rcvd; /* 0x58 # sync's received */ + _u16 num_sync_rqst; /* 0x5A # sync requests */ + _u16 num_tx; /* 0x5C Num pkts sent */ + _u16 num_rx; /* 0x5E Num pkts received */ + _u16 module_attached; /* 0x60 Module tpyes of attached */ + _u16 led_timeout; /* 0x62 LED timeout */ + _u16 first_port; /* 0x64 First port to service */ + _u16 last_port; /* 0x66 Last port to service */ + +} LPB; + +/* Same thing again, but defined as offsets... */ + +#define LPB_link_number 0x00 /* 0x00 Link Number */ +#define LPB_in_ch 0x02 /* 0x02 Link In Channel */ +#define LPB_out_ch 0x04 /* 0x04 Link Out Channel */ +#define LPB_attached_serial 0x06 /* 0x06 Attached serial number */ +#define LPB_attached_host_serial 0x0A /* 0x0A Serial number of Host who booted other end */ +#define LPB_descheduled 0x0E /* 0x0E Currently Descheduled */ +#define LPB_state 0x10 /* 0x10 Current state */ +#define LPB_send_poll 0x12 /* 0x12 Send a Poll Packet */ +#define LPB_ltt_p 0x14 /* 0x14 Process Descriptor */ +#define LPB_lrt_p 0x16 /* 0x16 Process Descriptor */ +#define LPB_lrt_status 0x18 /* 0x18 Current lrt status */ +#define LPB_ltt_status 0x1A /* 0x1A Current ltt status */ +#define LPB_timeout 0x1C /* 0x1C Timeout value */ +#define LPB_topology 0x1E /* 0x1E Topology bits */ +#define LPB_mon_ltt 0x20 /* 0x20 */ +#define LPB_mon_lrt 0x22 /* 0x22 */ +#define LPB_num_pkts 0x24 /* 0x24 */ +#define LPB_add_packet_list 0x26 /* 0x26 Add packets to here */ +#define LPB_remove_packet_list 0x28 /* 0x28 Send packets from here */ +#define LPB_lrt_fail_chan 0x2A /* 0x2A Lrt's failure channel */ +#define LPB_ltt_fail_chan 0x2C /* 0x2C Ltt's failure channel */ +#define LPB_rup 0x2E /* 0x2E RUP structure for HOST to driver comms */ +#define LPB_link_rup 0x40 /* 0x40 RUP for the link (POLL, topology etc.) */ +#define LPB_attached_link 0x52 /* 0x52 Number of attached link */ +#define LPB_csum_errors 0x54 /* 0x54 csum errors */ +#define LPB_num_disconnects 0x56 /* 0x56 number of disconnects */ +#define LPB_num_sync_rcvd 0x58 /* 0x58 # sync's received */ +#define LPB_num_sync_rqst 0x5A /* 0x5A # sync requests */ +#define LPB_num_tx 0x5C /* 0x5C Num pkts sent */ +#define LPB_num_rx 0x5E /* 0x5E Num pkts received */ +#define LPB_module_attached 0x60 /* 0x60 Module tpyes of attached */ +#define LPB_led_timeout 0x62 /* 0x62 LED timeout */ +#define LPB_first_port 0x64 /* 0x64 First port to service */ +#define LPB_last_port 0x66 /* 0x66 Last port to service */ +#define sizeof_LPB 0x68 /* structure size = 0x68 */ + +#define LINKS_PER_UNIT 4 /* number of links from a host */ + +/***************************************************************************** +******************************** ******************************* +******************************** FREE_LIST ******************************* +******************************** ******************************* +*****************************************************************************/ + +/* Used to overlay packet headers when allocating/freeing packets from the free list */ + +typedef struct _FREE_LIST +{ + _u16 next; /* 0x00 offset of next list item */ + _u16 prev; /* 0x02 offset of previous list item */ + +} FREE_LIST; + +/* Same thing again, but defined as offsets... */ + +#define FL_next 0x00 /* 0x00 offset of next list item */ +#define FL_prev 0x02 /* 0x02 offset of previous list item */ + +/***************************************************************************** +********************************** *********************************** +********************************** PKT *********************************** +********************************** *********************************** +*****************************************************************************/ + +/* The PKT is the main unit of communication between Host Cards and RTAs across + the RIO network. */ + +#define PKT_MAX_DATA_LEN 72 /* Size of packet data */ + +typedef struct _PKT +{ + _u8 dest_unit; /* 0x00 Destination Unit Id */ + _u8 dest_port; /* 0x01 Destination Port */ + _u8 src_unit; /* 0x02 Source Unit Id */ + _u8 src_port; /* 0x03 Source Port */ + _u8 len; /* 0x04 Length (in bytes) of data field */ + _u8 control; /* 0x05 */ + _u8 data[PKT_MAX_DATA_LEN]; /* 0x06 Actual data */ + _u16 csum; /* 0x4E C-SUM */ + +} PKT; + +/* Same thing again, but defined as offsets... */ + +#define PKT_dest_unit 0x00 /* 0x00 Destination Unit Id */ +#define PKT_dest_port 0x01 /* 0x01 Destination Port */ +#define PKT_src_unit 0x02 /* 0x02 Source Unit Id */ +#define PKT_src_port 0x03 /* 0x03 Source Port */ +#define PKT_len 0x04 /* 0x04 Length (in bytes) of data field */ +#define PKT_control 0x05 /* 0x05 */ +#define PKT_data 0x06 /* 0x06 Actual data */ +#define PKT_csum 0x4E /* 0x4E C-SUM */ +#define sizeof_PKT 0x50 /* structure size = 0x50 */ + +/* PKT.len definitions... */ +#define PKT_CMD_BIT 0x80 +#define PKT_CMD_DATA 0x80 +#define PKT_LEN_MASK 0x7F + +/* PKT.control definitions... */ +#define PKT_ACK 0x40 +#define PKT_TGL 0x20 +#define DATA_WNDW 0x10 +#define PKT_TTL_MASK 0x0F +#define MAX_TTL 0x0F + +/***************************************************************************** +***************************** **************************** +***************************** Control Packets **************************** +***************************** **************************** +*****************************************************************************/ + +/* The following definitions and structures define the control packets sent + between the driver and RIO Ports, RTAs and Host Cards. */ + +#define PRE_EMPTIVE 0x80 /* Pre-emptive command (sent via port's RUP) */ + +/* "in-band" and "pre-emptive" port commands... */ +#define OPEN 0x00 /* Driver->RIO Open a port */ +#define CONFIG 0x01 /* Driver->RIO Configure a port */ +#define MOPEN 0x02 /* Driver->RIO Modem open (wait for DCD) */ +#define CLOSE 0x03 /* Driver->RIO Close a port */ +#define WFLUSH (0x04|PRE_EMPTIVE) /* Driver->RIO Write flush */ +#define RFLUSH (0x05|PRE_EMPTIVE) /* Driver->RIO Read flush */ +#define RESUME (0x06|PRE_EMPTIVE) /* Driver->RIO Behave as if XON received */ +#define SBREAK 0x07 /* Driver->RIO Start break */ +#define EBREAK 0x08 /* Driver->RIO End break */ +#define SUSPEND (0x09|PRE_EMPTIVE) /* Driver->RIO Behave as if XOFF received */ +#define FCLOSE (0x0A|PRE_EMPTIVE) /* Driver->RIO Force close */ +#define XPRINT 0x0B /* Driver->RIO Xprint packet */ +#define MBIS (0x0C|PRE_EMPTIVE) /* Driver->RIO Set modem lines */ +#define MBIC (0x0D|PRE_EMPTIVE) /* Driver->RIO Clear modem lines */ +#define MSET (0x0E|PRE_EMPTIVE) /* Driver->RIO Set modem lines */ +#define PCLOSE 0x0F /* Driver->RIO Pseudo close */ +#define MGET (0x10|PRE_EMPTIVE) /* Driver->RIO Force update of modem status */ +#define MEMDUMP (0x11|PRE_EMPTIVE) /* Driver->RIO DEBUG request for RTA memory */ +#define READ_REGISTER (0x12|PRE_EMPTIVE) /* Driver->RIO DEBUG read CD1400 register */ + +/* Remote Unit Port (RUP) packet definitions... (specified in PKT.dest_unit and PKT.src_unit) */ +#define SYNC_RUP 0xFF /* Download internal */ +#define COMMAND_RUP 0xFE /* Command ack/status */ +#define ERROR_RUP 0xFD /* Download internal */ +#define POLL_RUP 0xFC /* Download internal */ +#define BOOT_RUP 0xFB /* Used to boot RTAs */ +#define ROUTE_RUP 0xFA /* Used to specify routing/topology */ +#define STATUS_RUP 0xF9 /* Not used */ +#define POWER_RUP 0xF8 /* Download internal */ + +/* COMMAND_RUP definitions... */ +#define COMPLETE (0x20|PRE_EMPTIVE) /* RIO->Driver Command complete */ +#define BREAK_RECEIVED (0x21|PRE_EMPTIVE) /* RIO->Driver Break received */ +#define MODEM_STATUS (0x22|PRE_EMPTIVE) /* RIO->Driver Modem status change */ + +/* BOOT_RUP definitions... */ +#define BOOT_REQUEST 0x00 /* RIO->Driver Request for boot */ +#define BOOT_ABORT 0x01 /* Driver->RIO Abort a boot */ +#define BOOT_SEQUENCE 0x02 /* Driver->RIO Packet with firmware details */ +#define BOOT_COMPLETED 0x03 /* RIO->Driver Boot completed */ +#define IFOAD 0x2F /* Driver->RIO Shutdown/Reboot RTA (Fall Over And Die) */ +#define IDENTIFY 0x30 /* Driver->RIO Identify RTA */ +#define ZOMBIE 0x31 /* Driver->RIO Shutdown/Flash LEDs */ +#define UFOAD 0x32 /* Driver->RIO Shutdown/Reboot neighbouring RTA */ +#define IWAIT 0x33 /* Driver->RIO Pause booting process */ + +/* ROUTE_RUP definitions... */ +#define ROUTE_REQUEST 0x00 /* RIO->Driver Request an ID */ +#define ROUTE_FOAD 0x01 /* Driver->RIO Shutdown/reboot RTA */ +#define ROUTE_ALREADY 0x02 /* Driver->RIO Not used */ +#define ROUTE_USED 0x03 /* Driver->RIO Not used */ +#define ROUTE_ALLOCATE 0x04 /* Driver->RIO Allocate RTA RUP numbers */ +#define ROUTE_REQ_TOP 0x05 /* Driver->RIO Not used */ +#define ROUTE_TOPOLOGY 0x06 /* RIO->Driver Route/Topology status */ + +/***************************************************************************** +********************************** ********************************** +********************************** OPEN ********************************** +********************************** ********************************** +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + Sent to open a port. + Structure of configuration info used with OPEN, CONFIG and MOPEN packets... */ + +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_Cor1 (PKT_Data+1) /* Channel Option Register 1 */ +#define PKT_Cor2 (PKT_Data+2) /* Channel Option Register 2 */ +#define PKT_Cor4 (PKT_Data+3) /* Channel Option Register 4 */ +#define PKT_Cor5 (PKT_Data+4) /* Channel Option Register 5 */ +#define PKT_TxXon (PKT_Data+5) /* Transmit XON character */ +#define PKT_TxXoff (PKT_Data+6) /* Transmit XOFF character */ +#define PKT_RxXon (PKT_Data+7) /* Receive XON character */ +#define PKT_RxXoff (PKT_Data+8) /* Receive XOFF character */ +#define PKT_Lnext (PKT_Data+9) /* Lnext character */ +#define PKT_TxBaud (PKT_Data+10) /* Transmit baud rate */ +#define PKT_RxBaud (PKT_Data+11) /* Receive baud rate */ + +/* COR1 definitions... */ +#define COR1_PARITY 0xE0 /* Parity mask */ +#define COR1_NONE 0x00 /* No parity */ +#define COR1_SPACE 0x20 /* Space parity */ +#define COR1_EVEN 0x40 /* Even parity */ +#define COR1_MARK 0xA0 /* Mark parity */ +#define COR1_ODD 0xC0 /* Odd parity */ + +#define COR1_STOPBITS 0x0C /* Stop bits mask */ +#define COR1_STOP1 0x00 /* 1 stop bit */ +#define COR1_STOP1_5 0x04 /* 1.5 stop bits */ +#define COR1_STOP2 0x08 /* 2 stop bits */ + +#define COR1_DATABITS 0x03 /* Data bits mask */ +#define COR1_DATA5 0x00 /* 5 data bits */ +#define COR1_DATA6 0x01 /* 6 data bits */ +#define COR1_DATA7 0x02 /* 7 data bits */ +#define COR1_DATA8 0x03 /* 8 data bits */ + +/* COR2 definitions... */ +#define COR2_XON_TXFLOW 0x40 /* XON/XOFF Transmit Flow */ +#define COR2_XANY_TXFLOW 0xC0 /* XON/XANY Transmit Flow */ +#define COR2_HUPCL 0x20 /* Hang Up On Close */ +#define COR2_DSR_TXFLOW 0x08 /* DSR Transmit Flow Control */ +#define COR2_RTS_RXFLOW 0x04 /* RTS Receive Flow Control */ +#define COR2_CTS_TXFLOW 0x02 /* CTS Transmit Flow Control */ +#define COR2_XON_RXFLOW 0x01 /* XON/XOFF Receive Flow */ + +/* COR4 definition... */ +#define COR4_IGNCR 0x80 /* Discard received CR */ +#define COR4_ICRNL 0x40 /* Map received CR -> NL */ +#define COR4_INLCR 0x20 /* Map received NL -> CR */ +#define COR4_IGNBRK 0x10 /* Ignore Received Break */ +#define COR4_NBRKINT 0x08 /* No interrupt on rx Break */ +#define COR4_IGNPAR 0x04 /* ignore rx parity error chars */ +#define COR4_PARMRK 0x02 /* Mark rx parity error chars */ +#define COR4_RAISEMOD 0x01 /* Raise modem lines on !0 baud */ + +/* COR5 definitions... */ +#define COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */ +#define COR5_LNE 0x40 /* Enable LNEXT processing */ +#define COR5_CMOE 0x20 /* Match good & error characters */ +#define COR5_TAB3 0x10 /* TAB3 mode */ +#define COR5_TSTATE_ON 0x08 /* Enable tbusy/tstop monitoring */ +#define COR5_TSTATE_OFF 0x04 /* Disable tbusy/tstop monitoring */ +#define COR5_ONLCR 0x02 /* NL -> CR NL on output */ +#define COR5_OCRNL 0x01 /* CR -> NL on output */ + +/* 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 */ + +/***************************************************************************** +********************************* ********************************* +********************************* CONFIG ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + CONFIG is sent from the driver to configure an already opened port. + Packet structure is same as OPEN. */ + +/***************************************************************************** +********************************* ********************************** +********************************* MOPEN ********************************** +********************************* ********************************** +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + MOPEN is sent from the driver to open a port attached to a modem. (in-band) + Packet structure is same as OPEN. */ + +/***************************************************************************** +********************************* ********************************** +********************************* CLOSE ********************************** +********************************* ********************************** +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + CLOSE is sent from the driver to close a previously opened port. + No parameters. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +/***************************************************************************** +********************************* ********************************* +********************************* WFLUSH ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + WFLUSH is sent pre-emptively from the driver to flush the write buffers and + packets of a port. (pre-emptive) + + WFLUSH is also sent in-band from the driver to a port as a marker to end + write flushing previously started by a pre-emptive WFLUSH packet. (in-band) + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ + +/***************************************************************************** +********************************* ********************************* +********************************* RFLUSH ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + RFLUSH is sent pre-emptively from the driver to flush the read buffers and + packets of a port. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +/***************************************************************************** +********************************* ********************************* +********************************* RESUME ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + RESUME is sent pre-emptively from the driver to cause a port to resume + transmission of data if blocked by XOFF. (as if XON had been received) + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +/***************************************************************************** +********************************* ********************************* +********************************* SBREAK ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + SBREAK is sent in-band from the driver to a port to suspend data and start + break signal transmission. + + If the break delay is 0, the break signal will be acknowledged with a + RUP_COMMAND, COMPLETE packet and continue until an EBREAK packet is received. + + Otherwise, there is no acknowledgement and the break signal will last for the + specified number of mS. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_BreakDelay (PKT_Data+1) /* Break delay in mS */ + +/***************************************************************************** +********************************* ********************************* +********************************* EBREAK ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + EBREAK is sent in-band from the driver to a port to stop transmission of a + break signal. + + No parameters. */ + +/***************************************************************************** +********************************* ******************************** +********************************* SUSPEND ******************************** +********************************* ******************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + SUSPEND is sent pre-emptively from the driver to cause a port to suspend + transmission of data. (as if XOFF had been received) + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +/***************************************************************************** +********************************* ********************************* +********************************* FCLOSE ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + FCLOSE is sent pre-emptively from the driver to force close a port. + A force close flushes receive and transmit queues, and also lowers all output + modem signals if the COR5_HUPCL (Hang Up On Close) flag is set. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +/***************************************************************************** +********************************* ********************************* +********************************* XPRINT ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + XPRINT is sent as a normal I/O data packet except that the PKT_CMD_BIT of + the "len" field is set, and the first "data" byte is XPRINT. + + The I/O data in the XPRINT packet will contain the following: + - Transparent Print Start Sequence + - Transparent Print Data + - Transparent Print Stop Sequence. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +/***************************************************************************** +********************************** ********************************** +********************************** MBIS ********************************** +********************************** ********************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + MBIS is sent pre-emptively from the driver to set a port's modem signals. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif +#define PKT_ModemSet (PKT_Data+4) /* Modem set signals mask */ + +/* ModemSet definitions... */ +#define MBIS_RTS 0x01 /* RTS modem signal */ +#define MBIS_DTR 0x02 /* DTR modem signal */ + +/***************************************************************************** +********************************** ********************************** +********************************** MBIC ********************************** +********************************** ********************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + MBIC is sent pre-emptively from the driver to clear a port's modem signals. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +#define PKT_ModemClear (PKT_Data+4) /* Modem clear signals mask */ + +/* ModemClear definitions... */ +#define MBIC_RTS 0x01 /* RTS modem signal */ +#define MBIC_DTR 0x02 /* DTR modem signal */ + +/***************************************************************************** +********************************** ********************************** +********************************** MSET ********************************** +********************************** ********************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + MSET is sent pre-emptively from the driver to set/clear a port's modem signals. */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#endif + +#define PKT_ModemSet (PKT_Data+4) /* Modem set signals mask */ + +/* ModemSet definitions... */ +#define MSET_RTS 0x01 /* RTS modem signal */ +#define MSET_DTR 0x02 /* DTR modem signal */ + +/***************************************************************************** +********************************* ********************************* +********************************* PCLOSE ********************************* +********************************* ********************************* +*****************************************************************************/ + +/* (Driver->RIO,in-band) + + PCLOSE is sent from the driver to pseudo close a previously opened port. + + The port will close when all data has been sent/received, however, the + port's transmit / receive and modem signals will be left enabled and the + port marked internally as Pseudo Closed. */ + +#define PKT_Cmd (PKT_Data+0) /* Command code */ + +/***************************************************************************** +********************************** ********************************** +********************************** MGET ********************************** +********************************** ********************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + MGET is sent pre-emptively from the driver to request the port's current modem signals. */ + +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ + +/***************************************************************************** +********************************* ******************************** +********************************* MEMDUMP ******************************** +********************************* ******************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + MEMDUMP is sent pre-emptively from the driver to request a dump of 32 bytes + of the specified port's RTA address space. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_SubCmd (PKT_Data+5) /* Sub Command */ +#define PKT_Address (PKT_Data+6) /* Requested address */ + +/***************************************************************************** +****************************** ***************************** +****************************** READ_REGISTER ***************************** +****************************** ***************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + READ_REGISTER is sent pre-emptively from the driver to request the contents + of the CD1400 register specified in address. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_SubCmd (PKT_Data+5) /* Sub Command */ +#define PKT_Address (PKT_Data+6) /* Requested address */ + +/***************************************************************************** +************************ ************************** +************************ COMMAND_RUP - COMPLETE ************************** +************************ ************************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + COMMAND_RUP - COMPLETE is sent in response to all port I/O control command + packets, except MEMDUMP and READ_REGISTER. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_Cmd2 (PKT_Data+2) /* Command code copy */ +#define PKT_ModemStatus (PKT_Data+3) /* Modem signal status */ +#define PKT_PortStatus (PKT_Data+4) /* Port signal status */ +#define PKT_SubCmd (PKT_Data+5) /* Sub Command */ + +/* ModemStatus definitions... */ +#define MODEM_DSR 0x80 /* Data Set Ready modem state */ +#define MODEM_CTS 0x40 /* Clear To Send modem state */ +#define MODEM_RI 0x20 /* Ring Indicate modem state */ +#define MODEM_CD 0x10 /* Carrier Detect modem state */ +#define MODEM_TSTOP 0x08 /* Transmit Stopped state */ +#define MODEM_TEMPTY 0x04 /* Transmit Empty state */ +#define MODEM_DTR 0x02 /* DTR modem output state */ +#define MODEM_RTS 0x01 /* RTS modem output state */ + +/* PortStatus definitions... */ +#define PORT_ISOPEN 0x01 /* Port open ? */ +#define PORT_HUPCL 0x02 /* Hangup on close? */ +#define PORT_MOPENPEND 0x04 /* Modem open pending */ +#define PORT_ISPARALLEL 0x08 /* Parallel port */ +#define PORT_BREAK 0x10 /* Port on break */ +#define PORT_STATUSPEND 0020 /* Status packet pending */ +#define PORT_BREAKPEND 0x40 /* Break packet pending */ +#define PORT_MODEMPEND 0x80 /* Modem status packet pending */ + +/***************************************************************************** +************************ ************************** +************************ COMMAND_RUP - COMPLETE ************************** +************************ ************************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + COMMAND_RUP - COMPLETE is sent in response to all port I/O control command + packets, except MEMDUMP and READ_REGISTER. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_Cmd2 (PKT_Data+2) /* Command code copy */ +#endif +#define PKT_ModemStatus (PKT_Data+3) /* Modem signal status */ +#define PKT_PortStatus (PKT_Data+4) /* Port signal status */ +#if 0 +#define PKT_SubCmd (PKT_Data+5) /* Sub Command */ +#endif + +/* ModemStatus definitions... */ +#define MODEM_DSR 0x80 /* Data Set Ready modem state */ +#define MODEM_CTS 0x40 /* Clear To Send modem state */ +#define MODEM_RI 0x20 /* Ring Indicate modem state */ +#define MODEM_CD 0x10 /* Carrier Detect modem state */ +#define MODEM_TSTOP 0x08 /* Transmit Stopped state */ +#define MODEM_TEMPTY 0x04 /* Transmit Empty state */ +#define MODEM_DTR 0x02 /* DTR modem output state */ +#define MODEM_RTS 0x01 /* RTS modem output state */ + +/* PortStatus definitions... */ +#define PORT_ISOPEN 0x01 /* Port open ? */ +#define PORT_HUPCL 0x02 /* Hangup on close? */ +#define PORT_MOPENPEND 0x04 /* Modem open pending */ +#define PORT_ISPARALLEL 0x08 /* Parallel port */ +#define PORT_BREAK 0x10 /* Port on break */ +#define PORT_STATUSPEND 0020 /* Status packet pending */ +#define PORT_BREAKPEND 0x40 /* Break packet pending */ +#define PORT_MODEMPEND 0x80 /* Modem status packet pending */ + +/***************************************************************************** +******************** ******************** +******************** COMMAND_RUP - COMPLETE - MEMDUMP ******************** +******************** ******************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + COMMAND_RUP - COMPLETE - MEMDUMP is sent as an acknowledgement for a MEMDUMP + port I/O control command packet. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_Cmd2 (PKT_Data+2) /* Command code copy */ +#define PKT_ModemStatus (PKT_Data+3) /* Modem signal status */ +#define PKT_PortStatus (PKT_Data+4) /* Port signal status */ +#define PKT_SubCmd (PKT_Data+5) /* Sub Command */ +#define PKT_Address (PKT_Data+6) /* Requested address */ +#endif +#define PKT_Dump (PKT_Data+8) /* 32bytes of requested dump data */ + +/***************************************************************************** +***************** ***************** +***************** COMMAND_RUP - COMPLETE - READ_REGISTER ***************** +***************** ***************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + COMMAND_RUP - COMPLETE - READ_REGISTER is sent as an acknowledgement for a + READ_REGISTER port I/O control command packet. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /*Command code */ +#define PKT_PhbNum (PKT_Data+1) /*Port number wrt RTA */ +#define PKT_Cmd2 (PKT_Data+2) /* Command code copy */ +#endif +#define PKT_RegisterValue (PKT_Data+3) /* Modem signal status */ +#if 0 +#define PKT_PortStatus (PKT_Data+4) /* Port signal status */ +#define PKT_SubCmd (PKT_Data+5) /* Sub Command */ +#endif + +/***************************************************************************** +********************* *********************** +********************* COMMAND_RUP - BREAK_RECEIVED *********************** +********************* *********************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + COMMAND_RUP - BREAK_RECEIVED packets are sent when the port detects a receive BREAK signal. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_Cmd2 (PKT_Data+2) /* Command code copy */ +#endif + +/***************************************************************************** +********************* ************************* +********************* COMMAND_RUP - MODEM_STATUS ************************* +********************* ************************* +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + COMMAND_RUP - MODEM_STATUS packets are sent whenever the port detects a + change in the input modem signal states. + + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_PhbNum (PKT_Data+1) /* Port number wrt RTA */ +#define PKT_Cmd2 (PKT_Data+2) /* Command code copy */ +#define PKT_ModemStatus (PKT_Data+3) /* Modem signal status */ +#endif + +/***************************************************************************** +************************ ************************* +************************ BOOT_RUP - BOOT_REQUEST ************************* +************************ ************************* +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + BOOT_RUP - BOOT_REQUEST packets are sent to the Driver from RIO to request + firmware code to load onto attached RTAs. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif + +/***************************************************************************** +************************ ************************ +************************ BOOT_RUP - BOOT_SEQUENCE ************************ +************************ ************************ +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + BOOT_RUP - BOOT_SEQUENCE packets are sent from the Driver to RIO in response + to a BOOT_RUP - BOOT_REQUEST packet. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_NumPackets (PKT_Data+2) /* Packets required to load firmware */ +#define PKT_LoadBase (PKT_Data+4) /* RTA firmware load address */ +#define PKT_CodeSize (PKT_Data+6) /* Size of firmware in bytes */ +#define PKT_CmdString (PKT_Data+8) /* Command string */ + +/***************************************************************************** +************************ *********************** +************************ BOOT_RUP - BOOT_COMPLETED *********************** +************************ *********************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + BOOT_RUP - BOOT_COMPLETE is sent to the Driver from RIO when downloading of + RTA firmware has completed. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_LinkNumber (PKT_Data+1) /* Link number RTA booted on */ +#define PKT_SerialNumber (PKT_Data+2) /* 4 byte serial number */ + +/***************************************************************************** +************************ *********************** +************************ BOOT_RUP - Packet Request *********************** +************************ *********************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + BOOT_RUP packet without the PKT_CMD_BIT set in the PKT->len field is sent + from RIO to the Driver as a request for a firmware boot packet. */ + +#define PKT_SequenceNumber (PKT_Data+0) /* Packet sequence number */ + +/***************************************************************************** +*********************** *********************** +*********************** BOOT_RUP - Packet Response *********************** +*********************** *********************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + In response to a BOOT_RUP boot packet request, the driver fills out the response + packet with the 70 bytes of the requested sequence. + */ +#if 0 +#define PKT_SequenceNumber (PKT_Data+0) /* Packet sequence number */ +#endif +#define PKT_FirmwarePacket (PKT_Data+2) /* Firmware packet */ + +/***************************************************************************** +**************************** **************************** +**************************** BOOT_RUP - IFOAD **************************** +**************************** **************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + BOOT_RUP - IFOAD packets are sent from the Driver to an RTA to cause the + RTA to shut down and reboot. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_IfoadId1 (PKT_Data+2) /* IFOAD Id 1 */ +#define PKT_IfoadId2 (PKT_Data+3) /* IFOAD Id 2 */ + +#define IFOADID1 0xAD +#define IFOADID2 0xF0 + +/***************************************************************************** +************************** *************************** +************************** BOOT_RUP - IDENTIFY *************************** +************************** *************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + BOOT_RUP - IDENTIFY packets are sent from the Driver to an RTA to cause the + RTA to flash its LEDs for a period of time. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_IdentifyId (PKT_Data+2) /* defines pattern to flash */ + +/***************************************************************************** +**************************** *************************** +**************************** BOOT_RUP - ZOMBIE *************************** +**************************** *************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + BOOT_RUP - ZOMBIE packets are sent from the Driver to an RTA to cause the + RTA to shut down and flash it's LEDs. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_ZombieId1 (PKT_Data+2) /* ZOMBIE Id 1 */ +#define PKT_ZombieId2 (PKT_Data+3) /* ZOMBIE Id 2 */ + +#define ZOMBIEID1 0x52 +#define ZOMBIEID2 0x21 + +/***************************************************************************** +**************************** **************************** +**************************** BOOT_RUP - UFOAD **************************** +**************************** **************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + BOOT_RUP - UFOAD packets are sent from the Driver to an RTA to cause the RTA + to ask it's neighbouring RTA to shut down and reboot. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_LinkNumber (PKT_Data+1) /* Link number of RTA to UFOAD */ +#endif +#define PKT_UfoadId1 (PKT_Data+2) /* UFOAD Id 1 */ +#define PKT_UfoadId2 (PKT_Data+3) /* UFOAD Id 2 */ + +#define UFOADID1 0x1E +#define UFOADID2 0x0D + +/***************************************************************************** +**************************** **************************** +**************************** BOOT_RUP - IWAIT **************************** +**************************** **************************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + BOOT_RUP - IWAIT packets are sent from the Driver to an RTA to cause the RTA + to pause booting on the specified link for 30 seconds. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#define PKT_LinkNumber (PKT_Data+1) /* Link number of RTA to UFOAD */ +#endif +#define PKT_IwaitId1 (PKT_Data+2) /* IWAIT Id 1 */ +#define PKT_IwaitId2 (PKT_Data+3) /* IWAIT Id 2 */ + +#define IWAITID1 0xDE +#define IWAITID2 0xB1 + +/***************************************************************************** +************************ *********************** +************************ ROUTE_RUP - ROUTE_REQUEST *********************** +************************ *********************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + ROUTE_RUP - ROUTE_REQUEST packets are sent from a newly booted or connected + RTA to a Driver to request an ID (RUP or unit number). + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_SerialNumber (PKT_Data+2) /* 4 byte serial number */ +#define PKT_ModuleTypes (PKT_Data+6) /* RTA Module types */ + +/* ModuleTypes definitions... */ +#define MOD_BLANK 0x0F /* Blank plate attached */ +#define MOD_RS232DB25 0x00 /* RS232 DB25 connector */ +#define MOD_RS232RJ45 0x01 /* RS232 RJ45 connector */ +#define MOD_RS422DB25 0x02 /* RS422 DB25 connector */ +#define MOD_RS485DB25 0x03 /* RS485 DB25 connector */ +#define MOD_PARALLEL 0x04 /* Centronics parallel */ + +#define MOD2 0x08 /* Set to indicate Rev2 module */ + +/***************************************************************************** +************************* ************************* +************************* ROUTE_RUP - ROUTE_FOAD ************************* +************************* ************************* +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + ROUTE_RUP - ROUTE_FOAD packet is sent as a response to a ROUTE_RUP - ROUTE_REQUEST + packet to cause the RTA to "Fall Over And Die"., i.e. shutdown and reboot. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_RouteCmdString (PKT_Data+2) /* Command string */ + +/***************************************************************************** +*********************** *********************** +*********************** ROUTE_RUP - ROUTE_ALLOCATE *********************** +*********************** *********************** +*****************************************************************************/ + +/* (Driver->RIO,pre-emptive) + + ROUTE_RUP - ROUTE_ALLOCATE packet is sent as a response to a ROUTE_RUP - ROUTE_REQUEST + packet to allocate the RTA's Id number (RUP number 1..16) + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_IdNum (PKT_Data+1) /* RUP number for ports 1..8 */ +#if 0 +#define PKT_RouteCmdString (PKT_Data+2) /* Command string */ +#endif +#define PKT_IdNum2 (PKT_Data+0x17) /* RUP number for ports 9..16 */ + +/***************************************************************************** +*********************** *********************** +*********************** ROUTE_RUP - ROUTE_TOPOLOGY *********************** +*********************** *********************** +*****************************************************************************/ + +/* (RIO->Driver,pre-emptive) + + ROUTE_RUP - ROUTE_TOPOLOGY packet is sent to inform the driver of an RTA's + current link status. + */ +#if 0 +#define PKT_Cmd (PKT_Data+0) /* Command code */ +#endif +#define PKT_Link1Rup (PKT_Data+2) /* Link 1 RUP number */ +#define PKT_Link1Link (PKT_Data+3) /* Link 1 link number */ +#define PKT_Link2Rup (PKT_Data+4) /* Link 2 RUP number */ +#define PKT_Link2Link (PKT_Data+5) /* Link 2 link number */ +#define PKT_Link3Rup (PKT_Data+6) /* Link 3 RUP number */ +#define PKT_Link3Link (PKT_Data+7) /* Link 3 link number */ +#define PKT_Link4Rup (PKT_Data+8) /* Link 4 RUP number */ +#define PKT_Link4Link (PKT_Data+9) /* Link 4 link number */ +#define PKT_RtaVpdProm (PKT_Data+10) /* 32 bytes of RTA VPD PROM Contents */ + +#endif /* _sxwinif_h */ + +/* End of RIOWINIF.H */ diff --git a/drivers/char/rio/riscos.h b/drivers/char/rio/riscos.h new file mode 100644 index 000000000000..7685cc1d9e7b --- /dev/null +++ b/drivers/char/rio/riscos.h @@ -0,0 +1,63 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : riscos.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:19 +** Retrieved : 11/6/98 11:34:22 +** +** ident @(#)riscos.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_riscos_h__ +#define __rio_riscos_h__ + +#ifdef SCCS_LABELS +static char *_riscos_h_sccs_ = "@(#)riscos.h 1.2"; +#endif + +/* +** This module used to define all those little itsy bits required for RISC/OS +** now it's full of null macros. +*/ + +/* +** RBYTE reads a byte from a location. +** RWORD reads a word from a location. +** WBYTE writes a byte to a location. +** WWORD writes a word to a location. +** RINDW reads a word through a pointer. +** WINDW writes a word through a pointer. +** RIOSWAB swaps the two bytes of a word, if needed. +*/ + +#define RIOSWAB(N) (N) +#define WBYTE(A,V) (A)=(uchar)(V) +#define WWORD(A,V) (A)=(ushort)(V) +#define RBYTE(A) (uchar)(A) +#define RWORD(A) (ushort)(A) +#define RINDW(A) (*(ushort *)(A)) +#define WINDW(A,V) (*(ushort *)(A)=(ushort)(V)) + +#endif /* __rio_riscos_h__ */ diff --git a/drivers/char/rio/rom.h b/drivers/char/rio/rom.h new file mode 100644 index 000000000000..ee79b8e5b972 --- /dev/null +++ b/drivers/char/rio/rom.h @@ -0,0 +1,64 @@ +/**************************************************************************** + ******* ******* + ******* R O M + ******* ******* + **************************************************************************** + + 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 _rom_h +#define _rom_h 1 + +#ifndef lint +#ifdef SCCS +static char *_rio_rom_h_sccs = "@(#)rom.h 1.1" ; +#endif +#endif + +typedef struct ROM ROM ; +struct ROM { + u_short slx ; + char pcb_letter_rev ; + char pcb_number_rev ; + char serial[4] ; + char year ; + char week ; + } ; + +#endif + +#define HOST_ROM (ROM *) 0x7c00 +#define RTA_ROM (ROM *) 0x7801 +#define ROM_LENGTH 0x20 + +/*********** end of file ***********/ + + diff --git a/drivers/char/rio/route.h b/drivers/char/rio/route.h new file mode 100644 index 000000000000..c42dbb971718 --- /dev/null +++ b/drivers/char/rio/route.h @@ -0,0 +1,108 @@ +/**************************************************************************** + ******* ******* + ******* 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 + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_route_h_sccs = "@(#)route.h 1.3"; */ +#endif +#endif + +#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/rtahw.h b/drivers/char/rio/rtahw.h new file mode 100644 index 000000000000..06860118cbc5 --- /dev/null +++ b/drivers/char/rio/rtahw.h @@ -0,0 +1,75 @@ + +/**************************************************************************** + ******* ******* + ******* R T A H A R D W A 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 lint +#ifdef SCCS_LABELS +static char *_rio_rtahw_h_sccs = "@(#)rtahw.h 1.5" ; +#endif +#endif + +#define WATCHDOG_ADDR ((unsigned short *)0x7a00) +#define RTA_LED_ADDR ((unsigned short *)0x7c00) +#define SERIALNUM_ADDR ((unsigned char *)0x7809) +#define LATCH_ADDR ((unsigned char *)0x7800) + +/* +** Here we define where the cd1400 chips are in memory. +*/ +#define CD1400_ONE_ADDR (0x7300) +#define CD1400_TWO_ADDR (0x7200) +#define CD1400_THREE_ADDR (0x7100) +#define CD1400_FOUR_ADDR (0x7000) + +/* +** Define the different types of modules we can have +*/ +enum module { + MOD_BLANK = 0x0f, /* Blank plate attached */ + MOD_RS232DB25 = 0x00, /* RS232 DB25 connector */ + MOD_RS232RJ45 = 0x01, /* RS232 RJ45 connector */ + MOD_RS422DB25 = 0x02, /* RS422 DB25 connector */ + MOD_RS485DB25 = 0x03, /* RS485 DB25 connector */ + MOD_PARALLEL = 0x04 /* Centronics parallel */ +}; + +#define TYPE_HOST 0 +#define TYPE_RTA8 1 +#define TYPE_RTA16 2 + +#define WATCH_DOG WATCHDOG_ADDR + +/*********** end of file ***********/ diff --git a/drivers/char/rio/rup.h b/drivers/char/rio/rup.h new file mode 100644 index 000000000000..b9d2bc03d14b --- /dev/null +++ b/drivers/char/rio/rup.h @@ -0,0 +1,82 @@ +/**************************************************************************** + ******* ******* + ******* 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 + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_rup_h_sccs = "@(#)rup.h 1.5"; */ +#endif +#endif + +#if defined( HOST ) || defined( INKERNEL ) +#define MAX_RUP ((short) 16) +#endif +#ifdef RTA +#define MAX_RUP ((short) 1) +#endif + +#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 { + PKT_ptr txpkt; /* Outgoing packet */ + PKT_ptr rxpkt; /* Incoming packet */ + WORD link; /* Which link to send down? */ + BYTE rup_dest_unit[2]; /* Destination unit */ + WORD handshake; /* For handshaking */ + WORD timeout; /* Timeout */ + WORD status; /* Status */ + WORD txcontrol; /* Transmit control */ + WORD rxcontrol; /* Receive control */ + }; + +#endif + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/rupstat.h b/drivers/char/rio/rupstat.h new file mode 100644 index 000000000000..b4aafaff0d78 --- /dev/null +++ b/drivers/char/rio/rupstat.h @@ -0,0 +1,51 @@ +/**************************************************************************** + ******* ******* + ******* RUPSTAT + ******* ******* + **************************************************************************** + + Author : 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 _rupstat_h +#define _rupstat_h + +#ifndef lint +#ifdef SCCS_LABELS +static char *_rio_rupstat_h_sccs = "@(#)rupstat.h 1.1" ; +#endif +#endif + +#define STATUS_SYNC 0 +#define STATUS_REQ_TOP 1 +#define STATUS_TOPOLOGY 2 + +#endif + diff --git a/drivers/char/rio/sam.h b/drivers/char/rio/sam.h new file mode 100644 index 000000000000..c1accb8cb624 --- /dev/null +++ b/drivers/char/rio/sam.h @@ -0,0 +1,74 @@ +/**************************************************************************** + ******* ******* + ******* S A M . H + ******* ******* + **************************************************************************** + + 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 _sam_h +#define _sam_h 1 + +#ifdef SCCS_LABELS +#ifndef lint +/* static char *_rio_sam_h_sccs = "@(#)sam.h 1.3"; */ +#endif +#endif + + +#if !defined( HOST ) && !defined( INKERNEL ) +#define RTA 1 +#endif + +#define NUM_FREE_LIST_UNITS 500 + +#ifndef FALSE +#define FALSE (short) 0x00 +#endif +#ifndef TRUE +#define TRUE (short) !FALSE +#endif + +#define TX TRUE +#define RX FALSE + + +typedef struct FREE_LIST FREE_LIST ; +struct FREE_LIST { + FREE_LIST_ptr next ; + FREE_LIST_ptr prev ; + } ; + + +#endif +/*********** end of file ***********/ + + + diff --git a/drivers/char/rio/selftest.h b/drivers/char/rio/selftest.h new file mode 100644 index 000000000000..deae48722a21 --- /dev/null +++ b/drivers/char/rio/selftest.h @@ -0,0 +1,73 @@ +/* +** File: selftest.h +** +** Author: David Dix +** +** Created: 15th March 1993 +** +** Last modified: 94/06/14 +** + * + * (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. +*/ + +#ifndef _selftests_h_ +#define _selftests_h_ + +/* +** Selftest identifier... +*/ +#define SELFTEST_MAGIC 0x5a5a + +/* +** This is the structure of the packet that is sent back after each +** selftest on a booting RTA. +*/ +typedef struct { + short magic; /* Identifies packet type */ + int test; /* Test number, see below */ + unsigned int result; /* Result value */ + unsigned int dataIn; + unsigned int dataOut; +}selftestStruct; + +/* +** The different tests are identified by the following data values. +*/ +enum test { + TESTS_COMPLETE = 0x00, + MEMTEST_ADDR = 0x01, + MEMTEST_BIT = 0x02, + MEMTEST_FILL = 0x03, + MEMTEST_DATABUS = 0x04, + MEMTEST_ADDRBUS = 0x05, + CD1400_INIT = 0x10, + CD1400_LOOP = 0x11, + CD1400_INTERRUPT = 0x12 +}; + +enum result { + E_PORT = 0x10, + E_TX = 0x11, + E_RX = 0x12, + E_EXCEPT = 0x13, + E_COMPARE = 0x14, + E_MODEM = 0x15, + E_TIMEOUT = 0x16, + E_INTERRUPT = 0x17 +}; +#endif /* _selftests_h_ */ diff --git a/drivers/char/rio/space.h b/drivers/char/rio/space.h new file mode 100644 index 000000000000..72398d342051 --- /dev/null +++ b/drivers/char/rio/space.h @@ -0,0 +1,45 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : space.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:19 +** Retrieved : 11/6/98 11:34:22 +** +** ident @(#)space.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_space_h__ +#define __rio_space_h__ + +#ifdef SCCS_LABELS +static char *_space_h_sccs_ = "@(#)space.h 1.2"; +#endif + +extern int rio_cntls; +extern int rio_bases[]; +extern int rio_limits[]; +extern int rio_vects[]; + +#endif /* __rio_space_h__ */ diff --git a/drivers/char/rio/sysmap.h b/drivers/char/rio/sysmap.h new file mode 100644 index 000000000000..fdc731393576 --- /dev/null +++ b/drivers/char/rio/sysmap.h @@ -0,0 +1,63 @@ + +/**************************************************************************** + ******* ******* + ******* S Y S T E M M A P H E A D E R + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS_LABELS +static char *_rio_sysmap_h_sccs = "@(#)sysmap.h 1.1" ; +#endif +#endif + +#define SYSTEM_MAP_LEN 64 /* Len of System Map array */ + + +typedef struct SYS_MAP SYS_MAP ; +typedef struct SYS_MAP_LINK SYS_MAP_LINK ; + +struct SYS_MAP_LINK { + short id ; /* Unit Id */ + short link ; /* Id's Link */ + short been_here ; /* Used by map_gen */ + } ; + +struct SYS_MAP { + char serial_num[4] ; + SYS_MAP_LINK link[4] ; + } ; + + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/timeouts.h b/drivers/char/rio/timeouts.h new file mode 100644 index 000000000000..11b31330c901 --- /dev/null +++ b/drivers/char/rio/timeouts.h @@ -0,0 +1,51 @@ + +/**************************************************************************** + ******* ******* + ******* T I M E O U T S + ******* ******* + **************************************************************************** + + 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 lint +#ifdef SCCS_LABELS +static char *_rio_defaults_h_sccs = "@(#)timeouts.h 1.3" ; +#endif +#endif + +#define MILLISECOND (int) (1000/64) /* 15.625 low ticks */ +#define SECOND (int) 15625 /* Low priority ticks */ + +#define TX_TIMEOUT (int) (200 * MILLISECOND) + + +/*********** end of file ***********/ + diff --git a/drivers/char/rio/top.h b/drivers/char/rio/top.h new file mode 100644 index 000000000000..255c40d463a6 --- /dev/null +++ b/drivers/char/rio/top.h @@ -0,0 +1,49 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : top.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:19 +** Retrieved : 11/6/98 11:34:22 +** +** ident @(#)top.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_top_h__ +#define __rio_top_h__ + +#ifdef SCCS_LABELS +static char *_top_h_sccs_ = "@(#)top.h 1.2"; +#endif + +/* +** Topology information +*/ +struct Top +{ + uchar Unit; + uchar Link; +}; + +#endif /* __rio_top_h__ */ diff --git a/drivers/char/rio/typdef.h b/drivers/char/rio/typdef.h new file mode 100644 index 000000000000..2cb9dd693fa1 --- /dev/null +++ b/drivers/char/rio/typdef.h @@ -0,0 +1,82 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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 : typdef.h +** SID : 1.2 +** Last Modified : 11/6/98 11:34:20 +** Retrieved : 11/6/98 11:34:22 +** +** ident @(#)typdef.h 1.2 +** +** ----------------------------------------------------------------------------- +*/ + +#ifndef __rio_typdef_h__ +#define __rio_typdef_h__ + +#ifdef SCCS_LABELS +static char *_typdef_h_sccs_ = "@(#)typdef.h 1.2"; +#endif + +#undef VPIX + +/* +** IT IS REALLY, REALLY, IMPORTANT THAT BYTES ARE UNSIGNED! +** +** These types are ONLY to be used for refering to data structures +** on the RIO Host card! +*/ +typedef volatile unsigned char BYTE; +typedef volatile unsigned short WORD; +typedef volatile unsigned int DWORD; +typedef volatile unsigned short RIOP; +typedef volatile short NUMBER; + + +/* +** 27.01.199 ARG - mods to compile 'newutils' on LyxnOS - +** These #defines are for the benefit of the 'libfuncs' library +** only. They are not necessarily correct type mappings and +** are here only to make the source compile. +*/ +/* typedef unsigned int uint; */ +typedef unsigned long ulong_t; +typedef unsigned short ushort_t; +typedef unsigned char uchar_t; +typedef unsigned char queue_t; +typedef unsigned char mblk_t; +typedef unsigned int paddr_t; +typedef unsigned char uchar; + +#define TPNULL ((ushort)(0x8000)) + + +/* +** RIO structures defined in other include files. +*/ +typedef struct PKT PKT; +typedef struct LPB LPB; +typedef struct RUP RUP; +typedef struct Port Port; +typedef struct DpRam DpRam; + +#endif /* __rio_typdef_h__ */ diff --git a/drivers/char/rio/unixrup.h b/drivers/char/rio/unixrup.h new file mode 100644 index 000000000000..eddf86278abc --- /dev/null +++ b/drivers/char/rio/unixrup.h @@ -0,0 +1,56 @@ +/* +** ----------------------------------------------------------------------------- +** +** 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__ + +#ifdef SCCS_LABELS +static char *_unixrup_h_sccs_ = "@(#)unixrup.h 1.2"; +#endif + +/* +** 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 *RupP; /* the Rup to send it to */ + uint Id; /* Id number */ + uint BaseSysPort; /* SysPort of first tty on this RTA */ + uint ModTypes; /* Modules on this RTA */ + spinlock_t RupLock; /* Lock structure for MPX */ +/* struct lockb RupLock; */ /* Lock structure for MPX */ +}; + +#endif /* __rio_unixrup_h__ */ |