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