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 "dev/x86/i8042.hh"
33 #include "base/bitunion.hh"
34 #include "debug/I8042.hh"
35 #include "mem/packet.hh"
36 #include "mem/packet_access.hh"
39 * Note: For details on the implementation see
40 * https://wiki.osdev.org/%228042%22_PS/2_Controller
43 // The 8042 has a whopping 32 bytes of internal RAM.
44 const uint8_t RamSize
= 32;
45 const uint8_t NumOutputBits
= 14;
48 X86ISA::I8042::I8042(Params
*p
)
49 : BasicPioDevice(p
, 0), // pioSize arg is dummy value... not used
50 latency(p
->pio_latency
),
51 dataPort(p
->data_port
), commandPort(p
->command_port
),
52 statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand
),
53 mouseIntPin(p
->mouse_int_pin
), keyboardIntPin(p
->keyboard_int_pin
),
54 mouse(p
->mouse
), keyboard(p
->keyboard
)
56 fatal_if(!mouse
, "The i8042 model requires a mouse instance");
57 fatal_if(!keyboard
, "The i8042 model requires a keyboard instance");
59 statusReg
.passedSelfTest
= 1;
60 statusReg
.commandLast
= 1;
61 statusReg
.keyboardUnlocked
= 1;
63 commandByte
.convertScanCodes
= 1;
64 commandByte
.passedSelfTest
= 1;
65 commandByte
.keyboardFullInt
= 1;
70 X86ISA::I8042::getAddrRanges() const
73 // TODO: Are these really supposed to be a single byte and not 4?
74 ranges
.push_back(RangeSize(dataPort
, 1));
75 ranges
.push_back(RangeSize(commandPort
, 1));
80 X86ISA::I8042::writeData(uint8_t newData
, bool mouse
)
82 DPRINTF(I8042
, "Set data %#02x.\n", newData
);
84 statusReg
.outputFull
= 1;
85 statusReg
.mouseOutputFull
= (mouse
? 1 : 0);
86 if (!mouse
&& commandByte
.keyboardFullInt
) {
87 DPRINTF(I8042
, "Sending keyboard interrupt.\n");
88 keyboardIntPin
->raise();
90 keyboardIntPin
->lower();
91 } else if (mouse
&& commandByte
.mouseFullInt
) {
92 DPRINTF(I8042
, "Sending mouse interrupt.\n");
100 X86ISA::I8042::readDataOut()
102 uint8_t data
= dataReg
;
103 statusReg
.outputFull
= 0;
104 statusReg
.mouseOutputFull
= 0;
105 if (keyboard
->hostDataAvailable()) {
106 writeData(keyboard
->hostRead(), false);
107 } else if (mouse
->hostDataAvailable()) {
108 writeData(mouse
->hostRead(), true);
114 X86ISA::I8042::read(PacketPtr pkt
)
116 assert(pkt
->getSize() == 1);
117 Addr addr
= pkt
->getAddr();
118 if (addr
== dataPort
) {
119 uint8_t data
= readDataOut();
120 //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
121 pkt
->setLE
<uint8_t>(data
);
122 } else if (addr
== commandPort
) {
123 //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
124 pkt
->setLE
<uint8_t>((uint8_t)statusReg
);
126 panic("Read from unrecognized port %#x.\n", addr
);
128 pkt
->makeAtomicResponse();
133 X86ISA::I8042::write(PacketPtr pkt
)
135 assert(pkt
->getSize() == 1);
136 Addr addr
= pkt
->getAddr();
137 uint8_t data
= pkt
->getLE
<uint8_t>();
138 if (addr
== dataPort
) {
139 statusReg
.commandLast
= 0;
140 switch (lastCommand
) {
142 keyboard
->hostWrite(data
);
143 if (keyboard
->hostDataAvailable())
144 writeData(keyboard
->hostRead(), false);
147 mouse
->hostWrite(data
);
148 if (mouse
->hostDataAvailable())
149 writeData(mouse
->hostRead(), true);
151 case WriteCommandByte
:
153 DPRINTF(I8042
, "Got data %#02x for \"Write "
154 "command byte\" command.\n", data
);
155 statusReg
.passedSelfTest
= (uint8_t)commandByte
.passedSelfTest
;
157 case WriteMouseOutputBuff
:
158 DPRINTF(I8042
, "Got data %#02x for \"Write "
159 "mouse output buffer\" command.\n", data
);
160 writeData(data
, true);
162 case WriteKeyboardOutputBuff
:
163 DPRINTF(I8042
, "Got data %#02x for \"Write "
164 "keyboad output buffer\" command.\n", data
);
165 writeData(data
, false);
167 case WriteOutputPort
:
168 DPRINTF(I8042
, "Got data %#02x for \"Write "
169 "output port\" command.\n", data
);
170 panic_if(bits(data
, 0) != 1, "Reset bit should be 1");
171 // Safe to ignore otherwise
174 panic("Data written for unrecognized "
175 "command %#02x\n", lastCommand
);
177 lastCommand
= NoCommand
;
178 } else if (addr
== commandPort
) {
179 DPRINTF(I8042
, "Got command %#02x.\n", data
);
180 statusReg
.commandLast
= 1;
181 // These purposefully leave off the first byte of the controller RAM
182 // so it can be handled specially.
183 if (data
> ReadControllerRamBase
&&
184 data
< ReadControllerRamBase
+ RamSize
) {
185 panic("Attempted to use i8042 read controller RAM command to "
186 "get byte %d.\n", data
- ReadControllerRamBase
);
187 } else if (data
> WriteControllerRamBase
&&
188 data
< WriteControllerRamBase
+ RamSize
) {
189 panic("Attempted to use i8042 read controller RAM command to "
190 "get byte %d.\n", data
- ReadControllerRamBase
);
191 } else if (data
>= PulseOutputBitBase
&&
192 data
< PulseOutputBitBase
+ NumOutputBits
) {
193 panic("Attempted to use i8042 pulse output bit command to "
194 "to pulse bit %d.\n", data
- PulseOutputBitBase
);
198 DPRINTF(I8042
, "Getting command byte.\n");
199 writeData(commandByte
);
201 case WriteCommandByte
:
202 DPRINTF(I8042
, "Setting command byte.\n");
203 lastCommand
= WriteCommandByte
;
205 case CheckForPassword
:
206 panic("i8042 \"Check for password\" command not implemented.\n");
208 panic("i8042 \"Load password\" command not implemented.\n");
210 panic("i8042 \"Check password\" command not implemented.\n");
212 DPRINTF(I8042
, "Disabling mouse at controller.\n");
213 commandByte
.disableMouse
= 1;
216 DPRINTF(I8042
, "Enabling mouse at controller.\n");
217 commandByte
.disableMouse
= 0;
220 panic("i8042 \"Test mouse\" command not implemented.\n");
222 panic("i8042 \"Self test\" command not implemented.\n");
224 panic("i8042 \"Interface test\" command not implemented.\n");
226 panic("i8042 \"Diagnostic dump\" command not implemented.\n");
227 case DisableKeyboard
:
228 DPRINTF(I8042
, "Disabling keyboard at controller.\n");
229 commandByte
.disableKeyboard
= 1;
232 DPRINTF(I8042
, "Enabling keyboard at controller.\n");
233 commandByte
.disableKeyboard
= 0;
236 panic("i8042 \"Read input port\" command not implemented.\n");
237 case ContinuousPollLow
:
238 panic("i8042 \"Continuous poll low\" command not implemented.\n");
239 case ContinuousPollHigh
:
240 panic("i8042 \"Continuous poll high\" command not implemented.\n");
242 panic("i8042 \"Read output port\" command not implemented.\n");
243 case WriteOutputPort
:
244 lastCommand
= WriteOutputPort
;
246 case WriteKeyboardOutputBuff
:
247 lastCommand
= WriteKeyboardOutputBuff
;
249 case WriteMouseOutputBuff
:
250 DPRINTF(I8042
, "Got command to write to mouse output buffer.\n");
251 lastCommand
= WriteMouseOutputBuff
;
254 DPRINTF(I8042
, "Expecting mouse command.\n");
255 lastCommand
= WriteToMouse
;
258 panic("i8042 \"Disable A20\" command not implemented.\n");
260 panic("i8042 \"Enable A20\" command not implemented.\n");
262 panic("i8042 \"Read test inputs\" command not implemented.\n");
264 panic("i8042 \"System reset\" command not implemented.\n");
266 warn("Write to unknown i8042 "
267 "(keyboard controller) command port.\n");
270 panic("Write to unrecognized port %#x.\n", addr
);
272 pkt
->makeAtomicResponse();
277 X86ISA::I8042::serialize(CheckpointOut
&cp
) const
279 SERIALIZE_SCALAR(dataPort
);
280 SERIALIZE_SCALAR(commandPort
);
281 SERIALIZE_SCALAR(statusReg
);
282 SERIALIZE_SCALAR(commandByte
);
283 SERIALIZE_SCALAR(dataReg
);
284 SERIALIZE_SCALAR(lastCommand
);
288 X86ISA::I8042::unserialize(CheckpointIn
&cp
)
290 UNSERIALIZE_SCALAR(dataPort
);
291 UNSERIALIZE_SCALAR(commandPort
);
292 UNSERIALIZE_SCALAR(statusReg
);
293 UNSERIALIZE_SCALAR(commandByte
);
294 UNSERIALIZE_SCALAR(dataReg
);
295 UNSERIALIZE_SCALAR(lastCommand
);
299 I8042Params::create()
301 return new X86ISA::I8042(this);