home *** CD-ROM | disk | FTP | other *** search
/ Troubleshooting Netware Systems / CSTRIAL0196.BIN / attach / pcc / v08n03 / netwrk.exe / WDPOST.ZIP / WDPOST.TAR / wdpost.dir / sample.drv / macmod.c < prev    next >
Text File  |  1988-06-21  |  20KB  |  695 lines

  1. /************************************************************************
  2. * RCS  $Revision$            $Date$                *
  3. *                                    *
  4. * MACMOD.C                                *
  5. * (c) Copyright 1987 Western Digital Corporation (R).            *
  6. * All rights reserved. Contains confidential information and trade     *
  7. * secrets proprietary to Western Digital.
  8. *                                    *
  9. * Environment:                                *
  10. *     MS-DOS, WD8003                             *
  11. *                                    *
  12. *                                    *
  13. * Module Description:                            *
  14. *    This file contains the interface routines to the LLC sublayer,    *
  15. *    and the 8390 based WD8003 LAN controller card.            *
  16. *                                    *
  17. * Function:                                *
  18. * --------                                *
  19. *    There are six routines in this C file                *
  20. *                                    *
  21. *    1.  init_lanc    one time LAN controller set up routine        *
  22. *    2.  stop_mac    reset 8390, take it off line            *
  23. *    3.a init_mac    MAC sublayer initialization routine        *
  24. *    3.b start_mac    MAC sublayer start routine            *
  25. *    4.  M_DATArequest    handle a msdu from LLC layer            *
  26. *    5.  do_mac_queue    process rx_queue until it is empty        *
  27. *                                    *
  28. * History:                                 *
  29. * -------                                    *
  30. *    DATE:  3/18/87                                     *        *
  31. *    LEVEL: et.bb.00                            *
  32. *    WHO:   KC                                *
  33. *    CHANGE: create macmod.c for wd8003                    *
  34. *                                    *
  35. *    DATE:  6/18/87                                     *        *
  36. *    LEVEL: et.bb.01                            *
  37. *    WHO:   KC                                *
  38. *    CHANGE: [01]  WDBPR# 762                                 *
  39. *    PROBLEM:hw int gets in before init_all() completed. System halts    *
  40. *         during NETBIOS loading with fatal code 12 (bad work entry).*
  41. *    FIX:    use in_diags to block the hw int form entering osi module. *
  42. *         set in_diags at beginning of init_lanc() and stop_mac,    *
  43. *         reset in_diags at end of start_mac().            *
  44. *                                    *
  45. *    DATE:  9/24/87                                     *        *
  46. *    LEVEL: et.bb.05                            *
  47. *    WHO:   KC                                *
  48. *    CHANGE: [02]  WDBPR# 823                                 *
  49. *    PROBLEM:add delay before tx frame in order to run 8003S with 8000S    *
  50. *    FIX:    init_lanc() calls starlan_wait() before calls init_8390    *
  51. *         to set up the wait loop count for different speed machine    *
  52. *         when using start lan board.                        *
  53. *                                    *
  54. *    Date: 10/6/87
  55. *    Level:etbb05
  56. *    WHO:  Steve Chen
  57. *    CHANGE: porting to microsoft c compiler 4.0
  58. *
  59. ************************************************************************/
  60.  
  61.  
  62. #include "mac.h"                          
  63.  
  64. #define COMMENTOUT
  65.  
  66. /* defined some hardware dependent value, should put into lancons.h
  67.    and MACcons.h later on */
  68.  
  69. /* #define IO_BASE_OF_WD8003    0x0280    */    /* default base */
  70. #define MAX_WD8003_DATA           1518    /* should be other value,chip depnendent value */
  71.  
  72. #define W83CREG        0x00    /* I/O port definition */
  73. #define    ADDROM        0x08
  74. #define    CMDR        0x10    
  75. #define RCR        0x1C
  76.  
  77. #define MSK_RESET    0x80    /* W83CREG masks */
  78. #define MSK_ENASH    0x40
  79.  
  80. #define MSK_STP        0x01    /* 8390 CMDR masks */
  81. #define MSK_STA        0x02      
  82. #define MSK_RD2        0x20
  83.  
  84. #define MSK_AB        0x04    /* 8390 RCR */
  85.  
  86. #define TB_SIZE        0x02    /* number of tx buff in shard memory */
  87.  
  88.  
  89. extern    hdw_isr();        /* network interrupt service routine */
  90. extern    long get_vec();        /* returns interrupt vectors */
  91. extern    int debug;
  92. extern    char phreaque;
  93. extern    node_address *my_eaddr;
  94. extern    int bufsize;
  95. extern    int  WD8_base; 
  96. extern    int SM_base;
  97. extern    char adapter_irq;
  98. extern  char in_diags;        /* [01] */
  99. /* %%5%%+ */
  100. extern    int m_channel;        /*[8] micro channel flag */
  101. /* %%5%%- */
  102. /* OSI version info */
  103. char    version[] = VERSION;
  104. char    licensee[] = LICENSEE;
  105. char    machine[] = MACHINE;
  106.  
  107.  
  108. buf_type    tx_buf;        /* transmit buffer */
  109. buf_type    rx_buf;        /* receive buffer */
  110. struct db_list    tx_queue;    /* mac tx queue */
  111. struct db_list    rx_queue;    /* mac rx queue */
  112. unsigned char tb_cur;    /* curr tx buf of shr mem being tx */
  113. unsigned char tb_use;    /* no of tx buf's being occupied */
  114. unsigned int tb_lnth[TB_SIZE];    /* an array for byte count of each tb in shr mem */
  115. unsigned char OSI_RST = 0; /* flag for OSI reset, set by stop_mac, reset by init_mac */
  116.  
  117. /* broadcast node address (used by network layer) */
  118. node_address brd_node = {
  119.             {0xff,0xff,0xff,0xff,0xff,0xff}
  120.             };
  121.  
  122. char    mac_type=3;    /* MAC type in 802 family */
  123. /* %%4%%+ */
  124. int    int_mask_reg; /*[8] interrupt mask register  */
  125. extern     int    int_reg;   /* [8] interrupt register */
  126. int    int_base;  /* base vector # for controller */
  127. /* %%4%%- */
  128. /*
  129.  * MAC sublayer statistics counters.  The order of counters 0-12 should
  130.  * not be changed from one driver to the next since the Netbios uses 
  131.  * these statistics in all drivers for it's STATUS command.
  132.  */
  133. struct mstat MACstat;
  134. struct sminfo macinfo[] = {
  135.     {0, &MACstat.t0},
  136.     {1, &MACstat.txok},
  137.     {2, &MACstat.collsn},
  138.     {3, &MACstat.txbad},
  139.     {4, &MACstat.collsn},
  140.     {5, &MACstat.underrun},
  141.     {6, &MACstat.rxrd},
  142.     {7, &MACstat.rxok},
  143.     {8, &MACstat.crcerr},
  144.     {9, &MACstat.rxblkd},
  145.     {10,&MACstat.algerr},
  146.     {11,&MACstat.srtfrm},
  147.     {12,&MACstat.rxnom},
  148.     {13,&MACstat.lostcrs},
  149.     {14,&MACstat.lostcts},
  150.     {15,&MACstat.overrun},
  151.     {-1, NULL}
  152. };
  153.  
  154. /************************************************************************
  155. *                                    *
  156. *    init_lanc(max_tpdu, base, uirq, page, node, fnode)            *
  157. *                                    *
  158. *    One time LANC setup.                        *
  159. *    Setup and enable MAC interrupts and lanc control structures.    *
  160. *    Should be called before "terminate & stay resident" is called.    *
  161. *                                    *
  162. *                                    *
  163. *    Description :                            *
  164. *    -----------                            *
  165. *    check if hw can accommodate proposed max frame size        *
  166. *        if not, exit 1                             *
  167. *    overwrite default SM_base(c000h) if page specified by user    *
  168. *    overwrite default WD8_base(280h) if base specified by user    *
  169. *    Sumcheck the LAN addr                        *
  170. *        if failed, exit 2                    *
  171. *    if uirq specified by user                    *
  172. *        if range check failed, exit 2                *
  173. *        if range ok, write to adapter_irq & irq            *
  174. *    if uirq not specified by user                    *
  175. *        read irq level from status reg or use default value    *
  176. *        write to adpter_irq                     *
  177. *    set up LAN interrupt vector & enable LAN interrupt        *
  178. *    clr rx_q & tx_q                            *
  179. *    clr phreaque                            *
  180. *    write MAX_BFSZ into bufsize                    *
  181. *    set up my_eaddr(ptr) useing user specified addr 'node' or    *
  182. *         read from ADDROM. and return value to fnode(ptr)    *
  183. *    reset WD 8003                            *
  184. *    do dgn test here if available                    *
  185. *         if failed, reset 8003 and restore old irq vector, exit2*
  186. *    call init_8390() to initial the 8390                *
  187. *                                    *
  188. *    Error Exit : 1  'unable to accomdate the user specified frame'    *
  189. *    ----------       or 'network irq already in use'            *
  190. *             2  'bad ROM checksum' or                *
  191. *                 'bad user irq' or                *    *
  192. *                 'bad dgn test' (not available now)        *                    *
  193. *                                    *                                    *
  194. *    Call: init_8390()                         *
  195. *    ----                                   *
  196. *                                    *
  197. ************************************************************************/
  198.  
  199. init_lanc(max_tpdu, base, uirq, page, node, fnode)
  200.     int        max_tpdu;    /* includes transport header */
  201.     unsigned     base;        /* I/O base of WD8000 */
  202.     char        uirq;        /* interrupt level selected by user */
  203.     unsigned    page;        /* page addr of shared memory */
  204.     register node_address     *node;    /* node address selected by user */
  205.     node_address    *fnode;        /* return addr for node address */
  206.  
  207.     {
  208.     struct cpuaddr    netvec;
  209.     long        oldnetvec;    /* old network interrupt vector */
  210.     char         oldmask, newmask;
  211.     unsigned char    irq;
  212.     unsigned char    adrsum;
  213.     register int        i;
  214. in_diags = 1;    /* [01] */
  215. debug = 1;
  216. #ifdef DEBUG
  217.     if (debug) 
  218.         {
  219.         printf("<ilanc base %x uirq %b node ", base, uirq);
  220.         print_addr(node);
  221.         }
  222. #endif
  223.  
  224.     /* see if the hardware can accommodate proposed max frame size */
  225.     if ((max_tpdu + MPCI_LEN + LPCI_LEN + NPCI_LEN)  > MAX_WD8003_DATA)
  226.         {
  227.         printf("Unable to accommodate frame size (%d)\n", max_tpdu);
  228.         _exit(1);
  229.         }                            
  230.  
  231.     /* set up SM_base if value selected by the user otherwise use default */
  232.     if (page != 0xffff)
  233.         SM_base = page << 4;    /* page number into paragragh number */
  234.                                            
  235.         
  236.     /* set up WD8_base using value selected by the user or default value */
  237.     if (base != 0xffff)
  238.         WD8_base = base;        /* WD8_base default to 280h */
  239. /*    if (uirq == 0xff)
  240.         uirq = INTVEC;    */          
  241.     
  242.     /* sumcheck the addr ROM */
  243.     adrsum = 0;
  244.     for (i= 0; i < 8; i++)
  245.         adrsum = adrsum + in(ADDROM + WD8_base + i);
  246.     if (adrsum != 0xff)
  247.         {
  248.         printf("Checksum error in LAN address ROM\n");
  249.         printf("Possible error in I/O base address (%x)\n", WD8_base);
  250.         printf(" --- Netbios Emulator installation aborted.\n");
  251.         _exit(2);   
  252.         }
  253.  
  254.     /*
  255.      * Set up and enable lanc interrupts, uirq is set to 0xff 
  256.      * if the interrupt level should be read from the board
  257.      */ 
  258.     
  259.     /* set up irq level from user selected uirq(parm3) or from Board
  260.     or use default INTVEC = 3, write irq into adapter_irq */
  261.     
  262.     irq = uirq;
  263.     if ( irq != 0xff)        /* user selected */ 
  264. /* %%4%%+ */
  265.         {        /*[8] different irq allowed for micro channel */
  266.         if (  (!m_channel && (irq < 2 || irq > 7)) || ( m_channel && (irq != 3) && (irq != 4) && (irq != 10) && (irq != 15))  ) 
  267. /* %%4%%- */
  268.             {
  269.             printf("Invalid interrupt level (%x)\n", irq);
  270.             printf (" --- Netbios Emulator installation aborted.\n");
  271.             _exit(2);
  272.             }
  273.         adapter_irq = irq;
  274.         }
  275.  
  276.     else
  277.         {
  278.         /* read from status reg or use default value */
  279.             /* irq = in( WD8_base + W83SREG); */
  280.         /* irq = irq & 0x07;    */
  281.         
  282.         irq = INTVEC;            /* use default value */
  283.         adapter_irq = INTVEC;
  284.         }
  285.  
  286.  
  287. #ifdef DEBUG
  288.     if (debug) printf("<getirq irq%bH>", irq);
  289. #endif
  290. /* %%4%%+ */
  291.     if ( irq > 7) {     /*[8]micro channel level 10, 15 */
  292.         int_mask_reg = P8259_2;    /* interrupt controller 2 */
  293.         int_reg    = INTREG_2;
  294.         newmask = 1 << (irq - 8);
  295.         int_base = INTBASE_2 - 8;     /* interrupt base vector */
  296.          }
  297.     else {
  298.         int_mask_reg = P8259;     /* interrupt controller 1 */
  299.         int_reg = INTREG;
  300.         newmask = 1 << irq;
  301.         int_base = INTBASE;    /* interrupt base vector */
  302.     } 
  303.     /* use interrupt level to set up 8259 controller mask */
  304.     /* newmask = 1 << irq;*/
  305.     oldmask = in(int_mask_reg);
  306.  
  307.     /* for micro channel irq = 3, 4, 10,15  
  308.               use int vector # 11,12,0x72,0x77 
  309.        for Non micro channel machine irq =  2, 3, 4, 5, 6, 7  
  310.                               use vector #  10,11,12,13,14,15 */ 
  311.                  
  312. #ifndef COMMENTOUT
  313.     /* Check if the interrupt is already in use */
  314.     if ( !(oldmask & newmask))
  315.         {
  316.         printf("Network interrupt already in use (%bH)\n", 
  317.              irq+int_base);
  318.         _exit(1);
  319.         }
  320. #endif
  321.  
  322.     /* Setup the controller interrupt vector */
  323.     oldnetvec = get_vec(irq+int_base);     /* get old interrupt vec */
  324.     netvec.offs = (unsigned) hdw_isr;    /* make new net vector */
  325.     netvec.seg  = (unsigned) get_cs();    
  326.     set_vec(irq+int_base, netvec);        /* set new vector up */
  327.     
  328.     /* Enable network interrupts */
  329.     out(int_mask_reg, oldmask & ~newmask);                        
  330. /* %%4%%- */
  331.        
  332.     /*    
  333.      * Initialize the controller. Controller needs to test OSI's
  334.      * maximum buffer size in it's self-test, our node address is
  335.      * then copied to fnode.
  336.      */
  337.  
  338.     /* initialize queues for use in hdw_init */
  339.     tx_queue.first = tx_queue.last = (buf_type) &tx_queue;
  340.     rx_queue.first = rx_queue.last = (buf_type) &rx_queue;
  341.  
  342.     /* clear phreaque */
  343.  
  344.            phreaque = 0;
  345.  
  346.     /* write max buf size (defined in comcons.h) into  bufsize */
  347.     bufsize = MAXBFSZ;                 
  348.  
  349.     /* set up my_eaddr from user(parm4:node) or from addr ROM */
  350.     my_eaddr = fnode;
  351.     for (i = 0; i< NODSIZ ; i++)    /* test if user select nd adr */
  352.         if( node->addr[i] != 0xff ) break;            
  353.  
  354.     
  355.     if ( i == NODSIZ )    /* node = 0xffff..., read from ROM */
  356.         for (i = 0; i< NODSIZ; i++)
  357.             fnode->addr[i] = in(WD8_base + ADDROM + i);
  358.     else        /* user selected adr (parm4 != 0xffffffffffff) */
  359.         for (i = 0; i< NODSIZ; i++)
  360.             fnode->addr[i] = node->addr[i];
  361.  
  362.     /* reset WD8003 board, and then enable the shared memory */
  363.     /* use SM_base to calculate the MSK_DECOD */
  364.     out(WD8_base + W83CREG, MSK_RESET);
  365.     out(WD8_base + W83CREG, 0);
  366. /* %%1%%+ */    
  367.     if ( m_channel)            /*[8] micro channel machine */
  368.         out(WD8_base + W83CREG, MSK_ENASH);
  369.     else
  370.         out(WD8_base + W83CREG, MSK_ENASH + (SM_base>>9 & 0x3f));
  371. /* %%1%%- */    
  372.  
  373. /* clear MACstat if there is some DGN test performed  in hdw_init */
  374. /*    status = init_dgn()
  375.          MACstat.t0 = 0;
  376.     MACstat.txok = 0;
  377.     MACstat.txbad = 0;
  378.     MACstat.collsn = 0;
  379.     MACstat.lostcrs = 0;
  380.     MACstat.lostcts = 0;
  381.     MACstat.underrun = 0;
  382.     MACstat.rxrd = 0;
  383.     MACstat.rxok = 0;
  384.     MACstat.rxnrd = 0;
  385.     MACstat.crcerr = 0;
  386.     MACstat.overrun = 0;
  387.     MACstat.algerr = 0;
  388.     MACstat.srtfrm = 0;
  389.     MACstat.rxnom = 0;
  390.     MACstat.rxblkd = 0;
  391.     MACstat.ex_lockup = 0;
  392.     MACstat.ia_corrup = 0;
  393.     MACstat.spur_int = 0;    
  394.     
  395.  
  396. #ifdef DEBUG
  397.     if (debug) printf("<init_dgn stat%xH>", status);
  398. #endif
  399. */
  400. /* Check for hardware init_dgn failure. if failed, reset 8003 and restore old int */
  401. /*    if (status < 0)
  402.         {
  403.         out (WD8_base + W83CREG, MSK_RESET);
  404.         out (WD8_base + W83CREG, 0);
  405.         printf (" --- OSI protocol layer installation aborted.\n");
  406.  
  407.         set_vec(irq+int_base, oldnetvec);    
  408.  
  409.         _exit(2);
  410.         }
  411. */
  412.     
  413.     /* [02] */
  414.     starlan_wait();     /* initialize LAN type and Starlan write wait states */
  415.  
  416.  
  417.     /* call init_8390 */
  418.     init_8390();
  419.  
  420. #ifdef DEBUG
  421.     if (debug) printf("<init_lanc done>\n");
  422. #endif
  423.  
  424.     }
  425.  
  426.  
  427. /************************************************************************
  428. *                                    *
  429. *     stop_mac - reset 8390, reinitial LAN controller register.    *
  430. *           and take 8390 off line, init_mac will activate it    * 
  431. *           later.                            *
  432. *                                    *
  433. ************************************************************************/
  434.  
  435. stop_mac ()
  436.     {
  437.     in_diags = 1;        /* [01] */
  438.     /* set flag OSI_RST for init_8390 */
  439.     OSI_RST = 1;
  440.     /* do a software reset */
  441.     out (WD8_base + CMDR, MSK_STP + MSK_RD2);        /* take 8390 off line */
  442.  
  443.     /* call init_8390 */
  444.     init_8390();
  445.  
  446.     
  447.  
  448. #ifdef DEBUG
  449.     if (debug)
  450.         printf("<stop_mac done>");
  451. #endif
  452.  
  453.     }
  454.  
  455.  
  456. #ifdef DEBUG
  457.  
  458. print_addr(node)
  459.     register node_address    *node;
  460.  
  461.     {
  462.     register int        j;
  463.  
  464.     for (j=0; j<NODSIZ; j++)
  465.         printf("%b", node->addr[j]);
  466.     }
  467. #endif
  468.  
  469.  
  470. /************************************************************************
  471. *                                    *
  472. *  init_mac()                                *
  473. *  Media Access Control Sublayer initialization routine.        *
  474. *  Called whenever the OSI module is reset (ie. via a Netbios RESET    *
  475. *  command).  Init_mac should only be called after stop_mac.        *
  476. *                                    *
  477. ************************************************************************/
  478.  
  479. init_mac ()
  480.     {
  481.  
  482.     tx_buf = NULL;
  483.     tx_queue.first = tx_queue.last = (buf_type) &tx_queue;
  484.     rx_queue.first = rx_queue.last = (buf_type) &rx_queue;
  485.     
  486.     tb_use = 0;                  /* clr flag and phreaque */
  487.     tb_cur = 0;
  488.     phreaque = 0;        
  489.  
  490.     /* reset  the OSI_RST flag and put 8390 on line */
  491.     OSI_RST = 0;
  492.  
  493.                                 
  494.     }
  495.  
  496.  
  497. /************************************************************************
  498. *                                    *
  499. *    start_mac()                            *
  500. *    Media Access Control Sublayer start routine.            *
  501. *    put 8390 on line and enables the receiver                        *
  502. *                                    *
  503. ************************************************************************/
  504.                                      
  505. start_mac()
  506.     {
  507.  
  508.     /* put 8390 on line and enable the receiver */
  509.     out(CMDR + WD8_base, MSK_STA + MSK_RD2);            /* activate the 8390 */
  510.     out(RCR + WD8_base, MSK_AB);                /* enable the rxer */
  511.     
  512.     in_diags = 0;    /* [01] */
  513.     }
  514.  
  515.  
  516.  
  517. /************************************************************************
  518. *                                    *
  519. *    M_DATArequest(remote_st, msdu)                    *
  520. *                                    *
  521. *    Input:     remote_st, pointer of the remote station address    *
  522. *        mpdu, media access protocol data unit            *
  523. *    Output: no error, if the msdu has a valid length        *
  524. *        LONG_SDU_ERROR if length > max                *
  525. *                                    *
  526. *    This routine is called every time there is an mpdu to be     *
  527. *    transmitted.                            *
  528. *                                    *
  529. *    Add padding (if data < 46 bytes), data lenth, source addr,    *
  530. *    remote addr, txblk length into the msdu.            *
  531. *                                    *
  532. *    If tb_use = 0 (txer not busy), call xmt_frm.            *
  533. *    If 0 < tb_use < n, queue it into shared memory tb.        *
  534. *    If tb_use = n (tb of shr mem full), queue it into tx_queue    *
  535. *                                    *
  536. *    Call: cp_frm (tx_buff), xmt_frm (), QInsert (tx_buff, &tx_q)    *
  537. *                                    *
  538. *    Note:   xmt_frm () :   tx frm in tb_cur             *
  539. *         cp_frm (tx_buff) :   copy tx_buff to (tb_cur+tb_use)%TB_SIZE  * 
  540. *                                    *
  541. ************************************************************************/
  542.  
  543. M_DATArequest (remote_st, msdu)
  544.     node_address        *remote_st;    /* remote station address */
  545.     register buf_type    msdu;        /* MAC protocol data unit */
  546.  
  547.     {
  548.     union    swap    sw;
  549.     register char    *msdup;
  550.     int        psw;
  551.     register int        msdu_len, txblk_len;
  552. #ifdef DEBUG
  553.     int         i;
  554. #endif
  555.     
  556.     msdu_len = BuffSize (msdu);    /* save the msdu length */
  557.     if (msdu_len > MAX_MSDU)
  558.         /* return error if too large */
  559.         return (SDU_LONG_ERROR);
  560.  
  561. #ifdef DEBUG
  562.     if (debug){
  563.          printf("<mactx length= %x> remadr= ", msdu_len); 
  564.          print_addr(remote_st);    
  565.          printf(" DATA= ");
  566.          msdup = BuffData (msdu);
  567.          for (i=0; i<msdu_len; i++)
  568.             printf("%b",*msdup++);
  569.          }
  570. #endif
  571.  
  572.     /*
  573.      * Construct the transmit data block. Point to the start of the 
  574.      * tx block; 2 for total tx block size, NODSIZ for destination
  575.      * addres, 2 for llc data length. 
  576.      */
  577.     BuffPrepend (msdu, NODSIZ + 2 + 2);
  578.     msdup = BuffData (msdu);
  579.  
  580.     txblk_len = msdu_len + NODSIZ + 2;    /* tx block length */
  581.  
  582.     /* pad the frame to min len */
  583.     if (txblk_len < MIN_FRM - NODSIZ - CRC_LEN)
  584.         txblk_len = MIN_FRM - NODSIZ - CRC_LEN;
  585.  
  586.     /* save the block length in cpu order, others in network order */
  587.  
  588.     * (unsigned short *) msdup = txblk_len;        /* save the block length */
  589.     msdup += sizeof(short);
  590.     /* add2 (msdup, txblk_len); */        /* save the block length */
  591.                      
  592.     bcopy (remote_st->addr, msdup, NODSIZ);    /* save the destination address */
  593.     skip (msdup, NODSIZ);
  594.     add2 (msdup, msdu_len);            /* set the msdu length */
  595.  
  596.     /* tx or queue this frm. */
  597.  
  598.     psw = disave ();     /* must disable interrupts while checking */
  599.  
  600.     if (tb_use == 0)        /* txer idle */
  601.         {
  602.         cp_frm (msdu);
  603.         tb_use ++;
  604.     /*    restor (psw);      */    /* the rep movs should not be int */
  605.         xmt_frm ();        /* tx now */
  606.         MACstat.t0++;        /* increment the initial tx attemp */
  607. #ifdef DEBUG
  608.         if (debug) printf("<xmt_frm>");
  609. #endif
  610.         }
  611.     else if    (tb_use < TB_SIZE)        /* txer busy, tb not full */
  612.         {
  613.         cp_frm (msdu);        /* queue it into tb of shr mem */
  614.         tb_use ++;
  615.      /*    restor (psw);        */    
  616. #ifdef DEBUG
  617.         if (debug) printf("<Q:tb of shr mem>");
  618. #endif
  619.         } 
  620.     else                /* tb's of shr mem full */        
  621.         {
  622.         QInsert (msdu, &tx_queue);    /* put into tx_q */
  623.       /*    restor (psw);  */    /* restore the cpu status */
  624. #ifdef DEBUG
  625.         if (debug) printf("<Q:tx_queue>");
  626. #endif
  627.         }
  628.     
  629.     restor (psw);
  630.     }
  631.  
  632.  
  633. /************************************************************************
  634. *                                    *
  635. *  do_mac_queue()                            *
  636. *                                    *
  637. *  Handle MAC background activities (ie. processing receives).        *
  638. *  Process rx_queue until it is empty.                    *
  639. *                                    *
  640. *  Call: M_DATAindication (&loc_adr, &rem_adr, bp), QRemove(rx_buff)    *
  641. *                                    *
  642. ************************************************************************/
  643.  
  644. do_mac_queue ()
  645.     {
  646.     register buf_type bp;
  647.     node_address    loc_adr, rem_adr;
  648.     union  swap    sw;
  649.     register char        *mpdup;
  650.     int        psw, msdu_len;
  651. #ifdef DEBUG
  652.     int        i;
  653. #endif
  654.  
  655.     psw = disave ();
  656.  
  657.     /* Are there any messages in the rx queue ? */
  658.     while ((bp = rx_queue.first) != (buf_type) &rx_queue)
  659.         {
  660. #ifdef DEBUG
  661.         if (debug) printf("<mac_rcv>");
  662. #endif
  663.         QRemove (bp);        /* remove it from queue */
  664.         restor (psw);
  665.         mpdup = BuffData (bp);    /* mpdup -> received DA */
  666.         BuffStrip (bp, 2*NODSIZ+2);
  667.         bcopy (mpdup, loc_adr.addr, NODSIZ);
  668.         skip (mpdup, NODSIZ);    
  669.         bcopy (mpdup, rem_adr.addr, NODSIZ);
  670.         skip (mpdup, NODSIZ);
  671.         get2 (msdu_len, mpdup);
  672.         BuffAdjust (bp, BuffSize (bp) - msdu_len);
  673.  
  674. #ifdef DEBUG
  675.         if (debug)
  676.             {
  677.             printf("\n");
  678.             printf("DA  "); print_addr(&loc_adr);
  679.             printf("\tSA  "); print_addr(&rem_adr);
  680.             printf("\tmsdulen\t%d", msdu_len);
  681.             printf("\n");
  682.             printf("data\t");                
  683.             for (i=0; i<msdu_len; i++)
  684.                 printf("%b",*mpdup++);
  685.             printf("\n");
  686.             }
  687. #endif
  688.         M_DATAindication (&loc_adr, &rem_adr, bp);
  689.         psw = disave ();
  690.         }    /* end of while */
  691.     restor (psw);
  692.     }
  693.  
  694. 
  695.