i8042.cc revision 11320:42ecb523c64a
1/* 2 * Copyright (c) 2008 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Gabe Black 29 */ 30 31#include "base/bitunion.hh" 32#include "debug/I8042.hh" 33#include "dev/x86/i8042.hh" 34#include "mem/packet.hh" 35#include "mem/packet_access.hh" 36 37// The 8042 has a whopping 32 bytes of internal RAM. 38const uint8_t RamSize = 32; 39const uint8_t NumOutputBits = 14; 40const uint8_t X86ISA::PS2Keyboard::ID[] = {0xab, 0x83}; 41const uint8_t X86ISA::PS2Mouse::ID[] = {0x00}; 42const uint8_t CommandAck = 0xfa; 43const uint8_t CommandNack = 0xfe; 44const uint8_t BatSuccessful = 0xaa; 45 46 47X86ISA::I8042::I8042(Params *p) 48 : BasicPioDevice(p, 0), // pioSize arg is dummy value... not used 49 latency(p->pio_latency), 50 dataPort(p->data_port), commandPort(p->command_port), 51 statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand), 52 mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin) 53{ 54 statusReg.passedSelfTest = 1; 55 statusReg.commandLast = 1; 56 statusReg.keyboardUnlocked = 1; 57 58 commandByte.convertScanCodes = 1; 59 commandByte.passedSelfTest = 1; 60 commandByte.keyboardFullInt = 1; 61} 62 63 64AddrRangeList 65X86ISA::I8042::getAddrRanges() const 66{ 67 AddrRangeList ranges; 68 // TODO: Are these really supposed to be a single byte and not 4? 69 ranges.push_back(RangeSize(dataPort, 1)); 70 ranges.push_back(RangeSize(commandPort, 1)); 71 return ranges; 72} 73 74void 75X86ISA::I8042::writeData(uint8_t newData, bool mouse) 76{ 77 DPRINTF(I8042, "Set data %#02x.\n", newData); 78 dataReg = newData; 79 statusReg.outputFull = 1; 80 statusReg.mouseOutputFull = (mouse ? 1 : 0); 81 if (!mouse && commandByte.keyboardFullInt) { 82 DPRINTF(I8042, "Sending keyboard interrupt.\n"); 83 keyboardIntPin->raise(); 84 //This is a hack 85 keyboardIntPin->lower(); 86 } else if (mouse && commandByte.mouseFullInt) { 87 DPRINTF(I8042, "Sending mouse interrupt.\n"); 88 mouseIntPin->raise(); 89 //This is a hack 90 mouseIntPin->lower(); 91 } 92} 93 94void 95X86ISA::PS2Device::serialize(const std::string &base, CheckpointOut &cp) const 96{ 97 paramOut(cp, base + ".lastCommand", lastCommand); 98 99 std::vector<uint8_t> buffer(outBuffer.size()); 100 std::copy(outBuffer.begin(), outBuffer.end(), buffer.begin()); 101 arrayParamOut(cp, base + ".outBuffer.elts", buffer); 102} 103 104void 105X86ISA::PS2Device::unserialize(const std::string &base, CheckpointIn &cp) 106{ 107 paramIn(cp, base + ".lastCommand", lastCommand); 108 109 std::vector<uint8_t> buffer; 110 arrayParamIn(cp, base + ".outBuffer.elts", buffer); 111 assert(outBuffer.empty()); 112 for (auto c : buffer) 113 outBuffer.push_back(c); 114} 115 116 117void 118X86ISA::PS2Device::ack() 119{ 120 bufferData(&CommandAck, sizeof(CommandAck)); 121} 122 123void 124X86ISA::PS2Device::nack() 125{ 126 bufferData(&CommandNack, sizeof(CommandNack)); 127} 128 129void 130X86ISA::PS2Device::bufferData(const uint8_t *data, int size) 131{ 132 assert(data || size == 0); 133 while (size) { 134 outBuffer.push_back(*(data++)); 135 size--; 136 } 137} 138 139uint8_t 140X86ISA::I8042::readDataOut() 141{ 142 uint8_t data = dataReg; 143 statusReg.outputFull = 0; 144 statusReg.mouseOutputFull = 0; 145 if (keyboard.hasData()) { 146 writeData(keyboard.getData(), false); 147 } else if (mouse.hasData()) { 148 writeData(mouse.getData(), true); 149 } 150 return data; 151} 152 153bool 154X86ISA::PS2Keyboard::processData(uint8_t data) 155{ 156 if (lastCommand != NoCommand) { 157 switch (lastCommand) { 158 case LEDWrite: 159 DPRINTF(I8042, "Setting LEDs: " 160 "caps lock %s, num lock %s, scroll lock %s\n", 161 bits(data, 2) ? "on" : "off", 162 bits(data, 1) ? "on" : "off", 163 bits(data, 0) ? "on" : "off"); 164 ack(); 165 lastCommand = NoCommand; 166 break; 167 case TypematicInfo: 168 DPRINTF(I8042, "Setting typematic info to %#02x.\n", data); 169 ack(); 170 lastCommand = NoCommand; 171 break; 172 } 173 return hasData(); 174 } 175 switch (data) { 176 case LEDWrite: 177 DPRINTF(I8042, "Got LED write command.\n"); 178 ack(); 179 lastCommand = LEDWrite; 180 break; 181 case DiagnosticEcho: 182 panic("Keyboard diagnostic echo unimplemented.\n"); 183 case AlternateScanCodes: 184 panic("Accessing alternate scan codes unimplemented.\n"); 185 case ReadID: 186 DPRINTF(I8042, "Got keyboard read ID command.\n"); 187 ack(); 188 bufferData((uint8_t *)&ID, sizeof(ID)); 189 break; 190 case TypematicInfo: 191 DPRINTF(I8042, "Setting typematic info.\n"); 192 ack(); 193 lastCommand = TypematicInfo; 194 break; 195 case Enable: 196 DPRINTF(I8042, "Enabling the keyboard.\n"); 197 ack(); 198 break; 199 case Disable: 200 DPRINTF(I8042, "Disabling the keyboard.\n"); 201 ack(); 202 break; 203 case DefaultsAndDisable: 204 DPRINTF(I8042, "Disabling and resetting the keyboard.\n"); 205 ack(); 206 break; 207 case AllKeysToTypematic: 208 panic("Setting all keys to typemantic unimplemented.\n"); 209 case AllKeysToMakeRelease: 210 panic("Setting all keys to make/release unimplemented.\n"); 211 case AllKeysToMake: 212 panic("Setting all keys to make unimplemented.\n"); 213 case AllKeysToTypematicMakeRelease: 214 panic("Setting all keys to " 215 "typematic/make/release unimplemented.\n"); 216 case KeyToTypematic: 217 panic("Setting a key to typematic unimplemented.\n"); 218 case KeyToMakeRelease: 219 panic("Setting a key to make/release unimplemented.\n"); 220 case KeyToMakeOnly: 221 panic("Setting key to make only unimplemented.\n"); 222 case Resend: 223 panic("Keyboard resend unimplemented.\n"); 224 case Reset: 225 panic("Keyboard reset unimplemented.\n"); 226 default: 227 panic("Unknown keyboard command %#02x.\n", data); 228 } 229 return hasData(); 230} 231 232bool 233X86ISA::PS2Mouse::processData(uint8_t data) 234{ 235 if (lastCommand != NoCommand) { 236 switch(lastCommand) { 237 case SetResolution: 238 DPRINTF(I8042, "Mouse resolution set to %d.\n", data); 239 resolution = data; 240 ack(); 241 lastCommand = NoCommand; 242 break; 243 case SampleRate: 244 DPRINTF(I8042, "Mouse sample rate %d samples " 245 "per second.\n", data); 246 sampleRate = data; 247 ack(); 248 lastCommand = NoCommand; 249 break; 250 default: 251 panic("Not expecting data for a mouse command.\n"); 252 } 253 return hasData(); 254 } 255 switch (data) { 256 case Scale1to1: 257 DPRINTF(I8042, "Setting mouse scale to 1:1.\n"); 258 status.twoToOne = 0; 259 ack(); 260 break; 261 case Scale2to1: 262 DPRINTF(I8042, "Setting mouse scale to 2:1.\n"); 263 status.twoToOne = 1; 264 ack(); 265 break; 266 case SetResolution: 267 DPRINTF(I8042, "Setting mouse resolution.\n"); 268 lastCommand = SetResolution; 269 ack(); 270 break; 271 case GetStatus: 272 DPRINTF(I8042, "Getting mouse status.\n"); 273 ack(); 274 bufferData((uint8_t *)&(status), 1); 275 bufferData(&resolution, sizeof(resolution)); 276 bufferData(&sampleRate, sizeof(sampleRate)); 277 break; 278 case ReadData: 279 panic("Reading mouse data unimplemented.\n"); 280 case ResetWrapMode: 281 panic("Resetting mouse wrap mode unimplemented.\n"); 282 case WrapMode: 283 panic("Setting mouse wrap mode unimplemented.\n"); 284 case RemoteMode: 285 panic("Setting mouse remote mode unimplemented.\n"); 286 case ReadID: 287 DPRINTF(I8042, "Mouse ID requested.\n"); 288 ack(); 289 bufferData(ID, sizeof(ID)); 290 break; 291 case SampleRate: 292 DPRINTF(I8042, "Setting mouse sample rate.\n"); 293 lastCommand = SampleRate; 294 ack(); 295 break; 296 case DisableReporting: 297 DPRINTF(I8042, "Disabling data reporting.\n"); 298 status.enabled = 0; 299 ack(); 300 break; 301 case EnableReporting: 302 DPRINTF(I8042, "Enabling data reporting.\n"); 303 status.enabled = 1; 304 ack(); 305 break; 306 case DefaultsAndDisable: 307 DPRINTF(I8042, "Disabling and resetting mouse.\n"); 308 sampleRate = 100; 309 resolution = 4; 310 status.twoToOne = 0; 311 status.enabled = 0; 312 ack(); 313 break; 314 case Resend: 315 panic("Mouse resend unimplemented.\n"); 316 case Reset: 317 DPRINTF(I8042, "Resetting the mouse.\n"); 318 sampleRate = 100; 319 resolution = 4; 320 status.twoToOne = 0; 321 status.enabled = 0; 322 ack(); 323 bufferData(&BatSuccessful, sizeof(BatSuccessful)); 324 bufferData(ID, sizeof(ID)); 325 break; 326 default: 327 warn("Unknown mouse command %#02x.\n", data); 328 nack(); 329 break; 330 } 331 return hasData(); 332} 333 334 335Tick 336X86ISA::I8042::read(PacketPtr pkt) 337{ 338 assert(pkt->getSize() == 1); 339 Addr addr = pkt->getAddr(); 340 if (addr == dataPort) { 341 uint8_t data = readDataOut(); 342 //DPRINTF(I8042, "Read from data port got %#02x.\n", data); 343 pkt->set<uint8_t>(data); 344 } else if (addr == commandPort) { 345 //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg); 346 pkt->set<uint8_t>((uint8_t)statusReg); 347 } else { 348 panic("Read from unrecognized port %#x.\n", addr); 349 } 350 pkt->makeAtomicResponse(); 351 return latency; 352} 353 354Tick 355X86ISA::I8042::write(PacketPtr pkt) 356{ 357 assert(pkt->getSize() == 1); 358 Addr addr = pkt->getAddr(); 359 uint8_t data = pkt->get<uint8_t>(); 360 if (addr == dataPort) { 361 statusReg.commandLast = 0; 362 switch (lastCommand) { 363 case NoCommand: 364 if (keyboard.processData(data)) { 365 writeData(keyboard.getData(), false); 366 } 367 break; 368 case WriteToMouse: 369 if (mouse.processData(data)) { 370 writeData(mouse.getData(), true); 371 } 372 break; 373 case WriteCommandByte: 374 commandByte = data; 375 DPRINTF(I8042, "Got data %#02x for \"Write " 376 "command byte\" command.\n", data); 377 statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest; 378 break; 379 case WriteMouseOutputBuff: 380 DPRINTF(I8042, "Got data %#02x for \"Write " 381 "mouse output buffer\" command.\n", data); 382 writeData(data, true); 383 break; 384 default: 385 panic("Data written for unrecognized " 386 "command %#02x\n", lastCommand); 387 } 388 lastCommand = NoCommand; 389 } else if (addr == commandPort) { 390 DPRINTF(I8042, "Got command %#02x.\n", data); 391 statusReg.commandLast = 1; 392 // These purposefully leave off the first byte of the controller RAM 393 // so it can be handled specially. 394 if (data > ReadControllerRamBase && 395 data < ReadControllerRamBase + RamSize) { 396 panic("Attempted to use i8042 read controller RAM command to " 397 "get byte %d.\n", data - ReadControllerRamBase); 398 } else if (data > WriteControllerRamBase && 399 data < WriteControllerRamBase + RamSize) { 400 panic("Attempted to use i8042 read controller RAM command to " 401 "get byte %d.\n", data - ReadControllerRamBase); 402 } else if (data >= PulseOutputBitBase && 403 data < PulseOutputBitBase + NumOutputBits) { 404 panic("Attempted to use i8042 pulse output bit command to " 405 "to pulse bit %d.\n", data - PulseOutputBitBase); 406 } 407 switch (data) { 408 case GetCommandByte: 409 DPRINTF(I8042, "Getting command byte.\n"); 410 writeData(commandByte); 411 break; 412 case WriteCommandByte: 413 DPRINTF(I8042, "Setting command byte.\n"); 414 lastCommand = WriteCommandByte; 415 break; 416 case CheckForPassword: 417 panic("i8042 \"Check for password\" command not implemented.\n"); 418 case LoadPassword: 419 panic("i8042 \"Load password\" command not implemented.\n"); 420 case CheckPassword: 421 panic("i8042 \"Check password\" command not implemented.\n"); 422 case DisableMouse: 423 DPRINTF(I8042, "Disabling mouse at controller.\n"); 424 commandByte.disableMouse = 1; 425 break; 426 case EnableMouse: 427 DPRINTF(I8042, "Enabling mouse at controller.\n"); 428 commandByte.disableMouse = 0; 429 break; 430 case TestMouse: 431 panic("i8042 \"Test mouse\" command not implemented.\n"); 432 case SelfTest: 433 panic("i8042 \"Self test\" command not implemented.\n"); 434 case InterfaceTest: 435 panic("i8042 \"Interface test\" command not implemented.\n"); 436 case DiagnosticDump: 437 panic("i8042 \"Diagnostic dump\" command not implemented.\n"); 438 case DisableKeyboard: 439 DPRINTF(I8042, "Disabling keyboard at controller.\n"); 440 commandByte.disableKeyboard = 1; 441 break; 442 case EnableKeyboard: 443 DPRINTF(I8042, "Enabling keyboard at controller.\n"); 444 commandByte.disableKeyboard = 0; 445 break; 446 case ReadInputPort: 447 panic("i8042 \"Read input port\" command not implemented.\n"); 448 case ContinuousPollLow: 449 panic("i8042 \"Continuous poll low\" command not implemented.\n"); 450 case ContinuousPollHigh: 451 panic("i8042 \"Continuous poll high\" command not implemented.\n"); 452 case ReadOutputPort: 453 panic("i8042 \"Read output port\" command not implemented.\n"); 454 case WriteOutputPort: 455 warn("i8042 \"Write output port\" command not implemented.\n"); 456 lastCommand = WriteOutputPort; 457 case WriteKeyboardOutputBuff: 458 warn("i8042 \"Write keyboard output buffer\" " 459 "command not implemented.\n"); 460 lastCommand = WriteKeyboardOutputBuff; 461 case WriteMouseOutputBuff: 462 DPRINTF(I8042, "Got command to write to mouse output buffer.\n"); 463 lastCommand = WriteMouseOutputBuff; 464 break; 465 case WriteToMouse: 466 DPRINTF(I8042, "Expecting mouse command.\n"); 467 lastCommand = WriteToMouse; 468 break; 469 case DisableA20: 470 panic("i8042 \"Disable A20\" command not implemented.\n"); 471 case EnableA20: 472 panic("i8042 \"Enable A20\" command not implemented.\n"); 473 case ReadTestInputs: 474 panic("i8042 \"Read test inputs\" command not implemented.\n"); 475 case SystemReset: 476 panic("i8042 \"System reset\" command not implemented.\n"); 477 default: 478 warn("Write to unknown i8042 " 479 "(keyboard controller) command port.\n"); 480 } 481 } else { 482 panic("Write to unrecognized port %#x.\n", addr); 483 } 484 pkt->makeAtomicResponse(); 485 return latency; 486} 487 488void 489X86ISA::I8042::serialize(CheckpointOut &cp) const 490{ 491 uint8_t statusRegData = statusReg.__data; 492 uint8_t commandByteData = commandByte.__data; 493 494 SERIALIZE_SCALAR(dataPort); 495 SERIALIZE_SCALAR(commandPort); 496 SERIALIZE_SCALAR(statusRegData); 497 SERIALIZE_SCALAR(commandByteData); 498 SERIALIZE_SCALAR(dataReg); 499 SERIALIZE_SCALAR(lastCommand); 500 mouse.serialize("mouse", cp); 501 keyboard.serialize("keyboard", cp); 502} 503 504void 505X86ISA::I8042::unserialize(CheckpointIn &cp) 506{ 507 uint8_t statusRegData; 508 uint8_t commandByteData; 509 510 UNSERIALIZE_SCALAR(dataPort); 511 UNSERIALIZE_SCALAR(commandPort); 512 UNSERIALIZE_SCALAR(statusRegData); 513 UNSERIALIZE_SCALAR(commandByteData); 514 UNSERIALIZE_SCALAR(dataReg); 515 UNSERIALIZE_SCALAR(lastCommand); 516 mouse.unserialize("mouse", cp); 517 keyboard.unserialize("keyboard", cp); 518 519 statusReg.__data = statusRegData; 520 commandByte.__data = commandByteData; 521} 522 523void 524X86ISA::PS2Mouse::serialize(const std::string &base, CheckpointOut &cp) const 525{ 526 PS2Device::serialize(base, cp); 527 528 paramOut(cp, base + ".status", status); 529 paramOut(cp, base + ".resolution", resolution); 530 paramOut(cp, base + ".sampleRate", sampleRate); 531} 532 533void 534X86ISA::PS2Mouse::unserialize(const std::string &base, CheckpointIn &cp) 535{ 536 PS2Device::unserialize(base, cp); 537 538 paramIn(cp, base + ".status", status); 539 paramIn(cp, base + ".resolution", resolution); 540 paramIn(cp, base + ".sampleRate", sampleRate); 541} 542 543X86ISA::I8042 * 544I8042Params::create() 545{ 546 return new X86ISA::I8042(this); 547} 548