ps2bus.java

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

JAVA
311
字号
/*
 * Written by Michael Klaus <qades@users.fourceforge.net>
 * 
 * This work is partially based on work by Ewout Prangsma <epr@users.sourceforge.net>
 * 
 * other parts are derived from the Linux source code linux/drivers/char/pc_keyb.c by Geert
 * Uytterhoeven Martin Mares Johan Myreen <jem@iki.fi> C. Scott Ananian
 * <cananian@alumni.princeton.edu>
 * 
 * $Id: PS2Bus.java,v 1.5 2003/12/21 07:59:16 epr Exp $
 */
package org.jnode.driver.ps2;

import java.io.IOException;

import javax.naming.NameNotFoundException;

import org.apache.log4j.Logger;
import org.jnode.driver.Bus;
import org.jnode.driver.DeviceException;
import org.jnode.driver.DriverException;
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.TimeoutException;

/**
 * Provides common functionality shared by the drivers (read/write data/status)
 * 
 * @author qades
 */
public class PS2Bus extends Bus implements IRQHandler, PS2Constants {

	/** My logger */
	private final Logger log = Logger.getLogger(getClass());
	private IOResource ioResData;
	private IOResource ioResCtrl;
	private int activeCount = 0;
	private final PS2ByteChannel kbChannel = new PS2ByteChannel();
	private final PS2ByteChannel mouseChannel = new PS2ByteChannel();
	/** If true, the interrupt handler will read and process the input queue */
	private boolean irqReadQueue = true;

	/**
	 * Create a PS2 object.
	 */
	PS2Bus(Bus parent) {
		super(parent);
	}

	/**
	 * All necessary resources are claimed in this method.
	 * 
	 * @param owner the
	 *            driver for which the resources are to be claimed
	 * @return the IRQResource for the driver in question
	 */
	final synchronized IRQResource claimResources(ResourceOwner owner, int irq) throws DriverException {
		try {
			final ResourceManager rm;
			try {
				rm = (ResourceManager) InitialNaming.lookup(ResourceManager.NAME);
			} catch (NameNotFoundException ex) {
				throw new DriverException("Cannot find ResourceManager: ", ex);
			}
			if (ioResData == null) {
				ioResData = rm.claimIOResource(owner, PS2_DATA_PORT, 1);
				ioResCtrl = rm.claimIOResource(owner, PS2_CTRL_PORT, 1);
			}
			final IRQResource irqRes = rm.claimIRQ(owner, irq, this, true);
			if (activeCount == 0) {
				processQueues();
			}
			activeCount++;
			return irqRes;
		} catch (ResourceNotFreeException ex) {
			throw new DriverException("Cannot claim necessairy resources: ", ex);
		}
	}

	/**
	 * Release all resource held by this bus, only if all devices that depend on this bus have been
	 * stopped.
	 */
	final synchronized void releaseResources() {
		activeCount--;
		if (activeCount == 0) {
			ioResData.release();
			ioResCtrl.release();
			ioResData = null;
			ioResCtrl = null;
		}
	}

	/**
	 * Handles a PS/2 interrupt
	 * 
	 * @see org.jnode.system.IRQHandler#handleInterrupt(int)
	 */
	public synchronized final void handleInterrupt(int irq) {
		if (irqReadQueue) {
			processQueues();
		}
	}

	/**
	 * Read the queue until it is empty and process the read data.
	 */
	final void processQueues() {
		int status;
		//System.out.print('<');
		while (((status = readStatus()) & AUX_STAT_OBF) != 0) {
			final int data = readData();

			// determine which driver shall handle the scancode
			final PS2ByteChannel channel;
			if ((status & STAT_MOUSE_OBF) != 0) {
				channel = mouseChannel;
			} else {
				channel = kbChannel;
			}
			// if this driver is not registered, merely exit
			if (channel == null) {
				log.debug("Unhandled scancode 0x" + Integer.toHexString(data) + " status=0x" + Integer.toHexString(status));
			} else {
				// let the driver handle the scancode
				channel.handleScancode(data);
			}
		}
		//System.out.print('>');
	}

	/**
	 * Get the status of the PS/2 port.
	 * 
	 * @return the status byte
	 */
	final int readStatus() {
		return ioResCtrl.inPortByte(PS2_STAT_PORT) & 0xff;
	}

	/**
	 * Write a byte to the control port
	 * 
	 * @param b
	 */
	private void writeController(int b) throws DeviceException {
		waitWrite();
		ioResCtrl.outPortByte(PS2_CTRL_PORT, b);
	}

	/**
	 * Write a byte to the data port
	 * 
	 * @param b
	 */
	private final void writeData(int b) throws DeviceException {
		waitWrite();
		ioResData.outPortByte(PS2_DATA_PORT, b);
	}

	/**
	 * Wait for a non-ready inputbuffer.
	 */
	private final void waitWrite() throws DeviceException {
		int count = 0;
		while (count < 1000) {
			if ((readStatus() & STAT_IBF) == 0) {
				return;
			} else {
				count++;
				Thread.yield();
			}
		}
		throw new DeviceException("InputBuffer full");
	}

	/**
	 * Read a byte from the data port
	 * 
	 * @return
	 */
	private final int readData() {
		return ioResData.inPortByte(PS2_DATA_PORT) & 0xff;
	}

	/**
	 * Gets the mode register
	 * 
	 * @return int
	 */
	final int getMode() throws DeviceException {
		writeController(CCMD_READ_MODE);
		return readData();
	}

	/**
	 * Sets the mode register
	 */
	final void setMode(int mode) throws DeviceException {
		writeController(CCMD_WRITE_MODE);
		writeData(mode);
	}

	/**
	 * Test for the presence of a connected mouse device
	 * 
	 * @return true if a mouse is present, false if not
	 */
	final boolean testMouse() throws DeviceException {
		irqReadQueue = false;
		try {
			writeController(CCMD_TEST_MOUSE);
			final int status = readStatus();
			final int rc = readData();
			log.debug("testMouse rc=0x" + NumberUtils.hex(rc, 2) + ", status 0x" + NumberUtils.hex(status, 2));
			return (rc != 0xFF);
		} finally {
			irqReadQueue = true;
			processQueues();
		}
	}

	/**
	 * Activate/Deactivate the mouse
	 */
	final void setMouseEnabled(boolean enable) throws DeviceException {
		writeController(enable ? CCMD_MOUSE_ENABLE : CCMD_MOUSE_DISABLE);
	}

	/**
	 * Activate/Deactivate the keyboard
	 */
	final void setKeyboardEnabled(boolean enable) throws DeviceException {
		writeController(enable ? CCMD_KB_ENABLE : CCMD_KB_DISABLE);
	}

	/**
	 * Write a command to the mouse
	 * 
	 * @param cmd
	 * @return
	 */
	final boolean writeMouseCommand(int cmd) throws DeviceException {
		// First clear the mouse channel, otherwise we might read
		// old data back
		mouseChannel.clear();
		// Transmit the command
		writeController(CCMD_WRITE_MOUSE);
		writeData(cmd);

		int data;
		try {
			data = mouseChannel.read(COMMAND_TIMEOUT);
		} catch (IOException ex) {
			log.debug("IOException in readMouse", ex);
			return false;
		} catch (TimeoutException ex) {
			log.debug("Timeout in readMouse");
			return false;
		} catch (InterruptedException ex) {
			log.debug("Interrupted in readMouse");
			return false;
		}

		if (data == REPLY_ACK) {
			return true; // command acknowledged
		} else if (data == REPLY_RESEND) {
			log.debug("Mouse replied with RESEND");
		} else {
			log.debug("Invalid reply 0x" + Integer.toHexString(data));
		}

		return false; // on error
	}

	/**
	 * Write a series of commands to the mouse
	 * 
	 * @param cmds
	 * @return
	 */
	final boolean writeMouseCommands(int[] cmds) throws DeviceException {
		boolean ok = true;
		for (int i = 0; i < cmds.length; i++) {
			ok &= writeMouseCommand(cmds[i]);
		}
		return ok;
	}

	/**
	 * @return
	 */
	final PS2ByteChannel getKbChannel() {
		return this.kbChannel;
	}

	/**
	 * @return
	 */
	final PS2ByteChannel getMouseChannel() {
		return this.mouseChannel;
	}

}

⌨️ 快捷键说明

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