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::getAddrRanges() const
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));
57 X86ISA::I8042::writeData(uint8_t newData
, bool mouse
)
59 DPRINTF(I8042
, "Set data %#02x.\n", 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();
67 keyboardIntPin
->lower();
68 } else if (mouse
&& commandByte
.mouseFullInt
) {
69 DPRINTF(I8042
, "Sending mouse interrupt.\n");
77 X86ISA::PS2Device::ack()
79 bufferData(&CommandAck
, sizeof(CommandAck
));
83 X86ISA::PS2Device::nack()
85 bufferData(&CommandNack
, sizeof(CommandNack
));
89 X86ISA::PS2Device::bufferData(const uint8_t *data
, int size
)
91 assert(data
|| size
== 0);
93 outBuffer
.push(*(data
++));
99 X86ISA::I8042::readDataOut()
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);
113 X86ISA::PS2Keyboard::processData(uint8_t data
)
115 if (lastCommand
!= NoCommand
) {
116 switch (lastCommand
) {
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");
124 lastCommand
= NoCommand
;
127 DPRINTF(I8042
, "Setting typematic info to %#02x.\n", data
);
129 lastCommand
= NoCommand
;
136 DPRINTF(I8042
, "Got LED write command.\n");
138 lastCommand
= LEDWrite
;
141 panic("Keyboard diagnostic echo unimplemented.\n");
142 case AlternateScanCodes
:
143 panic("Accessing alternate scan codes unimplemented.\n");
145 DPRINTF(I8042
, "Got keyboard read ID command.\n");
147 bufferData((uint8_t *)&ID
, sizeof(ID
));
150 DPRINTF(I8042
, "Setting typematic info.\n");
152 lastCommand
= TypematicInfo
;
155 DPRINTF(I8042
, "Enabling the keyboard.\n");
159 DPRINTF(I8042
, "Disabling the keyboard.\n");
162 case DefaultsAndDisable
:
163 DPRINTF(I8042
, "Disabling and resetting the keyboard.\n");
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");
171 panic("Setting all keys to make unimplemented.\n");
172 case AllKeysToTypematicMakeRelease
:
173 panic("Setting all keys to "
174 "typematic/make/release unimplemented.\n");
176 panic("Setting a key to typematic unimplemented.\n");
177 case KeyToMakeRelease
:
178 panic("Setting a key to make/release unimplemented.\n");
180 panic("Setting key to make only unimplemented.\n");
182 panic("Keyboard resend unimplemented.\n");
184 panic("Keyboard reset unimplemented.\n");
186 panic("Unknown keyboard command %#02x.\n", data
);
192 X86ISA::PS2Mouse::processData(uint8_t data
)
194 if (lastCommand
!= NoCommand
) {
195 switch(lastCommand
) {
197 DPRINTF(I8042
, "Mouse resolution set to %d.\n", data
);
200 lastCommand
= NoCommand
;
203 DPRINTF(I8042
, "Mouse sample rate %d samples "
204 "per second.\n", data
);
207 lastCommand
= NoCommand
;
210 panic("Not expecting data for a mouse command.\n");
216 DPRINTF(I8042
, "Setting mouse scale to 1:1.\n");
221 DPRINTF(I8042
, "Setting mouse scale to 2:1.\n");
226 DPRINTF(I8042
, "Setting mouse resolution.\n");
227 lastCommand
= SetResolution
;
231 DPRINTF(I8042
, "Getting mouse status.\n");
233 bufferData((uint8_t *)&(status
), 1);
234 bufferData(&resolution
, sizeof(resolution
));
235 bufferData(&sampleRate
, sizeof(sampleRate
));
238 panic("Reading mouse data unimplemented.\n");
240 panic("Resetting mouse wrap mode unimplemented.\n");
242 panic("Setting mouse wrap mode unimplemented.\n");
244 panic("Setting mouse remote mode unimplemented.\n");
246 DPRINTF(I8042
, "Mouse ID requested.\n");
248 bufferData(ID
, sizeof(ID
));
251 DPRINTF(I8042
, "Setting mouse sample rate.\n");
252 lastCommand
= SampleRate
;
255 case DisableReporting
:
256 DPRINTF(I8042
, "Disabling data reporting.\n");
260 case EnableReporting
:
261 DPRINTF(I8042
, "Enabling data reporting.\n");
265 case DefaultsAndDisable
:
266 DPRINTF(I8042
, "Disabling and resetting mouse.\n");
274 panic("Mouse resend unimplemented.\n");
276 DPRINTF(I8042
, "Resetting the mouse.\n");
282 bufferData(&BatSuccessful
, sizeof(BatSuccessful
));
283 bufferData(ID
, sizeof(ID
));
286 warn("Unknown mouse command %#02x.\n", data
);
295 X86ISA::I8042::read(PacketPtr pkt
)
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
);
307 panic("Read from unrecognized port %#x.\n", addr
);
309 pkt
->makeAtomicResponse();
314 X86ISA::I8042::write(PacketPtr pkt
)
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
) {
323 if (keyboard
.processData(data
)) {
324 writeData(keyboard
.getData(), false);
328 if (mouse
.processData(data
)) {
329 writeData(mouse
.getData(), true);
332 case WriteCommandByte
:
334 DPRINTF(I8042
, "Got data %#02x for \"Write "
335 "command byte\" command.\n", data
);
336 statusReg
.passedSelfTest
= (uint8_t)commandByte
.passedSelfTest
;
338 case WriteMouseOutputBuff
:
339 DPRINTF(I8042
, "Got data %#02x for \"Write "
340 "mouse output buffer\" command.\n", data
);
341 writeData(data
, true);
344 panic("Data written for unrecognized "
345 "command %#02x\n", lastCommand
);
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
);
368 DPRINTF(I8042
, "Getting command byte.\n");
369 writeData(commandByte
);
371 case WriteCommandByte
:
372 DPRINTF(I8042
, "Setting command byte.\n");
373 lastCommand
= WriteCommandByte
;
375 case CheckForPassword
:
376 panic("i8042 \"Check for password\" command not implemented.\n");
378 panic("i8042 \"Load password\" command not implemented.\n");
380 panic("i8042 \"Check password\" command not implemented.\n");
382 DPRINTF(I8042
, "Disabling mouse at controller.\n");
383 commandByte
.disableMouse
= 1;
386 DPRINTF(I8042
, "Enabling mouse at controller.\n");
387 commandByte
.disableMouse
= 0;
390 panic("i8042 \"Test mouse\" command not implemented.\n");
392 panic("i8042 \"Self test\" command not implemented.\n");
394 panic("i8042 \"Interface test\" command not implemented.\n");
396 panic("i8042 \"Diagnostic dump\" command not implemented.\n");
397 case DisableKeyboard
:
398 DPRINTF(I8042
, "Disabling keyboard at controller.\n");
399 commandByte
.disableKeyboard
= 1;
402 DPRINTF(I8042
, "Enabling keyboard at controller.\n");
403 commandByte
.disableKeyboard
= 0;
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");
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
;
423 DPRINTF(I8042
, "Expecting mouse command.\n");
424 lastCommand
= WriteToMouse
;
427 panic("i8042 \"Disable A20\" command not implemented.\n");
429 panic("i8042 \"Enable A20\" command not implemented.\n");
431 panic("i8042 \"Read test inputs\" command not implemented.\n");
433 panic("i8042 \"System reset\" command not implemented.\n");
435 panic("Write to unknown i8042 "
436 "(keyboard controller) command port.\n");
439 panic("Write to unrecognized port %#x.\n", addr
);
441 pkt
->makeAtomicResponse();
446 X86ISA::I8042::serialize(std::ostream
&os
)
448 uint8_t statusRegData
= statusReg
.__data
;
449 uint8_t commandByteData
= commandByte
.__data
;
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
);
462 X86ISA::I8042::unserialize(Checkpoint
*cp
, const std::string
§ion
)
464 uint8_t statusRegData
;
465 uint8_t commandByteData
;
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
);
476 statusReg
.__data
= statusRegData
;
477 commandByte
.__data
= commandByteData
;
481 X86ISA::PS2Keyboard::serialize(const std::string
&base
, std::ostream
&os
)
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();
491 arrayParamOut(os
, base
+ ".outBuffer.elts", buffer
,
492 bufferSize
*sizeof(uint8_t));
497 X86ISA::PS2Keyboard::unserialize(const std::string
&base
, Checkpoint
*cp
,
498 const std::string
§ion
)
500 paramIn(cp
, section
, base
+ ".lastCommand", lastCommand
);
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
]);
513 X86ISA::PS2Mouse::serialize(const std::string
&base
, std::ostream
&os
)
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();
524 arrayParamOut(os
, base
+ ".outBuffer.elts", buffer
,
525 bufferSize
*sizeof(uint8_t));
527 paramOut(os
, base
+ ".status", statusData
);
528 paramOut(os
, base
+ ".resolution", resolution
);
529 paramOut(os
, base
+ ".sampleRate", sampleRate
);
533 X86ISA::PS2Mouse::unserialize(const std::string
&base
, Checkpoint
*cp
,
534 const std::string
§ion
)
537 paramIn(cp
, section
, base
+ ".lastCommand", lastCommand
);
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
]);
547 paramIn(cp
, section
, base
+ ".status", statusData
);
548 paramIn(cp
, section
, base
+ ".resolution", resolution
);
549 paramIn(cp
, section
, base
+ ".sampleRate", sampleRate
);
551 status
.__data
= statusData
;
555 I8042Params::create()
557 return new X86ISA::I8042(this);