idebus.java

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

JAVA
423
字号
/*
 * $Id: IDEBus.java,v 1.2 2003/11/29 17:20:24 gbin Exp $
 */
package org.jnode.driver.ide;

import javax.naming.NameNotFoundException;

import org.apache.log4j.Logger;
import org.jnode.driver.Bus;
import org.jnode.driver.Device;
import org.jnode.naming.InitialNaming;
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.Queue;
import org.jnode.util.QueueProcessor;
import org.jnode.util.QueueProcessorThread;
import org.jnode.util.TimeoutException;

/**
 * @author epr
 */
public class IDEBus extends Bus implements IDEConstants, IRQHandler, QueueProcessor {

	/** My logger */
	private final Logger log = Logger.getLogger(getClass());
	private IRQResource irqRes;
	/** IDE Taskfile io space */
	private IOResource ideIO;
	/** IDE High taskfile io space */
	private IOResource ideHighIO;
	/** The command queue for IDE commands */
	private final Queue commandQueue = new Queue();
	/** The command that is currently being processed */
	private IDECommand currentCommand;
	/** The worker thread for the command queue */
	private QueueProcessorThread queueProcessor;
	private final int taskfile;
	/** First port of the taskfile this command is intended for */
	protected final int startPort;
	/** The IRQ for this processor */
	private final int irq;
	
	/**
	 * Create a new instance
	 */
	protected IDEBus(Device parent, int taskfile) 
	throws IllegalArgumentException {
		super(parent);
		switch (taskfile) {
			case 0: {
				startPort = IDE0_START_PORT;
				irq = IDE0_IRQ; 
			} break;
			case 1: {
				startPort = IDE1_START_PORT;
				irq = IDE1_IRQ; 
			} break;
			default: {
				throw new IllegalArgumentException("Invalid taskfile " + taskfile);
			}
		}
		this.taskfile = taskfile;
	}
	
	/**
	 * Add the given command to the queue of commands to be executed.
	 * @param command
	 */
	public void execute(IDECommand command) {
		commandQueue.add(command);
	}
	
	/**
	 * Add the given command to the queue of commands to be executed and wait
	 * for the command to finish.
	 * @param command
	 */
	public void executeAndWait(IDECommand command)
	throws InterruptedException {
		execute(command);
		command.waitUntilFinished();
	}

	/**
	 * Add the given command to the queue of commands to be executed and wait
	 * for the command to finish.
	 * @param command
	 * @param timeout Maximum time to wait
	 */
	public void executeAndWait(IDECommand command, long timeout) 
	throws InterruptedException {
		execute(command);
		try {
			command.waitUntilFinished(timeout);
		} catch (TimeoutException ex) {
			// ignore
		}
	}

	/**
	 * Starts this processor.
	 * First the IRQ handler is registers, after that a queue processor
	 * is initialized and started.
	 */	
	public void start(ResourceOwner owner) 
	throws ResourceNotFreeException {
		// Claim the IOResources
		IOResource ideIO = null;
		IOResource ideHighIO = null;
		final ResourceManager rm;
		try {
			rm = (ResourceManager)InitialNaming.lookup(ResourceManager.NAME);
			ideIO = rm.claimIOResource(owner, startPort, IDE_NR_PORTS);
			ideHighIO = rm.claimIOResource(owner, startPort + HIGH_OFFSET, IDE_NR_HIGH_PORTS);
		} catch (NameNotFoundException ex) {
			throw new ResourceNotFreeException("Cannot find ResourceManager", ex);
		} catch (ResourceNotFreeException ex) {
			if (ideIO != null) {
				ideIO.release();
			}
			if (ideHighIO != null) {
				ideHighIO.release();
			}
			throw ex;
		}
		this.ideIO = ideIO;
		this.ideHighIO = ideHighIO;
		// Register the irq handler
		irqRes = rm.claimIRQ(owner, irq, this, false);
		// Reset the controller
		setControlReg(CTR_SRST);
		try {
			Thread.sleep(50);
		} catch (InterruptedException ex) {
			/* ignore */
		}
		// Set the controller to interrupts enabled
		setControlReg(0);
		// Create and start the queue processor
		queueProcessor = new QueueProcessorThread("IDE-" + taskfile, commandQueue, this);
		queueProcessor.start();
	}
	
	/**
	 * Stop this processor.
	 */
	public void stop() {
		queueProcessor.stopProcessor();
		irqRes.release();
		queueProcessor = null;
		ideIO.release();
		ideHighIO.release();
	}

	/**
	 * Handle the IDE interrupt.
	 */
	public void handleInterrupt(int irq) {
		final IDECommand cmd = currentCommand;
		//log.debug("IDE IRQ " + irq + " cmd=" + cmd);
		if (cmd != null) {
			cmd.handleIRQ(this);
			if (cmd.isFinished()) {
				currentCommand = null;
			}
		}
	}
	
	/**
	 * Probe for the existence of a given IDE device.
	 * @param master
	 */
	public IDEDriveDescriptor probe(boolean master) 
	throws InterruptedException {
		
		log.info("Probing IDE" + taskfile + "." + (master ? "0" : "1"));
		setControlReg(0); // Interrupts enabled

		// First try a normal IDE Identify command
		IDEIdCommand cmd = new IDEIdCommand(taskfile, master, false);
		executeAndWait(cmd, IDE_TIMEOUT);
		if (cmd.isFinished()) {
			final IDEDriveDescriptor result = cmd.getResult();
			if (result != null) {
				return result;
			} else {
				if (!cmd.isPacketResponse()) {
					// Not an ATAPI device.
					return null;
				}
				//log.debug("result==null");
			}
		} else {
			// Force a reset of any IRQ
			final int state = getStatusReg();
			// Timeout
			log.debug("Timeout state=" + NumberUtils.hex(state));
			return null;
		}
		
		// Clear any interrupts
		getStatusReg();
		
		// IDE Identify failed, do an ATAPI Identify
		cmd = new IDEIdCommand(taskfile, master, true);
		executeAndWait(cmd, IDE_TIMEOUT);
		// Force a reset of any IRQ
		getStatusReg();
		// Good result?
		if (cmd.isFinished()) {
			return cmd.getResult();
		}
		
		log.debug("Probe done, return null");
		// No device found
		return null;
	}
	
	/**
	 * Gets a word from the data register
	 */
	protected final int getDataReg() {
		return ideIO.inPortWord(startPort + RW16_DATA_OFFSET);
	}
	
	/**
	 * Writes a word to the data register
	 * @param dataWord
	 */
	protected final void setDataReg(int dataWord) {
		ideIO.outPortWord(startPort + RW16_DATA_OFFSET, dataWord);
	}
	
	/**
	 * Gets the contents of the error register
	 */
	protected final int getErrorReg() {
		return ideIO.inPortByte(startPort + R8_ERROR_OFFSET);
	}
	
	/**
	 * Sets the contents of the featureregister
	 */
	protected final void setFeatureReg(int features) {
		ideIO.outPortByte(startPort + W8_FEATURE_OFFSET, features);
	}
	
	/**
	 * Gets the contents of the sector count register
	 */
	protected final int getSectorCountReg() {
		return ideIO.inPortByte(startPort + RW8_SECTOR_COUNT_OFFSET);
	}
	
	/**
	 * Sets the sector count register
	 * @param sectorCount
	 */
	protected final void setSectorCountReg(int sectorCount) {
		ideIO.outPortByte(startPort + RW8_SECTOR_COUNT_OFFSET, sectorCount);
	}
	
	/**
	 * Gets the contents of the sector register
	 */
	protected final int getSectorReg() {
		return ideIO.inPortByte(startPort + RW8_SECTOR_OFFSET);
	}
	
	/**
	 * Gets the contents of the LBA low register
	 */
	protected final int getLbaLowReg() {
		return ideIO.inPortByte(startPort + RW8_LBA_LOW_OFFSET);
	}
	
	/**
	 * Gets the contents of the LBA mid register
	 */
	protected final int getLbaMidReg() {
		return ideIO.inPortByte(startPort + RW8_LBA_MID_OFFSET);
	}
	
	/**
	 * Gets the contents of the LBA high register
	 */
	protected final int getLbaHighReg() {
		return ideIO.inPortByte(startPort + RW8_LBA_HIGH_OFFSET);
	}
	
	/**
	 * Sets the contents of the LBA low register
	 */
	protected final void setLbaLowReg(int value) {
		ideIO.outPortByte(startPort + RW8_LBA_LOW_OFFSET, value);
	}
	
	/**
	 * Sets the contents of the LBA mid register
	 */
	protected final void setLbaMidReg(int value) {
		ideIO.outPortByte(startPort + RW8_LBA_MID_OFFSET, value);
	}
	
	/**
	 * Sets the contents of the LBA high register
	 */
	protected final void setLbaHighReg(int value) {
		ideIO.outPortByte(startPort + RW8_LBA_HIGH_OFFSET, value);
	}
	
	/**
	 * Sets the sector register
	 * @param sector
	 */
	protected final void setSectorReg(int sector) {
		ideIO.outPortByte(startPort + RW8_SECTOR_OFFSET, sector);
	}
	
	/**
	 * Gets the combined cylinder value out the the cylinder LSB and MSB registers.
	 */
	protected final int getCylinderRegs() {
		final int lsb = ideIO.inPortByte(startPort + RW8_CYLINDER_LSB_OFFSET);
		final int msb = ideIO.inPortByte(startPort + RW8_CYLINDER_MSB_OFFSET);
		return ((msb & 0xFF) << 8) | (lsb & 0xFF); 
	}
	
	/**
	 * Sets the cylinder registers value (both LSB and MSB)
	 */
	protected final void setCylinderRegs(int cylinder) {
		final int lsb = cylinder & 0xFF;
		final int msb = (cylinder >> 8) & 0xFF; 
		ideIO.outPortByte(startPort + RW8_CYLINDER_LSB_OFFSET, lsb);
		ideIO.outPortByte(startPort + RW8_CYLINDER_MSB_OFFSET, msb);
	}
	
	/**
	 * Gets the contents of the select register
	 */
	protected final int getSelectReg() {
		return ideIO.inPortByte(startPort + RW8_SELECT_OFFSET);
	}
	
	/**
	 * Sets the select register
	 * @param select
	 */
	protected final void setSelectReg(int select) {
		ideIO.outPortByte(startPort + RW8_SELECT_OFFSET, select);
	}

	/**
	 * Gets the status of the IDE controller. Any pending IRQ is reset.
	 */
	protected final int getStatusReg() {
		return ideIO.inPortByte(startPort + R8_STATUS_OFFSET);
	}

	/**
	 * Gets the alternative status of the IDE controller. 
	 * Any pending IRQ is NOT reset.
	 */
	protected final int getAltStatusReg() {
		return ideHighIO.inPortByte(startPort + R8_ALTSTATUS_OFFSET);
	}
	
	/**
	 * Sets the command register. This also activates the IDE controller
	 * so always set other registers first.
	 * @param command
	 */
	protected final void setCommandReg(int command) {
		ideIO.outPortByte(startPort + W8_COMMAND_OFFSET, command);
	}

	/**
	 * Sets the control register. 
	 * @param control The new value for the control register
	 */
	protected final void setControlReg(int control) {
		ideHighIO.outPortByte(startPort + W8_CONTROL_OFFSET, control);
	}

	/**
	 * Block the current thread until the controller is not busy anymore.
	 */
	protected final void waitUntilNotBusy() {
		int state = ideHighIO.inPortByte(startPort + R8_ALTSTATUS_OFFSET);
		while ((state & ST_BUSY) != 0) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException ex) {
                // nothing special to do
			}
			state = ideHighIO.inPortByte(startPort + R8_ALTSTATUS_OFFSET);
		}
	}

	/**
	 * @see org.jnode.util.QueueProcessor#process(java.lang.Object)
	 */
	public void process(Object object) throws Exception {
		final IDECommand cmd = (IDECommand)object;
				
		// Wait until the controller is not busy anymore
		if ((getAltStatusReg() & ST_BUSY) == ST_BUSY) {
			log.debug("<wait>");
			waitUntilNotBusy();
			log.debug("</wait>");
		}
				
		currentCommand = cmd;
		cmd.setup(IDEBus.this);
	}
}

⌨️ 快捷键说明

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