📄 pi.c
字号:
hp->rxcnt = 0;
hp->rstate = RXERROR; /* set error flag */
hp->rovers++;
} else if(hp->rxcnt >= hp->bufsiz){
/* Too large -- toss entire frame */
/* reset buffer pointers */
hp->rcp = hp->rcvbuf;
hp->rxcnt = 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->rxcnt++; /* 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->rxcnt > 0){
if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(hp->rxcnt < 10)){
if((hp->rxcnt >= 10) && (rse & CRC_ERR))
hp->crcerr++; /* Ignore noise */
hp->rcp = hp->rcvbuf;
hp->rxcnt = 0;
} else {
/* Here we have a valid frame */
hp->rxcnt -= 2; /* Toss 2 crc bytes */
if((bp = alloc_mbuf(hp->rxcnt+sizeof(struct iface *)))
!= NULL){
bp->data += sizeof(struct iface *);
bp->cnt = hp->rxcnt;
memcpy(bp->data,hp->rcvbuf,hp->rxcnt);
net_route(hp->iface,&bp);
hp->rxframes++;
}
/* packet queued - get ready for next frame */
hp->rcp = hp->rcvbuf;
hp->rxcnt = 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 uint16 cmd;
char c;
struct mbuf *bp;
int i_state;
cmd = CTL+hp->base;
i_state = dirps();
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((bp = dequeue(&hp->sndq)) == NULL){
/* Nothing to send - return to receive mode
* Tx OFF now - flag should have gone
*/
rts(hp,OFF);
restore(i_state);
return;
}
hp->txcnt = pullup(&bp,hp->sndbuf,hp->bufsiz);
free_p(&bp); /* Truncate overly long packets */
/* 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(hp->txcnt-- != 0){
c = *hp->tcp++;
/* next char is gone */
xwrite_scc(hp,cmd,R8,c);
/* stuffing a char satisfies Interrupt condition */
} else {
/* No more to send */
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;
register uint16 cmd;
char c;
struct mbuf *bp;
int i_state;
cmd = CTL+hp->base;
hp->exints++;
i_state = dirps();
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 */
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((bp = dequeue(&hp->sndq)) == NULL){
/* Nothing to send - return to receive mode
* Tx OFF now - flag should have gone
*/
rts(hp,OFF);
hp->tstate = IDLE;
restore(i_state);
return;
}
hp->txcnt = pullup(&bp,hp->sndbuf,hp->bufsiz);
free_p(&bp); /* Truncate overly long packets */
hp->tcp = hp->sndbuf;
/* Get next char to send */
c = *hp->tcp++;
hp->txcnt--;
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 */
c = *hp->tcp++;
hp->txcnt--;
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;
hp->rxcnt = 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;
uint16 x;
{
uint16 tc;
long br;
uint16 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;
hp->rxcnt = 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;
{
int cmd;
int dmaport;
int i_state;
cmd = hp->base+CTL;
dmaport = DMABASE+2*hp->dmachan;
i_state = dirps();
if(!hp->rcvbuf){
/* No rx buffer available */
restore(i_state);
return;
}
/* 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(Page_regs[hp->dmachan],hp->rcvphys >> 16);/* Store in 64K DMA page */
outportb(DMA_RESETFF,0); /* reset byte pointer flipflop */
/* Output buffer start (dest) address */
outportb(dmaport,hp->rcvphys);
outportb(dmaport,hp->rcvphys >> 8);
/* output DMA maximum byte count */
dmaport++;
outportb(dmaport,hp->bufsiz - 1);
outportb(dmaport, (hp->bufsiz - 1) >> 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)
struct pichan *hp;
{
int dmaport;
uint16 length;
int i_state;
length = hp->txcnt - 1;
dmaport = DMABASE + 2*hp->dmachan;
i_state = dirps();
outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
/* Set DMA mode register to single transfers, incrementing address,
* no auto init, reads
*/
outportb(DMA_MODE,DMA_TX_MODE|hp->dmachan);
outportb(Page_regs[hp->dmachan],hp->sndphys >> 16); /* Store in 64K DMA page */
outportb(DMA_RESETFF,0); /* reset byte pointer flipflop */
outportb(dmaport,hp->sndphys); /* Output buffer start (source) address */
outportb(dmaport,hp->sndphys >> 8);
/* output byte count */
dmaport++;
outportb(dmaport,length);
outportb(dmaport, length >> 8);
restore(i_state);
}
/* Initialize pi controller parameters */
static int
scc_init(hp)
register struct pichan *hp;
{
uint16 tc;
long br;
register uint16 cmd;
int i_state;
/* Initialize 8530 channel for SDLC operation */
cmd = CTL+hp->base;
#ifdef notdef
printf("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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -