home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / tcpipsrc / drsi.c < prev    next >
C/C++ Source or Header  |  1990-11-29  |  32KB  |  1,107 lines

  1. /*
  2.  * Version with Stopwatches
  3.  *
  4.  * 0 - Not used
  5.  * 1 - rx_fsm run time
  6.  * 2 - drtx_active run time (per character tx time)
  7.  * 
  8.  * Interface driver for the DRSI board for KA9Q's TCP/IP on an IBM-PC ONLY!
  9.  *
  10.  * Derived from a driver written by Art Goldman, WA3CVG
  11.  * (c) Copyright 1987 All Rights Reserved
  12.  * Permission for non-commercial use is hereby granted provided this notice
  13.  * is retained.  For info call: (301) 997-3838.
  14.  *
  15.  * Heavily re-written from the original,  a driver for the EAGLE board into
  16.  * a driver for the DRSI PC* Packet adpator. Copyright as original, all
  17.  * amendments likewise providing credit given and notice retained.
  18.  * Stu Phillips - N6TTO, W6/G8HQA (yes Virginia,  really !).
  19.  * For info call: (408) 285-4142
  20.  *
  21.  * This driver supports 1 (one) DRSI board.
  22.  * 
  23.  * Reformatted and added ANSI-style declarations, integrated into NOS
  24.  * by KA9Q, 10/14/89
  25.  *
  26.  * Latest set of defect fixes added 1/2/90 by N6TTO
  27.  * 1. Made P-PERSIST work properly
  28.  * 2. Fixed UNDERRUN bug when in DEFER state
  29.  * 3. Tx now defers correctly when DCD is high (!)
  30.  *
  31.  * Changed 3/4/90 by N6TTO
  32.  * Changed method of enabling the IRQ to the 8259 to call maskon()
  33.  * instead of clrbit(); change made to allow interrupts > 8 to work
  34.  * on an AT.
  35.  *
  36.  * Changed 11/14/90 by N6TTO
  37.  * Fixed incompatiblity between current NOS memory allocation scheme
  38.  * and changes made to speed up drsi transmit state machine.
  39.  *
  40.  */
  41.  
  42. #include <stdio.h>
  43. #include <dos.h>
  44. #include <time.h>
  45. #include "global.h"
  46. #include "mbuf.h"
  47. #include "iface.h"
  48. #include "pktdrvr.h"
  49. #include "netuser.h"
  50. #include "drsi.h"
  51. #include "ax25.h"
  52. #include "trace.h"
  53. #include "pc.h"
  54. #include "8530.h"
  55.  
  56. static int dr_ctl __ARGS((struct iface *iface,int argc,char *argv[]));
  57. static int dr_raw __ARGS((struct iface *iface,struct mbuf *bp));
  58. static int dr_stop __ARGS((struct iface *iface));
  59. static void dr_wake __ARGS((struct drchan *hp,int rx_or_tx,
  60.     void (*routine) __ARGS((struct drchan *)),int ticks));
  61. static int drchanparam __ARGS((struct drchan *hp));
  62. static void drexint __ARGS((struct drchan *hp));
  63. static void drinitctc __ARGS((unsigned port));
  64. static void drrx_active __ARGS((struct drchan *hp));
  65. static void drrx_enable __ARGS((struct drchan *hp));
  66. static void drtx_active __ARGS((struct drchan *hp));
  67. static void drtx_defer __ARGS((struct drchan *hp));
  68. static void drtx_downtx __ARGS((struct drchan *hp));
  69. static void drtx_flagout __ARGS((struct drchan *hp));
  70. static void drtx_idle __ARGS((struct drchan *hp));
  71. static void drtx_rrts __ARGS((struct drchan *hp));
  72. static void drtx_tfirst __ARGS((struct drchan *hp));
  73. static char read_ctc __ARGS((unsigned port,unsigned reg));
  74. static void rx_fsm __ARGS((struct drchan *hp));
  75. static void tx_fsm __ARGS((struct drchan *hp));
  76. static void write_ctc __ARGS((unsigned port,unsigned reg,unsigned val));
  77.  
  78. struct DRTAB Drsi[DRMAX];    /* Device table - one entry per card */
  79. INTERRUPT (*Drhandle[]) __ARGS((void)) = { dr0vec };  /* handler interrupt vector table */
  80. struct drchan Drchan[2*DRMAX];     /* channel table - 2 entries per card */
  81. int16 Drnbr;
  82.  
  83. /* Set specified routine to be 'woken' up after specified number
  84.  * of ticks (allows CPU to be freed up and reminders posted);
  85.  */
  86. static void
  87. dr_wake(hp, rx_or_tx, routine, ticks)
  88. struct drchan *hp;
  89. int rx_or_tx;
  90. void (*routine) __ARGS((struct drchan *));
  91. int ticks;
  92. {
  93.     hp->w[rx_or_tx].wcall = routine;
  94.     hp->w[rx_or_tx].wakecnt = ticks;
  95. }
  96.  
  97. /* Master interrupt handler.  One interrupt at a time is handled.
  98.  * here. Service routines are called from here.
  99.  */
  100. void
  101. drint(dev)
  102. int dev;
  103. {
  104.     register char st;
  105.     register int16 pcbase, i;
  106.     struct drchan *hpa,*hpb;
  107.  
  108.     Drsi[dev].ints++;
  109.     pcbase = Drsi[dev].addr;
  110.     hpa = &Drchan[2 * dev];
  111.     hpb = &Drchan[(2 * dev)+1];
  112.  
  113. yuk:
  114.     /* Check CTC for timer interrupt */
  115.     st = read_ctc(pcbase, Z8536_CSR3);
  116.     if(st & Z_IP){
  117.         /* Reset interrupt pending */
  118.         write_ctc(pcbase, Z8536_CSR3, Z_CIP|Z_GCB);
  119.         for(i=0;i<=1;i++){
  120.             if(hpa->w[i].wakecnt){
  121.                 if(--hpa->w[i].wakecnt == 0){
  122.                     (hpa->w[i].wcall)(hpa);
  123.                 }
  124.             }
  125.             if(hpb->w[i].wakecnt){
  126.                 if(--hpb->w[i].wakecnt == 0){
  127.                     (hpb->w[i].wcall)(hpb);
  128.                 }
  129.             }
  130.         }
  131.     }
  132.     /* Check the SIO for interrupts */
  133.  
  134.     /* Read interrupt status register from channel A */
  135.     while((st = read_scc(pcbase+CHANA+CTL,R3)) != 0){
  136.         /* Use IFs to process ALL interrupts pending
  137.          * because we need to check all interrupt conditions
  138.          */
  139.         if(st & CHARxIP){
  140.             /* Channel A Rcv Interrupt Pending */
  141.             rx_fsm(hpa);
  142.         }
  143.         if(st & CHBRxIP){
  144.             /* Channel B Rcv Interrupt Pending */
  145.             rx_fsm(hpb);
  146.         }
  147.         if(st & CHATxIP){
  148.             /* Channel A Transmit Int Pending */
  149.             tx_fsm(hpa);
  150.         }
  151.         if(st & CHBTxIP){
  152.             /* Channel B Transmit Int Pending */
  153.             tx_fsm(hpb);
  154.         }
  155.         if(st & CHAEXT){
  156.             /* Channel A External Status Int */
  157.             drexint(hpa);
  158.         }
  159.         if(st & CHBEXT){
  160.             /* Channel B External Status Int */
  161.             drexint(hpb);
  162.         }
  163.         /* Reset highest interrupt under service */
  164.         write_scc(hpa->base+CTL,R0,RES_H_IUS);
  165.  
  166.     } /* End of while loop on int processing */
  167.     if(read_ctc(pcbase, Z8536_CSR3) & Z_IP)
  168.         goto yuk;
  169. }
  170.  
  171.  
  172. /* DRSI SIO External/Status interrupts
  173.  * This can be caused by a receiver abort, or a Tx UNDERRUN/EOM.
  174.  * Receiver automatically goes to Hunt on an abort.
  175.  *
  176.  * If the Tx Underrun interrupt hits, change state and
  177.  * issue a reset command for it, and return.
  178.  */
  179. static void
  180. drexint(hp)
  181. register struct drchan *hp;
  182. {
  183.     register int base = hp->base;
  184.     char st, i_state;
  185.  
  186.     i_state = dirps();     /* disable interrupts */
  187.     hp->exints++;
  188.  
  189.     st = read_scc(base+CTL,R0);     /* Fetch status */
  190.  
  191.     /* Check for Tx UNDERRUN/EOM - only in Transmit Mode */
  192.         /* Note that the TxEOM bit remains set once we go    */
  193.     /* back to receive.  The following qualifications    */
  194.     /* are necessary to prevent an aborted frame causing */
  195.     /* a queued transmit frame to be tossed when in      */
  196.     /* DEFER state on transmit.                 */
  197.     if((hp->tstate != DEFER) && (hp->rstate==0) && (st & TxEOM)){
  198.         if(hp->tstate != UNDERRUN){
  199.             /* This is an unexpected underrun.  Discard the current
  200.              * frame (there's no way to rewind),  kill the transmitter
  201.              * and return to receive with a wakeup posted to get the
  202.              * next (if any) frame.  Any recovery will have to be done
  203.              * by higher level protocols (yuk).
  204.              */
  205.             write_scc(base, R5, Tx8|DTR);    /* Tx off now */
  206.             write_scc(base, R1, 0);        /* Prevent ext.status int */
  207.             write_scc(base, R0, RES_Tx_P);  /* Reset Tx int pending */
  208.             write_scc(base, R0, ERR_RES);
  209.             write_scc(base, R0, RES_EOM_L); /* Reset underrun latch */
  210.             free_p(hp->sndbuf);
  211.             hp->tstate = IDLE;
  212.             hp->tx_state = drtx_idle;
  213.             dr_wake(hp, TX, tx_fsm, hp->params[SLOTIME]);
  214.             hp->rstate = ENABLE;
  215.             hp->rx_state = drrx_enable;
  216.             drrx_enable(hp);
  217.         }
  218.     }
  219.     /* Receive Mode only
  220.      * This triggers when hunt mode is entered, & since an ABORT
  221.      * automatically enters hunt mode, we use that to clean up
  222.      * any waiting garbage
  223.      */
  224.     if((hp->rstate != IDLE) && (st & BRK_ABRT)){
  225.         if(hp->rcvbuf != NULLBUF){
  226.             hp->rcp = hp->rcvbuf->data;
  227.             hp->rcvbuf->cnt = 0;
  228.         }
  229.         while(read_scc(base,R0) & Rx_CH_AV)
  230.             (void) inportb(base+DATA);
  231.         hp->aborts++;
  232.         hp->rstate = ACTIVE;
  233.         write_scc(base, R0, ERR_RES);
  234.     }
  235.     /* reset external status latch */
  236.     write_scc(base,R0,RES_EXT_INT);
  237.     restore(i_state);
  238. }
  239.  
  240. /* Receive Finite State Machine - dispatcher */
  241. static void
  242. rx_fsm(hp)
  243. struct drchan *hp;
  244. {
  245.     char i_state = dirps();
  246.  
  247.     hp->rxints++;
  248.     (*hp->rx_state)(hp);
  249.     restore(i_state);
  250. }
  251.  
  252. /* drrx_enable
  253.  * Receive ENABLE state processor
  254.  */
  255. static void
  256. drrx_enable(hp)
  257. struct drchan *hp;
  258. {
  259.     register int16 base = hp->base;
  260.  
  261.     write_scc(base, R1, INT_ALL_Rx|EXT_INT_ENAB);
  262.     write_scc(base, R15, BRKIE);    /* Allow ABORT Int */
  263.     write_scc(base, R14, BRSRC|BRENABL|SEARCH);
  264.     /* Turn on rx and enter hunt mode */
  265.     write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  266.  
  267.     if(hp->rcvbuf != NULLBUF){
  268.         hp->rcvbuf->cnt = 0;
  269.         hp->rcp = hp->rcvbuf->data;
  270.     }
  271.     hp->rstate = ACTIVE;
  272.     hp->rx_state = drrx_active;
  273. }
  274.  
  275. /* drrx_active
  276.  * Receive ACTIVE state processor
  277.  */
  278. static void
  279. drrx_active(hp)
  280. struct drchan *hp;
  281. {
  282.     register int16 base = hp->base;
  283.     unsigned char rse,st;
  284.     struct phdr *phdr;
  285.     struct mbuf *bp;
  286.  
  287.     /* Allocate a receive buffer if not already present */
  288.     if(hp->rcvbuf == NULLBUF){
  289.         bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  290.         if(bp == NULLBUF){
  291.             /* No buffer - abort the receiver */
  292.             write_scc(base, R3, ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  293.             /* Clear character from rx buffer in SIO */
  294.             (void) inportb(base+DATA);
  295.             return;
  296.         }
  297.         hp->rcvbuf->cnt = 0; 
  298.         hp->rcp = hp->rcvbuf->data;
  299.     }
  300.  
  301.     st = read_scc(base, R0); /* get interrupt status from R0 */
  302.     rse = read_scc(base,R1); /* get special status from R1 */
  303.  
  304.     if(st & Rx_CH_AV){
  305.         /* there is a char to be stored
  306.          * read special condition bits before reading the data char
  307.          * (already read above)
  308.          */
  309.         if(rse & Rx_OVR){
  310.             /* Rx overrun - toss buffer */
  311.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  312.             hp->rcvbuf->cnt = 0;
  313.             hp->rstate = RXERROR;    /* set error flag */
  314.             hp->rovers++;        /* count overruns */
  315.         } else if(hp->rcvbuf->cnt >= hp->bufsiz){
  316.             /* Too large -- toss buffer */
  317.             hp->toobig++;
  318.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  319.             hp->rcvbuf->cnt = 0;
  320.             hp->rstate = TOOBIG;    /* when set, chars are not stored */
  321.         }
  322.         /* ok, we can store the received character now */
  323.         if((hp->rstate == ACTIVE) && ((st & BRK_ABRT) == 0)){
  324.             *hp->rcp++ = inportb(base+DATA); /* char to rcv buff */
  325.             hp->rcvbuf->cnt++;         /* bump count */
  326.         } else {
  327.             /* got to empty FIFO */
  328.             (void) inportb(base+DATA);
  329.             hp->rcp = hp->rcvbuf->data;    /* reset buffer pointers */
  330.             hp->rcvbuf->cnt = 0;
  331.             hp->rstate = RXABORT;
  332.             write_scc(base,R0,ERR_RES);    /* reset err latch */
  333.         }
  334.     }
  335.     /* The End of Frame bit is ALWAYS associated with a character,
  336.      * usually, it is the last CRC char.  Only when EOF is true can
  337.      * we look at the CRC byte to see if we have a valid frame
  338.      */
  339.     if(rse & END_FR){
  340.         hp->rxframes++;
  341.         /* END OF FRAME -- Make sure Rx was active */
  342.         if(hp->rcvbuf->cnt > 0){    /* any data to store */
  343.             /* looks like a frame was received
  344.              * now is the only time we can check for CRC error
  345.              */
  346.             if((rse & CRC_ERR) || (hp->rstate > ACTIVE) ||
  347.              (hp->rcvbuf->cnt < 10) || (st & BRK_ABRT)){
  348.                 /* error occurred; toss frame */
  349.                 if(rse & CRC_ERR)
  350.                     hp->crcerr++;    /* count CRC errs */
  351.                 hp->rcp = hp->rcvbuf->data;
  352.                 hp->rcvbuf->cnt = 0;
  353.                 hp->rstate = ACTIVE;   /* Clear error state */
  354.             } else {
  355.                 /* Here we have a valid frame */
  356.                 bp = alloc_mbuf(sizeof(struct phdr));
  357.                 bp->cnt = sizeof(struct phdr);
  358.                 phdr = (struct phdr *)bp->data;
  359.                 phdr->type = CL_AX25;
  360.                 phdr->iface = hp->iface;
  361.                 bp->next = hp->rcvbuf;
  362.                 hp->rcvbuf->cnt -= 2;    /* chuck FCS bytes */
  363.                 enqueue(&Hopper, bp);    /* queue it in */
  364.                 hp->enqueued++;
  365.                 /* packet queued - reset buffer pointer */
  366.                 hp->rcvbuf = NULLBUF;
  367.             } /* end good frame queued */
  368.         }  /* end check for active receive upon EOF */
  369.     }
  370. }
  371.  
  372. /*
  373.  * TX finite state machine - dispatcher
  374.  */
  375. static void
  376. tx_fsm(hp)
  377. struct drchan *hp;
  378. {
  379.     char i_state = dirps();
  380.     if(hp->tstate != DEFER && hp->tstate)
  381.         hp->txints++;
  382.     (*hp->tx_state)(hp);
  383.     restore(i_state);
  384. }
  385.  
  386. /* drtx_idle
  387.  * Transmit IDLE transmit state processor
  388.  */
  389. static void
  390. drtx_idle(hp)
  391. struct drchan *hp;
  392. {
  393.     register int16 base;
  394.  
  395.     /* Tx idle - is there a frame to transmit ? */
  396.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  397.         /* Nothing to send - return to receive mode
  398.          * Turn Tx off - any trailing flag should have been sent
  399.          * by now
  400.          */
  401. #ifdef DRSIDEBUG
  402.         printf("Nothing to TX\n");
  403. #endif
  404.         base = hp->base;
  405.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  406.         write_scc(base, R0, ERR_RES);    /* Reset error bits */
  407.  
  408.         /* Delay for squelch tail before enabling receiver */
  409.         hp->rstate = ENABLE;
  410.         hp->rx_state = drrx_enable;
  411.         dr_wake(hp, RX, rx_fsm, hp->params[SQUELDELAY]);
  412.     } else {
  413.         /* Frame to transmit */
  414.         hp->tstate = DEFER;
  415.         hp->tx_state = drtx_defer;
  416.         drtx_defer(hp);
  417.     }
  418. }
  419.  
  420. /* drtx_defer
  421.  * Transmit DEFER state processor
  422.  */
  423. static void
  424. drtx_defer(hp)
  425. struct drchan *hp;
  426. {
  427.     register int16 base = hp->base;
  428.  
  429.     /* We may have defered a previous tx attempt - in any event...
  430.      * Check DCD in case someone is already transmitting
  431.      * then check to see if we should defer due to P-PERSIST.
  432.      */
  433.  
  434. #ifdef DRSIDEBUG
  435.     printf("drtx_defer - checking for DCD\n");
  436. #endif
  437.     if((read_scc(base+CTL, R0) & DCD) > 0){
  438.         /* Carrier detected - defer */
  439.         hp->txdefers++;
  440.         dr_wake(hp, TX, tx_fsm, 10);    /* Defer for 100 mS */
  441. #ifdef DRSIDEBUG
  442.         printf("drtx_defer - TX deferred\n");
  443. #endif
  444.         return;
  445.     }
  446.  
  447. #ifdef DRSIDEBUG
  448.     printf("drtx_defer - checking for P-PERSIST backoff\n");
  449. #endif
  450.     /* P-PERSIST is checked against channel 3 of the 8536 which is
  451.      * the free running counter for the 10 mS tick; The counter
  452.      * goes through 0x6000 ticks per 10 mS or one tick every
  453.      * 407 nS - this is pretty random compared to the DOS time of
  454.      * day clock (0x40:0x6C) used by the other (EAGLE) drivers.
  455.      */
  456.         if (hp->params[PERSIST] <= read_ctc(base,Z8536_CC3LSB)) {
  457. #ifdef DRSIDEBUG
  458.         printf("drtx_defer - BACKOFF\n");
  459. #endif
  460.         hp->txppersist++;
  461.         dr_wake (hp, TX, tx_fsm, hp->params[SLOTIME]);
  462.         return;
  463.     }
  464.     /* No backoff - set RTS and start to transmit frame */
  465.     write_scc(base, R1, 0);        /* Prevent external status int */
  466.     write_scc(base, R3, Rx8);    /* Turn Rx off */
  467.     hp->rstate = IDLE;        /* Mark Rx as idle */
  468.     hp->tstate = RRTS;
  469.     hp->tx_state = drtx_rrts;
  470. #ifdef DRSIDEBUG
  471.     printf("drtx_defer - wake posted for drtx_rrts\n");
  472. #endif
  473.     write_scc(base, R9, 0);        /* Interrupts off */
  474.     write_scc(base,R5,RTS|Tx8|DTR);    /* Turn tx on */
  475.     dr_wake(hp, TX, tx_fsm, 10);
  476. }
  477.  
  478. /* drtx_rrts
  479.  * Transmit RRTS state processor
  480.  */
  481. static void
  482. drtx_rrts(hp)
  483. struct drchan *hp;
  484. {
  485.     register int16 base = hp->base;
  486.  
  487.     write_scc(base, R9, 0);    /* Interrupts off */
  488.     write_scc(base,R5,TxCRC_ENAB|RTS|TxENAB|Tx8|DTR);    /* Tx now on */
  489.     hp->tstate = TFIRST;
  490.     hp->tx_state = drtx_tfirst;
  491. #ifdef DRSIDEBUG
  492.     printf("8530 Int status %x\n", read_scc(base+CHANA,R3)); 
  493.     printf("drtx_rrts - Wake posted for TXDELAY\n");
  494. #endif
  495.     dr_wake(hp, TX, tx_fsm, hp->params[TXDELAY]);
  496. }
  497.     
  498. /* drtx_tfirst
  499.  * Transmit TFIRST state processor
  500.  */
  501. static void
  502. drtx_tfirst(hp)
  503. struct drchan *hp;
  504. {
  505.     register int16 base = hp->base;
  506.     char c;
  507.     
  508.     /* Copy data to a local buffer to save on mbuf overheads
  509.      * during transmit interrupt time.
  510.      */
  511.     hp->drtx_cnt = len_p(hp->sndbuf);
  512.     hp->drtx_tcp = hp->drtx_buffer;
  513.     
  514.     pullup(&hp->sndbuf, hp->drtx_tcp, hp->drtx_cnt);
  515.     
  516.     /* Transmit the first character in the buffer */
  517.     c = *hp->drtx_tcp++;
  518.     hp->drtx_cnt--;
  519.  
  520.     write_scc(base, R0, RES_Tx_CRC);    /* Reset CRC */
  521.     write_scc(base, R0, RES_EOM_L);        /* Reset underrun latch */
  522.     outportb(base+DATA, c);            /* Output first character */
  523.     write_scc(base, R15, TxUIE);        /* Allow underrun ints only */
  524.     write_scc(base, R1, TxINT_ENAB|EXT_INT_ENAB); /* Tx/Ext status ints on */
  525.     write_scc(base, R9, MIE|NV);        /* master enable */
  526.     hp->tstate = ACTIVE;
  527.     hp->tx_state = drtx_active;
  528. }
  529.  
  530. /* drtx_active
  531.  * Transmit ACTIVE state processor
  532.  */
  533. static void
  534. drtx_active(hp)
  535. struct drchan *hp;
  536. {
  537.     if(hp->drtx_cnt-- > 0){
  538.         /* Send next character */
  539.         outportb(hp->base+DATA, *hp->drtx_tcp++);
  540.     } else {
  541.         /* No more to send - wait for underrun to hit */
  542.         hp->tstate = UNDERRUN;
  543.         hp->tx_state = drtx_flagout;
  544.         free_p(hp->sndbuf);
  545.         write_scc(hp->base, R0, RES_EOM_L);  /* Send CRC on underrun */
  546.         write_scc(hp->base, R0, RES_Tx_P);   /* Reset Tx Int pending */
  547.     }
  548. }
  549.  
  550. /* drtx_flagout
  551.  * Transmit FLAGOUT state processor
  552.  */
  553. static void
  554. drtx_flagout(hp)
  555. struct drchan *hp;
  556. {
  557.     /* Arrive here after CRC sent and Tx interrupt fires.
  558.      * Post a wake for ENDDELAY
  559.      */
  560.  
  561.     hp->tstate = UNDERRUN;
  562.     hp->tx_state = drtx_downtx;
  563.     write_scc(hp->base, R9, 0);
  564.     write_scc(hp->base, R0,  RES_Tx_P);
  565.     dr_wake(hp, TX, tx_fsm, hp->params[ENDDELAY]);
  566. }
  567.  
  568. /* drtx_downtx
  569.  * Transmit DOWNTX state processor
  570.  */
  571. static void
  572. drtx_downtx(hp)
  573. struct drchan *hp;
  574. {
  575.     register int base = hp->base;
  576.  
  577.     /* See if theres anything left to send - if there is,  send it ! */
  578.     if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  579.         /* Nothing left to send - return to receive */
  580.         write_scc(base, R5, Tx8|DTR);   /* Tx off now */
  581.         write_scc(base, R0, ERR_RES);   /* Reset error bits */
  582.         hp->tstate = IDLE;
  583.         hp->tx_state = drtx_idle;
  584.         hp->rstate = ENABLE;
  585.         hp->rx_state = drrx_enable;
  586.         drrx_enable(hp);
  587.     } else
  588.         drtx_tfirst(hp);
  589.  
  590. }
  591.     
  592. /* Write CTC register */
  593. static void
  594. write_ctc(port, reg, val)
  595. unsigned port,reg,val;
  596. {
  597.     char i_state;
  598.     int16 base = port;
  599.     
  600.     i_state = dirps();
  601.     /* Select register */
  602.     outportb(base+Z8536_MASTER,(char)reg);
  603.     outportb(base+Z8536_MASTER,(char)val);
  604.     restore(i_state);
  605. }
  606.  
  607. /* Read CTC register */
  608. static char
  609. read_ctc(port, reg)
  610. unsigned port, reg;
  611. {
  612.     char c,i_state;
  613.     int16 i,base = port;
  614.     
  615.     i_state = dirps();
  616.     /* Select register */
  617.         outportb(base+Z8536_MASTER,(char)(reg&0xFF));
  618.     /* Delay for a short time to allow 8536 to settle */
  619.     for(i=0;i<100;i++);
  620.     c = inportb(base+Z8536_MASTER);
  621.     restore(i_state);
  622.     return(c&0xFF);
  623. }
  624.  
  625. /* Initialize dr controller parameters */
  626. static int
  627. drchanparam(hp)
  628. register struct drchan *hp;
  629. {
  630.     int16 tc;
  631.     long br;
  632.     char i_state;
  633.     register int16 base;
  634.  
  635.     /* Initialize 8530 channel for SDLC operation */
  636.     base = hp->base;
  637.     i_state = dirps();
  638.  
  639.     switch(base & 2){
  640.     case 2:
  641.         write_scc(base,R9,CHRA);    /* Reset channel A */
  642.         break;
  643.     case 0:
  644.         write_scc(base,R9,CHRB);    /* Reset channel B */
  645.         break;
  646.     }
  647.     /* Deselect all Rx and Tx interrupts */
  648.     write_scc(base,R1,0);
  649.  
  650.     /* Turn off external interrupts (like CTS/CD) */
  651.     write_scc(base,R15,0);
  652.  
  653.     /* X1 clock, SDLC mode */
  654.     write_scc(base,R4,SDLC|X1CLK);     /* SDLC mode and X1 clock */
  655.  
  656.     /* Now some misc Tx/Rx parameters */
  657.     /* CRC PRESET 1, NRZI Mode */
  658.     write_scc(base,R10,CRCPS|NRZI);
  659.  
  660.     /* Set up BRG and DPLL multiplexers */
  661.     /* Tx Clk from RTxC. Rcv Clk from DPLL, TRxC pin outputs BRG */
  662.     write_scc(base,R11,RCDPLL|TCRTxCP|TRxCOI|TRxCBR);
  663.  
  664.     /* Null out SDLC start address */
  665.     write_scc(base,R6,0);
  666.  
  667.     /* SDLC flag */
  668.     write_scc(base,R7,FLAG);
  669.  
  670.     /* Set up the Transmitter but don't enable it */
  671.     /*  DTR, 8 bit TX chars only - TX NOT ENABLED */
  672.     write_scc(base,R5,Tx8|DTR);
  673.  
  674.     /* Receiver - initial setup only - more later */
  675.     write_scc(base,R3,Rx8);         /* 8 bits/char */
  676.  
  677.     /* Setting up BRG now - turn it off first */
  678.     write_scc(base,R14,BRSRC);     /* BRG off, but keep Pclk source */
  679.  
  680.     /* set the 32x time constant for the BRG */
  681.  
  682.     br = hp->speed;            /* get desired speed */
  683.     tc = ((XTAL/32)/br)-2;        /* calc 32X BRG divisor */
  684.  
  685.     write_scc(base,R12,tc&0xFF);      /* lower byte */
  686.     write_scc(base,R13,(tc>>8)&0xFF); /* upper bite */
  687.  
  688.     /* Time to set up clock control register for RECEIVE mode
  689.      * DRSI has xtal osc going to pclk at 4.9152 Mhz
  690.      * The BRG is sourced from that, and set to 32x clock
  691.      * The DPLL is sourced from the BRG.  BRG is fed to the TRxC pin
  692.      * Transmit clock is provided by the BRG externally divided by
  693.      * 32 in the CTC counter 1 and 2.
  694.      * Receive clock is from the DPLL
  695.      */
  696.  
  697.     /* Following subroutine sets up and ENABLES the receiver */
  698.     drrx_enable(hp);
  699.     
  700.     /* DPLL from BRG, BRG source is PCLK */
  701.     write_scc(hp->base,R14,BRSRC|SSBR);
  702.     /* SEARCH mode, keep BRG source */
  703.     write_scc(hp->base,R14,BRSRC|SEARCH);
  704.     /* Enable the BRG */
  705.     write_scc(hp->base,R14,BRSRC|BRENABL);
  706.  
  707.     /* enable the receive interrupts */
  708.  
  709.     write_scc(hp->base,R1,(INT_ALL_Rx|EXT_INT_ENAB));
  710.     write_scc(hp->base,R15,BRKIE);    /* ABORT int */
  711.     write_scc(hp->base,R9,MIE|NV);    /* master enable */
  712.  
  713.  
  714.     /* Now, turn on the receiver and hunt for a flag */
  715.     write_scc(hp->base,R3,RxENABLE|RxCRC_ENAB|Rx8);
  716.  
  717.     restore(i_state);
  718.     return 0;
  719. }
  720.  
  721. /*
  722.  * Initialize the CTC (8536)
  723.  * Only the counter/timers are used - the IO ports are un-comitted.
  724.  * Channels 1 and 2 are linked to provide a /32 counter to convert
  725.  * the SIO BRG to a real clock for Transmit clocking.
  726.  * CTC 3 is left free running on a 10 mS period.  It is always polled
  727.  * and therefore all interrupts from the chip are disabled.
  728.  *
  729.  * Updated 02/16/89 by N6TTO
  730.  * Changed to support the use of the second channel on the 8530.
  731.  * Added so that the driver works on the DRSI type 2 PC Adaptor
  732.  * which has 2 1200 bps modems.
  733.  *
  734.  */
  735. static void
  736. drinitctc(port)
  737. unsigned port;
  738. {
  739.     long i;
  740.  
  741.     /* Initialize 8536 CTC */
  742.  
  743.     /* Initialize 8536 */
  744.     /* Start by forcing chip into known state */
  745.     (void) read_ctc(port, Z8536_MICR);
  746.  
  747.     write_ctc(port, Z8536_MICR, 0x01);    /* Reset the CTC */
  748.     for(i=0;i < 1000L; i++)        /* Loop to delay */
  749.         ;
  750.     write_ctc(port, Z8536_MICR, 0x00);    /* Clear reset and start init seq. */
  751.  
  752.     /* Wait for chip to come ready */
  753.     while((read_ctc(port, Z8536_MICR)) != (char) 0x02)
  754.         ;
  755.  
  756.     write_ctc(port, Z8536_MICR, 0xa6);    /* MIE|NV|CT_VIS|RJA */
  757.     write_ctc(port, Z8536_MCCR, 0xf4);    /* PBE|CT1E|CT2E|CT3E|PAE */
  758.  
  759.     write_ctc(port, Z8536_CTMS1, 0xe2);    /* Continuous,EOE,ECE, Pulse output */
  760.     write_ctc(port, Z8536_CTMS2, 0xe2);    /* Continuous,EOE,ECE, Pulse output */
  761.     write_ctc(port, Z8536_CTMS3, 0x80);    /* Continuous,Pulse output */
  762.     write_ctc(port, Z8536_CT1MSB, 0x00);    /* Load time constant CTC #1 */
  763.     write_ctc(port, Z8536_CT1LSB, 0x10);
  764.     write_ctc(port, Z8536_CT2MSB, 0x00);    /* Load time constant CTC #2 */
  765.     write_ctc(port, Z8536_CT2LSB, 0x10);
  766.     write_ctc(port, Z8536_CT3MSB, 0x60);    /* Load time constant CTC #3 */
  767.     write_ctc(port, Z8536_CT3LSB, 0x00);
  768.  
  769.     write_ctc(port, Z8536_IVR, 0x06);
  770.  
  771.     /* Set port direction bits in port A and B
  772.      * Data is input on bits d1 and d5, output on d0 and d4.
  773.      * The direction is set by 1 for input and 0 for output
  774.      */
  775.     write_ctc(port, Z8536_PDCA, 0x22);
  776.     write_ctc(port, Z8536_PDCB, 0x22);
  777.  
  778.     write_ctc(port, Z8536_CSR1, Z_GCB|Z_TCB);  /* Start CTC #1 running */
  779.     write_ctc(port, Z8536_CSR2, Z_GCB|Z_TCB);  /* Start CTC #2 running */
  780.     write_ctc(port, Z8536_CSR3, Z_IE|Z_GCB|Z_TCB); /* Start CTC #3 running */
  781. }
  782.  
  783. /* Attach a DRSI interface to the system
  784.  * argv[0]: hardware type, must be "drsi"
  785.  * argv[1]: I/O address, e.g., "0x300"
  786.  * argv[2]: vector, e.g., "2"
  787.  * argv[3]: mode, must be:
  788.  *        "ax25" (AX.25 UI frame format)
  789.  * argv[4]: iface label, e.g., "dr0"
  790.  * argv[5]: receiver packet buffer size in bytes
  791.  * argv[6]: maximum transmission unit, bytes
  792.  * argv[7]: iface speed for channel A
  793.  * argv[8]: iface speed for channel B (defaults to same as A if absent)
  794.  * argv[9]: First IP address, optional (defaults to Ip_addr)
  795.  * argv[10]: Second IP address, optional (defaults to Ip_addr)
  796.  */
  797. int
  798. dr_attach(argc,argv)
  799. int argc;
  800. char *argv[];
  801. {
  802.     register struct iface *if_pca,*if_pcb;
  803.     struct drchan *hp;
  804.     int dev;
  805.  
  806.     /* Quick check to make sure args are good and mycall is set */
  807.     if(strcmp(argv[3],"ax25") != 0){
  808.         printf("Mode %s unknown for interface %s\n",
  809.             argv[3],argv[4]);
  810.         return -1;
  811.     }
  812.     if(if_lookup(argv[4]) != NULLIF){
  813.         printf("Interface %s already exists\n", argv[4]);
  814.         return -1;
  815.     }    
  816.     if(Mycall[0] == '\0'){
  817.         printf("set mycall first\n");
  818.         return -1;
  819.     }
  820.     /* Note: More than one card can be supported if you give up a COM:
  821.      * port, thus freeing up an IRQ line and port address
  822.      */
  823.     if(Drnbr >= DRMAX){
  824.         printf("Only 1 DRSI controller supported right now!\n");
  825.         return -1;
  826.     }
  827.     dev = Drnbr++;
  828.  
  829.     /* Initialize hardware-level control structure */
  830.     Drsi[dev].addr = htoi(argv[1]);
  831.     Drsi[dev].vec = htoi(argv[2]);
  832.  
  833.     /* Save original interrupt vector */
  834.     Drsi[dev].oldvec = getirq(Drsi[dev].vec);
  835.  
  836.     /* Set new interrupt vector */
  837.     if(setirq(Drsi[dev].vec,Drhandle[dev]) == -1){
  838.         printf("IRQ %u out of range\n",Drsi[dev].vec);
  839.         Drnbr--;
  840.     }    
  841.     /* Initialize the CTC */
  842.     drinitctc(Drsi[dev].addr);
  843.     
  844.     /* Create iface structures and fill in details */
  845.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  846.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  847.  
  848.     if_pca->addr = if_pcb->addr = Ip_addr;
  849.     if(argc > 9)
  850.         if_pca->addr = resolve(argv[9]);
  851.     if(argc > 10)
  852.         if_pcb->addr = resolve(argv[10]);
  853.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  854.         tprintf(Noipaddr);
  855.         free((char *)if_pca);
  856.         free((char *)if_pcb);
  857.         return -1;
  858.     }
  859.     /* Append "a" to iface associated with A channel */
  860.     if_pca->name = mallocw((unsigned)strlen(argv[4])+2);
  861.     strcpy(if_pca->name,argv[4]);
  862.     strcat(if_pca->name,"a");
  863.  
  864.     /* Append "b" to iface associated with B channel */
  865.     if_pcb->name = mallocw((unsigned)strlen(argv[4])+2);
  866.     strcpy(if_pcb->name,argv[4]);
  867.     strcat(if_pcb->name,"b");
  868.  
  869.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  870.     if_pcb->type = if_pca->type = CL_AX25;
  871.     if_pcb->ioctl = if_pca->ioctl = dr_ctl;
  872.     if_pca->dev = 2*dev;            /* dr0a */
  873.     if_pcb->dev = 2*dev + 1;        /* dr0b */
  874.     if_pcb->stop = if_pca->stop = dr_stop;
  875.     if_pcb->output = if_pca->output = ax_output;
  876.     if_pcb->raw = if_pca->raw = dr_raw;
  877.  
  878.     if(strcmp(argv[3],"ax25") == 0){
  879.         /* Must be true, was checked at top */
  880.         if_pcb->send = if_pca->send = ax_send;
  881.         if(if_pcb->hwaddr == NULLCHAR)
  882.             if_pcb->hwaddr = mallocw(sizeof(Mycall));
  883.         memcpy(if_pcb->hwaddr,(char *)&Mycall,sizeof(Mycall));
  884.         if(if_pca->hwaddr == NULLCHAR)
  885.             if_pca->hwaddr = mallocw(sizeof(Mycall));
  886.         memcpy(if_pca->hwaddr,(char *)&Mycall,sizeof(Mycall));
  887.     }
  888.     /* Link em in to the iface chain */
  889.     if_pca->next = if_pcb;
  890.     if_pcb->next = Ifaces;
  891.     Ifaces = if_pca;
  892.  
  893.     /* set params in drchan table for CHANNEL B */
  894.  
  895.     hp = &Drchan[2*dev+1];                /* dr1 is offset 1 */
  896.     hp->iface = if_pcb;
  897.     hp->stata = Drsi[dev].addr + CHANA + CTL;    /* permanent status */
  898.     hp->statb = Drsi[dev].addr + CHANB + CTL;    /* addrs for CHANA/B*/
  899.     if(argc > 8){
  900.         /* Separate speed for channel B */
  901.         hp->speed = (int16)atoi(argv[8]);
  902.     } else {
  903.         /* Set speed to same as for channel A */
  904.         hp->speed = (int16)atoi(argv[7]);
  905.     }
  906.     hp->base = Drsi[dev].addr + CHANB;
  907.     hp->bufsiz = atoi(argv[5]);
  908.     hp->drtx_buffer = mallocw(if_pcb->mtu+100);
  909.     hp->tstate = IDLE;
  910.     hp->tx_state = drtx_idle;
  911.     hp->w[RX].wcall = NULL;
  912.     hp->w[RX].wakecnt = 0;
  913.     hp->w[TX].wcall = NULL;
  914.     hp->w[TX].wakecnt = 0;
  915.     /* default KISS Params */
  916.     hp->params[TXDELAY] = 25;        /* 250 Ms */
  917.     hp->params[PERSIST] = 64;        /* 25% persistence */
  918.     hp->params[SLOTIME] = 10;        /* 100 Ms */
  919.     hp->params[SQUELDELAY] = 20;        /* 200 Ms */
  920.     hp->params[ENDDELAY] = 10;        /* 100 Ms */
  921.     
  922.     write_scc(hp->stata,R9,FHWRES);        /* Hardware reset */
  923.     
  924.     /* Disable interrupts with Master interrupt ctrl reg */
  925.     write_scc(hp->stata,R9,0);
  926.  
  927.     drchanparam(hp); 
  928.  
  929.     /* Initialize buffer pointers */
  930.     hp->rcvbuf = NULLBUF;
  931.     hp->rcvbuf->cnt = 0;
  932.     hp->sndq = NULLBUF;
  933.     
  934.     /* set params in drchan table for CHANNEL A */
  935.     hp = &Drchan[2*dev];            /* dr0a is offset 0 */
  936.     hp->iface = if_pca;
  937.     hp->speed = (int16)atoi(argv[7]);
  938.     hp->base = Drsi[dev].addr + CHANA;
  939.     hp->bufsiz = atoi(argv[5]);
  940.     hp->drtx_buffer = mallocw(if_pca->mtu+100);
  941.     hp->tstate = IDLE;
  942.     hp->tx_state = drtx_idle;
  943.     hp->w[RX].wcall = NULL;
  944.     hp->w[RX].wakecnt = 0;
  945.     hp->w[TX].wcall = NULL;
  946.     hp->w[TX].wakecnt = 0;
  947.     /* default KISS Params */
  948.     hp->params[TXDELAY] = 30;        /* 300 Ms */
  949.     hp->params[PERSIST] = 64;        /* 25% persistence */
  950.     hp->params[SLOTIME] = 10;        /* 100 Ms */
  951.     hp->params[SQUELDELAY] = 20;        /* 200 Ms */
  952.     hp->params[ENDDELAY] = 10;        /* 100 Ms */
  953.  
  954.     drchanparam(hp);
  955.  
  956.     /* Initialize buffer pointers */
  957.     hp->rcvbuf = NULLBUF;
  958.     hp->rcvbuf->cnt = 0;
  959.     hp->sndq = NULLBUF;
  960.  
  961.     write_scc(hp->base,R9,MIE|NV);        /* master interrupt enable */
  962.  
  963.     /* Enable interrupt in 8259 interrupt controller */
  964.     maskon(Drsi[dev].vec);
  965.     
  966.     return 0;
  967. }
  968.  
  969. /* Shut down iface */
  970. static int
  971. dr_stop(iface)
  972. struct iface *iface;
  973. {
  974.     int16 dev;
  975.  
  976.     dev = iface->dev;
  977.     if(dev & 1)
  978.         return 0;
  979.     dev >>= 1;    /* Convert back into DRSI number */
  980.  
  981.     /* Set 8259 interrupt mask (turn off interrupts) */
  982.     maskoff(Drsi[dev].vec);
  983.  
  984.     /* Restore original interrupt vector */
  985.     setirq(Drsi[dev].vec, Drsi[dev].oldvec);
  986.     Drnbr--;
  987.     
  988.     /* Force hardware reset */
  989.     write_scc(Drsi[dev].addr + CHANA + CTL,R9,FHWRES);
  990.     /* Reset the CTC */
  991.     (void) read_ctc(Drsi[dev].addr, Z8536_MICR);
  992.     write_ctc(Drsi[dev].addr, Z8536_MICR, 0x01);
  993.     return 0;
  994. }
  995.  
  996. /* Send raw packet on DRSI card */
  997. static int
  998. dr_raw(iface,bp)
  999. struct iface *iface;
  1000. struct mbuf *bp;
  1001. {
  1002.     char kickflag;
  1003.     struct drchan *hp;
  1004.     char i_st = dirps();
  1005.     
  1006.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  1007.     hp = &Drchan[iface->dev];
  1008.     kickflag = (hp->sndq == NULL) & (hp->sndbuf == NULLBUF);
  1009.     /* clever! flag=1 if something in queue */
  1010.     enqueue(&hp->sndq,bp);
  1011.  
  1012.     if(kickflag)            /* simulate interrupt to xmit */
  1013.         tx_fsm(hp);        /* process interrupt */
  1014.  
  1015.     restore(i_st);
  1016.     return 0;
  1017. }
  1018.  
  1019. /* display DRSI Channel stats */
  1020. int
  1021. dodrstat(argc,argv,p)
  1022. int argc;
  1023. char *argv[];
  1024. void *p;
  1025. {
  1026.     struct drchan *hp0, *hp1;
  1027.     int i;
  1028.  
  1029.     for(i=0; i<DRMAX; i++){
  1030.         hp0 = &Drchan[i];
  1031.         hp1 = &Drchan[i+1];
  1032.         i = Drchan[i].base;
  1033.         tprintf("DRSI Board Statistics - N6TTO 112790.0\n");
  1034.         tprintf("--------------------------------------\n");
  1035.         tprintf("Channel - %s\n", hp0->iface->name);
  1036.         tprintf("Rxints  - %8ld  Txints  - %8ld  Exints  - %8ld\n",
  1037.             hp0->rxints, hp0->txints, hp0->exints);
  1038.         tprintf("Enqued  - %8ld  Crcerr  - %8ld  Aborts  - %8ld\n",
  1039.             hp0->enqueued, hp0->crcerr, hp0->aborts);
  1040.         tprintf("RFrames - %8ld  Rxovers - %8ld  TooBig  - %8ld\n",
  1041.             hp0->rxframes, hp0->rovers, hp0->toobig);
  1042.         tprintf("Txdefer - %8ld  Txppers - %8ld  Nomem   - %8ld\n",
  1043.             hp0->txdefers, hp0->txppersist, hp0->nomem);
  1044.         tprintf("Tx state  %8d  Rx state  %8d\n\n",hp0->tstate,hp0->rstate);
  1045.         tprintf("Channel - %s\n", hp1->iface->name);
  1046.         tprintf("Rxints  - %8ld  Txints  - %8ld  Exints  - %8ld\n",
  1047.             hp1->rxints, hp1->txints, hp1->exints);
  1048.         tprintf("Enqued  - %8ld  Crcerr  - %8ld  Aborts  - %8ld\n",
  1049.             hp1->enqueued, hp1->crcerr, hp1->aborts);
  1050.         tprintf("RFrames - %8ld  Rxovers - %8ld  TooBig  - %8ld\n",
  1051.             hp1->rxframes, hp1->rovers, hp1->toobig);
  1052.         tprintf("Txdefer - %8ld  Txppers - %8ld  Nomem   - %8ld\n",
  1053.             hp1->txdefers, hp1->txppersist, hp1->nomem);
  1054.         tprintf("Tx state  %8d  Rx state  %8d\n",hp1->tstate,hp1->rstate);
  1055.     }
  1056.     return 0;
  1057. }
  1058.  
  1059. /* Subroutine to set kiss params in channel tables */
  1060. static int
  1061. dr_ctl(iface,argc,argv)
  1062. struct iface *iface;
  1063. int argc;
  1064. char *argv[];
  1065. {
  1066.     struct drchan *hp;
  1067.     int p, v;
  1068.  
  1069.     if(argc < 2){
  1070.     /* If called with less than the required # of parameters
  1071.      * - dump the current values.
  1072.      */
  1073.     hp = &Drchan[iface->dev];
  1074.     for(p = 0;p < CCP_COUNT; p++)
  1075.         switch(p){
  1076.         case TXDELAY:
  1077.             printf("Tx Delay         - %d\n", hp->params[p]);
  1078.             break;
  1079.         case PERSIST:
  1080.             printf("Persistence      - %d\n", hp->params[p]);
  1081.             break;
  1082.         case SLOTIME:
  1083.             printf("Slot time        - %d\n", hp->params[p]);
  1084.             break;
  1085.         case SQUELDELAY:
  1086.             printf("Squelch delay    - %d\n", hp->params[p]);
  1087.             break;
  1088.         case ENDDELAY:
  1089.             printf("End delay        - %d\n", hp->params[p]);
  1090.             break;
  1091.         default:
  1092.             break;
  1093.         }
  1094.         printf("Speed (bps)      - %d\n", hp->speed);
  1095.         return 0;
  1096.     }
  1097.     hp = &Drchan[iface->dev];    /* point to channel table */
  1098.     p = atoi(argv[0]);        /* parameter in binary */
  1099.     if(p > CCP_COUNT){
  1100.         printf("parameter %d out of range\n",p);
  1101.         return 1;
  1102.     }
  1103.     v = (int16)atoi(argv[1]);    /* value to be loaded */
  1104.     hp->params[p] = v;        /* Stuff in Kiss array */
  1105.     return 0;
  1106. }
  1107.