diff --git a/src/dev/x86/i8042.hh b/src/dev/x86/i8042.hh --- a/src/dev/x86/i8042.hh +++ b/src/dev/x86/i8042.hh @@ -87,6 +87,11 @@ enum Command { + // Trackpoint commands. + ReadExtendedID = 0xD0, + ReadSecondaryID = 0xE1, + TrackpointControllerCommand = 0xE2, + Scale1to1 = 0xE6, Scale2to1 = 0xE7, SetResolution = 0xE8, @@ -196,9 +201,10 @@ enum Command { GetCommandByte = 0x20, - ReadControllerRamBase = 0x20, - WriteCommandByte = 0x60, - WriteControllerRamBase = 0x60, + ReadControllerRamVal = 0x20, + ReadControllerRamMask = 0xE0, + WriteControllerRamVal = 0x60, + WriteControllerRamMask = 0xE0, CheckForPassword = 0xA4, LoadPassword = 0xA5, CheckPassword = 0xA6, @@ -221,8 +227,8 @@ DisableA20 = 0xDD, EnableA20 = 0xDF, ReadTestInputs = 0xE0, - PulseOutputBitBase = 0xF0, - SystemReset = 0xFE + PulseOutputBitMask = 0xF0, + PulseOutputBitVal = 0xF0, }; BitUnion8(StatusReg) @@ -245,10 +251,31 @@ Bitfield<0> keyboardFullInt; EndBitUnion(CommandByte) + BitUnion8(OutputPorts) + // 1: Normal, 0: Reset + Bitfield<0> reset; + Bitfield<1> a20; + // 1: Pull low, 0: High z + Bitfield<2> mouseData; + // 1: Pull low, 0: High z + Bitfield<3> mouseClock; + // 1: Assert KB IBF int, 0: Deassert KB IBF int + Bitfield<4> keyboard; + // 1: Assert mouse IBF int, 0: Deassert mouse IBF int + Bitfield<5> mouse; + // 1: Pull low, 0: High z + Bitfield<6> keyboardClock; + // 1: Pull low, 0: High z + Bitfield<7> keyboardData; + EndBitUnion(OutputPorts) + Tick latency; Addr dataPort; Addr commandPort; + OutputPorts outputs; + void setOutputPorts(uint8_t val); + StatusReg statusReg; CommandByte commandByte; # Node ID 740dbb64ce346ae6a5f068e5e7a192dc703e725b # Parent f49f05ff36a4f05267132f9b22ec837e5298e396 diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc --- a/src/dev/x86/i8042.cc +++ b/src/dev/x86/i8042.cc @@ -37,7 +37,6 @@ // 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; @@ -48,11 +47,14 @@ 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), + dataPort(p->data_port), commandPort(p->command_port), outputs(0), statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand), mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin), mouse(this) { + outputs.reset = 1; + outputs.a20 = 1; + statusReg.passedSelfTest = 1; statusReg.commandLast = 1; statusReg.keyboardUnlocked = 1; @@ -169,7 +171,9 @@ lastCommand = LEDWrite; break; case DiagnosticEcho: - panic("Keyboard diagnostic echo unimplemented.\n"); + ack(); + bufferData(&data, 1); + break; case AlternateScanCodes: panic("Accessing alternate scan codes unimplemented.\n"); case ReadID: @@ -319,6 +323,18 @@ return hasData(); } switch (data) { + case ReadExtendedID: + DPRINTF(I8042, "Ignoring \"Read extended ID\" command.\n"); + nack(); + break; + case ReadSecondaryID: + DPRINTF(I8042, "Ignoring \"Read secondary ID\" command.\n"); + nack(); + break; + case TrackpointControllerCommand: + DPRINTF(I8042, "Ignoring trackpoint controller command.\n"); + nack(); + break; case Scale1to1: DPRINTF(I8042, "Setting mouse scale to 1:1.\n"); status.twoToOne = 0; @@ -421,10 +437,10 @@ Addr addr = pkt->getAddr(); if (addr == dataPort) { uint8_t data = readDataOut(); - //DPRINTF(I8042, "Read from data port got %#02x.\n", data); + DPRINTF(I8042, "Read from data port got %#02x.\n", data); pkt->set(data); } else if (addr == commandPort) { - //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg); + DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg); pkt->set((uint8_t)statusReg); } else { panic("Read from unrecognized port %#x.\n", addr); @@ -433,6 +449,24 @@ return latency; } +void +X86ISA::I8042::setOutputPorts(uint8_t val) +{ + outputs = val; + if (!outputs.reset) + panic("Keyboard reset not implemented.\n"); + if (!outputs.a20) + panic("A20 gate not implemented.\n"); + if (!outputs.mouse) + mouseIntPin->lower(); + else + mouseIntPin->raise(); + if (!outputs.keyboard) + keyboardIntPin->lower(); + else + keyboardIntPin->raise(); +} + Tick X86ISA::I8042::write(PacketPtr pkt) { @@ -452,11 +486,18 @@ writeData(mouse.getData(), true); } break; - case WriteCommandByte: + case WriteControllerRamVal: commandByte = data; + DPRINTF(I8042, "Setting command byte to %#02x.\n", data); + statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest; + break; + case WriteOutputPort: + DPRINTF(I8042, "Writing %#x to the output ports.\n", data); + break; + case WriteKeyboardOutputBuff: DPRINTF(I8042, "Got data %#02x for \"Write " - "command byte\" command.\n", data); - statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest; + "keyboard output buffer\" command.\n", data); + writeData(data, false); break; case WriteMouseOutputBuff: DPRINTF(I8042, "Got data %#02x for \"Write " @@ -473,92 +514,102 @@ 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: - warn("i8042 \"Write output port\" command not implemented.\n"); - lastCommand = WriteOutputPort; - case WriteKeyboardOutputBuff: - warn("i8042 \"Write keyboard output buffer\" " - "command not implemented.\n"); - lastCommand = WriteKeyboardOutputBuff; - 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: - warn("Write to unknown i8042 " - "(keyboard controller) command port.\n"); + if ((data & ReadControllerRamMask) == ReadControllerRamVal) { + uint8_t offset = data & ~ReadControllerRamMask; + if (!offset) { + DPRINTF(I8042, "Getting command byte.\n"); + writeData(commandByte); + } else { + panic("Attempted to use i8042 read controller RAM command to " + "get byte %d.\n", offset); + } + } else if ((data & WriteControllerRamMask) == WriteControllerRamVal) { + uint8_t offset = data & ~WriteControllerRamMask; + if (!offset) { + DPRINTF(I8042, "Setting command byte.\n"); + lastCommand = data; + } else { + panic("Attempted to use i8042 write controller RAM command to " + "get byte %d.\n", offset); + } + } else if ((data & PulseOutputBitMask) == PulseOutputBitVal) { + DPRINTF(I8042, "Pulsing lower output ports to %#0x.\n", + bits(data, 3, 0)); + uint8_t oldPorts = outputs; + setOutputPorts(mbits(oldPorts, 7, 4) | bits(data, 3, 0)); + setOutputPorts(oldPorts); + } else { + switch (data) { + 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: + DPRINTF(I8042, "Got command to write the output ports.\n"); + lastCommand = WriteOutputPort; + break; + case WriteKeyboardOutputBuff: + DPRINTF(I8042, "Got command to write to " + "keyboard output buffer.\n"); + lastCommand = WriteKeyboardOutputBuff; + break; + 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: + outputs.a20 = 1; + break; + case ReadTestInputs: + panic("i8042 \"Read test inputs\" command not implemented.\n"); + default: + warn("Write to unknown i8042 " + "(keyboard controller) command port %d.\n"); + } } } else { panic("Write to unrecognized port %#x.\n", addr);