home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / HAPN.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  12KB  |  537 lines

  1. /*  Driver for HAPN-1 8273 card on PC
  2.  *  Jon Bloom, KE3Z; adapted from KA9Q's PC-100 driver
  3.  *  Modified Rx interrupt routine to prevent lockup
  4.  *  John Tanner VK2ZXQ 6th Feb 1988
  5.  *  Adapted back into 871225.9 by KA9Q 15 Feb 1988
  6.  */
  7.  
  8. /****************************************************************************
  9. *    $Id: hapn.c 1.2 93/07/16 11:45:00 ROOT_DOS Exp $
  10. *    15 Jul 93    1.2        GT    Fix warnings.                                    *
  11. ****************************************************************************/
  12.  
  13. #include <stdio.h>
  14. #include <dos.h>
  15. #include "global.h"
  16. #ifdef    ANSIPROTO
  17. #include <stdarg.h>
  18. #endif
  19. #include "timer.h"
  20. #include "mbuf.h"
  21. #include "iface.h"
  22. #include "pktdrvr.h"
  23. #include "netuser.h"
  24. #include "hapn.h"
  25. #include "ax25.h"
  26. #include "trace.h"
  27. #include "pc.h"
  28. #include "proc.h"
  29. #include "ip.h"
  30.  
  31. static void cmd_8273 __ARGS((int16 base,int cmd,int np,...));
  32. static int hapn_init __ARGS((struct hapn *hp));
  33. static int hapn_raw __ARGS((struct iface *iface,struct mbuf *bp));
  34. static int hapn_stop __ARGS((struct iface *iface));
  35. static int hcdchk __ARGS((int16 base));
  36. static void hrxint __ARGS((struct hapn *hp));
  37. static void hrxgo __ARGS((struct hapn *hp));
  38. static void htxint __ARGS((void *p));
  39.  
  40. static struct hapn Hapn[NHAPN];
  41. static INTERRUPT (*H_handle[])() = { ha0vec };
  42. static int16 Nhapn;
  43.  
  44. /*  send command to the 8273
  45.  *  "base" = base port of 8273
  46.  *  "cmd"  = command byte
  47.  *  "np"   = number of parameter bytes
  48.  *  "p1"   = first parameter (parameters are int)
  49.  */
  50. #ifdef    ANSIPROTO
  51. static void
  52. cmd_8273(int16 base, int cmd, int np, ...)
  53. {
  54.     int p;
  55.     va_list ap;
  56.  
  57.     while(inportb(base+STA) & CBSY)
  58.         ;
  59.     outportb(base+CMD, cmd);
  60.  
  61.     va_start(ap,np);
  62.     while(np--){
  63.         while(inportb(base+STA) & CPBF)
  64.             ;
  65.         p = va_arg(ap,int);
  66.         outportb(base+PAR, p);
  67.     }
  68.     va_end(ap);
  69. }
  70. #else
  71. /*VARARGS3*/
  72. static void
  73. cmd_8273(base, cmd, np, p1)
  74. int16 base;
  75. int cmd, np, p1;
  76. {
  77.     int *p;
  78.  
  79.     while(inportb(base+STA) & CBSY)
  80.         ;
  81.     outportb(base+CMD, cmd);
  82.     p = &p1;
  83.     while(np--){
  84.         while(inportb(base+STA) & CPBF)
  85.             ;
  86.         outportb(base+PAR, *p++);
  87.     }
  88. }
  89. #endif
  90. /*  Start receiver of 8273 */
  91. static void
  92. hrxgo(hp)
  93. register struct hapn *hp;
  94. {
  95.     cmd_8273(hp->base, GENERAL_RX, 2, hp->bufsiz & 0xff, hp->bufsiz >> 8);
  96. }
  97.  
  98. /*  Interrupt service function.  Entered with hapn index
  99.  *  The "flag" variable is used in this routine to indicate a
  100.  *  valid TX or RX interrupt. If an invalid interrupt is detected
  101.  *  the 8273 is reset.
  102.  */
  103. void
  104. haint(dev)
  105. int dev;
  106. {
  107.     register struct hapn *hp;
  108.     register int16 base;
  109.     char flag = 0;
  110.  
  111.     hp = &Hapn[dev];
  112.     base = hp->base;
  113.  
  114.     /*  Check for TX interrupt  */
  115.     if(inportb(base+STA) & TXINT){
  116.         flag = 1;    /* Valid interrupt, set flag */
  117.         htxint(hp);
  118.     }
  119.     /*  Check for RX interrupt  */
  120.     if(inportb(base+STA) & RXINT){
  121.         flag = 1;    /* Valid interrupt, set flag */
  122.         hrxint(hp);
  123.     }
  124.     /* Check for unknown interrupt  */
  125.     if(!flag){
  126.         hp->badint++;    /* Increment error counter */
  127.         hapn_init(hp);    /* Reinitialise the 8273 */
  128.     }
  129. }
  130. /*  RX interrupt service
  131.  *  if status register bit "RXIRA" is set, interrupt is final,
  132.  *  otherwise, interrupt is data request
  133.  */
  134. static void
  135. hrxint(hp)
  136. register struct hapn *hp;
  137. {
  138.     register struct mbuf *bp;
  139.     register int16 base;
  140.     unsigned char results[10];
  141.     struct phdr phdr;
  142.  
  143.     hp->rxints++;
  144.     base = hp->base;
  145.  
  146.     if(inportb(base+STA) & RXIRA){
  147.         /* RX result interrupt
  148.          * If the result is a good frame 3 bytes need to be read
  149.          * If an error has occurred only one byte need to be read
  150.          */
  151.  
  152.         /* Read first result byte and test for good data */
  153.         if((results[0]=(inportb(base + RXI))) == 0xe0){
  154.             /* Good result; read two more result bytes */
  155.             while((inportb(base + STA) & RXIRA) == 0)
  156.                 ;
  157.             /* Read second result byte */
  158.             results[1] = inportb(base + RXI);
  159.             /* Wait for third result byte  */
  160.             while((inportb(base + STA) & RXIRA) == 0)
  161.                 ;  
  162.             results[2] = inportb(base + RXI);/* Read it */
  163.  
  164.             /* Since this frame is ok put it on the queue */
  165.             bp = alloc_mbuf(sizeof(phdr));
  166.             bp->cnt = sizeof(phdr);
  167.             phdr.iface = hp->iface;
  168.             phdr.type = CL_AX25;
  169.             memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  170.             bp->next = hp->rcvbuf;
  171.             hp->rcvbuf = NULLBUF;
  172.             enqueue(&Hopper, bp);
  173.             hp->rframes++;
  174.         } else {
  175.             /* Error termination
  176.              * Parse RIC and act accordingly
  177.              * Only one result byte returned on error
  178.              */
  179.             switch(results[0]){
  180.             case CRCERR:
  181.                 hp->crcerr++;
  182.                 break;
  183.             case ABORT_DET:
  184.                 hp->aborts++;
  185.                 break;
  186.             case DMA_OVRN:
  187.                 hp->dmaorun++;
  188.                 break;
  189.             case MEM_OVFL:
  190.                 hp->toobig++;
  191.                 break;
  192.             case CD_LOSS:
  193.                 hp->cdloss++;
  194.                 hapn_init(hp);    /* 8273 reset on cd error */
  195.                 break;
  196.             case RX_ORUN:
  197.                 hp->rxorun++;
  198.                 break;
  199.             }
  200.             /* Throw rx buffer contents away to start over */
  201.             hp->rcp = hp->rcvbuf->data;
  202.             hp->rcvbuf->cnt = 0;
  203.         }
  204.         /* Restart the receiver */
  205.         cmd_8273(base,RX_DISABLE,0);
  206.         hrxgo(hp);
  207.     } else {
  208.         /* RX data interrupt; allocate new rx buffer if none present */
  209.         if((bp = hp->rcvbuf) == NULLBUF){
  210.             bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  211.             if(bp == NULLBUF){
  212.                 /* No memory available */
  213.                 hp->nomem++;
  214.                 cmd_8273(base, RX_DISABLE, 0);
  215.                 hrxgo(hp);
  216.                 return;
  217.             }
  218.             /* Init buffer pointer */
  219.             hp->rcp = hp->rcvbuf->data;
  220.         }
  221.         /*  Barf if rx data is more than buffer can hold (should never
  222.          *  happen since 8273 is also counting bytes).
  223.          */
  224.         if(bp->cnt++ >= hp->bufsiz){
  225.             hp->toobig++;
  226.             cmd_8273(base, RX_DISABLE, 0);
  227.             hrxgo(hp);
  228.             free_p(bp);
  229.             hp->rcvbuf = NULLBUF;
  230.             return;
  231.         }
  232.         /* Store the received byte */
  233.         *hp->rcp++ = inportb(base+RXD);
  234.     }
  235. }
  236.  
  237. /*  test for busy channel (CD active)
  238.  *  returns TRUE if channel busy
  239.  */
  240. static int
  241. hcdchk(base)
  242. int16 base;
  243. {
  244.     char isav;
  245.  
  246.     isav = dirps();
  247.     cmd_8273(base, READ_A, 0);
  248.     while(!(inportb(base+STA) & CRBF))
  249.         ;
  250.     restore(isav);
  251.     return((inportb(base+RES) & CD) != 0);
  252. }
  253.  
  254. /*  TX interrupt service
  255.  *  if status register bit "TXIRA" is set, interrupt is final,
  256.  *  otherwise, interrupt is data request
  257.  */
  258. static void
  259. htxint(p)
  260. void *p;
  261. {
  262.     register struct hapn *hp;
  263.     char isav;
  264.     register int16 base;
  265.     int16 len;
  266.     int c;
  267.  
  268.     hp = (struct hapn *)p;
  269.     isav = dirps();
  270.     hp->txints++;
  271.     base = hp->base;
  272.  
  273.     c = 0;
  274.     if(inportb(base+STA) & TXIRA){        /* TX result interupt */
  275.         hp->tstate = IDLE;
  276.         free_p(hp->sndbuf);
  277.         hp->sndbuf = NULLBUF;
  278.  
  279.         /*  Read result  */
  280.         while((inportb(base+STA) & (TXINT | TXIRA)) != (TXINT | TXIRA))
  281.             ;
  282.         c = inportb(base+TXI);
  283.  
  284.         /*  Test for tx abort  */
  285.         switch(c & 0x1f){
  286.         case DMA_URUN:
  287.             hp->t_urun++;
  288.             break;
  289.         case CTS_LOSS:
  290.             hp->ctsloss++;
  291.             break;
  292.         case ABORT_CMPLT:
  293.             hp->taborts++;
  294.             break;
  295.         }
  296.     }
  297.     switch(hp->tstate){
  298.     case IDLE:    /*  See if a buffer is ready to be sent  */
  299.         if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  300.             break;
  301.  
  302.     case DEFER:    /*  Busy-channel check  */
  303.         if(hp->mode == CSMA && (c & 0x1f) != EARLY_TXI){
  304.             if(hcdchk(base)){
  305.                 hp->tstate = DEFER;
  306.                 start_timer(&hp->defer);
  307.                 break;
  308.             }
  309.         }
  310.         /*  Start transmitter  */
  311.         stop_timer(&hp->defer);
  312.         len = len_p(hp->sndbuf);
  313.         cmd_8273(base, TX_FRAME, 2, len & 0xff, len >> 8);
  314.         hp->tstate = ACTIVE;
  315.         hp->tframes++;
  316.         break;
  317.     case ACTIVE:    /*  Get next byte to send  */
  318.         if((c = PULLCHAR(&hp->sndbuf)) == -1){
  319.             cmd_8273(base, ABORT_TXF, 0);
  320.             hp->tstate = IDLE;
  321.         } else
  322.             outportb(base+TXD, c);
  323.         break;
  324.     }
  325.     restore(isav);
  326. }
  327.  
  328. /*  Attach a HAPN adaptor to the system
  329.  *  argv[0]:  hardware type, must be "hapn"
  330.  *  argv[1]:  I/O address, e.g. "0x310"
  331.  *  argv[2]:  vector, e.g. "2"
  332.  *  argv[3]:  mode, must be "ax25"
  333.  *  argv[4]:  interface name, e.g. "ha0"
  334.  *  argv[5]:  rx packet buffer size in bytes
  335.  *  argv[6]:  maximum transmission unit in bytes
  336.  *  argv[7]:  channel-access mechanism, "csma" or "full"
  337.  *  argv[8]: IP address, optional (defaults to Ip_addr)
  338.  */
  339. int
  340. hapn_attach(argc, argv,p)
  341. int argc;
  342. char *argv[];
  343. void *p;
  344. {
  345.     register struct iface *if_h;
  346.     struct hapn *hp;
  347.     int dev, i;
  348.     char isav;
  349.     static struct {
  350.         char *str;
  351.         char type;
  352.     } ch_access [] = { { "csma", 0 }, { "full", 1 } };
  353.  
  354.     if(Nhapn >= NHAPN){
  355.         tprintf("Too many HAPN adaptors\n");
  356.         return -1;
  357.     }
  358.     if(if_lookup(argv[4]) != NULLIF){
  359.         tprintf("Interface %s already exists\n",argv[4]);
  360.         return -1;
  361.     }
  362.     /*  Create new interface structure  */
  363.     if_h = (struct iface *) callocw(1,sizeof(struct iface));
  364.  
  365.     /*  Set interface address  */
  366.     if_h->addr = Ip_addr;
  367.     if(argc > 8)
  368.         if_h->addr = resolve(argv[8]);
  369.     if(if_h->addr == 0){
  370.         tprintf(Noipaddr);
  371.         free((char *)if_h);
  372.         return -1;
  373.     }
  374.     dev = Nhapn++;
  375.     hp = &Hapn[dev];
  376.  
  377.     /*  Initialize hardware constants */
  378.     hp->base = htoi(argv[1]);
  379.     hp->vec = htoi(argv[2]);
  380.  
  381.     /*  Save original interrupt vector  */
  382.     hp->oldvec = getirq(Hapn[dev].vec);
  383.  
  384.     /*  Set new interrupt vector  */
  385.     setirq(hp->vec, H_handle[dev]);
  386.  
  387.     /* Continue filling interface structure */
  388.     if_h->name = strdup(argv[4]);
  389.     if_h->type = CL_AX25;
  390.     if_h->mtu = atoi(argv[6]);
  391.     if_h->dev = dev;
  392.     if_h->stop = hapn_stop;
  393.     if_h->output = ax_output;
  394.     if_h->raw = hapn_raw;
  395.     hp->iface = if_h;
  396.  
  397.     if(strcmp(argv[3], "ax25")){
  398.         tprintf("Mode %s unknown for interface %s\n", argv[3], argv[4]);
  399.         free(if_h->name);
  400.         free((char *) if_h);
  401.         return -1;
  402.     }
  403.     if(Mycall[0] == '\0'){
  404.         tprintf("set mycall first\n");
  405.         free(if_h->name);
  406.         free((char *) if_h);
  407.         return -1;
  408.     }
  409.     if_h->send = ax_send;
  410.     if(if_h->hwaddr == NULLCHAR)
  411.         if_h->hwaddr = mallocw(AXALEN);
  412.     memcpy(if_h->hwaddr,Mycall,AXALEN);
  413.     /*  Link the interface into the interface list  */
  414.     if_h->next = Ifaces;
  415.     Ifaces = if_h;
  416.  
  417.     /*  Fill the local data structure  */
  418.     hp->bufsiz = atoi(argv[5]);
  419.     for(i = 0; i < (sizeof ch_access / sizeof ch_access[0]); i++)
  420.         if(!strcmp(argv[7], ch_access[i].str))
  421.             hp->mode = ch_access[i].type;
  422.  
  423.     /*  Initialize the hardware  */
  424.     isav = dirps();
  425.     hapn_init(hp);
  426.  
  427.     /* Initialize the defer timer */
  428.     set_timer(&hp->defer,MSPTICK);
  429.     hp->defer.func = htxint;
  430.     hp->defer.arg = hp;
  431.  
  432.     /*  Enable the interrupt  */
  433.     maskon(hp->vec);
  434.  
  435.     restore(isav);
  436.     return 0;
  437. }
  438.  
  439. /*  initialize the HAPN adaptor */
  440. static int
  441. hapn_init(hp)
  442. register struct hapn *hp;
  443. {
  444.     register int16 base;
  445.     char isav;
  446.  
  447.     isav = dirps();
  448.     base = hp->base;
  449.  
  450.     /*  Reset the 8273 */
  451.     outportb(base+RST, 1);
  452.     outportb(base+RST, 0);
  453.     inportb(base+TXI);        /* Clear any old IR contents */
  454.     inportb(base+RXI);
  455.  
  456.     /*  Select the operating modes  */
  457.     cmd_8273(base, SET_XFER, 1, 1);
  458.     cmd_8273(base, SET_MODE, 1, HDLC | EARLY | PREFRM | FLG_STM);
  459.     cmd_8273(base, SET_SERIAL, 1, NRZI);
  460.     cmd_8273(base, SET_B, 1, IRQ_ENB | RTS);
  461.     cmd_8273(base, RST_B, 1, 0xff ^ RTS);
  462.     hrxgo(hp);
  463.     restore(isav);
  464.     return 0;
  465. }
  466.  
  467. /*  shut down the HAPN adaptor */
  468. static int
  469. hapn_stop(iface)
  470. struct iface *iface;
  471. {
  472.     int dev;
  473.     int16 base;
  474.     struct hapn *hp;
  475.  
  476.     dev = iface->dev;
  477.     hp = &Hapn[dev];
  478.     base = hp->base;
  479.  
  480.     /*  Mask off interrupt input  */
  481.     maskoff(hp->vec);
  482.  
  483.     /*  Restore original interrupt vector  */
  484.     setirq(hp->vec,hp->oldvec);
  485.  
  486.     /*  Reset the 8273  */
  487.     outportb(base+RST, 1);
  488.     outportb(base+RST, 0);
  489.     return 0;
  490. }
  491.  
  492. /* Display adaptor statistics */
  493. int
  494. dohapnstat(argc,argv,p)
  495. int argc;
  496. char *argv[];
  497. void *p;
  498. {
  499.     struct hapn *hp;
  500.     int i;
  501.  
  502.     if(Nhapn == 0){
  503.         tprintf("No HAPN adaptor attached\n");
  504.         return 1;
  505.     }
  506.     for(i = 0; i < Nhapn; i++){
  507.         hp = &Hapn[i];
  508.         tprintf("HAPN %d:   rxints: %ld   txints: %ld   badint: %-5d\n", i,
  509.          hp->rxints,hp->txints,hp->badint);
  510.         tprintf(" receive  - frames:  %-5d  crcerrs: %-5d  aborts: %-5d  dmaorun: %-5d\n",
  511.          hp->rframes,hp->crcerr, hp->aborts, hp->dmaorun);
  512.         tprintf("          - toobig:  %-5d  dcdloss: %-5d  rxorun: %-5d\n",
  513.          hp->toobig,hp->cdloss,hp->rxorun);
  514.         if(tprintf(" transmit - frames:  %-5d  aborts : %-5d  uruns : %-5d  ctsloss: %-5d\n",
  515.          hp->tframes,hp->taborts, hp->t_urun, hp->ctsloss) == EOF)
  516.             break;
  517.     }
  518.     return 0;
  519. }
  520.  
  521. /* Send raw packet on HAPN interface */
  522. static int
  523. hapn_raw(iface,bp)
  524. struct iface *iface;
  525. struct mbuf *bp;
  526. {
  527.     struct hapn *hp;
  528.  
  529.     hp = &Hapn[iface->dev];
  530.     enqueue(&hp->sndq, bp);
  531.  
  532.     /*  See if anything being transmitted  */
  533.     if(hp->tstate == IDLE)
  534.         htxint(hp);
  535.     return 0;
  536. }
  537.