home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Examples / DriverKit / SMC16 / SMC16_reloc.tproj / SMC16.m < prev    next >
Encoding:
Text File  |  1993-09-15  |  19.1 KB  |  955 lines

  1. /*
  2.  * Copyright (c) 1993 NeXT Computer, Inc.
  3.  *
  4.  * Driver class for SMC EtherCard Plus Elite16 adaptors.
  5.  *
  6.  * HISTORY
  7.  *
  8.  * 19 Apr 1993 
  9.  *    Added multicast & promiscuous mode support.
  10.  *
  11.  * 26 Jan 1993
  12.  *    Created.
  13.  */
  14.  
  15. #define MACH_USER_API    1
  16.  
  17. #import <driverkit/generalFuncs.h>
  18. #import <driverkit/IONetbufQueue.h>
  19.  
  20. #import "SMC16.h"
  21. #import "SMC16IOInline.h"
  22. #import "SMC16Private.h"
  23.  
  24. #import <kernserv/kern_server_types.h>
  25. #import <kernserv/prototypes.h>
  26. #import <kernserv/i386/spl.h>
  27.  
  28. @implementation SMC16
  29.  
  30. /*
  31.  * Private Instance Methods
  32.  */
  33.  
  34. /*
  35.  * _memAvail
  36.  * Returns the amount of onboard memory not currently in use.
  37.  * Never returns less than zero.
  38.  */
  39. - (SMC16_len_t)_memAvail
  40. {
  41.     int        available;
  42.     
  43.     available = (memtotal - memused);
  44.     
  45.     return ((SMC16_len_t) ((available < 0)? 0: available));
  46. }
  47.  
  48. /*
  49.  * _memRegion
  50.  * Returns the next available NIC_PAGE_SIZE chunk of onboard memory.
  51.  */
  52. - (SMC16_off_t)_memRegion:(SMC16_len_t)length
  53. {
  54.     if ([self _memAvail] < length)
  55.         IOPanic("SMC16: onboard memory exhausted");
  56.     
  57.     return ((SMC16_off_t) (memused / NIC_PAGE_SIZE));
  58. }
  59.  
  60. /*
  61.  * _memAlloc
  62.  * Allocates onboard memory in chunks of NIC_PAGE_SIZE 
  63.  */
  64. - (SMC16_off_t)_memAlloc:(SMC16_len_t)length
  65. {
  66.     SMC16_off_t    region;
  67.     
  68.     /*
  69.      * Round up to the next multiple of NIC_PAGE_SIZE
  70.      */
  71.     length = ((length + NIC_PAGE_SIZE - 1) & ~(NIC_PAGE_SIZE - 1));
  72.     
  73.     region = [self _memRegion:length];
  74.     
  75.     memused += length;
  76.     
  77.     return (region);
  78. }
  79.  
  80. /*
  81.  * _initializeHardware
  82.  * Resets the SMC adaptor.  Disables interrupts, resets the NIC, and
  83.  * configures the onboard memory.
  84.  */
  85. - (void)_initializeHardware
  86. {    
  87.     setIRQ(irq, YES, base);
  88.     
  89.     resetNIC(base);
  90.     
  91.     memtotal = setupRAM(membase, memsize, base);
  92.     memused = 0;
  93. }
  94.  
  95. /*
  96.  * _receiveInitialize
  97.  * Prepares the card for receive operations.  Allocates as many NIC_PAGE_SIZE
  98.  * buffers from the available onboard memory.
  99.  */
  100. - (void)_receiveInitialize
  101. {
  102.     SMC16_len_t        avail = [self _memAvail];
  103.     
  104.     rstart = [self _memAlloc:avail];
  105.     rstop = rstart + (avail / NIC_PAGE_SIZE);
  106.  
  107.     /*
  108.      * Setup the receive ring
  109.      */    
  110.     put_rstart_reg(rstart, base); put_rstop_reg(rstop, base);
  111.     
  112.     /*
  113.      * Reset the boundary buffer pointer
  114.      */    
  115.     put_bound_reg(rstart, base);
  116.     
  117.     rnext = rstart + 1;
  118.     
  119.     /*
  120.      * Reset the current buffer pointer    
  121.      */    
  122.     (void)sel_reg_page(REG_PAGE1, base);
  123.     put_curr_reg(rnext, base);
  124.     (void)sel_reg_page(REG_PAGE0, base);
  125. }
  126.  
  127. /*
  128.  * _transmitInitialize
  129.  * Prepares for transmit operations.  We use 1 transmit buffer of maximum
  130.  * size.
  131.  */
  132. - (void)_transmitInitialize
  133. {
  134.     tstart = [self _memAlloc:ETHERMAXPACKET];
  135. }
  136.  
  137. /*
  138.  * _initializeSoftware
  139.  * Prepare the adaptor for network operations and start them.
  140.  */
  141. - (void)_initializeSoftware
  142. {
  143.     setStationAddress(&myAddress, base);
  144.     
  145.     [self _transmitInitialize]; 
  146.     [self _receiveInitialize];
  147.         
  148.     startNIC(base, rconsave);
  149. }
  150.  
  151. /*
  152.  * _receiveInterruptOccurred
  153.  * This method handles the process of moving received frames from 
  154.  * onboard adaptor memory to netbufs and handing them up to the network
  155.  * object.
  156.  */
  157. - (void)_receiveInterruptOccurred
  158. {
  159.     nic_recv_hdr_t    *rhdr;
  160.     netbuf_t        pkt;
  161.     int            pkt_len, pre_wrap_len;
  162.     void         *pkt_data = NULL;
  163.  
  164. #ifdef DEBUG
  165.  
  166.     /*
  167.      * Change this to 1 to be inundated with messages.
  168.      */
  169.     boolean_t    SMC16_recvTrace = 0;
  170.  
  171. #endif DEBUG
  172.  
  173.     
  174.     /*
  175.      * Grab buffers until we point to the next available one.
  176.      */
  177.     while (rnext != getCurrentBuffer(base)) {
  178.  
  179.     /*
  180.      * Point to the receive header in this buffer.
  181.      */
  182.     rhdr = (nic_recv_hdr_t *)nic_page_addr(rnext,membase);
  183.  
  184. #ifdef DEBUG
  185.     if (SMC16_recvTrace) {
  186.         IOLog("[rstat %02x next %02x len %03x rnext "
  187.             "%02x bound %02x curr %02x]\n",
  188.             *(unsigned char *)&rhdr->rstat, 
  189.         rhdr->next, rhdr->len, rnext, 
  190.         get_bound_reg(base), getCurrentBuffer(base));
  191.     }
  192. #endif DEBUG
  193.     
  194.     
  195.     /*
  196.      * Display a somewhat cryptic message if the xxx bit is set.
  197.      */
  198.     if (!rhdr->rstat.prx) {
  199.         IOLog("rhdr1 rstat %02x next %02x len %x\n", 
  200.             *(unsigned char *)&rhdr->rstat, rhdr->next, rhdr->len);
  201.         rnext = rhdr->next; continue;
  202.     }
  203.     
  204.     /*
  205.      * Display a slightly different, equally cryptic message 
  206.      * if the pointer to the next buffer in this header is outside
  207.      * the range configured buffers.  If this is the case, force a
  208.      * reset by invoking -timeoutOccurred.
  209.      */
  210.     if (rhdr->next >= rstop || rhdr->next < rstart) {
  211.         IOLog("rhdr2 rstat %02x next %02x len %x\n", 
  212.             *(unsigned char *)&rhdr->rstat, rhdr->next, rhdr->len);
  213.         [self timeoutOccurred]; 
  214.         return;
  215.     }
  216.  
  217.     /*
  218.      * Get the overall packet length and the length between
  219.      * the start of the packet and the end of onboard memory.
  220.      * Any packet data beyond that will wrap back to the start
  221.      * of onboard memory.
  222.      */
  223.     pkt_len = rhdr->len - ETHERCRC;
  224.     pre_wrap_len =    nic_page_addr(rstop,membase) -
  225.             nic_page_addr(rnext,membase) -
  226.             sizeof (*rhdr);
  227.  
  228.     /*
  229.      * If the packet length looks reasonable, allocate a net buffer
  230.      * for it and establish a pointer to the data in that net buffer.
  231.      */
  232.     if (pkt_len >= (ETHERMINPACKET - ETHERCRC) && 
  233.         pkt_len <= ETHERMAXPACKET) {
  234.         pkt = nb_alloc(pkt_len);
  235.         if (pkt)
  236.             pkt_data = nb_map(pkt);
  237.     }
  238.     else
  239.         pkt = 0;
  240.         
  241.     /*
  242.      * If none of the packet wraps around the ring, just
  243.      * copy it into the netbuf.
  244.      */
  245.     if (pkt_len <= pre_wrap_len) {
  246.         if (pkt)
  247.         IOCopyMemory(
  248.             (void *)nic_page_addr(rnext,membase) + sizeof (*rhdr),
  249.             pkt_data,
  250.             pkt_len,
  251.             sizeof(short));
  252.     /*
  253.      * Otherwise, copy up to the end of memory, then copy the remaining
  254.      * portion from the start of memory.
  255.      */
  256.     }
  257.     else {
  258.         if (pkt) {
  259.         IOCopyMemory(
  260.             (void *)nic_page_addr(rnext,membase) + sizeof (*rhdr),
  261.             pkt_data,
  262.             pre_wrap_len,
  263.             sizeof(short));
  264.         IOCopyMemory(
  265.             (void *)nic_page_addr(rstart,membase),
  266.             pkt_data + pre_wrap_len,
  267.             pkt_len - pre_wrap_len,
  268.             sizeof(short));
  269.         }
  270.     }
  271.     
  272.     /*
  273.      * Increment the ring buffer pointers.
  274.      */
  275.     rnext = rhdr->next;
  276.     if ((rnext - 1) >= rstart)
  277.         put_bound_reg(rnext - 1, base);
  278.     else
  279.         put_bound_reg(rstop - 1, base);
  280.  
  281.     /*
  282.      * We only pass packets upward if they pass thru multicast filter.
  283.      */
  284.     if(pkt) {
  285.           if([super isUnwantedMulticastPacket:(ether_header_t *)nb_map(pkt)]) 
  286.         {
  287.         nb_free(pkt);
  288.         } 
  289.         else {
  290.         
  291.             [network handleInputPacket:pkt extra:0];
  292.  
  293.         } 
  294.     }
  295.     }
  296.  
  297. }
  298.  
  299. /*
  300.  * _receiveOverwriteOccurred
  301.  * Called when the adaptor tells us that we haven't fetched frames from
  302.  * onboard memory fast enough, so it's overwritten an old frame with a new
  303.  * one.  Oh well...
  304.  */
  305. - (void)_receiveOverwriteOccurred
  306. {
  307. #ifdef DEBUG
  308.     IOLog("overwrite bound %02x curr %02x rnext %02x\n", get_bound_reg(base), getCurrentBuffer(base), rnext);
  309. #endif DEBUG
  310. }
  311.  
  312. /*
  313.  * _transmitInterruptOccurred
  314.  * Called when the adaptor indicated a transmit operation is complete.  Check
  315.  * tstat register and increment the appropriate counters.  Clear the
  316.  * timeout we set when we initiated the transmit and clear the transmitActive
  317.  * flag.  Finally, if there are any outgoing packets in the queue, send the
  318.  * next one.
  319.  */
  320. - (void)_transmitInterruptOccurred
  321. {
  322.     nic_tstat_reg_t    tstat_reg;
  323.     netbuf_t        pkt;
  324.  
  325.     if (transmitActive) {
  326.         tstat_reg = get_tstat_reg(base);
  327.     
  328.     /*
  329.      * Always check transmit status (if available) here.  On a
  330.      * transmit error, increment statistics and reset the
  331.      * adaptor if necessary (not for SMC).  NEVER TRY TO 
  332.      * RETRANSMIT A PACKET.  Leave this up to higher level
  333.      * software, which should insure reliability when
  334.      * it's needed.
  335.      */
  336.     if (tstat_reg.ptx)
  337.         [network incrementOutputPackets];
  338.     else
  339.         [network incrementOutputErrors];
  340.         
  341.     if (tstat_reg.abort || tstat_reg.twc)
  342.         [network incrementCollisions];
  343.     
  344.     [self clearTimeout];    
  345.     transmitActive = NO;
  346.     }
  347.     
  348.     if (pkt = [transmitQueue dequeue])
  349.         [self transmit:pkt];
  350. }
  351.  
  352. /*
  353.  * Public Factory Methods
  354.  */
  355.  
  356. + (BOOL)probe:(IODeviceDescription *)devDesc
  357. {
  358.     SMC16        *dev = [self alloc];
  359.     IOEISADeviceDescription
  360.             *deviceDescription = (IOEISADeviceDescription *)devDesc;
  361.     IORange        *io;
  362.  
  363.     if (dev == nil)
  364.         return NO;
  365.     
  366.     /* 
  367.      * Valid configuration?
  368.      */
  369.     if (    [deviceDescription numPortRanges] < 1
  370.         ||
  371.             [deviceDescription numMemoryRanges] < 1
  372.         ||
  373.             [deviceDescription numInterrupts] < 1) {
  374.         [dev free]; 
  375.     return NO;
  376.     }
  377.     
  378.     /*
  379.      * Make sure we're configured for 16K (even though we can only use 8)
  380.      */
  381.     io = [deviceDescription memoryRangeList];
  382.     if (io->size < 16*1024) {
  383.         [dev free]; 
  384.     return NO;
  385.     }
  386.     
  387.     /*
  388.      * More configuration validation
  389.      */
  390.     io = [deviceDescription portRangeList];
  391.     if (io->size < 16) {
  392.     [dev free]; 
  393.     return NO;
  394.     }
  395.  
  396.     /* 
  397.      * Configuration checks out so let's actually probe for hardware.
  398.      */
  399.     if (!checksumLAR(io->start)) {
  400.         IOLog("SMC16: Adaptor not present or invalid EEROM checksum.\n");
  401.     [dev free]; 
  402.     return NO;
  403.     }
  404.     
  405.     if (!checkBoardRev(io->start)) {
  406.         IOLog("SMC16: Unsupported board revision.\n");
  407.     [dev free]; 
  408.     return NO;
  409.     }
  410.     
  411.     return [dev initFromDeviceDescription:devDesc] != nil;
  412. }
  413.  
  414. /*
  415.  * Public Instance Methods
  416.  */
  417.  
  418. - initFromDeviceDescription:(IODeviceDescription *)devDesc
  419. {
  420.     IOEISADeviceDescription
  421.             *deviceDescription = (IOEISADeviceDescription *)devDesc;
  422.     IORange        *io;
  423.  
  424.     if ([super initFromDeviceDescription:devDesc] == nil) 
  425.         return nil;
  426.     
  427.     /* 
  428.      * Initialize ivars
  429.      */
  430.     irq = [deviceDescription interrupt];
  431.     
  432.     io = [deviceDescription portRangeList];
  433.     base = io->start;
  434.     
  435.     io = [deviceDescription memoryRangeList];
  436.     membase = io->start;    
  437.     memsize = io->size;
  438.  
  439.     /*
  440.      * Broadcasts should be enabled
  441.      */
  442.     rconsave.broad = 1;
  443.  
  444.     /*
  445.      * Reset the adaptor, but don't enable yet.  We'll receive 
  446.      * -resetAndEnable:YES as a side effect of calling
  447.      * -attachToNetworkWithAddress:
  448.      */
  449.     [self resetAndEnable:NO];    
  450.     
  451.     IOLog("SMC16 at port %x irq %d\n",base, irq);
  452.         
  453.     transmitQueue = [[IONetbufQueue alloc] initWithMaxCount:32];
  454.     
  455.     network = [super attachToNetworkWithAddress:myAddress];
  456.     return self;        
  457. }
  458.  
  459. - free
  460. {
  461.     [transmitQueue free];
  462.     
  463.     return [super free];
  464. }
  465.  
  466. - (IOReturn)enableAllInterrupts
  467. {
  468.     unmaskInterrupts(base);
  469.  
  470.     setIRQ(irq, YES, base);
  471.     
  472.     return [super enableAllInterrupts];
  473. }
  474.  
  475. - (void)disableAllInterrupts
  476. {
  477.     setIRQ(irq, NO, base);
  478.     
  479.     [super disableAllInterrupts];
  480. }
  481.  
  482. - (BOOL)resetAndEnable:(BOOL)enable
  483. {
  484.     [self disableAllInterrupts];
  485.    
  486.     transmitActive = NO;
  487.     
  488.     [self _initializeHardware];
  489.     
  490.     getStationAddress(&myAddress, base);
  491.     
  492.     [self _initializeSoftware];
  493.     
  494.     if (enable && [self enableAllInterrupts] != IO_R_SUCCESS) {
  495.     [self setRunning:NO];
  496.         return NO;
  497.     }
  498.     
  499.     [self setRunning:enable];
  500.     return YES;
  501. }
  502.  
  503. - (void)timeoutOccurred
  504. {
  505.     netbuf_t    pkt = NULL;
  506.     
  507.     if ([self isRunning]) {
  508.         if ([self resetAndEnable:YES]) {
  509.  
  510.         if (pkt = [transmitQueue dequeue])
  511.         [self transmit:pkt];
  512.     }
  513.     }
  514.     /*
  515.      * Value of [self isRunning] may have been modified by
  516.      * resetAndEnable:
  517.      */
  518.     if (![self isRunning]) {    
  519.     /*
  520.      * Free any packets in the queue since we're not running.
  521.      */
  522.         if ([transmitQueue count]) {
  523.         transmitActive = NO;
  524.         while (pkt = [transmitQueue dequeue])
  525.         nb_free(pkt);
  526.     }
  527.     }
  528. }
  529.  
  530. /* 
  531.  * Called by our IOThread when it receives a message signifying
  532.  * an interrupt.  We check the istat register and vector off
  533.  * to the appropriate handler routines.
  534.  */
  535. - (void)interruptOccurred
  536. {
  537.     nic_istat_reg_t    istat_reg;
  538.     
  539.     istat_reg = get_istat_reg(base);
  540.     put_istat_reg(istat_reg, base);
  541.     
  542.     if (istat_reg.ovw)
  543.         [self _receiveOverwriteOccurred];
  544.     
  545.     if (istat_reg.prx)
  546.         [self _receiveInterruptOccurred];
  547.         
  548.     if (istat_reg.ptx || istat_reg.txe)
  549.         [self _transmitInterruptOccurred];
  550. }
  551.  
  552.  
  553. /*
  554.  * Enable promiscuous mode (invoked by superclass).
  555.  */
  556. - (BOOL)enablePromiscuousMode
  557. {
  558.     int     old_page = sel_reg_page(REG_PAGE0, base);
  559.  
  560.     rconsave.prom = 1;
  561.     put_rcon_reg(rconsave, base);
  562.     sel_reg_page(old_page, base);
  563.  
  564.     return YES;
  565. }
  566.  
  567. /*
  568.  * Disable promiscuous mode (invoked by superclass).
  569.  */
  570. - (void)disablePromiscuousMode
  571. {
  572.    int     old_page = sel_reg_page(REG_PAGE0, base);
  573.  
  574.     rconsave.prom = 0;
  575.     put_rcon_reg(rconsave, base);
  576.     sel_reg_page(old_page, base);
  577.  
  578. }
  579.  
  580.  
  581. - (BOOL)enableMulticastMode
  582. {
  583.     int     old_page = sel_reg_page(REG_PAGE0, base);
  584.  
  585.     rconsave.group = 1;
  586.     put_rcon_reg(rconsave, base);
  587.     sel_reg_page(old_page, base);
  588.  
  589.     return YES;
  590. }
  591.  
  592. - (void)disableMulticastMode
  593. {
  594.     int     old_page = sel_reg_page(REG_PAGE0, base);
  595.  
  596.     rconsave.group = 0;
  597.     put_rcon_reg(rconsave, base);
  598.     sel_reg_page(old_page, base);
  599.  
  600. }
  601.  
  602. - (void)transmit:(netbuf_t)pkt
  603. {
  604.     int            pkt_len;
  605.  
  606.     /*
  607.      * If we're already transmitting, just queue up the packet.
  608.      */
  609.     if (transmitActive)
  610.         [transmitQueue enqueue:pkt];
  611.     else {
  612.      
  613.     /*
  614.      * We execute a softare loopback since this adaptor doesn't
  615.      * deal with this in hardware.
  616.      */
  617.     [self performLoopback:pkt];     
  618.         
  619.     /*
  620.      * Copy the packet into our transmit buffer, then free it.
  621.      */
  622.     pkt_len = nb_size(pkt);
  623.     IOCopyMemory(
  624.         nb_map(pkt),
  625.         (void *)nic_page_addr(tstart,membase),
  626.         pkt_len,
  627.         sizeof(short));
  628.     
  629.     /*
  630.      * Once the packet is copied out to the adaptor's onboard RAM,
  631.      * always free the packet.  DON'T SAVE A REFERENCE FOR 
  632.      * RETRANSMISSION PURPOSES.  Retransmission should be handled
  633.      * at the higher levels.  
  634.      */
  635.     nb_free(pkt);
  636.     
  637.     /*
  638.      * Setup up and initiate the transmit operation
  639.      */
  640.     put_tcnt_reg(pkt_len, base);
  641.     put_tstart_reg(tstart, base);
  642.     startTransmit(base);
  643.     
  644.     /*
  645.      * Start a timer whose expiration will call -timeoutOccurred, then
  646.      * set the transmitActive flag so we don't step on this operation.
  647.      */
  648.     [self setRelativeTimeout:3000];
  649.     transmitActive = YES;
  650.     }
  651. }
  652.  
  653.  
  654. @end
  655.  
  656. /*
  657.  * Private Functions
  658.  */
  659.  
  660. static BOOL
  661. checksumLAR(
  662.     IOEISAPortAddress    base
  663. )
  664. {
  665.     IOEISAPortAddress    offset;
  666.     unsigned char    sum = 0;
  667.     
  668.     for (offset = BIC_LAR_OFF; offset <= BIC_LAR_CKSUM_OFF; offset++)
  669.         sum += inb(base + SMC16_BIC_OFF + offset);
  670.     
  671.     return (sum == 0xff);
  672. }
  673.  
  674. static void
  675. getStationAddress(
  676.     enet_addr_t        *ea,
  677.     IOEISAPortAddress    base
  678. )
  679. {
  680.     int            i;
  681.     unsigned char    *enaddr = (unsigned char *)ea;
  682.     
  683.     for (i = 0; i < sizeof (*ea); i++)
  684.         *(enaddr + i) = inb(base + SMC16_BIC_OFF + BIC_LAR_OFF + i);
  685. }
  686.  
  687. static void
  688. setStationAddress(
  689.     enet_addr_t        *ea,
  690.     IOEISAPortAddress    base
  691. )
  692. {
  693.     int            i, old_page;
  694.     unsigned char    *enaddr = (unsigned char *)ea;
  695.     
  696.     old_page = sel_reg_page(REG_PAGE1, base);
  697.     
  698.     for (i = 0; i < sizeof (*ea); i++)
  699.         outb(base + SMC16_NIC_OFF + NIC_STA_REG_OFF + i, *(enaddr + i));
  700.     
  701.     (void)sel_reg_page(old_page, base);
  702. }
  703.  
  704. static BOOL
  705. checkBoardRev(
  706.     IOEISAPortAddress    base
  707. )
  708. {
  709.     unsigned int    bid;
  710.     
  711.     bid = get_bid(base);
  712.     
  713.     if (SMC16_REV(bid) < 2)
  714.         return NO;
  715.     
  716.     return YES;
  717. }
  718.  
  719. static void
  720. resetNIC(
  721.     IOEISAPortAddress    base
  722. )
  723. {
  724.     bic_msr_t        msr = { 0 };
  725.     nic_istat_reg_t    istat_reg;
  726.  
  727.     /*
  728.      * Perform HW Reset of NIC    
  729.      */    
  730.     msr.rst = 1;    put_msr(msr, base);
  731.     IODelay(500);
  732.     msr.rst = 0;    put_msr(msr, base);
  733.  
  734.     /*
  735.      * Wait for NIC to enter stopped state    
  736.      */    
  737.     do {
  738.     istat_reg = get_istat_reg(base);
  739.     } while (istat_reg.rst == 0);
  740. }
  741.  
  742. static SMC16_len_t
  743. setupRAM(
  744.     vm_offset_t        addr,
  745.     vm_size_t        size,
  746.     IOEISAPortAddress    base
  747. )
  748. {
  749.     SMC16_len_t        total;
  750.     SMC16_off_t        block_addr;
  751.     bic_laar_t        laar;
  752.     bic_msr_t        msr;
  753. #ifdef SIXTEEN_BIT_MODE
  754.     bic_icr_t        icr;
  755. #endif SIXTEEN_BIT_MODE
  756.     union {
  757.     struct {
  758.         unsigned int        :13,
  759.                 madr    :6,
  760.                 ladr    :5,
  761.                         :8;
  762.     } bic_addr;
  763.     struct {
  764.        unsigned int            :16,
  765.                    block    :8,
  766.                         :8;
  767.     } nic_addr;
  768.     unsigned int    address;
  769.     } _mconv;
  770.  
  771. /*
  772.  * NOTE:  We cannot put the card into 16-bit (and therefore 16K) mode because
  773.  * the bus interface chip will behave as though a full 64K is mapped, even
  774.  * though only 16K exists on the board.  Needless to say this causes problems,
  775.  * whether something else is mapped into the top 3/4 of that 64K or not.
  776.  * Unless the hardware changes, we're limited to using 8K of onboard memory
  777.  * and 8-bit transfer mode.
  778.  */     
  779.  
  780. #ifdef SIXTEEN_BIT_MODE
  781.     icr = get_icr(base);
  782.  
  783.     total = (icr.msz ? 16 : 64) * 1024;
  784.  
  785.     if (total > 16 * 1024)
  786.     total = 16 * 1024;
  787. #else // SIXTEEN_BIT_MODE
  788.     total = 8 * 1024;
  789. #endif SIXTEEN_BIT_MODE
  790.     
  791.     if (total > size)
  792.     total = size;
  793.  
  794. #ifdef DEBUG
  795.     IOLog("SMC16: using %d bytes of onboard memory\n",total);
  796. #endif DEBUG
  797.  
  798.     _mconv.address = addr;
  799.  
  800.     laar = get_laar(base);
  801. #ifdef SIXTEEN_BIT_MODE        
  802.     laar.zws16 = TRUE;
  803.     laar.l16en = TRUE;
  804.     laar.m16en = TRUE;
  805. #endif SIXTEEN_BIT_MODE
  806.     laar.ladr = _mconv.bic_addr.ladr;
  807.     put_laar(laar, base);
  808.     
  809.     msr = get_msr(base);
  810.     msr.madr = _mconv.bic_addr.madr;
  811.     msr.menb = TRUE;
  812.     put_msr(msr, base);
  813.  
  814.     block_addr = _mconv.nic_addr.block;
  815.     put_block_reg(block_addr, base);
  816.  
  817.     return (total);
  818. }
  819.     
  820. static void
  821. startNIC(
  822.     IOEISAPortAddress    base,
  823.     nic_rcon_reg_t    rcon_reg
  824. )
  825. {
  826.     nic_cmd_reg_t    cmd_reg = { 0 };
  827.     nic_enh_reg_t    enh_reg = { 0 };
  828.     nic_dcon_reg_t    dcon_reg = { 0 };
  829.     nic_tcon_reg_t    tcon_reg = { 0 };
  830.     nic_istat_reg_t    istat_reg;
  831.  
  832.     enh_reg.slot = NIC_SLOT_512_BIT;
  833.     enh_reg.wait = 0;
  834.     put_enh_reg(enh_reg, base);
  835.  
  836.     dcon_reg.bsize = NIC_DMA_BURST_8b;
  837. #ifdef SIXTEEN_BIT_MODE
  838.     dcon_reg.bus16 = TRUE;
  839. #endif SIXTEEN_BIT_MODE
  840.     put_dcon_reg(dcon_reg, base);
  841.     
  842.     put_tcon_reg(tcon_reg, base);
  843.     
  844.     istat_reg = get_istat_reg(base);
  845.     put_istat_reg(istat_reg, base);
  846.     
  847.     cmd_reg.sta = 1;
  848.     put_cmd_reg(cmd_reg, base);
  849.     
  850.     put_rcon_reg(rcon_reg, base);
  851. }
  852.  
  853. static void
  854. unmaskInterrupts(
  855.     IOEISAPortAddress    base
  856. )
  857. {
  858.     nic_imask_reg_t    imask_reg = { 0 };
  859.  
  860.     /*
  861.      * Receive conditions
  862.      */    
  863.     imask_reg.prxe = imask_reg.rxee = imask_reg.ovwe = TRUE;
  864.     
  865.     /*
  866.      * Transmit conditions
  867.      */    
  868.     imask_reg.ptxe = imask_reg.txee = TRUE;
  869.     
  870.     put_imask_reg(imask_reg, base);
  871. }
  872.  
  873. static SMC16_off_t
  874. getCurrentBuffer(
  875.     IOEISAPortAddress    base
  876. )
  877. {
  878.     SMC16_off_t        curr;
  879.     int            old_page;
  880.     
  881.     old_page = sel_reg_page(REG_PAGE1, base);
  882.     curr = get_curr_reg(base);
  883.     if (old_page != REG_PAGE1)
  884.         sel_reg_page(old_page, base);
  885.     
  886.     return (curr);
  887. }
  888.  
  889. static void
  890. startTransmit(
  891.     IOEISAPortAddress    base
  892. )
  893. {
  894.     nic_cmd_reg_t    cmd_reg = { 0 };
  895.     
  896.     cmd_reg.txp = 1;
  897.     cmd_reg.sta = 1;
  898.     put_cmd_reg(cmd_reg, base);
  899. }
  900.  
  901. static void
  902. setIRQ(
  903.     int            irq,
  904.     BOOL        enable,
  905.     IOEISAPortAddress    base
  906. )
  907. {
  908.     bic_irr_t        irr;
  909.     bic_icr_t        icr;
  910.     static char        _irx_map[16] = {    -1,
  911.                         -1,
  912.                         -1,
  913.                         BIC_IRX_3,
  914.                         BIC_IRX_4,
  915.                         BIC_IRX_5,
  916.                         -1,
  917.                         BIC_IRX_7,
  918.                         -1,
  919.                         BIC_IRX_9,
  920.                         BIC_IRX_10,
  921.                         BIC_IRX_11,
  922.                         -1,
  923.                         -1,
  924.                         -1,
  925.                         BIC_IRX_15 };
  926.     static char        _ir2_map[16] = {    -1,
  927.                         -1,
  928.                         -1,
  929.                         ICR_IR2_3,
  930.                         ICR_IR2_4,
  931.                         ICR_IR2_5,
  932.                         -1,
  933.                         ICR_IR2_7,
  934.                         -1,
  935.                         ICR_IR2_9,
  936.                         ICR_IR2_10,
  937.                         ICR_IR2_11,
  938.                         -1,
  939.                         -1,
  940.                         -1,
  941.                         ICR_IR2_15 };
  942.  
  943.     irr = get_irr(base);
  944.     irr.irx = _irx_map[irq]; 
  945.     irr.ien = FALSE;
  946.     put_irr(irr, base);
  947.  
  948.     icr = get_icr(base);
  949.     icr.ir2 = _ir2_map[irq];
  950.     put_icr(icr, base);
  951.     
  952.     irr.ien = enable;
  953.     put_irr(irr, base);    
  954. }
  955.