?? scc.c
字號:
/* Generic driver for Z8530 boards, modified from the PE1CHL
* driver for use with NOS. This version also supports the NRS
* mode when used as an asynch port. Device setup is similar to
* that of the PE1CHL version, with the addition of user specification
* of buffer size (bufsize). See the file "scc.txt" for general
* information on the use of this driver and setup procedures.
*
* General differences between this driver and the original version:
*
* 1) Slip encoding and decoding is not done in the driver, but
* using the routines in slip.c, and these routines are supported
* in a manner similar to the asynch routines for the 8250. The
* input is handled via fifo buffer, while output is direct. The
* routines scc_send and get_scc are called via pointers in the
* Slip and Nrs structs for the parcticular channel.
*
* 2) The timer routine, scctim, is not installed directly in the
* timer interrupt chain, but is called through the systick routine
* in pc.c.
*
* 3) Facilities of nos are used whenever possible in place of direct
* structure or variable manipulation. Mbuf management is handled
* this way, along with interface initialization.
*
* 4) Nrs mode support is added in a manner similar to that of the
* Slip support. I have not had an opportunity to test this, but
* it is essentially identical to the way the 8250 version works.
*
* 5) Callsign specification on radio modes (kiss,nrs,ax25) is an
* option. If not supplied, the value of Mycall will be used.
*
* 6) Bufsize specification is now a parameter on setup of each channel.
* This is the size of the fifo on asynch input, and the size of
* mbuf buffers for sdlc mode. Since the fifo buffer can fill up,
* this value should be reasonably large for asynch mode. Mbufs
* are chained when they fill up, so having a small bufsize with
* sdlc modes (ax25) does not result in loss of characters.
*
* 7) Because slip and nrs decoding is handled outside the driver,
* sccstat cannot be used to report sent and receive packet counts
* in asynch mode, and these fields are blanked on display in asynch
* modes.
*
*
* I am interested in setting up some default initializations for
* the popular Z8530 boards, to minimize user problems in constructing
* the proper attach init entries. These would allow for shortened
* entries to use the defaults, such as "attach scc 1 init drsi" to
* attach a DRSI board in standard configuration at its default address.
* Since I do not have complete technical information on all such boards,
* I would very much appreciate any information that users can provide
* me regarding particular boards.
*
* 1/25/90
*
* Modifications:
*
* 2/17/90:
*
* 1) Added mods from PE1CHL which reflect relevent changes to the
* scc driver in his version of net between 10/89 and 1/90. Changes
* incorporated include additional delays in sccvec.asm, addition
* of external clock mode, and initialization for the 8536 as a
* clock divider on the DRSI board. "INLINE" is a slight delay
* for register access incorporated for use with the inline i/o
* code in MSC. This may not be useful or necessary with TURBO.
* Changes making "TPS" a variable were not added, since the
* scc timer does not install itself on the hardware interrupt
* in this version.
*
*
* Ken Mitchum, KY3B km@cs.pitt.edu km@dsl.pitt.edu
* or mail to the tcpip group
*
* 5 Aug 91:
* Support added for Sealevel Systems Inc's ACB-IV 8530 card (HWSEALEVEL)
* <hdwe> == HWSEALEVEL (0x10) sets the control/status port at chipbase + 4
* to the value in <param>. (Where the control bits for both side's DTR
* lines are; the 8530-internal DTR/REQB is used for DMA...)
*
* Added a side-effect to ATTACH SCC's <speed> == 'ext'. Previously, all
* async modes set a 16X clock; now when external clock is selected, the
* baud rate divider in R4 is set to 1X.
*
* Tom Jennings, Cygnus Support (tomj@cygnus.com)
*
*
* 9 Aug 91:
* Allow 'v' to specify Van Jacobson TCP header compression (SLIP only).
* Because the 8th arg is optional [<call>], this checks for 'v' in the
* 9th arg if that exists, otherwise the 8th arg is used. Not pretty
* but servicable.
*
* Tom Jennings, Cygnus Support (tomj@cygnus.com)
*/
/* Added ANSI-style prototypes, reformatted source, minor delinting.
* Integrated into standard 900201 NOS by KA9Q.
*/
/*
* Generic driver for Z8530 SCC chip in SLIP, KISS or AX.25 mode.
*
* Written by R.E. Janssen (PE1CHL) using material from earlier
* EAGLE and PC100 drivers in this package.
*
* The driver has initially been written for my own Atari SCC interface
* board, but it could eventually replace the other SCC drivers.
*
* Unfortunately, there is little consistency between the different interface
* boards, as to the use of a clock source, the solution for the fullduplex
* clocking problem, and most important of all: the generation of the INTACK
* signal. Most designs do not even support the generation of an INTACK and
* the read of the interrupt vector provided by the chip.
* This results in lots of configuration parameters, and a fuzzy
* polltable to be able to support multiple chips connected at one interrupt
* line...
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <dos.h>
#include "global.h"
#include "mbuf.h"
#include "config.h"
#include "netuser.h"
#include "proc.h"
#include "iface.h"
#include "pktdrvr.h"
#include "slip.h"
#include "nrs.h"
#include "n8250.h"
#include "scc.h"
#include "z8530.h"
#include "z8536.h"
#include "ax25.h"
#include "trace.h"
#include "nospc.h"
#include "kiss.h"
#include "devparam.h"
/* interrupt handlers */
extern INTERRUPT sccvec();
extern INTERRUPT sccnovec();
/* variables used by the SCC interrupt handler in sccvec.asm */
static INTERRUPT (*Orgivec)(); /* original interrupt vector */
struct sccinfo Sccinfo = {0}; /* global info about SCCs */
struct sccchan *Sccchan[2 * MAXSCC] = {0}; /* information per channel */
ioaddr Sccvecloc = {0}; /* location to access for SCC vector */
unsigned char Sccmaxvec = {0}; /* maximum legal vector from SCC */
ioaddr Sccpolltab[MAXSCC+1][2] = {0}; /* polling table when no vectoring */
#if defined(INLINE)
static unsigned scc_delay(unsigned v);
static unsigned scc_delay (v) /* delay for about 5 PCLK cycles */
unsigned v; /* pass-through used for input */
{
register int i,j; /* it takes time to save them */
return v; /* return the passed parameter */
}
#endif
unsigned char Random = 0; /* random number for p-persist */
static int scc_call(struct iface *ifp,char *call);
static int scc_init(int nchips,ioaddr iobase,int space,int aoff,
int boff,int doff,ioaddr intack,int ivec,long clk,int pclk,int hwtype,
int hwparam);
static int scc_raw(struct iface *ifp,struct mbuf **bpp);
static int scc_stop(struct iface *ifp);
static int get_scc(int dev);
static int scc_send(int dev,struct mbuf **bpp);
static int scc_async(struct sccchan *scc);
static void scc_sdlc(struct sccchan *scc);
static void scc_tossb(struct sccchan *scc);
static void scc_txon(struct sccchan *scc);
static void scc_txoff(struct sccchan *scc);
static int32 scc_aioctl(struct iface *ifp,int cmd,int set,int32 val);
static int32 scc_sioctl(struct iface *ifp,int cmd,int set,int32 val);
static void scc_sstart(struct sccchan *scc);
static unsigned int scc_speed(struct sccchan *scc,
unsigned int clkmode,long speed);
static void scc_asytx(struct sccchan *scc);
static void scc_asyex(struct sccchan *scc);
static void scc_asyrx(struct sccchan *scc);
static void scc_asysp(struct sccchan *scc);
static void scc_sdlctx(struct sccchan *scc);
static void scc_sdlcex(struct sccchan *scc);
static void scc_sdlcrx(struct sccchan *scc);
static void scc_sdlcsp(struct sccchan *scc);
/* Attach an SCC channel to the system, or initialize SCC driver.
* operation depends on argv[2]:
* when "init", the SCC driver is initialized, and global information about
* the hardware is set up.
* argv[0]: hardware type, must be "scc"
* argv[1]: number of SCC chips we will support
* argv[2]: mode, must be: "init" in this case
* argv[3]: base address of SCC chip #0 (hex)
* argv[4]: spacing between SCC chip base addresses
* argv[5]: offset from chip base address to channel A control register
* argv[6]: offset from chip base address to channel B control register
* argv[7]: offset from each channel's control register to data register
* argv[8]: address of INTACK/Read Vector port. 0 to read from RR3A/RR2B
* argv[9]: CPU interrupt vector number for all connected SCCs
* argv[10]: clock frequency (PCLK/RTxC) of all SCCs in cycles per second
* prefix with "p" for PCLK, "r" for RTxC clock (for baudrate gen)
* argv[11]: optional hardware type (for special features)
* argv[12]: optional extra parameter for special hardware
*
* otherwise, a single channel is attached using the specified parameters:
* argv[0]: hardware type, must be "scc"
* argv[1]: SCC channel number to attach, 0/1 for first chip A/B, 2/3 for 2nd...
* argv[2]: mode, can be:
* "slip", "kiss", "ax25"
* argv[3]: interface label, e.g., "sl0"
* argv[4]: maximum transmission unit, bytes
* argv[5]: interface speed, e.g, "1200". prefix with "d" when an external
* divider is available to generate the TX clock. When the clock
* source is PCLK, this can be a /32 divider between TRxC and RTxC.
* When the clock is at RTxC, the TX rate must be supplied at TRxC.
* This is needed only for AX.25 fullduplex.
* When this arg is given as "ext", the transmit and receive clock
* are external, and the BRG and DPLL are not used.
* argv[6]: buffer size
* argv[7]: callsign used on the radio channels (optional) or 'v' to
* specify Van Jacobson TCP header compression. See argv[8] below.
* argv[8]: 'v' here specifies Van Jacobson TCP header compression iff
* there is a 9th arg (ie. [7] is a callsign.)
*/
int
scc_attach(argc,argv)
int argc;
char *argv[];
{
register struct iface *ifp;
struct sccchan *scc;
unsigned int chan,brgrate;
int pclk = 0,hwtype = 0,hwparam = 0;
int xdev;
char *cp;
/* first handle the special "init" mode, to initialize global stuff */
if(!strcmp(argv[2],"init")){
if(argc < 11) /* need at least argv[1]..argv[10] */
return -1;
if(isupper(argv[10][0]))
argv[10][0] = tolower(argv[10][0]);
if(argv[10][0] == 'p'){ /* wants to use PCLK as clock? */
pclk = 1;
argv[10]++;
} else {
if(argv[10][0] == 'r') /* wants to use RTxC? */
argv[10]++; /* that's the default */
}
if(argc > 11) /* optional hardware type */
hwtype = htoi(argv[11]); /* it is given in hex */
if(argc > 12) /* optional hardware param */
hwparam = htoi(argv[12]); /* also in hex */
return scc_init(atoi(argv[1]),(ioaddr) htol(argv[3]),atoi(argv[4]),
atoi(argv[5]),atoi(argv[6]),atoi(argv[7]),
(ioaddr) htol(argv[8]),atoi(argv[9]),
atol(argv[10]),pclk,hwtype,hwparam);
}
/* not "init", so it must be a valid mode to attach a channel */
if(strcmp(argv[2],"ax25") && strcmp(argv[2],"kiss") &&
strcmp(argv[2],"slip")){
printf("Mode %s unknown for SCC\n",argv[2]);
return -1;
}
if(strcmp(argv[2],"slip") == 0 || strcmp(argv[2],"kiss") == 0){
for(xdev = 0;xdev < SLIP_MAX;xdev++)
if(Slip[xdev].iface == NULL)
break;
if(xdev >= SLIP_MAX){
printf("Too many slip devices\n");
return -1;
}
}
if(strcmp(argv[2],"nrs") == 0){
for(xdev = 0;xdev < NRS_MAX;xdev++)
if(Nrs[xdev].iface == NULL)
break;
if(xdev >= NRS_MAX){
printf("Too many nrs devices\n");
return -1;
}
}
if(!Sccinfo.init){
printf("First init SCC driver\n");
return -1;
}
if((chan = atoi(argv[1])) > Sccinfo.maxchan){
printf("SCC channel %d out of range\n",chan);
return -1;
}
if(Sccchan[chan] != NULL){
printf("SCC channel %d already attached\n",chan);
return -1;
}
/* create interface structure and fill in details */
ifp = (struct iface *) callocw(1,sizeof(struct iface));
ifp->name = mallocw(strlen(argv[3]) + 1);
strcpy(ifp->name,argv[3]);
ifp->mtu = atoi(argv[4]);
ifp->dev = chan;
ifp->stop = scc_stop;
scc = (struct sccchan *) callocw(1,sizeof(struct sccchan));
scc->ctrl = Sccinfo.iobase + (chan / 2) * Sccinfo.space + Sccinfo.off[chan % 2];
scc->data = scc->ctrl + Sccinfo.doff;
scc->iface = ifp;
if(isupper(argv[5][0]))
argv[5][0] = tolower(argv[5][0]);
switch (argv[5][0]) {
case 'd': /* fulldup divider installed? */
scc->fulldup = 1; /* set appropriate flag */
argv[5]++; /* skip the 'd' */
break;
case 'e': /* external clocking? */
scc->extclock = 1; /* set the flag */
break;
}
scc->bufsiz = atoi(argv[6]);
ifp->addr = Ip_addr;
Sccchan[chan] = scc; /* put addr in table for interrupts */
switch(argv[2][0]){ /* mode already checked above */
#ifdef AX25
case 'a': /* AX.25 */
scc_sdlc(scc); /* init SCC in SDLC mode */
if (!scc->extclock) {
brgrate = scc_speed(scc,32,atol(argv[5]));/* init SCC speed */
scc->speed = Sccinfo.clk / (64L * (brgrate + 2));/* calc real speed */
}
brgrate = scc_speed(scc,32,atol(argv[5]));/* init SCC speed */
scc->speed = Sccinfo.clk / (64L * (brgrate + 2));/* calc real speed */
setencap(ifp,"AX25UI");
scc_call(ifp,argc > 7 ? argv[7] : (char *) 0); /* set the callsign */
ifp->ioctl = scc_sioctl;
ifp->raw = scc_raw;
/* default KISS Params */
scc->a.txdelay = 36*TPS/100; /* 360 ms */
scc->a.persist = 25; /* 10% persistence */
scc->a.slottime = 16*TPS/100; /* 160 ms */
#if TPS > 67
scc->a.tailtime = 3*TPS/100; /* 30 ms */
#else
scc->a.tailtime = 2; /* minimal reasonable value */
#endif
scc->a.fulldup = 0; /* CSMA */
scc->a.waittime = 50*TPS/100; /* 500 ms */
scc->a.maxkeyup = 7; /* 7 s */
scc->a.mintime = 3; /* 3 s */
scc->a.idletime = 120; /* 120 s */
break;
case 'k': /* kiss */
scc_async(scc); /* init SCC in async mode */
brgrate = scc_speed(scc,16,atol(argv[5]));
scc->speed = Sccinfo.clk / (32L * (brgrate + 2));
setencap(ifp,"AX25UI");
scc_call(ifp,argc > 7 ? argv[7] : (char *) 0); /* set the callsign */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -