home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / misc / src0131 / ohs.c < prev    next >
C/C++ Source or Header  |  1990-02-15  |  15KB  |  613 lines

  1. /* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
  2.  * connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
  3.  * interrupts disabled for maximum speed.
  4.  */
  5. #include <stdio.h>
  6. #include <dos.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "iface.h"
  10. #include "netuser.h"
  11. #include "hs.h"
  12. #include "8530.h"
  13. #include "ax25.h"
  14. #include "trace.h"
  15. #include "hardware.h"
  16. #include "proc.h"
  17.  
  18. static void flushrx __ARGS((int16 data));
  19. static void hdlcparam __ARGS((struct hdlc *hp));
  20. static void hexint __ARGS((struct hdlc *hp));
  21. static void hrxint __ARGS((struct hdlc *hp));
  22. static int hs_stop __ARGS((struct iface *iface));
  23. static int hs_raw __ARGS((struct iface *iface,struct mbuf *bp));
  24. static void hs_tx __ARGS((int unused,void *hp1,void *a));
  25. static void hstxoff __ARGS((struct hdlc *hp));
  26. static void hstxon __ARGS((struct hdlc *hp));
  27. static void htxint __ARGS((struct hdlc *hp));
  28.  
  29. static struct hs Hs[NHS];
  30. static INTERRUPT (*Hshandle[])() = { hs0vec };
  31. static struct hdlc Hdlc[2*NHS];
  32. static int16 Nhs;
  33.  
  34. /* Master interrupt handler for the PC-100 card. All interrupts come
  35.  * here first, then are switched out to the appropriate routine.
  36.  */
  37. void
  38. hsint(dev)
  39. int dev;
  40. {
  41.     register char iv;
  42.     int16 hsbase;
  43.     register struct hdlc *hp;
  44.     
  45.     Hs[dev].ints++;
  46.     hsbase = Hs[dev].addr;
  47.  
  48. #ifdef    foo
  49.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  50.     (void)inportb(hsbase+CHANA+CTL,R0);
  51.     outportb(hsbase+4,0x8);        /***/
  52. #endif
  53.  
  54.     /* Read interrupt status from channel A */
  55.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  56.         if(iv & CHARxIP){
  57.             /* Channel A Rcv Interrupt Pending */
  58.             hp = &Hdlc[2*dev];
  59.             hrxint(hp);
  60.         } else if(iv & CHATxIP){
  61.             /* Channel A Transmit Int Pending */
  62.             hp = &Hdlc[2*dev];
  63.             htxint(hp);
  64.         } else if(iv & CHAEXT){
  65.             /* Channel A External Status Int */
  66.             hp = &Hdlc[2*dev];
  67.             hexint(hp);
  68.         } else if(iv & CHBRxIP){
  69.             /* Channel B Rcv Interrupt Pending */
  70.             hp = &Hdlc[(2*dev)+1];
  71.             hrxint(hp);
  72.         } else if(iv & CHBTxIP){
  73.             /* Channel B Transmit Int Pending */
  74.             hp = &Hdlc[(2*dev)+1];
  75.             htxint(hp);
  76.         } else if(iv & CHBEXT){
  77.             /* Channel B External Status Int */
  78.             hp = &Hdlc[(2*dev)+1];
  79.             hexint(hp);
  80.         }
  81.         /* Reset interrupt pending state */
  82.         write_scc(hp->ctl,R0,RES_H_IUS);
  83.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  84.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  85.     }
  86.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  87.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  88. }
  89. /* HDLC SIO External/Status interrupts
  90.  * The only one that can happen in this driver is a DCD change
  91.  */
  92. static void
  93. hexint(hp)
  94. register struct hdlc *hp;
  95. {
  96.     struct mbuf *rcvbuf;
  97.     struct phdr *phdr;
  98.     char *cp;
  99.     int cnt,data;
  100.     register int ctl;
  101.  
  102.     ctl = hp->ctl;
  103.     data = hp->data;
  104.     hp->exints++;
  105.  
  106.     /* Allocate a receive buffer */
  107.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr))) == NULLBUF){
  108.         /* Alloc failed; refuse to proceed */
  109.         hp->nomem++;
  110.         write_scc(ctl,R0,RES_EXT_INT);
  111.         return;
  112.     }
  113.     /* Allow space for phdr descriptor on front */
  114.     cp = rcvbuf->data + sizeof(struct phdr);
  115.     cnt = 0;
  116.  
  117.     /* Disable DCDIE bit so we can track changes in DCD */
  118.     write_scc(ctl,R15,0);
  119.  
  120.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  121.     flushrx(data);
  122.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  123.         if(cnt > 4){
  124.             /* Good frame */
  125.             hp->good++;
  126.             /* Toss crc */
  127.             rcvbuf->cnt = sizeof(struct phdr) + cnt - 1;
  128.             phdr = (struct phdr *)rcvbuf->data;
  129.             phdr->iface = hp->iface;
  130.             phdr->type = TYPE_AX25;
  131.             enqueue(&Hopper,rcvbuf);
  132.             /* Replenish buffer */
  133.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct phdr));
  134.         }
  135.         /* Start new buffer */
  136.         if(rcvbuf == NULLBUF)
  137.             break;    /* alloc failed */
  138.         cp = rcvbuf->data + sizeof(struct phdr);
  139.         cnt = 0;
  140.     }    
  141.     write_scc(ctl,R0,RES_EXT_INT);
  142.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  143.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  144.  
  145.     /* Get rid of fragmentary buffer */
  146.     free_p(rcvbuf);
  147. }
  148. static void
  149. flushrx(data)
  150. register int16 data;
  151. {
  152.     register int i = 5;
  153.     while(i-- != 0)
  154.         (void)inportb(data);
  155. }
  156. /* HDLC receiver interrupt handler.
  157.  * Not used in this driver
  158.  */
  159. static void
  160. hrxint(hp)
  161. register struct hdlc *hp;
  162. {
  163. }
  164. /* HDLC transmit interrupt service routine
  165.  * Not used in this driver
  166.  */
  167. static void
  168. htxint(hp)
  169. register struct hdlc *hp;
  170. {
  171. }
  172.  
  173. /* (re)Initialize HDLC controller parameters */
  174. static void
  175. hdlcparam(hp)
  176. register struct hdlc *hp;
  177. {
  178.     char i_state;
  179.     register int16 ctl;
  180.  
  181.     /* Initialize 8530 channel for SDLC operation */
  182.     ctl = hp->ctl;
  183.     i_state = dirps();
  184.  
  185. #ifdef    foo
  186.     switch(ctl & 2){
  187.     case CHANA:
  188.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  189.         break;
  190.     case CHANB:
  191.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  192.         break;
  193.     }
  194.     pause(1L);    /* Allow plenty of time for resetting */
  195. #endif
  196.  
  197.     /* Deselect interrupts for now */
  198.     write_scc(ctl,R1,0);
  199.     write_scc(ctl,R15,0);
  200.  
  201.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  202.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  203.  
  204.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  205.      * flag on underrun, no loop mode, 8 bit sync
  206.      */
  207.     write_scc(ctl,R10,CRCPS|NRZ);
  208.  
  209.     /* 8530 gets both tx and rx clock from modem.
  210.      * TRxC = transmit clock, RTxC = receive clock
  211.      * (swapped 11 Feb 1990 to use new DRSI wiring)
  212.      */
  213.     write_scc(ctl,R11,RCRTxCP | TCTRxCP);
  214.  
  215.     /* Note: baud rate generator not used */
  216.  
  217.     /* Null out SDLC start address */
  218.     write_scc(ctl,R6,0);
  219.  
  220.     /* SDLC flag */
  221.     write_scc(ctl,R7,FLAG);
  222.  
  223.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  224.      * RTS off, TxCRC enable
  225.      */
  226.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  227.  
  228.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  229.      * no address search, no inhibit sync chars, disable RX. Rx is
  230.      * started only by an actual DCD interrupt
  231.      */
  232.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  233.  
  234.     /* Dummy interrupt vector
  235.      * (This probably isn't necessary)
  236.      */
  237.     write_scc(ctl,R2,0);
  238.  
  239.     /* Enable only the external interrupts (modem interrupts) since
  240.      * polling is used for all actual tx/rx operations
  241.      */
  242.     write_scc(ctl,R1,EXT_INT_ENAB);
  243.  
  244.     /* Enable only DCD interrupts */
  245.     write_scc(ctl,R15,DCDIE);
  246.  
  247.     /* No reset, status low, master int enable, enable lower chain,
  248.      * no vector
  249.      */
  250.     write_scc(ctl,R9,MIE|NV);
  251.  
  252.     restore(i_state);
  253. }
  254. /* Attach a high speed iterface to the system
  255.  * argv[0]: hardware type, must be "hs"
  256.  * argv[1]: I/O address, e.g., "0x380"
  257.  * argv[2]: vector, e.g., "2"
  258.  * argv[3]: mode, must be "ax25"
  259.  * argv[4]: interface label, e.g., "drsi0". 
  260.  * argv[5]: receiver packet buffer size in bytes
  261.  * argv[6]: maximum transmission unit, bytes
  262.  * argv[7]: keyup delay, clock ticks
  263.  * argv[8]: persistence value, 0-255
  264.  */
  265. int
  266. hs_attach(argc,argv,p)
  267. int argc;
  268. char *argv[];
  269. void *p;
  270. {
  271.     register struct iface *if_hsa,*if_hsb;
  272.     struct hdlc *hp;
  273.     int dev;
  274.  
  275.     if(Nhs >= NHS){
  276.         tprintf("Too many hs controllers\n");
  277.         return -1;
  278.     }
  279.     if(if_lookup(argv[4]) != NULLIF){
  280.         tprintf("Interface %s already exists\n",argv[4]);
  281.         return -1;
  282.     }
  283.     dev = Nhs++;
  284.  
  285.     /* Initialize hardware-level control structure */
  286.     Hs[dev].addr = htoi(argv[1]);
  287.     Hs[dev].vec = htoi(argv[2]);
  288.  
  289.     /* Save original interrupt vector */
  290.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  291.     /* Set new interrupt vector */
  292.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  293.         tprintf("IRQ %u out of range\n",Hs[dev].vec);
  294.         Nhs--;
  295.         return -1;
  296.     }
  297.     /* Create interface structures and fill in details */
  298.     if_hsa = (struct iface *)callocw(1,sizeof(struct iface));
  299.     if_hsb = (struct iface *)callocw(1,sizeof(struct iface));
  300.  
  301.     if_hsa->addr = if_hsb->addr = Ip_addr;
  302.     if_hsa->name = strdup(argv[4]);
  303.     if_hsb->name = strdup(argv[4]);
  304.     if_hsb->name[strlen(argv[4]) - 1]++;    /* kludge */
  305.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  306.     if_hsb->type = if_hsa->type = TYPE_AX25;
  307.     if_hsa->dev = 2*dev;
  308.     if_hsb->dev = 2*dev + 1;
  309.     if_hsb->stop = if_hsa->stop = hs_stop;
  310.     if_hsb->output = if_hsa->output = ax_output;
  311.     if_hsb->raw = if_hsa->raw = hs_raw;
  312.  
  313.     if(strcmp(argv[3],"ax25") == 0){
  314.         axarp();
  315.         if(Mycall[0] == '\0'){
  316.             tprintf("set mycall first\n");
  317.             free((char *)if_hsa);
  318.             free((char *)if_hsb);
  319.             return -1;
  320.         }        
  321.         if_hsb->send = if_hsa->send = ax_send;
  322.         if(if_hsb->hwaddr == NULLCHAR)
  323.             if_hsb->hwaddr = mallocw(AXALEN);
  324.         memcpy(if_hsb->hwaddr,Mycall,AXALEN);
  325.         if(if_hsa->hwaddr == NULLCHAR)
  326.             if_hsa->hwaddr = mallocw(AXALEN);
  327.         memcpy(if_hsa->hwaddr,Mycall,AXALEN);
  328.     } else {
  329.         tprintf("Mode %s unknown for interface %s\n",
  330.             argv[3],argv[4]);
  331.         free((char *)if_hsa);
  332.         free((char *)if_hsb);
  333.         return -1;
  334.     }
  335.     if_hsa->next = if_hsb;
  336.     if_hsb->next = Ifaces;
  337.     Ifaces = if_hsa;
  338.  
  339.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  340.     hp = &Hdlc[2*dev+1];
  341.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  342.     hp->data = Hs[dev].addr + CHANB + DATA;
  343.     hp->bufsiz = atoi(argv[5]);
  344.     if(argc > 7)
  345.         hp->txdelay = atol(argv[7]);
  346.     else
  347.         hp->txdelay = 1L;
  348.     if(argc > 8)
  349.         hp->p = atoi(argv[8]);
  350.     else
  351.         hp->p = 64;
  352.     hp->iface = if_hsb;
  353.     hdlcparam(hp);
  354.     newproc("hs_tx",1024,hs_tx,0,hp,NULL);
  355.  
  356.     hp = &Hdlc[2*dev];
  357.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  358.     hp->data = Hs[dev].addr + CHANA + DATA;
  359.     hp->bufsiz = atoi(argv[5]);
  360.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  361.     hp->p = Hdlc[2*dev+1].p;
  362.     hp->iface = if_hsb;
  363.     hp->iface = if_hsa;
  364.     hdlcparam(hp);
  365.     newproc("hs_tx",1024,hs_tx,0,hp,NULL);
  366.  
  367.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  368.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  369.     maskon(Hs[dev].vec);
  370.  
  371.     return 0;
  372. }
  373. static int
  374. hs_stop(iface)
  375. struct iface *iface;
  376. {
  377.     int dev;
  378.  
  379.     dev = iface->dev;
  380.     if(dev & 1)
  381.         return -1;    /* Valid only for the first device */
  382.     dev >>= 1;    /* Convert back into hs number */
  383.     /* Turn off interrupts */
  384.     maskoff(Hs[dev].vec);
  385.  
  386.     /* Restore original interrupt vector */
  387.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  388.  
  389.     /* Force hardware reset */
  390.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  391.     return 0;
  392. }
  393. /* Send raw packet */
  394. static int
  395. hs_raw(iface,bp)
  396. struct iface *iface;
  397. struct mbuf *bp;
  398. {
  399.  
  400.     struct hdlc *hp;
  401.  
  402.     dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
  403.     hp = &Hdlc[iface->dev];
  404.     hp->txpkts++;
  405.     enqueue(&hp->txq,bp);    /* Put on queue for hs_tx process */
  406.     return 0;
  407. }
  408.  
  409. /* High speed transmit process */
  410. void
  411. hs_tx(unused,hp1,a)
  412. int unused;
  413. void *hp1;
  414. void *a;    /* Unused */
  415. {
  416.     struct mbuf *bp;
  417.     register int16 cnt;
  418.     register char *cp;
  419.     char *buffer;
  420.     int16 ctl,data;
  421.     int txon = 0;    /* Transmitter on/off state */
  422.     struct hdlc *hp;
  423.  
  424.     hp = (struct hdlc *)hp1;
  425.     ctl = hp->ctl;
  426.     data = hp->data;
  427.  
  428.     for(;;){
  429.         /* Wait for work */
  430.         while(hp->txq == NULLBUF){
  431.             if(txon){
  432.                 /* No more frames, shut down tx */
  433.                 hstxoff(hp);
  434.                 txon = 0;
  435.             }
  436.             pwait(&hp->txq);
  437.         }
  438.         bp = dequeue(&hp->txq);
  439.         /* Copy to new buffer for speed */
  440.         cnt = len_p(bp);
  441.         if((cp = buffer = malloc(cnt)) == NULLCHAR){
  442.             hp->nomem++;
  443.             free_p(bp);
  444.             continue;
  445.         }
  446.         pullup(&bp,cp,cnt);
  447.         /* Turn transmitter on if necessary */
  448.         if(!txon){
  449.             hstxon(hp);
  450.             txon = 1;
  451.         }
  452.         /* Initialize transmitter CRC */
  453.         write_scc(ctl,R0,RES_Tx_CRC);
  454.         for(;;){
  455.             /* Wait for the transmitter to become ready */
  456.             while(!(inportb(ctl) & Tx_BUF_EMP))
  457.                 ;
  458.             if(cnt-- == 0)
  459.                 break;
  460.             outportb(data,*cp++); /* Send the character */
  461.         }
  462.         write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  463.  
  464.         /* End of frame. Wait for TxEOM to go high, indicating start of
  465.          * CRC transmission. Note that we don't reset the transmit
  466.          * interrupt pending flag as one ordinarily would, since we're
  467.          * not using tx interrupts.
  468.          */
  469.         while(!(inportb(ctl) & TxEOM))
  470.             ;
  471.  
  472.         free(buffer);
  473.     }
  474. }
  475.  
  476. /* Turn on high speed transmitter. Does p-persistence, then sends a dummy
  477.  * frame to allow for keyup delay. Returns with transmitter on and interrupts
  478.  * disabled
  479.  */
  480. static void
  481. hstxon(hp)
  482. struct hdlc *hp;
  483. {
  484.     int16 ctl,data;
  485.     int i;
  486.  
  487.     ctl = hp->ctl;
  488.     data = hp->data;
  489.  
  490.     /* P-persistence. The slot time is fixed at one tick. */
  491.     while((rand() & 0xff) > uchar(hp->p))
  492.         pause(1L);
  493.  
  494.     /* Prevent distractions. In particular, block off the DCD interrupt
  495.      * so we don't hear our own carrier and hang in the interrupt handler!
  496.      * Note that simply disabling CPU interrupts isn't enough since
  497.      * the call to pause will block and the kernel will re-enable
  498.      * them.
  499.      */
  500.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  501.     (void)dirps();        /* Return value is always 1 */
  502.  
  503.     /* Turn on carrier, enable transmitter */
  504.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  505.  
  506.     /* Delay by sending dummy frame */
  507.     for(i=hp->txdelay;i != 0;i--){
  508.         while(!(inportb(ctl) & Tx_BUF_EMP))
  509.             ;
  510.         outportb(data,0);
  511.     }
  512.     write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  513.  
  514.     /* End of frame. Wait for TxEOM to go high, indicating start of
  515.      * CRC transmission. Note that we don't reset the transmit interrupt
  516.      * pending flag as one ordinarily would, since we're not using tx
  517.      * interrupts.
  518.      */
  519.     while(!(inportb(ctl) & TxEOM))
  520.         ;
  521. }
  522. /* Turn transmitter off at the end of a series of frames */
  523. static void
  524. hstxoff(hp)
  525. struct hdlc *hp;
  526. {
  527.     int cnt;
  528.     int16 ctl,data;
  529.  
  530.     ctl = hp->ctl;
  531.     data = hp->data;
  532.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  533.      * then abort it
  534.      */
  535.     for(cnt=5;cnt != 0;cnt--){
  536.         while(!(inportb(ctl) & Tx_BUF_EMP))
  537.             ;
  538.         outportb(data,0);
  539.     }
  540.     write_scc(ctl,R0,SEND_ABORT);
  541.  
  542.     /* Turn off carrier and disable transmitter */
  543.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  544.     /* Re-Enable SCC interrupts */
  545.     write_scc(ctl,R9,MIE|NV);        
  546.     restore(1);    /* Turn interrupts back on */
  547. }
  548.  
  549. int
  550. dohs(argc,argv,p)
  551. int argc;
  552. char *argv[];
  553. void *p;
  554. {
  555.     register int i;
  556.     register struct hdlc *hp;
  557.  
  558.     for(i=0;i<2*Nhs;i++){
  559.         hp = &Hdlc[i];
  560.         if(tprintf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  561.          i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
  562.          hp->nomem,hp->toobig,hp->crcerr,hp->aborts,
  563.          hp->overrun) == EOF)
  564.             break;
  565.     }
  566.     return 0;
  567. }
  568. #ifdef    notdef        /* replaced with assembler in 8530.asm */
  569. /* Read data from the 8530 receiver.
  570.  * Returns when either a good frame is received, or when carrier drops.
  571.  * If a good frame is received, the length is returned; otherwise -1.
  572.  */
  573. int
  574. rx8530(ctl,data,buf,bufsize)
  575. int16 ctl,data;
  576. char *buf;
  577. int16 bufsize;
  578. {
  579.     int cnt = 0;
  580.     register char status;
  581.     char error;
  582.     register char *cp = buf;
  583.  
  584.     for(;;){
  585.         status = inportb(ctl);
  586.         if(!(status & DCD)){
  587.             cnt = -1;
  588.             break;
  589.         } else if(status & BRK_ABRT){
  590.             cp = buf;
  591.             cnt = 0;
  592.         } else if(status & Rx_CH_AV){
  593.             /* Receive character is ready, get it */
  594.             *cp++ = inportb(data);
  595.             if(++cnt > bufsize){
  596.                 /* Buffer overflow, start again */
  597.                 write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  598.                 cp = buf;
  599.                 cnt = 0;
  600.             }
  601.         } else if((error = read_scc(ctl,R1)) & END_FR){
  602.             if(!(error & CRC_ERR))
  603.                 break;    /* Good frame! */
  604.             /* Bad frame, start again */
  605.             cp = buf;
  606.             cnt = 0;
  607.         }
  608.     }
  609.     return cnt;
  610. }
  611. #endif
  612.  
  613.