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