X86: Add a keyboard controller device.
This commit is contained in:
parent
0287f19ede
commit
7cf276bed3
43
src/dev/x86/I8042.py
Normal file
43
src/dev/x86/I8042.py
Normal 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')
|
|
@ -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')
|
||||||
|
|
|
@ -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
529
src/dev/x86/i8042.cc
Normal 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
142
src/dev/x86/i8042.hh
Normal 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__
|
Loading…
Reference in a new issue