📄 pi.c
字号:
#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 "z8530.h"
#include "ax25.h"
#include "trace.h"
#include "nospc.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
void b_rxint(struct pichan *);
void b_txint(struct pichan *);
void b_exint(struct pichan *);
void a_rxint(struct pichan *);
void a_txint(struct pichan *);
void a_exint(struct pichan *);
static void xwrite_scc(struct pichan *hp,uint16 ctl,uint16 reg,
uint16 val );
static char xread_scc(struct pichan *hp, uint16 ctl, char reg);
static int32 pi_ctl(struct iface *iface,int cmd,int set,int32 val);
static int pi_raw(struct iface *iface,struct mbuf **bpp);
static int pi_stop(struct iface *iface);
static void rts(struct pichan *hp, uint16 x);
void setup_rx_dma(struct pichan *hp);
void setup_tx_dma(struct pichan *hp);
static void set_acc_delay(void);
static void tdelay(register struct pichan *hp,unsigned int time);
static int scc_init(register struct pichan *hp);
static struct PITAB Pi[PIMAX]; /* Device table - one entry per card */
static INTERRUPT (*pihandle[])() = { /* handler interrupt vector table */
pi0vec,
pi1vec,
pi2vec
};
static uint16 Page_regs[] = {
0x87,0x83,0x81,0x82,0,0x8b,0x89,0x8a
};
static struct pichan Pichan[2*PIMAX]; /* channel table - 2 entries per card */
static uint16 pinbr;
extern uint16 acc_delay; /* Delay for the 8530 chip access recovery time */
/* 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 uint16 ctl;
uint16 reg,val;
{
wrtscc(hp->cardbase,ctl,reg,val);
}
/* Read 8530 register */
static char
xread_scc(hp,ctl,reg)
register struct pichan *hp;
register uint16 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 uint16 pcbase;
struct pichan *hp;
struct PITAB *pip;
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 uint16 cmd;
char st;
int32 t,ca;
struct mbuf *bp;
int i_state;
i_state = dirps();
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:
hp->tstate = FLAGOUT;
tdelay(hp,hp->squeldelay);
break;
case FLAGOUT:
if((bp = dequeue(&hp->sndq)) == NULL){
/* Nothing to send - return to receive mode */
hp->tstate = IDLE;
rts(hp,OFF);
restore(i_state);
return;
}
/* Get all chars */
hp->txcnt = pullup(&bp,hp->sndbuf,hp->bufsiz);
free_p(&bp); /* Truncate overly long packets */
/* 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);
/* Setup DMA controller for tx */
setup_tx_dma(hp);
/* 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) > 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 uint16 cmd;
register uint16 bytecount;
char rse;
struct mbuf *bp;
int i_state;
hp->rxints++;
cmd = hp->base+CTL;
i_state = dirps();
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(DMABASE+2*hp->dmachan+1);
bytecount += inportb(DMABASE+2*hp->dmachan+1) << 8;
bytecount = hp->bufsiz - 1 - 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. Copy to buffer,
* minus 2 CRC bytes
*/
bytecount -= 2;
if((bp = alloc_mbuf(bytecount+sizeof(struct iface *)))
!= NULL){
bp->data += sizeof(struct iface *);
bp->cnt = bytecount;
memcpy(bp->data,hp->rcvbuf,bytecount);
net_route(hp->iface,&bp);
hp->rxcnt = 0;
hp->rxframes++;
}
/* packet queued - get buffer for next frame */
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 uint16 cmd;
int32 t,ca;
struct mbuf *bp;
int i_state;
cmd = CTL+hp->base;
i_state = dirps();
switch(hp->tstate){
case IDLE:
/* Transmitter idle. Find a frame for transmission */
if((bp = dequeue(&hp->sndq)) == NULL){
rts(hp,OFF);
restore(i_state);
return;
}
/* If a buffer to send, we drop thru here */
hp->txcnt = pullup(&bp,hp->sndbuf,hp->bufsiz);
free_p(&bp); /* Truncate overly long packet */
hp->tcp = hp->sndbuf;
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) > 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 uint16 cmd;
char rse;
struct mbuf *bp;
int i_state;
hp->rxints++;
cmd = CTL+hp->base;
i_state = dirps();
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -