?? scc.c
字號:
WRREG(scc->ctrl,ERR_RES);
}
/* Interrupt handlers for sdlc mode (AX.25) */
/* Transmitter interrupt handler */
static void
scc_sdlctx(scc)
register struct sccchan *scc;
{
register struct mbuf *bp;
scc->txints++;
switch(scc->a.tstate){ /* look at transmitter state */
case ACTIVE: /* busy sending data bytes */
while ((bp = scc->tbp)->cnt == 0){ /* nothing left in this mbuf? */
bp = bp->next; /* save link to next */
free_mbuf(&scc->tbp); /*KM*/
if((scc->tbp = bp) == NULL){/* see if more mbufs follow */
if(RDREG(scc->ctrl) & TxEOM){ /* check tx underrun status */
scc->rovers++; /* oops, an underrun! count them */
WRREG(scc->ctrl,SEND_ABORT);/* send an abort to be sure */
scc->a.tstate = TAIL; /* key down tx after TAILTIME */
scc->timercount = scc->a.tailtime;
return;
}
cl(scc,R10,ABUNDER); /* frame complete, allow CRC transmit */
scc->a.tstate = FLUSH;
WRREG(scc->ctrl,RES_Tx_P); /* reset pending int */
return;
}
}
/* now bp = scc->tbp (either from while or from if stmt above) */
WRREG(scc->data,*(bp->data++)); /* send the character */
bp->cnt--; /* decrease mbuf byte count */
return;
case FLUSH: /* CRC just went out, more to send? */
or(scc,R10,ABUNDER); /* re-install underrun protection */
/* verify that we are not exeeding max tx time (if defined) */
if((scc->timercount != 0 || scc->a.maxkeyup == 0) &&
(scc->tbp = scc->sndq) != NULL){ /* dequeue a frame */
scc->sndq = scc->sndq->anext;
WRREG(scc->ctrl,RES_Tx_CRC); /* reset the TX CRC generator */
scc->a.tstate = ACTIVE;
scc_sdlctx(scc); /* write 1st byte */
WRREG(scc->ctrl,RES_EOM_L); /* reset the EOM latch */
return;
}
scc->a.tstate = TAIL; /* no more, key down tx after TAILTIME */
scc->timercount = scc->a.tailtime;
WRREG(scc->ctrl,RES_Tx_P);
return;
default: /* another state */
WRREG(scc->ctrl,RES_Tx_P); /* then don't send anything */
return;
}
}
/* External/Status interrupt handler */
static void
scc_sdlcex(scc)
register struct sccchan *scc;
{
register unsigned char status,changes;
scc->exints++;
status = RDREG(scc->ctrl);
changes = status ^ scc->status;
if(changes & BRK_ABRT){ /* Received an ABORT */
if(status & BRK_ABRT){ /* is this the beginning? */
if(scc->rbp != NULL){/* did we receive something? */
/* check if a significant amount of data came in */
/* this is because the drop of DCD tends to generate an ABORT */
if(scc->rbp->next != NULL || scc->rbp->cnt > 0)
scc->rxerrs++; /* then count it as an error */
scc_tossb(scc); /* throw away buffer */
}
VOID(RDREG(scc->data)); /* flush the FIFO */
VOID(RDREG(scc->data));
VOID(RDREG(scc->data));
}
}
if(changes & CTS){ /* CTS input changed state */
if(status & CTS){ /* CTS is now ON */
if(scc->a.tstate == KEYWT &&
scc->a.txdelay == 0) /* zero TXDELAY = wait for CTS */
scc->timercount = 1; /* it will start within 10 ms */
}
}
if(changes & DCD){ /* DCD input changed state */
if(status & DCD){ /* DCD is now ON */
if (!scc->extclock)
WRSCC(scc->ctrl,R14,SEARCH|scc->wreg[R14]); /* DPLL: enter search mode */
or(scc,R3,ENT_HM|RxENABLE); /* enable the receiver, hunt mode */
} else { /* DCD is now OFF */
cl(scc,R3,ENT_HM|RxENABLE); /* disable the receiver */
VOID(RDREG(scc->data)); /* flush the FIFO */
VOID(RDREG(scc->data));
VOID(RDREG(scc->data));
if(scc->rbp != NULL){/* did we receive something? */
/* check if a significant amount of data came in */
/* this is because some characters precede the drop of DCD */
if(scc->rbp->next != NULL || scc->rbp->cnt > 0)
scc->rxerrs++; /* then count it as an error */
scc_tossb(scc); /* throw away buffer */
}
}
}
scc->status = status;
WRREG(scc->ctrl,RES_EXT_INT);
}
/* Receiver interrupt handler */
static void
scc_sdlcrx(scc)
register struct sccchan *scc;
{
register struct mbuf *bp;
scc->rxints++;
if((bp = scc->rbp1) == NULL){ /* no buffer available now */
if(scc->rbp == NULL){
if((bp = alloc_mbuf(scc->bufsiz+sizeof(struct iface *))) != NULL){
scc->rbp = scc->rbp1 = bp;
bp->cnt = 0;
}
} else if((bp = alloc_mbuf(scc->bufsiz)) != NULL){
scc->rbp1 = bp;
for(bp = scc->rbp; bp->next != NULL; bp = bp->next)
;
bp->next = scc->rbp1;
bp = scc->rbp1;
}
if(bp == NULL){
VOID(RDREG(scc->data)); /* so we have to discard the char */
or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
scc_tossb(scc); /* put buffers back on pool */
scc->nospace++; /* count these events */
return;
}
}
/* now, we have a buffer (at bp). read character and store it */
bp->data[bp->cnt++] = RDREG(scc->data);
if(bp->cnt == bp->size) /* buffer full? */
scc->rbp1 = NULL; /* acquire a new one next time */
}
/* Receive Special Condition interrupt handler */
static void
scc_sdlcsp(scc)
register struct sccchan *scc;
{
register unsigned char status;
register struct mbuf *bp;
scc->spints++;
status = rd(scc,R1); /* read receiver status */
VOID(RDREG(scc->data)); /* flush offending character */
if(status & Rx_OVR){ /* receiver overrun */
scc->rovers++; /* count them */
or(scc,R3,ENT_HM); /* enter hunt mode for next flag */
scc_tossb(scc); /* rewind the buffer and toss */
}
if(status & END_FR && /* end of frame */
scc->rbp != NULL){ /* at least received something */
if((status & CRC_ERR) == 0 && /* no CRC error is indicated */
(status & 0xe) == RES8 && /* 8 bits in last byte */
scc->rbp->cnt > 0){
/* we seem to have a good frame. but the last byte received */
/* from rx interrupt is in fact a CRC byte, so discard it */
if(scc->rbp1 != NULL){
scc->rbp1->cnt--; /* current mbuf was not full */
} else {
for(bp = scc->rbp; bp->next != NULL; bp = bp->next);
/* find last mbuf */
bp->cnt--; /* last byte is first CRC byte */
}
net_route(scc->iface,&scc->rbp);
scc->rbp = scc->rbp1 = NULL;
scc->rxframes++;
} else { /* a bad frame */
scc_tossb(scc); /* throw away frame */
scc->rxerrs++;
}
}
WRREG(scc->ctrl,ERR_RES);
}
/* Throw away receive mbuf(s) when an error occurred */
static void
scc_tossb (scc)
register struct sccchan *scc;
{
register struct mbuf *bp;
if((bp = scc->rbp) != NULL){
free_p(&bp->next);
free_p(&bp->dup); /* Should be NULL */
bp->next = NULL;
scc->rbp1 = bp; /* Don't throw this one away */
bp->cnt = 0; /* Simply rewind it */
}
}
/* Switch the SCC to "transmit" mode */
/* Only to be called from an interrupt handler, while in AX.25 mode */
static void
scc_txon(scc)
register struct sccchan *scc;
{
if (!scc->fulldup && !scc->extclock){ /* no fulldup divider? */
cl(scc,R3,RxENABLE); /* then switch off receiver */
cl(scc,R5,TxENAB); /* transmitter off during switch */
scc_speed(scc,1,scc->speed); /* reprogram baudrate generator */
}
or(scc,R5,RTS|TxENAB); /* set the RTS line and enable TX */
if(Sccinfo.hwtype & HWPRIMUS) /* PRIMUS has another PTT bit... */
WRREG(scc->ctrl + 4,Sccinfo.hwparam | 0x80); /* set that bit! */
}
/* Switch the SCC to "receive" mode (or: switch off transmitter)
* Only to be called from an interrupt handler, while in AX.25 mode
*/
static void
scc_txoff(scc)
register struct sccchan *scc;
{
cl(scc,R5,RTS); /* turn off RTS line */
if(Sccinfo.hwtype & HWPRIMUS) /* PRIMUS has another PTT bit... */
WRREG(scc->ctrl + 4,Sccinfo.hwparam); /* clear that bit! */
if (!scc->fulldup && !scc->extclock){ /* no fulldup divider? */
cl(scc,R5,TxENAB); /* then disable the transmitter */
scc_speed(scc,32,scc->speed); /* back to receiver baudrate */
}
}
/* SCC timer interrupt handler. Will be called every 1/TPS s by the
* routine systick in pc.c
*/
void scctimer()
{
register struct sccchan *scc;
register struct sccchan **sccp;
int i_state;
i_state = dirps();
for(sccp = Sccchan + Sccinfo.maxchan; sccp >= Sccchan; sccp--){
if((scc = *sccp) != NULL &&
scc->timercount != 0 &&
--(scc->timercount) == 0){
/* handle an SCC timer event for this SCC channel
* this can only happen when the channel is AX.25 type
* (the SLIP/KISS driver does not use timers)
*/
switch(scc->a.tstate){
case IDLE: /* it was idle, this is FULLDUP2 timeout */
scc_txoff(scc); /* switch-off the transmitter */
break;
case DEFER: /* trying to get the channel */
/* operation is as follows:
* CSMA: when channel clear AND persistence randomgenerator
* wins, AND group restrictions allow it:
* keyup the transmitter
* if not, delay one SLOTTIME and try again
* FULL: always keyup the transmitter
*/
if(scc->a.fulldup == 0){
Random = 21 * Random + 53;
if(scc->status & DCD || scc->a.persist < Random){
/* defer transmission again. check for limit */
defer_it: if(--(scc->a.maxdefer) == 0){
/* deferred too long. choice is to:
* - throw away pending frames, or
* - smash-on the transmitter and send them.
* the first would be the choice in a clean
* environment, but in the amateur radio world
* a distant faulty station could tie us up
* forever, so the second may be better...
*/
#ifdef THROW_AWAY_AFTER_DEFER_TIMEOUT
struct mbuf *bp,*bp1;
while ((bp = scc->sndq) != NULL){
scc->sndq = scc->sndq->anext;
free_p(&bp);
}
#else
goto keyup; /* just keyup the transmitter... */
#endif
}
scc->timercount = scc->a.slottime;
break;
}
if(scc->group != NOGROUP){
int i;
struct sccchan *scc2;
for(i = 0; i <= Sccinfo.maxchan; i++)
if((scc2 = Sccchan[i]) != NULL &&
scc2 != scc &&
scc2->group & scc->group &&
((scc->group & TXGROUP && scc2->wreg[R5] & RTS) ||
(scc->group & RXGROUP && scc2->status & DCD))){
goto defer_it;
}
}
}
case KEYUP: /* keyup transmitter (note fallthrough) */
keyup: if((scc->wreg[R5] & RTS) == 0){ /* when not yet keyed */
scc->a.tstate = KEYWT;
scc->timercount = scc->a.txdelay; /* 0 if CTSwait */
scc_txon(scc);
break;
}
/* when already keyed, directly fall through */
case KEYWT: /* waited for CTS or TXDELAY */
/* when a frame is available (it should be...):
* - dequeue it from the send queue
* - reset the transmitter CRC generator
* - set a timeout on transmission length, if defined
* - send the first byte of the frame
* - reset the EOM latch
* when no frame available, proceed to TAIL handling
*/
if((scc->tbp = scc->sndq) != NULL){
scc->sndq = scc->sndq->anext;
WRREG(scc->ctrl,RES_Tx_CRC);
scc->a.tstate = ACTIVE;
scc->timercount = TPS * scc->a.maxkeyup;
scc_sdlctx(scc);
WRREG(scc->ctrl,RES_EOM_L);
break;
}
/* when no frame queued, fall through to TAIL case */
case TAIL: /* at end of frame */
/* when fulldup is 0 or 1, switch off the transmitter.
* when frames are still queued (because of transmit time limit),
* restart the procedure to get the channel after MINTIME.
* when fulldup is 2, the transmitter remains keyed and we
* continue sending. IDLETIME is an idle timeout in this case.
*/
if(scc->a.fulldup < 2){
scc->a.tstate = IDLE;
scc_txoff(scc);
if(scc->sndq != NULL){
scc->a.tstate = DEFER;
scc->a.maxdefer = TPS * scc->a.idletime /
scc->a.slottime;
scc->timercount = TPS * scc->a.mintime;
}
break;
}
if(scc->sndq != NULL){ /* still frames on the queue? */
scc->a.tstate = KEYWT; /* continue sending */
scc->timercount = TPS * scc->a.mintime; /* after mintime */
} else {
scc->a.tstate = IDLE;
scc->timercount = TPS * scc->a.idletime;
}
break;
case ACTIVE: /* max keyup time expired */
case FLUSH: /* same while in flush mode */
break; /* no action required yet */
default: /* unexpected state */
scc->a.tstate = IDLE; /* that should not happen, but... */
scc_txoff(scc); /* at least stop the transmitter */
break;
}
}
}
restore(i_state);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -