home *** CD-ROM | disk | FTP | other *** search
- /*
- * Interface driver for the VE3IFB 8530 card (PI card)
- * Copyright 1990 by Dave Perry, VE3IFB
- * Minor delinting - KA9Q 2/2/91
- *
- * Portions of this driver were derived from the Eagle card
- * driver by Art Goldman, WA3CVG. It has been very extensively
- * modified from his work, due to the addition of DMA support
- * and due to differences in the hardware. The PI card is NOT
- * an Eagle card clone. It is an original design by Dave Perry,
- * VE3IFB. Art's copyright notice follows:
- *
- * Written by Art Goldman, WA3CVG - (c) Copyright 1987 All Rights Reserved
- * Permission for non-commercial use is hereby granted provided this notice
- * is retained. For info call: (301) 997-3838.
- *
- */
-
- #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 "pc.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
-
- static void xwrite_scc __ARGS((struct pichan *hp,int16 ctl,int16 reg,
- int16 val ));
- static char xread_scc __ARGS((struct pichan *hp, int16 ctl, char reg));
- static int32 pi_ctl __ARGS((struct iface *iface,int cmd,int set,int32 val));
- static int pi_raw __ARGS((struct iface *iface,struct mbuf *bp));
- static int pi_stop __ARGS((struct iface *iface));
- static void rts __ARGS((struct pichan *hp, int16 x));
- void setup_rx_dma __ARGS((struct pichan *hp));
- void setup_tx_dma __ARGS((struct pichan *hp, char *buffer, int length));
- static void set_acc_delay __ARGS((void));
- static void tdelay __ARGS((register struct pichan *hp,unsigned int time));
-
- static struct PITAB Pi[PIMAX]; /* Device table - one entry per card */
- static INTERRUPT (*pihandle[])() = { /* handler interrupt vector table */
- pi0vec,
- pi1vec,
- pi2vec
- };
- static int16 Page_regs[] = {
- 0x87,0x83,0x81,0x82,0,0x8b,0x89,0x8a
- };
- static struct pichan Pichan[2*PIMAX]; /* channel table - 2 entries per card */
- static int16 pinbr;
-
- extern int16 acc_delay; /* Delay for the 8530 chip access recovery time */
-
- /* Allocate a buffer which does not cross a dma page boundary */
- /* This really belongs in mbuf.c */
- struct mbuf *
- alloc_dmabuf(size)
- register int16 size;
- {
- struct mbuf *bp[20],*retbuf;
- unsigned buf_offset, buf_segment;
- long longseg, dma_abs, dma_page;
- int n;
-
- for(n = 0; n < 20 ;n++){
- if((bp[n] = alloc_mbuf(size)) == NULLBUF){
- /* Free the buffers which failed the test */
- while(--n >= 0)
- free_p(bp[n]);
- return(NULLBUF);
- }
- /* Calculate the DMA page */
- buf_offset = FP_OFF(bp[n]);
- buf_segment= FP_SEG(bp[n]);
- longseg = (long) buf_segment;
- dma_abs = (longseg << 4) + (long) buf_offset;
- dma_page = dma_abs >> 16;
- if(((dma_abs+size) >> 16) == dma_page){
- /* Save the one that passed */
- retbuf = bp[n];
- /* Free the buffers which failed the test */
- while(--n >= 0)
- free_p(bp[n]);
- return(retbuf);
- }
- }
- /* Free the buffers which failed the test */
- while(--n >= 0)
- free_p(bp[n]);
- return(NULLBUF);
- }
-
- /* 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 int16 ctl;
- int16 reg,val;
- {
- wrtscc(hp->cardbase,ctl,reg,val);
- }
-
- /* Read 8530 register */
- static char
- xread_scc(hp,ctl,reg)
- register struct pichan *hp;
- register int16 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 int16 pcbase;
- struct pichan *hp;
- struct PITAB *pip;
- void b_rxint(),b_txint(),b_exint();
- void a_rxint(),a_txint(),a_exint();
-
- 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 int16 cmd;
- char st;
- int length;
- int32 t,ca;
-
- DISABLE();
-
- 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:
- free_p(hp->sndbuf);
- hp->sndbuf = NULLBUF;
- hp->tstate = FLAGOUT;
- tdelay(hp,hp->squeldelay);
- break;
- case FLAGOUT:
- if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
- /* Nothing to send - return to receive mode */
- hp->tstate = IDLE;
- rts(hp,OFF);
- RESTORE();
- return;
- }
- /* 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);
-
- /* Get all chars */
- length = pullup(&hp->sndbuf,hp->txdmabuf,hp->bufsiz);
-
- /* Setup DMA controller for tx */
- setup_tx_dma(hp,hp->txdmabuf,length);
-
- /* 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();
- 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();
- return;
- }
- hp->deftime = t; /* Keep from getting too old */
- if((rand() & 0xff) > uchar(hp->persist)){
- hp->tstate = DEFER;
- tdelay(hp,hp->slotime);
- RESTORE();
- 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();
- return;
- } /* switch(hp->tstate) */
-
- RESTORE();
- } /* a_exint() */
-
- /* Receive interrupt handler for the A channel
- */
- static void
- a_rxint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- register int16 bytecount;
- char rse;
-
-
- hp->rxints++;
- cmd = hp->base+CTL;
-
- DISABLE();
- 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(hp->dma_wcr);
- bytecount += inportb(hp->dma_wcr) << 8;
- /* Allow for the extra space for the header */
- bytecount = (hp->bufsiz - 1 - sizeof(struct iface *)) - 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 */
- /* Toss 2 crc bytes */
- hp->rcvbuf->cnt = bytecount - 2;
- /* "Can't fail" */
- net_route(hp->iface,hp->rcvbuf);
- hp->rcvbuf = NULLBUF;
- hp->rxframes++;
-
- /* packet queued - get buffer for next frame */
- hp->rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct iface *));
- if(hp->rcvbuf != NULLBUF)
- /* Allow room for header */
- hp->rcvbuf->data += sizeof(struct iface *);
- setup_rx_dma(hp);
- } /* end good frame queued */
- } /* end EOF check */
-
- xwrite_scc(hp,hp->base+CTL,R0,ERR_RES); /* error reset */
- RESTORE();
- }
-
- void
- a_txint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- int32 t,ca;
-
- cmd = CTL+hp->base;
-
- DISABLE();
- switch(hp->tstate){
- case IDLE:
- /* Transmitter idle. Find a frame for transmission */
- if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
- rts(hp,OFF);
- RESTORE();
- return;
- }
- /* 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();
- 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();
- return;
- }
- hp->deftime = t; /* Keep from getting too old */
- if((rand() & 0xff) > uchar(hp->persist)){
- hp->tstate = DEFER;
- tdelay(hp,hp->slotime);
- RESTORE();
- 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();
- return;
- default:
- break;
- } /* end switch(hp->state) */
-
- RESTORE();
- } /*a_txint */
-
- static void
- b_rxint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- char rse;
-
- hp->rxints++;
- cmd = CTL+hp->base;
-
- DISABLE();
- 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->data;
- hp->rcvbuf->cnt = 0;
- hp->rstate = RXERROR; /* set error flag */
- hp->rovers++;
- } else if(hp->rcvbuf->cnt >= hp->bufsiz - sizeof(struct iface *)){
- /* Too large -- toss buffer */
- /* reset buffer pointers */
- hp->rcp = hp->rcvbuf->data;
- hp->rcvbuf->cnt = 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->rcvbuf->cnt++; /* 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->rcvbuf->cnt > 0){
- if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(hp->rcvbuf->cnt < 10)){
- if((hp->rcvbuf->cnt >= 10) && (rse & CRC_ERR))
- hp->crcerr++; /* Ignore noise */
-
- hp->rcp = hp->rcvbuf->data;
- hp->rcvbuf->cnt = 0;
- } else {
- /* Here we have a valid frame */
- hp->rcvbuf->cnt -= 2; /* Toss 2 crc bytes */
- /* "Can't fail" */
- net_route(hp->iface,hp->rcvbuf);
- hp->rxframes++;
-
- /* packet queued - get buffer for next frame */
- hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct iface *));
- if(hp->rcvbuf == NULLBUF){
- /* No memory - abort rx */
- xwrite_scc(hp,cmd,R3,Rx8);
- RESTORE();
- return;
- }
- hp->rcvbuf->data += sizeof(struct iface *);
- hp->rcp = hp->rcvbuf->data;
- hp->rcvbuf->cnt = 0;
- } /* end good frame queued */
- } /* end check for active receive upon EOF */
- hp->rstate = ACTIVE; /* and clear error status */
- } /* end EOF check */
-
- RESTORE();
- }
-
- static void
- b_txint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- char c;
-
- cmd = CTL+hp->base;
-
- DISABLE();
- if(hp->tstate != DEFER && hp->tstate)
- hp->txints++;
-
- switch(hp->tstate){
- case CRCOUT:
- hp->tstate = FLAGOUT;
- tdelay(hp,hp->squeldelay);
- RESTORE();
- return;
- case IDLE:
- /* Transmitter idle. Find a frame for transmission */
- if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
- /* Nothing to send - return to receive mode
- * Tx OFF now - flag should have gone
- */
- rts(hp,OFF);
- RESTORE();
- return;
- }
- /* 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();
- 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();
- return;
- }
- inportb(hp->cardbase+TMR0); /* Discard MSB */
-
- rts(hp,ON); /* Transmitter on */
- hp->tstate = ST_TXDELAY;
- tdelay(hp,hp->txdelay);
- RESTORE();
- return;
-
- case ACTIVE:
- /* Here we are actively sending a frame */
- if((c = PULLCHAR(&hp->sndbuf)) != -1){
- /* next char is gone */
- xwrite_scc(hp,cmd,R8,c);
- /* stuffing a char satisfies Interrupt condition */
- } else {
- /* No more to send */
- free_p(hp->sndbuf);
- 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();
- 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();
- return; /* back to wait for interrupt */
- } /* end switch */
- RESTORE();
- }
-
- /* 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 int16 cmd;
- char c;
-
- cmd = CTL+hp->base;
- hp->exints++;
- DISABLE();
- 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 */
- free_p(hp->sndbuf);
- xwrite_scc(hp,cmd,R0,SEND_ABORT);
- hp->tstate = FLAGOUT;
- hp->tunders++;
- tdelay(hp,hp->squeldelay);
- RESTORE();
- return;
- case UNDERRUN:
- hp->tstate = CRCOUT;
- RESTORE();
- return;
- case FLAGOUT:
- /* Find a frame for transmission */
- if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
- /* Nothing to send - return to receive mode
- * Tx OFF now - flag should have gone
- */
- rts(hp,OFF);
- hp->tstate = IDLE;
- RESTORE();
- return;
- }
- /* Get next char to send */
- pullup(&hp->sndbuf,&c,1); /* one char at a time */
- 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();
- 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();
- 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();
- return;
- }
- inportb(hp->cardbase+TMR0); /* Discard MSB */
-
- rts(hp,ON); /* Transmitter on */
- hp->tstate = ST_TXDELAY;
- tdelay(hp,hp->txdelay);
- RESTORE();
- return;
-
- case ST_TXDELAY:
-
- /* Get next char to send */
- pullup(&hp->sndbuf,&c,1); /* one char at a time */
- 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();
- 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->data;
- hp->rcvbuf->cnt = 0; /* rewind on DCD transition */
- }
- RESTORE();
- }
-
- /* SET Transmit or Receive Mode
- * Set RTS (request-to-send) to modem on Transmit
- */
- static void
- rts(hp,x)
- register struct pichan *hp;
- int16 x;
- {
- int16 tc;
- long br;
- int16 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->data;
- hp->rcvbuf->cnt = 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;
- {
- unsigned buf_offset, buf_segment;
- int cmd;
- long longseg, dma_abs, dma_page;
-
- cmd = hp->base+CTL;
-
- DISABLE();
- if(!hp->rcvbuf){
- /* No rx buffer available */
- RESTORE();
- return;
- }
-
- /* Calculate high order 4 bits of the buffer area and store
- * them in the DMA page register
- */
- buf_offset = FP_OFF(hp->rcvbuf->data);
- buf_segment= FP_SEG(hp->rcvbuf->data);
- longseg = (long) buf_segment;
- dma_abs = (longseg << 4) + (long) buf_offset;
- dma_page = dma_abs >> 16;
-
- if(((dma_abs + hp->bufsiz -1) >> 16) != dma_page)
- printf("PI: ERROR - RX DMA page boundary violation\n");
-
- /* 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(hp->page_addr,dma_page);/* Store in 64K DMA page */
- outportb(DMA_RESETFF,0); /* reset byte pointer flipflop */
- /* Output buffer start (dest) address */
- outportb(hp->dma_dest,dma_abs);
- outportb(hp->dma_dest,dma_abs >> 8);
- /* output DMA maximum byte count */
- outportb(hp->dma_wcr,hp->bufsiz - 1 - sizeof(struct iface *));
- outportb(hp->dma_wcr, (hp->bufsiz - 1 - sizeof(struct iface *)) >> 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();
- }
-
- void
- setup_tx_dma(hp,buffer,length)
- struct pichan *hp;
- char *buffer;
- int length;
- {
- unsigned buf_offset, buf_segment;
- long longseg, dma_abs, dma_page;
-
- DISABLE();
-
- /* Calculate high order 4 bits of the buffer area and store
- * them in the DMA page register
- */
-
- buf_offset = FP_OFF(buffer);
- buf_segment= FP_SEG(buffer);
- longseg = (long) buf_segment;
- dma_abs = (longseg << 4) + (long) buf_offset;
- dma_page = dma_abs >> 16;
-
- outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA chan */
- if(((dma_abs + length) >> 16) != dma_page)
- printf("PI: ERROR - TX DMA page boundary violation\n");
- --length; /* Adjust length for DMA chip */
- /* Set DMA mode register to single transfers, incrementing address,
- * no auto init, reads
- */
- outportb(DMA_MODE,DMA_TX_MODE|hp->dmachan);
-
- outportb(hp->page_addr,dma_page); /* Store in 64K DMA page */
- outportb(DMA_RESETFF,0); /* reset byte pointer flipflop */
- outportb(hp->dma_dest,dma_abs); /* Output buffer start (source) address */
- outportb(hp->dma_dest,dma_abs >> 8);
- /* output byte count */
- outportb(hp->dma_wcr,length);
- outportb(hp->dma_wcr, (length) >> 8);
-
- RESTORE();
- }
-
- /* Initialize pi controller parameters */
- static int
- scc_init(hp)
- register struct pichan *hp;
- {
- int16 tc;
- long br;
- register int16 cmd;
-
- /* 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
- DISABLE();
-
- switch(cmd & 2){
- case 2:
- xwrite_scc(hp,cmd,R9,CHRA); /* Reset channel A */
- xwrite_scc(hp,cmd,R2,0xff); /* Initialize interrupt vector */
- break;
- case 0:
- xwrite_scc(hp,cmd,R9,CHRB); /* Reset channel B */
- break;
- }
-
- /* Deselect all Rx and Tx interrupts */
- xwrite_scc(hp,cmd,R1,0);
-
- /* Turn off external interrupts (like CTS/CD) */
- xwrite_scc(hp,cmd,R15,0);
-
- /* X1 clock, SDLC mode */
- xwrite_scc(hp,cmd,R4,SDLC|X1CLK);
-
- /* Now some misc Tx/Rx parameters */
- /* CRC PRESET 1, NRZI Mode */
- if(hp->speed){
- xwrite_scc(hp,cmd,R10,CRCPS|NRZI);
- /* Tx Clk from BRG. Rcv Clk from DPLL, TRxC pin outputs DPLL */
- xwrite_scc(hp,cmd,R11,TCBR|RCDPLL|TRxCDP|TRxCOI);
- } else {
- xwrite_scc(hp,cmd,R10,CRCPS);
- /* Tx Clk from Trxcl. Rcv Clk from Rtxcl, TRxC pin is input */
- xwrite_scc(hp,cmd,R11,TCTRxCP);
- }
-
- /* Null out SDLC start address */
- xwrite_scc(hp,cmd,R6,0);
-
- /* SDLC flag */
- xwrite_scc(hp,cmd,R7,FLAG);
-
- /* Set up the Transmitter but don't enable it
- * DTR, 8 bit TX chars only - TX NOT ENABLED
- */
- xwrite_scc(hp,cmd,R5,Tx8|DTR);
-
- /* Receiver - intial setup only - more later */
- xwrite_scc(hp,cmd,R3,Rx8); /* 8 bits/char */
-
- /* Setting up BRG now - turn it off first */
- xwrite_scc(hp,cmd,R14,BRSRC); /* BRG off, but keep Pclk source */
-
- /* set the 32x time constant for the BRG in Receive mode */
-
- if(hp->speed){
- br = hp->speed; /* get desired speed */
- tc = ((XTAL/32)/br)-2; /* calc 32X BRG divisor */
- } else {
- tc = 14;
- }
-
- xwrite_scc(hp,cmd,R12,tc&0xFF); /* lower byte */
- xwrite_scc(hp,cmd,R13,(tc>>8)&0xFF); /* upper byte */
-
- /* Following subroutine sets up and ENABLES the receiver */
- rts(hp,OFF); /* TX OFF and RX ON */
-
- if(hp->speed){
- /* DPLL frm BRG, BRG src PCLK */
- xwrite_scc(hp,cmd,R14,BRSRC|SSBR);
- } else {
- /* DPLL frm rtxc,BRG src PCLK */
- xwrite_scc(hp,cmd,R14,BRSRC|SSRTxC);
- }
- xwrite_scc(hp,cmd,R14,BRSRC|SEARCH); /* SEARCH mode, keep BRG source */
- xwrite_scc(hp,cmd,R14,BRSRC|BRENABL);/* Enable the BRG */
-
- if(!(cmd & 2)) /* if channel b */
- xwrite_scc(hp,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
-
- xwrite_scc(hp,cmd,R15,BRKIE); /* ABORT int */
-
- /* Now, turn on the receiver and hunt for a flag */
- xwrite_scc(hp,cmd,R3,RxENABLE|RxCRC_ENAB|Rx8);
-
- RESTORE();
- return 0;
- }
-
- /* Process to recover from ibuffails.
- * This could be done in the function network() in config.c,
- * to save a context switch. I put it here so the driver would
- * be more self contained.
- */
- void
- buf_recover(unused,b,a)
- int unused;
- void *b; /* Unused */
- void *a; /* Unused */
- {
- struct pichan *hp0, *hp1;
- int i;
-
- for(;;){
- pwait(NULL);
-
- for(i=0; i<pinbr; i++){ /* for each card */
- hp0 = &Pichan[i];
- hp1 = &Pichan[i + 1];
- if(!hp0->rcvbuf){ /* No rx buffer allocated */
- DISABLE();
- hp0->rcvbuf = alloc_mbuf(hp0->bufsiz + sizeof(struct iface *));
- if(hp0->rcvbuf != NULLBUF)
- hp0->rcvbuf->data += sizeof(struct iface *);
- RESTORE();
- setup_rx_dma(hp0);
- }
- DISABLE();
- if(!hp1->rcvbuf && (hp1->rstate == ACTIVE)){
- /* No rx buf allocated */
- if((hp1->rcvbuf = alloc_mbuf(hp1->bufsiz+sizeof(struct iface *))) != NULL){
- hp1->rcvbuf->data += sizeof(struct iface *);
- hp1->rcp = hp1->rcvbuf->data;
- hp1->rcvbuf->cnt = 0;
- xwrite_scc(hp1,CTL+hp1->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
- }
- }
- RESTORE();
- }
- }
- }
-
- /* Attach a PI interface to the system
- * argv[0]: hardware type, must be "pi"
- * argv[1]: I/O address, e.g., "0x300"
- * argv[2]: vector, e.g., "2"
- * argv[3]: dma channel (1..3)
- * argv[4]: mode, must be:
- * "ax25" (AX.25 UI frame format)
- * argv[5]: interface label, e.g., "pi0"
- * argv[6]: receiver packet buffer size in bytes
- * argv[7]: maximum transmission unit, bytes
- * argv[8]: channel A interface speed, e.g, "1200", 0 = ext. clock
- * argv[9]: channel B interface speed
- * argv[10]: First IP address, optional (defaults to Ip_addr);
- * argv[11]: Second IP address, optional (defaults to Ip_addr);
- */
- int
- pi_attach(argc,argv)
- int argc;
- char *argv[];
- {
- struct mbuf *bp;
- extern void refiq();
- register struct iface *if_pca,*if_pcb;
- struct pichan *hp;
- int dev;
- int n;
- char *cp;
-
- refiq(); /* replenish interrupt buffer pool (in mbuf.c) */
- if(acc_delay == 0){ /* Only do this once */
- /* Adapt recovery time delay to processor speed */
- set_acc_delay();
- }
- /* Quick check to make sure args are good and mycall is set */
- if(strcmp(argv[4],"ax25") != 0){
- printf("PI: Mode %s unknown for interface %s\n",
- argv[4],argv[5]);
- return -1;
- }
- if(if_lookup(argv[5]) != NULLIF){
- printf("PI: Interface %s already exists\n",argv[5]);
- return -1;
- }
- if(Mycall[0] == '\0'){
- printf("PI: Set mycall first\n");
- return -1;
- }
- /* Note: each card must have a unique address, IRQ and DMA */
-
- if(pinbr >= PIMAX){
- printf("PI: Maximum of %d PI cards supported\n",PIMAX);
- return -1;
- }
- dev = pinbr++;
-
- /* Initialize hardware-level control structure */
- Pi[dev].addr = htoi(argv[1]);
- Pi[dev].vec = atoi(argv[2]);
- if(strchr(argv[2],'c') != NULLCHAR)
- Pi[dev].chain = 1;
- else
- Pi[dev].chain = 0;
-
- /* Set up counter chip */
- /* 500 uS square wave */
- outportb(Pi[dev].addr+TMRCMD, SC0|LSB_MSB|MODE3);
- for(n=0; n<5;n++) /* satisfy access time restriction */
- ;
- outportb(Pi[dev].addr+TMR0, 922 & 0xFF);
- for(n=0; n<5;n++) /* satisfy access time restriction */
- ;
- outportb(Pi[dev].addr+TMR0, 922 >> 8);
- for(n=0; n<5;n++) /* satisfy access time restriction */
- ;
-
- /* Save original interrupt vector */
- Pi[dev].oldvec = getirq(Pi[dev].vec);
-
- /* Set new interrupt vector */
- if(setirq(Pi[dev].vec,pihandle[dev]) == -1){
- printf("PI: IRQ %u out of range\n",Pi[dev].vec);
- pinbr--;
- return -1;
- }
-
- if((atoi(argv[3]) < 1) || (atoi(argv[3]) > 3)){
- printf("PI: DMA %d out of range\n",atoi(argv[3]));
- pinbr--;
- return -1;
- }
-
- /* Create interface structures and fill in details */
- if_pca = (struct iface *)callocw(1,sizeof(struct iface));
- if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
-
- if_pca->addr = if_pcb->addr = Ip_addr;
- if(argc > 10)
- if_pca->addr = resolve(argv[10]);
- if(argc > 11)
- if_pcb->addr = resolve(argv[11]);
-
- if(if_pca->addr == 0 || if_pcb->addr == 0){
- printf("PI: No IP address");
- free((char *)if_pca);
- free((char *)if_pcb);
- return -1;
- }
- /* Append "a" to interface associated with A channel */
- if_pca->name = malloc((unsigned)strlen(argv[5])+2);
- strcpy(if_pca->name,argv[5]);
- strcat(if_pca->name,"a");
- /* Append "b" to interface associated with B channel */
- if_pcb->name = malloc((unsigned)strlen(argv[5])+2);
- strcpy(if_pcb->name,argv[5]);
- strcat(if_pcb->name,"b");
-
- if_pcb->mtu = if_pca->mtu = atoi(argv[7]);
- if_pcb->ioctl = if_pca->ioctl = pi_ctl;
- if_pca->dev = 2*dev; /* pi0a */
- if_pcb->dev = 2*dev + 1; /* pi0b */
- if_pcb->stop = if_pca->stop = pi_stop;
- if_pcb->raw = if_pca->raw = pi_raw;
-
- if(strcmp(argv[4],"ax25") == 0){
- /* Must be true, was checked at top */
- setencap(if_pca,"AX25");
- setencap(if_pcb,"AX25");
- if(if_pcb->hwaddr == NULLCHAR)
- if_pcb->hwaddr = mallocw(AXALEN);
- memcpy(if_pcb->hwaddr,Mycall,AXALEN);
- if(if_pca->hwaddr == NULLCHAR)
- if_pca->hwaddr = mallocw(AXALEN);
- memcpy(if_pca->hwaddr,Mycall,AXALEN);
- }
- /* Link em in to the interface chain */
- if_pca->next = if_pcb;
- if_pcb->next = Ifaces;
- Ifaces = if_pca;
-
- /* set params in pichan table for CHANNEL B */
- hp = &Pichan[2*dev+1]; /* pi1 is offset 1 */
- hp->dmachan = 0; /* Channel B does not have dma */
- hp->cardbase = Pi[dev].addr;
- hp->iface = if_pcb;
- hp->stata = Pi[dev].addr + CHANA + CTL; /* permanent status */
- hp->statb = Pi[dev].addr + CHANB + CTL; /* addrs for CHANA/B*/
- hp->speed = (int16)atoi(argv[9]);
- hp->base = Pi[dev].addr + CHANB;
- hp->bufsiz = atoi(argv[6]);
- hp->tstate = IDLE;
- /* default channel access Params */
- hp->txdelay = 30; /* 300 Ms */
- hp->persist = 128; /* 50% persistence */
- hp->slotime = 30; /* 300 Ms */
- hp->squeldelay = 3; /* 30 Ms */
-
- xwrite_scc(hp,CTL+hp->stata,R9,FHWRES); /* Hardware reset */
- /* one time only */
- /* Disable interrupts with Master interrupt ctrl reg */
- xwrite_scc(hp,CTL+hp->stata,R9,0);
-
- scc_init(hp);
-
- /* Pre-allocate a receive buffer */
- DISABLE();
- hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct iface *));
- RESTORE();
- if(hp->rcvbuf == NULLBUF){
- /* No memory, abort receiver */
- printf("PI: No memory available for receive buffers\n");
- /* Restore original interrupt vector */
- setirq(Pi[dev].vec,Pi[dev].oldvec);
- pinbr--;
- return -1;
- }
- hp->rcvbuf->data += sizeof(struct iface *);
- hp->rcp = hp->rcvbuf->data;
- hp->rcvbuf->cnt = 0;
- hp->sndq = NULLBUF;
-
- /* set params in pichan table for CHANNEL A */
- hp = &Pichan[2*dev]; /* pi0a is offset 0 */
- hp->dmachan = (unsigned char)atoi(argv[3]);
- /* Figure out where the dma page register is. */
- if(hp->dmachan < 8 && hp->dmachan >= 0){
- hp->page_addr = Page_regs[hp->dmachan];
- } else {
- printf("PI: DMA channel %d out of range\n",hp->dmachan);
- free_p(hp->rcvbuf);
- /* Restore original interrupt vector */
- setirq(Pi[dev].vec,Pi[dev].oldvec);
- pinbr--;
- return -1;
- }
-
- hp->dma_dest = hp->dmachan * 2;
- hp->dma_wcr = hp->dma_dest + 1;
-
- hp->cardbase = Pi[dev].addr;
- hp->iface = if_pca;
- hp->speed = (int16)atoi(argv[8]);
- hp->base = Pi[dev].addr + CHANA;
- hp->bufsiz = atoi(argv[6]);
- hp->tstate = IDLE;
- /* default channel access Params */
- hp->txdelay = 15; /* 15 mS */
- hp->persist = 128; /* 50% persistence */
- hp->slotime = 15; /* 15 mS */
- hp->squeldelay = 1; /* 1 mS */
- newproc("buf_recover",256,buf_recover,0,hp,NULL,0);
-
- /* Pre-allocate a receive buffer */
- /* buffer is allocated with ints off */
- DISABLE();
- hp->rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct iface *));
- RESTORE();
- if(hp->rcvbuf == NULLBUF){
- /* No memory, abort receiver */
- printf("PI: No memory available for receive buffers\n");
- /* Restore original interrupt vector */
- setirq(Pi[dev].vec,Pi[dev].oldvec);
- pinbr--;
- return -1;
- }
- hp->rcvbuf->data += sizeof(struct iface *);
- hp->rcvbuf->cnt = 0;
- hp->sndq = NULLBUF;
-
- /* Get a buffer for tx which does not cross a dma boundary */
- /* buffer is allocated with ints off */
- DISABLE();
- bp = alloc_mbuf(hp->bufsiz);
- if(bp != NULLBUF)
- hp->txdmabuf = bp->data;
- else
- hp->txdmabuf = NULLCHAR;
- RESTORE();
- if(!hp->txdmabuf)
- printf("PI: No memory available for transmit buffer");
-
- scc_init(hp);
- /* master interrupt enable */
- xwrite_scc(hp,CTL+hp->base,R9,MIE|NV);
-
- /* Enable interrupt */
- maskon(Pi[dev].vec);
-
- cp = if_name(if_pca," tx");
- if_pca->txproc = newproc(cp,512,if_tx,0,if_pca,NULL,0);
- free(cp);
- cp = if_name(if_pcb," tx");
- if_pcb->txproc = newproc(cp,512,if_tx,0,if_pcb,NULL,0);
- free(cp);
- return 0;
- }
-
- /* Shut down interface */
- int
- pi_stop(iface)
- struct iface *iface;
- {
- int16 dev;
- struct pichan *hp;
-
- dev = iface->dev;
- if(dev & 1) /* Because there are 2 devices per card */
- return 0;
- dev >>= 1; /* Convert back into pi number */
- hp = &Pichan[2*dev]; /* pi0a is offset 0 */
-
- outportb(DMA_MASK, DMA_DISABLE|hp->dmachan); /* Disable DMA channel */
-
- /* Turn off interrupts */
- maskoff(Pi[dev].vec);
-
- /* Restore original interrupt vector */
- setirq(Pi[dev].vec,Pi[dev].oldvec);
-
- /* Force hardware reset */
- xwrite_scc(&Pichan[2*dev],CTL+Pi[dev].addr + CHANA,R9,FHWRES);
-
- return 0;
- }
-
- /* Send raw packet on pi card */
- int
- pi_raw(iface,bp)
- struct iface *iface;
- struct mbuf *bp;
- {
- char kickflag;
- struct pichan *hp;
-
- dump(iface,IF_TRACE_OUT,bp);
- iface->rawsndcnt++;
- iface->lastsent = secclock();
-
- hp = &Pichan[iface->dev];
- kickflag = (hp->sndq == NULLBUF) & (hp->sndbuf == NULLBUF);
- enqueue(&hp->sndq,bp);
- hp->enqueued++;
- if(kickflag){
- /* simulate interrupt to xmit */
- switch(hp->base & 2){
- case 2:
- a_txint(hp); /* process interrupt */
- break;
- case 0:
- DISABLE();
- if(hp->tstate == IDLE)
- b_txint(hp);
- RESTORE();
- break;
- }
- }
- return 0;
- }
-
- /* display PI Channel stats */
- int
- dopistat()
- {
- struct pichan *hp;
- int i;
-
- printf("PI Board Statistics:\n\n");
- printf("Base Addr Rxints Txints Exints TxFrms RxFrms Crcerr RxOvrs TxUndr \n");
- printf("--------- ------ ------ ------ ------ ------ ------ ------ ------ \n");
- for(i=0; i<pinbr*2; i++){
- hp = &Pichan[i];
-
- printf("0x%03x % 8lu% 8lu% 8lu% 8u% 8u% 8u% 8u% 8u\nRcv State=%s ",
- hp->base, hp->rxints, hp->txints, hp->exints, hp->enqueued,
- hp->rxframes, hp->crcerr, hp->rovers, hp->tunders,
- hp->rstate==0 ?
- "IDLE" : hp->rstate==1 ?
- "ACTIVE" : hp->rstate==2 ?
- "RXERROR" : hp->rstate==3 ?
- "RXABORT":"TOOBIG"
- );
-
- printf("Tstate = %s\n",
- hp->tstate == 0 ?
- "IDLE" : hp->tstate == 1 ?
- "ACTIVE" : hp->tstate == 2 ?
- "UNDERRUN" : hp->tstate == 3 ?
- "FLAGOUT" : hp->tstate == 4 ?
- "DEFER" : hp->tstate == 5 ?
- "TXDELAY" : "CRCOUT"
- );
- }
- return 0;
- }
-
- /* Subroutine to set kiss params in channel tables */
- int32
- pi_ctl(iface,cmd,set,val)
- struct iface *iface;
- int cmd;
- int set;
- int32 val;
- {
- struct pichan *hp;
- int32 t,ca;
-
- hp = &Pichan[iface->dev]; /* point to channel table */
- switch(cmd){
- case PARAM_TXDELAY:
- if(set)
- hp->txdelay = val;
- return hp->txdelay;
- case PARAM_PERSIST:
- if(set)
- hp->persist = val;
- return uchar(hp->persist);
- case PARAM_SLOTTIME:
- if(set)
- hp->slotime = val;
- return hp->slotime;
- case PARAM_TXTAIL:
- if(set)
- hp->squeldelay = val;
- return hp->squeldelay;
- case PARAM_MUTE:
- 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;
- }
-