📄 hs.c
字号:
hp->txdelay = atol(argv[7]);
else
hp->txdelay = 15L;
if(argc > 8)
hp->p = atoi(argv[8]);
else
hp->p = 64;
if(argc > 9 && argv[9][0] == 'r')
hp->clkrev = 1;
else
hp->clkrev = 0;
hp->iface = if_hsb;
hdlcparam(hp);
hp = &Hdlc[2*dev];
hp->ctl = Hs[dev].addr + CHANA + CTL;
hp->data = Hs[dev].addr + CHANA + DATA;
hp->bufsiz = atoi(argv[5]);
hp->txdelay = Hdlc[2*dev+1].txdelay;
hp->p = Hdlc[2*dev+1].p;
if(argc > 9 && argv[9][0] == 'r')
hp->clkrev = 1;
else
hp->clkrev = 0;
hp->iface = if_hsa;
hdlcparam(hp);
outportb(Hs[dev].addr + 4,0x08); /*EAGLE INT GATE */
/* Clear mask (enable interrupt) in 8259 interrupt controller */
maskon(Hs[dev].vec);
/* Initialize timing delay loop */
init_delay();
cp = if_name(if_hsa," tx");
if_hsa->txproc = newproc(cp,512,if_tx,0,if_hsa,NULL,0);
free(cp);
cp = if_name(if_hsb," tx");
if_hsb->txproc = newproc(cp,512,if_tx,0,if_hsb,NULL,0);
free(cp);
return 0;
}
static int
hs_stop(iface)
struct iface *iface;
{
int dev;
dev = iface->dev;
if(dev & 1)
return -1; /* Valid only for the first device */
dev >>= 1; /* Convert back into hs number */
/* Turn off interrupts */
maskoff(Hs[dev].vec);
/* Restore original interrupt vector */
setirq(Hs[dev].vec,Hs[dev].save.vec);
/* Force hardware reset */
write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
return 0;
}
/* Send raw packet */
static int
hs_raw(
struct iface *iface,
struct mbuf **bpp
){
struct hdlc *hp;
struct mbuf *nbp;
register uint16 cnt;
register uint8 *cp;
uint16 ctl,data;
dump(iface,IF_TRACE_OUT,*bpp);
iface->rawsndcnt++;
iface->lastsent = secclock();
hp = &Hdlc[iface->dev];
hp->txpkts++;
ctl = hp->ctl;
data = hp->data;
cnt = len_p(*bpp);
/* If buffer isn't contiguous (which is almost always
* the case) copy it to a new buffer for speed
*/
if((*bpp)->next != NULL){
if((nbp = copy_p(*bpp,cnt)) == NULL){
hp->nomem++;
free_p(bpp);
return -1;
}
free_p(bpp);
*bpp = nbp;
}
cp = (*bpp)->data;
/* Turn transmitter on */
hstxon(hp);
/* Initialize transmitter CRC */
write_scc(ctl,R0,RES_Tx_CRC);
for(;;){
/* Wait for the transmitter to become ready */
while(!(inportb(ctl) & Tx_BUF_EMP))
;
if(cnt-- == 0)
break;
outportb(data,*cp++); /* Send the character */
}
write_scc(ctl,R0,RES_EOM_L); /* Allow CRC generation */
/* End of frame. Wait for TxEOM to go high, indicating start of
* CRC transmission. Note that we don't reset the transmit
* interrupt pending flag as one ordinarily would, since we're
* not using tx interrupts.
*/
while(!(inportb(ctl) & TxEOM))
;
free_p(bpp);
hstxoff(hp); /* Shut down tx */
/* Hold off to give other guy a chance to
* respond
*/
hp->deftime = msclock() + hp->txdelay + 500;
return 0;
}
/* Turn on high speed transmitter. Does p-persistence, then sends a dummy
* frame to allow for keyup delay. Returns with transmitter on and interrupts
* disabled
*/
static void
hstxon(hp)
struct hdlc *hp;
{
uint16 ctl;
int i;
long ca;
int32 t;
ctl = hp->ctl;
/* 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).
*/
for(;;){
t = msclock();
ca = hp->deftime - t;
if(ca > 0){
ppause(ca);
continue;
}
hp->deftime = t; /* Keep from getting too old */
if((rand() & 0xff) > hp->p){
ppause((long)MSPTICK);
continue;
}
break;
}
/* Prevent distractions. In particular, block off the DCD interrupt
* so we don't hear our own carrier and hang in the interrupt handler!
* Note that simply disabling CPU interrupts isn't enough since
* the call to ppause will block and the kernel will re-enable
* them.
*/
write_scc(ctl,R9,0); /* Disable all SCC interrupts */
disable();
/* Turn on carrier, enable transmitter */
write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
/* Delay for keyup interval */
for(i=hp->txdelay;i != 0;i--)
msdelay();
}
/* Turn transmitter off at the end of a series of frames */
static void
hstxoff(hp)
struct hdlc *hp;
{
int cnt;
uint16 ctl,data;
ctl = hp->ctl;
data = hp->data;
/* To allow the SCC buffering to drain, we begin a dummy frame,
* then abort it
*/
for(cnt=5;cnt != 0;cnt--){
while(!(inportb(ctl) & Tx_BUF_EMP))
;
outportb(data,0);
}
write_scc(ctl,R0,SEND_ABORT);
/* Turn off carrier and disable transmitter */
write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
/* Re-Enable SCC interrupts */
write_scc(ctl,R9,MIE|NV);
enable(); /* Turn interrupts back on */
}
int
dohs(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register int i;
register struct hdlc *hp;
for(i=0;i<2*Nhs;i++){
hp = &Hdlc[i];
printf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
hp->nomem,hp->toobig,hp->crcerr,hp->aborts,
hp->overrun);
}
return 0;
}
static int32
hs_ctl(iface,cmd,set,val)
struct iface *iface;
int cmd;
int set;
int32 val;
{
register struct hdlc *hp;
int32 t,ca;
hp = &Hdlc[iface->dev];
switch(cmd){
case PARAM_TXDELAY: /* Tx keyup delay */
if(set)
hp->txdelay = val;
return hp->txdelay;
case PARAM_PERSIST:
if(set)
hp->p = val;
return hp->p;
case PARAM_MUTE:
/* Mute transmitter for specified # of ms */
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;
}
#ifdef notdef /* replaced with assembler in 8530.asm */
/* Read data from the 8530 receiver.
* Returns when either a good frame is received, or when carrier drops.
* If a good frame is received, the length is returned; otherwise -1.
*/
int
rx8530(ctl,data,buf,bufsize)
uint16 ctl,data;
char *buf;
uint16 bufsize;
{
int cnt = 0;
register char status;
char error;
register char *cp = buf;
for(;;){
status = inportb(ctl);
if(!(status & DCD)){
cnt = -1;
break;
} else if(status & BRK_ABRT){
cp = buf;
cnt = 0;
} else if(status & Rx_CH_AV){
/* Receive character is ready, get it */
*cp++ = inportb(data);
if(++cnt > bufsize){
/* Buffer overflow, start again */
write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
cp = buf;
cnt = 0;
}
} else if((error = read_scc(ctl,R1)) & END_FR){
if(!(error & CRC_ERR))
break; /* Good frame! */
/* Bad frame, start again */
cp = buf;
cnt = 0;
}
}
return cnt;
}
#endif
static int32 Del_const;
/* Find the value of Del_const that will cause one execution of mloop()
* to take one millisecond
*/
static void
init_delay()
{
int32 start,delay;
register int i,j;
int success = 0;
/* Start with small value to make things tolerable on slow machines */
Del_const = 10;
printf("Del_const = %lu\n",Del_const);
/* Limit the number of iterations in case we don't converge */
for(i=0;i<5;i++){
start = msclock();
for(j=0;j<1000;j++)
msdelay();
delay = msclock()-start;
printf("delay %lu\n",delay);
if(delay == 0){
/* Too fast for accurate measurement on coarse clk */
Del_const *= 10;
printf("Del_const = %lu\n",Del_const);
continue;
}
Del_const = (Del_const * 1000)/delay;
printf("Del_const = %lu\n",Del_const);
if(delay > 950 && delay < 1050){
success = 1;
break; /* Within 1 tick - Close enough */
}
}
if(!success)
printf("HS: Warning: auto delay set failed\n");
}
/* Delay for one millisecond (once calibrated by init_delay()) */
static void
msdelay()
{
int32 i;
for(i=Del_const;i !=0;i--)
;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -