Handle simultaneous kbd and mouse streams
Continuing from PR #184, fixes #182. Two main changes: 1. Pulse the interrupt lines to ensure rising edge. Some say that the controller clears the interrupt lines themselves after a small delay to create a pulse: - http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/ - https://wiki.osdev.org/8259_PIC#What_does_the_8259_PIC_do.3F (paragraph 1) although that contradicts with: - Section "Reading Keyboard Input" paragraph 3 http://www.computer-engineering.org/ps2keyboard/#General%20Description%20FN where they say the interrupts are cleared only after reading port 0x60. Could possibly be because they are referring to the older AT keyboard controller. 2. Wait until current byte has been read via port 0x60 before changing between kbd and mouse queues. In hardware terms: inhibit kbd and mouse communication, and don't overwrite the DBBOUT output buffer until OBF is cleared. Interesting reading: - Section "Reading Keyboard Input" paragraph 1 http://www.computer-engineering.org/ps2keyboard/#General%20Description%20FN - Disassembly "Main Entry" $0102 http://www.halicery.com/8042/8042_1503033.TXT Unlike PR #184, this gives kbd data priority over mouse data (as it used to), and this seems to avoid requiring timers to expire abandoned bytes.
This commit is contained in:
parent
3cee397d0e
commit
afbbf0cc7c
96
src/ps2.js
96
src/ps2.js
|
@ -80,6 +80,14 @@ function PS2(cpu, bus)
|
|||
*/
|
||||
this.mouse_buffer = new ByteQueue(1024);
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* Also known as DBBOUT OBF - Output Buffer Full flag
|
||||
*/
|
||||
this.next_byte_is_ready = false;
|
||||
|
||||
/** @type {boolean} */
|
||||
this.next_byte_is_aux = false;
|
||||
|
||||
this.bus.register("keyboard-code", function(code)
|
||||
{
|
||||
|
@ -170,21 +178,64 @@ PS2.prototype.set_state = function(state)
|
|||
this.read_output_register = state[21];
|
||||
this.read_command_register = state[22];
|
||||
|
||||
this.next_byte_is_ready = false;
|
||||
this.next_byte_is_aux = false;
|
||||
this.kbd_buffer.clear();
|
||||
this.mouse_buffer.clear();
|
||||
|
||||
this.bus.send("mouse-enable", this.use_mouse);
|
||||
};
|
||||
|
||||
PS2.prototype.raise_irq = function()
|
||||
{
|
||||
if(this.next_byte_is_ready)
|
||||
{
|
||||
// Wait until previous byte is read
|
||||
// http://halicery.com/Hardware/8042/8042_1503033_TXT.htm
|
||||
return;
|
||||
}
|
||||
|
||||
// Kbd has priority over aux
|
||||
if(this.kbd_buffer.length)
|
||||
{
|
||||
this.kbd_irq();
|
||||
}
|
||||
else if(this.mouse_buffer.length)
|
||||
{
|
||||
this.mouse_irq();
|
||||
}
|
||||
};
|
||||
|
||||
PS2.prototype.mouse_irq = function()
|
||||
{
|
||||
this.next_byte_is_ready = true;
|
||||
this.next_byte_is_aux = true;
|
||||
|
||||
if(this.command_register & 2)
|
||||
{
|
||||
dbg_log("Mouse irq", LOG_PS2);
|
||||
|
||||
// Pulse the irq line
|
||||
// Note: can't lower immediately after rising, so lower before rising
|
||||
// http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/
|
||||
this.cpu.device_lower_irq(12);
|
||||
this.cpu.device_raise_irq(12);
|
||||
}
|
||||
};
|
||||
|
||||
PS2.prototype.kbd_irq = function()
|
||||
{
|
||||
this.next_byte_is_ready = true;
|
||||
this.next_byte_is_aux = false;
|
||||
|
||||
if(this.command_register & 1)
|
||||
{
|
||||
dbg_log("Keyboard irq", LOG_PS2);
|
||||
|
||||
// Pulse the irq line
|
||||
// Note: can't lower immediately after rising, so lower before rising
|
||||
// http://www.os2museum.com/wp/ibm-ps2-model-50-keyboard-controller/
|
||||
this.cpu.device_lower_irq(1);
|
||||
this.cpu.device_raise_irq(1);
|
||||
}
|
||||
};
|
||||
|
@ -193,8 +244,9 @@ PS2.prototype.kbd_send_code = function(code)
|
|||
{
|
||||
if(this.enable_keyboard_stream)
|
||||
{
|
||||
dbg_log("adding kbd code: " + h(code), LOG_PS2);
|
||||
this.kbd_buffer.push(code);
|
||||
this.kbd_irq();
|
||||
this.raise_irq();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -278,7 +330,7 @@ PS2.prototype.send_mouse_packet = function(dx, dy)
|
|||
dbg_log("adding mouse packets: " + [info_byte, dx, dy], LOG_PS2);
|
||||
}
|
||||
|
||||
this.mouse_irq();
|
||||
this.raise_irq();
|
||||
};
|
||||
|
||||
PS2.prototype.apply_scaling2 = function(n)
|
||||
|
@ -304,15 +356,12 @@ PS2.prototype.apply_scaling2 = function(n)
|
|||
}
|
||||
};
|
||||
|
||||
PS2.prototype.next_byte_is_aux = function()
|
||||
{
|
||||
return this.mouse_buffer.length && !this.kbd_buffer.length;
|
||||
};
|
||||
|
||||
PS2.prototype.port60_read = function()
|
||||
{
|
||||
//dbg_log("port 60 read: " + (buffer[0] || "(none)"));
|
||||
|
||||
this.next_byte_is_ready = false;
|
||||
|
||||
if(!this.kbd_buffer.length && !this.mouse_buffer.length)
|
||||
{
|
||||
// should not happen
|
||||
|
@ -320,33 +369,22 @@ PS2.prototype.port60_read = function()
|
|||
return this.last_port60_byte;
|
||||
}
|
||||
|
||||
var do_mouse_buffer = this.next_byte_is_aux();
|
||||
|
||||
if(do_mouse_buffer)
|
||||
if(this.next_byte_is_aux)
|
||||
{
|
||||
this.cpu.device_lower_irq(12);
|
||||
this.last_port60_byte = this.mouse_buffer.shift();
|
||||
|
||||
if(PS2_LOG_VERBOSE)
|
||||
{
|
||||
dbg_log("Port 60 read (mouse): " + h(this.last_port60_byte), LOG_PS2);
|
||||
}
|
||||
|
||||
if(this.mouse_buffer.length >= 1)
|
||||
{
|
||||
this.mouse_irq();
|
||||
}
|
||||
dbg_log("Port 60 read (mouse): " + h(this.last_port60_byte), LOG_PS2);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.cpu.device_lower_irq(1);
|
||||
this.last_port60_byte = this.kbd_buffer.shift();
|
||||
dbg_log("Port 60 read (kbd) : " + h(this.last_port60_byte), LOG_PS2);
|
||||
}
|
||||
|
||||
if(this.kbd_buffer.length >= 1)
|
||||
{
|
||||
this.kbd_irq();
|
||||
}
|
||||
if(this.kbd_buffer.length || this.mouse_buffer.length)
|
||||
{
|
||||
this.raise_irq();
|
||||
}
|
||||
|
||||
return this.last_port60_byte;
|
||||
|
@ -358,11 +396,11 @@ PS2.prototype.port64_read = function()
|
|||
|
||||
var status_byte = 0x10;
|
||||
|
||||
if(this.mouse_buffer.length || this.kbd_buffer.length)
|
||||
if(this.next_byte_is_ready)
|
||||
{
|
||||
status_byte |= 1;
|
||||
status_byte |= 0x1;
|
||||
}
|
||||
if(this.next_byte_is_aux())
|
||||
if(this.next_byte_is_aux)
|
||||
{
|
||||
status_byte |= 0x20;
|
||||
}
|
||||
|
@ -616,6 +654,7 @@ PS2.prototype.port64_write = function(write_byte)
|
|||
this.kbd_buffer.clear();
|
||||
this.mouse_buffer.clear();
|
||||
this.kbd_buffer.push(this.command_register);
|
||||
this.kbd_irq();
|
||||
break;
|
||||
case 0x60:
|
||||
this.read_command_register = true;
|
||||
|
@ -641,17 +680,20 @@ PS2.prototype.port64_write = function(write_byte)
|
|||
this.kbd_buffer.clear();
|
||||
this.mouse_buffer.clear();
|
||||
this.kbd_buffer.push(0);
|
||||
this.kbd_irq();
|
||||
break;
|
||||
case 0xAA:
|
||||
this.kbd_buffer.clear();
|
||||
this.mouse_buffer.clear();
|
||||
this.kbd_buffer.push(0x55);
|
||||
this.kbd_irq();
|
||||
break;
|
||||
case 0xAB:
|
||||
// Test first PS/2 port
|
||||
this.kbd_buffer.clear();
|
||||
this.mouse_buffer.clear();
|
||||
this.kbd_buffer.push(0);
|
||||
this.kbd_irq();
|
||||
break;
|
||||
case 0xAD:
|
||||
// Disable Keyboard
|
||||
|
|
Loading…
Reference in a new issue