mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
hle_mouse: high-level emulation of PS/2 mouse
This commit is contained in:
parent
a389d4bef3
commit
d00c294732
@ -1573,6 +1573,8 @@ if (BUSES["PC_KBD"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/pc_kbd/pcxt83.h",
|
||||
MAME_DIR .. "src/devices/bus/pc_kbd/pcat101.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pc_kbd/pcat101.h",
|
||||
MAME_DIR .. "src/devices/bus/pc_kbd/hle_mouse.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pc_kbd/hle_mouse.h",
|
||||
}
|
||||
end
|
||||
|
||||
|
537
src/devices/bus/pc_kbd/hle_mouse.cpp
Normal file
537
src/devices/bus/pc_kbd/hle_mouse.cpp
Normal file
@ -0,0 +1,537 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* PS/2 mouse high-level emulation.
|
||||
*
|
||||
* This device emulates a mouse with three buttons, using the original three-
|
||||
* byte PS/2 mouse protocol. Serial I/O is driven at 10kHz by a 40kHz timer
|
||||
* to generate somewhat accurate clock rising and falling edges, as well as
|
||||
* sampling or writing the data line in the middle of each high or low cycle
|
||||
* as exoected by the protocol.
|
||||
*
|
||||
* The original IBM PS/2 mouse had only two buttons and the documented protocol
|
||||
* reflects this, however it also allows a third button to be added without any
|
||||
* significant changes. IBM later produced three-button mice which apparently
|
||||
* took advantage of this, making it about as standard as it gets.
|
||||
*
|
||||
* Microsoft introduced the IntelliMouse in 1996 which adds another two buttons
|
||||
* and a scroll wheel, requiring a change to the protocol from three to four
|
||||
* byte data packets. The IntelliMouse protocol is only enabled after sending
|
||||
* a specific sequence of "set sample rate" commands, without which the mouse
|
||||
* uses the original protocol.
|
||||
*
|
||||
* Sources:
|
||||
*
|
||||
* https://web.archive.org/web/20180126072045/http://www.computer-engineering.org/ps2mouse/
|
||||
* https://wiki.osdev.org/PS/2_Mouse
|
||||
* https://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html
|
||||
* http://read.pudn.com/downloads136/ebook/579116/docs/Designing%20a%20low%20cost%20CY7C63723%20combination%20mouse.pdf
|
||||
*
|
||||
* TODO
|
||||
* - IntelliMouse device/protocol (4-byte packet, 5 buttons, scroll wheel)
|
||||
* - configurable clock (10kHz-16.7kHz)
|
||||
* - receive parity error handling
|
||||
* - resolve issue with earlier Indy/Indigo² PROM versions (IBF ignored)
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "hle_mouse.h"
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_RXTX (1U << 1)
|
||||
#define LOG_COMMAND (1U << 2)
|
||||
#define LOG_REPORT (1U << 3)
|
||||
#define LOG_STATE (1U << 4)
|
||||
|
||||
//#define VERBOSE (LOG_COMMAND)
|
||||
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(HLE_PS2_MOUSE, hle_ps2_mouse_device, "hle_ps2_mouse", "HLE PS/2 Mouse")
|
||||
|
||||
ALLOW_SAVE_TYPE(hle_ps2_mouse_device::serial_state);
|
||||
|
||||
INPUT_PORTS_START(hle_ps2_mouse_device)
|
||||
PORT_START("mouse_x_axis")
|
||||
PORT_BIT(0xffff, 0, IPT_MOUSE_X) PORT_SENSITIVITY(100)
|
||||
|
||||
PORT_START("mouse_y_axis")
|
||||
PORT_BIT(0xffff, 0, IPT_MOUSE_Y) PORT_SENSITIVITY(100)
|
||||
|
||||
PORT_START("mouse_buttons")
|
||||
PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Left Button")
|
||||
PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Right Button")
|
||||
PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_CODE(MOUSECODE_BUTTON3) PORT_NAME("Middle Button")
|
||||
PORT_BIT(0xf8, IP_ACTIVE_HIGH, IPT_UNUSED)
|
||||
INPUT_PORTS_END
|
||||
|
||||
static constexpr attotime serial_cycle = attotime::from_usec(25);
|
||||
|
||||
hle_ps2_mouse_device::hle_ps2_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, HLE_PS2_MOUSE, tag, owner, clock)
|
||||
, device_pc_kbd_interface(mconfig, *this)
|
||||
, m_port_x_axis(*this, "mouse_x_axis")
|
||||
, m_port_y_axis(*this, "mouse_y_axis")
|
||||
, m_port_buttons(*this, "mouse_buttons")
|
||||
{
|
||||
}
|
||||
|
||||
ioport_constructor hle_ps2_mouse_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(hle_ps2_mouse_device);
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_state));
|
||||
save_item(NAME(m_bit));
|
||||
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_sample_rate));
|
||||
save_item(NAME(m_resolution));
|
||||
|
||||
save_item(NAME(m_rx_len));
|
||||
save_item(NAME(m_rx_buf));
|
||||
save_item(NAME(m_tx_len));
|
||||
save_item(NAME(m_tx_pos));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_parity));
|
||||
|
||||
save_item(NAME(m_mouse_x));
|
||||
save_item(NAME(m_mouse_y));
|
||||
save_item(NAME(m_mouse_b));
|
||||
|
||||
set_pc_kbdc_device();
|
||||
|
||||
m_serial = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hle_ps2_mouse_device::serial), this));
|
||||
m_sample = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(hle_ps2_mouse_device::sample), this));
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::device_reset()
|
||||
{
|
||||
// configure default settings
|
||||
defaults();
|
||||
|
||||
// reset mouse state
|
||||
update();
|
||||
|
||||
// clear tx/rx buffers
|
||||
m_rx_len = 0;
|
||||
m_tx_len = 0;
|
||||
m_tx_pos = 0;
|
||||
|
||||
// enqueue bat result
|
||||
m_tx_buf[m_tx_len++] = 0xaa;
|
||||
m_tx_buf[m_tx_len++] = 0x00;
|
||||
|
||||
m_state = IDLE;
|
||||
|
||||
// release clock and data lines
|
||||
m_pc_kbdc->data_write_from_kb(1);
|
||||
m_pc_kbdc->clock_write_from_kb(1);
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::clock_write(int state)
|
||||
{
|
||||
// record when the clock signal last changed state
|
||||
m_clock_changed = machine().time();
|
||||
|
||||
// resume serial communication
|
||||
resume();
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::resume()
|
||||
{
|
||||
if (clock_signal() && m_state == IDLE)
|
||||
{
|
||||
// check if receiving a start bit
|
||||
if (!data_signal())
|
||||
m_state = RX_START;
|
||||
|
||||
// start serial communication
|
||||
if (!m_serial->enabled())
|
||||
m_serial->adjust(serial_cycle, 0, serial_cycle);
|
||||
}
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::serial(void *ptr, s32 param)
|
||||
{
|
||||
// host may inhibit device communication by holding the clock low for 100µs
|
||||
if (!clock_signal() && clock_held(100))
|
||||
{
|
||||
m_state = IDLE;
|
||||
|
||||
// release clock and data lines
|
||||
m_pc_kbdc->data_write_from_kb(1);
|
||||
m_pc_kbdc->clock_write_from_kb(1);
|
||||
|
||||
// stop serial communication
|
||||
m_serial->enable(false);
|
||||
return;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_STATE, "state %d clock %d data %d\n", m_state, clock_signal(), data_signal());
|
||||
|
||||
switch (m_state)
|
||||
{
|
||||
case IDLE:
|
||||
if (clock_signal())
|
||||
{
|
||||
// stop serial communication if nothing to transmit
|
||||
if (m_tx_pos == m_tx_len)
|
||||
m_serial->enable(false);
|
||||
else
|
||||
// device may transmit after clock is high for 50µs
|
||||
if (clock_held(50))
|
||||
m_state = TX_START;
|
||||
}
|
||||
break;
|
||||
|
||||
case RX_START:
|
||||
// check for start bit
|
||||
if (!data_signal())
|
||||
{
|
||||
m_state = RX_CLOCK_LO0;
|
||||
|
||||
// prepare data
|
||||
m_data = 0;
|
||||
m_parity = 1;
|
||||
m_bit = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case RX_CLOCK_LO0:
|
||||
// assert clock
|
||||
m_state = RX_CLOCK_LO1;
|
||||
m_pc_kbdc->clock_write_from_kb(0);
|
||||
break;
|
||||
|
||||
case RX_CLOCK_LO1:
|
||||
// hold clock
|
||||
m_state = RX_CLOCK_HI0;
|
||||
break;
|
||||
|
||||
case RX_CLOCK_HI0:
|
||||
// release clock
|
||||
m_state = RX_CLOCK_HI1;
|
||||
m_pc_kbdc->clock_write_from_kb(1);
|
||||
break;
|
||||
|
||||
case RX_CLOCK_HI1:
|
||||
switch (m_bit)
|
||||
{
|
||||
case 8: // parity bit
|
||||
m_state = RX_CLOCK_LO0;
|
||||
|
||||
if (data_signal() == (m_parity & 1))
|
||||
{
|
||||
LOGMASKED(LOG_RXTX, "rx data 0x%02x\n", m_data);
|
||||
m_rx_buf[m_rx_len++] = m_data;
|
||||
}
|
||||
else
|
||||
// TODO: transmit unbuffered resend command
|
||||
LOGMASKED(LOG_RXTX, "rx error data 0x%02x parity %d\n", m_data, data_signal());
|
||||
m_bit++;
|
||||
break;
|
||||
|
||||
case 9: // acknowledge
|
||||
if (data_signal())
|
||||
{
|
||||
m_state = RX_CLOCK_LO0;
|
||||
m_pc_kbdc->data_write_from_kb(0);
|
||||
m_bit++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 10: // finished
|
||||
if (m_rx_len)
|
||||
m_state = COMMAND;
|
||||
else
|
||||
m_state = IDLE;
|
||||
m_pc_kbdc->data_write_from_kb(1);
|
||||
break;
|
||||
|
||||
default: // data bit
|
||||
m_state = RX_CLOCK_LO0;
|
||||
m_parity += data_signal();
|
||||
m_data |= (data_signal() << m_bit++);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMAND:
|
||||
m_state = IDLE;
|
||||
|
||||
// execute the command
|
||||
command(m_rx_buf[0]);
|
||||
|
||||
// reset mouse state
|
||||
update();
|
||||
break;
|
||||
|
||||
case TX_START:
|
||||
// prepare data
|
||||
m_data = m_tx_buf[m_tx_pos++];
|
||||
m_parity = 1;
|
||||
m_bit = 0;
|
||||
|
||||
// start bit
|
||||
m_state = TX_CLOCK_LO0;
|
||||
m_pc_kbdc->data_write_from_kb(0);
|
||||
break;
|
||||
|
||||
case TX_CLOCK_LO0:
|
||||
// assert clock
|
||||
m_state = TX_CLOCK_LO1;
|
||||
m_pc_kbdc->clock_write_from_kb(0);
|
||||
break;
|
||||
|
||||
case TX_CLOCK_LO1:
|
||||
// hold clock
|
||||
m_state = TX_CLOCK_HI0;
|
||||
break;
|
||||
|
||||
case TX_CLOCK_HI0:
|
||||
// release clock
|
||||
m_state = TX_CLOCK_HI1;
|
||||
m_pc_kbdc->clock_write_from_kb(1);
|
||||
break;
|
||||
|
||||
case TX_CLOCK_HI1:
|
||||
switch (m_bit)
|
||||
{
|
||||
case 8: // parity bit
|
||||
m_state = TX_CLOCK_LO0;
|
||||
m_pc_kbdc->data_write_from_kb(m_parity & 1);
|
||||
LOGMASKED(LOG_RXTX, "tx data 0x%02x\n", m_data);
|
||||
m_bit++;
|
||||
break;
|
||||
|
||||
case 9: // stop bit
|
||||
m_state = TX_CLOCK_LO0;
|
||||
m_pc_kbdc->data_write_from_kb(1);
|
||||
m_bit++;
|
||||
break;
|
||||
|
||||
case 10: // finished
|
||||
m_state = IDLE;
|
||||
break;
|
||||
|
||||
default: // data
|
||||
m_state = TX_CLOCK_LO0;
|
||||
m_parity += BIT(m_data, m_bit);
|
||||
m_pc_kbdc->data_write_from_kb(BIT(m_data, m_bit));
|
||||
m_bit++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::command(u8 const command)
|
||||
{
|
||||
// consume the command byte
|
||||
m_rx_len--;
|
||||
|
||||
// reset the transmit position
|
||||
m_tx_pos = 0;
|
||||
|
||||
// special case for resend
|
||||
if (command == 0xfe)
|
||||
{
|
||||
LOGMASKED(LOG_COMMAND, "resend\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_tx_len = 0;
|
||||
|
||||
// special case for wrap mode
|
||||
if ((m_mode & WRAP) && command != 0xff && command != 0xec)
|
||||
{
|
||||
// echo the command
|
||||
m_tx_buf[m_tx_len++] = command;
|
||||
return;
|
||||
}
|
||||
|
||||
// handle the command
|
||||
switch (command)
|
||||
{
|
||||
case 0xe6: // set scaling 1:1
|
||||
LOGMASKED(LOG_COMMAND, "set scaling 1:1\n");
|
||||
m_mode &= ~SCALE;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xe7: // set scaling 2:1
|
||||
LOGMASKED(LOG_COMMAND, "set scaling 2:1\n");
|
||||
m_mode |= SCALE;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xe8: // set resolution
|
||||
if (m_rx_len == 1)
|
||||
{
|
||||
m_resolution = m_rx_buf[m_rx_len--];
|
||||
LOGMASKED(LOG_COMMAND, "set resolution 0x%02x\n", m_resolution);
|
||||
}
|
||||
else
|
||||
// re-enqueue the command and wait for the parameter
|
||||
m_rx_len++;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xe9: // status request
|
||||
LOGMASKED(LOG_COMMAND, "status request\n");
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
m_tx_buf[m_tx_len++] = m_mode | m_port_buttons->read();
|
||||
m_tx_buf[m_tx_len++] = m_resolution;
|
||||
m_tx_buf[m_tx_len++] = m_sample_rate;
|
||||
break;
|
||||
|
||||
case 0xea: // set stream mode
|
||||
LOGMASKED(LOG_COMMAND, "set stream mode\n");
|
||||
m_mode &= ~REMOTE;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xeb: // read data
|
||||
LOGMASKED(LOG_COMMAND, "read data\n");
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
|
||||
// force data sample after acknowledge transmitted
|
||||
m_sample->adjust(serial_cycle * 48, 1);
|
||||
break;
|
||||
|
||||
case 0xec: // reset wrap mode
|
||||
LOGMASKED(LOG_COMMAND, "reset wrap mode\n");
|
||||
m_mode &= ~WRAP;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xee: // set wrap mode
|
||||
LOGMASKED(LOG_COMMAND, "set wrap mode\n");
|
||||
m_mode |= WRAP;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xf0: // set remote mode
|
||||
LOGMASKED(LOG_COMMAND, "set remote mode\n");
|
||||
m_mode |= REMOTE;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xf2: // get device id
|
||||
LOGMASKED(LOG_COMMAND, "get device id\n");
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
m_tx_buf[m_tx_len++] = 0x00;
|
||||
break;
|
||||
|
||||
case 0xf3: // set sample rate
|
||||
if (m_rx_len == 1)
|
||||
{
|
||||
m_sample_rate = m_rx_buf[m_rx_len--];
|
||||
LOGMASKED(LOG_COMMAND, "set sample rate %d\n", m_sample_rate);
|
||||
}
|
||||
else
|
||||
// re-enqueue the command and wait for the parameter
|
||||
m_rx_len++;
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xf4: // enable data reporting
|
||||
LOGMASKED(LOG_COMMAND, "enable data reporting\n");
|
||||
m_mode |= ENABLE;
|
||||
m_sample->adjust(attotime::from_hz(m_sample_rate), 0, attotime::from_hz(m_sample_rate));
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xf5: // disable data reporting
|
||||
LOGMASKED(LOG_COMMAND, "disable data reporting\n");
|
||||
m_mode &= ~ENABLE;
|
||||
m_sample->enable(false);
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xf6: // set defaults
|
||||
LOGMASKED(LOG_COMMAND, "set defaults\n");
|
||||
defaults();
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
break;
|
||||
|
||||
case 0xff: // reset
|
||||
LOGMASKED(LOG_COMMAND, "reset\n");
|
||||
defaults();
|
||||
m_tx_buf[m_tx_len++] = 0xfa;
|
||||
m_tx_buf[m_tx_len++] = 0xaa; // bat successful
|
||||
m_tx_buf[m_tx_len++] = 0x00; // device id
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_COMMAND, "unrecognized command 0x%02x\n", command);
|
||||
m_tx_buf[m_tx_len++] = 0xfc; // error
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::sample(void *ptr, s32 param)
|
||||
{
|
||||
// read mouse state
|
||||
s16 const x = m_port_x_axis->read();
|
||||
s16 const y = m_port_y_axis->read();
|
||||
u8 const b = m_port_buttons->read();
|
||||
|
||||
// compute delta
|
||||
s16 dx = x - m_mouse_x;
|
||||
s16 dy = m_mouse_y - y;
|
||||
u8 const db = b ^ m_mouse_b;
|
||||
|
||||
// data report if transmit buffer empty and position or buttons changed
|
||||
if ((m_tx_pos == m_tx_len) && (dx || dy || db || param))
|
||||
{
|
||||
LOGMASKED(LOG_REPORT, "data report dx %d dy %d db %d\n", dx, dy, db);
|
||||
|
||||
// compute sign and overflow
|
||||
u8 const sx = (dx < 0) ? 0x10 : 0x00;
|
||||
u8 const sy = (dy < 0) ? 0x20 : 0x00;
|
||||
u8 const ox = ((dx < -256) || (dx > 255)) ? 0x40 : 0x00;
|
||||
u8 const oy = ((dy < -256) || (dy > 255)) ? 0x80 : 0x00;
|
||||
|
||||
// apply scaling
|
||||
if (m_mode & SCALE)
|
||||
{
|
||||
static s32 const scale[] = { -9, -6, -3, -1, -1, 0, 1, 1, 3, 6, 9 };
|
||||
|
||||
dx = (std::abs(dx) > 5) ? dx * 2 : scale[dx + 5];
|
||||
dy = (std::abs(dy) > 5) ? dy * 2 : scale[dy + 5];
|
||||
}
|
||||
|
||||
// transmit data report
|
||||
m_tx_len = 0;
|
||||
m_tx_buf[m_tx_len++] = oy | ox | sy | sx | 0x08 | b;
|
||||
m_tx_buf[m_tx_len++] = u8(dx);
|
||||
m_tx_buf[m_tx_len++] = u8(dy);
|
||||
m_tx_pos = 0;
|
||||
|
||||
// record mouse state
|
||||
m_mouse_x = x;
|
||||
m_mouse_y = y;
|
||||
m_mouse_b = b;
|
||||
|
||||
// resume serial communication
|
||||
resume();
|
||||
}
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::defaults()
|
||||
{
|
||||
m_mode = 0;
|
||||
m_sample_rate = 100;
|
||||
m_resolution = 2;
|
||||
}
|
||||
|
||||
void hle_ps2_mouse_device::update()
|
||||
{
|
||||
m_mouse_x = m_port_x_axis->read();
|
||||
m_mouse_y = m_port_y_axis->read();
|
||||
m_mouse_b = m_port_buttons->read();
|
||||
}
|
98
src/devices/bus/pc_kbd/hle_mouse.h
Normal file
98
src/devices/bus/pc_kbd/hle_mouse.h
Normal file
@ -0,0 +1,98 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_BUS_HLE_PS2_MOUSE_H
|
||||
#define MAME_BUS_HLE_PS2_MOUSE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pc_kbdc.h"
|
||||
|
||||
class hle_ps2_mouse_device
|
||||
: public device_t
|
||||
, public device_pc_kbd_interface
|
||||
{
|
||||
public:
|
||||
hle_ps2_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// device_t overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// device_pc_kbd_interface overrides
|
||||
virtual void clock_write(int state) override;
|
||||
|
||||
private:
|
||||
bool const clock_held(unsigned usec) { return (machine().time() - m_clock_changed) >= attotime::from_usec(usec); }
|
||||
|
||||
void resume();
|
||||
TIMER_CALLBACK_MEMBER(serial);
|
||||
void command(u8 const command);
|
||||
|
||||
TIMER_CALLBACK_MEMBER(sample);
|
||||
void defaults();
|
||||
void update();
|
||||
|
||||
required_ioport m_port_x_axis;
|
||||
required_ioport m_port_y_axis;
|
||||
required_ioport m_port_buttons;
|
||||
|
||||
emu_timer *m_serial;
|
||||
emu_timer *m_sample;
|
||||
|
||||
attotime m_clock_changed;
|
||||
|
||||
// serial state
|
||||
enum serial_state : unsigned
|
||||
{
|
||||
IDLE,
|
||||
COMMAND,
|
||||
|
||||
RX_START,
|
||||
RX_CLOCK_LO0,
|
||||
RX_CLOCK_LO1,
|
||||
RX_CLOCK_HI0,
|
||||
RX_CLOCK_HI1,
|
||||
|
||||
TX_START,
|
||||
TX_CLOCK_LO0,
|
||||
TX_CLOCK_LO1,
|
||||
TX_CLOCK_HI0,
|
||||
TX_CLOCK_HI1,
|
||||
}
|
||||
m_state;
|
||||
unsigned m_bit;
|
||||
|
||||
// setting state
|
||||
enum mode_mask : u8
|
||||
{
|
||||
SCALE = 0x10, // 2:1 scaling
|
||||
ENABLE = 0x20, // data reporting
|
||||
REMOTE = 0x40,
|
||||
WRAP = 0x80,
|
||||
};
|
||||
u8 m_mode;
|
||||
u8 m_sample_rate;
|
||||
u8 m_resolution;
|
||||
|
||||
// tx/rx state
|
||||
unsigned m_rx_len;
|
||||
u8 m_rx_buf[2];
|
||||
unsigned m_tx_len;
|
||||
unsigned m_tx_pos;
|
||||
u8 m_tx_buf[4];
|
||||
u8 m_data;
|
||||
unsigned m_parity;
|
||||
|
||||
// mouse state
|
||||
s16 m_mouse_x;
|
||||
s16 m_mouse_y;
|
||||
u8 m_mouse_b;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(HLE_PS2_MOUSE, hle_ps2_mouse_device)
|
||||
|
||||
#endif // MAME_BUS_HLE_PS2_MOUSE_H
|
@ -11,6 +11,7 @@
|
||||
#include "pcxt83.h"
|
||||
#include "pcat84.h"
|
||||
#include "pcat101.h"
|
||||
#include "hle_mouse.h"
|
||||
|
||||
void pc_xt_keyboards(device_slot_interface &device)
|
||||
{
|
||||
@ -30,3 +31,8 @@ void pc_at_keyboards(device_slot_interface &device)
|
||||
device.option_add(STR_KBD_IBM_3270PC_122, PC_KBD_IBM_3270PC_122);
|
||||
device.option_add(STR_KBD_IBM_PC_AT_101, PC_KBD_IBM_PC_AT_101);
|
||||
}
|
||||
|
||||
void ps2_mice(device_slot_interface &device)
|
||||
{
|
||||
device.option_add(STR_HLE_PS2_MOUSE, HLE_PS2_MOUSE);
|
||||
}
|
||||
|
@ -31,4 +31,9 @@ void pc_xt_keyboards(device_slot_interface &device);
|
||||
|
||||
void pc_at_keyboards(device_slot_interface &device);
|
||||
|
||||
// PS/2 protocol mice
|
||||
#define STR_HLE_PS2_MOUSE "hle_ps2_mouse"
|
||||
|
||||
void ps2_mice(device_slot_interface &device);
|
||||
|
||||
#endif // MAME_BUS_PC_KBD_KEYBOARDS_H
|
||||
|
Loading…
Reference in New Issue
Block a user