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