35 #define STATUS_OBF 0x01 // 0 : Output Buffer Full (0 = output buffer empty) 36 #define STATUS_IBF 0x02 // 1 : Input Buffer Full (0 = input buffer empty) 37 #define STATUS_SYSFLAG 0x04 // 2 : 0 = power on reset, 1 = diagnostic ok 38 #define STATUS_CMD 0x08 // 3 : Command or Data, 0 = write to port 0 (0x60), 1 = write to port 1 (0x64) 39 #define STATUS_INH 0x10 // 4 : Inhibit Switch, 0 = Keyboard inhibited, 1 = Keyboard not inhibited 40 #define STATUS_AOBF 0x20 // 5 : Auxiliary Output Buffer Full, 0 = keyboard data, 1 = mouse data 41 #define STATUS_TIMEOUT 0x40 // 6 : 1 = Timeout Error 42 #define STATUS_PARITY_ERR 0x80 // 7 : 1 = Parity Error 46 #define CTRLCMD_NONE 0x00 47 #define CTRLCMD_GET_COMMAND_BYTE 0x20 48 #define CTRLCMD_READ_CONTROLLER_RAM_BEGIN 0x21 49 #define CTRLCMD_READ_CONTROLLER_RAM_END 0x3f 50 #define CTRLCMD_WRITE_COMMAND_BYTE 0x60 51 #define CTRLCMD_WRITE_CONTROLLER_RAM_BEGIN 0x61 52 #define CTRLCMD_WRITE_CONTROLLER_RAM_END 0x7f 53 #define CTRLCMD_DISABLE_MOUSE_PORT 0xa7 54 #define CTRLCMD_ENABLE_MOUSE_PORT 0xa8 55 #define CTRLCMD_TEST_MOUSE_PORT 0xa9 56 #define CTRLCMD_SELF_TEST 0xaa 57 #define CTRLCMD_TEST_KEYBOARD_PORT 0xab 58 #define CTRLCMD_DISABLE_KEYBOARD 0xad 59 #define CTRLCMD_ENABLE_KEYBOARD 0xae 60 #define CTRLCMD_READ_INPUT_PORT 0xc0 61 #define CTRLCMD_READ_OUTPUT_PORT 0xd0 62 #define CTRLCMD_WRITE_OUTPUT_PORT 0xd1 63 #define CTRLCMD_WRITE_KEYBOARD_OUTPUT_BUFFER 0xd2 64 #define CTRLCMD_WRITE_MOUSE_OUTPUT_BUFFER 0xd3 65 #define CTRLCMD_WRITE_TO_MOUSE 0xd4 66 #define CTRLCMD_SYSTEM_RESET 0xfe 70 #define CMDBYTE_ENABLE_KEYBOARD_IRQ 0x01 // 0 : 1 = Keyboard output buffer full causes interrupt (IRQ 1) 71 #define CMDBYTE_ENABLE_MOUSE_IRQ 0x02 // 1 : 1 = Mouse output buffer full causes interrupt (IRQ 12) 72 #define CMDBYTE_SYSFLAG 0x04 // 2 : 1 = System flag after successful controller self-test 73 #define CMDBYTE_UNUSED1 0x08 // 3 : unused (must be 0) 74 #define CMDBYTE_DISABLE_KEYBOARD 0x10 // 4 : 1 = Disable keyboard by forcing the keyboard clock low 75 #define CMDBYTE_DISABLE_MOUSE 0x20 // 5 : 1 = Disable mouse by forcing the mouse serial clock line low 76 #define CMDBYTE_STD_SCAN_CONVERSION 0x40 // 6 : 1 = Standard Scan conversion 77 #define CMDBYTE_UNUSED2 0x80 // 7 : unused (must be 0) 96 if (!PS2Controller::initialized())
99 m_PS2Controller.keyboard()->enableVirtualKeys(
false,
false);
100 m_keyboard = m_PS2Controller.keyboard();
101 m_mouse = m_PS2Controller.mouse();
109 m_STATUS = STATUS_SYSFLAG | STATUS_INH;
112 m_commandByte = CMDBYTE_ENABLE_KEYBOARD_IRQ | CMDBYTE_ENABLE_MOUSE_IRQ | CMDBYTE_SYSFLAG | CMDBYTE_STD_SCAN_CONVERSION | CMDBYTE_DISABLE_MOUSE;
114 m_executingCommand = CTRLCMD_NONE;
115 m_writeToMouse =
false;
116 m_mousePacketIdx = -1;
121 m_sysReqTriggered =
false;
125 uint8_t i8042::read(
int address)
132 m_STATUS &= ~(STATUS_OBF | STATUS_AOBF);
149 void i8042::write(
int address, uint8_t value)
158 m_STATUS = (m_STATUS & ~STATUS_CMD) | STATUS_IBF;
166 m_STATUS |= STATUS_CMD | STATUS_IBF;
176 if ((m_STATUS & STATUS_OBF) == 0 && m_keyboard->scancodeAvailable() && (m_commandByte & CMDBYTE_DISABLE_KEYBOARD) == 0) {
177 if (m_commandByte & CMDBYTE_STD_SCAN_CONVERSION) {
179 int scode2 = m_keyboard->getNextScancode();
181 uint8_t scode = Keyboard::convScancodeSet2To1(scode2);
182 m_DBBOUT = (m_DBBOUT == 0xf0 ? (0x80 | scode) : scode);
184 m_STATUS |= STATUS_OBF;
190 int scode2 = m_keyboard->getNextScancode();
193 m_STATUS |= STATUS_OBF;
199 if ((m_STATUS & STATUS_OBF) == 0 && (m_mousePacketIdx > -1 || m_mouse->packetAvailable()) && (m_commandByte & CMDBYTE_DISABLE_MOUSE) == 0) {
200 if (m_mousePacketIdx == -1)
201 m_mouse->getNextPacket(&m_mousePacket);
202 m_DBBOUT = m_mousePacket.data[++m_mousePacketIdx];
203 if (m_mousePacketIdx == m_mouse->getPacketSize() - 1)
204 m_mousePacketIdx = -1;
205 m_STATUS |= STATUS_OBF | STATUS_AOBF;
210 if (m_STATUS & STATUS_CMD) {
211 m_STATUS &= ~(STATUS_IBF | STATUS_CMD);
216 if ((m_STATUS & STATUS_IBF) && m_executingCommand != CTRLCMD_NONE) {
217 m_STATUS &= ~STATUS_IBF;
222 if (m_STATUS & STATUS_IBF) {
223 m_STATUS &= ~(STATUS_IBF | STATUS_PARITY_ERR);
225 m_mouse->sendCommand(m_DBBIN);
227 m_keyboard->sendCommand(m_DBBIN);
228 m_writeToMouse =
false;
229 m_STATUS |= STATUS_PARITY_ERR * m_keyboard->parityError();
233 if (m_keybIntTrigs && trigKeyboardInterrupt())
235 if (m_mouseIntTrigs && trigMouseInterrupt())
240 void i8042::execCommand()
242 uint8_t cmd = m_executingCommand == CTRLCMD_NONE ? m_DBBIN : m_executingCommand;
246 case CTRLCMD_GET_COMMAND_BYTE:
247 m_DBBOUT = m_commandByte;
248 m_STATUS |= STATUS_OBF;
251 case CTRLCMD_WRITE_COMMAND_BYTE:
252 if (m_executingCommand) {
254 updateCommandByte(m_DBBIN);
255 m_executingCommand = CTRLCMD_NONE;
258 m_executingCommand = CTRLCMD_WRITE_COMMAND_BYTE;
262 case CTRLCMD_DISABLE_MOUSE_PORT:
266 case CTRLCMD_ENABLE_MOUSE_PORT:
270 case CTRLCMD_TEST_MOUSE_PORT:
271 m_DBBOUT = m_mouse->isMouseAvailable() ? 0x00 : 0x02;
272 m_STATUS |= STATUS_OBF;
275 case CTRLCMD_SELF_TEST:
277 m_STATUS |= STATUS_OBF;
280 case CTRLCMD_TEST_KEYBOARD_PORT:
281 m_DBBOUT = m_keyboard->isKeyboardAvailable() ? 0x00 : 0x02;
282 m_STATUS |= STATUS_OBF;
285 case CTRLCMD_DISABLE_KEYBOARD:
286 updateCommandByte(m_commandByte | CMDBYTE_DISABLE_KEYBOARD);
289 case CTRLCMD_ENABLE_KEYBOARD:
290 updateCommandByte(m_commandByte & ~CMDBYTE_DISABLE_KEYBOARD);
293 case CTRLCMD_WRITE_TO_MOUSE:
297 case CTRLCMD_SYSTEM_RESET:
302 printf(
"8042: unsupported controller command %02X\n", cmd);
308 void i8042::enableMouse(
bool value)
310 updateCommandByte(value ? (m_commandByte & ~CMDBYTE_DISABLE_MOUSE) : (m_commandByte | CMDBYTE_DISABLE_MOUSE));
314 void i8042::updateCommandByte(uint8_t newValue)
317 if ((newValue ^ m_commandByte) & CMDBYTE_DISABLE_KEYBOARD) {
318 if (newValue & CMDBYTE_DISABLE_KEYBOARD) {
319 m_keyboard->suspendPort();
321 m_keyboard->resumePort();
326 if ((newValue ^ m_commandByte) & CMDBYTE_DISABLE_MOUSE) {
327 if (newValue & CMDBYTE_DISABLE_MOUSE) {
328 m_mouse->suspendPort();
330 m_mouse->resumePort();
334 m_commandByte = newValue;
339 bool i8042::trigKeyboardInterrupt()
341 return m_commandByte & CMDBYTE_ENABLE_KEYBOARD_IRQ ? m_keyboardInterrupt(m_context) : true;
345 bool i8042::trigMouseInterrupt()
347 return m_commandByte & CMDBYTE_ENABLE_MOUSE_IRQ ? m_mouseInterrupt(m_context) : true;
352 void i8042::checkSysReq(
int scode2)
354 if (m_DBBOUT == 0xf0) {
355 if (scode2 == 0x84) {
356 m_sysReqTriggered =
true;
357 }
else if (m_sysReqTriggered && scode2 == 0x11) {
358 m_sysReqTriggered =
false;
static void quickCheckHardware()
Disable re-try when a mouse is not found.