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