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