diff options
Diffstat (limited to 'src/devices/machine/8042kbdc.cpp')
-rw-r--r-- | src/devices/machine/8042kbdc.cpp | 211 |
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; } |