X86: Add a keyboard controller device.
authorGabe Black <gblack@eecs.umich.edu>
Sun, 1 Feb 2009 07:59:01 +0000 (23:59 -0800)
committerGabe Black <gblack@eecs.umich.edu>
Sun, 1 Feb 2009 07:59:01 +0000 (23:59 -0800)
src/dev/x86/I8042.py [new file with mode: 0644]
src/dev/x86/SConscript
src/dev/x86/SouthBridge.py
src/dev/x86/i8042.cc [new file with mode: 0644]
src/dev/x86/i8042.hh [new file with mode: 0644]

diff --git a/src/dev/x86/I8042.py b/src/dev/x86/I8042.py
new file mode 100644 (file)
index 0000000..1f6a484
--- /dev/null
@@ -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')
index 167b14a8438535380d1d1a08110e702fdaeaa46b..e7543dfdf27ef27a96bb9eda58012a7e11124559 100644 (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')
index ba9aaf2b42b552693232df74a24020eb8ebafb72..a3db83610befb26b85710c896274bf9ff2911e77 100644 (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
diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc
new file mode 100644 (file)
index 0000000..7dff498
--- /dev/null
@@ -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);
+}
diff --git a/src/dev/x86/i8042.hh b/src/dev/x86/i8042.hh
new file mode 100644 (file)
index 0000000..7eeb5f7
--- /dev/null
@@ -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__