> I just got an ENCORE PCMCIA Netowrk Card. From their website I d/l the
> "linux drivers". This consisted of these files:
> 
> 8390.c, gen1, gen2, and PCNET_CS.c. as well as a readme with the following
> instructions:
> 
> 16-bit 100/10M Fast Ethernet PCMCIA Adapter LINUX DRIVER INSTALL
>  Note: this driver for linux 2.0.30
> 
>  1. copy driver to /FASTPCM
>     # mcopy a:/* /FASTPCM
>  
>  2. download pcmcia-cs-3.0.x.tar.gz from hyper.stanford.edu
>     in the /pub/pcmcia directory
>     readme PCMCIA-HOWTO file & install it 
>  
>  3. add the following lines into /etc/pcmcia/config
>     card "16-bit 100/10M Fast Ethernet PCMCIA Adapter"
>     version "PCMCIA", "100BASE"
>     bind "pcnet_cs"
> 
>  4.# cd /FASTPCM
>    # chmod +x gen1 gen2
>  
>  5.# gen1
>    # gen2
>  
>  6.# reboot
>  
> 
> None of this is working. I have PCMCIA services working fine with another
> 3com PCMCIA network card, so I think I have the SLOT configured properly.
> Is there anyway to simply compile that 8930.c file into 8930.o and
> 'insmod' it ? I have never used linux on a laptop, and I have never worked
> with PCMCIA before. I assume the list doesnt like attachments, so if
> anyone is intereseted in the files, I will be happy to provide them. As an
> alternative I will make this e-mail extrememly long and attach the text of
> the files below:
> 
> --------------------------------------------------------------------------
> ------------------------------------------------------
> 
> (/* 8390.c: A general NS8390 ethernet driver core for linux. */
> /*
>       Written 1992-94 by Donald Becker.
>   
>       Copyright 1993 United States Government as represented by the
>       Director, National Security Agency.
> 
>       This software may be used and distributed according to the terms
>       of the GNU Public License, incorporated herein by reference.
> 
>       The author may be reached as [EMAIL PROTECTED], or C/O
>       Center of Excellence in Space Data and Information Sciences
>          Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
>   
>   This is the chip-specific code for many 8390-based ethernet adaptors.
>   This is not a complete driver, it must be combined with board-specific
>   code such as ne.c, wd.c, 3c503.c, etc.
> 
>   Seeing how at least eight drivers use this code, (not counting the
>   PCMCIA ones either) it is easy to break some card by what seems like
>   a simple innocent change. Please contact me or Donald if you think
>   you have found something that needs changing. -- PG
> 
> 
>   Changelog:
> 
>   Paul Gortmaker      : remove set_bit lock, other cleanups.
>   Paul Gortmaker      : add ei_get_8390_hdr() so we can pass skb's to 
>                         ei_block_input() for eth_io_copy_and_sum().
>   Paul Gortmaker      : exchange static int ei_pingpong for a #define,
>                         also add better Tx error handling.
>   Paul Gortmaker      : rewrite Rx overrun handling as per NS specs.
> 
>   
> 
>   Sources:
>   The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
> 
>   */
> 
> static const char *version =
>     "8390.c:v1.10 9/23/94 Donald Becker ([EMAIL PROTECTED])\n";
> 
> #include <linux/module.h>
> #include <linux/kernel.h>
> #include <linux/sched.h>
> #include <linux/fs.h>
> #include <linux/types.h>
> #include <linux/ptrace.h>
> #include <linux/string.h>
> #include <asm/system.h>
> #include <asm/segment.h>
> #include <asm/bitops.h>
> #include <asm/io.h>
> #include <linux/errno.h>
> #include <linux/fcntl.h>
> #include <linux/in.h>
> #include <linux/interrupt.h>
> 
> #include <linux/netdevice.h>
> #include <linux/etherdevice.h>
> 
> #include "8390.h"
> 
> // These are the operational function interfaces to board-specific
> // routines.
> //    void reset_8390(struct device *dev)
> //            Resets the board associated with DEV, including a hardware
> reset of
> //            the 8390.  This is only called when there is a transmit
> timeout, and
> //            it is always followed by 8390_init().
> //    void block_output(struct device *dev, int count, const unsigned char
> *buf,
> //                                      int start_page)
> //            Write the COUNT bytes of BUF to the packet buffer at
> START_PAGE.  The
> //            "page" value uses the 8390's 256-byte pages.
> //    void get_8390_hdr(struct device *dev, struct e8390_hdr *hdr, int
> ring_page)
> //            Read the 4 byte, page aligned 8390 header. *If* there is a
> //            subsequent read, it will be of the rest of the packet.
> //    void block_input(struct device *dev, int count, struct sk_buff *skb,
> int ring_offset)
> //            Read COUNT bytes from the packet buffer into the skb data
> area. Start 
> //            reading from RING_OFFSET, the address as the 8390 sees it.
> This will always
> //            follow the read of the 8390 header. 
> 
> #define ei_reset_8390 (ei_local->reset_8390)
> #define ei_block_output (ei_local->block_output)
> #define ei_block_input (ei_local->block_input)
> #define ei_get_8390_hdr (ei_local->get_8390_hdr)
> 
> /* use 0 for production, 1 for verification, >2 for debug */
> #ifdef EI_DEBUG
> int ei_debug = EI_DEBUG;
> #else
> int ei_debug = 1;
> #endif
> 
> /* Index to functions. */
> static void ei_tx_intr(struct device *dev);
> static void ei_tx_err(struct device *dev);
> static void ei_receive(struct device *dev);
> static void ei_rx_overrun(struct device *dev);
> 
> /* Routines generic to NS8390-based boards. */
> static void NS8390_trigger_send(struct device *dev, unsigned int length,
>                                                               int
> start_page);
> static void set_multicast_list(struct device *dev);
> 
> 
> /* Open/initialize the board.  This routine goes all-out, setting
> everything
>    up anew at each open, even though many of these registers should only
>    need to be set once at boot.
>    */
> int ei_open(struct device *dev)
> {
>     struct ei_device *ei_local = (struct ei_device *) dev->priv;
> 
>     /* This can't happen unless somebody forgot to call ethdev_init(). */
>     if (ei_local == NULL) {
>       printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n",
> dev->name);
>       return -ENXIO;
>     }
>     
>     irq2dev_map[dev->irq] = dev;
>     NS8390_init(dev, 1);
>     dev->start = 1;
>     ei_local->irqlock = 0;
>     return 0;
> }
> 
> /* Opposite of above. Only used when "ifconfig <devname> down" is done. */
> int ei_close(struct device *dev)
> {
>     NS8390_init(dev, 0);
>     dev->start = 0;
>     return 0;
> }
> 
> static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
> {
>       int e8390_base = dev->base_addr;
>       struct ei_device *ei_local = (struct ei_device *) dev->priv;
>       int length, output_page;
>       unsigned long flags;
> 
>       if (dev->start == 0) {
>               printk("%s: xmit on stopped card\n", dev->name);
>               return 1;
>       }
> 
> //    *
> //    * We normally shouldn't be called if dev->tbusy is set, but the
> //    * existing code does anyway. If it has been too long since the
> //    * last Tx, we assume the board has died and kick it.
> //    *
>  
>       if (dev->tbusy) {       // Do timeouts, just like the 8003 driver.
>               int txsr = inb(e8390_base+EN0_TSR), isr;
>               int tickssofar = jiffies - dev->trans_start;
> 
>               if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5)
> && !(txsr & ENTSR_PTX)))
>               {
>                       return 1;
>               }
>               isr = inb(e8390_base+EN0_ISR);
> 
>               //*
>               //* Note that if the Tx posted a TX_ERR interrupt, then the
>               //* error will have been handled from the interrupt handler.
>               //* and not here.
>               //*
> 
>               printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x,
> t=%d.\n",
>                  dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
>                  (isr) ? "lost interrupt?" : "cable problem?", txsr, isr,
> tickssofar);
> 
>               if (!isr && !ei_local->stat.tx_packets) {
>                  // The 8390 probably hasn't gotten on the cable yet.
>                  ei_local->interface_num ^= 1;   // Try a different xcvr.
>               }
> 
>               // Try to restart.  Perhaps the user has fixed something.
>               ei_reset_8390(dev);
>               NS8390_init(dev, 1);
>               dev->trans_start = jiffies;
>       }
>     
>       // Sending a NULL skb means some higher layer thinks we've missed an
>       // tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
> itself.
> 
>       if (skb == NULL) {
> //            dev_tint(dev);
>               return 0;
>       }
>       if (skb->len <= 14 || skb->len >= 1518)
>               return 0;
> 
>       length = skb->len;
> //    if (length < ETH_ZLEN)          // AX88190 will auto-padding
> //            length = ETH_ZLEN;      // the short packet
> 
> #ifdef EI_PINGPONG
> 
>       // Mask interrupts from the ethercard.
> //    outb_p(0x00, e8390_base + EN0_IMR);
> //    if (dev->interrupt) {
> //            printk("%s: Tx request while isr active.\n",dev->name);
> //            outb_p(ENISR_ALL, e8390_base + EN0_IMR);
> //            return 1;
> //    }
> //    ei_local->irqlock = 1;
> 
>       save_flags(flags);
>       cli();
> 
> //    *
> //    * We have two Tx slots available for use. Find the first free
> //    * slot, and then perform some sanity checks. With two Tx bufs,
> //    * you get very close to transmitting back-to-back packets. With
> //    * only one Tx buf, the transmitter sits idle while you reload the
> //    * card, leaving a substantial gap between each transmitted packet.
> 
>       if (!ei_local->txing)
>       {
>               if (ei_local->tx1 != 0)
>                       return 1;
>               output_page = ei_local->tx_start_page;
>               ei_block_output(dev, length, skb->data, output_page);
>               ei_local->tx1 = length;
>       }
>       else
>       {
>               if (ei_local->tx2 != 0)
>                       return 1;
>               output_page = ei_local->tx_start_page + TX_1X_PAGES;
>               ei_block_output(dev, length, skb->data, output_page);
>               ei_local->tx2 = length;
>       }
> 
> /*
>     if (ei_local->tx1 == 0) {
>       output_page = ei_local->tx_start_page;
>       ei_local->tx1 = length;
>       if (ei_debug  &&  ei_local->tx2 > 0)
>               printk("%s: idle transmitter tx2=%d, lasttx=%d,
> txing=%d.\n",
>                       dev->name, ei_local->tx2, ei_local->lasttx,
> ei_local->txing);
>     } else if (ei_local->tx2 == 0) {
>       output_page = ei_local->tx_start_page + TX_1X_PAGES;
>       ei_local->tx2 = length;
>       if (ei_debug  &&  ei_local->tx1 > 0)
>               printk("%s: idle transmitter, tx1=%d, lasttx=%d,
> txing=%d.\n",
>                       dev->name, ei_local->tx1, ei_local->lasttx,
> ei_local->txing);
>     } else {  // We should never get here.
>       if (ei_debug)
>               printk("%s: No Tx buffers free! irq=%d tx1=%d tx2=%d
> last=%d\n",
>                       dev->name, dev->interrupt, ei_local->tx1,
> ei_local->tx2, ei_local->lasttx);
>       dev->tbusy = 1;
> //    ei_local->irqlock = 0;
> //    outb_p(ENISR_ALL, e8390_base + EN0_IMR);
>       return 1;
>     }
> */
> 
>       //*
>       //* Okay, now upload the packet and trigger a send if the
> transmitter
>       //* isn't already sending. If it is busy, the interrupt handler will
>       //* trigger the send later, upon receiving a Tx done interrupt.
>       //*
> 
>       if (ei_local->lasttx == -1)
>       {
>               ei_local->lasttx = ei_local->txing;
>               NS8390_trigger_send(dev, length, output_page);
>               dev->trans_start = jiffies;
>       }
>       else
>               dev->tbusy = 1;
> 
>       ei_local->txing ^= 1;
> 
> /*
>     if (! ei_local->txing) {
>       ei_local->txing = 1;
>       NS8390_trigger_send(dev, length, output_page);
>       dev->trans_start = jiffies;
>       if (output_page == ei_local->tx_start_page) {
>               ei_local->tx1 = -1;
>               ei_local->lasttx = -1;
>       } else {
>               ei_local->tx2 = -1;
>               ei_local->lasttx = -2;
>       }
>     } else
>       ei_local->txqueue++;
> 
>     dev->tbusy = (ei_local->tx1  &&  ei_local->tx2);
> */
> 
>       // Turn 8390 interrupts back on.
> //    ei_local->irqlock = 0;
> //    outb_p(ENISR_ALL, e8390_base + EN0_IMR);
> 
>       restore_flags(flags);
> 
> #else // EI_PINGPONG
> 
>       //*
>       //* Only one Tx buffer in use. You need two Tx bufs to come close to
>       //* back-to-back transmits. Expect a 20 -> 25% performance hit on
>       //* reasonable hardware if you only use one Tx buffer.
>       //*
> 
>       ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
>       NS8390_trigger_send(dev, length, ei_local->tx_start_page);
>       dev->trans_start = jiffies;
>       dev->tbusy = 1;
> //    ei_local->txing = 1;
> 
> #endif        /* EI_PINGPONG */
> 
>       dev_kfree_skb (skb, FREE_WRITE);
>     
>       return 0;
> }
> 
> /* The typical workload of the driver:
>    Handle the ether interface interrupts. */
> void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
> {
>       struct device *dev = (struct device *)(irq2dev_map[irq]);
>       int e8390_base;
>       int interrupts;
> //    int nr_serviced = 0;
>       struct ei_device *ei_local;
>     
>       if (dev == NULL) {
>               printk ("net_interrupt(): irq %d for unknown device.\n",
> irq);
>               return;
>       }
> 
>       e8390_base = dev->base_addr;
>       ei_local = (struct ei_device *) dev->priv;
>       if (dev->interrupt) {           // || ei_local->irqlock
>               // The "irqlock" check is only for testing.
>               printk(ei_local->irqlock
>                          ? "%s: Interrupted while interrupts are masked!
> isr=%#2x imr=%#2x.\n"
>                          : "%s: Reentering the interrupt handler! isr=%#2x
> imr=%#2x.\n",
>                          dev->name, inb_p(e8390_base + EN0_ISR),
>                          inb_p(e8390_base + EN0_IMR));
>               return;
>       }
>       dev->interrupt = 1;
> 
>       if (ei_debug > 3)
>               printk("%s: interrupt(isr=%#2.2x).\n", dev->name,
>                       inb_p(e8390_base + EN0_ISR));
>     
>       // Change to page 0 and read the intr status reg.
> //    outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
>     
>       // Mask interrupts from the ethercard.
>       outb_p(0x00, e8390_base + EN0_IMR);
>       ei_local->irqlock = 1;
> 
>       // !!Assumption!! -- we stay in page 0. Don't break this!
>       while (
>               ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0)
> //            && (++nr_serviced < MAX_SERVICE)
>               )
>       {
>               if (dev->start == 0) {
>                       printk("%s: interrupt from stopped card\n",
> dev->name);
>                       interrupts = 0;
>                       break;
>               }
>               outb_p(interrupts, e8390_base + EN0_ISR);
>               while(inb(e8390_base + EN0_ISR) & interrupts) { //AX88190
> Bug!
>                       outb_p(0, e8390_base + EN0_ISR);
>                       outb_p(interrupts, e8390_base + EN0_ISR);
>               }                                               //AX88190
> Bug!
>               if (interrupts & ENISR_OVER) {
>                       ei_rx_overrun(dev);
>               } else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
>                       // Got a good (?) packet.
>                       ei_receive(dev);
>               }
> 
>               // Push the next to-transmit packet through.
>               if (interrupts & ENISR_TX) {
>                       ei_tx_intr(dev);
>               } else if (interrupts & ENISR_TX_ERR) {
>                       ei_tx_err(dev);
>               }
> 
>               if (interrupts & ENISR_COUNTERS) {
>                       ei_local->stat.rx_frame_errors += inb_p(e8390_base +
> EN0_COUNTER0);
>                       ei_local->stat.rx_crc_errors   += inb_p(e8390_base +
> EN0_COUNTER1);
>                       ei_local->stat.rx_missed_errors+= inb_p(e8390_base +
> EN0_COUNTER2);
>               }
>               
>               // Ignore any RDC interrupts that make it back to here.
> //            if (interrupts & ENISR_RDC) {
> //            }
> 
> //            outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base +
> E8390_CMD);
>       }
> /*
>     if (interrupts && ei_debug) {
>               outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base +
> E8390_CMD);
>               if (nr_serviced >= MAX_SERVICE) {
>                       printk("%s: Too much work at interrupt, status
> %#2.2x\n",
>                                  dev->name, interrupts);
>                       while(inb(e8390_base + EN0_ISR) & ENISR_ALL) {
>                               outb_p(0, e8390_base + EN0_ISR);
>                               outb_p(ENISR_ALL, e8390_base + EN0_ISR); //
> Ack. most intrs.
>                       }
>               } else {
>                       printk("%s: unknown interrupt %#2x\n", dev->name,
> interrupts);
>                       while(inb(e8390_base + EN0_ISR) & 0x7f) {
>                               outb_p(0, e8390_base + EN0_ISR);
>                               outb_p(0x7f, e8390_base + EN0_ISR); // Ack.
> all intrs.
>                       }
>               }
>     }
> */
>       // Turn 8390 interrupts back on.
>       ei_local->irqlock = 0;
>       outb_p(ENISR_ALL, e8390_base + EN0_IMR);
> 
>     dev->interrupt = 0;
>     return;
> }
> 
> /*
>  * A transmitter error has happened. Most likely excess collisions (which
>  * is a fairly normal condition). If the error is one where the Tx will
>  * have been aborted, we try and send another one right away, instead of
>  * letting the failed packet sit and collect dust in the Tx buffer. This
>  * is a much better solution as it avoids kernel based Tx timeouts, and
>  * an unnecessary card reset.
>  */
> 
> static void ei_tx_err(struct device *dev)
> {
>     int e8390_base = dev->base_addr;
>     unsigned char txsr = inb_p(e8390_base+EN0_TSR);
>     unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
>     struct ei_device *ei_local = (struct ei_device *) dev->priv;
> 
> #ifdef VERBOSE_ERROR_DUMP
>     printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
>     if (txsr & ENTSR_ABT)
>               printk("excess-collisions ");
>     if (txsr & ENTSR_ND)
>               printk("non-deferral ");
>     if (txsr & ENTSR_CRS)
>               printk("lost-carrier ");
>     if (txsr & ENTSR_FU)
>               printk("FIFO-underrun ");
>     if (txsr & ENTSR_CDH)
>               printk("lost-heartbeat ");
>     printk("\n");
> #endif
> 
>     if (tx_was_aborted)
>       ei_tx_intr(dev);
> 
>       //*
>       //* Note: NCR reads zero on 16 collisions so we add them
>       //* in by hand. Somebody might care...
>       //*
>       if (txsr & ENTSR_ABT)
>               ei_local->stat.collisions += 16;
>       
> }
> 
> /* We have finished a transmit: check for errors and then trigger the next
>    packet to be sent. */
> static void ei_tx_intr(struct device *dev)
> {
>       int e8390_base = dev->base_addr;
>       int status = inb(e8390_base + EN0_TSR);
>       struct ei_device *ei_local = (struct ei_device *) dev->priv;
>     
> #ifdef EI_PINGPONG
> 
>       //*
>       //* There are two Tx buffers, see which one finished, and trigger
>       //* the send of another one if it exists.
>       //*
> 
>       ei_local->lasttx ^= 1;
>       if (!ei_local->lasttx)
>       {
>               ei_local->tx2 = 0;
>               if (ei_local->tx1 != 0)
>               {
>                       NS8390_trigger_send(dev, ei_local->tx1,
>                                       ei_local->tx_start_page);
>                       dev->trans_start = jiffies;
>               }
>               else
>                       ei_local->lasttx = -1;
>       }
>       else
>       {
>               ei_local->tx1 = 0;
>               if (ei_local->tx2 != 0)
>               {
>                       NS8390_trigger_send(dev, ei_local->tx2,
>                                       ei_local->tx_start_page +
> TX_1X_PAGES);
>                       dev->trans_start = jiffies;
>               }
>               else
>                       ei_local->lasttx = -1;
>       }
>       dev->tbusy = 0;
> 
> 
> /*
>     ei_local->txqueue--;
>     if (ei_local->tx1 < 0) {
>       if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
>               printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
>                          ei_local->name, ei_local->lasttx, ei_local->tx1);
>       ei_local->tx1 = 0;
>       dev->tbusy = 0;
>       if (ei_local->tx2 > 0) {
>               ei_local->txing = 1;
>               NS8390_trigger_send(dev, ei_local->tx2,
> ei_local->tx_start_page + 6);
>               dev->trans_start = jiffies;
>               ei_local->tx2 = -1,
>               ei_local->lasttx = 2;
>       } else
>               ei_local->lasttx = 20, ei_local->txing = 0;
>     } else if (ei_local->tx2 < 0) {
>       if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
>               printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
>                          ei_local->name, ei_local->lasttx, ei_local->tx2);
>       ei_local->tx2 = 0;
>       dev->tbusy = 0;
>       if (ei_local->tx1 > 0) {
>               ei_local->txing = 1;
>               NS8390_trigger_send(dev, ei_local->tx1,
> ei_local->tx_start_page);
>               dev->trans_start = jiffies;
>               ei_local->tx1 = -1;
>               ei_local->lasttx = 1;
>       } else
>               ei_local->lasttx = 10, ei_local->txing = 0;
>     } else
>       printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
>                  dev->name, ei_local->lasttx);
> */
> #else // EI_PINGPONG
>       // Single Tx buffer: mark it free so another packet can be loaded.
> 
>       dev->tbusy = 0;
> //    ei_local->txing = 0;
> #endif
> 
>     // Minimize Tx latency: update the statistics after we restart TXing.
>     if (status & ENTSR_COL)
>       ei_local->stat.collisions++;
>     if (status & ENTSR_PTX)
>       ei_local->stat.tx_packets++;
>     else {
>       ei_local->stat.tx_errors++;
>       if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;
>       if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
>       if (status & ENTSR_FU)  ei_local->stat.tx_fifo_errors++;
>       if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
>       if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
>     }
> 
>     mark_bh (NET_BH);
> }
> 
> // We have a good packet(s), get it/them out of the buffers.
> static void ei_receive(struct device *dev)
> {
>     int e8390_base = dev->base_addr;
>     struct ei_device *ei_local = (struct ei_device *) dev->priv;
>     unsigned char rxing_page, this_frame, next_frame;
>     unsigned short current_offset;
>     struct e8390_pkt_hdr rx_frame;
>     int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
> //    int rx_pkt_count = 0;
>     
> //    while (++rx_pkt_count < 10) {
>       while (1) {
>               int pkt_len;
>               
>               // Get the rx page (incoming packet pointer).
> //            outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
>               rxing_page = inb_p(e8390_base + EN1_CURPAG -1); //AX88190
> //            outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
>               
>               // Remove one frame from the ring.  Boundary is always a
> page behind.
>               this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
>               if (this_frame >= ei_local->stop_page)
>                       this_frame = ei_local->rx_start_page;
>               
>               // Someday we'll omit the previous, iff we never get this
> message.
>               // (There is at least one clone claimed to have a problem.)
>               if (ei_debug > 0  &&  this_frame != ei_local->current_page)
>                       printk("%s: mismatched read page pointers %2x vs
> %2x.\n",
>                                  dev->name, this_frame,
> ei_local->current_page);
>               
>               if (this_frame == rxing_page)   // Read all the frames?
>                       break;                  // Done for now
>               
>               current_offset = this_frame << 8;
>               ei_get_8390_hdr(dev, &rx_frame, this_frame);
>               
>               pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
>               
>               next_frame = this_frame + 1 + ((pkt_len+4)>>8);
> /*            
>               // Check for bogosity warned by 3c503 book: the status byte
> is never
>               // written.  This happened a lot during testing! This code
> should be
>               // cleaned up someday.
>               if (rx_frame.next != next_frame
>                       && rx_frame.next != next_frame + 1
>                       && rx_frame.next != next_frame - num_rx_pages
>                       && rx_frame.next != next_frame + 1 - num_rx_pages) {
>                       ei_local->current_page = rxing_page;
>                       outb(ei_local->current_page-1,
> e8390_base+EN0_BOUNDARY);
>                       ei_local->stat.rx_errors++;
>                       continue;
>               }
> */
>               if (pkt_len < 60  ||  pkt_len > 1518) {
>                       if (ei_debug)
>                               printk("%s: bogus packet size: %d,
> status=%#2x nxpg=%#2x.\n",
>                                          dev->name, rx_frame.count,
> rx_frame.status,
>                                          rx_frame.next);
>                       ei_local->stat.rx_errors++;
>               } else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
>                       struct sk_buff *skb;
>                       
>                       skb = dev_alloc_skb(pkt_len+2);
>                       if (skb == NULL) {
>                               if (ei_debug > 1)
>                                       printk("%s: Couldn't allocate a
> sk_buff of size %d.\n",
>                                                  dev->name, pkt_len);
>                               ei_local->stat.rx_dropped++;
>                               break;
>                       } else {
>                               skb_reserve(skb,2);     /* IP headers on 16
> byte boundaries */
>                               skb->dev = dev;
>                               skb_put(skb, pkt_len);  /* Make room */
>                               ei_block_input(dev, pkt_len, skb,
> current_offset + sizeof(rx_frame));
>                               skb->protocol=eth_type_trans(skb,dev);
>                               netif_rx(skb);
>                               ei_local->stat.rx_packets++;
>                       }
>               } else {
>                       int errs = rx_frame.status;
>                       if (ei_debug)
>                               printk("%s: bogus packet: status=%#2x
> nxpg=%#2x size=%d\n",
>                                          dev->name, rx_frame.status,
> rx_frame.next,
>                                          rx_frame.count);
>                       if (errs & ENRSR_FO)
>                               ei_local->stat.rx_fifo_errors++;
>               }
>               next_frame = rx_frame.next;
> 
>               // This _should_ never happen: it's here for avoiding bad
> clones.
>               if (next_frame >= ei_local->stop_page) {
>                       printk("%s: next frame inconsistency, %#2x\n",
> dev->name,
>                                  next_frame);
>                       next_frame = ei_local->rx_start_page;
>               }
>               ei_local->current_page = next_frame;
>               outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
>       }
> 
> //    We used to also ack ENISR_OVER here, but that would sometimes mask
> //    a real overrun, leaving the 8390 in a stopped state with rec'vr off.
> //    while(inb(e8390_base + EN0_ISR) & (ENISR_RX+ENISR_RX_ERR)) {
> //            outb_p(0, e8390_base + EN0_ISR);
> //            outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
> //    }
> 
>     return;
> }
> 
> /* 
>  * We have a receiver overrun: we have to kick the 8390 to get it started
>  * again. Problem is that you have to kick it exactly as NS prescribes in
>  * the updated datasheets, or "the NIC may act in an unpredictable
> manner."
>  * This includes causing "the NIC to defer indefinitely when it is stopped
>  * on a busy network."  Ugh.
>  */
> static void ei_rx_overrun(struct device *dev)
> {
>       int e8390_base = dev->base_addr;
>       struct ei_device *ei_local = (struct ei_device *) dev->priv;
>       unsigned long wait_start_time;
> //    unsigned char was_txing, must_resend = 0;
>     
>       ei_local->stat.rx_over_errors++;
>       if (ei_debug > 1)
>               printk("%s: Receiver overrun.\n", dev->name);
>     
>       //*
>       //* Record whether a Tx was in progress and then issue the
>       //* stop command.
>       //*
> //    was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
>       outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
> 
>       //* 
>       //* Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms
> total.
>       //* Early datasheets said to poll the reset bit, but now they say
> that
>       //* it "is not a reliable indicator and subsequently should be
> ignored."
>       //* We wait at least 10ms.
>       //*
> //    wait_start_time = jiffies;
> //    while (jiffies - wait_start_time <= 1*HZ/100)
> //            barrier();
> 
>       //*
>       //* Reset RBCR[01] back to zero as per magic incantation.
>       //*
> //    outb_p(0x00, e8390_base+EN0_RCNTLO);
> //    outb_p(0x00, e8390_base+EN0_RCNTHI);
> 
>       //*
>       //* See if any Tx was interrupted or not. According to NS, this
>       //* step is vital, and skipping it will cause no end of havoc.
>       //*
> //    if (was_txing) { 
> //            unsigned char tx_completed =
> //                     inb_p(e8390_base+EN0_ISR) &
> (ENISR_TX+ENISR_TX_ERR);
> //
> //            if (!tx_completed)
> //                    must_resend = 1;
> //    }
> 
>       //*
>       //* Have to enter loopback mode and then restart the NIC before
>       //* you are allowed to slurp packets up off the ring.
>       //*
>       outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
>       outb_p(E8390_NODMA +E8390_PAGE0 +E8390_START, e8390_base +
> E8390_CMD);
> 
>       //*
>       //* Clear the Rx ring of all the debris, and ack the interrupt.
>       //*
>       ei_receive(dev);
> 
>       //*
>       //* Leave loopback mode, and resend any packet that got stopped.
>       //*
>       outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
> 
> //    if (must_resend)
> //            outb_p(E8390_NODMA +E8390_PAGE0 +E8390_START +E8390_TRANS,
> e8390_base + E8390_CMD);
>       
> }
> 
> static struct enet_statistics *get_stats(struct device *dev)
> {
>     short ioaddr = dev->base_addr;
>     struct ei_device *ei_local = (struct ei_device *) dev->priv;
>     
>     /* If the card is stopped, just return the present stats. */
>     if (dev->start == 0) return &ei_local->stat;
> 
>     /* Read the counter registers, assuming we are in page 0. */
>     ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
>     ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
>     ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
>     
>     return &ei_local->stat;
> }
> 
> /*
>  *    Set or clear the multicast filter for this adaptor.
>  */
>  
> static void set_multicast_list(struct device *dev)
> {
>       short ioaddr = dev->base_addr;
>     
>       if(dev->flags&IFF_PROMISC)
>       {
>               outb_p(E8390_RXCONFIG |0x40 |0x18, ioaddr + EN0_RXCR);
>       }
>       else if((dev->flags&IFF_ALLMULTI)||dev->mc_list)
>       {
>               /* The multicast-accept list is initialized to accept-all,
> and we
>                  rely on higher-level filtering for now. */
>               outb_p(E8390_RXCONFIG |0x40 |0x08, ioaddr + EN0_RXCR);
>       } 
>       else
>               outb_p(E8390_RXCONFIG |0x40, ioaddr + EN0_RXCR);
> }
> 
> /* Initialize the rest of the 8390 device structure. */
> int ethdev_init(struct device *dev)
> {
>     if (ei_debug > 1)
>               printk(version);
>     
>     if (dev->priv == NULL) {
>               struct ei_device *ei_local;
>               
>               dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
>               if (dev->priv == NULL)
>                       return -ENOMEM;
>               memset(dev->priv, 0, sizeof(struct ei_device));
>               ei_local = (struct ei_device *)dev->priv;
>     }
>     
>     dev->hard_start_xmit = &ei_start_xmit;
>     dev->get_stats    = get_stats;
>     dev->set_multicast_list = &set_multicast_list;
> 
>     ether_setup(dev);
>         
>     return 0;
> }
> 
> 
> // This page of functions should be 8390 generic
> // Follow National Semi's recommendations for initializing the "NIC".
> void NS8390_init(struct device *dev, int startp)
> {
>     int e8390_base = dev->base_addr;
>     struct ei_device *ei_local = (struct ei_device *) dev->priv;
>     int i;
>     int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
>     unsigned long flags;
>     
>     // Follow National Semi's recommendations for initing the DP83902.
>     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); // 0x21
>     outb_p(endcfg, e8390_base + EN0_DCFG);    // 0x48 or 0x49
>     // Clear the remote byte count registers.
>     outb_p(0x00,  e8390_base + EN0_RCNTLO);
>     outb_p(0x00,  e8390_base + EN0_RCNTHI);
>     // Set to monitor and loopback mode -- this is vital!.
>     outb_p(E8390_RXOFF |0x40, e8390_base + EN0_RXCR); // 0x20
>     outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); // 0x02
>     // Set the transmit page and receive ring.
>     outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
>     outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
>     outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); // 3c503
> says 0x3f,NS0x26
>     ei_local->current_page = ei_local->rx_start_page; // assert boundary+1
>     outb_p(ei_local->stop_page,         e8390_base + EN0_STOPPG);
>     // Clear the pending interrupts and mask.
>     outb_p(0xFF, e8390_base + EN0_ISR);
>     outb_p(0x00,  e8390_base + EN0_IMR);
>     
>     save_flags(flags);
>     cli();
>     outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base);       //
> 0x61
> 
>     // Copy the station address into the DS8390 registers,
>     // and set the multicast hash bitmap to receive all multicasts.
>     for(i = 0; i < 6; i++)
>               outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
>     // Initialize the multicast list to accept-all.  If we enable
> multicast
>     // the higher levels can do the filtering.
>     for(i = 0; i < 8; i++)
>               outb_p(0xff, e8390_base + EN1_MULT + i);
>     
>     outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
>     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
>     restore_flags(flags);
> 
>       ei_local->txing = ei_local->tx1 = ei_local->tx2 = 0;
>       ei_local->lasttx = -1;
>       dev->interrupt = 0;
>       dev->tbusy = 0;
> 
>     if (startp) {
>               outb_p(0xff,  e8390_base + EN0_ISR);
>               outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
>               outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
>               outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on.
> */
>               /* 3c503 TechMan says rxconfig only after the NIC is
> started. */
>               outb_p(E8390_RXCONFIG |0x40, e8390_base + EN0_RXCR); /* rx
> on,  */
>               dev->set_multicast_list(dev);           /* Get the multicast
> status right if this
>                                                          was a reset. */
>     }
>     return;
> }
> 
> /* Trigger a transmit start, assuming the length is valid. */
> static void NS8390_trigger_send(struct device *dev, unsigned int length,
>                                                               int
> start_page)
> {
>       int e8390_base = dev->base_addr;
> 
> //    outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
> 
>       if (inb_p(e8390_base) & E8390_TRANS) {
>               printk("%s: trigger_send() called with the transmitter
> busy.\n",
>                       dev->name);
>               return;
>       }
>       outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
>       outb_p(length >> 8, e8390_base + EN0_TCNTHI);
>       outb_p(start_page, e8390_base + EN0_TPSR);
>       outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
>       return;
> }
> 
> #ifdef MODULE
> 
> int init_module(void)
> {
>      return 0;
> }
> 
> void
> cleanup_module(void)
> {
> }
> #endif /* MODULE */
> 
> 
> 
> /*
>  * Local variables:
>  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall
> -Wstrict-prototypes -O6 -m486 -c 8390.c"
>  *  version-control: t
>  *  kept-new-versions: 5
>  *  c-indent-level: 4
>  *  tab-width: 4
>  * End:
>  */
> 
> --------------------------------------------------------------------------
> ----------------------------------------
> GEN1:
> 
> gcc -DMODULE -D__KERNEL__ -I/usr/src/linux
> -I/usr/src/pcmcia-cs-3.0.9/include -c -O6 pcnet_cs.c
> cp pcnet_cs.o /lib/modules/2.0.30/pcmcia/pcnet_cs.o
> 
> --------------------------------------------------------------------------
> -----------------------------------------
> 
> GEN2:
> 
> gcc -DMODULE -D__KERNEL__ -I/usr/src/linux -I/usr/src/linux/drivers/net -c
> -O6 8390.c
> cp 8390.o /lib/modules/2.0.30/net/8390.o
> 
> 

Reply via email to