?? scc.c
字號:
case CL_SERIAL_LINE:
case CL_KISS:
free(scc->fifo.buf);
default:
break;
}
free(scc);
Sccchan[ifp->dev] = NULL;
restore(i_state);
return 0;
}
/* de-activate SCC driver on program exit */
void
sccstop()
{
if(Sccinfo.init){ /* was it initialized? */
maskoff(Sccinfo.ivec); /* disable the interrupt */
setirq(Sccinfo.ivec,Orgivec); /* restore original interrupt vector */
}
}
/* perform ioctl on SCC (async) channel
* this is used for SLIP mode only, and will read/set the line speed
*/
static int32
scc_aioctl(ifp,cmd,set,val)
struct iface *ifp;
int cmd;
int set;
int32 val;
{
struct sccchan *scc;
unsigned int brgrate;
scc = Sccchan[ifp->dev];
switch(cmd){
case PARAM_SPEED:
if(set){
brgrate = scc_speed(scc,16,val);
scc->speed = Sccinfo.clk / (32L * (brgrate + 2));
}
return scc->speed;
}
return 0;
}
/* perform ioctl on SCC (sdlc) channel
* this is used for AX.25 mode only, and will set the "kiss" parameters
*/
static int32
scc_sioctl(ifp,cmd,set,val)
struct iface *ifp;
int cmd;
int set;
int32 val;
{
struct sccchan *scc;
unsigned int brgrate;
int i_state;
scc = Sccchan[ifp->dev];
switch(cmd){
case PARAM_SPEED:
if(set){
if(val == 0)
scc->extclock = 1;
else {
brgrate = scc_speed(scc,32,val);/* init SCC speed */
scc->speed = Sccinfo.clk / (64L * (brgrate + 2));/* calc real speed */
}
}
return scc->speed;
case PARAM_TXDELAY:
if(set)
scc->a.txdelay = val;
return scc->a.txdelay;
case PARAM_PERSIST:
if(set)
scc->a.persist = val;
return scc->a.persist;
case PARAM_SLOTTIME:
if(set)
scc->a.slottime = val;
return scc->a.slottime;
case PARAM_TXTAIL:
if(set)
scc->a.tailtime = val;
return scc->a.tailtime;
case PARAM_FULLDUP:
if(set)
scc->a.fulldup = val;
return scc->a.fulldup;
case PARAM_WAIT:
if(set)
scc->a.waittime = val;
return scc->a.waittime;
case PARAM_MAXKEY:
if(set)
scc->a.maxkeyup = val;
return scc->a.maxkeyup;
case PARAM_MIN:
if(set)
scc->a.mintime = val;
return scc->a.mintime;
case PARAM_IDLE:
if(set)
scc->a.idletime = val;
return scc->a.idletime;
case PARAM_DTR:
if(set){
if(val)
scc->wreg[R5] |= DTR;
else
scc->wreg[R5] &= ~DTR;
i_state = dirps();
if(scc->a.tstate == IDLE && scc->timercount == 0)
scc->timercount = 1; /* force an update */
restore(i_state);
}
return (scc->wreg[R5] & DTR) ? 1 : 0;
case PARAM_GROUP:
if(set)
scc->group = val;
return scc->group;
}
return -1;
}
/* start SCC transmitter when it is idle (SLIP/KISS mode only) */
static void
scc_sstart(scc)
register struct sccchan *scc;
{
if(scc->tbp != NULL || /* busy */
scc->sndq == NULL) /* no work */
return;
scc->tbp = dequeue(&scc->sndq);
WRREG(scc->data,FR_END);
}
/* show SCC status */
int
dosccstat()
{
register struct sccchan *scc;
int i;
if(!Sccinfo.init){
printf("SCC driver not initialized\n");
return 0;
}
printf("Ch Iface Sent Rcvd Error Space Overr Rxints Txints Exints Spints\n");
for(i = 0; i <= Sccinfo.maxchan; i++){
if((scc = Sccchan[i]) == NULL)
continue;
if(scc->int_receive == scc_asyrx)
printf("%2d %-6s ** asynch ** %7lu %5u %5u %8lu %8lu %8lu %8lu\n",i,scc->iface->name,
scc->rxerrs,scc->nospace,scc->rovers,
scc->rxints,scc->txints,scc->exints,scc->spints);
else
printf("%2d %-6s %6lu %6lu %7lu %5u %5u %8lu %8lu %8lu %8lu\n",i,scc->iface->name,
scc->enqueued,scc->rxframes,scc->rxerrs,scc->nospace,scc->rovers,
scc->rxints,scc->txints,scc->exints,scc->spints);
}
return 0;
}
/* send raw frame to SCC. used for AX.25 */
static int
scc_raw(
struct iface *ifp,
struct mbuf **bpp
){
struct sccchan *scc;
int i_state;
dump(ifp,IF_TRACE_OUT,*bpp);
ifp->rawsndcnt++;
ifp->lastsent = secclock();
scc = Sccchan[ifp->dev];
if (scc->tx_inhibit){ /* transmitter inhibit */
free_p(bpp);
return -1;
}
enqueue(&scc->sndq,bpp); /* enqueue packet */
scc->enqueued++;
i_state = dirps();
if(scc->a.tstate == IDLE){ /* when transmitter is idle */
scc->a.tstate = DEFER; /* start the key-up sequence */
scc->a.maxdefer = TPS * scc->a.idletime /
scc->a.slottime;
scc->timercount = scc->a.waittime;
}
restore(i_state);
return 0;
}
static int
scc_send(
int dev,
struct mbuf **bpp
){
struct sccchan *scc;
scc = Sccchan[dev];
enqueue(&scc->sndq,bpp);
if(scc->tbp == NULL)
scc_sstart(scc);
return(0);
}
/* initialize interface for AX.25 use */
static int
scc_call(ifp,call)
register struct iface *ifp;
char *call;
{
uint8 out[AXALEN];
ifp->hwaddr = mallocw(AXALEN);
if(setcall(out,call) == 0)
memcpy(ifp->hwaddr,out,AXALEN);
else
memcpy(ifp->hwaddr,Mycall,AXALEN);
return 0;
}
/* Interrupt handlers for asynchronous modes (kiss, slip) */
/* Transmitter interrupt handler */
/* This routine sends data from mbufs in SLIP format */
static void
scc_asytx(scc)
register struct sccchan *scc;
{
register struct mbuf *bp;
scc->txints++;
if(scc->txchar != 0){ /* a character pending for transmit? */
WRREG(scc->data,scc->txchar); /* send it now */
scc->txchar = 0; /* next time, ignore it */
return;
}
if(scc->tbp == NULL){ /* nothing to send? */
if((scc->tbp = scc->sndq) != NULL){ /* dequeue next frame */
scc->sndq = scc->sndq->anext;
WRREG(scc->data,FR_END); /* send FR_END to flush line garbage */
} else {
WRREG(scc->ctrl,RES_Tx_P); /* else only reset pending int */
}
return;
}
while ((bp = scc->tbp)->cnt == 0){ /* nothing left in this mbuf? */
bp = bp->next; /* save link to next */
free_mbuf(&scc->tbp);
if((scc->tbp = bp) == NULL){ /* see if more mbufs follow */
WRREG(scc->data,FR_END); /* frame complete, send FR_END */
return;
}
}
/* now bp = scc->tbp (either from while or from if stmt above) */
WRREG(scc->data,*(bp->data)); /* just send the character */
bp->cnt--; /* decrease mbuf byte count */
bp->data++; /* and increment the data pointer */
}
/* External/Status interrupt handler */
static void
scc_asyex(scc)
register struct sccchan *scc;
{
register unsigned char status,changes;
scc->exints++;
status = RDREG(scc->ctrl);
changes = status ^ scc->status;
if(changes & BRK_ABRT){ /* BREAK? */
if((status & BRK_ABRT) == 0) /* BREAK now over? */
VOID(RDREG(scc->data)); /* read the NUL character */
}
scc->status = status;
WRREG(scc->ctrl,RES_EXT_INT);
}
/* Receiver interrupt handler under NOS.
* Since the higher serial protocol routines are all written to work
* well with the routines in 8250.c, it makes sense to handle
* asynch i/o with the 8530 in a similar manner. Therefore, these
* routines are as close to their counterparts in 8250.c as possible.
*/
static void
scc_asyrx(scc)
register struct sccchan *scc;
{
register struct fifo *fp;
char c;
scc->rxints++;
fp = &(scc->fifo);
do {
c = RDREG(scc->data);
if(fp->cnt != fp->bufsize){
*fp->wp++ = c;
if(fp->wp >= &fp->buf[fp->bufsize])
fp->wp = fp->buf;
fp->cnt++;
} else
scc->nospace++;
} while(RDREG(scc->ctrl) & Rx_CH_AV);
ksignal(fp,1); /* eventually move this to timer routine */
}
/* Blocking read from asynch input.
* Essentially the same as get_asy() in 8250.c
* See comments in asyrxint().
*/
static int
get_scc(dev)
int dev;
{
register struct fifo *fp;
uint8 c;
int tmp;
int i_state;
fp = &(Sccchan[dev]->fifo);
for(;;){
i_state = dirps();
tmp = fp->cnt;
if(tmp != 0){
fp->cnt--;
restore(i_state);
break;
}
restore(i_state);
kwait(fp);
}
c = *fp->rp++;
if(fp->rp >= &fp->buf[fp->bufsize])
fp->rp = fp->buf;
return c;
}
int
scc_frameup(dev)
int dev;
{
Sccchan[dev]->rxframes++;
return 0;
}
/* Receive Special Condition interrupt handler */
static void
scc_asysp(scc)
register struct sccchan *scc;
{
register unsigned char status;
scc->spints++;
status = rd(scc,R1); /* read receiver status */
VOID(RDREG(scc->data)); /* flush offending character */
if(status & (CRC_ERR | Rx_OVR)) /* did a framing error or overrun occur ? */
scc->rovers++; /* report as overrun */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -