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