X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fdev%2Fx86%2Fi8042.cc;h=41c1c368c4b5f402e134a6db83ec7ebffbf286f5;hb=bdb2820218c6760101194d464b4fbd1c1c185014;hp=746a087782ba9ffe63cdde22ab1b578ff5cd634b;hpb=07cf9d914b292008ead7021182ec2ef8fc4671f1;p=gem5.git diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc index 746a08778..41c1c368c 100644 --- a/src/dev/x86/i8042.cc +++ b/src/dev/x86/i8042.cc @@ -24,29 +24,59 @@ * 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 "dev/x86/i8042.hh" + #include "base/bitunion.hh" #include "debug/I8042.hh" -#include "dev/x86/i8042.hh" #include "mem/packet.hh" #include "mem/packet_access.hh" +/** + * Note: For details on the implementation see + * https://wiki.osdev.org/%228042%22_PS/2_Controller + */ + // The 8042 has a whopping 32 bytes of internal RAM. const uint8_t RamSize = 32; const uint8_t NumOutputBits = 14; -const uint8_t X86ISA::PS2Keyboard::ID[] = {0xab, 0x83}; -const uint8_t X86ISA::PS2Mouse::ID[] = {0x00}; -const uint8_t CommandAck = 0xfa; -const uint8_t CommandNack = 0xfe; -const uint8_t BatSuccessful = 0xaa; + + +X86ISA::I8042::I8042(Params *p) + : BasicPioDevice(p, 0), // pioSize arg is dummy value... not used + latency(p->pio_latency), + dataPort(p->data_port), commandPort(p->command_port), + statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand), + mouse(p->mouse), keyboard(p->keyboard) +{ + fatal_if(!mouse, "The i8042 model requires a mouse instance"); + fatal_if(!keyboard, "The i8042 model requires a keyboard instance"); + + statusReg.passedSelfTest = 1; + statusReg.commandLast = 1; + statusReg.keyboardUnlocked = 1; + + commandByte.convertScanCodes = 1; + commandByte.passedSelfTest = 1; + commandByte.keyboardFullInt = 1; + + for (int i = 0; i < p->port_keyboard_int_pin_connection_count; i++) { + keyboardIntPin.push_back(new IntSourcePin( + csprintf("%s.keyboard_int_pin[%d]", name(), i), i, this)); + } + for (int i = 0; i < p->port_mouse_int_pin_connection_count; i++) { + mouseIntPin.push_back(new IntSourcePin( + csprintf("%s.mouse_int_pin[%d]", name(), i), i, this)); + } +} + AddrRangeList -X86ISA::I8042::getAddrRanges() +X86ISA::I8042::getAddrRanges() const { AddrRangeList ranges; + // TODO: Are these really supposed to be a single byte and not 4? ranges.push_back(RangeSize(dataPort, 1)); ranges.push_back(RangeSize(commandPort, 1)); return ranges; @@ -61,36 +91,18 @@ X86ISA::I8042::writeData(uint8_t newData, bool mouse) statusReg.mouseOutputFull = (mouse ? 1 : 0); if (!mouse && commandByte.keyboardFullInt) { DPRINTF(I8042, "Sending keyboard interrupt.\n"); - keyboardIntPin->raise(); - //This is a hack - keyboardIntPin->lower(); + for (auto *wire: keyboardIntPin) { + wire->raise(); + //This is a hack + wire->lower(); + } } else if (mouse && commandByte.mouseFullInt) { DPRINTF(I8042, "Sending mouse interrupt.\n"); - mouseIntPin->raise(); - //This is a hack - mouseIntPin->lower(); - } -} - -void -X86ISA::PS2Device::ack() -{ - bufferData(&CommandAck, sizeof(CommandAck)); -} - -void -X86ISA::PS2Device::nack() -{ - bufferData(&CommandNack, sizeof(CommandNack)); -} - -void -X86ISA::PS2Device::bufferData(const uint8_t *data, int size) -{ - assert(data || size == 0); - while (size) { - outBuffer.push(*(data++)); - size--; + for (auto *wire: mouseIntPin) { + wire->raise(); + //This is a hack + wire->lower(); + } } } @@ -100,196 +112,14 @@ X86ISA::I8042::readDataOut() uint8_t data = dataReg; statusReg.outputFull = 0; statusReg.mouseOutputFull = 0; - if (keyboard.hasData()) { - writeData(keyboard.getData(), false); - } else if (mouse.hasData()) { - writeData(mouse.getData(), true); + if (keyboard->hostDataAvailable()) { + writeData(keyboard->hostRead(), false); + } else if (mouse->hostDataAvailable()) { + writeData(mouse->hostRead(), true); } return data; } -bool -X86ISA::PS2Keyboard::processData(uint8_t data) -{ - if (lastCommand != NoCommand) { - switch (lastCommand) { - 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"); - ack(); - lastCommand = NoCommand; - break; - case TypematicInfo: - DPRINTF(I8042, "Setting typematic info to %#02x.\n", data); - ack(); - lastCommand = NoCommand; - break; - } - return hasData(); - } - switch (data) { - case LEDWrite: - DPRINTF(I8042, "Got LED write command.\n"); - ack(); - lastCommand = LEDWrite; - break; - case DiagnosticEcho: - panic("Keyboard diagnostic echo unimplemented.\n"); - case AlternateScanCodes: - panic("Accessing alternate scan codes unimplemented.\n"); - case ReadID: - DPRINTF(I8042, "Got keyboard read ID command.\n"); - ack(); - bufferData((uint8_t *)&ID, sizeof(ID)); - break; - case TypematicInfo: - DPRINTF(I8042, "Setting typematic info.\n"); - ack(); - lastCommand = TypematicInfo; - break; - case Enable: - DPRINTF(I8042, "Enabling the keyboard.\n"); - ack(); - break; - case Disable: - DPRINTF(I8042, "Disabling the keyboard.\n"); - ack(); - break; - case DefaultsAndDisable: - DPRINTF(I8042, "Disabling and resetting the keyboard.\n"); - ack(); - 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 Reset: - panic("Keyboard reset unimplemented.\n"); - default: - panic("Unknown keyboard command %#02x.\n", data); - } - return hasData(); -} - -bool -X86ISA::PS2Mouse::processData(uint8_t data) -{ - if (lastCommand != NoCommand) { - switch(lastCommand) { - case SetResolution: - DPRINTF(I8042, "Mouse resolution set to %d.\n", data); - resolution = data; - ack(); - lastCommand = NoCommand; - break; - case SampleRate: - DPRINTF(I8042, "Mouse sample rate %d samples " - "per second.\n", data); - sampleRate = data; - ack(); - lastCommand = NoCommand; - break; - default: - panic("Not expecting data for a mouse command.\n"); - } - return hasData(); - } - switch (data) { - case Scale1to1: - DPRINTF(I8042, "Setting mouse scale to 1:1.\n"); - status.twoToOne = 0; - ack(); - break; - case Scale2to1: - DPRINTF(I8042, "Setting mouse scale to 2:1.\n"); - status.twoToOne = 1; - ack(); - break; - case SetResolution: - DPRINTF(I8042, "Setting mouse resolution.\n"); - lastCommand = SetResolution; - ack(); - break; - case GetStatus: - DPRINTF(I8042, "Getting mouse status.\n"); - ack(); - bufferData((uint8_t *)&(status), 1); - bufferData(&resolution, sizeof(resolution)); - bufferData(&sampleRate, sizeof(sampleRate)); - break; - case ReadData: - panic("Reading mouse data unimplemented.\n"); - case ResetWrapMode: - panic("Resetting mouse wrap mode unimplemented.\n"); - case WrapMode: - panic("Setting mouse wrap mode unimplemented.\n"); - case RemoteMode: - panic("Setting mouse remote mode unimplemented.\n"); - case ReadID: - DPRINTF(I8042, "Mouse ID requested.\n"); - ack(); - bufferData(ID, sizeof(ID)); - break; - case SampleRate: - DPRINTF(I8042, "Setting mouse sample rate.\n"); - lastCommand = SampleRate; - ack(); - break; - case DisableReporting: - DPRINTF(I8042, "Disabling data reporting.\n"); - status.enabled = 0; - ack(); - break; - case EnableReporting: - DPRINTF(I8042, "Enabling data reporting.\n"); - status.enabled = 1; - ack(); - break; - case DefaultsAndDisable: - DPRINTF(I8042, "Disabling and resetting mouse.\n"); - sampleRate = 100; - resolution = 4; - status.twoToOne = 0; - status.enabled = 0; - ack(); - break; - case Resend: - panic("Mouse resend unimplemented.\n"); - case Reset: - DPRINTF(I8042, "Resetting the mouse.\n"); - sampleRate = 100; - resolution = 4; - status.twoToOne = 0; - status.enabled = 0; - ack(); - bufferData(&BatSuccessful, sizeof(BatSuccessful)); - bufferData(ID, sizeof(ID)); - break; - default: - warn("Unknown mouse command %#02x.\n", data); - nack(); - break; - } - return hasData(); -} - - Tick X86ISA::I8042::read(PacketPtr pkt) { @@ -298,10 +128,10 @@ X86ISA::I8042::read(PacketPtr pkt) if (addr == dataPort) { uint8_t data = readDataOut(); //DPRINTF(I8042, "Read from data port got %#02x.\n", data); - pkt->set(data); + pkt->setLE(data); } else if (addr == commandPort) { //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg); - pkt->set((uint8_t)statusReg); + pkt->setLE((uint8_t)statusReg); } else { panic("Read from unrecognized port %#x.\n", addr); } @@ -314,19 +144,19 @@ X86ISA::I8042::write(PacketPtr pkt) { assert(pkt->getSize() == 1); Addr addr = pkt->getAddr(); - uint8_t data = pkt->get(); + uint8_t data = pkt->getLE(); if (addr == dataPort) { statusReg.commandLast = 0; switch (lastCommand) { case NoCommand: - if (keyboard.processData(data)) { - writeData(keyboard.getData(), false); - } + keyboard->hostWrite(data); + if (keyboard->hostDataAvailable()) + writeData(keyboard->hostRead(), false); break; case WriteToMouse: - if (mouse.processData(data)) { - writeData(mouse.getData(), true); - } + mouse->hostWrite(data); + if (mouse->hostDataAvailable()) + writeData(mouse->hostRead(), true); break; case WriteCommandByte: commandByte = data; @@ -339,6 +169,17 @@ X86ISA::I8042::write(PacketPtr pkt) "mouse output buffer\" command.\n", data); writeData(data, true); break; + case WriteKeyboardOutputBuff: + DPRINTF(I8042, "Got data %#02x for \"Write " + "keyboad output buffer\" command.\n", data); + writeData(data, false); + break; + case WriteOutputPort: + DPRINTF(I8042, "Got data %#02x for \"Write " + "output port\" command.\n", data); + panic_if(bits(data, 0) != 1, "Reset bit should be 1"); + // Safe to ignore otherwise + break; default: panic("Data written for unrecognized " "command %#02x\n", lastCommand); @@ -410,10 +251,11 @@ X86ISA::I8042::write(PacketPtr pkt) case ReadOutputPort: panic("i8042 \"Read output port\" command not implemented.\n"); case WriteOutputPort: - panic("i8042 \"Write output port\" command not implemented.\n"); + lastCommand = WriteOutputPort; + break; case WriteKeyboardOutputBuff: - panic("i8042 \"Write keyboard output buffer\" " - "command not implemented.\n"); + lastCommand = WriteKeyboardOutputBuff; + break; case WriteMouseOutputBuff: DPRINTF(I8042, "Got command to write to mouse output buffer.\n"); lastCommand = WriteMouseOutputBuff; @@ -431,7 +273,7 @@ X86ISA::I8042::write(PacketPtr pkt) case SystemReset: panic("i8042 \"System reset\" command not implemented.\n"); default: - panic("Write to unknown i8042 " + warn("Write to unknown i8042 " "(keyboard controller) command port.\n"); } } else { @@ -442,112 +284,25 @@ X86ISA::I8042::write(PacketPtr pkt) } void -X86ISA::I8042::serialize(std::ostream &os) +X86ISA::I8042::serialize(CheckpointOut &cp) const { - uint8_t statusRegData = statusReg.__data; - uint8_t commandByteData = commandByte.__data; - SERIALIZE_SCALAR(dataPort); SERIALIZE_SCALAR(commandPort); - SERIALIZE_SCALAR(statusRegData); - SERIALIZE_SCALAR(commandByteData); + SERIALIZE_SCALAR(statusReg); + SERIALIZE_SCALAR(commandByte); SERIALIZE_SCALAR(dataReg); SERIALIZE_SCALAR(lastCommand); - mouse.serialize("mouse", os); - keyboard.serialize("keyboard", os); } void -X86ISA::I8042::unserialize(Checkpoint *cp, const std::string §ion) +X86ISA::I8042::unserialize(CheckpointIn &cp) { - uint8_t statusRegData; - uint8_t commandByteData; - UNSERIALIZE_SCALAR(dataPort); UNSERIALIZE_SCALAR(commandPort); - UNSERIALIZE_SCALAR(statusRegData); - UNSERIALIZE_SCALAR(commandByteData); + UNSERIALIZE_SCALAR(statusReg); + UNSERIALIZE_SCALAR(commandByte); UNSERIALIZE_SCALAR(dataReg); UNSERIALIZE_SCALAR(lastCommand); - mouse.unserialize("mouse", cp, section); - keyboard.unserialize("keyboard", cp, section); - - statusReg.__data = statusRegData; - commandByte.__data = commandByteData; -} - -void -X86ISA::PS2Keyboard::serialize(const std::string &base, std::ostream &os) -{ - paramOut(os, base + ".lastCommand", lastCommand); - int bufferSize = outBuffer.size(); - paramOut(os, base + ".outBuffer.size", bufferSize); - uint8_t *buffer = new uint8_t[bufferSize]; - for (int i = 0; i < bufferSize; ++i) { - buffer[i] = outBuffer.front(); - outBuffer.pop(); - } - arrayParamOut(os, base + ".outBuffer.elts", buffer, - bufferSize*sizeof(uint8_t)); - delete buffer; -} - -void -X86ISA::PS2Keyboard::unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion) -{ - paramIn(cp, section, base + ".lastCommand", lastCommand); - int bufferSize; - paramIn(cp, section, base + ".outBuffer.size", bufferSize); - uint8_t *buffer = new uint8_t[bufferSize]; - arrayParamIn(cp, section, base + ".outBuffer.elts", buffer, - bufferSize*sizeof(uint8_t)); - for (int i = 0; i < bufferSize; ++i) { - outBuffer.push(buffer[i]); - } - delete buffer; -} - -void -X86ISA::PS2Mouse::serialize(const std::string &base, std::ostream &os) -{ - uint8_t statusData = status.__data; - paramOut(os, base + ".lastCommand", lastCommand); - int bufferSize = outBuffer.size(); - paramOut(os, base + ".outBuffer.size", bufferSize); - uint8_t *buffer = new uint8_t[bufferSize]; - for (int i = 0; i < bufferSize; ++i) { - buffer[i] = outBuffer.front(); - outBuffer.pop(); - } - arrayParamOut(os, base + ".outBuffer.elts", buffer, - bufferSize*sizeof(uint8_t)); - delete buffer; - paramOut(os, base + ".status", statusData); - paramOut(os, base + ".resolution", resolution); - paramOut(os, base + ".sampleRate", sampleRate); -} - -void -X86ISA::PS2Mouse::unserialize(const std::string &base, Checkpoint *cp, - const std::string §ion) -{ - uint8_t statusData; - paramIn(cp, section, base + ".lastCommand", lastCommand); - int bufferSize; - paramIn(cp, section, base + ".outBuffer.size", bufferSize); - uint8_t *buffer = new uint8_t[bufferSize]; - arrayParamIn(cp, section, base + ".outBuffer.elts", buffer, - bufferSize*sizeof(uint8_t)); - for (int i = 0; i < bufferSize; ++i) { - outBuffer.push(buffer[i]); - } - delete buffer; - paramIn(cp, section, base + ".status", statusData); - paramIn(cp, section, base + ".resolution", resolution); - paramIn(cp, section, base + ".sampleRate", sampleRate); - - status.__data = statusData; } X86ISA::I8042 *