www.pudn.com > ejip.zip > CS8900.java


package ejip; 
 
/** 
*	CS8900.java 
* 
*	Low level interface to Cirrus Logic ethernet chip CS8900A. 
* 
*	Adapted from cs89x0.c driver for linux by  
*		Martin Schoeberl (martin.schoeberl@chello.at) 
* 
*	Written 1996 by Russell Nelson, with reference to skeleton.c 
*	written 1993-1994 by Donald Becker. 
*	Copyright, 1988-1992, Russell Nelson, Crynwr Software 
* 
*	This program is free software; you can redistribute it and/or modify 
*	it under the terms of the GNU General Public License as published by 
*	the Free Software Foundation, version 1. 
* 
*	This program is distributed in the hope that it will be useful, 
*	but WITHOUT ANY WARRANTY; without even the implied warranty of 
*	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
*	GNU General Public License for more details. 
* 
*	You should have received a copy of the GNU General Public License 
*	along with this program; if not, write to the Free Software 
*	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
* 
*		The author may be reached at nelson@crynwr.com, Crynwr 
*		Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 
* 
*   Changelog: 
*		2002-06-28	first working version 
*		2002-10-xx	some optimations, use Packet buffer (in 32 bit) 
*		2002-11-11	runs it its own thread (as LinkLayer) 
*/ 
 
import com.jopdesign.sys.*; 
import util.*; 
 
/** 
*	Low level interface to Cirrus Logic ethernet chip CS8900A. 
* 
*/ 
 
public class CS8900 extends LinkLayer { 
 
	public static final int ETH_HLEN = 14; 
 
/** 
*	flag allows new frame to be sent. 
*/ 
	private static boolean txFree;			// ready for next transmit 
 
	private static int[] eth;				// own ethernet address 
	private static int mac_low, mac_mid, mac_hi; 
	private static int ip;					// ip address for ARP requests 
 
 
	private static int tx_packets; 
	private static int tx_bytes; 
	private static int collisions; 
 
	private static int rx_packets; 
	private static int rx_bytes; 
	private static int rx_dropped; 
 
	private static int curr_rx_cfg;	/* a copy of PP_RxCFG */ 
 
/******** cs.h **********/ 
 
	private static final int PP_ISAIOB = 0x0020;	/*  IO base address */ 
 
	private static final int PP_RxCFG = 0x0102;		/*  Rx Bus config */ 
	private static final int PP_RxCTL = 0x0104;		/*  Receive Control Register */ 
	private static final int PP_TxCFG = 0x0106;		/*  Transmit Config Register */ 
	private static final int PP_TxCMD = 0x0108;		/*  Transmit Command Register */ 
	private static final int PP_BufCFG = 0x010A;	/*  Bus configuration Register */ 
	private static final int PP_LineCTL = 0x0112;	/*  Line Config Register */ 
	private static final int PP_SelfCTL = 0x0114;	/*  Self Command Register */ 
	private static final int PP_BusCTL = 0x0116;	/*  ISA bus control Register */ 
	private static final int PP_TestCTL = 0x0118;	/*  Test Register */ 
	private static final int PP_AutoNegCTL = 0x011C;	/*  Auto Negotiation Ctrl */ 
 
	private static final int PP_ISQ = 0x0120;		/*  Interrupt Status */ 
	private static final int PP_RxEvent = 0x0124;	/*  Rx Event Register */ 
	private static final int PP_TxEvent = 0x0128;	/*  Tx Event Register */ 
	private static final int PP_BufEvent = 0x012C;	/*  Bus Event Register */ 
	private static final int PP_RxMiss = 0x0130;	/*  Receive Miss Count */ 
	private static final int PP_TxCol = 0x0132;		/*  Transmit Collision Count */ 
	private static final int PP_LineST = 0x0134;	/*  Line State Register */ 
	private static final int PP_SelfST = 0x0136;	/*  Self State register */ 
	private static final int PP_BusST = 0x0138;		/*  Bus Status */ 
	private static final int PP_TDR = 0x013C;		/*  Time Domain Reflectometry */ 
	private static final int PP_AutoNegST = 0x013E;	/*  Auto Neg Status */ 
	private static final int PP_TxCommand = 0x0144;	/*  Tx Command */ 
	private static final int PP_TxLength = 0x0146;	/*  Tx Length */ 
	private static final int PP_LAF = 0x0150;		/*  Hash Table */ 
	private static final int PP_IA = 0x0158;		/*  Physical Address Register */ 
 
	private static final int PP_RxStatus = 0x0400;	/*  Receive start of frame */ 
	private static final int PP_RxLength = 0x0402;	/*  Receive Length of frame */ 
	private static final int PP_RxFrame = 0x0404;	/*  Receive frame pointer */ 
	private static final int PP_TxFrame = 0x0A00;	/*  Transmit frame pointer */ 
 
	private static final int ADD_MASK = 0x3000;		/*  Mask it use of the ADD_PORT register */ 
	private static final int ADD_SIG = 0x3000;		/*  Expected ID signature */ 
 
/*  Mask to find out the types of  registers */ 
	private static final int REG_TYPE_MASK = 0x001F; 
 
/*  Defines Control/Config register quintuplet numbers */ 
	private static final int RX_BUF_CFG = 0x0003; 
	private static final int RX_CONTROL = 0x0005; 
	private static final int TX_CFG = 0x0007; 
	private static final int TX_COMMAND = 0x0009; 
	private static final int BUF_CFG = 0x000B; 
	private static final int LINE_CONTROL = 0x0013; 
	private static final int SELF_CONTROL = 0x0015; 
	private static final int BUS_CONTROL = 0x0017; 
	private static final int TEST_CONTROL = 0x0019; 
 
/*  Defines Status/Count registers quintuplet numbers */ 
	private static final int RX_EVENT = 0x0004; 
	private static final int TX_EVENT = 0x0008; 
	private static final int BUF_EVENT = 0x000C; 
	private static final int RX_MISS_COUNT = 0x0010; 
	private static final int TX_COL_COUNT = 0x0012; 
	private static final int LINE_STATUS = 0x0014; 
	private static final int SELF_STATUS = 0x0016; 
	private static final int BUS_STATUS = 0x0018; 
	private static final int TDR = 0x001C; 
 
/* PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition -  Read/write */ 
	private static final int SKIP_1 = 0x0040; 
	private static final int RX_STREAM_ENBL = 0x0080; 
	private static final int RX_OK_ENBL = 0x0100; 
	private static final int RX_DMA_ONLY = 0x0200; 
	private static final int AUTO_RX_DMA = 0x0400; 
	private static final int BUFFER_CRC = 0x0800; 
	private static final int RX_CRC_ERROR_ENBL = 0x1000; 
	private static final int RX_RUNT_ENBL = 0x2000; 
	private static final int RX_EXTRA_DATA_ENBL = 0x4000; 
 
/* PP_RxCTL - Receive Control bit definition - Read/write */ 
	private static final int RX_IA_HASH_ACCEPT = 0x0040; 
	private static final int RX_PROM_ACCEPT = 0x0080; 
	private static final int RX_OK_ACCEPT = 0x0100; 
	private static final int RX_MULTCAST_ACCEPT = 0x0200; 
	private static final int RX_IA_ACCEPT = 0x0400; 
	private static final int RX_BROADCAST_ACCEPT = 0x0800; 
	private static final int RX_BAD_CRC_ACCEPT = 0x1000; 
	private static final int RX_RUNT_ACCEPT = 0x2000; 
	private static final int RX_EXTRA_DATA_ACCEPT = 0x4000; 
	private static final int RX_ALL_ACCEPT = (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT); 
/*  Default receive mode - individually addressed, broadcast, and error free */ 
	private static final int DEF_RX_ACCEPT = (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT); 
 
/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */ 
	private static final int TX_LOST_CRS_ENBL = 0x0040; 
	private static final int TX_SQE_ERROR_ENBL = 0x0080; 
	private static final int TX_OK_ENBL = 0x0100; 
	private static final int TX_LATE_COL_ENBL = 0x0200; 
	private static final int TX_JBR_ENBL = 0x0400; 
	private static final int TX_ANY_COL_ENBL = 0x0800; 
	private static final int TX_16_COL_ENBL = 0x8000; 
 
/* PP_TxCMD - Transmit Command bit definition - Read-only */ 
	private static final int TX_START_4_BYTES = 0x0000; 
	private static final int TX_START_64_BYTES = 0x0040; 
	private static final int TX_START_128_BYTES = 0x0080; 
	private static final int TX_START_ALL_BYTES = 0x00C0; 
	private static final int TX_FORCE = 0x0100; 
	private static final int TX_ONE_COL = 0x0200; 
	private static final int TX_TWO_PART_DEFF_DISABLE = 0x0400; 
	private static final int TX_NO_CRC = 0x1000; 
	private static final int TX_RUNT = 0x2000; 
 
/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */ 
	private static final int GENERATE_SW_INTERRUPT = 0x0040; 
	private static final int RX_DMA_ENBL = 0x0080; 
	private static final int READY_FOR_TX_ENBL = 0x0100; 
	private static final int TX_UNDERRUN_ENBL = 0x0200; 
	private static final int RX_MISS_ENBL = 0x0400; 
	private static final int RX_128_BYTE_ENBL = 0x0800; 
	private static final int TX_COL_COUNT_OVRFLOW_ENBL = 0x1000; 
	private static final int RX_MISS_COUNT_OVRFLOW_ENBL = 0x2000; 
	private static final int RX_DEST_MATCH_ENBL = 0x8000; 
 
/* PP_LineCTL - Line Control bit definition - Read/write */ 
	private static final int SERIAL_RX_ON = 0x0040; 
	private static final int SERIAL_TX_ON = 0x0080; 
	private static final int AUI_ONLY = 0x0100; 
	private static final int AUTO_AUI_10BASET = 0x0200; 
	private static final int MODIFIED_BACKOFF = 0x0800; 
	private static final int NO_AUTO_POLARITY = 0x1000; 
	private static final int TWO_PART_DEFDIS = 0x2000; 
	private static final int LOW_RX_SQUELCH = 0x4000; 
 
/* PP_SelfCTL - Software Self Control bit definition - Read/write */ 
	private static final int POWER_ON_RESET = 0x0040; 
	private static final int SW_STOP = 0x0100; 
	private static final int SLEEP_ON = 0x0200; 
	private static final int AUTO_WAKEUP = 0x0400; 
	private static final int HCB0_ENBL = 0x1000; 
	private static final int HCB1_ENBL = 0x2000; 
	private static final int HCB0 = 0x4000; 
	private static final int HCB1 = 0x8000; 
 
/* PP_BusCTL - ISA Bus Control bit definition - Read/write */ 
	private static final int RESET_RX_DMA = 0x0040; 
	private static final int MEMORY_ON = 0x0400; 
	private static final int DMA_BURST_MODE = 0x0800; 
	private static final int IO_CHANNEL_READY_ON = 0x1000; 
	private static final int RX_DMA_SIZE_64K = 0x2000; 
	private static final int ENABLE_IRQ = 0x8000; 
 
/* PP_TestCTL - Test Control bit definition - Read/write */ 
	private static final int LINK_OFF = 0x0080; 
	private static final int ENDEC_LOOPBACK = 0x0200; 
	private static final int AUI_LOOPBACK = 0x0400; 
	private static final int BACKOFF_OFF = 0x0800; 
	private static final int FDX_8900 = 0x4000; 
	private static final int FAST_TEST = 0x8000; 
 
/* PP_RxEvent - Receive Event Bit definition - Read-only */ 
	private static final int RX_IA_HASHED = 0x0040; 
	private static final int RX_DRIBBLE = 0x0080; 
	private static final int RX_OK = 0x0100; 
	private static final int RX_HASHED = 0x0200; 
	private static final int RX_IA = 0x0400; 
	private static final int RX_BROADCAST = 0x0800; 
	private static final int RX_CRC_ERROR = 0x1000; 
	private static final int RX_RUNT = 0x2000; 
	private static final int RX_EXTRA_DATA = 0x4000; 
 
	private static final int HASH_INDEX_MASK = 0x0FC00; 
 
/* PP_TxEvent - Transmit Event Bit definition - Read-only */ 
	private static final int TX_LOST_CRS = 0x0040; 
	private static final int TX_SQE_ERROR = 0x0080; 
	private static final int TX_OK = 0x0100; 
	private static final int TX_LATE_COL = 0x0200; 
	private static final int TX_JBR = 0x0400; 
	private static final int TX_16_COL = 0x8000; 
	private static final int TX_SEND_OK_BITS = (TX_OK|TX_LOST_CRS); 
	private static final int TX_COL_COUNT_MASK = 0x7800; 
 
/* PP_BufEvent - Buffer Event Bit definition - Read-only */ 
	private static final int SW_INTERRUPT = 0x0040; 
	private static final int RX_DMA = 0x0080; 
	private static final int READY_FOR_TX = 0x0100; 
	private static final int TX_UNDERRUN = 0x0200; 
	private static final int RX_MISS = 0x0400; 
	private static final int RX_128_BYTE = 0x0800; 
	private static final int TX_COL_OVRFLW = 0x1000; 
	private static final int RX_MISS_OVRFLW = 0x2000; 
	private static final int RX_DEST_MATCH = 0x8000; 
 
/* PP_LineST - Ethernet Line Status bit definition - Read-only */ 
	private static final int LINK_OK = 0x0080; 
	private static final int AUI_ON = 0x0100; 
	private static final int TENBASET_ON = 0x0200; 
	private static final int POLARITY_OK = 0x1000; 
	private static final int CRS_OK = 0x4000; 
 
/* PP_SelfST - Chip Software Status bit definition */ 
	private static final int ACTIVE_33V = 0x0040; 
	private static final int INIT_DONE = 0x0080; 
	private static final int SI_BUSY = 0x0100; 
	private static final int EEPROM_PRESENT = 0x0200; 
	private static final int EEPROM_OK = 0x0400; 
	private static final int EL_PRESENT = 0x0800; 
	private static final int EE_SIZE_64 = 0x1000; 
 
/* PP_BusST - ISA Bus Status bit definition */ 
	private static final int TX_BID_ERROR = 0x0080; 
	private static final int READY_FOR_TX_NOW = 0x0100; 
 
/* PP_AutoNegCTL - Auto Negotiation Control bit definition */ 
	private static final int RE_NEG_NOW = 0x0040; 
	private static final int ALLOW_FDX = 0x0080; 
	private static final int AUTO_NEG_ENABLE = 0x0100; 
	private static final int NLP_ENABLE = 0x0200; 
	private static final int FORCE_FDX = 0x8000; 
	private static final int AUTO_NEG_BITS = (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE); 
	private static final int AUTO_NEG_MASK = (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW); 
 
/* PP_AutoNegST - Auto Negotiation Status bit definition */ 
	private static final int AUTO_NEG_BUSY = 0x0080; 
	private static final int FLP_LINK = 0x0100; 
	private static final int FLP_LINK_GOOD = 0x0800; 
	private static final int LINK_FAULT = 0x1000; 
	private static final int HDX_ACTIVE = 0x4000; 
	private static final int FDX_ACTIVE = 0x8000; 
 
/*  The following block defines the ISQ event types */ 
	private static final int ISQ_RECEIVER_EVENT = 0x04; 
	private static final int ISQ_TRANSMITTER_EVENT = 0x08; 
	private static final int ISQ_BUFFER_EVENT = 0x0c; 
	private static final int ISQ_RX_MISS_EVENT = 0x10; 
	private static final int ISQ_TX_COL_EVENT = 0x12; 
 
	private static final int ISQ_EVENT_MASK = 0x003F;   /*  ISQ mask to find out type of event */ 
	private static final int ISQ_HIST = 16;		/*  small history buffer */ 
	private static final int AUTOINCREMENT = 0x8000;	/*  Bit mask to set bit-15 for autoincrement */ 
 
	private static final int TXRXBUFSIZE = 0x0600; 
	private static final int RXDMABUFSIZE = 0x8000; 
	private static final int RXDMASIZE = 0x4000; 
	private static final int TXRX_LENGTH_MASK = 0x07FF; 
 
/*  rx options bits */ 
	private static final int RCV_WITH_RXON	= 1;       /*  Set SerRx ON */ 
	private static final int RCV_COUNTS	= 2;       /*  Use Framecnt1 */ 
	private static final int RCV_PONG	= 4;       /*  Pong respondent */ 
	private static final int RCV_DONG	= 8;       /*  Dong operation */ 
	private static final int RCV_POLLING	= 0x10;	/*  Poll RxEvent */ 
	private static final int RCV_ISQ		= 0x20;	/*  Use ISQ, int */ 
	private static final int RCV_AUTO_DMA	= 0x100;	/*  Set AutoRxDMAE */ 
	private static final int RCV_DMA		= 0x200;	/*  Set RxDMA only */ 
	private static final int RCV_DMA_ALL	= 0x400;	/*  Copy all DMA'ed */ 
	private static final int RCV_FIXED_DATA	= 0x800;	/*  Every frame same */ 
	private static final int RCV_IO		= 0x1000;	/*  Use ISA IO only */ 
	private static final int RCV_MEMORY	= 0x2000;	/*  Use ISA Memory */ 
 
	private static final int RAM_SIZE	= 0x1000;       /*  The card has 4k bytes or RAM */ 
	private static final int PKT_START = PP_TxFrame;  /*  Start of packet RAM */ 
 
	private static final int RX_FRAME_PORT	= 0x0000; 
	private static final int TX_FRAME_PORT = RX_FRAME_PORT; 
	private static final int TX_CMD_PORT	= 0x0004; 
	private static final int TX_NOW		= 0x0000;       /*  Tx packet after   5 bytes copied */ 
	private static final int TX_AFTER_381	= 0x0040;       /*  Tx packet after 381 bytes copied */ 
	private static final int TX_AFTER_ALL	= 0x00c0;       /*  Tx packet after all bytes copied */ 
	private static final int TX_LEN_PORT	= 0x0006; 
	private static final int ISQ_PORT	= 0x0008; 
	private static final int ADD_PORT	= 0x000A; 
	private static final int DATA_PORT	= 0x000C; 
 
 
/*  Receive Header */ 
/*  Description of header of each packet in receive area of memory */ 
	private static final int RBUF_EVENT_LOW	= 0;   /*  Low byte of RxEvent - status of received frame */ 
	private static final int RBUF_EVENT_HIGH	= 1;   /*  High byte of RxEvent - status of received frame */ 
	private static final int RBUF_LEN_LOW	= 2;   /*  Length of received data - low byte */ 
	private static final int RBUF_LEN_HI	= 3;   /*  Length of received data - high byte */ 
	private static final int RBUF_HEAD_LEN	= 4;   /*  Length of this header */ 
 
	private static final int CHIP_READ = 0x1;   /*  Used to mark state of the repins code (chip or dma) */ 
	private static final int DMA_READ = 0x2;   /*  Used to mark state of the repins code (chip or dma) */ 
 
 
	private static final int IMM_BIT = 0x0040;		/*  ignore missing media	 */ 
 
	private static final int A_CNF_10B_T = 0x0001; 
	private static final int A_CNF_AUI = 0x0002; 
	private static final int A_CNF_10B_2 = 0x0004; 
	private static final int A_CNF_MEDIA_TYPE = 0x0060; 
	private static final int A_CNF_MEDIA_AUTO = 0x0000; 
	private static final int A_CNF_MEDIA_10B_T = 0x0020; 
	private static final int A_CNF_MEDIA_AUI = 0x0040; 
	private static final int A_CNF_MEDIA_10B_2 = 0x0060; 
	private static final int A_CNF_DC_DC_POLARITY = 0x0080; 
	private static final int A_CNF_NO_AUTO_POLARITY = 0x2000; 
	private static final int A_CNF_LOW_RX_SQUELCH = 0x4000; 
	private static final int A_CNF_EXTND_10B_2 = 0x8000; 
 
	private static final int PACKET_PAGE_OFFSET = 0x8; 
 
 
/** 
*	an ARP frame. 
*/ 
	private static final int ETH_ARP = 0x0806; 
/** 
*	an IP frame. 
*/ 
	private static final int ETH_IP = 0x0800; 
 
/** 
*	The one and only reference to this object. 
*/ 
	// private static CS8900 single; 
// just for first OEBB test 
public static CS8900 single; 
public static int[] llh;		// for OEBB test 
 
/** 
*	period for thread in ms. 
*/ 
	private static final int PERIOD = 10; 
 
/** 
*	private constructor. The singleton object is created in init(). 
*/ 
	private CS8900() { 
		super(PERIOD);						// thats the period. 
	} 
 
/** 
*	the polling thread loop. 
*/ 
	public void run() { 
 
		Packet p; 
 
		for (;;) { 
			waitForNextPeriod(); 
 
			poll(); 
			if (txFree) { 
				// 
				// get a ready to send packet with source from this driver. 
				// 
				p = Packet.getPacket(single, Packet.SND, Packet.ALLOC); 
				if (p!=null) { 
					send(p);				// send one packet 
				} 
			} 
		} 
	} 
 
/** 
*	allocate buffer, reset chip and start Thread. 
*/ 
	public static void init(int[] mac, int ipaddr) { 
 
		if (single != null) return;			// allready called init() 
 
		txFree = true; 
 
		eth = new int[6]; 
		for (int i=0; i<6; ++i) eth[i] = mac[i]; 
		// intel byte order !!! 
		mac_hi = mac[0]<<8 | mac[1]; 
		mac_mid = mac[2]<<8 | mac[3]; 
		mac_low = mac[4]<<8 | mac[5]; 
llh = new int[ETH_HLEN/2]; 
 
		ip = ipaddr; 
 
		tx_packets = 0; 
		tx_bytes = 0; 
		collisions = 0; 
 
		rx_packets = 0; 
		rx_bytes = 0; 
		rx_dropped = 0; 
 
		reset(); 
 
		single = new CS8900(); 
		single.start();						// kick off the thread 
	} 
 
 
// 
//	ISA bus handling 
// 
	private static final int IO_CTRL = 5; 
	private static final int IO_DATA = 6; 
 
	private static final int ISA_RESET = 0x20; 
	private static final int ISA_RD = 0x40; 
	private static final int ISA_WR = 0x80; 
	private static final int ISA_DIR = 0x100;	// means driving out 
/* 
	VHDL definition: 
 
	isa_a <= din(4 downto 0); 
	isa_reset <= din(5); 
	isa_nior <= not din(6); 
	isa_niow <= not din(7); 
	isa_dir <= din(8); 
*/ 
 
 
/** 
*	reset isa bus 
*/ 
	private static void resetIsa() { 
 
		try { 
			Native.wr(ISA_RESET, IO_CTRL);				// isa bus reset 
			Thread.sleep(5); 
			Native.wr(0, IO_CTRL);						// disable reset 
			Thread.sleep(5); 
		} catch (Exception e) {}; 
	} 
 
/** 
*	'ISA Bus' io read cycle 2x8 bit. 
*/ 
	private static int readWord(int port) { 
 
		Native.wr(port, IO_CTRL);				// port 
		Native.wr(port | ISA_RD, IO_CTRL);		// nior low 
		int ret = Native.rd(IO_DATA);			// read data 
		Native.wr(port, IO_CTRL);				// nior high again 
		++port; 
		Native.wr(port, IO_CTRL);				// port 
		Native.wr(port | ISA_RD, IO_CTRL);		// nior low 
		ret += Native.rd(IO_DATA)<<8;			// read data 
		Native.wr(port, IO_CTRL);				// nior high again 
 
		return ret; 
	} 
 
/** 
*	'ISA Bus' io read cycle 2x8 bit with high byte first. 
*/ 
	private static int readWordHighFirst(int port) { 
 
		++port; 
		Native.wr(port, IO_CTRL);				// addr 
		Native.wr(port | ISA_RD, IO_CTRL);		// nior low 
		int ret = Native.rd(IO_DATA)<<8;		// read data 
		Native.wr(port, IO_CTRL);				// nior high again 
		--port; 
		Native.wr(port, IO_CTRL);				// addr 
		Native.wr(port | ISA_RD, IO_CTRL);		// nior low 
		ret += Native.rd(IO_DATA)&0xff;			// read data 
		Native.wr(port, IO_CTRL);				// nior high again 
 
		return ret; 
	} 
 
/** 
*	'ISA Bus' io write cycle 2x8 bit. 
*	first low byte than high byte at higher address. 
*/ 
	private static void writeWord(int port, int value) { 
 
		Native.wr(value, IO_DATA);					// value in buffer 
		Native.wr(port | ISA_DIR, IO_CTRL);			// port and drive value out 
		Native.wr(port | ISA_WR | ISA_DIR, IO_CTRL);	// niow low 
		Native.wr(port | ISA_DIR, IO_CTRL);			// niow high again 
		++port; 
		Native.wr(value>>8, IO_DATA);				// value in buffer 
		Native.wr(port | ISA_DIR, IO_CTRL);			// port and drive value out 
		Native.wr(port | ISA_WR | ISA_DIR, IO_CTRL);	// niow low 
		Native.wr(port | ISA_DIR, IO_CTRL);			// niow high again 
		Native.wr(port, IO_CTRL);					// disable dout 
	} 
 
 
	private static int readReg(int reg) { 
		writeWord(ADD_PORT, reg); 
		return readWord(DATA_PORT); 
	} 
	private static void writeReg(int reg, int value) { 
		writeWord(ADD_PORT, reg); 
		writeWord(DATA_PORT, value); 
	} 
 
/** 
*	write ethernet header. 
*/ 
	private static void writeHead(Packet p) { 
 
		int i, val; 
 
		p.llh[3] = mac_hi; 
		p.llh[4] = mac_mid; 
		p.llh[5] = mac_low; 
		for (i=0; i>>8, IO_DATA);							// value in buffer 
			Native.wr(TX_FRAME_PORT | ISA_DIR, IO_CTRL);			// port and drive value out 
			Native.wr(TX_FRAME_PORT | ISA_WR | ISA_DIR, IO_CTRL);	// niow low 
			Native.wr(TX_FRAME_PORT | ISA_DIR, IO_CTRL);			// niow high again 
			Native.wr(val, IO_DATA);								// value in buffer 
			Native.wr(TX_FRAME_PORT+1 | ISA_DIR, IO_CTRL);			// port and drive value out 
			Native.wr(TX_FRAME_PORT+1 | ISA_WR | ISA_DIR, IO_CTRL);	// niow low 
			Native.wr(TX_FRAME_PORT+1 | ISA_DIR, IO_CTRL);			// niow high again 
		} 
		Native.wr(TX_FRAME_PORT+1, IO_CTRL);						// disable dout 
	} 
/** 
*	write tx data. 
*/ 
	private static void writeData(Packet p) { 
 
		int i, val; 
		int[] buf = p.buf; 
		int length = p.len; 
 
		if ((length & 1) == 1) ++length;		// even bytes 
		val = 0; 
 
		for (i=0; i>2)]; 
			} 
 
			Native.wr(val>>>24, IO_DATA);							// value in buffer 
			Native.wr(TX_FRAME_PORT | ISA_DIR, IO_CTRL);			// port and drive value out 
			Native.wr(TX_FRAME_PORT | ISA_WR | ISA_DIR, IO_CTRL);	// niow low 
			Native.wr(TX_FRAME_PORT | ISA_DIR, IO_CTRL);			// niow high again 
			Native.wr(val>>>16, IO_DATA);							// value in buffer 
			Native.wr(TX_FRAME_PORT+1 | ISA_DIR, IO_CTRL);			// port and drive value out 
			Native.wr(TX_FRAME_PORT+1 | ISA_WR | ISA_DIR, IO_CTRL);	// niow low 
			Native.wr(TX_FRAME_PORT+1 | ISA_DIR, IO_CTRL);			// niow high again 
		} 
		Native.wr(TX_FRAME_PORT+1, IO_CTRL);						// disable dout 
	} 
 
/** 
*	read ethernet header. 
*/ 
	private static void readHead(Packet p) { 
 
		int i, val; 
		int[] buf = p.llh; 
 
		for (i=0; i>2] = val; 
				val = 0; 
			} else { 
				val <<= 16; 
			} 
		} 
		if ((length & 2) != 0) {				// length is not a multiple of 4 
			buf[length>>2] = val; 
		} 
	} 
 
 
/** 
*	reset chip and set registers 
*/ 
	private static void reset() { 
 
		int i; 
 
		resetIsa();					// isa reset 
 
		// wait for init 
		while((readReg(PP_SelfST) & INIT_DONE) == 0)	// && jiffies - reset_start_time < 2) 
			; 
 
		// no int, no mem and don't use iochrdy pin 
		writeReg(PP_BusCTL, IO_CHANNEL_READY_ON); 
		// set the Ethernet address 
		for (i=0; i < 6/2; i++) { 
			writeReg(PP_IA+i*2, eth[i*2] | (eth[i*2+1] << 8)); 
		} 
		// default value, 10BASE-T only, disabled rx, tx 
		// set LOW_RX_SQUELCH for longer cables 
		writeReg(PP_LineCTL, 0); 
		// TODO check attached cable 
		// Turn on both receive and transmit operations 
		writeReg(PP_LineCTL, readReg(PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); 
	 
		// Receive only error free packets addressed to this card  
		// rx_mode = 0; 
		writeReg(PP_RxCTL, DEF_RX_ACCEPT); 
	 
		curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; 
	 
		writeReg(PP_RxCFG, curr_rx_cfg); 
	 
		writeReg(PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | 
			TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); 
	 
		writeReg(PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | 
			TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); 
	} 
 
/** 
*	Sends a packet to an CS8900 network device. 
*	old ret was 0 if ok, now true if ok! 
*/ 
	private static void send(Packet p) { 
	 
	 
		/* keep the upload from being interrupted, since we 
	                  ask the chip to start transmitting before the 
	                  whole packet has been completely uploaded. */ 
		// spin_lock_irq(&lp->lock); 
		// netif_stop_queue(dev); 
	 
		/* initiate a transmit sequence */ 
		writeWord(TX_CMD_PORT, TX_AFTER_ALL); 
		writeWord(TX_LEN_PORT, p.len+14); 
	 
		/* Test to see if the chip has allocated memory for the packet */ 
		if ((readReg(PP_BusST) & READY_FOR_TX_NOW) == 0) { 
			/* 
			 * Gasp!  It hasn't.  But that shouldn't happen since 
			 * we're waiting for TxOk, so return 1 and requeue this packet. 
			 */ 
			// p.setStatus(Packet.FREE); 
// or keep it in SND status??? 
Dbg.wr('^'); 
			return; 
		} 
 
 
		/* Write ethernet header */ 
		writeHead(p); 
		/* Write the contents of the packet */ 
		writeData(p); 
		p.setStatus(Packet.FREE); 
		txFree = false; 
 
		// 
		// txFree is set with an transmit event 
		// 
	} 
 
	private static final int EVENT_MASK = 0xffc0; 
 
	private static int pollRegs() { 
 
		int event; 
		 
		event = readReg(PP_RxEvent); 
		if ((event & EVENT_MASK)!=0) return event; 
		event = readReg(PP_TxEvent); 
		if ((event & EVENT_MASK)!=0) return event; 
		event = readReg(PP_BufEvent); 
		if ((event & EVENT_MASK)!=0) return event; 
 
		return 0; 
	} 
 
/** 
*	The typical workload of the driver: 
*   We have to poll the chip (in 8 Bit mode)! 
*/ 
	    
	private static void poll() { 
 
		int status, mask; 
	  
		/* we MUST read all the events out of the ISQ, otherwise we'll never 
	           get interrupted again.  As a consequence, we can't have any limit 
	           on the number of times we loop in the interrupt handler.  The 
	           hardware guarantees that eventually we'll run out of events.  Of 
	           course, if you're on a slow machine, and packets are arriving 
	           faster than you can read them off, you're screwed.  Hasta la 
	           vista, baby!  */ 
		while ((status = pollRegs()) != 0) { 
 
			mask = status & ISQ_EVENT_MASK; 
 
			if (mask == ISQ_RECEIVER_EVENT) { 
				/* Got a packet(s). */ 
				net_rx(); 
 
			} else if (mask == ISQ_TRANSMITTER_EVENT) { 
				tx_packets++; 
				// netif_wake_queue(dev);	/* Inform upper layers. */ 
				txFree = true; 
				if ((status & (	TX_OK | 
						TX_LOST_CRS | 
						TX_SQE_ERROR | 
						TX_LATE_COL | 
						TX_16_COL)) != TX_OK) { 
					; 
				} 
 
			} else if (mask == ISQ_BUFFER_EVENT) { 
 
				if ((status & READY_FOR_TX) != 0) { 
					/* we tried to transmit a packet earlier, 
	                                   but inexplicably ran out of buffers. 
	                                   That shouldn't happen since we only ever 
	                                   load one packet.  Shrug.  Do the right 
	                                   thing anyway. */ 
					// netif_wake_queue(dev);	/* Inform upper layers. */ 
					txFree = true; 
				} 
				if ((status & TX_UNDERRUN)!=0) { 
					/* transmit cycle is done, although 
					   frame wasn't transmitted - this 
					   avoids having to wait for the upper 
					   layers to timeout on us, in the 
					   event of a tx underrun */ 
					// netif_wake_queue(dev);	/* Inform upper layers. */ 
					txFree = true; 
				} 
			} 
		} 
	} 
	 
	/* We have a good packet(s), get it/them out of the buffers. */ 
	private static void net_rx() { 
 
		int status, length; 
	 
		// read high byte first: see AN181 
		status = readWordHighFirst(RX_FRAME_PORT); 
		length = readWordHighFirst(RX_FRAME_PORT)-14;	// don't count ethernet header 
	 
		if ((status & RX_OK) == 0) { 
			writeReg(PP_RxCFG, curr_rx_cfg | SKIP_1);	// release memory on chip 
			return; 
		} 
	 
		// get a free packet and set source to CS8900 
		Packet p = Packet.getPacket(Packet.FREE, Packet.ALLOC, single); 
		if (p == null) {								// got no free buffer! 
Dbg.wr('~'); 
			rx_dropped++; 
			writeReg(PP_RxCFG, curr_rx_cfg | SKIP_1);	// release memory on chip 
			return; 
		} 
	 
		p.len = length;	 
		// read ethernet header 
		readHead(p); 
		// read data 
		readData(p); 
 
		// 
		//	if an ARP request we handle it here. 
		// 
		int i = p.llh[6];					// type field of ethernet header 
		if (i == ETH_ARP) {					// ARP type 
			Arp.request(p, eth, ip); 
		} else if (i == ETH_IP) {			// IP type 
			p.setStatus(Packet.RCV);		// inform upper layer 
// OEBB test 
for (i=0; i