lance.java

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

JAVA
315
字号
/*
 * $Id: Lance.java,v 1.4 2003/12/21 08:04:06 epr Exp $
 */
package org.jnode.driver.net.lance;

import javax.naming.NameNotFoundException;

import org.apache.log4j.Logger;
import org.jnode.driver.DriverException;
import org.jnode.driver.pci.PCIBaseAddress;
import org.jnode.driver.pci.PCIDevice;
import org.jnode.driver.pci.PCIDeviceConfig;
import org.jnode.naming.InitialNaming;
import org.jnode.net.ethernet.EthernetAddress;
import org.jnode.net.ethernet.EthernetConstants;
import org.jnode.system.BootLog;
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;

/**
 * @author epr
 */
public class Lance implements IRQHandler, LanceConstants, EthernetConstants {

	/** My logger */
	private final Logger log = Logger.getLogger(getClass());
	/** Start of IO address space */
	private final int iobase;
	/** IO address space */
	private final IOResource io;
	/** IRQ */
	private final IRQResource irq;
	/** My ethernet address */
	private final EthernetAddress hwAddress;
	private final LanceFlags flags;
	private final RxTxBuffer rxtxbuf;

	private boolean chip16Bits = true;

	/**
	 * Create a new instance and allocate all resources
	 * 
	 * @throws ResourceNotFreeException
	 */
	public Lance(ResourceOwner owner, PCIDevice device, LanceFlags flags) throws ResourceNotFreeException, DriverException {
		final PCIDeviceConfig config = device.getConfig();
		final PCIBaseAddress[] addrs = config.getBaseAddresses();
		final int irq = config.getInterruptLine();
		log.debug("Found Lance IRQ: " + irq);
		this.flags = flags;

		if (addrs.length < 1) {
			throw new DriverException("Cannot find iobase: not base addresses");
		}
		if (!addrs[0].isIOSpace()) {
			throw new DriverException("Cannot find iobase: first address is not I/O");
		}

		// Get the start of the IO address space
		iobase = addrs[0].getIOBase();
		final int iolength = addrs[0].getSize();
		log.debug("Found Lance IOBase: 0x" + NumberUtils.hex(iobase) + ", length: " + iolength);
		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;
		}

		// Load the hw address
		this.hwAddress = loadHWAddress();
		log.debug("Found hwaddress: " + hwAddress);
		// Create rx & tx descriptor rings, initdata and databuffers
		this.rxtxbuf = new RxTxBuffer(4, 4, CSR15_DRX | CSR15_DTX, 0, 0, rm);
	}

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

	/**
	 * Initialize this device.
	 */
	public void initialize() {

		// reset the chip
		resetDW();
		reset();

		chip16Bits = true;

		if (getCSR(0) == 4 && check()) {
			BootLog.debug("PCNet :: 16 bits chip");
			chip16Bits = true;
		} else {
			chip16Bits = false;
			if (getCSR(0) == 4 && checkDW()) {
				BootLog.debug("PCNet :: 32 bits chip");
				chip16Bits = false;
			}
		}

		int chipVersion = getCSR(88) | (getCSR(89) << 16);
		chipVersion = (chipVersion >> 12) & 0xffff;

		String chipName;

		switch (chipVersion) {
			case 0x2420 :
				chipName = "PCnet/PCI 79C970";
				break;
			case 0x2430 :
				chipName = "PCnet/PCI 79C970 or PCnet/32 79C965";
				break;
			case 0x2621 :
				chipName = "PCnet/PCI II 79C970A";
				break;
			case 0x2623 :
				chipName = "PCnet/FAST 79C971";
				break;
			case 0x2624 :
				chipName = "PCnet/FAST+ 79C972";
				break;
			case 0x2625 :
				chipName = "PCnet/FAST III 79C973";
				break;
			case 0x2626 :
				chipName = "PCnet/Home 79C978";
				break;
			case 0x2627 :
				chipName = "PCnet/FAST III 79C970";
				break;
			default :
				chipName = "no device !";
				break;
		}

		BootLog.debug("Pcnet32 :: " + chipName + " at " + NumberUtils.hex(iobase));

		if (flags.isAutoSelectEnabled()) {
			/*
			 * This is 79C960 specific; Turn on auto-select of media
			 */
			final int current = getBCR(0x02);
			setBCR(0x02, current | BCR2_ASEL);
		}

		final int iaddr = rxtxbuf.getInitDataAddress();
		setCSR(1, iaddr & 0xFFFF);
		setCSR(2, (iaddr >> 16) & 0xFFFF);
		setCSR(4, CSR4_JABM | CSR4_TXSTRTM | CSR4_RCVCCOM | CSR4_MFCOM | CSR4_APAD_XMT); // Set
		// Interrupt
		// masks

		setCSR(0, CSR0_INIT | CSR0_IENA); // Trigger INIT, Enable interrupts
		// Wait for the initialization to finish
		int i = 0;
		while (i++ < 100) {
			if ((getCSR(0) & CSR0_IDON) != 0)
				break;
			//Thread.yield();
		}

		BootLog.debug("PCNet :: Init done after " + i + " ticks.");

		setCSR(0,0x0042);
		
		// Now enable RX/TX
		setCSR(15, 0);
	}

	/**
	 * Disable this device
	 *  
	 */
	public void disable() {
		reset();
		setCSR(0, CSR0_STOP);
	}

	/**
	 * Gets the hardware address of this card.
	 */
	public EthernetAddress getAddress() {
		return hwAddress;
	}

	/**
	 * Read the hardware address
	 */
	private final EthernetAddress loadHWAddress() {
		final byte[] addr = new byte[ETH_ALEN];
		for (int i = 0; i < addr.length; i++) {
			addr[i] = (byte) io.inPortByte(iobase + R_ETH_ADDR_OFFSET + i);
		}
		return new EthernetAddress(addr, 0);
	}

	/**
	 * Reset the device
	 */
	private final void reset() {
		// Read triggers a reset
		io.inPortWord(iobase + RW_RESET_OFFSET);
		if (flags.mustUnreset()) {
			// Write only needed on NE2100, should not harm others.
			io.outPortWord(iobase + RW_RESET_OFFSET, 0);
		}
	}

	/**
	 * Reset the device (DW version)
	 */
	private final void resetDW() {
		io.inPortDword(iobase + RDW_RESET_OFFSET);
	}

	/**
	 * Gets the contents of a Control and Status Register.
	 * 
	 * @param csrnr
	 */
	private final int getCSR(int csrnr) {
		if (chip16Bits) {
			io.outPortWord(iobase + RW_ADDR_OFFSET, csrnr);
			return io.inPortWord(iobase + RW_RDATA_OFFSET);
		} else {
			io.outPortDword(iobase + RDW_ADDR_OFFSET, csrnr);
			return (io.inPortDword(iobase + RDW_RDATA_OFFSET) & 0xffff);
		}

	}

	/**
	 * Sets the contents of a Control and Status Register.
	 * 
	 * @param csrnr
	 */
	private final void setCSR(int csrnr, int value) {
		if (chip16Bits) {
			io.outPortWord(iobase + RW_ADDR_OFFSET, csrnr);
			io.outPortWord(iobase + RW_RDATA_OFFSET, value);
		} else {
			io.outPortWord(iobase + RDW_ADDR_OFFSET, csrnr);
			io.outPortWord(iobase + RDW_RDATA_OFFSET, value);
		}
	}

	/**
	 * Gets the contents of a Bus Configuration Register.
	 * 
	 * @param bcrnr
	 */
	private final int getBCR(int bcrnr) {
		if (chip16Bits) {
			io.outPortWord(iobase + RW_ADDR_OFFSET, bcrnr);
			return io.inPortWord(iobase + RW_BDATA_OFFSET);
		} else {
			io.outPortWord(iobase + RDW_ADDR_OFFSET, bcrnr);
			return (io.inPortWord(iobase + RDW_BDATA_OFFSET) & 0xffff);
		}
	}

	/**
	 * Sets the contents of a Bus Configuration Register.
	 * 
	 * @param bcrnr
	 * @param value
	 */
	private final void setBCR(int bcrnr, int value) {
		if (chip16Bits) {
			io.outPortWord(iobase + RW_ADDR_OFFSET, bcrnr);
			io.outPortWord(iobase + RW_BDATA_OFFSET, value);
		} else {
			io.outPortWord(iobase + RDW_ADDR_OFFSET, bcrnr);
			io.outPortWord(iobase + RDW_BDATA_OFFSET, value);
		}
	}

	private final boolean check() {
		io.outPortWord(iobase + RW_ADDR_OFFSET, 88);
		return (io.inPortWord(iobase + RW_ADDR_OFFSET) == 88);
	}

	private final boolean checkDW() {
		io.outPortWord(iobase + RDW_ADDR_OFFSET, 88);
		return ((io.inPortWord(iobase + RDW_ADDR_OFFSET) & 0xffff) == 88);
	}

	/**
	 * @see org.jnode.system.IRQHandler#handleInterrupt(int)
	 */
	public void handleInterrupt(int irq) {
		final int csr0 = getCSR(0);
		setCSR(0, csr0); // This will clear the interrupt bits
		log.debug("Lance IRQ, CSR0: 0x" + NumberUtils.hex(csr0));
	}
}

⌨️ 快捷键说明

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