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') Source('i8237.cc')
TraceFlag('I8237', 'The I8237 dma controller'); TraceFlag('I8237', 'The I8237 dma controller');
SimObject('I8042.py')
Source('i8042.cc')
TraceFlag('I8042', 'The I8042 keyboard controller');
SimObject('PcSpeaker.py') SimObject('PcSpeaker.py')
Source('speaker.cc') Source('speaker.cc')
TraceFlag('PcSpeaker') TraceFlag('PcSpeaker')

View file

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