X86: Add a keyboard controller device.

This commit is contained in:
Gabe Black 2009-01-31 23:59:01 -08:00
parent 0287f19ede
commit 7cf276bed3
5 changed files with 731 additions and 0 deletions

43
src/dev/x86/I8042.py Normal file
View file

@ -0,0 +1,43 @@
# Copyright (c) 2008 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Gabe Black
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
from X86IntPin import X86IntSourcePin
class I8042(BasicPioDevice):
type = 'I8042'
cxx_class = 'X86ISA::I8042'
pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
data_port = Param.Addr('Data port address')
command_port = Param.Addr('Command/status port address')
mouse_int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
'Pin to signal the mouse has data')
keyboard_int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
'Pin to signal the keyboard has data')

View file

@ -53,6 +53,10 @@ if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'x86':
Source('i8237.cc')
TraceFlag('I8237', 'The I8237 dma controller');
SimObject('I8042.py')
Source('i8042.cc')
TraceFlag('I8042', 'The I8042 keyboard controller');
SimObject('PcSpeaker.py')
Source('speaker.cc')
TraceFlag('PcSpeaker')

View file

@ -29,6 +29,7 @@
from m5.params import *
from m5.proxy import *
from Cmos import Cmos
from I8042 import I8042
from I82094AA import I82094AA
from I8237 import I8237
from I8254 import I8254
@ -50,6 +51,8 @@ class SouthBridge(SimObject):
_pic2 = I8259(pio_addr=x86IOAddress(0xA0), mode='I8259Slave')
_cmos = Cmos(pio_addr=x86IOAddress(0x70))
_dma1 = I8237(pio_addr=x86IOAddress(0x0))
_keyboard = I8042(data_port=x86IOAddress(0x60), \
command_port=x86IOAddress(0x64))
_pit = I8254(pio_addr=x86IOAddress(0x40))
_speaker = PcSpeaker(pio_addr=x86IOAddress(0x61))
_io_apic = I82094AA(pio_addr=0xFEC00000)
@ -61,6 +64,7 @@ class SouthBridge(SimObject):
pic2 = Param.I8259(_pic2, "Slave PIC")
cmos = Param.Cmos(_cmos, "CMOS memory and real time clock device")
dma1 = Param.I8237(_dma1, "The first dma controller")
keyboard = Param.I8042(_keyboard, "The keyboard controller")
pit = Param.I8254(_pit, "Programmable interval timer")
speaker = Param.PcSpeaker(_speaker, "PC speaker")
io_apic = Param.I82094AA(_io_apic, "I/O APIC")
@ -75,6 +79,14 @@ class SouthBridge(SimObject):
self.connectPins(self.cmos.int_pin, self.pic2.pin(0))
self.connectPins(self.pit.int_pin, self.pic1.pin(0))
self.connectPins(self.pit.int_pin, self.io_apic.pin(2))
# self.connectPins(self.keyboard.keyboard_int_pin,
# self.pic1.pin(1))
self.connectPins(self.keyboard.keyboard_int_pin,
self.io_apic.pin(1))
# self.connectPins(self.keyboard.mouse_int_pin,
# self.pic2.pin(4))
self.connectPins(self.keyboard.mouse_int_pin,
self.io_apic.pin(12))
# Tell the devices about each other
self.pic1.slave = self.pic2
self.speaker.i8254 = self.pit
@ -82,6 +94,7 @@ class SouthBridge(SimObject):
# Connect to the bus
self.cmos.pio = bus.port
self.dma1.pio = bus.port
self.keyboard.pio = bus.port
self.pic1.pio = bus.port
self.pic2.pio = bus.port
self.pit.pio = bus.port

529
src/dev/x86/i8042.cc Normal file
View file

@ -0,0 +1,529 @@
/*
* Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Gabe Black
*/
#include "base/bitunion.hh"
#include "dev/x86/i8042.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
// The 8042 has a whopping 32 bytes of internal RAM.
const uint8_t RamSize = 32;
const uint8_t NumOutputBits = 14;
const uint8_t KeyboardID[] = {0xab, 0x83};
const uint8_t MouseID[] = {0x00};
const uint8_t CommandAck = 0xfa;
const uint8_t CommandNack = 0xfe;
const uint8_t BatSuccessful = 0xaa;
enum Port64Command
{
GetCommandByte = 0x20,
ReadControllerRamBase = 0x20,
WriteCommandByte = 0x60,
WriteControllerRamBase = 0x60,
CheckForPassword = 0xA4,
LoadPassword = 0xA5,
CheckPassword = 0xA6,
DisableMouse = 0xA7,
EnableMouse = 0xA8,
TestMouse = 0xA9,
SelfTest = 0xAA,
InterfaceTest = 0xAB,
DiagnosticDump = 0xAC,
DisableKeyboard = 0xAD,
EnableKeyboard = 0xAE,
ReadInputPort = 0xC0,
ContinuousPollLow = 0xC1,
ContinuousPollHigh = 0xC2,
ReadOutputPort = 0xD0,
WriteOutputPort = 0xD1,
WriteKeyboardOutputBuff = 0xD2,
WriteMouseOutputBuff = 0xD3,
WriteToMouse = 0xD4,
DisableA20 = 0xDD,
EnableA20 = 0xDF,
ReadTestInputs = 0xE0,
PulseOutputBitBase = 0xF0,
SystemReset = 0xFE
};
enum Port60Command
{
MouseScale1to1 = 0xE6,
MouseScale2to1 = 0xE7,
SetMouseResolution = 0xE8,
MouseGetStatus = 0xE9,
MouseReadData = 0xEB,
MouseResetWrapMode = 0xEC,
LEDWrite = 0xED,
DiagnosticEcho = 0xEE,
MouseWrapMode = 0xEE,
AlternateScanCodes = 0xF0,
MouseRemoteMode = 0xF0,
ReadKeyboardID = 0xF2,
ReadMouseID = 0xF2,
TypematicInfo = 0xF3,
MouseSampleRate = 0xF3,
KeyboardEnable = 0xF4,
MouseEnableReporting = 0xF4,
KeyboardDisable = 0xF5,
MouseDisableReporting = 0xF5,
DefaultsAndDisableKeyboard = 0xF6,
DefaultsAndDisableMouse = 0xF6,
AllKeysToTypematic = 0xF7,
AllKeysToMakeRelease = 0xF8,
AllKeysToMake = 0xF9,
AllKeysToTypematicMakeRelease = 0xFA,
KeyToTypematic = 0xFB,
KeyToMakeRelease = 0xFC,
KeyToMakeOnly = 0xFD,
Resend = 0xFE,
KeyboardReset = 0xFF,
MouseReset = 0xFF
};
void
X86ISA::I8042::addressRanges(AddrRangeList &range_list)
{
range_list.clear();
range_list.push_back(RangeSize(dataPort, 1));
range_list.push_back(RangeSize(commandPort, 1));
}
bool
X86ISA::I8042::writeData(uint8_t newData, bool mouse)
{
if (!statusReg.outputFull) {
DPRINTF(I8042, "Set data %#02x.\n", newData);
dataReg = newData;
statusReg.outputFull = 1;
statusReg.mouseOutputFull = (mouse ? 1 : 0);
return true;
} else {
return false;
}
}
void
X86ISA::I8042::keyboardAck()
{
while (!keyboardBuffer.empty())
keyboardBuffer.pop();
writeKeyboardData(&CommandAck, sizeof(CommandAck));
}
void
X86ISA::I8042::writeKeyboardData(const uint8_t *data, int size)
{
assert(data || size == 0);
while (size) {
keyboardBuffer.push(*(data++));
size--;
}
if (writeData(keyboardBuffer.front())) {
keyboardBuffer.pop();
if (commandByte.keyboardFullInt) {
DPRINTF(I8042, "Sending keyboard interrupt.\n");
keyboardIntPin->raise();
//XXX This is a hack.
keyboardIntPin->lower();
}
}
}
void
X86ISA::I8042::mouseAck()
{
while (!mouseBuffer.empty())
mouseBuffer.pop();
writeMouseData(&CommandAck, sizeof(CommandAck));
}
void
X86ISA::I8042::mouseNack()
{
while (!mouseBuffer.empty())
mouseBuffer.pop();
writeMouseData(&CommandNack, sizeof(CommandAck));
}
void
X86ISA::I8042::writeMouseData(const uint8_t *data, int size)
{
assert(data || size == 0);
while (size) {
mouseBuffer.push(*(data++));
size--;
}
if (writeData(mouseBuffer.front(), true)) {
mouseBuffer.pop();
if (commandByte.mouseFullInt) {
DPRINTF(I8042, "Sending mouse interrupt.\n");
mouseIntPin->raise();
//XXX This is a hack
mouseIntPin->lower();
}
}
}
uint8_t
X86ISA::I8042::readDataOut()
{
uint8_t data = dataReg;
statusReg.outputFull = 0;
statusReg.mouseOutputFull = 0;
if (!keyboardBuffer.empty()) {
writeKeyboardData(NULL, 0);
}
if (!mouseBuffer.empty()) {
writeMouseData(NULL, 0);
}
return data;
}
Tick
X86ISA::I8042::read(PacketPtr pkt)
{
assert(pkt->getSize() == 1);
Addr addr = pkt->getAddr();
if (addr == dataPort) {
uint8_t data = readDataOut();
//DPRINTF(I8042, "Read from data port got %#02x.\n", data);
pkt->set<uint8_t>(data);
} else if (addr == commandPort) {
//DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
pkt->set<uint8_t>((uint8_t)statusReg);
} else {
panic("Read from unrecognized port %#x.\n", addr);
}
return latency;
}
Tick
X86ISA::I8042::write(PacketPtr pkt)
{
assert(pkt->getSize() == 1);
Addr addr = pkt->getAddr();
uint8_t data = pkt->get<uint8_t>();
if (addr == dataPort) {
statusReg.commandLast = 0;
switch (lastCommand) {
case NoCommand:
if (lastKeyboardCommand != NoCommand) {
switch (lastKeyboardCommand) {
case LEDWrite:
DPRINTF(I8042, "Setting LEDs: "
"caps lock %s, num lock %s, scroll lock %s\n",
bits(data, 2) ? "on" : "off",
bits(data, 1) ? "on" : "off",
bits(data, 0) ? "on" : "off");
keyboardAck();
lastKeyboardCommand = NoCommand;
break;
case TypematicInfo:
DPRINTF(I8042,
"Setting typematic info to %#02x.\n", data);
keyboardAck();
lastKeyboardCommand = NoCommand;
break;
}
break;
}
DPRINTF(I8042, "Got port 0x60 command %#02x.\n", data);
switch (data) {
case LEDWrite:
DPRINTF(I8042, "Got LED write command.\n");
keyboardAck();
lastKeyboardCommand = LEDWrite;
break;
case DiagnosticEcho:
panic("Keyboard diagnostic echo unimplemented.\n");
case AlternateScanCodes:
panic("Accessing alternate scan codes unimplemented.\n");
case ReadKeyboardID:
DPRINTF(I8042, "Got keyboard read ID command.\n");
keyboardAck();
writeKeyboardData((uint8_t *)&KeyboardID, sizeof(KeyboardID));
break;
case TypematicInfo:
DPRINTF(I8042, "Setting typematic info.\n");
keyboardAck();
lastKeyboardCommand = TypematicInfo;
break;
case KeyboardEnable:
DPRINTF(I8042, "Enabling the keyboard.\n");
keyboardAck();
break;
case KeyboardDisable:
DPRINTF(I8042, "Disabling the keyboard.\n");
keyboardAck();
break;
case DefaultsAndDisableKeyboard:
DPRINTF(I8042, "Disabling and resetting the keyboard.\n");
keyboardAck();
break;
case AllKeysToTypematic:
panic("Setting all keys to typemantic unimplemented.\n");
case AllKeysToMakeRelease:
panic("Setting all keys to make/release unimplemented.\n");
case AllKeysToMake:
panic("Setting all keys to make unimplemented.\n");
case AllKeysToTypematicMakeRelease:
panic("Setting all keys to "
"typematic/make/release unimplemented.\n");
case KeyToTypematic:
panic("Setting a key to typematic unimplemented.\n");
case KeyToMakeRelease:
panic("Setting a key to make/release unimplemented.\n");
case KeyToMakeOnly:
panic("Setting key to make only unimplemented.\n");
case Resend:
panic("Keyboard resend unimplemented.\n");
case KeyboardReset:
panic("Keyboard reset unimplemented.\n");
default:
panic("Unknown keyboard command %#02x.\n", data);
}
break;
case WriteToMouse:
if (lastMouseCommand != NoCommand) {
switch(lastMouseCommand) {
case SetMouseResolution:
DPRINTF(I8042, "Mouse resolution set to %d.\n", data);
mouseResolution = data;
mouseAck();
lastMouseCommand = NoCommand;
break;
case MouseSampleRate:
DPRINTF(I8042, "Mouse sample rate %d samples "
"per second.\n", data);
mouseSampleRate = data;
mouseAck();
lastMouseCommand = NoCommand;
break;
default:
panic("Not expecting data for a mouse command.\n");
}
break;
}
switch (data) {
case MouseScale1to1:
DPRINTF(I8042, "Setting mouse scale to 1:1.\n");
mouseStatus.twoToOne = 0;
mouseAck();
break;
case MouseScale2to1:
DPRINTF(I8042, "Setting mouse scale to 2:1.\n");
mouseStatus.twoToOne = 1;
mouseAck();
break;
case SetMouseResolution:
DPRINTF(I8042, "Setting mouse resolution.\n");
lastMouseCommand = SetMouseResolution;
mouseAck();
break;
case MouseGetStatus:
DPRINTF(I8042, "Getting mouse status.\n");
mouseAck();
writeMouseData((uint8_t *)&(mouseStatus), 1);
writeMouseData(&mouseResolution, sizeof(mouseResolution));
writeMouseData(&mouseSampleRate, sizeof(mouseSampleRate));
break;
case MouseReadData:
panic("Reading mouse data unimplemented.\n");
case MouseResetWrapMode:
panic("Resetting mouse wrap mode unimplemented.\n");
case MouseWrapMode:
panic("Setting mouse wrap mode unimplemented.\n");
case MouseRemoteMode:
panic("Setting mouse remote mode unimplemented.\n");
case ReadMouseID:
DPRINTF(I8042, "Mouse ID requested.\n");
mouseAck();
writeMouseData(MouseID, sizeof(MouseID));
break;
case MouseSampleRate:
DPRINTF(I8042, "Setting mouse sample rate.\n");
lastMouseCommand = MouseSampleRate;
mouseAck();
break;
case MouseDisableReporting:
DPRINTF(I8042, "Disabling data reporting.\n");
mouseStatus.enabled = 0;
mouseAck();
break;
case MouseEnableReporting:
DPRINTF(I8042, "Enabling data reporting.\n");
mouseStatus.enabled = 1;
mouseAck();
break;
case DefaultsAndDisableMouse:
DPRINTF(I8042, "Disabling and resetting mouse.\n");
mouseSampleRate = 100;
mouseResolution = 4;
mouseStatus.twoToOne = 0;
mouseStatus.enabled = 0;
mouseAck();
break;
case Resend:
panic("Keyboard resent unimplemented.\n");
case MouseReset:
DPRINTF(I8042, "Resetting the mouse.\n");
mouseSampleRate = 100;
mouseResolution = 4;
mouseStatus.twoToOne = 0;
mouseStatus.enabled = 0;
mouseAck();
writeMouseData(&BatSuccessful, sizeof(BatSuccessful));
writeMouseData(MouseID, sizeof(MouseID));
break;
default:
warn("Unknown mouse command %#02x.\n", data);
mouseNack();
break;
}
break;
case WriteCommandByte:
commandByte = data;
DPRINTF(I8042, "Got data %#02x for \"Write "
"command byte\" command.\n", data);
statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
break;
case WriteMouseOutputBuff:
DPRINTF(I8042, "Got data %#02x for \"Write "
"mouse output buffer\" command.\n", data);
writeMouseData(&data, sizeof(data));
break;
default:
panic("Data written for unrecognized "
"command %#02x\n", lastCommand);
}
lastCommand = NoCommand;
} else if (addr == commandPort) {
DPRINTF(I8042, "Got command %#02x.\n", data);
statusReg.commandLast = 1;
// These purposefully leave off the first byte of the controller RAM
// so it can be handled specially.
if (data > ReadControllerRamBase &&
data < ReadControllerRamBase + RamSize) {
panic("Attempted to use i8042 read controller RAM command to "
"get byte %d.\n", data - ReadControllerRamBase);
} else if (data > WriteControllerRamBase &&
data < WriteControllerRamBase + RamSize) {
panic("Attempted to use i8042 read controller RAM command to "
"get byte %d.\n", data - ReadControllerRamBase);
} else if (data >= PulseOutputBitBase &&
data < PulseOutputBitBase + NumOutputBits) {
panic("Attempted to use i8042 pulse output bit command to "
"to pulse bit %d.\n", data - PulseOutputBitBase);
}
switch (data) {
case GetCommandByte:
DPRINTF(I8042, "Getting command byte.\n");
writeData(commandByte);
break;
case WriteCommandByte:
DPRINTF(I8042, "Setting command byte.\n");
lastCommand = WriteCommandByte;
break;
case CheckForPassword:
panic("i8042 \"Check for password\" command not implemented.\n");
case LoadPassword:
panic("i8042 \"Load password\" command not implemented.\n");
case CheckPassword:
panic("i8042 \"Check password\" command not implemented.\n");
case DisableMouse:
DPRINTF(I8042, "Disabling mouse at controller.\n");
commandByte.disableMouse = 1;
break;
case EnableMouse:
DPRINTF(I8042, "Enabling mouse at controller.\n");
commandByte.disableMouse = 0;
break;
case TestMouse:
panic("i8042 \"Test mouse\" command not implemented.\n");
case SelfTest:
panic("i8042 \"Self test\" command not implemented.\n");
case InterfaceTest:
panic("i8042 \"Interface test\" command not implemented.\n");
case DiagnosticDump:
panic("i8042 \"Diagnostic dump\" command not implemented.\n");
case DisableKeyboard:
DPRINTF(I8042, "Disabling keyboard at controller.\n");
commandByte.disableKeyboard = 1;
break;
case EnableKeyboard:
DPRINTF(I8042, "Enabling keyboard at controller.\n");
commandByte.disableKeyboard = 0;
break;
case ReadInputPort:
panic("i8042 \"Read input port\" command not implemented.\n");
case ContinuousPollLow:
panic("i8042 \"Continuous poll low\" command not implemented.\n");
case ContinuousPollHigh:
panic("i8042 \"Continuous poll high\" command not implemented.\n");
case ReadOutputPort:
panic("i8042 \"Read output port\" command not implemented.\n");
case WriteOutputPort:
panic("i8042 \"Write output port\" command not implemented.\n");
case WriteKeyboardOutputBuff:
panic("i8042 \"Write keyboard output buffer\" "
"command not implemented.\n");
case WriteMouseOutputBuff:
DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
lastCommand = WriteMouseOutputBuff;
break;
case WriteToMouse:
DPRINTF(I8042, "Expecting mouse command.\n");
lastCommand = WriteToMouse;
break;
case DisableA20:
panic("i8042 \"Disable A20\" command not implemented.\n");
case EnableA20:
panic("i8042 \"Enable A20\" command not implemented.\n");
case ReadTestInputs:
panic("i8042 \"Read test inputs\" command not implemented.\n");
case SystemReset:
panic("i8042 \"System reset\" command not implemented.\n");
default:
panic("Write to unknown i8042 "
"(keyboard controller) command port.\n");
}
} else {
panic("Write to unrecognized port %#x.\n", addr);
}
return latency;
}
X86ISA::I8042 *
I8042Params::create()
{
return new X86ISA::I8042(this);
}

142
src/dev/x86/i8042.hh Normal file
View file

@ -0,0 +1,142 @@
/*
* Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Gabe Black
*/
#ifndef __DEV_X86_I8042_HH__
#define __DEV_X86_I8042_HH__
#include "dev/io_device.hh"
#include "dev/x86/intdev.hh"
#include "params/I8042.hh"
#include <queue>
namespace X86ISA
{
class IntPin;
class I8042 : public BasicPioDevice
{
protected:
BitUnion8(StatusReg)
Bitfield<7> parityError;
Bitfield<6> timeout;
Bitfield<5> mouseOutputFull;
Bitfield<4> keyboardUnlocked;
Bitfield<3> commandLast;
Bitfield<2> passedSelfTest;
Bitfield<1> inputFull;
Bitfield<0> outputFull;
EndBitUnion(StatusReg)
BitUnion8(CommandByte)
Bitfield<6> convertScanCodes;
Bitfield<5> disableMouse;
Bitfield<4> disableKeyboard;
Bitfield<2> passedSelfTest;
Bitfield<1> mouseFullInt;
Bitfield<0> keyboardFullInt;
EndBitUnion(CommandByte)
Tick latency;
Addr dataPort;
Addr commandPort;
StatusReg statusReg;
CommandByte commandByte;
uint8_t dataReg;
static const uint16_t NoCommand = (uint16_t)(-1);
uint16_t lastCommand;
BitUnion8(MouseStatus)
Bitfield<6> remote;
Bitfield<5> enabled;
Bitfield<4> twoToOne;
Bitfield<2> leftButton;
Bitfield<0> rightButton;
EndBitUnion(MouseStatus)
IntSourcePin *mouseIntPin;
std::queue<uint8_t> mouseBuffer;
uint16_t lastMouseCommand;
uint8_t mouseResolution;
uint8_t mouseSampleRate;
MouseStatus mouseStatus;
IntSourcePin *keyboardIntPin;
std::queue<uint8_t> keyboardBuffer;
uint16_t lastKeyboardCommand;
bool writeData(uint8_t newData, bool mouse = false);
void keyboardAck();
void writeKeyboardData(const uint8_t *data, int size);
void mouseAck();
void mouseNack();
void writeMouseData(const uint8_t *data, int size);
uint8_t readDataOut();
public:
typedef I8042Params Params;
const Params *
params() const
{
return dynamic_cast<const Params *>(_params);
}
I8042(Params *p) : BasicPioDevice(p), latency(p->pio_latency),
dataPort(p->data_port), commandPort(p->command_port),
statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand),
mouseIntPin(p->mouse_int_pin), lastMouseCommand(NoCommand),
keyboardIntPin(p->keyboard_int_pin),
lastKeyboardCommand(NoCommand)
{
statusReg.passedSelfTest = 1;
statusReg.commandLast = 1;
statusReg.keyboardUnlocked = 1;
commandByte.convertScanCodes = 1;
commandByte.passedSelfTest = 1;
commandByte.keyboardFullInt = 1;
}
void addressRanges(AddrRangeList &range_list);
Tick read(PacketPtr pkt);
Tick write(PacketPtr pkt);
};
}; // namespace X86ISA
#endif //__DEV_X86_I8042_HH__