/*
JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine
Release Version 2.4
A project from the Physics Dept, The University of Oxford
Copyright (C) 2007-2010 The University of Oxford
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation.
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Details (including contact information) can be found at:
jpc.sourceforge.net
or the developer website
sourceforge.net/projects/jpc/
Conceived and Developed by:
Rhys Newman, Ian Preston, Chris Dennis
End of licence header
*/
package org.jpc.emulator.peripheral;
import java.io.*;
import java.util.logging.*;
import org.jpc.emulator.motherboard.*;
import org.jpc.emulator.memory.*;
import org.jpc.emulator.processor.Processor;
import org.jpc.emulator.*;
import org.jpc.j2se.*;
/**
*
* @author Chris Dennis
*/
public class Keyboard extends AbstractHardwareComponent implements IODevice
{
private static final Logger LOGGING = Logger.getLogger(Keyboard.class.getName());
private static final boolean LOG_ACCESS = false;
/* Keyboard Controller Commands */
private static final byte KBD_CCMD_READ_MODE = (byte)0x20; /* Read mode bits */
private static final byte KBD_CCMD_WRITE_MODE = (byte)0x60; /* Write mode bits */
private static final byte KBD_CCMD_GET_VERSION = (byte)0xA1; /* Get controller version */
private static final byte KBD_CCMD_MOUSE_DISABLE = (byte)0xA7; /* Disable mouse interface */
private static final byte KBD_CCMD_MOUSE_ENABLE = (byte)0xA8; /* Enable mouse interface */
private static final byte KBD_CCMD_TEST_MOUSE = (byte)0xA9; /* Mouse interface test */
private static final byte KBD_CCMD_SELF_TEST = (byte)0xAA; /* Controller self test */
private static final byte KBD_CCMD_KBD_TEST = (byte)0xAB; /* Keyboard interface test */
private static final byte KBD_CCMD_KBD_DISABLE = (byte)0xAD; /* Keyboard interface disable */
private static final byte KBD_CCMD_KBD_ENABLE = (byte)0xAE; /* Keyboard interface enable */
private static final byte KBD_CCMD_READ_INPORT = (byte)0xC0; /* read input port */
private static final byte KBD_CCMD_READ_OUTPORT = (byte)0xD0; /* read output port */
private static final byte KBD_CCMD_WRITE_OUTPORT = (byte)0xD1; /* write output port */
private static final byte KBD_CCMD_WRITE_OBUF = (byte)0xD2;
private static final byte KBD_CCMD_WRITE_AUX_OBUF = (byte)0xD3; /* Write to output buffer as if initiated by the auxiliary device */
private static final byte KBD_CCMD_WRITE_MOUSE = (byte)0xD4; /* Write the following byte to the mouse */
private static final byte KBD_CCMD_DISABLE_A20 = (byte)0xDD; /* HP vectra only ? */
private static final byte KBD_CCMD_ENABLE_A20 = (byte)0xDF; /* HP vectra only ? */
private static final byte KBD_CCMD_RESET = (byte)0xFE;
/* Keyboard Commands */
private static final byte KBD_CMD_SET_LEDS = (byte)0xED;; /* Set keyboard leds */
private static final byte KBD_CMD_ECHO = (byte)0xEE;
private static final byte KBD_CMD_GET_ID = (byte)0xF2; /* get keyboard ID */
private static final byte KBD_CMD_SET_RATE = (byte)0xF3; /* Set typematic rate */
private static final byte KBD_CMD_ENABLE = (byte)0xF4; /* Enable scanning */
private static final byte KBD_CMD_RESET_DISABLE = (byte)0xF5; /* reset and disable scanning */
private static final byte KBD_CMD_RESET_ENABLE = (byte)0xF6; /* reset and enable scanning */
private static final byte KBD_CMD_RESET = (byte)0xFF; /* Reset */
/* Keyboard Replies */
private static final byte KBD_REPLY_POR = (byte)0xAA; /* Power on reset */
private static final byte KBD_REPLY_ACK = (byte)0xFA; /* Command ACK */
private static final byte KBD_REPLY_RESEND = (byte)0xFE; /* Command NACK, send the cmd again */
/* Status Register Bits */
private static final byte KBD_STAT_OBF = (byte)0x01; /* Keyboard output buffer full */
private static final byte KBD_STAT_IBF = (byte)0x02; /* Keyboard input buffer full */
private static final byte KBD_STAT_SELFTEST = (byte)0x04; /* Self test successful */
private static final byte KBD_STAT_CMD = (byte)0x08; /* Last write was a command write (0=data) */
private static final byte KBD_STAT_UNLOCKED = (byte)0x10; /* Zero if keyboard locked */
private static final byte KBD_STAT_MOUSE_OBF = (byte)0x20; /* Mouse output buffer full */
private static final byte KBD_STAT_GTO = (byte)0x40; /* General receive/xmit timeout */
private static final byte KBD_STAT_PERR = (byte)0x80; /* Parity error */
/* Controller Mode Register Bits */
private static final int KBD_MODE_KBD_INT = 0x01; /* Keyboard data generate IRQ1 */
private static final int KBD_MODE_MOUSE_INT = 0x02; /* Mouse data generate IRQ12 */
private static final int KBD_MODE_SYS = 0x04; /* The system flag (?) */
private static final int KBD_MODE_NO_KEYLOCK = 0x08; /* The keylock doesn't affect the keyboard if set */
private static final int KBD_MODE_DISABLE_KBD = 0x10; /* Disable keyboard interface */
private static final int KBD_MODE_DISABLE_MOUSE = 0x20; /* Disable mouse interface */
private static final int KBD_MODE_KCC = 0x40; /* Scan code conversion to PC format */
private static final int KBD_MODE_RFU = 0x80;
/* Mouse Commands */
private static final byte AUX_SET_SCALE11 = (byte)0xE6; /* Set 1:1 scaling */
private static final byte AUX_SET_SCALE21 = (byte)0xE7; /* Set 2:1 scaling */
private static final byte AUX_SET_RES = (byte)0xE8; /* Set resolution */
private static final byte AUX_GET_SCALE = (byte)0xE9; /* Get scaling factor */
private static final byte AUX_SET_STREAM = (byte)0xEA; /* Set stream mode */
private static final byte AUX_POLL = (byte)0xEB; /* Poll */
private static final byte AUX_RESET_WRAP = (byte)0xEC; /* Reset wrap mode */
private static final byte AUX_SET_WRAP = (byte)0xEE; /* Set wrap mode */
private static final byte AUX_SET_REMOTE = (byte)0xF0; /* Set remote mode */
private static final byte AUX_GET_TYPE = (byte)0xF2; /* Get type */
private static final byte AUX_SET_SAMPLE = (byte)0xF3; /* Set sample rate */
private static final byte AUX_ENABLE_DEV = (byte)0xF4; /* Enable aux device */
private static final byte AUX_DISABLE_DEV = (byte)0xF5; /* Disable aux device */
private static final byte AUX_SET_DEFAULT = (byte)0xF6;
private static final byte AUX_RESET = (byte)0xFF; /* Reset aux device */
private static final byte AUX_ACK = (byte)0xFA; /* Command byte ACK. */
private static final byte MOUSE_STATUS_REMOTE = (byte)0x40;
private static final byte MOUSE_STATUS_ENABLED = (byte)0x20;
private static final byte MOUSE_STATUS_SCALE21 = (byte)0x10;
private static final int MOUSE_TYPE = 0; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
private static final int KBD_QUEUE_SIZE = 256;
//Instance Variables
private final KeyboardQueue queue;
private byte commandWrite;
private byte status;
private int mode;
/* keyboard state */
private int keyboardWriteCommand;
private boolean keyboardScanEnabled;
/* mouse state */ //Split this off?
private int mouseWriteCommand;
private int mouseStatus;
private int mouseResolution;
private int mouseSampleRate;
private boolean mouseWrap;
private int mouseDetectState;
private int mouseDx;
private int mouseDy;
private int mouseDz;
private int mouseButtons;
private boolean ioportRegistered;
private InterruptController irqDevice;
private Processor cpu;
private PhysicalAddressSpace physicalAddressSpace;
private LinearAddressSpace linearAddressSpace;
public Keyboard()
{
ioportRegistered = false;
queue = new KeyboardQueue();
physicalAddressSpace = null;
linearAddressSpace = null;
cpu = null;
reset();
}
public void saveState(DataOutput output) throws IOException
{
output.writeByte(commandWrite);
output.writeByte(status);
output.writeByte(mode);
output.writeInt(keyboardWriteCommand);
output.writeBoolean(keyboardScanEnabled);
output.writeInt(mouseWriteCommand);
output.writeInt(mouseStatus);
output.writeInt(mouseResolution);
output.writeInt(mouseSampleRate);
output.writeBoolean(mouseWrap);
output.writeInt(mouseDetectState);
output.writeInt(mouseDx);
output.writeInt(mouseDy);
output.writeInt(mouseDz);
output.writeInt(mouseButtons);
//dump keyboard queue
queue.saveState(output);
}
public void loadState(DataInput input) throws IOException
{
ioportRegistered = false;
commandWrite = input.readByte();
status = input.readByte();
mode = input.readByte();
keyboardWriteCommand = input.readInt();
keyboardScanEnabled = input.readBoolean();
mouseWriteCommand = input.readInt();
mouseStatus = input.readInt();
mouseResolution = input.readInt();
mouseSampleRate = input.readInt();
mouseWrap = input.readBoolean();
mouseDetectState = input.readInt();
mouseDx = input.readInt();
mouseDy = input.readInt();
mouseDz = input.readInt();
mouseButtons = input.readInt();
//load keyboard queue
queue.loadState(input);
}
//IODevice Methods
public int[] ioPortsRequested()
{
return new int[]{0x60, 0x64};
}
public int ioPortRead8(int address)
{
switch (address) {
case 0x60:
int res = readData();
if (LOG_ACCESS)
System.out.printf("Keyboard read address=%02x, result=%02x status=%02x\n", address, res, status);
return res;
case 0x64:
// if (LOG_ACCESS)
// System.out.printf("Keyboard read address=%02x, result=%02x\n", address, status);
return 0xff & status;
default:
return 0xffffffff;
}
}
public int ioPortRead16(int address)
{
return (0xff & ioPortRead8(address)) | (0xff00 & ioPortRead8(address + 1));
}
public int ioPortRead32(int address)
{
return 0xffffffff;
}
public void ioPortWrite8(int address, int data)
{
switch (address) {
case 0x60:
writeData((byte)data);
if (LOG_ACCESS)
System.out.printf("Keyboard write address=%02x, data=%02x status=%02x\n", address, data, status);
break;
case 0x64:
writeCommand((byte)data);
if (LOG_ACCESS)
System.out.printf("Keyboard write address=%02x, data=%02x status=%02x\n", address, data, status);
break;
default:
}
}
public void ioPortWrite16(int address, int data)
{
ioPortWrite8(address, data);
ioPortWrite8(address + 1, data >> 8);
}
public void ioPortWrite32(int address, int data)
{
ioPortWrite16(address, data);
ioPortWrite16(address + 2, data >> 16);
}
public void reset()
{
irqDevice = null;
cpu = null;
physicalAddressSpace = null;
linearAddressSpace = null;
ioportRegistered = false;
keyboardWriteCommand = -1;
mouseWriteCommand = -1;
mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
status = (byte)(KBD_STAT_CMD | KBD_STAT_UNLOCKED);
queue.reset();
commandWrite = 0;
keyboardWriteCommand = 0;
keyboardScanEnabled = false;
mouseWriteCommand = 0;
mouseStatus = 0;
mouseResolution = 0;
mouseSampleRate = 0;
mouseWrap = false;
mouseDetectState = 0;
mouseDx = 0;
mouseDy = 0;
mouseDz = 0;
mouseButtons = 0;
}
private void setGateA20State(boolean value)
{
physicalAddressSpace.setGateA20State(value);
}
private byte readData()
{
byte val = queue.readData();
updateIRQ();
return val;
}
private void writeData(byte data)
{
if (LOG_ACCESS)
System.out.printf("Write Data: commandWrite=%08x ", commandWrite);
switch(commandWrite) {
case 0:
writeKeyboard(data);
break;
case KBD_CCMD_WRITE_MODE:
mode = 0xff & data;
updateIRQ();
break;
case KBD_CCMD_WRITE_OBUF:
queue.writeData(data, (byte)0);
break;
case KBD_CCMD_WRITE_AUX_OBUF:
queue.writeData(data, (byte)1);
break;
case KBD_CCMD_WRITE_OUTPORT:
setGateA20State((data & 0x2) != 0);
if (0x1 != (data & 0x1))
cpu.reset();
break;
case KBD_CCMD_WRITE_MOUSE:
writeMouse(data);
break;
default:
break;
}
commandWrite = (byte)0x00;
status &= ~KBD_STAT_CMD;
}
private void writeCommand(byte data)
{
switch(data) {
case KBD_CCMD_READ_MODE:
queue.writeData((byte)mode, (byte)0);
break;
case KBD_CCMD_WRITE_MODE:
case KBD_CCMD_WRITE_OBUF:
case KBD_CCMD_WRITE_AUX_OBUF:
case KBD_CCMD_WRITE_MOUSE:
case KBD_CCMD_WRITE_OUTPORT:
commandWrite = data;
break;
case KBD_CCMD_MOUSE_DISABLE:
mode |= KBD_MODE_DISABLE_MOUSE;
break;
case KBD_CCMD_MOUSE_ENABLE:
mode &= ~KBD_MODE_DISABLE_MOUSE;
break;
case KBD_CCMD_TEST_MOUSE:
queue.writeData((byte)0x00, (byte)0);
break;
case KBD_CCMD_SELF_TEST:
status = (byte)((status & ~KBD_STAT_OBF) | KBD_STAT_SELFTEST);
queue.writeData((byte)0x55, (byte)0);
break;
case KBD_CCMD_KBD_TEST:
queue.writeData((byte)0x00, (byte)0);
break;
case KBD_CCMD_KBD_DISABLE:
mode |= KBD_MODE_DISABLE_KBD;
updateIRQ();
break;
case KBD_CCMD_KBD_ENABLE:
mode &= ~KBD_MODE_DISABLE_KBD;
updateIRQ();
break;
case KBD_CCMD_READ_INPORT:
queue.writeData((byte)0x00, (byte)0);
break;
case KBD_CCMD_READ_OUTPORT:
/* XXX: check that */
data = (byte)(0x01 | (physicalAddressSpace.getGateA20State() ? 0x02 : 0x00));
if (0 != (status & KBD_STAT_OBF))
data |= 0x10;
if (0 != (status & KBD_STAT_MOUSE_OBF))
data |= 0x20;
queue.writeData(data, (byte)0);
break;
case KBD_CCMD_ENABLE_A20:
setGateA20State(true);
break;
case KBD_CCMD_DISABLE_A20:
setGateA20State(false);
break;
case KBD_CCMD_RESET:
cpu.reset();
break;
case (byte)0xff:
/* ignore that - I don't know what is its use */
break;
default:
LOGGING.log(Level.INFO, "unsupported command 0x{0}", Integer.toHexString(0xff & data));
break;
}
}
private void writeKeyboard(byte data)
{
switch(keyboardWriteCommand) {
default:
case -1:
switch(data) {
case 0x00:
queue.writeData(KBD_REPLY_ACK, (byte)0);
break;
case 0x05:
queue.writeData(KBD_REPLY_RESEND, (byte)0);
break;
case KBD_CMD_GET_ID:
synchronized (queue) {
queue.writeData(KBD_REPLY_ACK, (byte) 0);
queue.writeData((byte) 0xab, (byte) 0);
queue.writeData((byte) 0x83, (byte) 0);
}
break;
case KBD_CMD_ECHO:
queue.writeData(KBD_CMD_ECHO, (byte)0);
break;
case KBD_CMD_ENABLE:
keyboardScanEnabled = true;
queue.writeData(KBD_REPLY_ACK, (byte)0);
break;
case KBD_CMD_SET_LEDS:
case KBD_CMD_SET_RATE:
keyboardWriteCommand = data;
queue.writeData(KBD_REPLY_ACK, (byte)0);
break;
case KBD_CMD_RESET_DISABLE:
resetKeyboard();
keyboardScanEnabled = false;
queue.writeData(KBD_REPLY_ACK, (byte)0);
break;
case KBD_CMD_RESET_ENABLE:
resetKeyboard();
keyboardScanEnabled = true;
queue.writeData(KBD_REPLY_ACK, (byte)0);
break;
case KBD_CMD_RESET:
resetKeyboard();
synchronized (queue) {
queue.writeData(KBD_REPLY_ACK, (byte) 0);
queue.writeData(KBD_REPLY_POR, (byte) 0);
}
break;
default:
queue.writeData(KBD_REPLY_ACK, (byte)0);
break;
}
break;
case KBD_CMD_SET_LEDS:
queue.writeData(KBD_REPLY_ACK, (byte)0);
keyboardWriteCommand = -1;
break;
case KBD_CMD_SET_RATE:
queue.writeData(KBD_REPLY_ACK, (byte)0);
keyboardWriteCommand = -1;
break;
}
}
private void writeMouse(byte data)
{
switch(mouseWriteCommand) {
default:
case -1:
/* mouse command */
if (mouseWrap) {
if (data == AUX_RESET_WRAP) {
mouseWrap = false;
queue.writeData(AUX_ACK, (byte)1);
return;
} else if (data != AUX_RESET) {
queue.writeData(data, (byte)1);
return;
}
}
switch(data) {
case AUX_SET_SCALE11:
mouseStatus &= ~MOUSE_STATUS_SCALE21;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_SET_SCALE21:
mouseStatus |= MOUSE_STATUS_SCALE21;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_SET_STREAM:
mouseStatus &= ~MOUSE_STATUS_REMOTE;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_SET_WRAP:
mouseWrap = true;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_SET_REMOTE:
mouseStatus |= MOUSE_STATUS_REMOTE;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_GET_TYPE:
synchronized (queue) {
queue.writeData(AUX_ACK, (byte) 1);
queue.writeData((byte) MOUSE_TYPE, (byte) 1);
}
break;
case AUX_SET_RES:
case AUX_SET_SAMPLE:
mouseWriteCommand = data;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_GET_SCALE:
synchronized (queue) {
queue.writeData(AUX_ACK, (byte) 1);
queue.writeData((byte) mouseStatus, (byte) 1);
queue.writeData((byte) mouseResolution, (byte) 1);
queue.writeData((byte) mouseSampleRate, (byte) 1);
}
break;
case AUX_POLL:
synchronized (queue) {
queue.writeData(AUX_ACK, (byte) 1);
mouseSendPacket();
}
break;
case AUX_ENABLE_DEV:
mouseStatus |= MOUSE_STATUS_ENABLED;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_DISABLE_DEV:
mouseStatus &= ~MOUSE_STATUS_ENABLED;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_SET_DEFAULT:
mouseSampleRate = 100;
mouseResolution = 2;
mouseStatus = 0;
queue.writeData(AUX_ACK, (byte)1);
break;
case AUX_RESET:
mouseSampleRate = 100;
mouseResolution = 2;
mouseStatus = 0;
synchronized (queue) {
queue.writeData(AUX_ACK, (byte) 1);
queue.writeData((byte) 0xaa, (byte) 1);
queue.writeData((byte) MOUSE_TYPE, (byte) 1);
}
break;
default:
break;
}
break;
case AUX_SET_SAMPLE:
mouseSampleRate = data;
queue.writeData(AUX_ACK, (byte)1);
mouseWriteCommand = -1;
break;
case AUX_SET_RES:
mouseResolution = data;
queue.writeData(AUX_ACK, (byte)1);
mouseWriteCommand = -1;
break;
}
}
private void resetKeyboard()
{
keyboardScanEnabled = true;
}
private void mouseSendPacket()
{
int dx1 = mouseDx;
int dy1 = mouseDy;
int dz1 = mouseDz;
/* XXX: increase range to 8 bits ? */
if (dx1 > 127)
dx1 = 127;
else if (dx1 < -127)
dx1 = -127;
if (dy1 > 127)
dy1 = 127;
else if (dy1 < -127)
dy1 = -127;
int x = 0;
int y = 0;
if (dx1 < 0)
x = 1;
if (dy1 < 0)
y = 1;
byte b = (byte)(0x08 | (x << 4) | (y << 5) | (mouseButtons & 0x07));
synchronized (queue) {
queue.writeData(b, (byte) 1);
queue.writeData((byte) dx1, (byte) 1);
queue.writeData((byte) dy1, (byte) 1);
/* extra byte for IMPS/2 or IMEX */
switch (MOUSE_TYPE) {
default:
break;
case 3:
if (dz1 > 127)
dz1 = 127;
else if (dz1 < -127)
dz1 = -127;
queue.writeData((byte) dz1, (byte) 1);
break;
case 4:
if (dz1 > 7)
dz1 = 7;
else if (dz1 < -7)
dz1 = -7;
b = (byte) ((dz1 & 0x0f) | ((mouseButtons & 0x18) << 1));
queue.writeData(b, (byte) 1);
break;
}
}
/* update deltas */
mouseDx -= dx1;
mouseDy -= dy1;
mouseDz -= dz1;
}
private void updateIRQ()
{
int irq1Level = 0;
int irq12Level = 0;
status = (byte)(status & ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
synchronized (queue) {
if (queue.length != 0) {
status = (byte) (status | KBD_STAT_OBF);
if (0 != queue.getAux()) {
status = (byte) (status | KBD_STAT_MOUSE_OBF);
if (0 != (mode & KBD_MODE_MOUSE_INT))
if (!Option.useBochs.isSet())
irq12Level = 1;
} else
if ((0 != (mode & KBD_MODE_KBD_INT)) &&
(0 == (mode & KBD_MODE_DISABLE_KBD)))
irq1Level = 1;
}
}
irqDevice.setIRQ(1, irq1Level);
irqDevice.setIRQ(12, irq12Level);
}
private class KeyboardQueue implements Hibernatable
{
private byte[] aux;
private byte[] data;
private int readPosition;
private int writePosition;
private int length;
public KeyboardQueue()
{
aux = new byte[KBD_QUEUE_SIZE];
data = new byte[KBD_QUEUE_SIZE];
readPosition = 0;
writePosition = 0;
length = 0;
}
public void saveState(DataOutput output) throws IOException
{
output.writeInt(aux.length);
output.write(aux);
output.writeInt(data.length);
output.write(data);
output.writeInt(readPosition);
output.writeInt(writePosition);
output.writeInt(length);
}
public void loadState(DataInput input) throws IOException
{
int len = input.readInt();
aux = new byte[len];
input.readFully(aux,0,len);
len = input.readInt();
data = new byte[len];
input.readFully(data,0,len);
readPosition = input.readInt();
writePosition = input.readInt();
length = input.readInt();
}
public void reset()
{
synchronized (this) {
readPosition = 0;
writePosition = 0;
length = 0;
}
}
public byte getAux()
{
synchronized (this) {
return aux[readPosition];
}
}
public byte readData()
{
synchronized (this) {
if (length == 0) {
/* NOTE: if no data left, we return the last keyboard one (needed for EMM386) */
/* XXX: need a timer to do things correctly */
int index = readPosition - 1;
if (index < 0)
index = KBD_QUEUE_SIZE - 1;
return data[index];
}
byte auxValue = this.aux[readPosition];
byte dataValue = this.data[readPosition];
if ((++readPosition) == KBD_QUEUE_SIZE)
readPosition = 0;
length--;
/* reading deasserts IRQ */
if (0 != auxValue)
Keyboard.this.irqDevice.setIRQ(12, 0);
else
Keyboard.this.irqDevice.setIRQ(1, 0);
return dataValue;
}
}
public void writeData(byte data, byte aux)
{
synchronized (this) {
if (length >= KBD_QUEUE_SIZE)
{
LOGGING.log(Level.INFO, "Keyboard buffer full, ignoring keycode: "+data);
return;
}
this.aux[writePosition] = aux;
this.data[writePosition] = data;
if ((++writePosition) == KBD_QUEUE_SIZE)
writePosition = 0;
length++;
}
Keyboard.this.updateIRQ();
}
}
public void keyPressed(byte scancode)
{
switch (scancode)
{
case (byte)0xff:
synchronized (queue) {
putKeyboardEvent((byte) 0xe1);
putKeyboardEvent((byte) 0x1d);
putKeyboardEvent((byte) 0x45);
putKeyboardEvent((byte) 0xe1);
putKeyboardEvent((byte) 0x9d);
putKeyboardEvent((byte) 0xc5);
}
return;
default:
synchronized (queue) {
if (scancode < 0)
putKeyboardEvent((byte) 0xe0);
putKeyboardEvent((byte) (scancode & 0x7f));
}
return;
}
}
public void keyReleased(byte scancode)
{
synchronized (queue) {
if (scancode < 0)
putKeyboardEvent((byte) 0xe0);
putKeyboardEvent((byte) (scancode | 0x80));
}
}
private void putKeyboardEvent(byte keycode)
{
queue.writeData(keycode, (byte)0);
}
public void putMouseEvent(int dx, int dy, int dz, int buttons)
{
if (0 == (mouseStatus & MOUSE_STATUS_ENABLED))
return;
mouseDx += dx;
mouseDy -= dy;
mouseDz += dz;
mouseButtons = buttons;
synchronized (queue) {
if ((0 == (mouseStatus & MOUSE_STATUS_REMOTE)) && (queue.length < (KBD_QUEUE_SIZE - 16)))
while (true) {
/* if not remote, send event. Multiple events are sent if too big deltas */
mouseSendPacket();
if (mouseDx == 0 && mouseDy == 0 && mouseDz == 0)
break;
}
}
}
public boolean initialised()
{
return ioportRegistered && (irqDevice != null) && (cpu != null) && (physicalAddressSpace != null) && (linearAddressSpace != null);
}
public boolean updated()
{
return ioportRegistered && irqDevice.updated() && cpu.updated() && physicalAddressSpace.updated() && linearAddressSpace.updated();
}
public void updateComponent(HardwareComponent component)
{
if ((component instanceof IOPortHandler) && component.updated())
{
((IOPortHandler)component).registerIOPortCapable(this);
ioportRegistered = true;
}
}
public void acceptComponent(HardwareComponent component)
{
if ((component instanceof InterruptController) && component.initialised())
irqDevice = (InterruptController)component;
if ((component instanceof IOPortHandler) && component.initialised())
{
((IOPortHandler)component).registerIOPortCapable(this);
ioportRegistered = true;
}
if ((component instanceof Processor) && component.initialised())
cpu = (Processor)component;
if (component instanceof PhysicalAddressSpace)
physicalAddressSpace = (PhysicalAddressSpace) component;
if (component instanceof LinearAddressSpace)
linearAddressSpace = (LinearAddressSpace) component;
}
}