home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
t
/
twindv21.zip
/
TWIN_AT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-12
|
47KB
|
1,727 lines
/****************************************************************************
*
* COPYRIGHT 1990,91,92 BY GRACILIS INC.
*
* 623 Palace St.
* Aurora, Il. 60506
*
* (708)-801-8800 Office
* (708)-844-0183 (FAX - Support BBS)
*
* GRACILIS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS
* SOFTWARE FOR ANY PURPOSE.
*
* THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
*
* Permission is granted for non-commercial use/distribution only, as long as
* this copyright header is included intact and unaltered.
*
******************************************************************************/
/*****************************************************************************
*
*
* File: twin_at.c
*
* Rev : 3.0
*
* Description:
*
* This File contains routines that implement PackeTwin
* synchronous SCC driver with an interface to KA9Q's TCP/IP suite.
*
*
* Routines:
*
* tsync_attach - Performs attach functions for TCP/IP, i.e.
* attach the tsync_driver to TCP/IP.
*
* do_tsync_stat - Applications' routine for "displaying" the
* tsync_driver statistics.
*
* tsync_ioctl - Set the IO Control parameters.
*
*
* Revision History:
*
* Release 2.0 - 9/7/92 First Release of cleaned up Twin driver
* with fewer files, and called twin_at instead
* of tsync_at
*
* Release 2.1 - 9/12/92 Fix bug in half-duplex dma mode, which caused
* loss of every other receive frame in a multi-
* frame transmission.
*/
#include <stdio.h>
#include <dos.h>
#include "global.h"
#include "config.h"
#include "hardware.h"
#include "mbuf.h"
#include "iface.h"
#include "ax25.h"
#include "trace.h"
#include "netuser.h"
#include "proc.h"
#include "pktdrvr.h"
#include "devparams.h"
#include "z8530.h"
#include "gracilis.h"
#include "twin.h"
/* If using the Borland stdio library... */
#ifdef OLD_KA9Q
#else
/* If using the new KA9Q stdio library... */
#define tprintf printf
#endif
/*******************************************************************
* TSYNC_ATTACH *
* *
* File: tsync_at.c *
* Rev : 3.0 *
* *
********************************************************************
*
*
* DESCRIPTION:
* -----------
* Attaches the PackeTwin's synchronous SCC driver to TCP/IP.
*
* ARGUMENTS:
* ---------
* All argv's are strings
* argv[0]: hardware type, "tsync"
* argv[1]: "0" = 8530 SCC A
* "1" = 8530 SCC B
* argv[2]: vector, Interrupt request line #
*
* argv[3]: IOBASE : base address for PackeTwin default 0x230
*
* argv[4]: "HDX" half-duplex
* "FDX" full-duplex
*
* argv[5]: mode, DMA/INTS for channel 1, MUST be INTS
*
* argv[6]: Dma channel to use for receive...
* 0 = none...
* 1 = Rx on dma channel 1 and if FULL DUPLEX tx on channel 3
* 3 = Rx on dma channel 3 and if FULL DUPLEX tx on channel 1
*
* argv[7]: interface label
*
* This label is provided by the user and the attach uses
* it in its tprintf's to tell the user which interface
* is being talked about.
*
* argv[8]: max receive packet buffer size in bytes
* argv[9]: max xmit packet buffer size in bytes
* argv[10]: interface baud rate, e.g, "9600"
* argv[11]: OPTIONAL - clocking options
* argv[12]: OPTIONAL - clocking options
* argv[13]: OPTIONAL - Data Encoding: NRZ/NRZI
* argv[14]: OPTIONAL - IP address - default is Ip_addr
* argv[15]: OPTIONAL - number of RX buffers to pre-allocate
*
* RETURN VALUES:
* -------------
* 0 - success
* -1 - failure, driver not attached and no memory left allocated
*
* GLOBAL INPUTS:
* -------------
*
* GLOBAL OUTPUTS:
* --------------
*
* FUNCTIONS CALLED:
* ----------------
* tprintf
* calloc
* malloc
* tsync_hwinit
* free
*
* IO:
* --
*
*
******************************************************************/
/* Extern declaration for the */
extern UNI_DCB Twin_udcb[]; /* array of universal control */
/* blocks for this driver */
/* interrupt handler */
extern INTERRUPT twinvec();
extern INTERRUPT (*Twin_oldvec) __ARGS((void)); /* Old vector contents */
extern INTERRUPT (*Twin_handler) __ARGS((void));
extern char *Twin_dvr_version;
extern int Twin_io_base;
extern int16 Twin_vector;
extern int Twin_cputype; /* Global to identify the machine type */
/* 0 = 8086 */
/* 2 = 80286 */
/* 3 = 80386 */
int
tsync_attach(argc,argv,p)
int argc;
char *argv[];
void *p; /* new for NOS */
{
extern void tsyncvec();
extern struct iface *ifaces;
char i_state;
int32 ipaddr; /* new for NOS - IP address */
int i;
char tmpbuf[80];
register struct iface *intfc_p;
DCB *dcbp;
UNI_DCB *udcbp;
int udcb_dev;
int16 rbufsize, xbufsize;
int rxdmachan,txdmachan;
struct drv_timer *timer1;
unsigned char far *cpusig_ptr; /* ptr to CPU signature byte in rom */
bool hdxflg,dmaflg;
#ifdef OLD_KA9Q
struct phdr *hdr; /* new for NOS - packet header*/
#endif
void tsync_recv(), tsync_txisr(), tsync_rxisr(), tsync_xstatisr();
int32 tsync_ioctl();
int tsync_send();
int tsync_output();
int tsync_stop();
int tsync_raw();
int ax_send();
int ax_output();
/* Try reading the Machine ID in ROM... */
cpusig_ptr = (unsigned char *)MK_FP(0xf000,0xfffe);
if((*cpusig_ptr == 0xfc) || (*cpusig_ptr == 0xf8))
Twin_cputype = 2; /* 80286 or better */
else Twin_cputype = 0; /* Default to type 8086 */
#ifdef TSYNC_DEBUG_PRT
printf("tsync_attach: argument count is %d\n",argc);
for(i=0;i<argc;i++)
printf("arg #%d: %s\n",i,argv[i]);
printf("\n\n");
#endif
/*
* validate input params
*/
if ( argc < 11 )
{
tprintf("tsync_attach: too few arguments (%d) \n", argc);
tprintf("tsync <chan> <vec> <iobase> <hdx|fdx> <dma|ints> <rx dmachan>\n");
tprintf(" <name> <rxsize> <txsize> <speed> [txclk] [rxclk] [nrz|nrzi] \n");
tprintf(" [ipaddr] [#rxbufs]\n");
return(1); /* should this be a -1, milt milt */
}
/* get the PackeTwin device number/address
* and validate it for a synchronous driver
*/
udcb_dev = htoi(argv[1]);
/* range check device number */
if ( (udcb_dev < 0) || (udcb_dev > 1) )
{
tprintf("tsync_attach error: Channel number %x out of range!\n", udcb_dev);
return(-1);
}
udcbp = &Twin_udcb[udcb_dev]; /* dev num is index number!!! */
/* See if already attached */
if ( udcbp->attached == TRUE )
{
tprintf("tsync_attach error: Channel %s already attached; interface is %s", argv[1], argv[7]);
return(-1);
}
if ( if_lookup(argv[7]) != NULLIF ) /* new for NOS */
{
tprintf("Interface %s already exists \n", argv[7]);
return(-1);
}
Twin_vector = htoi(argv[2]);
if( Twin_vector <= 0 || Twin_vector > 15)
{
tprintf("Illegal vector specified: %s\n", argv[2]);
return(-1);
}
if((htoi(argv[3])) >= 0x100)
Twin_io_base = htoi(argv[3]);
else
{
tprintf("Illegal iobase specified: %s\n", argv[3]);
return(-1);
}
if(strcmpi(argv[4],"hdx") == 0) hdxflg = TRUE;
else if(strcmpi(argv[4],"fdx") == 0) hdxflg = FALSE;
else
{
tprintf("tsync_attach error: Specified %s instead of \"hdx\" or \"fdx\" for interface %s\n",
argv[4],argv[7]);
return(-1);
}
/* Are we in DMA mode? */
if (strcmpi(argv[5],"dma") == 0)
{
dmaflg = TRUE;
rxdmachan = htoi(argv[6]);
/* Did they enter a valid dma channel #? */
if((rxdmachan != 3) && (rxdmachan != 1))
{
/* NO... bad channel # */
tprintf("tsync_attach error: Specified dma channel: %d instead of 1 or 3 for interface %s\n",
rxdmachan,argv[7]);
return(-1);
}
/* YES valid channel # */
else
{
if(hdxflg == FALSE)
{
if(rxdmachan == 1)txdmachan = 3;
else txdmachan = 1;
}
else txdmachan = rxdmachan;
}
}
/* in interrupt mode? */
else if (strcmpi(argv[5],"ints") == 0)dmaflg = FALSE;
else
{
tprintf("tsync_attach error: Specified %s instead of \"dma\" or \"ints\" for interface %s\n",
argv[5],argv[7]);
return(-1);
}
/* Can't specify DMA for port B */
if((dmaflg == TRUE) && (udcb_dev != 0))
{
tprintf("tsync_attach error: DMA is not supported on channel 1!\n");
return(-1);
}
if ( (rbufsize = atoi(argv[8])) == 0 )
{
tprintf("tsync_attach error: Receive buffer size error %s, interface %s\n",
argv[8],argv[7]);
return(-1);
}
if ( (xbufsize = atoi(argv[9])) == 0 )
{
tprintf("tsync_attach error: Transmit buffer size error %s, interface %s\n",
argv[9],argv[7]);
return(-1);
}
/* new for NOS, Set the IP address */
ipaddr = Ip_addr; /* default value */
if ( argc >= 15 )
ipaddr = resolve(argv[14]);
if ( ipaddr == 0 )
{
tprintf(Noipaddr);
return(-1);
}
/*
* try to allocate necessary memory
*/
intfc_p = (struct iface *)calloc(1,sizeof(struct iface));
if ( intfc_p != (struct iface *)NULLBUF )
{
intfc_p->name = malloc((unsigned int)strlen(argv[7])+2);
if (intfc_p->name != (char *)NULLBUF )
{
/* device hw addr */
intfc_p->hwaddr = malloc(AXALEN);
if ( intfc_p->hwaddr == NULLCHAR )
{
free(intfc_p->name);
free(intfc_p);
tprintf("tsync_attach error: no memory for interface hwaddr, size of sizeof(struct mycall) bytes, interface %s", argv[7]);
return(-1);
}
}
else
{
free(intfc_p);
tprintf("tsync_attach error: no memory for interface name, size 7 bytes, interface %s", argv[7]);
return(-1);
}
}
else
{
tprintf("tsync_attach error: no memory for interface struct, size of sizeof(struct iface), interface %s", argv[7]);
return(-1);
}
/* get the timer control blocks */
/* must have zeros in structure, so use calloc */
if ( (timer1 = (struct drv_timer *)calloc(1,sizeof(struct drv_timer))) == (struct drv_timer *)NULLBUF )
{
free(intfc_p->hwaddr);
free(intfc_p->name);
free(intfc_p);
tprintf("tsync_attach error: no memory for timer control block structure, size of sizeof(struct drv_timer), interface %s", argv[7]);
return(-1);
}
dcbp = (DCB *)calloc(1,sizeof(DCB)); /* zero-out the dcb */
if ( dcbp != (DCB *)NULLBUF )
{
dcbp->rxbufsize = rbufsize;
#ifdef OLD_KA9Q
dcbp->rxbufp = alloc_mbuf(rbufsize+sizeof(struct phdr));
#else
dcbp->rxbufp = alloc_mbuf(rbufsize);
#endif
if (dcbp->rxbufp != NULLBUF )
{
dcbp->ioctlparams = (struct tsync_ioctl *)malloc(sizeof(struct tsync_ioctl));
if ( dcbp->ioctlparams == (struct tsync_ioctl *)NULLBUF )
{
free(timer1);
free(intfc_p->hwaddr);
free(intfc_p->name);
free(intfc_p);
free(dcbp->rxbufp);
free(dcbp);
tprintf("tsync_attach error: no memory for IOCTL params size %x bytes, interface %s", sizeof(struct tsync_ioctl), argv[7]);
return(-1);
}
}
else
{
free(timer1);
free(intfc_p->hwaddr);
free(intfc_p->name);
free(intfc_p);
free(dcbp);
tprintf("tsync_attach error: no memory for receive buffer, size %x bytes, interface %s", rbufsize, argv[7]);
return(-1);
}
}
else
{
free(timer1);
free(intfc_p->hwaddr);
free(intfc_p->name);
free(intfc_p);
tprintf("tsync_attach error: no memory for device control block structure, size of sizeof(DCB), interface %s", argv[7]);
return(-1);
}
if ( Mycall[0] == '\0' )
{
free(timer1);
free(intfc_p->hwaddr);
free(intfc_p->name);
free(intfc_p);
free(dcbp->rxbufp);
free(dcbp);
tprintf("tsync_attach error: mycall not set\n");
return(-1);
}
/*
* Universal Driver Control Block Init -
* Except for the saving of old vectors and attached field.
* Attached field is saved for the very end.
*/
udcbp->type = SYNC_8530; /* 8530 scc */
/* set address of the unit's driver control block */
udcbp->dcbp = (char *)dcbp;
/* setup this device's interrupt handlers */
udcbp->prev_vec2 = tsync_txisr;
udcbp->prev_vec3 = tsync_rxisr;
udcbp->prev_vec4 = tsync_xstatisr;
/*
* Setup the interface structure and link it to the list
* of interface structures.
*/
/* the Ascii name of the driver unit */
strcpy(intfc_p->name,argv[7]);
/* set the device number, must be able to tell whether */
/* channel A or channel B is being used */
dcbp->dev = udcb_dev;
switch ( udcb_dev )
{
case TWINCOMM1:
dcbp->zhwmap.ctl = (int16)(Twin_io_base+SCCA_CMD);
dcbp->zhwmap.data = (int16)(Twin_io_base+SCCA_DATA);
break;
case TWINCOMM2:
dcbp->zhwmap.ctl = (int16)(Twin_io_base+SCCB_CMD);
dcbp->zhwmap.data = (int16)(Twin_io_base+SCCB_DATA);
break;
}
/* not for NOS intfc_p->recv = tsync_recv;
*/
intfc_p->mtu = xbufsize - MAX_AX25_HDR_LEN;
intfc_p->ioctl = tsync_ioctl;
intfc_p->raw = tsync_raw;
intfc_p->addr = ipaddr; /* new for NOS */
intfc_p->stop = tsync_stop;
intfc_p->dev = udcb_dev;
setencap(intfc_p,"AX25");
/* For packet radio put in the sender's "call letters" */
memcpy(intfc_p->hwaddr,Mycall,AXALEN);
/* lastly, but very importantly, put in the LL of interfaces */
intfc_p->next = Ifaces;
Ifaces = intfc_p;
/*
* Initialize the unit's driver control block
*/
dcbp->iface = intfc_p; /* new for NOS - save the iface */
/* address for use in queueing */
/* mbufs onto Hopper */
dcbp->txstate = IDLE;
dcbp->xmtq = (struct drvbuf *)NULLBUF;
dcbp->xmtqtail = (struct drvbuf *)NULLBUF; /* milt */
dcbp->freem = (struct drvbuf *)NULLBUF; /* milt */
dcbp->rxstate = IDLE;
dcbp->rxbufsize = atoi(argv[8]);
/*milt 3/15/91
dcbp->rxqhat.headp = NULLBUF;
dcbp->rxqhat.tailp = NULLBUF;
*/
/* Configure DMA stuff */
dcbp->dma_flg = dmaflg;
if(dmaflg == TRUE)
{
dcbp->dma_rx_chan = rxdmachan;
dcbp->dma_tx_chan = txdmachan;
switch(dcbp->dma_tx_chan)
{
case 1: dcbp->dma_tx_pagereg = 0x83;
dcbp->dma_tx_cnt_reg = DMA1CNT;
dcbp->dma_tx_addr_reg = DMA1ADR;
break;
case 3: dcbp->dma_tx_pagereg = 0x82;
dcbp->dma_tx_cnt_reg = DMA3CNT;
dcbp->dma_tx_addr_reg = DMA3ADR;
break;
}
switch(dcbp->dma_rx_chan)
{
case 1: dcbp->dma_rx_pagereg = 0x83;
dcbp->dma_rx_cnt_reg = DMA1CNT;
dcbp->dma_rx_addr_reg = DMA1ADR;
break;
case 3: dcbp->dma_rx_pagereg = 0x82;
dcbp->dma_rx_cnt_reg = DMA3CNT;
dcbp->dma_rx_addr_reg = DMA3ADR;
break;
}
/* SET up of the mode reg values for the DMA channels to be used */
if(hdxflg == FALSE)
{
/* FULL DUPLEX the values never change between rx/tx */
if(rxdmachan == 3)
dcbp->dma_rx_mode = dcbp->dma_tx_mode = PKTWIN_DMA_FDX_T1R3;
else
dcbp->dma_rx_mode = dcbp->dma_tx_mode = PKTWIN_DMA_FDX_T3R1;
}
else
{
/* Half DUPLEX... */
if(rxdmachan == 3)
{
dcbp->dma_rx_mode = PKTWIN_DMA_HDX_R3;
dcbp->dma_tx_mode = PKTWIN_DMA_HDX_T3;
}
else
{
dcbp->dma_rx_mode = PKTWIN_DMA_HDX_R1;
dcbp->dma_tx_mode = PKTWIN_DMA_HDX_T1;
}
}
} /* End of dma info setup */
/* no need to init stats because calloc zero-ed the dcbp */
/* default IOCTL Params */
dcbp->ioctlparams->xmitdelay = 250; /* 250 Ms */
dcbp->ioctlparams->persist= 64; /* 25% of 255 = 64 persistance*/
dcbp->ioctlparams->slotime = 10; /* 10 Ms */
dcbp->ioctlparams->squelch = 200; /* 200 Ms */
/* set the rxavailbufs parameter */
dcbp->ioctlparams->rxavailbufs = 0; /* zero 1st */
if ( argc >= 16 )
dcbp->ioctlparams->rxavailbufs = atoi(argv[15]);
if ( dcbp->ioctlparams->rxavailbufs < 4 )
dcbp->ioctlparams->rxavailbufs = 4; /* 4 is min!! */
/*
* setup the packet header for the DRIVER
* calling this routine
*/
/* init to packet header's byte count */
#ifdef OLD_KA9Q
dcbp->rxbufp->cnt = sizeof(struct phdr);
hdr = (struct phdr *)dcbp->rxbufp->data;
hdr->type = intfc_p->type;
hdr->iface = intfc_p;
/* Rx data goes in after packet header */
/* works because data is a char pointer */
dcbp->rxbufp->data += sizeof(struct phdr);
#else
dcbp->rxbufp->cnt = 0;
#endif
dcbp->rxcurp = dcbp->rxbufp->data;
/* get as many of the requested rx pre-allocated mbuf's */
dcbp->rxavailq = NULLBUF;
f_getavail(&(dcbp->rxavailq), dcbp->ioctlparams->rxavailbufs,
dcbp->rxbufsize,
&(dcbp->rxavailcount),
intfc_p, dcbp->dma_flg);
#ifdef TSYNC_DEBUG_PRT
printf("TSYNC_ATTACH: rxavailbufs is %d, rxavailcount is %d\n", dcbp->ioctlparams->rxavailbufs, dcbp->rxavailcount);
#endif
/* put in the timer control blocks */
dcbp->timer1 = timer1;
dcbp->baud = (int16)atoi(argv[10]);
/* set up duplex mode... */
dcbp->hduplex = hdxflg;
/* SET UP CLOCKING OPTIONS... */
/* Default to Externally supplied clocks */
/* select Tx clock mode for SCC */
/* Default is to expect clock to be supplied externally */
if((argc >= 12) && (strcmpi(argv[11],"int") == 0))dcbp->txclk_extrn = FALSE;
else dcbp->txclk_extrn = TRUE;
/* select Rx clock mode for SCC */
/* Default is to expect clock to be supplied externally */
if((argc >= 13) && (strcmpi(argv[12],"int") == 0))dcbp->rxclk_extrn = FALSE;
else dcbp->rxclk_extrn = TRUE;
/* select data coding scheme for SCC */
/* Default is NRZ */
if(argc >= 14)
{
if((strlen(argv[13]) >= strlen("nrzi")) &&
(strcmpi(argv[13],"nrzi") == 0))
{
dcbp->nrzi_flg = TRUE;
}
else dcbp->nrzi_flg = FALSE;
}
/*
* Now for the hardware dependent initializations.
* If device control block is an 8530 driver, then SCC
* stuff needs to be done.
*
* udcbp->type tells if its an 8530
* intfc_p->dev tells which unit/dev
*
*/
#ifdef TSYNC_DEBUG_PRT
printf("tsync_attach: intfc_p->dev = %x config 8530 HW \n", intfc_p->dev);
#endif
i_state = dirps(); /* {dgl} protect the writescc's */
/* and the vector reads/writes */
/* disable our ints */
maskoff(Twin_vector);
outportb(Twin_io_base+INT_CFG,(Twin_sercfg &= (~PKTWIN_EI)));
/*
* Can only reset the chip when it is not being used!!!
* This handles first time use of 8530.
* Set the base vector - since it is common set it here.
*/
if ( (Twin_udcb[TWINCOMM1].attached == FALSE) &&
(Twin_udcb[TWINCOMM2].attached == FALSE) )
{
/* This should NOT be done... if either ports are in use */
/* for ANYTHING */
Twin_write_scc(dcbp->zhwmap.ctl,R9,(dcbp->wr9 = FHWRES));
/* Save original interrupt vector */
Twin_oldvec = (INTERRUPT (*)())getirq(Twin_vector);
udcbp->prev_vec1 = (void (*)())Twin_oldvec;
/* New vector... */
setirq(Twin_vector, Twin_handler);
/* set up register images, and regs to defaults */
Twin_sercfg = Twin_dmacfg = 0;
outportb(Twin_io_base+INT_CFG,Twin_sercfg);
outportb(Twin_io_base+DMA_CFG,Twin_dmacfg);
}
/*
* Reset the individual channel. Handles cases of re-attaching
* channels and first attachment.
*
* For safetys sake set the Disable Lower Chain bit too.
*/
if ( dcbp->dev == TWINCOMM1 )
Twin_write_scc(dcbp->zhwmap.ctl,R9,(dcbp->wr9 = 0x84));
else
Twin_write_scc(dcbp->zhwmap.ctl,R9,(dcbp->wr9 = 0x44));
/* wait a bit... for chip to settle after reset */
/* Just in case... */
for(i=0;i<20;i++); /* milt */
/* configure the 8530 SCC */
if(tsync_hwinit(dcbp) == -1)
{
/* An error occurred in the hw init */
/* so clean up and leave... */
/* Mark it attached so the following detach routine */
/* won't complain */
udcbp->attached = TRUE;
if_detach(intfc_p);
/* re-enable this interrupt input */
maskon(Twin_vector);
restore(i_state);
tprintf("PackeTwin hardware unavailable or malfunctioning...\n");
return(-1);
}
/* enable PackeTwin ints */
outportb(Twin_io_base+INT_CFG,(Twin_sercfg |= PKTWIN_EI));
/* enable this level ints on 8259 */
maskon(Twin_vector);
/* {dgl} enable system-wide ints */
restore(i_state);
/*
* This channel is ATTACHED.
*/
udcbp->attached = TRUE;
/* new for NOS - start the two processes needed by the */
/* sync driver; one is for getting pre-allocated buffers */
/* the other is for kicking the transmitter after its */
/* timer has expired or when it needs a transmitted */
/* message free-ed. P.S. must do after attached set to TRUE */
sprintf(tmpbuf,"%s:getbuf",intfc_p->name);
dcbp->rxavproc = newproc(tmpbuf,150,tsync_rxavget,udcb_dev,NULL,NULL,0);
#ifdef TSYNC_DEBUG_PRT
printf("tsync_attach: called newproc for tsync_getbfs, procid = %lx \n",
dcbp->rxavproc);
#endif
sprintf(tmpbuf,"%s:kick",intfc_p->name);
dcbp->txkickproc = newproc(tmpbuf,150,tsync_txkick,udcb_dev,NULL,NULL,0);
#ifdef TSYNC_DEBUG_PRT
printf("tsync_attach: called newproc for tsync_txkick, procid = %lx \n",
dcbp->txkickproc);
tprintf("tsync_attach: All done!!! \n");
#endif
sprintf(tmpbuf,"%s:free",intfc_p->name);
dcbp->freetxproc = newproc(tmpbuf,150,tsync_freetx,udcb_dev,NULL,NULL,0);
/* Let our new processes get running... */
for(i=0;i<10;i++)pwait(NULL);
return(0);
}
/*
* End of tsync_attach()
******************************************************************/
/*
* Stop I/O
*/
int
tsync_stop(intfcp)
struct iface *intfcp;
{
DCB *sp;
UNI_DCB *udcbp;
int16 dev;
char i_state;
struct drvbuf *xbufp, *tmpptr;
struct mbuf *tmpbufp;
dev = intfcp->dev;
udcbp = &Twin_udcb[dev]; /* dev num is index number!!! */
if ( udcbp->attached != TRUE )
{
tprintf("tsync_stop err: Device already stopped/de-attached!!\n");
return(0);
}
else if ( (dev != TWINCOMM1) && (dev != TWINCOMM2) )
return(0); /* not for this driver */
sp = (DCB *)Twin_udcb[dev].dcbp;
/* kill off the support processes */
/* so they don't allocate memory */
/* whils't we're freeing it */
killproc(sp->rxavproc);
killproc(sp->txkickproc);
killproc(sp->freetxproc);
/* Turn off interrupts */
i_state = dirps();
/* mark port as available - do it now for if below */
udcbp->attached = FALSE;
/* Disable the DMA channels if any... */
if(sp->dma_flg)
{
outportb(DMAWSMR,sp->dma_rx_chan | 0x04);
outportb(DMAWSMR,sp->dma_tx_chan | 0x04);
}
/*
* Can only reset the chip when it is not being used!!!
* This handles first time use of 8530.
* Set the base vector - since it is common set it here.
*/
if ( (Twin_udcb[TWINCOMM2].attached == FALSE) &&
(Twin_udcb[TWINCOMM1].attached == FALSE) )
{
/* This should NOT be done... if either ports are in use */
/* for ANYTHING */
Twin_write_scc(sp->zhwmap.ctl,R9,(sp->wr9 = FHWRES));
/* Restore original interrupt vector */
setirq(Twin_vector,(INTERRUPT (*)())udcbp->prev_vec1);
/* Disable our board from generating ints... */
outportb(Twin_io_base+INT_CFG,(Twin_sercfg &= (~PKTWIN_EI)));
}
/*
* Reset the individual channel. Handles cases of re-attaching
* channels and first attachment.
*
*/
if ( sp->dev == TWINCOMM1 )
{
Twin_write_scc(sp->zhwmap.ctl,R9,(sp->wr9 = 0x88));
/* Drop DTR to indicate we are gone...*/
outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_DTRA_ON)));
}
else
{
Twin_write_scc(sp->zhwmap.ctl,R9,(sp->wr9 = 0x48));
/* Drop DTR to indicate we are gone...*/
outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_DTRB_ON)));
}
restore(i_state);
/*
* Flush all buffers and queue's
*/
/* Now free all preallocated rx buffers on the rx available queue */
while((tmpbufp = f_dequeavail(&sp->rxavailq,&sp->rxavailcount)) != NULLBUF)
free(tmpbufp); /* these mbuf's are one contigous */
/* chunk of memory */
if ( sp->rxbufp != NULLBUF )
free(sp->rxbufp);
/* free up any pending transmit buffers... */
while(sp->xmtq != (struct drvbuf *)NULLBUF)
{
tmpptr = sp->xmtq->next;
free(sp->xmtq);
sp->xmtq = tmpptr;
}
/* Free any previously sent frames, which are in the waiting to be */
/* free'd queue */
/* disable ints here to get queue head... */
i_state = dirps(); /* seems unecessary milt */
xbufp = sp->freem;
sp->freem = (struct drvbuf *)NULLBUF;
restore(i_state);
/* Here xbufp is a "to be free'd" */
/* queue pointer" */
/* now free memory of all the xmitted messages */
while ( xbufp != (struct drvbuf *)NULLBUF )
{
tmpptr = xbufp->next;
free((char *)xbufp);
xbufp = tmpptr;
}
/*
* Deallocate other driver related memory structures
*/
free(sp->timer1);
free(sp->ioctlparams);
free(sp);
return(0);
}
/*
* Display a PackeTwin SYNCHRONOUS channel's statistics.
*/
int
do_tsync_stat()
{
DCB *dcbp;
UNI_DCB *udcbp;
int16 dev;
unsigned long rxerrcnt;
bool hd8530;
/* Header for all the Synchronous channel's on the card */
tprintf(" PackeTwin Synchronous Driver Release %s\n\n"
,Twin_dvr_version);
hd8530 = FALSE;
for (dev=0, udcbp = &Twin_udcb[0]; dev < 2 ; udcbp++, dev++)
{
if ( udcbp->type == SYNC_8530 )
{
if ( udcbp->attached == TRUE )
{
if ( !hd8530 )
{
tprintf("\n");
tprintf("8530 RxChars RxPacks Rxerrs RxBf Txchars TxPacks TxUns RxNoBf\n");
tprintf("----- --------- ------- ------ ---- --------- ------- ----- ------\n");
hd8530 = TRUE;
}
dcbp = (DCB *)udcbp->dcbp;
/* total receiver error count */
rxerrcnt = dcbp->rxcrcerrcnt + dcbp->rxovercnt;
tprintf(" %4.1d %#9lu %#7lu %#6lu %#4lu %#9lu %#7lu %#5lu %#6lu\n",
dev, dcbp->rxbytecnt,
dcbp->rxpackcnt,
rxerrcnt,
dcbp->rxavailcount,
dcbp->txbytecnt,
dcbp->txpackcnt,
dcbp->txunderun,
dcbp->nobufs);
#ifdef TSYNC_DEBUG_PRT
printf("Crc's: %lx Overruns: %lx\n",dcbp->rxcrcerrcnt,dcbp->rxovercnt);
printf("DCB ptr: %p\n",dcbp);
printf("rxcurp: %p rxbufp: %p rxbufp->cnt: %d\n",dcbp->rxcurp,
dcbp->rxbufp,
dcbp->rxbufp->cnt);
#endif
}
}
} /* end of for loop */
for (dev=0, udcbp = &Twin_udcb[0]; dev < 2; udcbp++, dev++)
{
if ( udcbp->attached == FALSE )
tprintf("\nChannel %d is UN-attached", dev);
}
tprintf("\n");
return(0);
}
/* Subroutine to set kiss params in channel tables */
int32
tsync_ioctl(iface,cmd,set,val)
struct iface *iface;
int cmd;
int set;
int32 val;
{
DCB *dcbp;
dcbp = (DCB *)Twin_udcb[iface->dev].dcbp;
switch(cmd){
case PARAM_TXDELAY:
if(set)
dcbp->ioctlparams->xmitdelay = (int16)val;
return dcbp->ioctlparams->xmitdelay;
case PARAM_PERSIST:
if(set)
dcbp->ioctlparams->persist = (uchar)val;
return uchar(dcbp->ioctlparams->persist);
case PARAM_SLOTTIME:
if(set)
dcbp->ioctlparams->slotime = (int16)val;
return dcbp->ioctlparams->slotime;
case PARAM_TXTAIL:
if(set)
dcbp->ioctlparams->squelch = (int16)val;
return dcbp->ioctlparams->squelch;
case PARAM_RXBUFS:
if(set)
dcbp->ioctlparams->rxavailbufs = (int16)val;
return dcbp->ioctlparams->rxavailbufs;
}
return -1;
}
/*
* Initialize the SZ driver's hardware for SDLC, i.e. the 85c30 SCC.
*/
int
tsync_hwinit(dcbp)
register DCB *dcbp;
{
char i_state; /* for PackeTwin this is 2 bytes */
int16 tc; /* time constant for 8530 */
int i;
bool baudclk_flg;
bool both_clocks_internal;
void tsync_loopback();
void enable_escc();
int nop1 = 0;
#define nop nop1++;
#ifdef TSYNC_DEBUG_PRT
printf("Initializing TSYNC_DRIVER device num = %d\n", dcbp->dev);
#endif
i_state = dirps();
/* if both clocks are specified as internal, then override the */
/* specified data coding scheme, and MAKE it NRZI */
if((dcbp->rxclk_extrn == FALSE) && (dcbp->txclk_extrn == FALSE))
{
dcbp->nrzi_flg = TRUE;
both_clocks_internal = TRUE;
}
else
both_clocks_internal = FALSE;
/* If we are not using DMA, then try to enable the extended TX FIFO */
if(!(dcbp->dma_flg)) enable_escc(dcbp);
/* times 1 x clock, SDLC mode */
/* always set R4 before R1, R3, R6, and R7 */
Twin_write_scc(dcbp->zhwmap.ctl,R4,(dcbp->wr4 = 0x20));
/* mask-off all interrupt types */
/* No DMA, No Ints... */
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0));
/* Rx 8 bit/chars, enter hunt mode, CRC enable */
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xd8));
/* DTR, Tx 8 bit/chars and Tx disabled */
Twin_write_scc(dcbp->zhwmap.ctl,R5,(dcbp->wr5 = 0x60));
/* no SDLC transmit secondary address */
Twin_write_scc(dcbp->zhwmap.ctl,R6,(dcbp->wr6 = 0));
/* Set SDLC flag */
Twin_write_scc(dcbp->zhwmap.ctl,R7,(dcbp->wr7 = FLAG));
if(dcbp->nrzi_flg != TRUE)
{
/* Preset Tx CRC, NRZ Mode, flags on idle and */
/* underrun 8 bit sync mode */
Twin_write_scc(dcbp->zhwmap.ctl,R10,(dcbp->wr10 = 0x84));
}
else
{
/* Preset Tx CRC, NRZI Mode, flags on idle and */
/* aborts on underrun 8 bit sync mode */
Twin_write_scc(dcbp->zhwmap.ctl,R10,(dcbp->wr10 = 0xa4));
}
/* Set up BRG and DPLL multiplexers */
/* Case where only the Rx clock is supplied externally */
if((dcbp->rxclk_extrn == TRUE) && (dcbp->txclk_extrn != TRUE))
{
/* Tx Clk from BRG. Rcv Clk external on RTxC, */
/* TRxC pin outputs BRgen */
Twin_write_scc(dcbp->zhwmap.ctl,R11,(dcbp->wr11 = 0x16));
tc = ( (XTAL) / (dcbp->baud *2))-2;
baudclk_flg = TRUE;
/* disable the external TX clock receiver input */
if(dcbp->dev == TWINCOMM1) outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_EXTCLKA)));
else outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_EXTCLKB)));
}
/* Case where only the Tx clock is supplied externally */
if((dcbp->txclk_extrn == TRUE) && (dcbp->rxclk_extrn != TRUE))
{
/* Tx Clk external on TRxC, Rcv Clk internal BRgen, */
/* TRxC pin is input TX clock */
Twin_write_scc(dcbp->zhwmap.ctl,R11,(dcbp->wr11 = 0x4a));
tc = ( (XTAL) /(dcbp->baud *2))-2;
baudclk_flg = TRUE;
/* enable the external TX clock receiver input */
if(dcbp->dev == TWINCOMM1) outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_EXTCLKA));
else outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_EXTCLKB));
}
/* Case where both clocks are supplied externally */
if((dcbp->txclk_extrn == TRUE) && (dcbp->rxclk_extrn == TRUE))
{
/* Tx Clk external on TRxC, Rcv Clk external on RTxC, */
/* TRxC pin is input TX clock */
Twin_write_scc(dcbp->zhwmap.ctl,R11,(dcbp->wr11 = 0x0a));
baudclk_flg = FALSE;
/* enable the external TX clock receiver input */
if(dcbp->dev == TWINCOMM1) outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_EXTCLKA));
else outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_EXTCLKB));
/*DTR is in REQ mode for possible DMA */
if(dcbp->dma_flg)Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x04));
else Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x00));
}
if(both_clocks_internal == TRUE)
{
/* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
Twin_write_scc(dcbp->zhwmap.ctl,R11,(dcbp->wr11 = 0x77));
/* time constant 32X BRG divisor */
tc = ((XTAL/32)/(dcbp->baud * 2))-2;
/* DGL... fix a cut and paste error... */
/* baudclk_flg = FALSE; */
baudclk_flg = TRUE;
/* disable the external TX clock receiver input */
if(dcbp->dev == TWINCOMM1) outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_EXTCLKA)));
else outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_EXTCLKB)));
}
if(baudclk_flg == TRUE)
{
/* lower byte */
Twin_write_scc(dcbp->zhwmap.ctl,R12,(dcbp->wr12 = (tc&0xFF)));
/* upper byte */
Twin_write_scc(dcbp->zhwmap.ctl,R13,(dcbp->wr13 = ((tc>>8)&0xFF)));
/* enable the BR generator... */
/*DTR is in REQ mode for possible DMA */
if(dcbp->dma_flg)Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x07));
else Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x03));
}
if(both_clocks_internal == TRUE)
{
/* BRG off, Enter Search mode */
/*DTR is in REQ mode if possible DMA */
if(dcbp->dma_flg)Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x26));
else Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x22));
/* Set DPLL source to BRGEN */
/*DTR is in REQ mode for possible DMA */
if(dcbp->dma_flg)Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x86));
else Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x82));
/* Set DPLL mode to NRZI */
/*DTR is in REQ mode for possible DMA */
if(dcbp->dma_flg)Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0xe6));
else Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0xe2));
/* At this point; the DPLL is searching for a data edge to begin clocking */
/* The baud rate gen is set to 32 times the desired rate.. */
/* The transmitter is based on the BRGEN. (i.e. 32x ) */
/* */
/* Procedure here; Set up an external loopback, then send aborts, to */
/* trigger and sync up the DPLL. */
/* After the DPLL is running, then reprogram the Xmitter */
/* to use the DPLL output as it's transmitter clock. */
/* This saves us having to reprogram the BRG whenever we */
/* switch from RECV to TX and back. */
/*
/* Turn on the recvr */
/* Rx 8 bit/chars, enter hunt mode, CRC enable */
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xd9));
/* Turn on the transmitter */
/* DTR, Tx 8 bit/chars and Tx enabled */
Twin_write_scc(dcbp->zhwmap.ctl,R5,(dcbp->wr5 = 0x68));
/* reset TX CRC */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x80));
/* enable the BR generator to start things up...*/
/*DTR is in REQ mode for possible DMA */
if(dcbp->dma_flg)Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x07));
else Twin_write_scc(dcbp->zhwmap.ctl,R14,(dcbp->wr14 = 0x03));
/* OK now turn on the loopback */
tsync_loopback(dcbp,ON);
/* Now send sum aborts... */
for(i=0;i<25;i++)
{
/* read and toss any data */
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
inportb(dcbp->zhwmap.data);
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x18)); /* send abort */
}
/* OK, now the DPLL should be running at ~32 * baudrate requested */
/* Turn off the loopback... */
tsync_loopback(dcbp,OFF);
/* Now reprogram the transmitter clock to use the DPLL output */
/* TX clk is DPLL, RX clk is DPLL, TRxc is DPLL OUT */
Twin_write_scc(dcbp->zhwmap.ctl,R11,(dcbp->wr11 = 0x7f));
/* dgl for G3RUH modems... I need to do AUTO-ENABLES... */
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
}
else
{
/* Turn on the recvr */
/* Rx 8 bit/chars, enter hunt mode, CRC enable */
/* no autoenables */
/*
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xd9));
*/
/* dgl for G3RUH modems... I need to do AUTO-ENABLES... */
Twin_write_scc(dcbp->zhwmap.ctl,R3,(dcbp->wr3 = 0xf9));
}
/* Turn off external interrupts (like CTS/CD) */
Twin_write_scc(dcbp->zhwmap.ctl,R15,(dcbp->wr15 = 0x00));
/* TRANSMITTER OFF */
Twin_write_scc(dcbp->zhwmap.ctl,R5,(dcbp->wr5 = 0x60)); /* TX off now */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x80)); /* reset TX CRC generator */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x40)); /* reset RX CRC checker */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x28)); /* reset TX int pending */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x28)); /* reset TX int pending */
/* reset extrn/sts ints... twice */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x10));
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x10));
/* if we are interrupt driven only: then allow ints for ALL RCV cndxs,
*/
if(dcbp->dma_flg == FALSE)
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0x11));
/* otherwise interrupt on special rcv cdx only */
/* DMA req mode Req on rcv, Req enabled */
else Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0xf9));
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x30)); /* reset error bits */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x30)); /* twice superstition */
/* If neither of the PKTwin's ports are currently attached*/
/* Then set up the prescaler timer */
if ( (Twin_udcb[TWINCOMM2].attached == FALSE) &&
(Twin_udcb[TWINCOMM1].attached == FALSE) )
{
inportb(Twin_io_base+CLR_TMR1);
nop;
inportb(Twin_io_base+CLR_TMR2);
nop;
/* Timer counter channel 0 */
/* 1 ms period */
outportb(Twin_io_base+TMR_CTRL,(unsigned char)0x36);
nop;
outportb(Twin_io_base+TMR_CNT0,(unsigned char)0x00);
nop;
outportb(Twin_io_base+TMR_CNT0,(unsigned char)0x18);
nop;
outportb(Twin_io_base+TMR_CTRL,(unsigned char)0x70);
nop;
inportb(Twin_io_base+CLR_TMR1);
nop;
outportb(Twin_io_base+TMR_CTRL,(unsigned char)0xB0);
nop;
inportb(Twin_io_base+CLR_TMR2);
nop;
}
if(dcbp->dev == TWINCOMM1)
{
/* mode setup for this channel's driver timer */
/* Set it's timer for 1 tick and let it expire */
outportb(Twin_io_base+TMR_CTRL,(unsigned char)0x70);
nop;
inportb(Twin_io_base+CLR_TMR1);
nop;
/* If the timer hasn't gone off, the hardware is either */
/* not present, or broken... */
if(!inportb(Twin_io_base+INT_REG) & 0x02)
{
restore(i_state);
return(-1);
}
/* Assert DTR to indicate we are alive...*/
outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_DTRA_ON));
}
if(dcbp->dev == TWINCOMM2)
{
/* mode setup for this channel's driver timer */
outportb(Twin_io_base+TMR_CTRL,(unsigned char)0xb0);
nop;
inportb(Twin_io_base+CLR_TMR2);
nop;
/* If the timer hasn't gone off, the hardware is either */
/* not present, or broken... */
if(!inportb(Twin_io_base+INT_REG) & 0x04)
{
restore(i_state);
return(-1);
}
nop;
/* Assert DTR to indicate we are alive...*/
outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_DTRB_ON));
}
if(dcbp->dma_flg == TRUE)
{
/* mask off the DMA channel(s) */
outportb(DMAWSMR,(dcbp->dma_rx_chan | 0x04));
outportb(DMAWSMR,(dcbp->dma_tx_chan | 0x04));
outportb(Twin_io_base+DMA_CLR_FF,0x00); /* Initially clear the REQ's */
/* This is the PackeTwin reg..*/
/* NOT the 8237 reg... */
outportb(DMAMODE,dcbp->dma_rx_chan | RX_DMA);
if(dcbp->hduplex == FALSE)
{
outportb(DMAMODE,dcbp->dma_rx_chan | RX_DMA);
outportb(DMAMODE,dcbp->dma_tx_chan | TX_DMA);
/* tx dma, enabled, fdx, chan3*/
/* rx dma, enabled, fdx, chan1*/
outportb(Twin_io_base+DMA_CFG,dcbp->dma_tx_mode);
}
else
{
outportb(DMAMODE,dcbp->dma_rx_chan | RX_DMA);
/* rx dma,hdx, enabled, chan 1*/
outportb(Twin_io_base+DMA_CFG,dcbp->dma_rx_mode);
}
outportb(DMAFFCL,0x00); /* This is the 8237 reg */
rxprime_dma(dcbp,1); /* buglet... 9/12/92 */
/* {dgl} */
}
/* reset Tx int pending */
/* This should keep the chip from underrunning, as */
/* well as clearing any pending txempty interrupt */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = 0x28));
/* reset external status latch */
/* clear any pending ext sts bits */
/* TWICE for good measure */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = RES_EXT_INT));
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = RES_EXT_INT));
/* Reset Underrun/EOM latch */
/* clear the latch... it should stay that way...*/
/* at least till we send feed some data to the tx fifo */
Twin_write_scc(dcbp->zhwmap.ctl,R0,(dcbp->wr0 = (RES_EOM_L | RES_EXT_INT)));
/* Turn on DCD interrupt */
Twin_write_scc(dcbp->zhwmap.ctl,R15,(dcbp->wr15 = CTSIE|DCDIE));
/* save this initial state of RR0 */
dcbp->extreg = Twin_read_scc(dcbp->zhwmap.ctl,R0);
dcbp->extreg = dcbp->extreg |= TxEOM;
/* if we are interrupt driven only: then allow ints for ALL RCV cndxs,
*/
if(dcbp->dma_flg == FALSE)
Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0x13));
/* otherwise interrupt on special rcv cdx only */
/* DMA req mode Req on rcv, Req enabled */
else Twin_write_scc(dcbp->zhwmap.ctl,R1,(dcbp->wr1 = 0xf9));
/* master interrupt enable the channel */
Twin_write_scc(dcbp->zhwmap.ctl,R9,(dcbp->wr9 = (MIE|DLC|NV)));
restore(i_state);
return(0);
}
void
tsync_loopback(dcbp,flag)
DCB *dcbp;
char flag;
{
if(flag == ON)
{
switch(dcbp->dev)
{
case TWINCOMM1: outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_LOOPA_ON));
break;
case TWINCOMM2: outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg |= PKTWIN_LOOPB_ON));
break;
}
}
else
{
switch(dcbp->dev)
{
case TWINCOMM1: outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_LOOPA_ON)));
break;
case TWINCOMM2: outportb(Twin_io_base+SERIAL_CFG,(Twin_sercfg &= (~PKTWIN_LOOPB_ON)));
break;
}
}
}
void
tsync_reset_8530()
{
int16 ctl;
ctl = (int16)(Twin_io_base+SCCA_CMD);
Twin_write_scc(ctl,R9,FHWRES);
}
/*
1 2 3 4 5 6 7
01234567890123456789012345678901234567890123456789012345678901234567890123456789
/*
* Display a PackeTwin SYNCHRONOUS channel's internal state
*/
int
do_tsync_dump(argc,argv,p)
int argc;
char *argv[];
void *p; /* new for NOS */
{
DCB *dcbp;
UNI_DCB *udcbp;
int16 dev;
char tmpstr[40];
if(argc < 2)
{
tprintf("Usage: tsydump channel#\n");
return 1;
}
dev = htoi(argv[1]); /* get port number to look at */
tprintf(" PackeTwin Synchronous Channel Internals\n\n");
udcbp = &Twin_udcb[dev];
if ( udcbp->type == SYNC_8530 )
{
if ( udcbp->attached == TRUE )
{
dcbp = (DCB *)udcbp->dcbp;
tprintf("\n");
tprintf(" RECEIVER STATUS: \n");
tprintf(" Packcnt Nqued Bytecnt Availcount Nobufs\n");
tprintf("%#8ld %#8ld %#8ld %#8ld %#8ld\n",
dcbp->rxpackcnt,dcbp->rxnqued,
dcbp->rxbytecnt,dcbp->rxavailcount,dcbp->nobufs);
tprintf("\n"); /* blank line */
tprintf(" Overcnt Abortcnt Crcerrcnt Truncnt\n");
tprintf("%#8ld %#8ld %#8ld %#8ld\n",
dcbp->rxovercnt,dcbp->rxabortcnt,
dcbp->rxcrcerrcnt,dcbp->rxtruncnt);
tprintf("\n"); /* blank line */
switch(dcbp->txstate)
{
case IDLE:
strcpy(tmpstr,"IDLE");
break;
case DEFER:
strcpy(tmpstr,"DEFER");
break;
case TX_ACTIVE:
strcpy(tmpstr,"TX_ACTIVE");
break;
case KEYED_UP:
strcpy(tmpstr,"KEYED_UP");
break;
case CRCING:
strcpy(tmpstr,"CRCING");
break;
case TX_KEYUP_DELAY:
strcpy(tmpstr,"TX_KEYUP_DELAY");
break;
case TX_KEYDOWN_DELAY:
strcpy(tmpstr,"TX_KEYDOWN_DELAY");
break;
case TX_PERSIST:
strcpy(tmpstr,"TX_PERSIST");
break;
case TX_DONE:
strcpy(tmpstr,"TX_DONE");
break;
default:
strcpy(tmpstr,"UNKNOWN STATE");
break;
}
tprintf(" TRANSMITTER STATUS:\n");
tprintf(" Packcnt Bytecnt Underrun Cur_xbufp Cur_xbytes MxFIFO TX STATE\n");
tprintf("%8ld %8ld %8ld %8lx %8d %2.2d ",
dcbp->txpackcnt,dcbp->txbytecnt,
dcbp->txunderun,dcbp->cur_xbufp,
dcbp->cur_xbytes,dcbp->maxtxbytes);
tprintf("%s\n",tmpstr);
tprintf("\n"); /* blank line */
tprintf(" CTSlost: %d\n",dcbp->txctslost);
tprintf("\n"); /* blank line */
tprintf( "WR0 WR1 WR2 WR3 WR4 WR5 WR6 WR7 WR8 WR9 WR10 WR11 WR12 WR13 WR14 WR15");
tprintf(" %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x",
dcbp->wr0,dcbp->wr1,dcbp->wr2,dcbp->wr3,dcbp->wr4,
dcbp->wr5,dcbp->wr6,dcbp->wr7,0,dcbp->wr9,
dcbp->wr10,dcbp->wr11,dcbp->wr12,dcbp->wr13,dcbp->wr14,
dcbp->wr15);
tprintf("\n");
tprintf("\n");
tprintf("Extsts Extreg Hduplex Dma_flg Txclk_extrn Rxclk_extrn Nrzi_flg\n");
tprintf(" %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
dcbp->extsts,dcbp->extreg,dcbp->hduplex,
dcbp->dma_flg,dcbp->txclk_extrn,
dcbp->rxclk_extrn,dcbp->nrzi_flg);
tprintf("\n");
tprintf("Dma_rx_chan Dma_rx_mode Dma_rx_pagereg Dma_rx_cnt_reg Dma_rx_addr_reg\n");
tprintf( " %2.2x %2.2x %2.2x %2.2x %2.2x\n",
dcbp->dma_rx_chan,dcbp->dma_rx_mode,
dcbp->dma_rx_pagereg,dcbp->dma_rx_cnt_reg,
dcbp->dma_rx_addr_reg);
tprintf("Dma_tx_chan Dma_tx_mode Dma_tx_pagereg Dma_tx_cnt_reg Dma_tx_addr_reg\n");
tprintf( " %2.2x %2.2x %2.2x %2.2x %2.2x\n",
dcbp->dma_tx_chan,dcbp->dma_tx_mode,
dcbp->dma_tx_pagereg,dcbp->dma_tx_cnt_reg,
dcbp->dma_tx_addr_reg);
}
else tprintf("Channel %d: is UN-attached!\n",dev);
}
tprintf("\n");
return(0);
}
/* 85230 Mods: Call this routine to enable the Deeper TX fifo... */
/* Do it BEFORE you set up WR7 (sync char), cause it will trash */
/* WR7 if the installed chip is actually an 85c30 or 8530 instead*/
/* of an 85230 */
void
enable_escc(dcbp)
register DCB *dcbp;
{
/* try to enable the escc extended registers */
Twin_write_scc(dcbp->zhwmap.ctl,R15,0x01);
/* Set up the TX FIFO to generate an interrupt as soon */
/* as there is ANY room in the FIFO. Rather than the default */
/* of when the FIFO is empty. */
/* If this is just an SCC, then the R7 will be overwritten */
/* by the real init code later..., but if not, */
/* then this is R7' for FIFO control */
Twin_write_scc(dcbp->zhwmap.ctl,R7,0x00);
/* restore the WR15 to an acceptable value for an 8530 */
Twin_write_scc(dcbp->zhwmap.ctl,R15,0x00);
}