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