home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3
/
hamradioversion3.0examsandprograms1992.iso
/
misc
/
9q920411
/
pi.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-03
|
42KB
|
1,530 lines
/*
* Interface driver for the VE3IFB 8530 card (PI card)
* Copyright 1990 by Dave Perry, VE3IFB
* Minor delinting - KA9Q 2/2/91
*
* Portions of this driver were derived from the Eagle card
* driver by Art Goldman, WA3CVG. It has been very extensively
* modified from his work, due to the addition of DMA support
* and due to differences in the hardware. The PI card is NOT
* an Eagle card clone. It is an original design by Dave Perry,
* VE3IFB. Art's copyright notice follows:
*
* Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
* Permission for non-commercial use is hereby granted provided this notice
* is retained. For info call: (301) 997-3838.
*
*/
#include <time.h>
#include <stdio.h>
#include <dos.h>
#include <bios.h>
#include "global.h"
#include "mbuf.h"
#include "iface.h"
#include "pktdrvr.h"
#include "netuser.h"
#include "pi.h"
#include "8530.h"
#include "ax25.h"
#include "trace.h"
#include "pc.h"
#include "session.h"
#include "lapb.h"
#include "proc.h"
#include "ip.h"
#include "devparam.h"
#ifndef FP_OFF
#define FP_OFF(fp) ((unsigned)(fp))
#endif
#ifndef FP_SEG
#define FP_SEG(fp) ((unsigned)((unsigned long)(fp) >> 16))
#endif
static void xwrite_scc __ARGS((struct pichan *hp,int16 ctl,int16 reg,
int16 val ));
static char xread_scc __ARGS((struct pichan *hp, int16 ctl, char reg));
static int32 pi_ctl __ARGS((struct iface *iface,int cmd,int set,int32 val));
static int pi_raw __ARGS((struct iface *iface,struct mbuf *bp));
static int pi_stop __ARGS((struct iface *iface));
static void rts __ARGS((struct pichan *hp, int16 x));
void setup_rx_dma __ARGS((struct pichan *hp));
void setup_tx_dma __ARGS((struct pichan *hp, char *buffer, int length));
static void set_acc_delay __ARGS((void));
static void tdelay __ARGS((register struct pichan *hp,unsigned int time));
static struct PITAB Pi[PIMAX]; /* Device table - one entry per card */
static INTERRUPT (*pihandle[])() = { /* handler interrupt vector table */
pi0vec,
pi1vec,
pi2vec
};
static int16 Page_regs[] = {
0x87,0x83,0x81,0x82,0,0x8b,0x89,0x8a
};
static struct pichan Pichan[2*PIMAX]; /* channel table - 2 entries per card */
static int16 pinbr;
extern int16 acc_delay; /* Delay for the 8530 chip access recovery time */
/* Allocate a buffer which does not cross a dma page boundary */
/* This really belongs in mbuf.c */
struct mbuf *
alloc_dmabuf(size)
register int16 size;
{
struct mbuf *bp[20],*retbuf;
unsigned buf_offset, buf_segment;
long longseg, dma_abs, dma_page;
int n;
for(n = 0; n < 20 ;n++){
if((bp[n] = alloc_mbuf(size)) == NULLBUF){
/* Free the buffers which failed the test */
while(--n >= 0)
free_p(bp[n]);
return(NULLBUF);
}
/* Calculate the DMA page */
buf_offset = FP_OFF(bp[n]);
buf_segment= FP_SEG(bp[n]);
longseg = (long) buf_segment;
dma_abs = (longseg << 4) + (long) buf_offset;
dma_page = dma_abs >> 16;
if(((dma_abs+size) >> 16) == dma_page){
/* Save the one that passed */
retbuf = bp[n];
/* Free the buffers which failed the test */
while(--n >= 0)
free_p(bp[n]);
return(retbuf);
}
}
/* Free the buffers which failed the test */
while(--n >= 0)
free_p(bp[n]);
return(NULLBUF);
}
/* This calculates the constant to be used in the delay loops
* which satify the SCC's access recovery time. It needs to be timed and
* calculated because a fixed value would not work in a 4.77mhz XT
* to a 40mhz 486 (and beyond).
*/
static void
set_acc_delay()
{
long starttime, endtime;
int n;
int ticks;
starttime = bioscnt();
for(n = 0; n < 10; n++)
mloop();
endtime = bioscnt();
ticks = (int) (endtime - starttime);
if(ticks == 0)
ticks = 1;
acc_delay = 61/ticks;
if(acc_delay == 0)
acc_delay = 1;
fflush(stdout);
}
/* Write 8530 register */
static void
xwrite_scc(hp,ctl,reg,val)
register struct pichan *hp;
register int16 ctl;
int16 reg,val;
{
wrtscc(hp->cardbase,ctl,reg,val);
}
/* Read 8530 register */
static char
xread_scc(hp,ctl,reg)
register struct pichan *hp;
register int16 ctl;
char reg;
{
return(rdscc(hp->cardbase,ctl,reg));
}
/* Setup 8253 chip for time delay */
static void
tdelay(hp,time)
register struct pichan *hp;
unsigned int time; /* Time to delay in milliseconds */
{
int n,port;
unsigned int t1;
unsigned char sc;
if(hp->base & 2){ /* If A channel */
sc = SC1;
t1 = time;
port = hp->cardbase+TMR1;
} else {
sc = SC2;
t1 = 10 * time; /* 10s of milliseconds for the B channel */
port = hp->cardbase+TMR2;
}
/* Setup timer sc */
outportb(hp->cardbase+TMRCMD, sc|LSB_MSB|MODE0);
/* satisfy access time restriction */
for(n=0; n<5;n++)
;
/* times 2 to make millisecs */
outportb(port, (t1 << 1) & 0xFF);
/* satisfy access time restriction */
for(n=0; n<5;n++)
;
outportb(port, (t1 >> 7) & 0xFF);
/* Enable correct int for timeout */
xwrite_scc(hp,hp->base+CTL,R15,CTSIE);
xwrite_scc(hp,hp->base+CTL,R1,EXT_INT_ENAB);
xwrite_scc(hp,hp->base+CTL,R0,RES_EXT_INT);
}
/* Master interrupt handler. One interrupt at a time is handled.
* here. Service routines are called from here.
*/
INTERRUPT (far *(piint)(dev))()
int dev;
{
register char st;
register int16 pcbase;
struct pichan *hp;
struct PITAB *pip;
void b_rxint(),b_txint(),b_exint();
void a_rxint(),a_txint(),a_exint();
pip = &Pi[dev];
pip->ints++;
pcbase = pip->addr;
/* Read interrupt status register (only valid from channel A)
* Process all pending interrupts in while loop
*/
hp = &Pichan[2 * dev]; /* Assume channel A */
while((st = xread_scc(hp,pcbase+CHANA+CTL,R3)) != 0){
if(st & CHARxIP){
/* Channel A Rcv Interrupt Pending */
hp = &Pichan[2 * dev];
a_rxint(hp);
} else if(st & CHATxIP){
/* Channel A Transmit Int Pending */
hp = &Pichan[2 * dev];
a_txint(hp);
} else if(st & CHAEXT){
/* Channel A External Status Int */
hp = &Pichan[2 * dev];
a_exint(hp);
} else if(st & CHBRxIP){
/* Channel B Rcv Interrupt Pending */
hp = &Pichan[(2 * dev)+1];
b_rxint(hp);
} else if(st & CHBTxIP){
/* Channel B Transmit Int Pending */
hp = &Pichan[(2 * dev)+1];
b_txint(hp);
} else if(st & CHBEXT){
/* Channel B External Status Int */
hp = &Pichan[(2 * dev)+1];
b_exint(hp);
}
/* Reset highest interrupt under service */
xwrite_scc(hp,hp->base+CTL,R0,RES_H_IUS);
} /* End of while loop on int processing */
return pip->chain ? pip->oldvec : NULL;
}
static void
a_exint(hp)
register struct pichan *hp;
{
register int16 cmd;
char st, i_state;
int length;
int32 t,ca;
i_state = dirps(); /* disable interrupts */
st = xread_scc(hp,hp->base+CTL,R0); /* Fetch status */
/* reset external status latch */
xwrite_scc(hp,CTL+hp->base,R0,RES_EXT_INT);
cmd = hp->base+CTL;
hp->exints++;
if((hp->rstate >= ACTIVE) && (st & BRK_ABRT)){
setup_rx_dma(hp);
hp->rstate = ACTIVE;
}
switch(hp->tstate){
case ACTIVE:
free_p(hp->sndbuf);
hp->sndbuf = NULLBUF;
hp->tstate = FLAGOUT;
tdelay(hp,hp->squeldelay);
break;
case FLAGOUT:
if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
/* Nothing to send - return to receive mode */
hp->tstate = IDLE;
rts(hp,OFF);
restore(i_state);
return;
}
/* NOTE - fall through if more to send */
case ST_TXDELAY:
/* Disable DMA chan */
outportb(DMA_MASK, DMA_DISABLE|hp->dmachan);
/* Set up for TX dma */
xwrite_scc(hp,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);
/* Get all chars */
length = pullup(&hp->sndbuf,hp->txdmabuf,hp->bufsiz);
/* Setup DMA controller for tx */
setup_tx_dma(hp,hp->txdmabuf,length);
/* select transmit interrupts to enable */
/* Allow DMA on chan */
outportb(DMA_MASK,DMA_ENABLE|hp->dmachan);
/* reset CRC, Txint pend*/
xwrite_scc(hp,cmd,R0,RES_Tx_CRC|RES_Tx_P);
/* allow Underrun int only */
xwrite_scc(hp,cmd,R15,TxUIE);
/* Enable TX DMA */
xwrite_scc(hp,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|EXT_INT_ENAB);
/* Send CRC on underrun */
xwrite_scc(hp,cmd,R0,RES_EOM_L);
/* packet going out now */
hp->tstate = ACTIVE;
break;
case DEFER:
/* we have deferred prev xmit attempt
* See Intel Microcommunications Handbook, p2-308
*/
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
if((xread_scc(hp,cmd,R0) & DCD) != 0){
hp->tstate = DEFER;
tdelay(hp,100);
/* Defer until dcd transition or 100mS timeout */
xwrite_scc(hp,CTL+hp->base,R15,CTSIE|DCDIE);
restore(i_state);
return;
}
/* Defer logic. Wait until deftime is in the past (so we
* defer to any overheard CTS messages) AND the p-persistence
* dice roll succeeds. The computation of ca allows for clock
* rollover (which happens every 49+ days).
*/
t = msclock();
ca = hp->deftime - t;
if(ca > 0){
hp->tstate = DEFER;
tdelay(hp,ca);
restore(i_state);
return;
}
hp->deftime = t; /* Keep from getting too old */
if((rand() & 0xff) > uchar(hp->persist)){
hp->tstate = DEFER;
tdelay(hp,hp->slotime);
restore(i_state);
return;
}
/* Assert RTS early minimize collision window */
xwrite_scc(hp,cmd,R5,TxCRC_ENAB|RTS|Tx8);
rts(hp,ON); /* Transmitter on */
hp->tstate = ST_TXDELAY;
tdelay(hp,hp->txdelay);
restore(i_state);
return;
} /* switch(hp->tstate) */
restore(i_state);
} /* a_exint() */
/* Receive interrupt handler for the A channel
*/
static void
a_rxint(hp)
register struct pichan *hp;
{
register int16 cmd;
register int16 bytecount;
char rse, i_state;
i_state = dirps(); /* disable interrupts */
hp->rxints++;
cmd = hp->base+CTL;
rse = xread_scc(hp,cmd,R1); /* Get special condition bits from R1 */
if(rse & Rx_OVR){
/* If receiver overrun */
hp->rovers++;
hp->rstate = RXERROR;
}
if(rse & END_FR){
/* If end of frame */
/* figure length of frame from 8237 */
outportb(DMA_RESETFF,0); /* reset firstlast ff */
bytecount = inportb(hp->dma_wcr);
bytecount += inportb(hp->dma_wcr) << 8;
/* Allow for the extra space for phdr */
bytecount = (hp->bufsiz - 1 - sizeof(struct phdr)) - bytecount;
if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(bytecount < 10)){
if((bytecount >= 10) && (rse & CRC_ERR))
hp->crcerr++; /* Ignore noise */
/* Reset buffer pointers */
hp->rstate = ACTIVE;
setup_rx_dma(hp);
} else {
/* Here we have a valid frame */
/* Toss 2 crc bytes */
hp->rcvbuf->cnt = bytecount - 2;
/* "Can't fail" */
net_route(hp->iface,CL_AX25,hp->rcvbuf);
hp->rcvbuf = NULLBUF;
hp->rxframes++;
/* packet queued - get buffer for next frame */
hp->rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct phdr));
if(hp->rcvbuf != NULLBUF)
/* Allow room for phdr */
hp->rcvbuf->data += sizeof(struct phdr);
setup_rx_dma(hp);
} /* end good frame queued */
} /* end EOF check */
xwrite_scc(hp,hp->base+CTL,R0,ERR_RES); /* error reset */
restore(i_state);
}
void
a_txint(hp)
register struct pichan *hp;
{
register int16 cmd;
char i_state;
int32 t,ca;
i_state = dirps();
cmd = CTL+hp->base;
switch(hp->tstate){
case IDLE:
/* Transmitter idle. Find a frame for transmission */
if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
rts(hp,OFF);
restore(i_state);
return;
}
/* If a buffer to send, we drop thru here */
case DEFER:
/* we may have deferred prev xmit attempt */
/* Check DCD - debounce it
* See Intel Microcommunications Handbook, p2-308
*/
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
if((xread_scc(hp,cmd,R0) & DCD) != 0){
hp->tstate = DEFER;
tdelay(hp,100);
/* defer until DCD transition or timeout */
xwrite_scc(hp,cmd,R15,CTSIE|DCDIE);
restore(i_state);
return;
}
/* Defer logic. Wait until deftime is in the past (so we
* defer to any overheard CTS messages) AND the p-persistence
* dice roll succeeds. The computation of ca allows for clock
* rollover (which happens every 49+ days).
*/
t = msclock();
ca = hp->deftime - t;
if(ca > 0){
hp->tstate = DEFER;
tdelay(hp,ca);
restore(i_state);
return;
}
hp->deftime = t; /* Keep from getting too old */
if((rand() & 0xff) > uchar(hp->persist)){
hp->tstate = DEFER;
tdelay(hp,hp->slotime);
restore(i_state);
return;
}
/* Assert RTS early minimize collision window */
xwrite_scc(hp,cmd,R5,TxCRC_ENAB|RTS|Tx8);
rts(hp,ON); /* Transmitter on */
hp->tstate = ST_TXDELAY;
tdelay(hp,hp->txdelay);
restore(i_state);
return;
default:
break;
} /* end switch(hp->state) */
restore(i_state);
} /*a_txint */
static void
b_rxint(hp)
register struct pichan *hp;
{
register int16 cmd;
char rse, i_state;
i_state = dirps(); /* disable interrupts */
hp->rxints++;
cmd = CTL+hp->base;
if((xread_scc(hp,cmd,R0)) & Rx_CH_AV){
/* there is a char to be stored
* read special condition bits before reading the data char
*/
rse = xread_scc(hp,cmd,R1); /* get status byte from R1 */
if(rse & Rx_OVR){
/* Rx overrun - toss buffer */
/* reset buffer pointers */
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0;
hp->rstate = RXERROR; /* set error flag */
hp->rovers++;
} else if(hp->rcvbuf->cnt >= hp->bufsiz - sizeof(struct phdr)){
/* Too large -- toss buffer */
/* reset buffer pointers */
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0;
hp->rstate = TOOBIG; /* when set, chars are not stored */
}
/* ok, we can store the received character now */
if(hp->rstate == ACTIVE){ /* If no errors... */
*hp->rcp++ = xread_scc(hp,cmd,R8); /* char to rcv buff */
hp->rcvbuf->cnt++; /* bump count */
} else {
/* got to empty FIFO */
(void) xread_scc(hp,cmd,R8);
xwrite_scc(hp,cmd,R0,ERR_RES); /* reset err latch */
hp->rstate = ACTIVE;
}
}
if(rse & END_FR){
/* END OF FRAME -- Make sure Rx was active */
if(hp->rcvbuf->cnt > 0){
if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(hp->rcvbuf->cnt < 10)){
if((hp->rcvbuf->cnt >= 10) && (rse & CRC_ERR))
hp->crcerr++; /* Ignore noise */
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0;
} else {
/* Here we have a valid frame */
hp->rcvbuf->cnt -= 2; /* Toss 2 crc bytes */
/* "Can't fail" */
net_route(hp->iface,CL_AX25,hp->rcvbuf);
hp->rxframes++;
/* packet queued - get buffer for next frame */
hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
if(hp->rcvbuf == NULLBUF){
/* No memory - abort rx */
xwrite_scc(hp,cmd,R3,Rx8);
restore(i_state);
return;
}
hp->rcvbuf->data += sizeof(struct phdr);
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0;
} /* end good frame queued */
} /* end check for active receive upon EOF */
hp->rstate = ACTIVE; /* and clear error status */
} /* end EOF check */
restore(i_state);
}
static void
b_txint(hp)
register struct pichan *hp;
{
register int16 cmd;
char i_state,c;
i_state = dirps();
cmd = CTL+hp->base;
if(hp->tstate != DEFER && hp->tstate)
hp->txints++;
switch(hp->tstate){
case CRCOUT:
hp->tstate = FLAGOUT;
tdelay(hp,hp->squeldelay);
restore(i_state);
return;
case IDLE:
/* Transmitter idle. Find a frame for transmission */
if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
/* Nothing to send - return to receive mode
* Tx OFF now - flag should have gone
*/
rts(hp,OFF);
restore(i_state);
return;
}
/* If a buffer to send, we drop thru here */
case DEFER: /* we may have deferred prev xmit attempt */
/* Check DCD - debounce it */
/* See Intel Microcommunications Handbook, p2-308 */
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
if((xread_scc(hp,cmd,R0) & DCD) != 0){
hp->tstate = DEFER;
tdelay(hp,100);
/* defer until DCD transition or timeout */
xwrite_scc(hp,cmd,R15,CTSIE|DCDIE);
restore(i_state);
return;
}
/* p - persist calculation */
if(inportb(hp->cardbase+TMR0) > hp->persist){
inportb(hp->cardbase+TMR0); /* Discard MSB */
hp->tstate = DEFER;
tdelay(hp,hp->slotime);
restore(i_state);
return;
}
inportb(hp->cardbase+TMR0); /* Discard MSB */
rts(hp,ON); /* Transmitter on */
hp->tstate = ST_TXDELAY;
tdelay(hp,hp->txdelay);
restore(i_state);
return;
case ACTIVE:
/* Here we are actively sending a frame */
if((c = PULLCHAR(&hp->sndbuf)) != -1){
/* next char is gone */
xwrite_scc(hp,cmd,R8,c);
/* stuffing a char satisfies Interrupt condition */
} else {
/* No more to send */
free_p(hp->sndbuf);
if((xread_scc(hp,cmd,R0) & 0x40)){
/* Did we underrun? */
/* unexpected underrun */
hp->tunders++;
xwrite_scc(hp,cmd,R0,SEND_ABORT);
hp->tstate = FLAGOUT;
tdelay(hp,hp->squeldelay);
restore(i_state);
return;
}
hp->tstate = UNDERRUN; /* Now we expect to underrun */
/* Send flags on underrun */
if(hp->speed){ /* If externally clocked */
xwrite_scc(hp,cmd,R10,CRCPS|NRZI);
} else {
xwrite_scc(hp,cmd,R10,CRCPS);
}
xwrite_scc(hp,cmd,R0,RES_Tx_P); /* reset Tx Int Pend */
}
restore(i_state);
return; /* back to wait for interrupt */
} /* end switch */
restore(i_state);
}
/* Pi SIO External/Status interrupts (for the B channel)
* This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
* Receiver automatically goes to Hunt on an abort.
*
* If the Tx Underrun interrupt hits, change state and
* issue a reset command for it, and return.
*/
static void
b_exint(hp)
register struct pichan *hp;
{
char st, i_state;
register int16 cmd;
char c;
cmd = CTL+hp->base;
i_state = dirps(); /* disable interrupts */
hp->exints++;
st = xread_scc(hp,cmd,R0); /* Fetch status */
/* reset external status latch */
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
switch(hp->tstate){
case ACTIVE: /* Unexpected underrun */
free_p(hp->sndbuf);
xwrite_scc(hp,cmd,R0,SEND_ABORT);
hp->tstate = FLAGOUT;
hp->tunders++;
tdelay(hp,hp->squeldelay);
restore(i_state);
return;
case UNDERRUN:
hp->tstate = CRCOUT;
restore(i_state);
return;
case FLAGOUT:
/* Find a frame for transmission */
if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
/* Nothing to send - return to receive mode
* Tx OFF now - flag should have gone
*/
rts(hp,OFF);
hp->tstate = IDLE;
restore(i_state);
return;
}
/* Get next char to send */
pullup(&hp->sndbuf,&c,1); /* one char at a time */
xwrite_scc(hp,cmd,R0,RES_Tx_CRC);/* reset for next frame */
/* Send abort on underrun */
if(hp->speed){ /* If externally clocked */
xwrite_scc(hp,cmd,R10,CRCPS|NRZI|ABUNDER);
} else {
xwrite_scc(hp,cmd,R10,CRCPS|ABUNDER);
}
xwrite_scc(hp,cmd,R8,c); /* First char out now */
xwrite_scc(hp,cmd,R0,RES_EOM_L);/* Reset end of message latch */
/* select transmit interrupts to enable */
xwrite_scc(hp,cmd,R15,TxUIE); /* allow Underrun int only */
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
xwrite_scc(hp,cmd,R1,TxINT_ENAB|EXT_INT_ENAB); /* Tx/Extern ints on */
hp->tstate = ACTIVE; /* char going out now */
restore(i_state);
return;
case DEFER:
/* Check DCD - debounce it
* See Intel Microcommunications Handbook, p2-308
*/
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
if((xread_scc(hp,cmd,R0) & DCD) != 0){
hp->tstate = DEFER;
tdelay(hp,100);
/* defer until DCD transition or timeout */
xwrite_scc(hp,cmd,R15,CTSIE|DCDIE);
restore(i_state);
return;
}
/* p - persist calculation */
if(inportb(hp->cardbase+TMR0) > hp->persist){
inportb(hp->cardbase+TMR0); /* Discard MSB */
hp->tstate = DEFER;
tdelay(hp,hp->slotime);
restore(i_state);
return;
}
inportb(hp->cardbase+TMR0); /* Discard MSB */
rts(hp,ON); /* Transmitter on */
hp->tstate = ST_TXDELAY;
tdelay(hp,hp->txdelay);
restore(i_state);
return;
case ST_TXDELAY:
/* Get next char to send */
pullup(&hp->sndbuf,&c,1); /* one char at a time */
xwrite_scc(hp,cmd,R0,RES_Tx_CRC);/* reset for next frame */
/* Send abort on underrun */
if(hp->speed){ /* If externally clocked */
xwrite_scc(hp,cmd,R10,CRCPS|NRZI|ABUNDER);
} else {
xwrite_scc(hp,cmd,R10,CRCPS|ABUNDER);
}
xwrite_scc(hp,cmd,R8,c); /* First char out now */
xwrite_scc(hp,cmd,R0,RES_EOM_L);/* Reset end of message latch */
/* select transmit interrupts to enable */
xwrite_scc(hp,cmd,R15,TxUIE); /* allow Underrun int only */
xwrite_scc(hp,cmd,R0,RES_EXT_INT);
/* Tx/Extern ints on */
xwrite_scc(hp,cmd,R1,TxINT_ENAB|EXT_INT_ENAB);
hp->tstate = ACTIVE; /* char going out now */
restore(i_state);
return;
}
/* Receive Mode only
* This triggers when hunt mode is entered, & since an ABORT
* automatically enters hunt mode, we use that to clean up
* any waiting garbage
*/
if((hp->rstate == ACTIVE) && (st & BRK_ABRT)){
(void) xread_scc(hp,cmd,R8);
(void) xread_scc(hp,cmd,R8);
(void) xread_scc(hp,cmd,R8);
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0; /* rewind on DCD transition */
}
restore(i_state);
}
/* SET Transmit or Receive Mode
* Set RTS (request-to-send) to modem on Transmit
*/
static void
rts(hp,x)
register struct pichan *hp;
int16 x;
{
int16 tc;
long br;
int16 cmd;
cmd = CTL+hp->base;
/* Reprogram BRG and turn on transmitter to send flags */
if(x == ON){ /* Turn Tx ON and Receive OFF */
/* Exints off first to avoid abort int */
xwrite_scc(hp,cmd,R15,0);
xwrite_scc(hp,cmd,R3,Rx8); /* Rx off */
hp->rstate = IDLE;
if(cmd & 2){ /* if channel a */
/* Set up for TX dma */
xwrite_scc(hp,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);
} else {
xwrite_scc(hp,cmd,R1,0); /* No interrupts */
}
if(hp->speed){ /* if internally clocked */
br = hp->speed; /* get desired speed */
tc = (XTAL/br)-2; /* calc 1X BRG divisor */
xwrite_scc(hp,cmd,R12,tc&0xFF); /* lower byte */
xwrite_scc(hp,cmd,R13,(tc>>8)&0xFF);/* upper byte */
}
xwrite_scc(hp,cmd,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);
/* Transmitter now on */
} else { /* Tx OFF and Rx ON */
hp->tstate = IDLE;
xwrite_scc(hp,cmd,R5,Tx8|DTR); /* TX off */
if(hp->speed){ /* if internally clocked */
/* Reprogram BRG for 32x clock for receive DPLL */
/* BRG off, keep Pclk source */
xwrite_scc(hp,cmd,R14,BRSRC);
br = hp->speed; /* get desired speed */
/* calc 32X BRG divisor */
tc = ((XTAL/32)/br)-2;
xwrite_scc(hp,cmd,R12,tc&0xFF); /* lower byte */
xwrite_scc(hp,cmd,R13,(tc>>8)&0xFF);/* upper byte */
/* SEARCH mode, BRG source */
xwrite_scc(hp,cmd,R14,BRSRC|SEARCH);
/* Enable the BRG */
xwrite_scc(hp,cmd,R14,BRSRC|BRENABL);
}
/* Now, turn on the receiver and hunt for a flag */
xwrite_scc(hp,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
hp->rstate = ACTIVE; /* Normal state */
if(cmd & 2){/* if channel a */
setup_rx_dma(hp);
} else {
/* reset error bits */
/* xwrite_scc(hp,cmd,R0,ERR_RES); */
/* reset buffer pointers */
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0;
xwrite_scc(hp,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
}
xwrite_scc(hp,cmd,R15,BRKIE); /* allow ABORT int */
/* Hold tx off long enough for other station to reply */
hp->deftime = msclock() + hp->txdelay + 500;
}
}
void
setup_rx_dma(hp)
register struct pichan *hp;
{
unsigned buf_offset, buf_segment;
int cmd;
long longseg, dma_abs, dma_page;
char i_state;
i_state = dirps(); /* disable interrupts */
cmd = hp->base+CTL;
if(!hp->rcvbuf){
/* No rx buffer available */
restore(i_state);
return;
}
/* Calculate high order 4 bits of the buffer area and store
* them in the DMA page register
*/
buf_offset = FP_OFF(hp->rcvbuf->data);
buf_segment= FP_SEG(hp->rcvbuf->data);
longseg = (long) buf_segment;
dma_abs = (longseg << 4) + (long) buf_offset;
dma_page = dma_abs >> 16;
if(((dma_abs + hp->bufsiz -1) >> 16) != dma_page)
tprintf("PI: ERROR - RX DMA page boundary violation\n");
/* Get ready for RX DMA */
xwrite_scc(hp,cmd,R1,WT_FN_RDYFN|WT_RDY_RT|INT_ERR_Rx|EXT_INT_ENAB);
outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
/* Set DMA mode register to single transfers, incrementing address,
* auto init, writes
*/
outportb(DMA_MODE,DMA_RX_MODE|hp->dmachan);
outportb(hp->page_addr,dma_page);/* Store in 64K DMA page */
outportb(DMA_RESETFF,0); /* reset byte pointer flipflop */
/* Output buffer start (dest) address */
outportb(hp->dma_dest,dma_abs);
outportb(hp->dma_dest,dma_abs >> 8);
/* output DMA maximum byte count */
outportb(hp->dma_wcr,hp->bufsiz - 1 - sizeof(struct phdr));
outportb(hp->dma_wcr, (hp->bufsiz - 1 - sizeof(struct phdr)) >> 8);
/* Unmask channel 1 (start DMA) */
outportb(DMA_MASK, DMA_ENABLE|hp->dmachan); /* Enable DMA chan */
/* If a packet is already coming in, this line is supposed
* to mess up the crc to avoid receiving a partial packet
*/
xwrite_scc(hp,cmd,R0,RES_Rx_CRC);
/* Enable RX dma */
xwrite_scc(hp,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|WT_RDY_RT|INT_ERR_Rx|EXT_INT_ENAB);
restore(i_state);
}
void
setup_tx_dma(hp,buffer,length)
struct pichan *hp;
char *buffer;
int length;
{
unsigned buf_offset, buf_segment;
long longseg, dma_abs, dma_page;
char i_state;
i_state = dirps(); /* disable interrupts */
/* Calculate high order 4 bits of the buffer area and store
* them in the DMA page register
*/
buf_offset = FP_OFF(buffer);
buf_segment= FP_SEG(buffer);
longseg = (long) buf_segment;
dma_abs = (longseg << 4) + (long) buf_offset;
dma_page = dma_abs >> 16;
outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
if(((dma_abs + length) >> 16) != dma_page)
tprintf("PI: ERROR - TX DMA page boundary violation\n");
--length; /* Adjust length for DMA chip */
/* Set DMA mode register to single transfers, incrementing address,
* no auto init, reads
*/
outportb(DMA_MODE,DMA_TX_MODE|hp->dmachan);
outportb(hp->page_addr,dma_page); /* Store in 64K DMA page */
outportb(DMA_RESETFF,0); /* reset byte pointer flipflop */
outportb(hp->dma_dest,dma_abs); /* Output buffer start (source) address */
outportb(hp->dma_dest,dma_abs >> 8);
/* output byte count */
outportb(hp->dma_wcr,length);
outportb(hp->dma_wcr, (length) >> 8);
restore(i_state);
}
/* Initialize pi controller parameters */
static int
scc_init(hp)
register struct pichan *hp;
{
int16 tc;
long br;
char i_state;
register int16 cmd;
/* Initialize 8530 channel for SDLC operation */
cmd = CTL+hp->base;
#ifdef notdef
tprintf("Pi: Initializing Channel %c - Base = %x\n",cmd&2?'A':'B',cmd&~CTL);
#endif
i_state = dirps();
switch(cmd & 2){
case 2:
xwrite_scc(hp,cmd,R9,CHRA); /* Reset channel A */
xwrite_scc(hp,cmd,R2,0xff); /* Initialize interrupt vector */
break;
case 0:
xwrite_scc(hp,cmd,R9,CHRB); /* Reset channel B */
break;
}
/* Deselect all Rx and Tx interrupts */
xwrite_scc(hp,cmd,R1,0);
/* Turn off external interrupts (like CTS/CD) */
xwrite_scc(hp,cmd,R15,0);
/* X1 clock, SDLC mode */
xwrite_scc(hp,cmd,R4,SDLC|X1CLK);
/* Now some misc Tx/Rx parameters */
/* CRC PRESET 1, NRZI Mode */
if(hp->speed){
xwrite_scc(hp,cmd,R10,CRCPS|NRZI);
/* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
xwrite_scc(hp,cmd,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
} else {
xwrite_scc(hp,cmd,R10,CRCPS);
/* Tx Clk from Trxcl. Rcv Clk from Rtxcl, TRxC pin is input */
xwrite_scc(hp,cmd,R11,TCTRxCP);
}
/* Null out SDLC start address */
xwrite_scc(hp,cmd,R6,0);
/* SDLC flag */
xwrite_scc(hp,cmd,R7,FLAG);
/* Set up the Transmitter but don't enable it
* DTR, 8 bit TX chars only - TX NOT ENABLED
*/
xwrite_scc(hp,cmd,R5,Tx8|DTR);
/* Receiver - intial setup only - more later */
xwrite_scc(hp,cmd,R3,Rx8); /* 8 bits/char */
/* Setting up BRG now - turn it off first */
xwrite_scc(hp,cmd,R14,BRSRC); /* BRG off, but keep Pclk source */
/* set the 32x time constant for the BRG in Receive mode */
if(hp->speed){
br = hp->speed; /* get desired speed */
tc = ((XTAL/32)/br)-2; /* calc 32X BRG divisor */
} else {
tc = 14;
}
xwrite_scc(hp,cmd,R12,tc&0xFF); /* lower byte */
xwrite_scc(hp,cmd,R13,(tc>>8)&0xFF); /* upper byte */
/* Following subroutine sets up and ENABLES the receiver */
rts(hp,OFF); /* TX OFF and RX ON */
if(hp->speed){
/* DPLL frm BRG, BRG src PCLK */
xwrite_scc(hp,cmd,R14,BRSRC|SSBR);
} else {
/* DPLL frm rtxc,BRG src PCLK */
xwrite_scc(hp,cmd,R14,BRSRC|SSRTxC);
}
xwrite_scc(hp,cmd,R14,BRSRC|SEARCH); /* SEARCH mode, keep BRG source */
xwrite_scc(hp,cmd,R14,BRSRC|BRENABL);/* Enable the BRG */
if(!(cmd & 2)) /* if channel b */
xwrite_scc(hp,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
xwrite_scc(hp,cmd,R15,BRKIE); /* ABORT int */
/* Now, turn on the receiver and hunt for a flag */
xwrite_scc(hp,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
restore(i_state);
return 0;
}
/* Process to recover from ibuffails.
* This could be done in the function network() in config.c,
* to save a context switch. I put it here so the driver would
* be more self contained.
*/
void
buf_recover(unused,b,a)
int unused;
void *b; /* Unused */
void *a; /* Unused */
{
struct pichan *hp0, *hp1;
char i_state;
int i;
for(;;){
pwait(NULL);
for(i=0; i<pinbr; i++){ /* for each card */
hp0 = &Pichan[i];
hp1 = &Pichan[i + 1];
if(!hp0->rcvbuf){ /* No rx buffer allocated */
i_state = dirps();
hp0->rcvbuf = alloc_mbuf(hp0->bufsiz + sizeof(struct phdr));
if(hp0->rcvbuf != NULLBUF)
hp0->rcvbuf->data += sizeof(struct phdr);
restore(i_state);
setup_rx_dma(hp0);
}
i_state = dirps();
if(!hp1->rcvbuf && (hp1->rstate == ACTIVE)){
/* No rx buf allocated */
if((hp1->rcvbuf = alloc_mbuf(hp1->bufsiz+sizeof(struct phdr))) != NULL){
hp1->rcvbuf->data += sizeof(struct phdr);
hp1->rcp = hp1->rcvbuf->data;
hp1->rcvbuf->cnt = 0;
xwrite_scc(hp1,CTL+hp1->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
}
}
restore(i_state);
}
}
}
/* Attach a PI interface to the system
* argv[0]: hardware type, must be "pi"
* argv[1]: I/O address, e.g., "0x300"
* argv[2]: vector, e.g., "2"
* argv[3]: dma channel (1..3)
* argv[4]: mode, must be:
* "ax25" (AX.25 UI frame format)
* argv[5]: interface label, e.g., "pi0"
* argv[6]: receiver packet buffer size in bytes
* argv[7]: maximum transmission unit, bytes
* argv[8]: channel A interface speed, e.g, "1200", 0 = ext. clock
* argv[9]: channel B interface speed
* argv[10]: First IP address, optional (defaults to Ip_addr);
* argv[11]: Second IP address, optional (defaults to Ip_addr);
*/
int
pi_attach(argc,argv)
int argc;
char *argv[];
{
struct mbuf *bp;
extern void refiq();
register struct iface *if_pca,*if_pcb;
struct pichan *hp;
int dev;
char i_state;
int n;
refiq(); /* replenish interrupt buffer pool (in mbuf.c) */
if(acc_delay == 0){ /* Only do this once */
/* Adapt recovery time delay to processor speed */
set_acc_delay();
}
/* Quick check to make sure args are good and mycall is set */
if(strcmp(argv[4],"ax25") != 0){
tprintf("PI: Mode %s unknown for interface %s\n",
argv[4],argv[5]);
return -1;
}
if(if_lookup(argv[5]) != NULLIF){
tprintf("PI: Interface %s already exists\n",argv[5]);
return -1;
}
if(Mycall[0] == '\0'){
tprintf("PI: Set mycall first\n");
return -1;
}
/* Note: each card must have a unique address, IRQ and DMA */
if(pinbr >= PIMAX){
tprintf("PI: Maximum of %d PI cards supported\n",PIMAX);
return -1;
}
dev = pinbr++;
/* Initialize hardware-level control structure */
Pi[dev].addr = htoi(argv[1]);
Pi[dev].vec = atoi(argv[2]);
if(strchr(argv[2],'c') != NULLCHAR)
Pi[dev].chain = 1;
else
Pi[dev].chain = 0;
/* Set up counter chip */
/* 500 uS square wave */
outportb(Pi[dev].addr+TMRCMD, SC0|LSB_MSB|MODE3);
for(n=0; n<5;n++) /* satisfy access time restriction */
;
outportb(Pi[dev].addr+TMR0, 922 & 0xFF);
for(n=0; n<5;n++) /* satisfy access time restriction */
;
outportb(Pi[dev].addr+TMR0, 922 >> 8);
for(n=0; n<5;n++) /* satisfy access time restriction */
;
/* Save original interrupt vector */
Pi[dev].oldvec = getirq(Pi[dev].vec);
/* Set new interrupt vector */
if(setirq(Pi[dev].vec,pihandle[dev]) == -1){
tprintf("PI: IRQ %u out of range\n",Pi[dev].vec);
pinbr--;
return -1;
}
if((atoi(argv[3]) < 1) || (atoi(argv[3]) > 3)){
tprintf("PI: DMA %d out of range\n",atoi(argv[3]));
pinbr--;
return -1;
}
/* Create interface structures and fill in details */
if_pca = (struct iface *)callocw(1,sizeof(struct iface));
if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
if_pca->addr = if_pcb->addr = Ip_addr;
if(argc > 10)
if_pca->addr = resolve(argv[10]);
if(argc > 11)
if_pcb->addr = resolve(argv[11]);
if(if_pca->addr == 0 || if_pcb->addr == 0){
tprintf("PI: No IP address");
free((char *)if_pca);
free((char *)if_pcb);
return -1;
}
/* Append "a" to interface associated with A channel */
if_pca->name = malloc((unsigned)strlen(argv[5])+2);
strcpy(if_pca->name,argv[5]);
strcat(if_pca->name,"a");
/* Append "b" to interface associated with B channel */
if_pcb->name = malloc((unsigned)strlen(argv[5])+2);
strcpy(if_pcb->name,argv[5]);
strcat(if_pcb->name,"b");
if_pcb->mtu = if_pca->mtu = atoi(argv[7]);
if_pcb->type = if_pca->type = CL_AX25;
if_pcb->ioctl = if_pca->ioctl = pi_ctl;
if_pca->dev = 2*dev; /* pi0a */
if_pcb->dev = 2*dev + 1; /* pi0b */
if_pcb->stop = if_pca->stop = pi_stop;
if_pcb->output = if_pca->output = ax_output;
if_pcb->raw = if_pca->raw = pi_raw;
if(strcmp(argv[4],"ax25") == 0){
/* Must be true, was checked at top */
if(if_pcb->hwaddr == NULLCHAR)
if_pcb->hwaddr = mallocw(AXALEN);
memcpy(if_pcb->hwaddr,Mycall,AXALEN);
if(if_pca->hwaddr == NULLCHAR)
if_pca->hwaddr = mallocw(AXALEN);
memcpy(if_pca->hwaddr,Mycall,AXALEN);
}
/* Link em in to the interface chain */
if_pca->next = if_pcb;
if_pcb->next = Ifaces;
Ifaces = if_pca;
/* set params in pichan table for CHANNEL B */
hp = &Pichan[2*dev+1]; /* pi1 is offset 1 */
hp->dmachan = 0; /* Channel B does not have dma */
hp->cardbase = Pi[dev].addr;
hp->iface = if_pcb;
hp->stata = Pi[dev].addr + CHANA + CTL; /* permanent status */
hp->statb = Pi[dev].addr + CHANB + CTL; /* addrs for CHANA/B*/
hp->speed = (int16)atoi(argv[9]);
hp->base = Pi[dev].addr + CHANB;
hp->bufsiz = atoi(argv[6]);
hp->tstate = IDLE;
/* default channel access Params */
hp->txdelay = 30; /* 300 Ms */
hp->persist = 128; /* 50% persistence */
hp->slotime = 30; /* 300 Ms */
hp->squeldelay = 3; /* 30 Ms */
xwrite_scc(hp,CTL+hp->stata,R9,FHWRES); /* Hardware reset */
/* one time only */
/* Disable interrupts with Master interrupt ctrl reg */
xwrite_scc(hp,CTL+hp->stata,R9,0);
scc_init(hp);
/* Pre-allocate a receive buffer */
i_state = dirps();
hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
restore(i_state);
if(hp->rcvbuf == NULLBUF){
/* No memory, abort receiver */
tprintf("PI: No memory available for receive buffers\n");
/* Restore original interrupt vector */
setirq(Pi[dev].vec,Pi[dev].oldvec);
pinbr--;
return -1;
}
hp->rcvbuf->data += sizeof(struct phdr);
hp->rcp = hp->rcvbuf->data;
hp->rcvbuf->cnt = 0;
hp->sndq = NULLBUF;
/* set params in pichan table for CHANNEL A */
hp = &Pichan[2*dev]; /* pi0a is offset 0 */
hp->dmachan = (unsigned char)atoi(argv[3]);
/* Figure out where the dma page register is. */
if(hp->dmachan < 8 && hp->dmachan >= 0){
hp->page_addr = Page_regs[hp->dmachan];
} else {
printf("PI: DMA channel %d out of range\n",hp->dmachan);
free_p(hp->rcvbuf);
/* Restore original interrupt vector */
setirq(Pi[dev].vec,Pi[dev].oldvec);
pinbr--;
return -1;
}
hp->dma_dest = hp->dmachan * 2;
hp->dma_wcr = hp->dma_dest + 1;
hp->cardbase = Pi[dev].addr;
hp->iface = if_pca;
hp->speed = (int16)atoi(argv[8]);
hp->base = Pi[dev].addr + CHANA;
hp->bufsiz = atoi(argv[6]);
hp->tstate = IDLE;
/* default channel access Params */
hp->txdelay = 15; /* 15 mS */
hp->persist = 128; /* 50% persistence */
hp->slotime = 15; /* 15 mS */
hp->squeldelay = 1; /* 1 mS */
newproc("buf_recover",256,buf_recover,0,hp,NULL,0);
/* Pre-allocate a receive buffer */
/* buffer is allocated with ints off */
i_state = dirps();
hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr));
restore(i_state);
if(hp->rcvbuf == NULLBUF){
/* No memory, abort receiver */
tprintf("PI: No memory available for receive buffers\n");
/* Restore original interrupt vector */
setirq(Pi[dev].vec,Pi[dev].oldvec);
pinbr--;
return -1;
}
hp->rcvbuf->data += sizeof(struct phdr);
hp->rcvbuf->cnt = 0;
hp->sndq = NULLBUF;
/* Get a buffer for tx which does not cross a dma boundary */
/* buffer is allocated with ints off */
i_state = dirps();
bp = alloc_mbuf(hp->bufsiz);
if(bp != NULLBUF)
hp->txdmabuf = bp->data;
else
hp->txdmabuf = NULLCHAR;
restore(i_state);
if(!hp->txdmabuf)
tprintf("PI: No memory available for transmit buffer");
scc_init(hp);
/* master interrupt enable */
xwrite_scc(hp,CTL+hp->base,R9,MIE|NV);
/* Enable interrupt */
maskon(Pi[dev].vec);
if_pca->txproc = newproc("pi tx",512,if_tx,0,if_pca,NULL,0);
if_pcb->txproc = newproc("pi tx",512,if_tx,0,if_pcb,NULL,0);
return 0;
}
/* Shut down interface */
int
pi_stop(iface)
struct iface *iface;
{
int16 dev;
struct pichan *hp;
dev = iface->dev;
if(dev & 1) /* Because there are 2 devices per card */
return 0;
dev >>= 1; /* Convert back into pi number */
hp = &Pichan[2*dev]; /* pi0a is offset 0 */
outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA channel */
/* Turn off interrupts */
maskoff(Pi[dev].vec);
/* Restore original interrupt vector */
setirq(Pi[dev].vec,Pi[dev].oldvec);
/* Force hardware reset */
xwrite_scc(&Pichan[2*dev],CTL+Pi[dev].addr + CHANA,R9,FHWRES);
return 0;
}
/* Send raw packet on pi card */
int
pi_raw(iface,bp)
struct iface *iface;
struct mbuf *bp;
{
char i_state;
char kickflag;
struct pichan *hp;
dump(iface,IF_TRACE_OUT,CL_AX25,bp);
iface->rawsndcnt++;
iface->lastsent = secclock();
hp = &Pichan[iface->dev];
kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);
enqueue(&hp->sndq,bp);
hp->enqueued++;
if(kickflag){
/* simulate interrupt to xmit */
switch(hp->base & 2){
case 2:
a_txint(hp); /* process interrupt */
break;
case 0:
i_state = dirps();
if(hp->tstate == IDLE)
b_txint(hp);
restore(i_state);
break;
}
}
return 0;
}
/* display PI Channel stats */
int
dopistat()
{
struct pichan *hp;
int i;
tprintf("PI Board Statistics:\n\n");
tprintf("Base Addr Rxints Txints Exints TxFrms RxFrms Crcerr RxOvrs TxUndr \n");
tprintf("--------- ------ ------ ------ ------ ------ ------ ------ ------ \n");
for(i=0; i<pinbr*2; i++){
hp = &Pichan[i];
tprintf("0x%03x % 8lu% 8lu% 8lu% 8u% 8u% 8u% 8u% 8u\nRcv State=%s ",
hp->base, hp->rxints, hp->txints, hp->exints, hp->enqueued,
hp->rxframes, hp->crcerr, hp->rovers, hp->tunders,
hp->rstate==0 ?
"IDLE" : hp->rstate==1 ?
"ACTIVE" : hp->rstate==2 ?
"RXERROR" : hp->rstate==3 ?
"RXABORT":"TOOBIG"
);
tprintf("Tstate = %s\n",
hp->tstate == 0 ?
"IDLE" : hp->tstate == 1 ?
"ACTIVE" : hp->tstate == 2 ?
"UNDERRUN" : hp->tstate == 3 ?
"FLAGOUT" : hp->tstate == 4 ?
"DEFER" : hp->tstate == 5 ?
"TXDELAY" : "CRCOUT"
);
}
return 0;
}
/* Subroutine to set kiss params in channel tables */
int32
pi_ctl(iface,cmd,set,val)
struct iface *iface;
int cmd;
int set;
int32 val;
{
struct pichan *hp;
int32 t,ca;
hp = &Pichan[iface->dev]; /* point to channel table */
switch(cmd){
case PARAM_TXDELAY:
if(set)
hp->txdelay = val;
return hp->txdelay;
case PARAM_PERSIST:
if(set)
hp->persist = val;
return uchar(hp->persist);
case PARAM_SLOTTIME:
if(set)
hp->slotime = val;
return hp->slotime;
case PARAM_TXTAIL:
if(set)
hp->squeldelay = val;
return hp->squeldelay;
case PARAM_MUTE:
if(set){
if(val == -1){
/* Special case for duration of a CTS */
val = hp->txdelay + 500;
}
hp->deftime = msclock() + val;
}
t = msclock();
ca = hp->deftime - t;
if(ca < 0){
hp->deftime = t;
ca = 0;
}
return ca;
}
return -1;
}