2 * Copyright (c) 2008 The Regents of The University of Michigan
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.
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.
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"
37 // The 8042 has a whopping 32 bytes of internal RAM.
38 const uint8_t RamSize
= 32;
39 const uint8_t NumOutputBits
= 14;
40 const uint8_t X86ISA::PS2Keyboard::ID
[] = {0xab, 0x83};
41 const uint8_t X86ISA::PS2Mouse::ID
[] = {0x00};
42 const uint8_t CommandAck
= 0xfa;
43 const uint8_t CommandNack
= 0xfe;
44 const uint8_t BatSuccessful
= 0xaa;
47 X86ISA::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
)
54 statusReg
.passedSelfTest
= 1;
55 statusReg
.commandLast
= 1;
56 statusReg
.keyboardUnlocked
= 1;
58 commandByte
.convertScanCodes
= 1;
59 commandByte
.passedSelfTest
= 1;
60 commandByte
.keyboardFullInt
= 1;
65 X86ISA::I8042::getAddrRanges() const
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));
75 X86ISA::I8042::writeData(uint8_t newData
, bool mouse
)
77 DPRINTF(I8042
, "Set data %#02x.\n", 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();
85 keyboardIntPin
->lower();
86 } else if (mouse
&& commandByte
.mouseFullInt
) {
87 DPRINTF(I8042
, "Sending mouse interrupt.\n");
95 X86ISA::PS2Device::serialize(const std::string
&base
, CheckpointOut
&cp
) const
97 paramOut(cp
, base
+ ".lastCommand", lastCommand
);
99 std::vector
<uint8_t> buffer(outBuffer
.size());
100 std::copy(outBuffer
.begin(), outBuffer
.end(), buffer
.begin());
101 arrayParamOut(cp
, base
+ ".outBuffer.elts", buffer
);
105 X86ISA::PS2Device::unserialize(const std::string
&base
, CheckpointIn
&cp
)
107 paramIn(cp
, base
+ ".lastCommand", lastCommand
);
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
);
118 X86ISA::PS2Device::ack()
120 bufferData(&CommandAck
, sizeof(CommandAck
));
124 X86ISA::PS2Device::nack()
126 bufferData(&CommandNack
, sizeof(CommandNack
));
130 X86ISA::PS2Device::bufferData(const uint8_t *data
, int size
)
132 assert(data
|| size
== 0);
134 outBuffer
.push_back(*(data
++));
140 X86ISA::I8042::readDataOut()
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);
154 X86ISA::PS2Keyboard::processData(uint8_t data
)
156 if (lastCommand
!= NoCommand
) {
157 switch (lastCommand
) {
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");
165 lastCommand
= NoCommand
;
168 DPRINTF(I8042
, "Setting typematic info to %#02x.\n", data
);
170 lastCommand
= NoCommand
;
177 DPRINTF(I8042
, "Got LED write command.\n");
179 lastCommand
= LEDWrite
;
182 panic("Keyboard diagnostic echo unimplemented.\n");
183 case AlternateScanCodes
:
184 panic("Accessing alternate scan codes unimplemented.\n");
186 DPRINTF(I8042
, "Got keyboard read ID command.\n");
188 bufferData((uint8_t *)&ID
, sizeof(ID
));
191 DPRINTF(I8042
, "Setting typematic info.\n");
193 lastCommand
= TypematicInfo
;
196 DPRINTF(I8042
, "Enabling the keyboard.\n");
200 DPRINTF(I8042
, "Disabling the keyboard.\n");
203 case DefaultsAndDisable
:
204 DPRINTF(I8042
, "Disabling and resetting the keyboard.\n");
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");
212 panic("Setting all keys to make unimplemented.\n");
213 case AllKeysToTypematicMakeRelease
:
214 panic("Setting all keys to "
215 "typematic/make/release unimplemented.\n");
217 panic("Setting a key to typematic unimplemented.\n");
218 case KeyToMakeRelease
:
219 panic("Setting a key to make/release unimplemented.\n");
221 panic("Setting key to make only unimplemented.\n");
223 panic("Keyboard resend unimplemented.\n");
225 panic("Keyboard reset unimplemented.\n");
227 panic("Unknown keyboard command %#02x.\n", data
);
233 X86ISA::PS2Mouse::processData(uint8_t data
)
235 if (lastCommand
!= NoCommand
) {
236 switch(lastCommand
) {
238 DPRINTF(I8042
, "Mouse resolution set to %d.\n", data
);
241 lastCommand
= NoCommand
;
244 DPRINTF(I8042
, "Mouse sample rate %d samples "
245 "per second.\n", data
);
248 lastCommand
= NoCommand
;
251 panic("Not expecting data for a mouse command.\n");
257 DPRINTF(I8042
, "Setting mouse scale to 1:1.\n");
262 DPRINTF(I8042
, "Setting mouse scale to 2:1.\n");
267 DPRINTF(I8042
, "Setting mouse resolution.\n");
268 lastCommand
= SetResolution
;
272 DPRINTF(I8042
, "Getting mouse status.\n");
274 bufferData((uint8_t *)&(status
), 1);
275 bufferData(&resolution
, sizeof(resolution
));
276 bufferData(&sampleRate
, sizeof(sampleRate
));
279 panic("Reading mouse data unimplemented.\n");
281 panic("Resetting mouse wrap mode unimplemented.\n");
283 panic("Setting mouse wrap mode unimplemented.\n");
285 panic("Setting mouse remote mode unimplemented.\n");
287 DPRINTF(I8042
, "Mouse ID requested.\n");
289 bufferData(ID
, sizeof(ID
));
292 DPRINTF(I8042
, "Setting mouse sample rate.\n");
293 lastCommand
= SampleRate
;
296 case DisableReporting
:
297 DPRINTF(I8042
, "Disabling data reporting.\n");
301 case EnableReporting
:
302 DPRINTF(I8042
, "Enabling data reporting.\n");
306 case DefaultsAndDisable
:
307 DPRINTF(I8042
, "Disabling and resetting mouse.\n");
315 panic("Mouse resend unimplemented.\n");
317 DPRINTF(I8042
, "Resetting the mouse.\n");
323 bufferData(&BatSuccessful
, sizeof(BatSuccessful
));
324 bufferData(ID
, sizeof(ID
));
327 warn("Unknown mouse command %#02x.\n", data
);
336 X86ISA::I8042::read(PacketPtr pkt
)
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
);
348 panic("Read from unrecognized port %#x.\n", addr
);
350 pkt
->makeAtomicResponse();
355 X86ISA::I8042::write(PacketPtr pkt
)
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
) {
364 if (keyboard
.processData(data
)) {
365 writeData(keyboard
.getData(), false);
369 if (mouse
.processData(data
)) {
370 writeData(mouse
.getData(), true);
373 case WriteCommandByte
:
375 DPRINTF(I8042
, "Got data %#02x for \"Write "
376 "command byte\" command.\n", data
);
377 statusReg
.passedSelfTest
= (uint8_t)commandByte
.passedSelfTest
;
379 case WriteMouseOutputBuff
:
380 DPRINTF(I8042
, "Got data %#02x for \"Write "
381 "mouse output buffer\" command.\n", data
);
382 writeData(data
, true);
385 panic("Data written for unrecognized "
386 "command %#02x\n", lastCommand
);
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
);
409 DPRINTF(I8042
, "Getting command byte.\n");
410 writeData(commandByte
);
412 case WriteCommandByte
:
413 DPRINTF(I8042
, "Setting command byte.\n");
414 lastCommand
= WriteCommandByte
;
416 case CheckForPassword
:
417 panic("i8042 \"Check for password\" command not implemented.\n");
419 panic("i8042 \"Load password\" command not implemented.\n");
421 panic("i8042 \"Check password\" command not implemented.\n");
423 DPRINTF(I8042
, "Disabling mouse at controller.\n");
424 commandByte
.disableMouse
= 1;
427 DPRINTF(I8042
, "Enabling mouse at controller.\n");
428 commandByte
.disableMouse
= 0;
431 panic("i8042 \"Test mouse\" command not implemented.\n");
433 panic("i8042 \"Self test\" command not implemented.\n");
435 panic("i8042 \"Interface test\" command not implemented.\n");
437 panic("i8042 \"Diagnostic dump\" command not implemented.\n");
438 case DisableKeyboard
:
439 DPRINTF(I8042
, "Disabling keyboard at controller.\n");
440 commandByte
.disableKeyboard
= 1;
443 DPRINTF(I8042
, "Enabling keyboard at controller.\n");
444 commandByte
.disableKeyboard
= 0;
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");
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
;
466 DPRINTF(I8042
, "Expecting mouse command.\n");
467 lastCommand
= WriteToMouse
;
470 panic("i8042 \"Disable A20\" command not implemented.\n");
472 panic("i8042 \"Enable A20\" command not implemented.\n");
474 panic("i8042 \"Read test inputs\" command not implemented.\n");
476 panic("i8042 \"System reset\" command not implemented.\n");
478 warn("Write to unknown i8042 "
479 "(keyboard controller) command port.\n");
482 panic("Write to unrecognized port %#x.\n", addr
);
484 pkt
->makeAtomicResponse();
489 X86ISA::I8042::serialize(CheckpointOut
&cp
) const
491 uint8_t statusRegData
= statusReg
.__data
;
492 uint8_t commandByteData
= commandByte
.__data
;
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
);
505 X86ISA::I8042::unserialize(CheckpointIn
&cp
)
507 uint8_t statusRegData
;
508 uint8_t commandByteData
;
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
);
519 statusReg
.__data
= statusRegData
;
520 commandByte
.__data
= commandByteData
;
524 X86ISA::PS2Mouse::serialize(const std::string
&base
, CheckpointOut
&cp
) const
526 PS2Device::serialize(base
, cp
);
528 paramOut(cp
, base
+ ".status", status
);
529 paramOut(cp
, base
+ ".resolution", resolution
);
530 paramOut(cp
, base
+ ".sampleRate", sampleRate
);
534 X86ISA::PS2Mouse::unserialize(const std::string
&base
, CheckpointIn
&cp
)
536 PS2Device::unserialize(base
, cp
);
538 paramIn(cp
, base
+ ".status", status
);
539 paramIn(cp
, base
+ ".resolution", resolution
);
540 paramIn(cp
, base
+ ".sampleRate", sampleRate
);
544 I8042Params::create()
546 return new X86ISA::I8042(this);