x86: Use little endian packet accessors.
[gem5.git] / src / dev / x86 / i8042.cc
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 "dev/x86/i8042.hh"
32
33 #include "base/bitunion.hh"
34 #include "debug/I8042.hh"
35 #include "mem/packet.hh"
36 #include "mem/packet_access.hh"
37
38 /**
39 * Note: For details on the implementation see
40 * https://wiki.osdev.org/%228042%22_PS/2_Controller
41 */
42
43 // The 8042 has a whopping 32 bytes of internal RAM.
44 const uint8_t RamSize = 32;
45 const uint8_t NumOutputBits = 14;
46
47
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)
55 {
56 fatal_if(!mouse, "The i8042 model requires a mouse instance");
57 fatal_if(!keyboard, "The i8042 model requires a keyboard instance");
58
59 statusReg.passedSelfTest = 1;
60 statusReg.commandLast = 1;
61 statusReg.keyboardUnlocked = 1;
62
63 commandByte.convertScanCodes = 1;
64 commandByte.passedSelfTest = 1;
65 commandByte.keyboardFullInt = 1;
66 }
67
68
69 AddrRangeList
70 X86ISA::I8042::getAddrRanges() const
71 {
72 AddrRangeList ranges;
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));
76 return ranges;
77 }
78
79 void
80 X86ISA::I8042::writeData(uint8_t newData, bool mouse)
81 {
82 DPRINTF(I8042, "Set data %#02x.\n", newData);
83 dataReg = 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();
89 //This is a hack
90 keyboardIntPin->lower();
91 } else if (mouse && commandByte.mouseFullInt) {
92 DPRINTF(I8042, "Sending mouse interrupt.\n");
93 mouseIntPin->raise();
94 //This is a hack
95 mouseIntPin->lower();
96 }
97 }
98
99 uint8_t
100 X86ISA::I8042::readDataOut()
101 {
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);
109 }
110 return data;
111 }
112
113 Tick
114 X86ISA::I8042::read(PacketPtr pkt)
115 {
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);
125 } else {
126 panic("Read from unrecognized port %#x.\n", addr);
127 }
128 pkt->makeAtomicResponse();
129 return latency;
130 }
131
132 Tick
133 X86ISA::I8042::write(PacketPtr pkt)
134 {
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) {
141 case NoCommand:
142 keyboard->hostWrite(data);
143 if (keyboard->hostDataAvailable())
144 writeData(keyboard->hostRead(), false);
145 break;
146 case WriteToMouse:
147 mouse->hostWrite(data);
148 if (mouse->hostDataAvailable())
149 writeData(mouse->hostRead(), true);
150 break;
151 case WriteCommandByte:
152 commandByte = data;
153 DPRINTF(I8042, "Got data %#02x for \"Write "
154 "command byte\" command.\n", data);
155 statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
156 break;
157 case WriteMouseOutputBuff:
158 DPRINTF(I8042, "Got data %#02x for \"Write "
159 "mouse output buffer\" command.\n", data);
160 writeData(data, true);
161 break;
162 case WriteKeyboardOutputBuff:
163 DPRINTF(I8042, "Got data %#02x for \"Write "
164 "keyboad output buffer\" command.\n", data);
165 writeData(data, false);
166 break;
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
172 break;
173 default:
174 panic("Data written for unrecognized "
175 "command %#02x\n", lastCommand);
176 }
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);
195 }
196 switch (data) {
197 case GetCommandByte:
198 DPRINTF(I8042, "Getting command byte.\n");
199 writeData(commandByte);
200 break;
201 case WriteCommandByte:
202 DPRINTF(I8042, "Setting command byte.\n");
203 lastCommand = WriteCommandByte;
204 break;
205 case CheckForPassword:
206 panic("i8042 \"Check for password\" command not implemented.\n");
207 case LoadPassword:
208 panic("i8042 \"Load password\" command not implemented.\n");
209 case CheckPassword:
210 panic("i8042 \"Check password\" command not implemented.\n");
211 case DisableMouse:
212 DPRINTF(I8042, "Disabling mouse at controller.\n");
213 commandByte.disableMouse = 1;
214 break;
215 case EnableMouse:
216 DPRINTF(I8042, "Enabling mouse at controller.\n");
217 commandByte.disableMouse = 0;
218 break;
219 case TestMouse:
220 panic("i8042 \"Test mouse\" command not implemented.\n");
221 case SelfTest:
222 panic("i8042 \"Self test\" command not implemented.\n");
223 case InterfaceTest:
224 panic("i8042 \"Interface test\" command not implemented.\n");
225 case DiagnosticDump:
226 panic("i8042 \"Diagnostic dump\" command not implemented.\n");
227 case DisableKeyboard:
228 DPRINTF(I8042, "Disabling keyboard at controller.\n");
229 commandByte.disableKeyboard = 1;
230 break;
231 case EnableKeyboard:
232 DPRINTF(I8042, "Enabling keyboard at controller.\n");
233 commandByte.disableKeyboard = 0;
234 break;
235 case ReadInputPort:
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");
241 case ReadOutputPort:
242 panic("i8042 \"Read output port\" command not implemented.\n");
243 case WriteOutputPort:
244 lastCommand = WriteOutputPort;
245 break;
246 case WriteKeyboardOutputBuff:
247 lastCommand = WriteKeyboardOutputBuff;
248 break;
249 case WriteMouseOutputBuff:
250 DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
251 lastCommand = WriteMouseOutputBuff;
252 break;
253 case WriteToMouse:
254 DPRINTF(I8042, "Expecting mouse command.\n");
255 lastCommand = WriteToMouse;
256 break;
257 case DisableA20:
258 panic("i8042 \"Disable A20\" command not implemented.\n");
259 case EnableA20:
260 panic("i8042 \"Enable A20\" command not implemented.\n");
261 case ReadTestInputs:
262 panic("i8042 \"Read test inputs\" command not implemented.\n");
263 case SystemReset:
264 panic("i8042 \"System reset\" command not implemented.\n");
265 default:
266 warn("Write to unknown i8042 "
267 "(keyboard controller) command port.\n");
268 }
269 } else {
270 panic("Write to unrecognized port %#x.\n", addr);
271 }
272 pkt->makeAtomicResponse();
273 return latency;
274 }
275
276 void
277 X86ISA::I8042::serialize(CheckpointOut &cp) const
278 {
279 SERIALIZE_SCALAR(dataPort);
280 SERIALIZE_SCALAR(commandPort);
281 SERIALIZE_SCALAR(statusReg);
282 SERIALIZE_SCALAR(commandByte);
283 SERIALIZE_SCALAR(dataReg);
284 SERIALIZE_SCALAR(lastCommand);
285 }
286
287 void
288 X86ISA::I8042::unserialize(CheckpointIn &cp)
289 {
290 UNSERIALIZE_SCALAR(dataPort);
291 UNSERIALIZE_SCALAR(commandPort);
292 UNSERIALIZE_SCALAR(statusReg);
293 UNSERIALIZE_SCALAR(commandByte);
294 UNSERIALIZE_SCALAR(dataReg);
295 UNSERIALIZE_SCALAR(lastCommand);
296 }
297
298 X86ISA::I8042 *
299 I8042Params::create()
300 {
301 return new X86ISA::I8042(this);
302 }