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::ack()
97 bufferData(&CommandAck
, sizeof(CommandAck
));
101 X86ISA::PS2Device::nack()
103 bufferData(&CommandNack
, sizeof(CommandNack
));
107 X86ISA::PS2Device::bufferData(const uint8_t *data
, int size
)
109 assert(data
|| size
== 0);
111 outBuffer
.push(*(data
++));
117 X86ISA::I8042::readDataOut()
119 uint8_t data
= dataReg
;
120 statusReg
.outputFull
= 0;
121 statusReg
.mouseOutputFull
= 0;
122 if (keyboard
.hasData()) {
123 writeData(keyboard
.getData(), false);
124 } else if (mouse
.hasData()) {
125 writeData(mouse
.getData(), true);
131 X86ISA::PS2Keyboard::processData(uint8_t data
)
133 if (lastCommand
!= NoCommand
) {
134 switch (lastCommand
) {
136 DPRINTF(I8042
, "Setting LEDs: "
137 "caps lock %s, num lock %s, scroll lock %s\n",
138 bits(data
, 2) ? "on" : "off",
139 bits(data
, 1) ? "on" : "off",
140 bits(data
, 0) ? "on" : "off");
142 lastCommand
= NoCommand
;
145 DPRINTF(I8042
, "Setting typematic info to %#02x.\n", data
);
147 lastCommand
= NoCommand
;
154 DPRINTF(I8042
, "Got LED write command.\n");
156 lastCommand
= LEDWrite
;
159 panic("Keyboard diagnostic echo unimplemented.\n");
160 case AlternateScanCodes
:
161 panic("Accessing alternate scan codes unimplemented.\n");
163 DPRINTF(I8042
, "Got keyboard read ID command.\n");
165 bufferData((uint8_t *)&ID
, sizeof(ID
));
168 DPRINTF(I8042
, "Setting typematic info.\n");
170 lastCommand
= TypematicInfo
;
173 DPRINTF(I8042
, "Enabling the keyboard.\n");
177 DPRINTF(I8042
, "Disabling the keyboard.\n");
180 case DefaultsAndDisable
:
181 DPRINTF(I8042
, "Disabling and resetting the keyboard.\n");
184 case AllKeysToTypematic
:
185 panic("Setting all keys to typemantic unimplemented.\n");
186 case AllKeysToMakeRelease
:
187 panic("Setting all keys to make/release unimplemented.\n");
189 panic("Setting all keys to make unimplemented.\n");
190 case AllKeysToTypematicMakeRelease
:
191 panic("Setting all keys to "
192 "typematic/make/release unimplemented.\n");
194 panic("Setting a key to typematic unimplemented.\n");
195 case KeyToMakeRelease
:
196 panic("Setting a key to make/release unimplemented.\n");
198 panic("Setting key to make only unimplemented.\n");
200 panic("Keyboard resend unimplemented.\n");
202 panic("Keyboard reset unimplemented.\n");
204 panic("Unknown keyboard command %#02x.\n", data
);
210 X86ISA::PS2Mouse::processData(uint8_t data
)
212 if (lastCommand
!= NoCommand
) {
213 switch(lastCommand
) {
215 DPRINTF(I8042
, "Mouse resolution set to %d.\n", data
);
218 lastCommand
= NoCommand
;
221 DPRINTF(I8042
, "Mouse sample rate %d samples "
222 "per second.\n", data
);
225 lastCommand
= NoCommand
;
228 panic("Not expecting data for a mouse command.\n");
234 DPRINTF(I8042
, "Setting mouse scale to 1:1.\n");
239 DPRINTF(I8042
, "Setting mouse scale to 2:1.\n");
244 DPRINTF(I8042
, "Setting mouse resolution.\n");
245 lastCommand
= SetResolution
;
249 DPRINTF(I8042
, "Getting mouse status.\n");
251 bufferData((uint8_t *)&(status
), 1);
252 bufferData(&resolution
, sizeof(resolution
));
253 bufferData(&sampleRate
, sizeof(sampleRate
));
256 panic("Reading mouse data unimplemented.\n");
258 panic("Resetting mouse wrap mode unimplemented.\n");
260 panic("Setting mouse wrap mode unimplemented.\n");
262 panic("Setting mouse remote mode unimplemented.\n");
264 DPRINTF(I8042
, "Mouse ID requested.\n");
266 bufferData(ID
, sizeof(ID
));
269 DPRINTF(I8042
, "Setting mouse sample rate.\n");
270 lastCommand
= SampleRate
;
273 case DisableReporting
:
274 DPRINTF(I8042
, "Disabling data reporting.\n");
278 case EnableReporting
:
279 DPRINTF(I8042
, "Enabling data reporting.\n");
283 case DefaultsAndDisable
:
284 DPRINTF(I8042
, "Disabling and resetting mouse.\n");
292 panic("Mouse resend unimplemented.\n");
294 DPRINTF(I8042
, "Resetting the mouse.\n");
300 bufferData(&BatSuccessful
, sizeof(BatSuccessful
));
301 bufferData(ID
, sizeof(ID
));
304 warn("Unknown mouse command %#02x.\n", data
);
313 X86ISA::I8042::read(PacketPtr pkt
)
315 assert(pkt
->getSize() == 1);
316 Addr addr
= pkt
->getAddr();
317 if (addr
== dataPort
) {
318 uint8_t data
= readDataOut();
319 //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
320 pkt
->set
<uint8_t>(data
);
321 } else if (addr
== commandPort
) {
322 //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
323 pkt
->set
<uint8_t>((uint8_t)statusReg
);
325 panic("Read from unrecognized port %#x.\n", addr
);
327 pkt
->makeAtomicResponse();
332 X86ISA::I8042::write(PacketPtr pkt
)
334 assert(pkt
->getSize() == 1);
335 Addr addr
= pkt
->getAddr();
336 uint8_t data
= pkt
->get
<uint8_t>();
337 if (addr
== dataPort
) {
338 statusReg
.commandLast
= 0;
339 switch (lastCommand
) {
341 if (keyboard
.processData(data
)) {
342 writeData(keyboard
.getData(), false);
346 if (mouse
.processData(data
)) {
347 writeData(mouse
.getData(), true);
350 case WriteCommandByte
:
352 DPRINTF(I8042
, "Got data %#02x for \"Write "
353 "command byte\" command.\n", data
);
354 statusReg
.passedSelfTest
= (uint8_t)commandByte
.passedSelfTest
;
356 case WriteMouseOutputBuff
:
357 DPRINTF(I8042
, "Got data %#02x for \"Write "
358 "mouse output buffer\" command.\n", data
);
359 writeData(data
, true);
362 panic("Data written for unrecognized "
363 "command %#02x\n", lastCommand
);
365 lastCommand
= NoCommand
;
366 } else if (addr
== commandPort
) {
367 DPRINTF(I8042
, "Got command %#02x.\n", data
);
368 statusReg
.commandLast
= 1;
369 // These purposefully leave off the first byte of the controller RAM
370 // so it can be handled specially.
371 if (data
> ReadControllerRamBase
&&
372 data
< ReadControllerRamBase
+ RamSize
) {
373 panic("Attempted to use i8042 read controller RAM command to "
374 "get byte %d.\n", data
- ReadControllerRamBase
);
375 } else if (data
> WriteControllerRamBase
&&
376 data
< WriteControllerRamBase
+ RamSize
) {
377 panic("Attempted to use i8042 read controller RAM command to "
378 "get byte %d.\n", data
- ReadControllerRamBase
);
379 } else if (data
>= PulseOutputBitBase
&&
380 data
< PulseOutputBitBase
+ NumOutputBits
) {
381 panic("Attempted to use i8042 pulse output bit command to "
382 "to pulse bit %d.\n", data
- PulseOutputBitBase
);
386 DPRINTF(I8042
, "Getting command byte.\n");
387 writeData(commandByte
);
389 case WriteCommandByte
:
390 DPRINTF(I8042
, "Setting command byte.\n");
391 lastCommand
= WriteCommandByte
;
393 case CheckForPassword
:
394 panic("i8042 \"Check for password\" command not implemented.\n");
396 panic("i8042 \"Load password\" command not implemented.\n");
398 panic("i8042 \"Check password\" command not implemented.\n");
400 DPRINTF(I8042
, "Disabling mouse at controller.\n");
401 commandByte
.disableMouse
= 1;
404 DPRINTF(I8042
, "Enabling mouse at controller.\n");
405 commandByte
.disableMouse
= 0;
408 panic("i8042 \"Test mouse\" command not implemented.\n");
410 panic("i8042 \"Self test\" command not implemented.\n");
412 panic("i8042 \"Interface test\" command not implemented.\n");
414 panic("i8042 \"Diagnostic dump\" command not implemented.\n");
415 case DisableKeyboard
:
416 DPRINTF(I8042
, "Disabling keyboard at controller.\n");
417 commandByte
.disableKeyboard
= 1;
420 DPRINTF(I8042
, "Enabling keyboard at controller.\n");
421 commandByte
.disableKeyboard
= 0;
424 panic("i8042 \"Read input port\" command not implemented.\n");
425 case ContinuousPollLow
:
426 panic("i8042 \"Continuous poll low\" command not implemented.\n");
427 case ContinuousPollHigh
:
428 panic("i8042 \"Continuous poll high\" command not implemented.\n");
430 panic("i8042 \"Read output port\" command not implemented.\n");
431 case WriteOutputPort
:
432 warn("i8042 \"Write output port\" command not implemented.\n");
433 lastCommand
= WriteOutputPort
;
434 case WriteKeyboardOutputBuff
:
435 warn("i8042 \"Write keyboard output buffer\" "
436 "command not implemented.\n");
437 lastCommand
= WriteKeyboardOutputBuff
;
438 case WriteMouseOutputBuff
:
439 DPRINTF(I8042
, "Got command to write to mouse output buffer.\n");
440 lastCommand
= WriteMouseOutputBuff
;
443 DPRINTF(I8042
, "Expecting mouse command.\n");
444 lastCommand
= WriteToMouse
;
447 panic("i8042 \"Disable A20\" command not implemented.\n");
449 panic("i8042 \"Enable A20\" command not implemented.\n");
451 panic("i8042 \"Read test inputs\" command not implemented.\n");
453 panic("i8042 \"System reset\" command not implemented.\n");
455 warn("Write to unknown i8042 "
456 "(keyboard controller) command port.\n");
459 panic("Write to unrecognized port %#x.\n", addr
);
461 pkt
->makeAtomicResponse();
466 X86ISA::I8042::serializeOld(CheckpointOut
&cp
)
468 uint8_t statusRegData
= statusReg
.__data
;
469 uint8_t commandByteData
= commandByte
.__data
;
471 SERIALIZE_SCALAR(dataPort
);
472 SERIALIZE_SCALAR(commandPort
);
473 SERIALIZE_SCALAR(statusRegData
);
474 SERIALIZE_SCALAR(commandByteData
);
475 SERIALIZE_SCALAR(dataReg
);
476 SERIALIZE_SCALAR(lastCommand
);
477 mouse
.serialize("mouse", cp
);
478 keyboard
.serialize("keyboard", cp
);
482 X86ISA::I8042::unserialize(CheckpointIn
&cp
)
484 uint8_t statusRegData
;
485 uint8_t commandByteData
;
487 UNSERIALIZE_SCALAR(dataPort
);
488 UNSERIALIZE_SCALAR(commandPort
);
489 UNSERIALIZE_SCALAR(statusRegData
);
490 UNSERIALIZE_SCALAR(commandByteData
);
491 UNSERIALIZE_SCALAR(dataReg
);
492 UNSERIALIZE_SCALAR(lastCommand
);
493 mouse
.unserialize("mouse", cp
);
494 keyboard
.unserialize("keyboard", cp
);
496 statusReg
.__data
= statusRegData
;
497 commandByte
.__data
= commandByteData
;
501 X86ISA::PS2Keyboard::serialize(const std::string
&base
, CheckpointOut
&cp
)
503 paramOut(cp
, base
+ ".lastCommand", lastCommand
);
504 int bufferSize
= outBuffer
.size();
505 paramOut(cp
, base
+ ".outBuffer.size", bufferSize
);
506 uint8_t *buffer
= new uint8_t[bufferSize
];
507 for (int i
= 0; i
< bufferSize
; ++i
) {
508 buffer
[i
] = outBuffer
.front();
511 arrayParamOut(cp
, base
+ ".outBuffer.elts", buffer
,
512 bufferSize
*sizeof(uint8_t));
517 X86ISA::PS2Keyboard::unserialize(const std::string
&base
, CheckpointIn
&cp
)
519 paramIn(cp
, base
+ ".lastCommand", lastCommand
);
521 paramIn(cp
, base
+ ".outBuffer.size", bufferSize
);
522 uint8_t *buffer
= new uint8_t[bufferSize
];
523 arrayParamIn(cp
, base
+ ".outBuffer.elts", buffer
,
524 bufferSize
*sizeof(uint8_t));
525 for (int i
= 0; i
< bufferSize
; ++i
) {
526 outBuffer
.push(buffer
[i
]);
532 X86ISA::PS2Mouse::serialize(const std::string
&base
, CheckpointOut
&cp
)
534 uint8_t statusData
= status
.__data
;
535 paramOut(cp
, base
+ ".lastCommand", lastCommand
);
536 int bufferSize
= outBuffer
.size();
537 paramOut(cp
, base
+ ".outBuffer.size", bufferSize
);
538 uint8_t *buffer
= new uint8_t[bufferSize
];
539 for (int i
= 0; i
< bufferSize
; ++i
) {
540 buffer
[i
] = outBuffer
.front();
543 arrayParamOut(cp
, base
+ ".outBuffer.elts", buffer
,
544 bufferSize
*sizeof(uint8_t));
546 paramOut(cp
, base
+ ".status", statusData
);
547 paramOut(cp
, base
+ ".resolution", resolution
);
548 paramOut(cp
, base
+ ".sampleRate", sampleRate
);
552 X86ISA::PS2Mouse::unserialize(const std::string
&base
, CheckpointIn
&cp
)
555 paramIn(cp
, base
+ ".lastCommand", lastCommand
);
557 paramIn(cp
, base
+ ".outBuffer.size", bufferSize
);
558 uint8_t *buffer
= new uint8_t[bufferSize
];
559 arrayParamIn(cp
, base
+ ".outBuffer.elts", buffer
,
560 bufferSize
*sizeof(uint8_t));
561 for (int i
= 0; i
< bufferSize
; ++i
) {
562 outBuffer
.push(buffer
[i
]);
565 paramIn(cp
, base
+ ".status", statusData
);
566 paramIn(cp
, base
+ ".resolution", resolution
);
567 paramIn(cp
, base
+ ".sampleRate", sampleRate
);
569 status
.__data
= statusData
;
573 I8042Params::create()
575 return new X86ISA::I8042(this);