home *** CD-ROM | disk | FTP | other *** search
- /*
- * Interface driver for the VE3IFB 8530 card (PI card)
- * Copyright 1990 by Dave Perry, VE3IFB
- *
- * 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 <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 "8530.h"
- #include "ax25.h"
- #include "trace.h"
- #include "pc.h"
- #include <time.h>
-
- #include "session.h"
- #include "lapb.h"
- #include "proc.h"
- #include "ip.h"
-
- #define FP_OFF(fp) ((unsigned)(fp))
- #define FP_SEG(fp) ((unsigned)((unsigned long)(fp) >> 16))
-
- 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 int pi_ctl __ARGS((struct iface *iface,int argc,char *argv[]));
- 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 struct PITAB Pi[PIMAX]; /* Device table - one entry per card */
- static INTERRUPT (*pihandle[])() = { /* handler interrupt vector table */
- pi0vec,
- pi1vec,
- pi2vec
- };
- 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)
- {
- while(--n >= 0) /* Free the buffers which failed the test */
- 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)
- {
- retbuf = bp[n]; /* Save the one that passed */
- while(--n >= 0) /* Free the buffers which failed the test */
- free_p(bp[n]);
- return(retbuf);
- }
- }
- while(--n >= 0) /* Free the buffers which failed the test */
- 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).
- */
- set_acc_delay()
- {
- long starttime, endtime;
- int n;
- int ticks;
-
- starttime = biostime(0,0l);
- for(n = 0; n < 10; n++)
- mloop();
- endtime = biostime(0,0l);
- 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 tdelay(hp,time)
- register struct pichan *hp;
- unsigned char time; /* Time to delay in milliseconds */
- { int n;
- int port, 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;
- }
-
- outportb(hp->cardbase+TMRCMD, sc|LSB_MSB|MODE0); /* Setup timer sc */
- for(n=0; n<5;n++) ; /* satisfy access time restriction */
- outportb(port, (t1 << 1) & 0xFF);/* times 2 to make millisecs */
- for(n=0; n<5;n++) ; /* satisfy access time restriction */
- outportb(port, (t1 >> 7) & 0xFF);
-
- xwrite_scc(hp,hp->base+CTL,R15,CTSIE); /* Enable correct int for timeout */
- 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.
- */
- void
- piint(dev)
- int dev;
- {
- register char st;
- register int16 pcbase;
- struct pichan *hp;
- void b_rxint(),b_txint(),b_exint();
- void a_rxint(),a_txint(),a_exint();
-
- Pi[dev].ints++;
- pcbase = Pi[dev].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 */
- }
-
- static void
- a_exint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- char st, i_state;
- int i,length;
-
- i_state = dirps(); /* disable interrupts */
-
- 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->params[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(i_state);
- return;
- }
- /* NOTE - fall through if more to send */
- case ST_TXDELAY:
- outportb(DMA_MASK, DMA_DISABLE|hp->dmachan);/* Disable DMA chan */
- xwrite_scc(hp,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB);/*Set up for TX dma*/
- length = pullup(&hp->sndbuf,hp->txdmabuf,hp->bufsiz); /* Get all chars */
- setup_tx_dma(hp,hp->txdmabuf,length);/* Setup DMA controller for tx */
- /* select transmit interrupts to enable */
- outportb(DMA_MASK,DMA_ENABLE|hp->dmachan);/* Allow DMA on chan */
- xwrite_scc(hp,cmd,R0,RES_Tx_CRC|RES_Tx_P);/* reset CRC, Txint pend*/
- xwrite_scc(hp,cmd,R15,TxUIE); /* allow Underrun int only */
- /* Enable TX DMA */
- xwrite_scc(hp,cmd,R1,WT_RDY_ENAB|WT_FN_RDYFN|EXT_INT_ENAB);
- xwrite_scc(hp,cmd,R0,RES_EOM_L); /* Send CRC on underrun */
- /* Rest of frame sent by DMA */
- hp->tstate = ACTIVE; /* packet going out now */
- 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(i_state);
- return;
- }
-
- if((rand() & 0xff) > uchar(hp->params[PERSIST]))
- {
- hp->tstate = DEFER;
- tdelay(hp,hp->params[SLOTIME]);
- restore(i_state);
- return;
- }
-
- xwrite_scc(hp,cmd,R5,TxCRC_ENAB|RTS|Tx8);/* Assert RTS early minimize */
- /* collision window */
- rts(hp,ON); /* Transmitter on */
- hp->tstate = ST_TXDELAY;
- tdelay(hp,hp->params[TXDELAY]);
- restore(i_state);
- return;
-
- } /* switch(hp->tstate) */
-
- restore(i_state);
- } /* 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, i_state;
- struct mbuf *bp;
- struct phdr *phdr;
-
- i_state = dirps(); /* disable interrupts */
- hp->rxints++;
- cmd = hp->base+CTL;
-
- 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;
- bytecount = (hp->bufsiz - 1) - bytecount;
-
- if((rse & CRC_ERR)||(hp->rstate > ACTIVE)||(bytecount < 10))
- {
- if((bytecount >= 10) && (rse & CRC_ERR)) /* Ignore noise */
- hp->crcerr++;
-
- /* Reset buffer pointers */
- hp->rstate = ACTIVE;
- setup_rx_dma(hp);
- }
- else
- {
- /* Here we have a valid frame */
- hp->rcvbuf->cnt = bytecount - 2; /* Toss 2 crc bytes */
- bp = alloc_mbuf(sizeof(struct phdr));
- if(!bp)
- {
- setup_rx_dma(hp);
- xwrite_scc(hp,hp->base+CTL,R0,ERR_RES); /* error reset */
- restore(i_state);
- return;
- };
- bp->cnt = sizeof(struct phdr);
- phdr = (struct phdr *)bp->data;
- phdr->type = CL_AX25;
- phdr->iface = hp->iface;
- bp->next = hp->rcvbuf;
- hp->rcvbuf = NULLBUF;
- enqueue(&Hopper,bp); /* queue it in */
- hp->rxframes++;
-
- /* packet queued - get buffer for next frame */
- hp->rcvbuf = alloc_mbuf(hp->bufsiz);
- setup_rx_dma(hp);
- } /* end good frame queued */
- } /* end EOF check */
-
- xwrite_scc(hp,hp->base+CTL,R0,ERR_RES); /* error reset */
- restore(i_state);
- }
-
- void
- a_txint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- char i_state;
-
- i_state = dirps();
- cmd = CTL+hp->base;
-
- switch(hp->tstate)
- {
- case IDLE:
- /* Transmitter idle. Find a frame for transmission */
- if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
- {
- rts(hp,OFF);
- restore(i_state);
- 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(i_state);
- return;
- }
-
- if((rand() & 0xff) > uchar(hp->params[PERSIST]))
- {
- hp->tstate = DEFER;
- tdelay(hp,hp->params[SLOTIME]);
- restore(i_state);
- return;
- }
-
- xwrite_scc(hp,cmd,R5,TxCRC_ENAB|RTS|Tx8);/* Assert RTS early minimize */
- /* collision window */
- rts(hp,ON); /* Transmitter on */
- hp->tstate = ST_TXDELAY;
- tdelay(hp,hp->params[TXDELAY]);
- restore(i_state);
- return;
-
- default:
- break;
- } /* end switch(hp->state) */
-
- restore(i_state);
- } /*a_txint */
-
- static void
- b_rxint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- char rse, i_state;
- struct mbuf *bp;
- struct phdr *phdr;
-
- i_state = dirps(); /* disable interrupts */
- hp->rxints++;
- cmd = CTL+hp->base;
-
- 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 */
- hp->rcp = hp->rcvbuf->data; /* reset buffer pointers */
- hp->rcvbuf->cnt = 0;
- hp->rstate = RXERROR; /* set error flag */
- hp->rovers++;
- } else if(hp->rcvbuf->cnt >= hp->bufsiz) {
- /* Too large -- toss buffer */
- hp->rcp = hp->rcvbuf->data; /* reset buffer pointers */
- 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))/* Ignore noise */
- hp->crcerr++;
-
- hp->rcp = hp->rcvbuf->data;
- hp->rcvbuf->cnt = 0;
- } else {
- /* Here we have a valid frame */
- hp->rcvbuf->cnt -= 2; /* Toss 2 crc bytes */
- bp = alloc_mbuf(sizeof(struct phdr));
- if(!bp) /* we can't get memory - throw it away */
- {
- hp->rcp = hp->rcvbuf->data;
- hp->rcvbuf->cnt = 0;
- restore(i_state);
- return;
- }
- bp->cnt = sizeof(struct phdr);
- phdr = (struct phdr *)bp->data;
- phdr->type = CL_AX25;
- phdr->iface = hp->iface;
- bp->next = hp->rcvbuf;
- enqueue(&Hopper,bp); /* queue it in */
- hp->rxframes++;
-
- /* packet queued - get buffer for next frame */
- hp->rcvbuf = alloc_mbuf(hp->bufsiz);
- if(hp->rcvbuf == NULLBUF) {
- xwrite_scc(hp,cmd,R3,Rx8); /* No memory - abort rx */
- restore(i_state);
- return;
- }
- 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(i_state);
- }
-
- static void
- b_txint(hp)
- register struct pichan *hp;
- {
- register int16 cmd;
- char i_state,c;
-
- i_state = dirps();
- cmd = CTL+hp->base;
-
- if(hp->tstate != DEFER && hp->tstate)
- hp->txints++;
-
- switch(hp->tstate) {
- case CRCOUT:
- hp->tstate = FLAGOUT;
- tdelay(hp,hp->params[SQUELDELAY]);
- restore(i_state);
- 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(i_state);
- 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(i_state);
- return;
- }
-
- /* p - persist calculation */
- if(inportb(hp->cardbase+TMR0) > hp->params[PERSIST])
- { inportb(hp->cardbase+TMR0); /* Discard MSB */
- hp->tstate = DEFER;
- tdelay(hp,hp->params[SLOTIME]);
- restore(i_state);
- return;
- }
- inportb(hp->cardbase+TMR0); /* Discard MSB */
-
- rts(hp,ON); /* Transmitter on */
- hp->tstate = ST_TXDELAY;
- tdelay(hp,hp->params[TXDELAY]);
- restore(i_state);
- return;
-
- case ACTIVE:
- /* Here we are actively sending a frame */
- if((c = PULLCHAR(&hp->sndbuf)) != -1){
- xwrite_scc(hp,cmd,R8,c); /* next char is gone */
- /* 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->params[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, i_state;
- register int16 cmd;
- char c;
-
- cmd = CTL+hp->base;
- i_state = dirps(); /* disable interrupts */
- hp->exints++;
- 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->params[SQUELDELAY]);
- restore(i_state);
- return;
- case UNDERRUN:
- hp->tstate = CRCOUT;
- restore(i_state);
- 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(i_state);
- 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(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->params[PERSIST])
- { inportb(hp->cardbase+TMR0); /* Discard MSB */
- hp->tstate = DEFER;
- tdelay(hp,hp->params[SLOTIME]);
- restore(i_state);
- return;
- }
- inportb(hp->cardbase+TMR0); /* Discard MSB */
-
- rts(hp,ON); /* Transmitter on */
- hp->tstate = ST_TXDELAY;
- tdelay(hp,hp->params[TXDELAY]);
- restore(i_state);
- 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);
- 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;
-
- }
-
- /* 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(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;
- 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 */
- xwrite_scc(hp,cmd,R15,0); /* Exints off first to avoid abort int */
- xwrite_scc(hp,cmd,R3,Rx8); /* Rx off */
- hp->rstate = IDLE;
- if(cmd & 2) /* if channel a */
- xwrite_scc(hp,cmd,R1,WT_FN_RDYFN|EXT_INT_ENAB); /* Set up for TX dma */
- 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 */
- xwrite_scc(hp,cmd,R14,BRSRC); /* BRG off, keep Pclk source */
- br = hp->speed; /* get desired speed */
- tc = ((XTAL/32)/br)-2; /* calc 32X BRG divisor */
- xwrite_scc(hp,cmd,R12,tc&0xFF); /* lower byte */
- xwrite_scc(hp,cmd,R13,(tc>>8)&0xFF); /* upper bite */
- xwrite_scc(hp,cmd,R14,BRSRC|SEARCH); /* SEARCH mode, BRG source */
- xwrite_scc(hp,cmd,R14,BRSRC|BRENABL); /* Enable the BRG */
- }
-
- /* 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 {
- /* xwrite_scc(hp,cmd,R0,ERR_RES); */ /* reset error bits */
- hp->rcp = hp->rcvbuf->data; /* reset buffer pointers */
- hp->rcvbuf->cnt = 0;
- xwrite_scc(hp,cmd,R1,(INT_ALL_Rx|EXT_INT_ENAB));
- }
-
- xwrite_scc(hp,cmd,R15,BRKIE); /* allow ABORT int */
- }
- }
-
- void
- setup_rx_dma(hp)
- register struct pichan *hp;
- {
- unsigned buf_offset, buf_segment;
- int cmd;
- char dummy;
- long longseg, dma_abs, dma_page;
- char i_state;
-
- i_state = dirps(); /* disable interrupts */
-
- cmd = hp->base+CTL;
-
- if(!hp->rcvbuf) /* No rx buffer available */
- { restore(i_state);
- 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;
-
- /* 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 */
- outportb(hp->dma_dest,dma_abs); /* Output buffer start (dest) address */
- outportb(hp->dma_dest,dma_abs >> 8);
- /* output DMA maximum byte count */
- outportb(hp->dma_wcr,hp->bufsiz - 1);
- outportb(hp->dma_wcr, (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,buffer,length)
- struct pichan *hp;
- char *buffer;
- int length;
- {
- unsigned buf_offset, buf_segment;
- long longseg, dma_abs, dma_page;
- char i_state;
-
- i_state = dirps(); /* disable interrupts */
-
- /* 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)
- tprintf("PI: ERROR - 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(i_state);
- }
-
- /* Initialize pi controller parameters */
- static int
- scc_init(hp)
- register struct pichan *hp;
- {
- int16 tc;
- long br;
- char i_state;
- register int16 cmd;
-
- /* Initialize 8530 channel for SDLC operation */
-
- cmd = CTL+hp->base;
- #ifdef notdef
- tprintf("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 */
- 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); /* SDLC mode and X1 clock */
-
- /* 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 bite */
-
- /* Following subroutine sets up and ENABLES the receiver */
- rts(hp,OFF); /* TX OFF and RX ON */
-
- if(hp->speed)
- xwrite_scc(hp,cmd,R14,BRSRC|SSBR);/*DPLL frm BRG, BRG src PCLK */
- else
- xwrite_scc(hp,cmd,R14,BRSRC|SSRTxC);/*DPLL frm rtxc,BRG src PCLK */
-
- 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(i_state);
- 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;
- char i_state;
- 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 */
- {
- i_state = dirps();
- hp0->rcvbuf = alloc_mbuf(hp0->bufsiz);
- restore(i_state);
- setup_rx_dma(hp0);
- }
- i_state = dirps();
- if(!hp1->rcvbuf && (hp1->rstate == ACTIVE))/* No rx buf allocated */
- {
- if((hp1->rcvbuf = alloc_mbuf(hp1->bufsiz)) != NULL)
- {
- hp1->rcp = hp1->rcvbuf->data;
- hp1->rcvbuf->cnt = 0;
- xwrite_scc(hp1,CTL+hp1->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
- }
- }
- restore(i_state);
- }
- }
- }
-
- /* 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[];
- {
- extern void refiq();
- register struct iface *if_pca,*if_pcb;
- struct pichan *hp;
- int dev;
- char i_state;
- int n;
-
- refiq(); /* replenish interrupt buffer pool (in mbuf.c) */
- if(acc_delay == 0) /* Only do this once */
- set_acc_delay();/* Adapt recovery time delay to processor speed */
-
- /* Quick check to make sure args are good and mycall is set */
- if(strcmp(argv[4],"ax25") != 0){
- tprintf("PI: Mode %s unknown for interface %s\n",
- argv[4],argv[5]);
- return -1;
- }
- if(if_lookup(argv[5]) != NULLIF){
- tprintf("PI: Interface %s already exists\n",argv[5]);
- return -1;
- }
- if(Mycall[0] == '\0'){
- tprintf("PI: Set mycall first\n");
- return -1;
- }
- /* Note: each card must have a unique address, IRQ and DMA
- */
-
- if(pinbr >= PIMAX) {
- tprintf("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 = htoi(argv[2]);
-
- /* Set up counter chip */
- outportb(Pi[dev].addr+TMRCMD, SC0|LSB_MSB|MODE3); /* 500 uS square wave */
- 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){
- tprintf("PI: IRQ %u out of range\n",Pi[dev].vec);
- pinbr--;
- return -1;
- }
-
- if((atoi(argv[3]) < 1) || (atoi(argv[3]) > 3)){
- tprintf("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){
- tprintf("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->type = if_pca->type = CL_AX25;
- 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->output = if_pca->output = ax_output;
- if_pcb->raw = if_pca->raw = pi_raw;
-
- if(strcmp(argv[4],"ax25") == 0) {
- /* Must be true, was checked at top */
- if_pcb->send = if_pca->send = ax_send;
- 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 KISS Params */
- hp->params[TXDELAY] = 30; /* 300 Ms */
- hp->params[PERSIST] = 128; /* 50% persistence */
- hp->params[SLOTIME] = 30; /* 300 Ms */
- hp->params[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 */
- i_state = dirps();
- hp->rcvbuf = alloc_mbuf(hp->bufsiz);
- restore(i_state);
- if(hp->rcvbuf == NULLBUF) {
- /* No memory, abort receiver */
- tprintf("PI: No memory available for receive buffers\n");
- /* Restore original interrupt vector */
- setirq(Pi[dev].vec,Pi[dev].oldvec);
- pinbr--;
- return(-1);
- }
- 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. */
- switch(hp->dmachan) {
- case 0:
- case 1:
- hp->page_addr = 0x83;
- break;
- case 2:
- hp->page_addr = 0x81;
- break;
- case 3:
- hp->page_addr = 0x82;
- break;
- }
- 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 KISS Params */
- hp->params[TXDELAY] = 15; /* 15 mS */
- hp->params[PERSIST] = 128; /* 50% persistence */
- hp->params[SLOTIME] = 15; /* 15 mS */
- hp->params[SQUELDELAY] = 1; /* 1 mS */
- newproc("buf_recover",256,buf_recover,0,hp,NULL,0);
-
-
- /* Pre-allocate a receive buffer */
- i_state = dirps();/* buffer is allocated with ints off */
- hp->rcvbuf = alloc_mbuf(hp->bufsiz);
- restore(i_state);
- if(hp->rcvbuf == NULLBUF) {
- /* No memory, abort receiver */
- tprintf("PI: No memory available for receive buffers\n");
- /* Restore original interrupt vector */
- setirq(Pi[dev].vec,Pi[dev].oldvec);
- pinbr--;
- return -1;
- }
- hp->rcvbuf->cnt = 0;
- hp->sndq = NULLBUF;
-
- /* Get a buffer for tx which does not cross a dma boundary */
- i_state = dirps();/* buffer is allocated with ints off */
- hp->txdmabuf = (char *)alloc_mbuf(hp->bufsiz);
- restore(i_state);
- if(!hp->txdmabuf)
- tprintf("PI: No memory available for transmit buffer");
-
- scc_init(hp);
- xwrite_scc(hp,CTL+hp->base,R9,MIE|NV); /* master interrupt enable */
-
- /* Enable interrupt */
- maskon(Pi[dev].vec);
-
- 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 i_state;
- char kickflag;
- struct pichan *hp;
-
- dump(iface,IF_TRACE_OUT,CL_AX25,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:
- i_state = dirps();
- if(hp->tstate == IDLE)
- b_txint(hp);
- restore(i_state);
- break;
- }
- }
- return 0;
- }
-
- /* display PI Channel stats */
- int
- dopistat()
- {
- struct pichan *hp;
- int i;
-
- tprintf("PI Board Statistics:\n\n");
- tprintf("Base Addr Rxints Txints Exints TxFrms RxFrms Crcerr RxOvrs TxUndr \n");
- tprintf("--------- ------ ------ ------ ------ ------ ------ ------ ------ \n");
- for(i=0; i<pinbr*2; i++)
- {
- hp = &Pichan[i];
-
- tprintf("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"
- );
-
- tprintf("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 */
- int
- pi_ctl(iface,argc,argv)
- struct iface *iface;
- int argc;
- char *argv[];
- {
- struct pichan *hp;
- int p, v;
-
- if(argc < 2){
- tprintf("PI: Insufficient parameters\n");
- return 1;
- }
- hp = &Pichan[iface->dev]; /* point to channel table */
- p = atoi(argv[0]); /* parameter in binary */
- if(p > 3){
- tprintf("PI: Parameter %d out of range\n",p);
- return 1;
- }
- v = atoi(argv[1]); /* value to be loaded */
- hp->params[p] = v; /* Stuff in Kiss array */
- return 0;
- }
-
-