ne2000core.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 672 行 · 第 1/2 页

JAVA
672
字号
/*
 * $Id: Ne2000Core.java,v 1.2 2003/12/21 08:04:06 epr Exp $
 */
package org.jnode.driver.net.ne2000;

import java.util.Arrays;

import javax.naming.NameNotFoundException;

import org.apache.log4j.Logger;
import org.jnode.driver.Device;
import org.jnode.driver.DriverException;
import org.jnode.driver.net.AbstractDeviceCore;
import org.jnode.driver.net.NetworkException;
import org.jnode.driver.net.ne2000.pci.Ne2000PCIDriver;
import org.jnode.naming.InitialNaming;
import org.jnode.net.HardwareAddress;
import org.jnode.net.SocketBuffer;
import org.jnode.net.ethernet.EthernetAddress;
import org.jnode.net.ethernet.EthernetConstants;
import org.jnode.system.IOResource;
import org.jnode.system.IRQHandler;
import org.jnode.system.IRQResource;
import org.jnode.system.ResourceManager;
import org.jnode.system.ResourceNotFreeException;
import org.jnode.system.ResourceOwner;
import org.jnode.util.NumberUtils;
import org.jnode.util.TimeoutException;

/**
 * @author epr
 */
public abstract class Ne2000Core extends AbstractDeviceCore
	implements IRQHandler, Ne2000Constants, EthernetConstants {

	private static final int TX_PAGES = 6;

	/** My logger */
	private final Logger log = Logger.getLogger(getClass());
	/** Start of IO address space */
	protected final int iobase;
	/** IO address space */
	protected final IOResource io;
	/** IRQ */
	protected final IRQResource irq;
	/** My ethernet address */
	private final EthernetAddress hwAddress;
	/** My device flags */
	protected final Ne2000Flags flags;
	/** Start page of NIC memory */
	protected final int nic_start;
	/** Start page of transmit buffer */
	protected final int tx_start;
	/** Start page of receive buffer */
	protected final int rx_start;
	/** End page of receive buffer (exclusive) */
	protected final int rx_end;
	/** Is a transmit action in progress? */
	private boolean tx_active;
	private int rx_frame_errors;
	private int rx_crc_errors;
	private int rx_missed_errors;
	private int rx_overruns;
	/** The driver we will deliver the receive packets to */
	private final Ne2000PCIDriver driver;

	/**
	 * Create a new instance
	 * @param owner
	 * @param device
	 * @param flags
	 */
	public Ne2000Core(
		Ne2000PCIDriver driver,
		ResourceOwner owner,
		Device device,
		Ne2000Flags flags)
	throws ResourceNotFreeException, DriverException {
	
		final int irq = getIRQ(device, flags);
		this.driver = driver;
		this.flags = flags;
		this.tx_active = false;

		// Get the start of the IO address space
		iobase = getIOBase(device, flags);
		final int iolength = getIOLength(device, flags);
		final ResourceManager rm;
		try {
			rm = (ResourceManager)InitialNaming.lookup(ResourceManager.NAME);
		} catch (NameNotFoundException ex) {
			throw new DriverException("Cannot find ResourceManager");
		}
		this.irq = rm.claimIRQ(owner, irq, this, true);
		try {
			io = rm.claimIOResource(owner, iobase, iolength);
		} catch (ResourceNotFreeException ex) {
			this.irq.release();
			throw ex;
		}

		// Reset the device
		reset();

		// Load the hw address, todo this we must first do some initialization,
		// otherwise the hw address cannot be read.
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STP); // Select page 0
		setReg(NE_P0_DCR, 0x49); // Set word-wide access
		setReg(NE_P0_RBCR0, 0x00); // Clear count regs
		setReg(NE_P0_RBCR1, 0x00);
		setReg(NE_P0_IMR, 0x00); // Mask completion irq
		setReg(NE_P0_ISR, 0xff);
		setReg(NE_P0_RCR, NE_RXOFF);
		setReg(NE_P0_TCR, NE_TXOFF);

		// Load the start page		
		this.nic_start = probeNicMemoryStart();
		this.tx_start = nic_start;
		this.rx_start = tx_start + TX_PAGES;
		this.rx_end = nic_start + (flags.getMemSize() / NE_PAGESIZE);

		final byte[] saprom = new byte[32];
		getNicData(0, saprom, 0, 32);

		if (flags.is16bit()) {
			this.hwAddress =
				new EthernetAddress(
					saprom[0],
					saprom[2],
					saprom[4],
					saprom[6],
					saprom[8],
					saprom[10]);
		} else {
			this.hwAddress = new EthernetAddress(saprom, 0);
		}

		log.debug(
			"Found "
				+ flags.getName()
				+ " IRQ="
				+ irq
				+ ", IOBase=0x"
				+ NumberUtils.hex(iobase)
				+ ", MAC Address="
				+ hwAddress);
	}
	
	/**
	 * Gets the first IO-Address used by the given device
	 * @param device
	 * @param flags
	 */
	protected abstract int getIOBase(Device device, Ne2000Flags flags)
	throws DriverException;

	/**
	 * Gets the number of IO-Addresses used by the given device
	 * @param device
	 * @param flags
	 */
	protected abstract int getIOLength(Device device, Ne2000Flags flags)
	throws DriverException;

	/**
	 * Gets the IRQ used by the given device
	 * @param device
	 * @param flags
	 */
	protected abstract int getIRQ(Device device, Ne2000Flags flags)
	throws DriverException;

	/**
	 * Initialize the device
	 */
	public synchronized void initialize() {
		// Reset the device
		reset();

		// Load the hw address, todo this we must first do some initialization,
		// otherwise the hw address cannot be read.
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STP); // Select page 0
		setReg(NE_P0_DCR, 0x49); // Set word-wide access
		setReg(NE_P0_RBCR0, 0x00); // Clear count regs
		setReg(NE_P0_RBCR1, 0x00);
		setReg(NE_P0_ISR, 0xff); // Clear all interrupt flags
		setReg(NE_P0_IMR, NE_ISRCONFIG);

		// Setup buffer ring
		setReg(NE_P0_PSTART, rx_start);
		setReg(NE_P0_PSTOP, rx_end);
		setReg(NE_P0_BOUND, rx_end - 1);
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS1 | NE_CR_STP); // Select page 1
		setReg(NE_P1_CURR, rx_start);

		// Setup PAR0-5, MAR0-7
		for (int i = 0; i < ETH_ALEN; i++) {
			setReg(NE_P1_PAR0 + i, hwAddress.get(i));
		}
		for (int i = 0; i < ETH_ALEN; i++) {
			setReg(NE_P1_MAR0 + i, 0xff);
		}

		// Start the receive/transmit mode
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STA); // Select page 0
		setReg(NE_P0_RCR, NE_RXCONFIG);
		setReg(NE_P0_TCR, NE_TXCONFIG);

		log.debug(
			"Start receiving..rx_start="
				+ rx_start
				+ ", rx_end="
				+ rx_end
				+ ", tx_start="
				+ tx_start);
	}

	/**
	 * Disable the device
	 */
	public synchronized void disable() {
		// Start the receive/transmit mode
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STP); // Select page 0
		setReg(NE_P0_RCR, NE_RXOFF);
		setReg(NE_P0_TCR, NE_TXOFF);
	}

	/**
	 * Release all resources
	 */
	public synchronized void release() {
		io.release();
		irq.release();
	}

	/**
	 * Transmit the given buffer
	 * @param buf
	 * @param timeout
	 * @throws InterruptedException
	 * @throws TimeoutException
	 */
	public synchronized void transmit(SocketBuffer buf, long timeout)
		throws InterruptedException, TimeoutException {

		// Set the source address
		hwAddress.writeTo(buf, 6);

		// Wait until we can start transmitting
		while (tx_active) {
			wait(timeout);
		}
		tx_active = true;
		//log.debug("Going for transmit:\n" + NumberUtils.hex(buf.getBuffer(), buf.getBufferOffset(), buf.getSize()));

		final int length = buf.getSize();
		setNicData(buf, 0, (tx_start << 8), length);
		// Program the transmit
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STA);
		setReg(NE_P0_TPSR, tx_start);
		setReg(NE_P0_TBCR0, length & 0xFF);
		setReg(NE_P0_TBCR1, (length >> 8) & 0xFF);
		setReg(NE_P0_CR, NE_CR_TXP | NE_CR_NODMA | NE_CR_PS0 | NE_CR_STA);
	}

	/**
	 * @see org.jnode.system.IRQHandler#handleInterrupt(int)
	 */
	public synchronized void handleInterrupt(int irq) {

		// Get the interrupt status
		setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STA);

		int isr;
		int loops = 0;
		while (((isr = getReg(NE_P0_ISR)) != 0)
			&& (loops < NE_MAX_ISR_LOOPS)) {
			loops++;
			// Receive 
			if ((isr & NE_ISR_OVW) != 0) {
				processOverrunInterrupt();
				// Overrun interrupt is acknowledged in processOverrunInterrupt
			} else if ((isr & (NE_ISR_PRX | NE_ISR_RXE)) != 0) {
				processReceiveInterrupt();
				setReg(NE_P0_ISR, NE_ISR_PRX | NE_ISR_RXE);
			}

			// Transmit
			if ((isr & NE_ISR_TXE) != 0) {
				processTransmitErrorInterrupt();
				setReg(NE_P0_ISR, NE_ISR_PTX | NE_ISR_TXE);
			} else if ((isr & NE_ISR_PTX) != 0) {
				processTransmitInterrupt();
				setReg(NE_P0_ISR, NE_ISR_PTX | NE_ISR_TXE);
			}

			// Counters
			if ((isr & NE_ISR_CNT) != 0) {
				processCounterInterrupt();
				setReg(NE_P0_ISR, NE_ISR_CNT);
			}

			// Remote DMA completed, ignore
			if ((isr & NE_ISR_RDC) != 0) {
				setReg(NE_P0_ISR, NE_ISR_RDC);
			}

			// Reset start position
			setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STA);
		}

		if (isr != 0) {
			setReg(NE_P0_CR, NE_CR_NODMA | NE_CR_PS0 | NE_CR_STA);
			if (loops >= NE_MAX_ISR_LOOPS) {
				log.error(
					"Too much work in interrupt handler of "
						+ flags.getName()
						+ ", isr=0x"
						+ NumberUtils.hex(isr, 2));
				setReg(NE_P0_ISR, NE_ISRCONFIG);
			} else {
				log.error(
					"Unknown interrupt of "
						+ flags.getName()
						+ ", isr=0x"
						+ NumberUtils.hex(isr, 2));
				setReg(NE_P0_ISR, 0xFF);
			}
		}
	}

	/**
	 * Process an interrupt caused by an almost overrun of the NIC counters.
	 */
	private void processCounterInterrupt() {
		rx_frame_errors += getReg(NE_P0_CNTR0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?