[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

PCMCIA Network driver.



> 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 becker@CESDIS.gsfc.nasa.gov, 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 (becker@cesdis.gsfc.nasa.gov)\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 to: