diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 6e5cbd9c70e..662b2627c7e 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3031,6 +3031,20 @@ if (BUSES["SUNKBD"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/bus/sunmouse/sunmouse.h,BUSES["SUNMOUSE"] = true +--------------------------------------------------- + +if (BUSES["SUNMOUSE"]~=null) then + files { + MAME_DIR .. "src/devices/bus/sunmouse/hlemouse.cpp", + MAME_DIR .. "src/devices/bus/sunmouse/hlemouse.h", + MAME_DIR .. "src/devices/bus/sunmouse/sunmouse.cpp", + MAME_DIR .. "src/devices/bus/sunmouse/sunmouse.h", + } +end + --------------------------------------------------- -- --@src/devices/bus/sbus/sbus.h,BUSES["SBUS"] = true diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 9e4799dca7f..b8a01662661 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -782,6 +782,7 @@ BUSES["SPC1000"] = true BUSES["SPECTRUM"] = true BUSES["SS50"] = true BUSES["SUNKBD"] = true +BUSES["SUNMOUSE"] = true BUSES["SVI_EXPANDER"] = true BUSES["SVI_SLOT"] = true BUSES["TATUNG_PIPE"] = true diff --git a/src/devices/bus/sunkbd/hlekbd.cpp b/src/devices/bus/sunkbd/hlekbd.cpp index 48b16f13348..31eb9da9dd1 100644 --- a/src/devices/bus/sunkbd/hlekbd.cpp +++ b/src/devices/bus/sunkbd/hlekbd.cpp @@ -21,7 +21,7 @@ 0000 0011 bell off 0000 1010 enable keyclick (5ms duration 480us period on make) 0000 1011 disable keyclick - 0000 1110 ---k lscn LED (1 = on, k = kana, l = caps lock, s = scroll lock, c = compose, n = num lock) + 0000 1110 ---k lscn LED (1 = on: k = kana, l = caps lock, s = scroll lock, c = compose, n = num lock) 0000 1111 layout request (keyboard responds with layout response) message from keyboad to host: @@ -128,7 +128,7 @@ yen/pipe replaces backtick/tilde at top left corner of main area linefeed scancode repurposed for backslash/underscore kana replaces alt graph (with LED window) - extra kakutei, henkan and nihongo on-off keys + extra kakutei (確定), henkan (変換) and nihongo on-off keys */ @@ -148,6 +148,7 @@ DEFINE_DEVICE_TYPE_NS(SUN_TYPE5_JP_HLE_KEYBOARD, bus::sunkbd, hle_type5_jp_devic namespace bus { namespace sunkbd { namespace { + /*************************************************************************** INPUT PORT DEFINITIONS ***************************************************************************/ diff --git a/src/devices/bus/sunkbd/hlekbd.h b/src/devices/bus/sunkbd/hlekbd.h index a4f6d886f5c..4f442daad4a 100644 --- a/src/devices/bus/sunkbd/hlekbd.h +++ b/src/devices/bus/sunkbd/hlekbd.h @@ -122,6 +122,7 @@ public: device_t *owner, uint32_t clock); +protected: virtual ioport_constructor device_input_ports() const override; private: @@ -138,6 +139,7 @@ public: device_t *owner, uint32_t clock); +protected: virtual ioport_constructor device_input_ports() const override; }; @@ -151,6 +153,7 @@ public: device_t *owner, uint32_t clock); +protected: virtual ioport_constructor device_input_ports() const override; }; @@ -164,6 +167,7 @@ public: device_t *owner, uint32_t clock); +protected: virtual ioport_constructor device_input_ports() const override; }; @@ -177,6 +181,7 @@ public: device_t *owner, uint32_t clock); +protected: virtual ioport_constructor device_input_ports() const override; }; @@ -190,6 +195,7 @@ public: device_t *owner, uint32_t clock); +protected: virtual ioport_constructor device_input_ports() const override; }; diff --git a/src/devices/bus/sunkbd/sunkbd.cpp b/src/devices/bus/sunkbd/sunkbd.cpp index 2ac0eb65b4c..39394b78ded 100644 --- a/src/devices/bus/sunkbd/sunkbd.cpp +++ b/src/devices/bus/sunkbd/sunkbd.cpp @@ -1,5 +1,92 @@ // license:BSD-3-Clause // copyright-holders:Vas Crabb +/* + Sun keyboard port + + Pre-USB Sun keyboards use an asynchronous serial protocol. Data is + transmitted at TTL levels using an asynchronous serial protocol at + 1,200 Baud. The protocol remained compatible from at least the + Type 2 keyboard to the Type 6 keyboard, although key layout and key + cap labels varied, some scancodes were repurposed, and a variety of + connectors were used. + + From the Sun 2/50 onwards, the keyboard and mouse share a single + connector, either using a splitter adapter, or by plugging the mouse + into a pass-through connector on the keyboard. + + Type 3 female DA-15 connector on host (introduced on Sun 2/50): + 1: keyboard RxD 9: GND + 2: GND 10: +5V + 3: keyboard TxD 11: +5V + 4: GND 12: +5V + 5: mouse RxD 13: +5V + 6: GND 14: +5V + 7: mouse TxD 15: +5V + 8: GND + + Type 4 female Mini-DIN-8 connector on host (introduced on Sun 3/80): + 1: GND 3: +5V 6: keyboard RxD + 2: GND 4: mouse RxD 7: mouse TxD + 5: keyboard TxD 8: +5V + + Type 5 female Mini-DIN-8 connector on host: + 1: GND 3: +5V 6: keyboard RxD + 2: GND 4: mouse RxD 7: power key + 5: keyboard TxD 8: +5V + + Scancodes (U.S. caps except as noted): + 00: 20: 3 40: [ { 60: Page Up + 01: L1/Stop 21: 5 41: ] } 61: L10/Cut + 02: Volume Down 22: 5 42: Delete 62: Num Lock + 03: L2/Again 23: 6 43: Compose 63: Left Shift + 04: Volume Up 24: 7 44: R7/KP 7 64: Z + 05: F1 25: 8 45: R8/KP 8 65: X + 06: F2 26: 9 46: R9/KP 9 66: C + 07: F10 27: 0 47: KP - 67: V + 08: F3 28: - _ 48: L7/Open 68: B + 09: F11 29: = + 49: L8/Paste 69: N + 0a: F4 2a: ` ~ 4a: End 6a: M + 0b: F12 2b: Backspace 4b: 6b: , < + 0c: F5 2c: Insert 4c: Control 6c: . > + 0d: Alt Graph 2d: R4/KP =/Mute 4d: A 6d: / ? + 0e: F6 2e: R5/KP / 4e: S 6e: Right Shift + 0f: Blank 2f: R6/KP * 4f: D 6f: Line Feed/\ _ + 10: F7 30: Power 50: F 70: R13/KP 1 + 11: F8 31: L5/Front 51: G 71: R14/KP 2 + 12: F9 32: KP . 52: H 72: R15/KP 3 + 13: Alt 33: L6/Copy 53: J 73: Kakutei + 14: Cursor Up 34: Home 54: K 74: Henkan + 15: R1/Pause 35: Tab 55: L 75: Nihongo On-Off + 16: R2/Print Screen 36: Q 56: ; : 76: Help + 17: R3/Scroll Lock 37: W 57: ' " 77: Caps Lock + 18: Cursor Left 38: E 58: \ | 78: Left Meta + 19: L3/Props 39: R 59: Return 79: Space + 1a: L4/Undo 3a: T 5a: Enter 7a: Right Meta + 1b: Cursor Down 3b: Y 5b: R10/KP 4 7b: Page Down + 1c: Cursor Right 3c: U 5c: R11/KP 5 7c: < > + 1d: Escape 3d: I 5d: R12/KP 6 7d: KP + + 1e: 1 3e: O 5e: KP 0 7e: + 1f: 2 3f: P 5f: L9/Find 7f: + + 00, 7e, and 7f are reserved for special messages. + L function group and R function group repurposed on Type 4 keyboard. + F10, F11, F12, Alt Graph, Compose, and Help added on Type 4 keyboard. + Num Lock, KP -, KP +, KP 0, KP ., and Enter added on Type 4 keyboard. + Line Feed removed from Type 5 keyboard. + Cursor Up, Cursor Down, Cursor Left, and Cursor Right added on Type 5 keyboard. + Insert, Home, End, Page Up, and Page Down added on Type 5 keyboard. + Volume Down, Volume Up, and Power added on Type 5 keyboard. + KP = repurposed for Mute on Type 5 keyboard. + Blank key only present on Type 5 UNIX keyboard. + < > only present on Type 5 International (ISO) keyboard. + Line Feed repurposed for backslash/underscore on Japanese Type 5 keyboard. + Kakutei, Henkan, and Nihongo On-Off only present on Japanese Type 5 keyboard. + + TODO: + * Add power key line for soft power sun4c and later systems. + * Confirm actual logic levels. + * Dump keyboard microcontrollers. +*/ #include "emu.h" #include "sunkbd.h" @@ -52,6 +139,19 @@ void sun_keyboard_port_device::device_config_complete() } +void sun_keyboard_port_device::device_validity_check(validity_checker &valid) const +{ + device_t *const card(get_card_device()); + if (card && !dynamic_cast(card)) + { + osd_printf_error( + "Card device %s (%s) does not implement device_sun_keyboard_port_interface\n", + card->tag(), + card->name()); + } +} + + void sun_keyboard_port_device::device_resolve_objects() { m_rxd_handler.resolve_safe(); @@ -60,6 +160,14 @@ void sun_keyboard_port_device::device_resolve_objects() void sun_keyboard_port_device::device_start() { + if (get_card_device() && !m_dev) + { + throw emu_fatalerror( + "Card device %s (%s) does not implement device_sun_keyboard_port_interface\n", + get_card_device()->tag(), + get_card_device()->name()); + } + save_item(NAME(m_rxd)); m_rxd = 1; diff --git a/src/devices/bus/sunkbd/sunkbd.h b/src/devices/bus/sunkbd/sunkbd.h index 43f60067a46..532193cbf0d 100644 --- a/src/devices/bus/sunkbd/sunkbd.h +++ b/src/devices/bus/sunkbd/sunkbd.h @@ -28,7 +28,7 @@ public: sun_keyboard_port_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0); virtual ~sun_keyboard_port_device(); - // static configuration helpers + // configuration helpers auto rxd_handler() { return m_rxd_handler.bind(); } DECLARE_WRITE_LINE_MEMBER( write_txd ); @@ -38,9 +38,10 @@ public: protected: sun_keyboard_port_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, uint32_t clock); + virtual void device_config_complete() override; + virtual void device_validity_check(validity_checker &valid) const override; virtual void device_resolve_objects() override; virtual void device_start() override; - virtual void device_config_complete() override; int m_rxd; @@ -58,13 +59,13 @@ class device_sun_keyboard_port_interface : public device_slot_card_interface public: virtual ~device_sun_keyboard_port_interface() override; +protected: + device_sun_keyboard_port_interface(machine_config const &mconfig, device_t &device); + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) { } DECLARE_WRITE_LINE_MEMBER( output_rxd ) { m_port->m_rxd = state; m_port->m_rxd_handler(state); } -protected: - device_sun_keyboard_port_interface(machine_config const &mconfig, device_t &device); - sun_keyboard_port_device *m_port; static constexpr int START_BIT_COUNT = 1; diff --git a/src/devices/bus/sunmouse/hlemouse.cpp b/src/devices/bus/sunmouse/hlemouse.cpp new file mode 100644 index 00000000000..4cf26a76651 --- /dev/null +++ b/src/devices/bus/sunmouse/hlemouse.cpp @@ -0,0 +1,314 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +#include "emu.h" +#include "hlemouse.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_BIT (1U << 1) + +//#define VERBOSE (LOG_GENERAL | LOG_BIT) +//#define LOG_OUTPUT_STREAM std::cerr + +#include "logmacro.h" + +#define LOGBIT(...) LOGMASKED(LOG_BIT, __VA_ARGS__) + + +/* + Mostly compatible with the Mouse Systems "non-rotatable" protocol. + The only real difference is that the mouse may send a 3-byte frame + if the movement in each axis doesn't exceed the range -120 to 127 + counts (values in the range -128 to -121 are indistinguishable from + button states). +*/ + + +/*************************************************************************** + DEVICE TYPE GLOBALS +***************************************************************************/ + +DEFINE_DEVICE_TYPE_NS(SUN_1200BAUD_HLE_MOUSE, bus::sunmouse, hle_1200baud_device, "sunmouse_hle1200", "Sun Mouse (1200 Baud, HLE)") +DEFINE_DEVICE_TYPE_NS(SUN_4800BAUD_HLE_MOUSE, bus::sunmouse, hle_4800baud_device, "sunmouse_hle4800", "Sun Mouse (4800 Baud, HLE)") + +namespace bus { namespace sunmouse { + +namespace { + +INPUT_PORTS_START( mouse ) + PORT_START("BTN") + PORT_BIT( 0xfff8, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + + PORT_START("X") + PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) + + PORT_START("Y") + PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_device_base, input_changed, nullptr) +INPUT_PORTS_END + + +uint8_t extract_delta_byte(int32_t &delta) +{ + int32_t const result(std::min(std::max(delta, -120), 127)); + delta -= result; + return uint8_t(int8_t(result)); +} + +} // anonymous namespace + + + +/*************************************************************************** + BASE HLE MOUSE DEVICE +***************************************************************************/ + +hle_device_base::hle_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + uint32_t clock, + unsigned multiplier) + : device_t(mconfig, type, tag, owner, clock) + , device_serial_interface(mconfig, *this) + , device_sun_mouse_port_interface(mconfig, *this) + , m_buttons(*this, "BTN") + , m_x_axis(*this, "X") + , m_y_axis(*this, "Y") + , m_multiplier(multiplier) + , m_x_delta(0) + , m_y_delta(0) + , m_x_val(0U) + , m_y_val(0U) + , m_btn_sent(0x00U) + , m_btn_val(0x00U) + , m_phase(0U) +{ +} + + +hle_device_base::~hle_device_base() +{ +} + + +INPUT_CHANGED_MEMBER( hle_device_base::input_changed ) +{ + if (is_transmit_register_empty()) + { + assert((0U == m_phase) || (3U == m_phase)); + + check_inputs(); + if (0U == m_phase) + { + if (m_x_delta || m_y_delta || (m_btn_sent != m_btn_val)) + { + LOG("Inputs changed (B=%X->%x X=%d Y=%d) - sending button state\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup((m_btn_sent = m_btn_val) | 0x80U); + } + } + else if (m_x_delta || m_y_delta) + { + LOG("Inputs changed (B=%X->%x X=%d Y=%d) - sending X delta\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup(extract_delta_byte(m_x_delta)); + } + else if (m_btn_sent != m_btn_val) + { + LOG("Inputs changed (B=%X->%x X=%d Y=%d) - sending button state\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + m_phase = 0U; + transmit_register_setup((m_btn_sent = m_btn_val) | 0x80U); + } + } + else + { + LOG("Ignoring input changed while transmit register not empty\n"); + } +} + + +ioport_constructor hle_device_base::device_input_ports() const +{ + return INPUT_PORTS_NAME(mouse); +} + + +void hle_device_base::device_start() +{ + save_item(NAME(m_x_delta)); + save_item(NAME(m_y_delta)); + save_item(NAME(m_x_val)); + save_item(NAME(m_y_val)); + save_item(NAME(m_phase)); + + set_data_frame(START_BIT_COUNT, DATA_BIT_COUNT, PARITY, STOP_BITS); + set_rate(BAUD * m_multiplier); + receive_register_reset(); + transmit_register_reset(); + + output_rxd(0); + + m_x_delta = 0; + m_y_delta = 0; + m_btn_sent = 0x00U; + m_phase = 0U; +} + + +void hle_device_base::device_reset() +{ + m_x_val = m_x_axis->read(); + m_y_val = m_y_axis->read(); + m_btn_val = m_buttons->read(); +} + + +void hle_device_base::tra_callback() +{ + int const bit(transmit_register_get_data_bit() ? 0 : 1); + LOGBIT("Send bit !%d\n", bit); + output_rxd(bit); +} + + +void hle_device_base::tra_complete() +{ + check_inputs(); + + if (4U <= m_phase) + m_phase = 0U; + else + ++m_phase; + + switch (m_phase) + { + // sent second Y delta - send button state if anything changed + case 0U: + if (m_x_delta || m_y_delta || (m_btn_sent != m_btn_val)) + { + LOG("Sent Y delta (B=%X->%x X=%d Y=%d) - sending button state\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup((m_btn_sent = m_btn_val) | 0x80U); + } + else + { + LOG("Sent Y delta (B=%X->%x X=%d Y=%d) - nothing to send\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + } + break; + + // can wait after sending first Y delta + case 3U: + if (!m_x_delta && !m_y_delta && (m_btn_sent == m_btn_val)) + { + LOG("Sent Y delta (B=%X->%x X=%d Y=%d) - nothing to send\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + //break; uncommenting this causes problems with early versions of Solaris + } + case 1U: + LOG("Sent %s (B=%X->%x X=%d Y=%d) - sending X delta\n", + (1U == m_phase) ? "button state" : "Y delta", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup(extract_delta_byte(m_x_delta)); + break; + + // sent X delta - always follow with Y delta + case 2U: + case 4U: + LOG("Sent X delta (B=%X->%x X=%d Y=%d) - sending Y delta\n", + m_btn_sent, + m_btn_val, + m_x_delta, + m_y_delta); + transmit_register_setup(extract_delta_byte(m_y_delta)); + break; + } +} + + +void hle_device_base::check_inputs() +{ + // read new axis values and get difference + uint16_t const x_val(m_x_axis->read()); + uint16_t const y_val(m_y_axis->read()); + int16_t x_delta(x_val - m_x_val); + int16_t y_delta(y_val - m_y_val); + + // deal with wraparound + if (0x0800 <= x_delta) + x_delta -= 0x1000; + else if (-0x8000 >= x_delta) + x_delta += 0x1000; + if (0x0800 <= y_delta) + y_delta -= 0x1000; + else if (-0x8000 >= y_delta) + x_delta += 0x1000; + + // update state + m_x_delta += x_delta; + m_y_delta -= y_delta; + m_x_val = x_val; + m_y_val = y_val; + + // read new button values + m_btn_val = m_buttons->read(); +} + + + +/*************************************************************************** + 1200 BAUD HLE MOUSE DEVICE +***************************************************************************/ + +hle_1200baud_device::hle_1200baud_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock) + : hle_device_base(mconfig, SUN_1200BAUD_HLE_MOUSE, tag, owner, clock, 8U) // FIXME: hack because z80scc isn't working properly +{ +} + + + +/*************************************************************************** + 4800 BAUD HLE MOUSE DEVICE +***************************************************************************/ + +hle_4800baud_device::hle_4800baud_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock) + : hle_device_base(mconfig, SUN_4800BAUD_HLE_MOUSE, tag, owner, clock, 4U) +{ +} + +} } // namespace bus::sunmouse diff --git a/src/devices/bus/sunmouse/hlemouse.h b/src/devices/bus/sunmouse/hlemouse.h new file mode 100644 index 00000000000..6eb5cf44b63 --- /dev/null +++ b/src/devices/bus/sunmouse/hlemouse.h @@ -0,0 +1,82 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +#ifndef MAME_DEVICES_SUNMOUSE_HLEMOUSE_H +#define MAME_DEVICES_SUNMOUSE_HLEMOUSE_H + +#pragma once + +#include "sunmouse.h" +#include "diserial.h" + + +namespace bus { namespace sunmouse { + +class hle_device_base + : public device_t + , public device_serial_interface + , public device_sun_mouse_port_interface +{ +public: + virtual ~hle_device_base() override; + + DECLARE_INPUT_CHANGED_MEMBER( input_changed ); + +protected: + // constructor/destructor + hle_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + uint32_t clock, + unsigned multiplier); + + // device overrides + virtual ioport_constructor device_input_ports() const override; + virtual void device_start() override; + virtual void device_reset() override; + + // device_serial_interface overrides + virtual void tra_callback() override; + virtual void tra_complete() override; + +private: + void check_inputs(); + + required_ioport m_buttons, m_x_axis, m_y_axis; + unsigned const m_multiplier; + int32_t m_x_delta, m_y_delta; + uint16_t m_x_val, m_y_val; + uint8_t m_btn_sent, m_btn_val; + uint8_t m_phase; +}; + + +class hle_1200baud_device : public hle_device_base +{ +public: + hle_1200baud_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock); +}; + + +class hle_4800baud_device : public hle_device_base +{ +public: + hle_4800baud_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock); +}; + +} } // namespace bus::sunmouse + + +DECLARE_DEVICE_TYPE_NS(SUN_1200BAUD_HLE_MOUSE, bus::sunmouse, hle_1200baud_device) +DECLARE_DEVICE_TYPE_NS(SUN_4800BAUD_HLE_MOUSE, bus::sunmouse, hle_4800baud_device) + +#endif // MAME_DEVICES_SUNMOUSE_HLEMOUSE_H diff --git a/src/devices/bus/sunmouse/sunmouse.cpp b/src/devices/bus/sunmouse/sunmouse.cpp new file mode 100644 index 00000000000..519b300d49b --- /dev/null +++ b/src/devices/bus/sunmouse/sunmouse.cpp @@ -0,0 +1,184 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +/* + Sun mouse port + + Pre-USB Sun keyboards use an asynchronous serial protocol. Data is + transmitted at TTL levels using an asynchronous serial protocol. + The mouse RxD line is pulled up by the host and driven low by an + open collector driver in the mouse for the mark (1) condition. This + means that if no mouse is connected, the host will see a break + condition. The protocol is mostly compatible with the Mouse Systems + "non-rotatable" protocol. + + Most Sun mouse port devices transmit data at 1,200 Baud. However, + some devices transmit at 4,800 Baud, and it's possible to modify any + Type 5 mouse for 4,800 Baud operation. Solaris 2.3 or later is + required to support a 4,800 Baud mouse. + + From the Sun 2/50 onwards, the keyboard and mouse share a single + connector, either using a splitter adapter, or by plugging the mouse + into a pass-through connector on the keyboard. + + Type 3 female DA-15 connector on host (introduced on Sun 2/50): + 1: keyboard RxD 9: GND + 2: GND 10: +5V + 3: keyboard TxD 11: +5V + 4: GND 12: +5V + 5: mouse RxD 13: +5V + 6: GND 14: +5V + 7: mouse TxD 15: +5V + 8: GND + + Type 4 female Mini-DIN-8 connector on host (introduced on Sun 3/80): + 1: GND 3: +5V 6: keyboard RxD + 2: GND 4: mouse RxD 7: mouse TxD + 5: keyboard TxD 8: +5V + + Type 5 female Mini-DIN-8 connector on host: + 1: GND 3: +5V 6: keyboard RxD + 2: GND 4: mouse RxD 7: power key + 5: keyboard TxD 8: +5V + + Type 5 and later sacrifice the TxD line from the host to the mouse + in favour of a dedicated line for the soft power key. It was never + used for anything useful with standard Sun components anyway. + + Sun 2 and Sun 3 used an optical mouse made by Mouse Systems. The + colour varied (usually black for Sun 2 and white for Sun 3). They + require a Mouse Systems optical mouse pad to work correctly. The + later Sun optical mouse for Sun 4 requires a different pad with + thinner stripes. + + The Logitech Trackman T-CB1 is a compatible replacement for a Sun + Type 4 or Type 5 mouse, made at Sun's request. + + Known Sun mouse part numbers: + * 370-1169: Type 4 optical mouse (manufactured by Mouse Systems) + * 370-1398: Type 5 optical mouse (bridge JP2 for 4,800 Baud) + * 370-1586-01: SPARCstation Voyager 4,800 Baud mouse + * 370-1586-02: Type 5 opto-mechanical mouse + * 370-1586-03: Type 5 opto-mechanical mouse + + TODO: + * Confirm polarity of TxD signal from host to mouse. + * Dump mouse microcontrollers. +*/ + +#include "emu.h" +#include "sunmouse.h" + + +DEFINE_DEVICE_TYPE(SUNMOUSE_PORT, sun_mouse_port_device, "sunmouse", "Sun Mouse Port") + + +int const device_sun_mouse_port_interface::START_BIT_COUNT; +int const device_sun_mouse_port_interface::DATA_BIT_COUNT; +device_serial_interface::parity_t const device_sun_mouse_port_interface::PARITY; +device_serial_interface::stop_bits_t const device_sun_mouse_port_interface::STOP_BITS; +int const device_sun_mouse_port_interface::BAUD; + + + +sun_mouse_port_device::sun_mouse_port_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + uint32_t clock) + : sun_mouse_port_device(mconfig, SUNMOUSE_PORT, tag, owner, clock) +{ +} + + +sun_mouse_port_device::sun_mouse_port_device( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_slot_interface(mconfig, *this) + , m_rxd(0) + , m_rxd_handler(*this) + , m_dev(nullptr) +{ +} + + +sun_mouse_port_device::~sun_mouse_port_device() +{ +} + + +void sun_mouse_port_device::device_config_complete() +{ + m_dev = dynamic_cast(get_card_device()); +} + + +void sun_mouse_port_device::device_validity_check(validity_checker &valid) const +{ + device_t *const card(get_card_device()); + if (card && !dynamic_cast(card)) + { + osd_printf_error( + "Card device %s (%s) does not implement device_sun_mouse_port_interface\n", + card->tag(), + card->name()); + } +} + + +void sun_mouse_port_device::device_resolve_objects() +{ + m_rxd = 1; + + m_rxd_handler.resolve_safe(); +} + + +void sun_mouse_port_device::device_start() +{ + if (get_card_device() && !m_dev) + { + throw emu_fatalerror( + "Card device %s (%s) does not implement device_sun_mouse_port_interface\n", + get_card_device()->tag(), + get_card_device()->name()); + } + + save_item(NAME(m_rxd)); + + if (!m_dev) + m_rxd_handler(m_rxd = 0); +} + + +WRITE_LINE_MEMBER( sun_mouse_port_device::write_txd ) +{ + if (m_dev) + m_dev->input_txd(state ? 0 : 1); +} + + + +device_sun_mouse_port_interface::device_sun_mouse_port_interface(machine_config const &mconfig, device_t &device) + : device_slot_card_interface(mconfig, device) + , m_port(dynamic_cast(device.owner())) +{ +} + + +device_sun_mouse_port_interface::~device_sun_mouse_port_interface() +{ +} + + + +#include "hlemouse.h" + +void default_sun_mouse_devices(device_slot_interface &device) +{ + device.option_add("hle1200", SUN_1200BAUD_HLE_MOUSE); + device.option_add("hle4800", SUN_4800BAUD_HLE_MOUSE); +} diff --git a/src/devices/bus/sunmouse/sunmouse.h b/src/devices/bus/sunmouse/sunmouse.h new file mode 100644 index 00000000000..ff7dd9ca86a --- /dev/null +++ b/src/devices/bus/sunmouse/sunmouse.h @@ -0,0 +1,84 @@ +// license:BSD-3-Clause +// copyright-holders:Vas Crabb +#ifndef MAME_BUS_SUNMOUSE_SUNMOUSE_H +#define MAME_BUS_SUNMOUSE_SUNMOUSE_H + +#pragma once + +#include "diserial.h" + + +class device_sun_mouse_port_interface; + + +class sun_mouse_port_device : public device_t, public device_slot_interface +{ + friend class device_sun_mouse_port_interface; + +public: + template + sun_mouse_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) + : sun_mouse_port_device(mconfig, tag, owner, 0) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_fixed(false); + } + sun_mouse_port_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock = 0); + virtual ~sun_mouse_port_device(); + + // configuration helpers + auto rxd_handler() { return m_rxd_handler.bind(); } + + DECLARE_WRITE_LINE_MEMBER( write_txd ); + + DECLARE_READ_LINE_MEMBER( rxd_r ) { return m_rxd; } + +protected: + sun_mouse_port_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, uint32_t clock); + + virtual void device_config_complete() override; + virtual void device_validity_check(validity_checker &valid) const override; + virtual void device_resolve_objects() override; + virtual void device_start() override; + + int m_rxd; + + devcb_write_line m_rxd_handler; + +private: + device_sun_mouse_port_interface *m_dev; +}; + + +class device_sun_mouse_port_interface : public device_slot_card_interface +{ + friend class sun_mouse_port_device; + +public: + virtual ~device_sun_mouse_port_interface() override; + +protected: + device_sun_mouse_port_interface(machine_config const &mconfig, device_t &device); + + virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) { } + + DECLARE_WRITE_LINE_MEMBER( output_rxd ) { m_port->m_rxd_handler(m_port->m_rxd = state ? 0 : 1); } + + sun_mouse_port_device *m_port; + + static constexpr int START_BIT_COUNT = 1; + static constexpr int DATA_BIT_COUNT = 8; + static constexpr device_serial_interface::parity_t PARITY = device_serial_interface::PARITY_NONE; + static constexpr device_serial_interface::stop_bits_t STOP_BITS = device_serial_interface::STOP_BITS_1; + static constexpr int BAUD = 1'200; +}; + + +DECLARE_DEVICE_TYPE(SUNMOUSE_PORT, sun_mouse_port_device) + + +void default_sun_mouse_devices(device_slot_interface &device); + +#endif // MAME_BUS_SUNMOUSE_SUNMOUSE_H diff --git a/src/mame/drivers/sun3.cpp b/src/mame/drivers/sun3.cpp index 76f36d39ee0..9d9c7ea59a4 100644 --- a/src/mame/drivers/sun3.cpp +++ b/src/mame/drivers/sun3.cpp @@ -190,6 +190,7 @@ fefc34a - start of mem_size, which queries ECC registers for each memory board #include "bus/rs232/rs232.h" #include "bus/sunkbd/sunkbd.h" +#include "bus/sunmouse/sunmouse.h" #include "screen.h" @@ -200,6 +201,7 @@ fefc34a - start of mem_size, which queries ECC registers for each memory board #define RS232A_TAG "rs232a" #define RS232B_TAG "rs232b" #define KEYBOARD_TAG "keyboard" +#define MOUSE_TAG "mouseport" // page table entry constants #define PM_VALID (0x80000000) // page is valid @@ -1001,8 +1003,10 @@ MACHINE_CONFIG_START(sun3_state::sun3) SCC8530N(config, m_scc1, 4.9152_MHz_XTAL); m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); + m_scc1->out_txdb_callback().set(MOUSE_TAG, FUNC(sun_mouse_port_device::write_txd)); SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type3hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); + SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); SCC8530N(config, m_scc2, 4.9152_MHz_XTAL); m_scc2->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); @@ -1085,8 +1089,10 @@ MACHINE_CONFIG_START(sun3_state::sun3_50) SCC8530N(config, m_scc1, 4.9152_MHz_XTAL); m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); + m_scc1->out_txdb_callback().set(MOUSE_TAG, FUNC(sun_mouse_port_device::write_txd)); SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type3hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); + SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); SCC8530N(config, m_scc2, 4.9152_MHz_XTAL); m_scc2->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); diff --git a/src/mame/drivers/sun3x.cpp b/src/mame/drivers/sun3x.cpp index 1607affc44a..f07021c3dc2 100644 --- a/src/mame/drivers/sun3x.cpp +++ b/src/mame/drivers/sun3x.cpp @@ -143,6 +143,7 @@ #include "bus/rs232/rs232.h" #include "bus/sunkbd/sunkbd.h" +#include "bus/sunmouse/sunmouse.h" #include "screen.h" @@ -156,6 +157,7 @@ #define RS232A_TAG "rs232a" #define RS232B_TAG "rs232b" #define KEYBOARD_TAG "keyboard" +#define MOUSE_TAG "mouseport" class sun3x_state : public driver_device { @@ -597,8 +599,10 @@ MACHINE_CONFIG_START(sun3x_state::sun3_80) SCC8530N(config, m_scc1, 4.9152_MHz_XTAL); m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); + m_scc1->out_txdb_callback().set(MOUSE_TAG, FUNC(sun_mouse_port_device::write_txd)); SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type3hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); + SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); SCC8530N(config, m_scc2, 4.9152_MHz_XTAL); m_scc2->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); diff --git a/src/mame/drivers/sun4.cpp b/src/mame/drivers/sun4.cpp index 9f42ae58af4..2be69f71d95 100644 --- a/src/mame/drivers/sun4.cpp +++ b/src/mame/drivers/sun4.cpp @@ -413,6 +413,7 @@ #include "bus/rs232/rs232.h" #include "bus/sunkbd/sunkbd.h" +#include "bus/sunmouse/sunmouse.h" #include "bus/sbus/sbus.h" #include "bus/sbus/bwtwo.h" #include "cpu/sparc/sparc.h" @@ -442,6 +443,7 @@ #define SCC1_TAG "scc1" #define SCC2_TAG "scc2" #define KEYBOARD_TAG "keyboard" +#define MOUSE_TAG "mouseport" #define RS232A_TAG "rs232a" #define RS232B_TAG "rs232b" #define FDC_TAG "fdc" @@ -2124,8 +2126,10 @@ MACHINE_CONFIG_START(sun4_state::sun4) SCC8530N(config, m_scc1, 4.9152_MHz_XTAL); m_scc1->out_int_callback().set(FUNC(sun4_state::scc1_int)); m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); + m_scc1->out_txdb_callback().set(MOUSE_TAG, FUNC(sun_mouse_port_device::write_txd)); SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type4hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); + SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); // RS232 serial ports SCC8530N(config, m_scc2, 4.9152_MHz_XTAL); @@ -2186,8 +2190,10 @@ MACHINE_CONFIG_START(sun4_state::sun4c) SCC8530N(config, m_scc1, 4.9152_MHz_XTAL); m_scc1->out_int_callback().set(FUNC(sun4_state::scc1_int)); m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); + // no mouse TxD connection - replaced with soft power request input SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type5hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); + SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); // RS232 serial ports SCC8530N(config, m_scc2, 4.9152_MHz_XTAL);