home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / HS.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  19KB  |  756 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.  * This driver is a bit of a kludge. A DMA-driven card and driver (e.g.,
  6.  * the PI) is much better, but this is better than nothing if all you have
  7.  * is a "dumb" 8530 card.
  8.  *
  9.  * Copyright 1991 Phil Karn, KA9Q
  10.  */
  11.  
  12. /****************************************************************************
  13. *    $Id: hs.c 1.2 93/07/16 11:45:14 ROOT_DOS Exp $
  14. *    15 Jul 93    1.2        GT    Fix warnings.                                    *
  15. ****************************************************************************/
  16.  
  17. #include <stdio.h>
  18. #include <dos.h>
  19. #include "global.h"
  20. #include "mbuf.h"
  21. #include "iface.h"
  22. #include "pktdrvr.h"
  23. #include "netuser.h"
  24. #include "hs.h"
  25. #include "8530.h"
  26. #include "ax25.h"
  27. #include "trace.h"
  28. #include "pc.h"
  29. #include "proc.h"
  30. #include "devparam.h"
  31. #include "ip.h"
  32.  
  33. static void flushrx __ARGS((int16 data));
  34. static void hdlcparam __ARGS((struct hdlc *hp));
  35. static void hexint __ARGS((struct hdlc *hp));
  36. static void hrxint __ARGS((struct hdlc *hp));
  37. static int hs_stop __ARGS((struct iface *iface));
  38. static int hs_raw __ARGS((struct iface *iface,struct mbuf *bp));
  39. static void hs_tx __ARGS((int unused,void *hp1,void *a));
  40. static int32 hs_ctl __ARGS((struct iface *,int cmd,int set,int32 val));
  41. static void hstxoff __ARGS((struct hdlc *hp));
  42. static void hstxon __ARGS((struct hdlc *hp));
  43. static void htxint __ARGS((struct hdlc *hp));
  44. static void init_delay __ARGS((void));
  45. static void msdelay __ARGS((void));
  46.  
  47. static struct hs Hs[NHS];
  48. static INTERRUPT (*Hshandle[])() = { hs0vec };
  49. static struct hdlc Hdlc[2*NHS];
  50. static int16 Nhs;
  51.  
  52. /* Master interrupt handler for the PC-100 card. All interrupts come
  53.  * here first, then are switched out to the appropriate routine.
  54.  */
  55. void
  56. hsint(dev)
  57. int dev;
  58. {
  59.     register char iv;
  60.     int16 hsbase;
  61.     register struct hdlc *hp;
  62.     
  63.     Hs[dev].ints++;
  64.     hsbase = Hs[dev].addr;
  65.  
  66. #ifdef    foo
  67.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  68.     (void)inportb(hsbase+CHANA+CTL,R0);
  69.     outportb(hsbase+4,0x8);        /***/
  70. #endif
  71.  
  72.     /* Read interrupt status from channel A */
  73.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  74.         if(iv & CHARxIP){
  75.             /* Channel A Rcv Interrupt Pending */
  76.             hp = &Hdlc[2*dev];
  77.             hrxint(hp);
  78.         } else if(iv & CHATxIP){
  79.             /* Channel A Transmit Int Pending */
  80.             hp = &Hdlc[2*dev];
  81.             htxint(hp);
  82.         } else if(iv & CHAEXT){
  83.             /* Channel A External Status Int */
  84.             hp = &Hdlc[2*dev];
  85.             hexint(hp);
  86.         } else if(iv & CHBRxIP){
  87.             /* Channel B Rcv Interrupt Pending */
  88.             hp = &Hdlc[(2*dev)+1];
  89.             hrxint(hp);
  90.         } else if(iv & CHBTxIP){
  91.             /* Channel B Transmit Int Pending */
  92.             hp = &Hdlc[(2*dev)+1];
  93.             htxint(hp);
  94.         } else if(iv & CHBEXT){
  95.             /* Channel B External Status Int */
  96.             hp = &Hdlc[(2*dev)+1];
  97.             hexint(hp);
  98.         }
  99.         /* Reset interrupt pending state */
  100.         write_scc(hp->ctl,R0,RES_H_IUS);
  101.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  102.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  103.     }
  104.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  105.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  106. }
  107. /* HDLC SIO External/Status interrupts
  108.  * The only one that can happen in this driver is a DCD change
  109.  */
  110. static void
  111. hexint(hp)
  112. register struct hdlc *hp;
  113. {
  114.     struct mbuf *rcvbuf;
  115.     struct phdr phdr;
  116.     char *cp;
  117.     int cnt,data;
  118.     register int ctl;
  119.  
  120.     ctl = hp->ctl;
  121.     data = hp->data;
  122.     hp->exints++;
  123.  
  124.     /* Allocate a receive buffer */
  125.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(phdr))) == NULLBUF){
  126.         /* Alloc failed; refuse to proceed */
  127.         hp->nomem++;
  128.         write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  129.         write_scc(ctl,R0,RES_EXT_INT);
  130.         return;
  131.     }
  132.     /* Allow space for phdr descriptor on front */
  133.     cp = rcvbuf->data + sizeof(phdr);
  134.     cnt = 0;
  135.  
  136.     /* Disable DCDIE bit so we can track changes in DCD */
  137.     write_scc(ctl,R15,0);
  138.  
  139.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  140.     flushrx(data);
  141.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  142.         if(cnt > 4){
  143.             /* Good frame */
  144.             hp->good++;
  145.             /* Toss crc */
  146.             rcvbuf->cnt = sizeof(phdr) + cnt - 1;
  147.             phdr.iface = hp->iface;
  148.             phdr.type = CL_AX25;
  149.             memcpy(rcvbuf->data,(char *)&phdr,sizeof(phdr));
  150.             enqueue(&Hopper,rcvbuf);
  151.             /* Replenish buffer */
  152.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(phdr));
  153.         }
  154.         /* Start new buffer */
  155.         if(rcvbuf == NULLBUF)
  156.             break;    /* alloc failed */
  157.         cp = rcvbuf->data + sizeof(phdr);
  158.     }    
  159.     write_scc(ctl,R0,RES_EXT_INT);
  160.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  161.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  162.  
  163.     /* Get rid of fragmentary buffer */
  164.     free_p(rcvbuf);
  165. }
  166. static void
  167. flushrx(data)
  168. register int16 data;
  169. {
  170.     register int i = 5;
  171.     while(i-- != 0)
  172.         (void)inportb(data);
  173. }
  174. /* HDLC receiver interrupt handler.
  175.  * Not used in this driver
  176.  */
  177. static void
  178. hrxint(hp)
  179. register struct hdlc *hp;
  180. {
  181. }
  182. /* HDLC transmit interrupt service routine
  183.  * Not used in this driver
  184.  */
  185. static void
  186. htxint(hp)
  187. register struct hdlc *hp;
  188. {
  189. }
  190.  
  191. /* (re)Initialize HDLC controller parameters */
  192. static void
  193. hdlcparam(hp)
  194. register struct hdlc *hp;
  195. {
  196.     char i_state;
  197.     register int16 ctl;
  198.  
  199.     /* Initialize 8530 channel for SDLC operation */
  200.     ctl = hp->ctl;
  201.     i_state = dirps();
  202.  
  203. #ifdef    foo
  204.     switch(ctl & 2){
  205.     case CHANA:
  206.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  207.         break;
  208.     case CHANB:
  209.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  210.         break;
  211.     }
  212.     pause(1L);    /* Allow plenty of time for resetting */
  213. #endif
  214.  
  215.     /* Deselect interrupts for now */
  216.     write_scc(ctl,R1,0);
  217.     write_scc(ctl,R15,0);
  218.  
  219.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  220.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  221.  
  222.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  223.      * flag on underrun, no loop mode, 8 bit sync
  224.      */
  225.     write_scc(ctl,R10,CRCPS|NRZ);
  226.  
  227.     /* 8530 gets both tx and rx clock from modem.
  228.      * By default, TRxC = transmit clock, RTxC = receive clock
  229.      * (swapped 11 Feb 1990 to use new DRSI wiring) UNLESS
  230.      * the 'r' parameter is specified
  231.      */
  232.     if(!hp->clkrev)
  233.         write_scc(ctl,R11,RCRTxCP | TCTRxCP);
  234.     else
  235.         write_scc(ctl,R11,RCTRxCP | TCRTxCP);
  236.  
  237.     /* Note: baud rate generator not used */
  238.  
  239.     /* Null out SDLC start address */
  240.     write_scc(ctl,R6,0);
  241.  
  242.     /* SDLC flag */
  243.     write_scc(ctl,R7,FLAG);
  244.  
  245.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  246.      * RTS off, TxCRC enable
  247.      */
  248.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  249.  
  250.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  251.      * no address search, no inhibit sync chars, disable RX. Rx is
  252.      * started only by an actual DCD interrupt
  253.      */
  254.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  255.  
  256.     /* Dummy interrupt vector
  257.      * (This probably isn't necessary)
  258.      */
  259.     write_scc(ctl,R2,0);
  260.  
  261.     /* Enable only the external interrupts (modem interrupts) since
  262.      * polling is used for all actual tx/rx operations
  263.      */
  264.     write_scc(ctl,R1,EXT_INT_ENAB);
  265.  
  266.     /* Enable only DCD interrupts */
  267.     write_scc(ctl,R15,DCDIE);
  268.  
  269.     /* No reset, status low, master int enable, enable lower chain,
  270.      * no vector
  271.      */
  272.     write_scc(ctl,R9,MIE|NV);
  273.  
  274.     restore(i_state);
  275. }
  276. /* Attach a high speed iterface to the system
  277.  * argv[0]: hardware type, must be "hs"
  278.  * argv[1]: I/O address, e.g., "0x380"
  279.  * argv[2]: vector, e.g., "2"
  280.  * argv[3]: mode, must be "ax25"
  281.  * argv[4]: interface base label, e.g., "drsi0". Driver appends "a" and "b".
  282.  * argv[5]: receiver packet buffer size in bytes
  283.  * argv[6]: maximum transmission unit, bytes
  284.  * argv[7]: keyup delay, milliseconds
  285.  * argv[8]: persistence value, 0-255
  286.  * argv[9]: "r" to reverse sense of clock leads (optional)
  287.  */
  288. int
  289. hs_attach(argc,argv,p)
  290. int argc;
  291. char *argv[];
  292. void *p;
  293. {
  294.     register struct iface *if_hsa,*if_hsb;
  295.     struct hdlc *hp;
  296.     int dev;
  297.  
  298.     if(Nhs >= NHS){
  299.         tprintf("Too many hs controllers\n");
  300.         return -1;
  301.     }
  302.     if(if_lookup(argv[4]) != NULLIF){
  303.         tprintf("Interface %s already exists\n",argv[4]);
  304.         return -1;
  305.     }
  306.     dev = Nhs++;
  307.  
  308.     /* Initialize hardware-level control structure */
  309.     Hs[dev].addr = htoi(argv[1]);
  310.     Hs[dev].vec = htoi(argv[2]);
  311.  
  312.     /* Save original interrupt vector */
  313.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  314.     /* Set new interrupt vector */
  315.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  316.         tprintf("IRQ %u out of range\n",Hs[dev].vec);
  317.         Nhs--;
  318.         return -1;
  319.     }
  320.     /* Create interface structures and fill in details */
  321.     if_hsa = (struct iface *)callocw(1,sizeof(struct iface));
  322.     if_hsb = (struct iface *)callocw(1,sizeof(struct iface));
  323.  
  324.     if_hsa->addr = if_hsb->addr = Ip_addr;
  325.     if_hsa->name = mallocw(strlen(argv[4])+2);
  326.     strcpy(if_hsa->name,argv[4]);
  327.     strcat(if_hsa->name,"a");
  328.     if_hsb->name = mallocw(strlen(argv[4])+2);
  329.     strcpy(if_hsb->name,argv[4]);
  330.     strcat(if_hsb->name,"b");
  331.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  332.     if_hsb->type = if_hsa->type = CL_AX25;
  333.     if_hsa->dev = 2*dev;
  334.     if_hsb->dev = 2*dev + 1;
  335.     if_hsb->stop = if_hsa->stop = hs_stop;
  336.     if_hsb->output = if_hsa->output = ax_output;
  337.     if_hsb->raw = if_hsa->raw = hs_raw;
  338.     if_hsa->ioctl = if_hsb->ioctl = hs_ctl;
  339.  
  340.     if(strcmp(argv[3],"ax25") == 0){
  341.         if(Mycall[0] == '\0'){
  342.             tprintf("set mycall first\n");
  343.             free((char *)if_hsa);
  344.             free((char *)if_hsb);
  345.             return -1;
  346.         }        
  347.         if_hsb->send = if_hsa->send = ax_send;
  348.         if(if_hsb->hwaddr == NULLCHAR)
  349.             if_hsb->hwaddr = mallocw(AXALEN);
  350.         memcpy(if_hsb->hwaddr,Mycall,AXALEN);
  351.         if(if_hsa->hwaddr == NULLCHAR)
  352.             if_hsa->hwaddr = mallocw(AXALEN);
  353.         memcpy(if_hsa->hwaddr,Mycall,AXALEN);
  354.     } else {
  355.         tprintf("Mode %s unknown for interface %s\n",
  356.             argv[3],argv[4]);
  357.         free((char *)if_hsa);
  358.         free((char *)if_hsb);
  359.         return -1;
  360.     }
  361.     if_hsa->next = if_hsb;
  362.     if_hsb->next = Ifaces;
  363.     Ifaces = if_hsa;
  364.  
  365.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  366.     hp = &Hdlc[2*dev+1];
  367.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  368.     hp->data = Hs[dev].addr + CHANB + DATA;
  369.     hp->bufsiz = atoi(argv[5]);
  370.     if(argc > 7)
  371.         hp->txdelay = atol(argv[7]);
  372.     else
  373.         hp->txdelay = 15L;
  374.     if(argc > 8)
  375.         hp->p = atoi(argv[8]);
  376.     else
  377.         hp->p = 64;
  378.     if(argc > 9 && argv[9][0] == 'r')
  379.         hp->clkrev = 1;
  380.     else
  381.         hp->clkrev = 0;
  382.     hp->iface = if_hsb;
  383.     hdlcparam(hp);
  384.     if_hsa->txproc = newproc("hs_tx",1024,hs_tx,0,hp,NULL,0);
  385.  
  386.     hp = &Hdlc[2*dev];
  387.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  388.     hp->data = Hs[dev].addr + CHANA + DATA;
  389.     hp->bufsiz = atoi(argv[5]);
  390.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  391.     hp->p = Hdlc[2*dev+1].p;
  392.     if(argc > 9 && argv[9][0] == 'r')
  393.         hp->clkrev = 1;
  394.     else
  395.         hp->clkrev = 0;
  396.     hp->iface = if_hsa;
  397.     hdlcparam(hp);
  398.     if_hsb->txproc = newproc("hs_tx",1024,hs_tx,0,hp,NULL,0);
  399.  
  400.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  401.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  402.     maskon(Hs[dev].vec);
  403.  
  404.     /* Initialize timing delay loop */
  405.     init_delay();
  406.     return 0;
  407. }
  408. static int
  409. hs_stop(iface)
  410. struct iface *iface;
  411. {
  412.     int dev;
  413.  
  414.     dev = iface->dev;
  415.     if(dev & 1)
  416.         return -1;    /* Valid only for the first device */
  417.     dev >>= 1;    /* Convert back into hs number */
  418.  
  419.     /* Turn off interrupts */
  420.     maskoff(Hs[dev].vec);
  421.  
  422.     /* Restore original interrupt vector */
  423.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  424.  
  425.     /* Force hardware reset */
  426.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  427.     return 0;
  428. }
  429. /* Send raw packet */
  430. static int
  431. hs_raw(iface,bp)
  432. struct iface *iface;
  433. struct mbuf *bp;
  434. {
  435.  
  436.     struct hdlc *hp;
  437.  
  438.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  439.     iface->rawsndcnt++;
  440.     iface->lastsent = secclock();
  441.     hp = &Hdlc[iface->dev];
  442.     hp->txpkts++;
  443.     enqueue(&hp->txq,bp);    /* Put on queue for hs_tx process */
  444.     return 0;
  445. }
  446.  
  447. /* High speed transmit process */
  448. void
  449. hs_tx(unused,hp1,a)
  450. int unused;
  451. void *hp1;
  452. void *a;    /* Unused */
  453. {
  454.     struct mbuf *bp,*nbp;
  455.     register int16 cnt;
  456.     register char *cp;
  457.     int16 ctl,data;
  458.     int txon = 0;    /* Transmitter on/off state */
  459.     struct hdlc *hp;
  460.     int i;
  461.  
  462.     hp = (struct hdlc *)hp1;
  463.     ctl = hp->ctl;
  464.     data = hp->data;
  465.  
  466.     for(;;){
  467.         /* Wait for work */
  468.         while(hp->txq == NULLBUF){
  469.             if(txon){
  470.                 /* No more frames, shut down tx */
  471.                 hstxoff(hp);
  472.                 txon = 0;
  473.                 /* Hold off to give other guy a chance to
  474.                  * respond
  475.                  */
  476.                 hp->deftime = msclock() + hp->txdelay + 500;
  477.             }
  478.             pwait(&hp->txq);
  479.         }
  480.         bp = dequeue(&hp->txq);
  481.         cnt = len_p(bp);
  482.         /* If buffer isn't contiguous (which is almost always
  483.          * the case) copy it to a new buffer for speed
  484.          */
  485.         if(bp->next != NULLBUF){
  486.             if((nbp = copy_p(bp,cnt)) == NULLBUF){
  487.                 hp->nomem++;
  488.                 free_p(bp);
  489.                 continue;
  490.             }
  491.             free_p(bp);
  492.             bp = nbp;
  493.         }
  494.         cp = bp->data;
  495.         /* Turn transmitter on if necessary */
  496.         if(!txon){
  497.             hstxon(hp);
  498.             txon = 1;
  499.         } else {
  500.             /* Else wait another txd for receiver to get ready again */
  501.             for(i = (int) hp->txdelay; i != 0; i--)
  502.                 msdelay();
  503.         }
  504.         /* Initialize transmitter CRC */
  505.         write_scc(ctl,R0,RES_Tx_CRC);
  506.         for(;;){
  507.             /* Wait for the transmitter to become ready */
  508.             while(!(inportb(ctl) & Tx_BUF_EMP))
  509.                 ;
  510.             if(cnt-- == 0)
  511.                 break;
  512.             outportb(data,*cp++); /* Send the character */
  513.         }
  514.         write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  515.  
  516.         /* End of frame. Wait for TxEOM to go high, indicating start of
  517.          * CRC transmission. Note that we don't reset the transmit
  518.          * interrupt pending flag as one ordinarily would, since we're
  519.          * not using tx interrupts.
  520.          */
  521.         while(!(inportb(ctl) & TxEOM))
  522.             ;
  523.  
  524.         free_p(bp);
  525.     }
  526. }
  527.  
  528. /* Turn on high speed transmitter. Does p-persistence, then sends a dummy
  529.  * frame to allow for keyup delay. Returns with transmitter on and interrupts
  530.  * disabled
  531.  */
  532. static void
  533. hstxon(hp)
  534. struct hdlc *hp;
  535. {
  536.     int16 ctl;
  537.     int i;
  538.     long ca;
  539.     int32 t;
  540.  
  541.     ctl = hp->ctl;
  542.  
  543.     /* Defer logic. Wait until deftime is in the past (so we
  544.      * defer to any overheard CTS messages) AND the p-persistence
  545.      * dice roll succeeds. The computation of ca allows for clock
  546.      * rollover (which happens every 49+ days).
  547.      */
  548.     for(;;){
  549.         t = msclock();
  550.         ca = hp->deftime - t;
  551.         if(ca > 0){
  552.             pause(ca);
  553.             continue;
  554.         }
  555.         hp->deftime = t;    /* Keep from getting too old */
  556.         if((rand() & 0xff) > uchar(hp->p)){
  557.             pause((long)MSPTICK);
  558.             continue;
  559.         }
  560.         break;
  561.     }
  562.     /* Prevent distractions. In particular, block off the DCD interrupt
  563.      * so we don't hear our own carrier and hang in the interrupt handler!
  564.      * Note that simply disabling CPU interrupts isn't enough since
  565.      * the call to pause will block and the kernel will re-enable
  566.      * them.
  567.      */
  568.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  569.     (void)dirps();        /* Return value is always 1 */
  570.  
  571.     /* Turn on carrier, enable transmitter */
  572.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  573.  
  574.     /* Delay for keyup interval */
  575.     for(i = (int) hp->txdelay; i != 0; i--)
  576.         msdelay();
  577.  
  578. }
  579. /* Turn transmitter off at the end of a series of frames */
  580. static void
  581. hstxoff(hp)
  582. struct hdlc *hp;
  583. {
  584.     int cnt;
  585.     int16 ctl,data;
  586.  
  587.     ctl = hp->ctl;
  588.     data = hp->data;
  589.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  590.      * then abort it
  591.      */
  592.     for(cnt=5;cnt != 0;cnt--){
  593.         while(!(inportb(ctl) & Tx_BUF_EMP))
  594.             ;
  595.         outportb(data,0);
  596.     }
  597.     write_scc(ctl,R0,SEND_ABORT);
  598.  
  599.     /* Turn off carrier and disable transmitter */
  600.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  601.     /* Re-Enable SCC interrupts */
  602.     write_scc(ctl,R9,MIE|NV);        
  603.     restore(1);    /* Turn interrupts back on */
  604. }
  605.  
  606. int
  607. dohs(argc,argv,p)
  608. int argc;
  609. char *argv[];
  610. void *p;
  611. {
  612.     register int i;
  613.     register struct hdlc *hp;
  614.  
  615.     for(i=0;i<2*Nhs;i++){
  616.         hp = &Hdlc[i];
  617.         if(tprintf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  618.          i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
  619.          hp->nomem,hp->toobig,hp->crcerr,hp->aborts,
  620.          hp->overrun) == EOF)
  621.             break;
  622.     }
  623.     return 0;
  624. }
  625. static int32
  626. hs_ctl(iface,cmd,set,val)
  627. struct iface *iface;
  628. int cmd;
  629. int set;
  630. int32 val;
  631. {
  632.     register struct hdlc *hp;
  633.     int32 t,ca;
  634.  
  635.     hp = &Hdlc[iface->dev];
  636.     switch(cmd){
  637.     case PARAM_TXDELAY:    /* Tx keyup delay */
  638.         if(set)
  639.             hp->txdelay = val;
  640.         return hp->txdelay;
  641.     case PARAM_PERSIST:
  642.         if(set)
  643.             hp->p = val;
  644.         return uchar(hp->p);
  645.     case PARAM_MUTE:
  646.         /* Mute transmitter for specified # of ms */
  647.         if(set){
  648.             if(val == -1){
  649.                 /* Special case for duration of a CTS */
  650.                 val = hp->txdelay + 500;
  651.             }
  652.             hp->deftime = msclock() + val;
  653.         }
  654.         t = msclock();
  655.         ca = hp->deftime - t;
  656.         if(ca < 0){
  657.             hp->deftime = t;
  658.             ca = 0;
  659.         }
  660.         return ca;
  661.     }
  662.     return -1;
  663. }
  664. #ifdef    notdef        /* replaced with assembler in 8530.asm */
  665. /* Read data from the 8530 receiver.
  666.  * Returns when either a good frame is received, or when carrier drops.
  667.  * If a good frame is received, the length is returned; otherwise -1.
  668.  */
  669. int
  670. rx8530(ctl,data,buf,bufsize)
  671. int16 ctl,data;
  672. char *buf;
  673. int16 bufsize;
  674. {
  675.     int cnt = 0;
  676.     register char status;
  677.     char error;
  678.     register char *cp = buf;
  679.  
  680.     for(;;){
  681.         status = inportb(ctl);
  682.         if(!(status & DCD)){
  683.             cnt = -1;
  684.             break;
  685.         } else if(status & BRK_ABRT){
  686.             cp = buf;
  687.             cnt = 0;
  688.         } else if(status & Rx_CH_AV){
  689.             /* Receive character is ready, get it */
  690.             *cp++ = inportb(data);
  691.             if(++cnt > bufsize){
  692.                 /* Buffer overflow, start again */
  693.                 write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  694.                 cp = buf;
  695.                 cnt = 0;
  696.             }
  697.         } else if((error = read_scc(ctl,R1)) & END_FR){
  698.             if(!(error & CRC_ERR))
  699.                 break;    /* Good frame! */
  700.             /* Bad frame, start again */
  701.             cp = buf;
  702.             cnt = 0;
  703.         }
  704.     }
  705.     return cnt;
  706. }
  707. #endif
  708.  
  709. static int32 Del_const;
  710.  
  711. /* Find the value of Del_const that will cause one execution of mloop()
  712.  * to take one millisecond
  713.  */
  714. static void
  715. init_delay()
  716. {
  717.     int32 start,delay;
  718.     register int i,j;
  719.     int success = 0;
  720.  
  721.     /* Start with small value to make things tolerable on slow machines */
  722.     Del_const = 10;
  723.     printf("Del_const = %lu\n",Del_const);
  724.     /* Limit the number of iterations in case we don't converge */
  725.     for(i=0;i<5;i++){
  726.         start = msclock();
  727.         for(j=0;j<1000;j++)
  728.             msdelay();
  729.         delay = msclock()-start;
  730.         printf("delay %lu\n",delay);
  731.         if(delay == 0){
  732.             /* Too fast for accurate measurement on coarse clk */    
  733.             Del_const *= 10;
  734.             printf("Del_const = %lu\n",Del_const);
  735.             continue;
  736.         }
  737.         Del_const = (Del_const * 1000)/delay;
  738.         printf("Del_const = %lu\n",Del_const);
  739.         if(delay > 950 && delay < 1050){
  740.             success = 1;
  741.             break;    /* Within 1 tick - Close enough */
  742.         }
  743.     }
  744.     if(!success)
  745.         tprintf("HS: Warning: auto delay set failed\n");
  746. }
  747. /* Delay for one millisecond (once calibrated by init_delay()) */
  748. static void
  749. msdelay()
  750. {
  751.     int32 i;
  752.  
  753.     for(i=Del_const;i !=0;i--)
  754.         ;
  755. }
  756.