summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/8042kbdc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/8042kbdc.cpp')
-rw-r--r--src/devices/machine/8042kbdc.cpp211
1 files changed, 145 insertions, 66 deletions
diff --git a/src/devices/machine/8042kbdc.cpp b/src/devices/machine/8042kbdc.cpp
index 77d06e0e506..8f6918767e5 100644
--- a/src/devices/machine/8042kbdc.cpp
+++ b/src/devices/machine/8042kbdc.cpp
@@ -10,7 +10,7 @@
#include "emu.h"
-#include "machine/8042kbdc.h"
+#include "8042kbdc.h"
/***************************************************************************
@@ -22,8 +22,10 @@
#define PS2_MOUSE_ON 1
#define KEYBOARD_ON 1
-#define LOG_KEYBOARD 0
-#define LOG_ACCESSES 0
+#define LOG_KEYBOARD (1U << 1)
+#define LOG_ACCESSES (1U << 2)
+#define VERBOSE (0)
+#include "logmacro.h"
DEFINE_DEVICE_TYPE(KBDC8042, kbdc8042_device, "kbdc8042", "8042 Keyboard/Mouse Controller")
@@ -33,22 +35,19 @@ DEFINE_DEVICE_TYPE(KBDC8042, kbdc8042_device, "kbdc8042", "8042 Keyboard/Mouse C
kbdc8042_device::kbdc8042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, KBDC8042, tag, owner, clock)
- , m_keyboard_dev(*this, "at_keyboard")
+ , m_keyboard_dev(*this, finder_base::DUMMY_TAG)
, m_mousex_port(*this, "MOUSEX")
, m_mousey_port(*this, "MOUSEY")
, m_mousebtn_port(*this, "MOUSEBTN")
, m_system_reset_cb(*this)
, m_gate_a20_cb(*this)
, m_input_buffer_full_cb(*this)
+ , m_input_buffer_full_mouse_cb(*this)
, m_output_buffer_empty_cb(*this)
, m_speaker_cb(*this)
{
-}
-
-void kbdc8042_device::device_add_mconfig(machine_config &config)
-{
- AT_KEYB(config, m_keyboard_dev, pc_keyboard_device::KEYBOARD_TYPE::AT, 1);
- m_keyboard_dev->keypress().set(FUNC(kbdc8042_device::keyboard_w));
+ m_keybtype = KBDC8042_STANDARD;
+ m_interrupttype = KBDC8042_SINGLE;
}
@@ -58,22 +57,17 @@ void kbdc8042_device::device_add_mconfig(machine_config &config)
void kbdc8042_device::device_start()
{
- // resolve callbacks
- m_system_reset_cb.resolve_safe();
- m_gate_a20_cb.resolve_safe();
- m_input_buffer_full_cb.resolve_safe();
- m_output_buffer_empty_cb.resolve_safe();
- m_speaker_cb.resolve_safe();
- m_operation_write_state = 0; /* first write to 0x60 might occur before anything can set this */
memset(&m_keyboard, 0x00, sizeof(m_keyboard));
memset(&m_mouse, 0x00, sizeof(m_mouse));
m_mouse.sample_rate = 100;
+ m_mouse.resolution = 3;
+ m_mouse.on = true;
m_sending = 0;
m_last_write_to_control = 0;
- m_status_read_mode = 0;
+ m_speaker = 0;
+ m_offset1 = 0;
- m_update_timer = timer_alloc(TIMER_UPDATE);
- m_update_timer->adjust(attotime::never);
+ m_update_timer = timer_alloc(FUNC(kbdc8042_device::update_timer), this);
}
/*-------------------------------------------------
@@ -82,6 +76,10 @@ void kbdc8042_device::device_start()
void kbdc8042_device::device_reset()
{
+ m_operation_write_state = -1;
+ m_status_read_mode = 2;
+ m_keyboard.on = false;
+
m_poll_delay = 10;
/* ibmat bios wants 0x20 set! (keyboard locked when not set) 0x80 */
@@ -92,7 +90,7 @@ void kbdc8042_device::device_reset()
m_mouse_y = 0;
m_mouse_btn = 0;
- m_update_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
+ m_update_timer->adjust(attotime::never);
}
void kbdc8042_device::at_8042_set_outport(uint8_t data, int initial)
@@ -100,13 +98,10 @@ void kbdc8042_device::at_8042_set_outport(uint8_t data, int initial)
uint8_t change = initial ? 0xFF : (m_outport ^ data);
m_outport = data;
if (change & 0x02)
- {
- if (!m_gate_a20_cb.isnull())
- m_gate_a20_cb(data & 0x02 ? 1 : 0);
- }
+ m_gate_a20_cb(data & 0x02 ? 1 : 0);
}
-WRITE_LINE_MEMBER( kbdc8042_device::keyboard_w )
+void kbdc8042_device::keyboard_w(int state)
{
if(state)
at_8042_check_keyboard();
@@ -114,8 +109,7 @@ WRITE_LINE_MEMBER( kbdc8042_device::keyboard_w )
void kbdc8042_device::at_8042_receive(uint8_t data, bool mouse)
{
- if (LOG_KEYBOARD)
- logerror("at_8042_receive Received 0x%02x\n", data);
+ LOGMASKED(LOG_KEYBOARD, "at_8042_receive Received 0x%02x\n", data);
m_data = data;
if(!(m_speaker & 0x80) || mouse)
@@ -125,16 +119,29 @@ void kbdc8042_device::at_8042_receive(uint8_t data, bool mouse)
else
m_keyboard.received = 1;
- if (!m_input_buffer_full_cb.isnull())
+ if (m_interrupttype == KBDC8042_SINGLE)
+ {
m_input_buffer_full_cb(1);
+ }
+ else
+ {
+ if (m_keyboard.received && (m_command & 1))
+ {
+ m_input_buffer_full_cb(1);
+ }
+ if (m_mouse.received && (m_command & 2))
+ {
+ m_input_buffer_full_mouse_cb(1);
+ }
+ }
}
}
void kbdc8042_device::at_8042_check_keyboard()
{
- if (!m_keyboard.received && !m_mouse.received)
+ if (!m_keyboard.received && !m_mouse.received && m_keyboard_dev.found())
{
- int data = m_keyboard_dev->read(machine().dummy_space(), 0);
+ int data = m_keyboard_dev->read();
if (data)
at_8042_receive(data);
}
@@ -144,7 +151,7 @@ void kbdc8042_device::at_8042_check_mouse()
{
if ((m_keybtype == KBDC8042_PS2) && PS2_MOUSE_ON && !m_keyboard.received && !m_mouse.received)
{
- if (m_mouse.to_transmit == 0)
+ if (m_mouse.reporting && (m_mouse.to_transmit == 0))
{
uint16_t x = m_mousex_port->read();
uint16_t y = m_mousey_port->read();
@@ -171,6 +178,7 @@ void kbdc8042_device::at_8042_check_mouse()
if (dx != 0 || dy != 0 || buttons != old_mouse_btn)
{
m_mouse.to_transmit = 3;
+ m_mouse.from_transmit = 0;
m_mouse.transmit_buf[0] = buttons | 0x08 | (BIT(dx, 8) << 4) | (BIT(dy, 8) << 5);
m_mouse.transmit_buf[1] = dx & 0xff;
m_mouse.transmit_buf[2] = dy & 0xff;
@@ -179,12 +187,9 @@ void kbdc8042_device::at_8042_check_mouse()
if (m_mouse.to_transmit)
{
- at_8042_receive(m_mouse.transmit_buf[0], true);
+ at_8042_receive(m_mouse.transmit_buf[m_mouse.from_transmit], true);
m_mouse.to_transmit--;
- for (int i = 0; i < m_mouse.to_transmit; i++)
- {
- m_mouse.transmit_buf[i] = m_mouse.transmit_buf[i + 1];
- }
+ m_mouse.from_transmit = (m_mouse.from_transmit + 1) & (sizeof(m_mouse.transmit_buf) - 1);
}
}
}
@@ -193,21 +198,29 @@ void kbdc8042_device::at_8042_clear_keyboard_received()
{
if (m_keyboard.received)
{
- if (LOG_KEYBOARD)
- logerror("kbdc8042_8_r(): Clearing m_keyboard.received\n");
+ LOGMASKED(LOG_KEYBOARD, "kbdc8042_8_r(): Clearing m_keyboard.received\n");
}
m_input_buffer_full_cb(0);
+ m_input_buffer_full_mouse_cb(0);
m_keyboard.received = 0;
m_mouse.received = 0;
+ m_data = 0;
}
-void kbdc8042_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(kbdc8042_device::update_timer)
{
- if (id == TIMER_UPDATE)
- {
- at_8042_check_keyboard();
+ at_8042_check_keyboard();
+ if (m_mouse.on)
at_8042_check_mouse();
+}
+
+void kbdc8042_device::mouse_enqueue(uint8_t value)
+{
+ if (m_mouse.to_transmit < 8)
+ {
+ m_mouse.transmit_buf[(m_mouse.from_transmit + m_mouse.to_transmit) & (sizeof(m_mouse.transmit_buf) - 1)] = value;
+ m_mouse.to_transmit++;
}
}
@@ -234,7 +247,7 @@ void kbdc8042_device::device_timer(emu_timer &timer, device_timer_id id, int par
* 0: Keyboard data in
*/
-READ8_MEMBER(kbdc8042_device::data_r)
+uint8_t kbdc8042_device::data_r(offs_t offset)
{
uint8_t data = 0;
@@ -243,6 +256,8 @@ READ8_MEMBER(kbdc8042_device::data_r)
data = m_data;
at_8042_clear_keyboard_received();
at_8042_check_keyboard();
+ if (m_mouse.on)
+ at_8042_check_mouse();
break;
case 1:
@@ -275,7 +290,8 @@ READ8_MEMBER(kbdc8042_device::data_r)
case 4:
at_8042_check_keyboard();
- at_8042_check_mouse();
+ if (m_mouse.on)
+ at_8042_check_mouse();
if (m_keyboard.received || m_mouse.received)
data |= 1;
@@ -303,24 +319,27 @@ READ8_MEMBER(kbdc8042_device::data_r)
break;
}
- if (LOG_ACCESSES)
- logerror("kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data);
+ LOGMASKED(LOG_ACCESSES, "kbdc8042_8_r(): offset=%d data=0x%02x\n", offset, (unsigned) data);
return data;
}
-WRITE8_MEMBER(kbdc8042_device::data_w)
+void kbdc8042_device::data_w(offs_t offset, uint8_t data)
{
switch (offset) {
case 0:
m_last_write_to_control = 0;
m_status_read_mode = 0;
switch (m_operation_write_state) {
+ case -1:
+ break;
+
case 0:
m_data = data;
- m_sending=1;
- m_keyboard_dev->write(space, 0, data);
+ m_sending = 1;
+ if (m_keyboard_dev.found())
+ m_keyboard_dev->write(data);
break;
case 1:
@@ -352,22 +371,70 @@ WRITE8_MEMBER(kbdc8042_device::data_w)
m_data = data;
if (m_mouse.receiving_sample_rate)
{
- m_mouse.received = 1;
m_mouse.sample_rate = data;
- m_data = 0xfa;
+ m_mouse.receiving_sample_rate = false;
+ mouse_enqueue(0xfa);
+ break;
+ }
+ if (m_mouse.receiving_resolution)
+ {
+ m_mouse.resolution = data;
+ m_mouse.receiving_resolution = false;
+ mouse_enqueue(0xfa);
break;
}
switch (m_data)
{
+ case 0xff:
+ logerror("Mouse reset command received\n");
+ m_mouse.sample_rate = 100;
+ m_mouse.from_transmit = 0;
+ m_mouse.to_transmit = 0;
+ m_mouse.reporting = false;
+ if (m_mouse.on)
+ {
+ mouse_enqueue(0xfa);
+ mouse_enqueue(0xaa);
+ mouse_enqueue(0x00);
+ }
+ else
+ {
+ m_mouse.received = 1;
+ m_data = 0xfa;
+ }
+ break;
case 0xf6:
- m_mouse.received = 1;
- m_data = 0xfa;
+ mouse_enqueue(0xfa);
+ break;
+ case 0xf5:
+ m_mouse.reporting = false;
+ mouse_enqueue(0xfa);
+ break;
+ case 0xf4:
+ m_mouse.reporting = true;
+ mouse_enqueue(0xfa);
break;
case 0xf3:
- m_mouse.received = 1;
- m_data = 0xfa;
m_mouse.receiving_sample_rate = true;
+ mouse_enqueue(0xfa);
+ break;
+ case 0xf2:
+ mouse_enqueue(0xfa);
+ mouse_enqueue(0x00);
+ break;
+ case 0xe8:
+ mouse_enqueue(0xfa);
+ m_mouse.receiving_resolution = true;
+ break;
+ case 0xe6:
+ mouse_enqueue(0xfa);
+ break;
+ case 0xe9:
+ mouse_enqueue(0xfa);
+ mouse_enqueue(0x00);
+ mouse_enqueue(m_mouse.resolution);
+ mouse_enqueue(m_mouse.sample_rate);
break;
default:
logerror("%s: Unknown mouse command: %02x\n", machine().describe_context(), m_data);
@@ -391,13 +458,24 @@ WRITE8_MEMBER(kbdc8042_device::data_w)
at_8042_clear_keyboard_received();
}
m_speaker &= ~0x80;
- if (!m_speaker_cb.isnull())
- m_speaker_cb((offs_t)0, m_speaker);
+ m_speaker_cb(offs_t(0), m_speaker);
break;
case 4:
- m_last_write_to_control=1;
+ m_last_write_to_control = 1;
+
+ if (m_operation_write_state == -1)
+ {
+ m_status_read_mode = 0;
+ if (data != 0xaa && data != 0xd1)
+ break;
+ else
+ {
+ m_operation_write_state = 0;
+ m_update_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
+ }
+ }
/* switch based on the command */
switch(data) {
@@ -406,13 +484,12 @@ WRITE8_MEMBER(kbdc8042_device::data_w)
break;
case 0x60: /* next data byte is placed in 8042 command byte */
m_operation_write_state = 5;
- m_send_to_mouse = 0;
break;
case 0xa7: /* disable auxilary interface */
- m_mouse.on = 0;
+ m_mouse.on = false;
break;
case 0xa8: /* enable auxilary interface */
- m_mouse.on = 1;
+ m_mouse.on = true;
break;
case 0xa9: /* test mouse */
at_8042_receive(((m_keybtype == KBDC8042_PS2) && PS2_MOUSE_ON) ? 0x00 : 0xff);
@@ -463,21 +540,18 @@ WRITE8_MEMBER(kbdc8042_device::data_w)
* write is written to port 60h output register as if initiated
* by a device; invokes interrupt if enabled */
m_operation_write_state = 2;
- m_send_to_mouse = 0;
break;
case 0xd3:
/* write auxillary output register; on PS/2 systems next port 60h
* write is written to port 60h input register as if initiated
* by a device; invokes interrupt if enabled */
m_operation_write_state = 3;
- m_send_to_mouse = 1;
break;
case 0xd4:
/* write auxillary device; on PS/2 systems the next data byte
* written to input register a port at 60h is sent to the
* auxiliary device */
m_operation_write_state = 4;
- m_send_to_mouse = 1;
break;
case 0xe0:
/* read test inputs; read T1/T0 test inputs into bit 1/0 */
@@ -504,13 +578,18 @@ WRITE8_MEMBER(kbdc8042_device::data_w)
m_system_reset_cb(CLEAR_LINE);
at_8042_set_outport(m_outport | 0x02, 0);
break;
+ default:
+ if (data != 0xff)
+ {
+ logerror("%s: Unknown command: %02x\n", machine().describe_context(), data);
+ }
}
m_sending = 1;
break;
}
}
-WRITE_LINE_MEMBER(kbdc8042_device::write_out2)
+void kbdc8042_device::write_out2(int state)
{
m_out2 = state;
}