i8042.cc revision 8711:c7e14f52c682
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 46AddrRangeList 47X86ISA::I8042::getAddrRanges() 48{ 49 AddrRangeList ranges; 50 ranges.push_back(RangeSize(dataPort, 1)); 51 ranges.push_back(RangeSize(commandPort, 1)); 52 return ranges; 53} 54 55void 56X86ISA::I8042::writeData(uint8_t newData, bool mouse) 57{ 58 DPRINTF(I8042, "Set data %#02x.\n", newData); 59 dataReg = newData; 60 statusReg.outputFull = 1; 61 statusReg.mouseOutputFull = (mouse ? 1 : 0); 62 if (!mouse && commandByte.keyboardFullInt) { 63 DPRINTF(I8042, "Sending keyboard interrupt.\n"); 64 keyboardIntPin->raise(); 65 //This is a hack 66 keyboardIntPin->lower(); 67 } else if (mouse && commandByte.mouseFullInt) { 68 DPRINTF(I8042, "Sending mouse interrupt.\n"); 69 mouseIntPin->raise(); 70 //This is a hack 71 mouseIntPin->lower(); 72 } 73} 74 75void 76X86ISA::PS2Device::ack() 77{ 78 bufferData(&CommandAck, sizeof(CommandAck)); 79} 80 81void 82X86ISA::PS2Device::nack() 83{ 84 bufferData(&CommandNack, sizeof(CommandNack)); 85} 86 87void 88X86ISA::PS2Device::bufferData(const uint8_t *data, int size) 89{ 90 assert(data || size == 0); 91 while (size) { 92 outBuffer.push(*(data++)); 93 size--; 94 } 95} 96 97uint8_t 98X86ISA::I8042::readDataOut() 99{ 100 uint8_t data = dataReg; 101 statusReg.outputFull = 0; 102 statusReg.mouseOutputFull = 0; 103 if (keyboard.hasData()) { 104 writeData(keyboard.getData(), false); 105 } else if (mouse.hasData()) { 106 writeData(mouse.getData(), true); 107 } 108 return data; 109} 110 111bool 112X86ISA::PS2Keyboard::processData(uint8_t data) 113{ 114 if (lastCommand != NoCommand) { 115 switch (lastCommand) { 116 case LEDWrite: 117 DPRINTF(I8042, "Setting LEDs: " 118 "caps lock %s, num lock %s, scroll lock %s\n", 119 bits(data, 2) ? "on" : "off", 120 bits(data, 1) ? "on" : "off", 121 bits(data, 0) ? "on" : "off"); 122 ack(); 123 lastCommand = NoCommand; 124 break; 125 case TypematicInfo: 126 DPRINTF(I8042, "Setting typematic info to %#02x.\n", data); 127 ack(); 128 lastCommand = NoCommand; 129 break; 130 } 131 return hasData(); 132 } 133 switch (data) { 134 case LEDWrite: 135 DPRINTF(I8042, "Got LED write command.\n"); 136 ack(); 137 lastCommand = LEDWrite; 138 break; 139 case DiagnosticEcho: 140 panic("Keyboard diagnostic echo unimplemented.\n"); 141 case AlternateScanCodes: 142 panic("Accessing alternate scan codes unimplemented.\n"); 143 case ReadID: 144 DPRINTF(I8042, "Got keyboard read ID command.\n"); 145 ack(); 146 bufferData((uint8_t *)&ID, sizeof(ID)); 147 break; 148 case TypematicInfo: 149 DPRINTF(I8042, "Setting typematic info.\n"); 150 ack(); 151 lastCommand = TypematicInfo; 152 break; 153 case Enable: 154 DPRINTF(I8042, "Enabling the keyboard.\n"); 155 ack(); 156 break; 157 case Disable: 158 DPRINTF(I8042, "Disabling the keyboard.\n"); 159 ack(); 160 break; 161 case DefaultsAndDisable: 162 DPRINTF(I8042, "Disabling and resetting the keyboard.\n"); 163 ack(); 164 break; 165 case AllKeysToTypematic: 166 panic("Setting all keys to typemantic unimplemented.\n"); 167 case AllKeysToMakeRelease: 168 panic("Setting all keys to make/release unimplemented.\n"); 169 case AllKeysToMake: 170 panic("Setting all keys to make unimplemented.\n"); 171 case AllKeysToTypematicMakeRelease: 172 panic("Setting all keys to " 173 "typematic/make/release unimplemented.\n"); 174 case KeyToTypematic: 175 panic("Setting a key to typematic unimplemented.\n"); 176 case KeyToMakeRelease: 177 panic("Setting a key to make/release unimplemented.\n"); 178 case KeyToMakeOnly: 179 panic("Setting key to make only unimplemented.\n"); 180 case Resend: 181 panic("Keyboard resend unimplemented.\n"); 182 case Reset: 183 panic("Keyboard reset unimplemented.\n"); 184 default: 185 panic("Unknown keyboard command %#02x.\n", data); 186 } 187 return hasData(); 188} 189 190bool 191X86ISA::PS2Mouse::processData(uint8_t data) 192{ 193 if (lastCommand != NoCommand) { 194 switch(lastCommand) { 195 case SetResolution: 196 DPRINTF(I8042, "Mouse resolution set to %d.\n", data); 197 resolution = data; 198 ack(); 199 lastCommand = NoCommand; 200 break; 201 case SampleRate: 202 DPRINTF(I8042, "Mouse sample rate %d samples " 203 "per second.\n", data); 204 sampleRate = data; 205 ack(); 206 lastCommand = NoCommand; 207 break; 208 default: 209 panic("Not expecting data for a mouse command.\n"); 210 } 211 return hasData(); 212 } 213 switch (data) { 214 case Scale1to1: 215 DPRINTF(I8042, "Setting mouse scale to 1:1.\n"); 216 status.twoToOne = 0; 217 ack(); 218 break; 219 case Scale2to1: 220 DPRINTF(I8042, "Setting mouse scale to 2:1.\n"); 221 status.twoToOne = 1; 222 ack(); 223 break; 224 case SetResolution: 225 DPRINTF(I8042, "Setting mouse resolution.\n"); 226 lastCommand = SetResolution; 227 ack(); 228 break; 229 case GetStatus: 230 DPRINTF(I8042, "Getting mouse status.\n"); 231 ack(); 232 bufferData((uint8_t *)&(status), 1); 233 bufferData(&resolution, sizeof(resolution)); 234 bufferData(&sampleRate, sizeof(sampleRate)); 235 break; 236 case ReadData: 237 panic("Reading mouse data unimplemented.\n"); 238 case ResetWrapMode: 239 panic("Resetting mouse wrap mode unimplemented.\n"); 240 case WrapMode: 241 panic("Setting mouse wrap mode unimplemented.\n"); 242 case RemoteMode: 243 panic("Setting mouse remote mode unimplemented.\n"); 244 case ReadID: 245 DPRINTF(I8042, "Mouse ID requested.\n"); 246 ack(); 247 bufferData(ID, sizeof(ID)); 248 break; 249 case SampleRate: 250 DPRINTF(I8042, "Setting mouse sample rate.\n"); 251 lastCommand = SampleRate; 252 ack(); 253 break; 254 case DisableReporting: 255 DPRINTF(I8042, "Disabling data reporting.\n"); 256 status.enabled = 0; 257 ack(); 258 break; 259 case EnableReporting: 260 DPRINTF(I8042, "Enabling data reporting.\n"); 261 status.enabled = 1; 262 ack(); 263 break; 264 case DefaultsAndDisable: 265 DPRINTF(I8042, "Disabling and resetting mouse.\n"); 266 sampleRate = 100; 267 resolution = 4; 268 status.twoToOne = 0; 269 status.enabled = 0; 270 ack(); 271 break; 272 case Resend: 273 panic("Mouse resend unimplemented.\n"); 274 case Reset: 275 DPRINTF(I8042, "Resetting the mouse.\n"); 276 sampleRate = 100; 277 resolution = 4; 278 status.twoToOne = 0; 279 status.enabled = 0; 280 ack(); 281 bufferData(&BatSuccessful, sizeof(BatSuccessful)); 282 bufferData(ID, sizeof(ID)); 283 break; 284 default: 285 warn("Unknown mouse command %#02x.\n", data); 286 nack(); 287 break; 288 } 289 return hasData(); 290} 291 292 293Tick 294X86ISA::I8042::read(PacketPtr pkt) 295{ 296 assert(pkt->getSize() == 1); 297 Addr addr = pkt->getAddr(); 298 if (addr == dataPort) { 299 uint8_t data = readDataOut(); 300 //DPRINTF(I8042, "Read from data port got %#02x.\n", data); 301 pkt->set<uint8_t>(data); 302 } else if (addr == commandPort) { 303 //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg); 304 pkt->set<uint8_t>((uint8_t)statusReg); 305 } else { 306 panic("Read from unrecognized port %#x.\n", addr); 307 } 308 pkt->makeAtomicResponse(); 309 return latency; 310} 311 312Tick 313X86ISA::I8042::write(PacketPtr pkt) 314{ 315 assert(pkt->getSize() == 1); 316 Addr addr = pkt->getAddr(); 317 uint8_t data = pkt->get<uint8_t>(); 318 if (addr == dataPort) { 319 statusReg.commandLast = 0; 320 switch (lastCommand) { 321 case NoCommand: 322 if (keyboard.processData(data)) { 323 writeData(keyboard.getData(), false); 324 } 325 break; 326 case WriteToMouse: 327 if (mouse.processData(data)) { 328 writeData(mouse.getData(), true); 329 } 330 break; 331 case WriteCommandByte: 332 commandByte = data; 333 DPRINTF(I8042, "Got data %#02x for \"Write " 334 "command byte\" command.\n", data); 335 statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest; 336 break; 337 case WriteMouseOutputBuff: 338 DPRINTF(I8042, "Got data %#02x for \"Write " 339 "mouse output buffer\" command.\n", data); 340 writeData(data, true); 341 break; 342 default: 343 panic("Data written for unrecognized " 344 "command %#02x\n", lastCommand); 345 } 346 lastCommand = NoCommand; 347 } else if (addr == commandPort) { 348 DPRINTF(I8042, "Got command %#02x.\n", data); 349 statusReg.commandLast = 1; 350 // These purposefully leave off the first byte of the controller RAM 351 // so it can be handled specially. 352 if (data > ReadControllerRamBase && 353 data < ReadControllerRamBase + RamSize) { 354 panic("Attempted to use i8042 read controller RAM command to " 355 "get byte %d.\n", data - ReadControllerRamBase); 356 } else if (data > WriteControllerRamBase && 357 data < WriteControllerRamBase + RamSize) { 358 panic("Attempted to use i8042 read controller RAM command to " 359 "get byte %d.\n", data - ReadControllerRamBase); 360 } else if (data >= PulseOutputBitBase && 361 data < PulseOutputBitBase + NumOutputBits) { 362 panic("Attempted to use i8042 pulse output bit command to " 363 "to pulse bit %d.\n", data - PulseOutputBitBase); 364 } 365 switch (data) { 366 case GetCommandByte: 367 DPRINTF(I8042, "Getting command byte.\n"); 368 writeData(commandByte); 369 break; 370 case WriteCommandByte: 371 DPRINTF(I8042, "Setting command byte.\n"); 372 lastCommand = WriteCommandByte; 373 break; 374 case CheckForPassword: 375 panic("i8042 \"Check for password\" command not implemented.\n"); 376 case LoadPassword: 377 panic("i8042 \"Load password\" command not implemented.\n"); 378 case CheckPassword: 379 panic("i8042 \"Check password\" command not implemented.\n"); 380 case DisableMouse: 381 DPRINTF(I8042, "Disabling mouse at controller.\n"); 382 commandByte.disableMouse = 1; 383 break; 384 case EnableMouse: 385 DPRINTF(I8042, "Enabling mouse at controller.\n"); 386 commandByte.disableMouse = 0; 387 break; 388 case TestMouse: 389 panic("i8042 \"Test mouse\" command not implemented.\n"); 390 case SelfTest: 391 panic("i8042 \"Self test\" command not implemented.\n"); 392 case InterfaceTest: 393 panic("i8042 \"Interface test\" command not implemented.\n"); 394 case DiagnosticDump: 395 panic("i8042 \"Diagnostic dump\" command not implemented.\n"); 396 case DisableKeyboard: 397 DPRINTF(I8042, "Disabling keyboard at controller.\n"); 398 commandByte.disableKeyboard = 1; 399 break; 400 case EnableKeyboard: 401 DPRINTF(I8042, "Enabling keyboard at controller.\n"); 402 commandByte.disableKeyboard = 0; 403 break; 404 case ReadInputPort: 405 panic("i8042 \"Read input port\" command not implemented.\n"); 406 case ContinuousPollLow: 407 panic("i8042 \"Continuous poll low\" command not implemented.\n"); 408 case ContinuousPollHigh: 409 panic("i8042 \"Continuous poll high\" command not implemented.\n"); 410 case ReadOutputPort: 411 panic("i8042 \"Read output port\" command not implemented.\n"); 412 case WriteOutputPort: 413 panic("i8042 \"Write output port\" command not implemented.\n"); 414 case WriteKeyboardOutputBuff: 415 panic("i8042 \"Write keyboard output buffer\" " 416 "command not implemented.\n"); 417 case WriteMouseOutputBuff: 418 DPRINTF(I8042, "Got command to write to mouse output buffer.\n"); 419 lastCommand = WriteMouseOutputBuff; 420 break; 421 case WriteToMouse: 422 DPRINTF(I8042, "Expecting mouse command.\n"); 423 lastCommand = WriteToMouse; 424 break; 425 case DisableA20: 426 panic("i8042 \"Disable A20\" command not implemented.\n"); 427 case EnableA20: 428 panic("i8042 \"Enable A20\" command not implemented.\n"); 429 case ReadTestInputs: 430 panic("i8042 \"Read test inputs\" command not implemented.\n"); 431 case SystemReset: 432 panic("i8042 \"System reset\" command not implemented.\n"); 433 default: 434 panic("Write to unknown i8042 " 435 "(keyboard controller) command port.\n"); 436 } 437 } else { 438 panic("Write to unrecognized port %#x.\n", addr); 439 } 440 pkt->makeAtomicResponse(); 441 return latency; 442} 443 444void 445X86ISA::I8042::serialize(std::ostream &os) 446{ 447 uint8_t statusRegData = statusReg.__data; 448 uint8_t commandByteData = commandByte.__data; 449 450 SERIALIZE_SCALAR(dataPort); 451 SERIALIZE_SCALAR(commandPort); 452 SERIALIZE_SCALAR(statusRegData); 453 SERIALIZE_SCALAR(commandByteData); 454 SERIALIZE_SCALAR(dataReg); 455 SERIALIZE_SCALAR(lastCommand); 456 mouse.serialize("mouse", os); 457 keyboard.serialize("keyboard", os); 458} 459 460void 461X86ISA::I8042::unserialize(Checkpoint *cp, const std::string §ion) 462{ 463 uint8_t statusRegData; 464 uint8_t commandByteData; 465 466 UNSERIALIZE_SCALAR(dataPort); 467 UNSERIALIZE_SCALAR(commandPort); 468 UNSERIALIZE_SCALAR(statusRegData); 469 UNSERIALIZE_SCALAR(commandByteData); 470 UNSERIALIZE_SCALAR(dataReg); 471 UNSERIALIZE_SCALAR(lastCommand); 472 mouse.unserialize("mouse", cp, section); 473 keyboard.unserialize("keyboard", cp, section); 474 475 statusReg.__data = statusRegData; 476 commandByte.__data = commandByteData; 477} 478 479void 480X86ISA::PS2Keyboard::serialize(const std::string &base, std::ostream &os) 481{ 482 paramOut(os, base + ".lastCommand", lastCommand); 483 int bufferSize = outBuffer.size(); 484 paramOut(os, base + ".outBuffer.size", bufferSize); 485 uint8_t *buffer = new uint8_t[bufferSize]; 486 for (int i = 0; i < bufferSize; ++i) { 487 buffer[i] = outBuffer.front(); 488 outBuffer.pop(); 489 } 490 arrayParamOut(os, base + ".outBuffer.elts", buffer, 491 bufferSize*sizeof(uint8_t)); 492 delete buffer; 493} 494 495void 496X86ISA::PS2Keyboard::unserialize(const std::string &base, Checkpoint *cp, 497 const std::string §ion) 498{ 499 paramIn(cp, section, base + ".lastCommand", lastCommand); 500 int bufferSize; 501 paramIn(cp, section, base + ".outBuffer.size", bufferSize); 502 uint8_t *buffer = new uint8_t[bufferSize]; 503 arrayParamIn(cp, section, base + ".outBuffer.elts", buffer, 504 bufferSize*sizeof(uint8_t)); 505 for (int i = 0; i < bufferSize; ++i) { 506 outBuffer.push(buffer[i]); 507 } 508 delete buffer; 509} 510 511void 512X86ISA::PS2Mouse::serialize(const std::string &base, std::ostream &os) 513{ 514 uint8_t statusData = status.__data; 515 paramOut(os, base + ".lastCommand", lastCommand); 516 int bufferSize = outBuffer.size(); 517 paramOut(os, base + ".outBuffer.size", bufferSize); 518 uint8_t *buffer = new uint8_t[bufferSize]; 519 for (int i = 0; i < bufferSize; ++i) { 520 buffer[i] = outBuffer.front(); 521 outBuffer.pop(); 522 } 523 arrayParamOut(os, base + ".outBuffer.elts", buffer, 524 bufferSize*sizeof(uint8_t)); 525 delete buffer; 526 paramOut(os, base + ".status", statusData); 527 paramOut(os, base + ".resolution", resolution); 528 paramOut(os, base + ".sampleRate", sampleRate); 529} 530 531void 532X86ISA::PS2Mouse::unserialize(const std::string &base, Checkpoint *cp, 533 const std::string §ion) 534{ 535 uint8_t statusData; 536 paramIn(cp, section, base + ".lastCommand", lastCommand); 537 int bufferSize; 538 paramIn(cp, section, base + ".outBuffer.size", bufferSize); 539 uint8_t *buffer = new uint8_t[bufferSize]; 540 arrayParamIn(cp, section, base + ".outBuffer.elts", buffer, 541 bufferSize*sizeof(uint8_t)); 542 for (int i = 0; i < bufferSize; ++i) { 543 outBuffer.push(buffer[i]); 544 } 545 delete buffer; 546 paramIn(cp, section, base + ".status", statusData); 547 paramIn(cp, section, base + ".resolution", resolution); 548 paramIn(cp, section, base + ".sampleRate", sampleRate); 549 550 status.__data = statusData; 551} 552 553X86ISA::I8042 * 554I8042Params::create() 555{ 556 return new X86ISA::I8042(this); 557} 558