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

  1. /* Interface driver for the PACCOMM PC-100 board for the IBM PC */
  2. /* UNFINISHED, DOESN'T WORK YET - work in progress by Bdale */
  3. /* currently only attempting to use the AMD7910 on Channel A */
  4.  
  5. /****************************************************************************
  6. *    $Id: pc100.c 1.2 93/07/16 11:48:28 ROOT_DOS Exp $
  7. *    15 Jul 93    1.2        GT    Fix warnings.                                    *
  8. ****************************************************************************/
  9.  
  10. #include <stdio.h>
  11. #include <dos.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "iface.h"
  15. #include "pktdrvr.h"
  16. #include "netuser.h"
  17. #include "pc100.h"
  18. #include "8530.h"
  19. #include "ax25.h"
  20. #include "trace.h"
  21. #include "pc.h"
  22. #include "ip.h"
  23.  
  24. static void hspint __ARGS((struct hdlc *hp));
  25. static void hexint __ARGS((struct hdlc *hp));
  26. static void hrxint __ARGS((struct hdlc *hp));
  27. static void htxint __ARGS((register struct hdlc *hp));
  28. static void rts __ARGS((int16 base,int x));
  29. static void hdlcparam __ARGS((struct hdlc *hp));
  30. static int pc_raw __ARGS((struct iface *iface,struct mbuf *bp));
  31. static int pc_stop __ARGS((struct iface *iface));
  32.  
  33. static struct pc100 Pc100[NPC];
  34. static INTERRUPT (*Pchandle[])() = { pc0vec };
  35. static struct hdlc Hdlc[2*NPC];
  36. static int16 Npc;
  37.  
  38. /* Branch table for interrupt handler */
  39. static void (*Svec[]) __ARGS((struct hdlc *hp)) = {
  40.     htxint, hexint, hrxint, hspint
  41. };
  42.  
  43. /* Master interrupt handler for the PC-100 card. All interrupts come
  44.  * here first, then are switched out to the appropriate routine.
  45.  */
  46. void
  47. pcint(dev)
  48. int dev;
  49. {
  50.     register char iv;
  51.     register int16 pcbase;
  52.     struct hdlc *hp;
  53.  
  54.     Pc100[dev].ints++;
  55.     pcbase = Pc100[dev].addr;
  56.  
  57.     /* Read interrupt vector, including status, from channel B */
  58.     iv = read_scc(CTL+pcbase+CHANB,R2);
  59.  
  60.     hp = &Hdlc[2 * dev + ((iv & 0x80)? 0 : 1)];
  61.  
  62.     /* Now switch to appropriate routine */
  63.     (*Svec[(iv>>1) & 0x3])(hp);
  64.  
  65.     /* Reset interrupt pending state (register A only) */
  66.     write_scc(CTL+pcbase+CHANA,R0,RES_H_IUS);
  67.  
  68.     /* Wang the 8530 hardware interrupt acknowledge line - Bdale */
  69.     inportb(pcbase+INTACK);
  70. }
  71. /* HDLC Special Receive Condition interrupt
  72.  * The most common event that triggers this interrupt is the
  73.  * end of a frame; it can also be caused by a receiver overflow.
  74.  */
  75. static void
  76. hspint(hp)
  77. register struct hdlc *hp;
  78. {
  79.     register char c;
  80.  
  81.     hp->spints++;
  82.     c = read_scc(CTL+hp->base,R1);    /* Fetch latched bits */
  83.  
  84.     if((c & (END_FR|CRC_ERR)) == END_FR && hp->rcvbuf != NULLBUF
  85.         && hp->rcvbuf->cnt > 1){
  86.         /* End of valid frame */
  87.         hp->rcvbuf->cnt--;    /* Toss 1st crc byte */
  88.         enqueue(&hp->rcvq,hp->rcvbuf);
  89.         hp->rcvbuf = NULLBUF;
  90.         hp->rcvcnt++;
  91.     } else {
  92.         /* An overflow or CRC error occurred; restart receiver */
  93.         hp->crcerr++;
  94.         if(hp->rcvbuf != NULLBUF){
  95.             hp->rcp = hp->rcvbuf->data;
  96.             hp->rcvbuf->cnt = 0;
  97.         }
  98.     }
  99.     write_scc(CTL+hp->base,R0,ERR_RES);
  100. }
  101. /* HDLC SIO External/Status interrupts
  102.  * The only one of direct interest is a receiver abort; the other
  103.  * usual cause is a change in the modem control leads, so kick the
  104.  * transmit interrupt routine.
  105.  */
  106. static void
  107. hexint(hp)
  108. register struct hdlc *hp;
  109. {
  110.     hp->exints++;
  111.     hp->status = read_scc(CTL+hp->base,R0);    /* Fetch status */
  112.     if((hp->status & BRK_ABRT) && hp->rcvbuf != NULLBUF){
  113.         hp->aborts++;
  114.         /* Restart receiver */
  115.         hp->rcp = hp->rcvbuf->data;
  116.         hp->rcvbuf->cnt = 0;
  117.     }
  118.     write_scc(CTL+hp->base,R0,RES_EXT_INT);
  119.     write_scc(CTL+hp->base,R0,RES_H_IUS);
  120.     /* Kick the transmit interrupt routine for a possible modem change */
  121.     htxint(hp);
  122. }
  123. /* HDLC receiver interrupt handler. Allocates buffers off the freelist,
  124.  * fills them with receive data, and puts them on the receive queue.
  125.  */
  126. static void
  127. hrxint(hp)
  128. register struct hdlc *hp;
  129. {
  130.     register struct mbuf *bp;
  131.     register int16 base;
  132.  
  133.     hp->rxints++;
  134.     base = hp->base;
  135.     /* Allocate a receive buffer if not already present */
  136.     if((bp = hp->rcvbuf) == NULLBUF){
  137.         bp = hp->rcvbuf = alloc_mbuf(hp->bufsiz);
  138.         if(bp == NULLBUF){
  139.             /* No memory, abort receiver */
  140.             hp->nomem++;
  141.             write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  142.             (void) inportb(base+DATA);
  143.             return;
  144.         }
  145.         hp->rcp = hp->rcvbuf->data;
  146.     }
  147.     while(read_scc(CTL+base,R0) & Rx_CH_AV){
  148.         if(bp->cnt++ >= hp->bufsiz){
  149.             /* Too large; abort the receiver, toss buffer */
  150.             hp->toobig++;
  151.             write_scc(CTL+base,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  152.             (void) inportb(base+DATA);
  153.             free_p(bp);
  154.             hp->rcvbuf = NULLBUF;
  155.             break;
  156.         }
  157.         /* Normal save */
  158.         *hp->rcp++ = inportb(base+DATA);
  159.     }
  160. }
  161. static int ctswait;
  162. /* HDLC transmit interrupt service routine
  163.  *
  164.  * The state variable tstate, along with some static pointers,
  165.  * represents the state of the transmit "process".
  166.  */
  167. static void
  168. htxint(hp)
  169. register struct hdlc *hp;
  170. {
  171.     register int16 base;
  172.     char i_state;
  173.     int c;
  174.  
  175.     i_state = dirps();
  176.     hp->txints++;
  177.     base = hp->base;
  178.     while(read_scc(CTL+base,R0) & Tx_BUF_EMP){
  179.         switch(hp->tstate){
  180.         /* First here for efficiency */
  181.         case ACTIVE:        /* Sending frame */
  182.             if((c = PULLCHAR(&hp->sndbuf)) != -1){
  183.                 outportb(base+DATA,c);
  184.             } else {
  185.                 /* Do this after sending the last byte */
  186.                 write_scc(CTL+base,R0,RES_Tx_P);
  187.                 if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF){
  188.                     switch(hp->mode){
  189.                     case CSMA:
  190.                         /* Begin transmitter shutdown */
  191.                         hp->tstate = FLUSH;
  192.                         break;
  193.                     case FULLDUP:
  194.                         hp->tstate = IDLE;
  195.                         break;
  196.                     }
  197.                 }
  198.             }
  199.             continue;
  200.         case IDLE:
  201.             /* Transmitter idle. Find a frame for transmission */
  202.             if((hp->sndbuf = dequeue(&hp->sndq)) == NULLBUF)
  203.                 goto ret;
  204.  
  205.         case DEFER:    /* note fall-thru */
  206.             if(hp->mode == CSMA && (hp->status & DCD)){
  207.                 hp->tstate = DEFER;
  208.                 goto ret;
  209.             }
  210.             rts(base,ON);    /* Transmitter on */
  211.         case KEYUP:    /* note fall-thru */
  212.             if((hp->status & CTS) == 0){
  213.                 ctswait++;
  214.                 hp->tstate = KEYUP;
  215.                 goto ret;
  216.             }
  217.             write_scc(CTL+base,R0,RES_Tx_CRC);
  218.             c = PULLCHAR(&hp->sndbuf);
  219.             outportb(hp->base+DATA,c);
  220.             hp->tstate = ACTIVE;
  221.             write_scc(CTL+base,R0,RES_EOM_L);
  222.             continue;
  223.         case FLUSH:    /* Sending flush character */
  224.             outportb(hp->base+DATA,(char)0);
  225.             hp->tstate = FIN2;
  226.             continue;
  227.         case FIN2:
  228.             write_scc(CTL+base,R0,SEND_ABORT);
  229.             hp->tstate = IDLE;
  230.             rts(base,OFF);
  231.             write_scc(CTL+base,R0,RES_Tx_P);
  232.             continue;
  233.         }
  234.     }
  235. ret:    restore(i_state);
  236. }
  237.  
  238. /* Set request-to-send on modem */
  239. static void
  240. rts(base,x)
  241. int16 base;
  242. int x;
  243. {
  244.     int16 cmd;
  245.  
  246.     if(x)
  247.         cmd = TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR;
  248.     else
  249.         cmd = TxCRC_ENAB | TxENAB | Tx8 | DTR;
  250.     write_scc(CTL+base,R5,cmd);
  251. }
  252. /* (re)Initialize HDLC controller parameters */
  253. static void
  254. hdlcparam(hp)
  255. register struct hdlc *hp;
  256. {
  257.     int16 tc;
  258.     char i_state;
  259.     register int16 base;
  260.  
  261.     /* Initialize 8530 channel for SDLC operation */
  262.     base = hp->base;
  263.     i_state = dirps();
  264.  
  265.     switch(base & 2){
  266.     case 0:
  267.         write_scc(CTL+base,R9,CHRA);    /* Reset channel A */
  268.         break;
  269.     case 2:
  270.         write_scc(CTL+base,R9,CHRB);    /* Reset channel B */
  271.         break;
  272.     }
  273.     /* Wait/DMA disable, Int on all Rx chars + spec condition,
  274.      * parity NOT spec condition, TxINT enable, Ext Int enable
  275.      */
  276.     write_scc(CTL+base,R1,INT_ALL_Rx | TxINT_ENAB | EXT_INT_ENAB);
  277.  
  278.     /* Dummy interrupt vector, will be modified by interrupt type
  279.      * (This probably isn't necessary)
  280.      */
  281.     write_scc(CTL+base,R2,0);
  282.  
  283.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  284.      * no address search, no inhibit sync chars, enable RX
  285.      */
  286.     write_scc(CTL+base,R3,Rx8|RxCRC_ENAB|RxENABLE);
  287.  
  288.     /* X1 clock, SDLC mode, Sync modes enable, parity disable
  289.      * (Note: the DPLL does a by-32 clock division, so it's not necessary
  290.      * to divide here).
  291.      */
  292.     write_scc(CTL+base,R4,X1CLK | SDLC | SYNC_ENAB);
  293.  
  294.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  295.      * RTS off, TxCRC enable
  296.      */
  297.     write_scc(CTL+base,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  298.  
  299.     /* SDLC flag */
  300.     write_scc(CTL+base,R7,FLAG);
  301.  
  302.     /* No reset, status low, master int enable, enable lower chain,
  303.      * no vector, vector includes status
  304.      */
  305.     write_scc(CTL+base,R9,MIE|NV|VIS);
  306.     /* CRC preset 1, NRZI encoding, no active on poll, flag idle,
  307.      * flag on underrun, no loop mode, 8 bit sync
  308.      */
  309.     write_scc(CTL+base,R10,CRCPS|NRZI);
  310.  
  311.     /* Board no longer channel-specific for clk.  The board should be set
  312.      * up to run from the 4.9152Mhz onboard crystal connected to PCLK.
  313.      * Both channels get receive clock at 32x from PCLK via the DPLL,
  314.      * with TRxC as an output, via a 4040 div by 32 counter to RTxC set
  315.      * us as an input to provide the transmit clock.
  316.      */
  317.  
  318.     /*            TRxC = BR Generator Output, TRxC O/I,
  319.      *          transmit clock = RTxC pin, 
  320.      *          receive clock = DPLL output
  321.      */
  322.     write_scc(CTL+base,R11,TRxCBR|TRxCOI|TCRTxCP|RCDPLL);
  323.  
  324.     /* Compute and load baud rate generator time constant
  325.      * DPLL needs x32 clock
  326.      * XTAL is defined in pc100.h to be the crystal clock / (2 * 32)
  327.      */
  328.     tc = XTAL/(hp->speed) - 2;
  329.     write_scc(CTL+base,R12,tc & 0xff);
  330.     write_scc(CTL+base,R13,(tc >> 8) & 0xff);
  331.  
  332.     write_scc(CTL+base,R14,SNRZI);    /* Set NRZI mode */
  333.     write_scc(CTL+base,R14,SSBR);    /* Set DPLL source = BR generator */
  334.     write_scc(CTL+base,R14,SEARCH);    /* Enter search mode */
  335.     /* Set baud rate gen source = PCLK, enable baud rate gen */
  336.     write_scc(CTL+base,R14,BRENABL|BRSRC);
  337.  
  338.     /* Break/abort IE, TX EOM IE, CTS IE, no SYNC/HUNT IE, DCD IE,
  339.      * no Zero Count IE
  340.      */
  341.     write_scc(CTL+base,R15,BRKIE|TxUIE|CTSIE|DCDIE);
  342.  
  343.     restore(i_state);
  344.     if(hp->mode == FULLDUP){
  345.         rts(base,ON);
  346.     } else if(hp->tstate == IDLE){
  347.         rts(base,OFF);
  348.     }
  349. }
  350. /* Attach a PC-100 interface to the system
  351.  * argv[0]: hardware type, must be "pc100"
  352.  * argv[1]: I/O address, e.g., "0x380"
  353.  * argv[2]: vector, e.g., "2"
  354.  * argv[3]: mode, must be:
  355.  *        "ax25" (AX.25 UI frame format)
  356.  * argv[4]: interface label, e.g., "pc0"
  357.  * argv[5]: receiver packet buffer size in bytes
  358.  * argv[6]: maximum transmission unit, bytes
  359.  * argv[7]: interface speed, e.g, "9600"
  360.  * argv[8]: First IP address, optional (defaults to Ip_addr)
  361.  * argv[9]: Second IP address, optional (defaults to Ip_addr)
  362.  */
  363. int
  364. pc_attach(argc,argv,p)
  365. int argc;
  366. char *argv[];
  367. void *p;
  368. {
  369.     register struct iface *if_pca,*if_pcb;
  370.     struct hdlc *hp;
  371.     int dev;
  372.  
  373.     if(Npc >= NPC){
  374.         tprintf("Too many pc100 controllers\n");
  375.         return -1;
  376.     }
  377.     if(if_lookup(argv[4]) != NULLIF){
  378.         tprintf("Interface %s already exists\n",argv[4]);
  379.         return -1;
  380.     }
  381.     dev = Npc++;
  382.  
  383.     /* Initialize hardware-level control structure */
  384.     Pc100[dev].addr = htoi(argv[1]);
  385.     Pc100[dev].vec = htoi(argv[2]);
  386.     /* Initialize modems */
  387.     outportb(Pc100[dev].addr + MODEM_CTL,(char)0x22);
  388.  
  389.     /* Save original interrupt vector */
  390.     Pc100[dev].oldvec = getirq(Pc100[dev].vec);
  391.     /* Set new interrupt vector */
  392.     if(setirq(Pc100[dev].vec,Pchandle[dev]) == -1){
  393.         tprintf("IRQ %u out of range\n",Pc100[dev].vec);
  394.         Npc--;
  395.         return -1;
  396.     }
  397.     /* Create interface structures and fill in details */
  398.     if_pca = (struct iface *)callocw(1,sizeof(struct iface));
  399.     if_pcb = (struct iface *)callocw(1,sizeof(struct iface));
  400.  
  401.     if_pca->addr = if_pcb->addr = Ip_addr;
  402.     if(argc > 8)
  403.         if_pca->addr = resolve(argv[8]);
  404.  
  405.     if(argc > 9)
  406.         if_pcb->addr = resolve(argv[9]);
  407.     if(if_pca->addr == 0 || if_pcb->addr == 0){
  408.         tprintf(Noipaddr);
  409.         free((char *)if_pca);
  410.         free((char *)if_pcb);
  411.         return -1;
  412.     }
  413.     if_pca->name = strdup(argv[4]);
  414.     if_pcb->name = strdup(argv[4]);
  415.     if_pcb->name[strlen(argv[4]) - 1]++;    /* kludge */
  416.     if_pcb->mtu = if_pca->mtu = atoi(argv[6]);
  417.     if_pcb->type = if_pca->type = CL_AX25;
  418.     if_pca->dev = 2*dev;
  419.     if_pcb->dev = 2*dev + 1;
  420.     if_pcb->stop = if_pca->stop = pc_stop;
  421.     if_pcb->output = if_pca->output = ax_output;
  422.     if_pcb->raw = pc_raw;
  423.  
  424.     if(strcmp(argv[3],"ax25") == 0){
  425.         if(Mycall[0] == '\0'){
  426.             tprintf("set mycall first\n");
  427.             free((char *)if_pca);
  428.             free((char *)if_pcb);
  429.             return -1;
  430.         }        
  431.         if_pcb->send = if_pca->send = ax_send;
  432.         if(if_pcb->hwaddr == NULLCHAR)
  433.             if_pcb->hwaddr = mallocw(AXALEN);
  434.         memcpy(if_pcb->hwaddr,Mycall,AXALEN);
  435.     } else {
  436.         tprintf("Mode %s unknown for interface %s\n",
  437.             argv[3],argv[4]);
  438.         free((char *)if_pca);
  439.         free((char *)if_pcb);
  440.         return -1;
  441.     }
  442.     if_pca->next = if_pcb;
  443.     if_pcb->next = Ifaces;
  444.     Ifaces = if_pca;
  445.  
  446.     hp = &Hdlc[2*dev+1];
  447.     hp->speed = (int16)atoi(argv[7]);
  448.     hp->base = Pc100[dev].addr + CHANB;
  449.     hp->bufsiz = atoi(argv[5]);
  450.     hdlcparam(hp);
  451.  
  452.     hp = &Hdlc[2*dev];
  453.     hp->speed = (int16)atoi(argv[7]);
  454.     hp->base = Pc100[dev].addr + CHANA;
  455.     hp->bufsiz = atoi(argv[5]);
  456.     hdlcparam(hp);
  457.  
  458.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  459.     clrbit(INTMASK,(char)(1<<Pc100[dev].vec));
  460.  
  461.     return 0;
  462. }
  463. static int
  464. pc_stop(iface)
  465. struct iface *iface;
  466. {
  467.     int dev;
  468.  
  469.     dev = iface->dev;
  470.     if(dev & 1)
  471.         return 0;
  472.     dev >>= 1;    /* Convert back into PC100 number */
  473.     /* Turn off interrupts */
  474.     maskoff(Pc100[dev].vec);
  475.  
  476.     /* Restore original interrupt vector */
  477.     setirq(Pc100[dev].vec,Pc100[dev].oldvec);
  478.  
  479.     /* Force hardware reset */
  480.     write_scc(CTL+Pc100[dev].addr + CHANA,R9,FHWRES);
  481.     return 0;
  482. }
  483.     
  484. /* Send raw packet on PC-100 */
  485. static int
  486. pc_raw(iface,bp)
  487. struct iface *iface;
  488. struct mbuf *bp;
  489. {
  490.     char kickflag;
  491.     struct hdlc *hp;
  492.  
  493.     dump(iface,IF_TRACE_OUT,CL_AX25,bp);
  494.     iface->rawsndcnt++;
  495.     iface->lastsent = secclock();
  496.     hp = &Hdlc[iface->dev];
  497.     kickflag = (hp->sndq == NULL);
  498.     enqueue(&hp->sndq,bp);
  499.     if(kickflag)
  500.         htxint(&Hdlc[iface->dev]);
  501.     return 0;
  502. }
  503.