332 lines
10 KiB
C++
332 lines
10 KiB
C++
/////////////////////////////////////////////////////////////////////////
|
|
// $Id$
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2004-2009 The Bochs Project
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
// Initial code by Ben Lunt 'fys frontiernet net'
|
|
|
|
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
|
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
|
// is used to know when we are exporting symbols and when we are importing.
|
|
#define BX_PLUGGABLE
|
|
|
|
#include "iodev.h"
|
|
#include "busmouse.h"
|
|
|
|
#if BX_SUPPORT_BUSMOUSE
|
|
|
|
#define LOG_THIS theBusMouse->
|
|
|
|
bx_busm_c *theBusMouse = NULL;
|
|
|
|
int libbusmouse_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
|
{
|
|
// Create one instance of the busmouse device object.
|
|
theBusMouse = new bx_busm_c();
|
|
// Register this device.
|
|
BX_REGISTER_DEVICE_DEVMODEL (plugin, type, theBusMouse, BX_PLUGIN_BUSMOUSE);
|
|
return(0); // Success
|
|
}
|
|
|
|
void libbusmouse_LTX_plugin_fini(void)
|
|
{
|
|
delete theBusMouse;
|
|
}
|
|
|
|
bx_busm_c::bx_busm_c()
|
|
{
|
|
put("BUSM");
|
|
}
|
|
|
|
bx_busm_c::~bx_busm_c()
|
|
{
|
|
BX_DEBUG(("Exit"));
|
|
}
|
|
|
|
void bx_busm_c::init(void)
|
|
{
|
|
BX_DEBUG(("Init $Id$"));
|
|
|
|
DEV_register_irq(BUS_MOUSE_IRQ, "Bus Mouse");
|
|
|
|
// Call our timer routine at 30hz
|
|
BX_BUSM_THIS timer_index =
|
|
bx_pc_system.register_timer(this, timer_handler, 33334, 1, 1, "bus mouse timer");
|
|
|
|
for (int i=0x23C; i<=0x23F; i++) {
|
|
DEV_register_ioread_handler(this, read_handler, i, "Bus Mouse", 1);
|
|
DEV_register_iowrite_handler(this, write_handler, i, "Bus Mouse", 1);
|
|
}
|
|
DEV_register_default_mouse(this, mouse_enq_static, NULL);
|
|
|
|
BX_BUSM_THIS mouse_delayed_dx = 0;
|
|
BX_BUSM_THIS mouse_delayed_dy = 0;
|
|
BX_BUSM_THIS current_x =
|
|
BX_BUSM_THIS current_y =
|
|
BX_BUSM_THIS current_b = 0;
|
|
|
|
BX_BUSM_THIS sig_port_sequ = 0;
|
|
BX_BUSM_THIS interrupts = 0; // interrupts off
|
|
BX_BUSM_THIS command_val = 0; // command byte
|
|
BX_BUSM_THIS cur_command = 0;
|
|
|
|
// the control port values
|
|
BX_BUSM_THIS control_val =
|
|
BX_BUSM_THIS control.mode_set =
|
|
BX_BUSM_THIS control.modeA_select =
|
|
BX_BUSM_THIS control.portA_dir =
|
|
BX_BUSM_THIS control.portC_upper_dir =
|
|
BX_BUSM_THIS control.modeBC_select =
|
|
BX_BUSM_THIS control.portB_dir =
|
|
BX_BUSM_THIS control.portC_lower_dir =
|
|
BX_BUSM_THIS control_val = 0;
|
|
|
|
BX_INFO(("Initialized BusMouse"));
|
|
}
|
|
|
|
void bx_busm_c::register_state(void)
|
|
{
|
|
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "busmouse", "Busmouse State", 12);
|
|
BXRS_HEX_PARAM_FIELD(list, mouse_delayed_dx, BX_BUSM_THIS mouse_delayed_dx);
|
|
BXRS_HEX_PARAM_FIELD(list, mouse_delayed_dx, BX_BUSM_THIS mouse_delayed_dy);
|
|
BXRS_HEX_PARAM_FIELD(list, current_x, BX_BUSM_THIS current_x);
|
|
BXRS_HEX_PARAM_FIELD(list, current_y, BX_BUSM_THIS current_y);
|
|
BXRS_HEX_PARAM_FIELD(list, current_b, BX_BUSM_THIS current_b);
|
|
BXRS_HEX_PARAM_FIELD(list, sig_port_sequ, BX_BUSM_THIS sig_port_sequ);
|
|
BXRS_HEX_PARAM_FIELD(list, control_val, BX_BUSM_THIS control_val);
|
|
|
|
bx_list_c *ctrl = new bx_list_c(list, "control", 7);
|
|
BXRS_PARAM_BOOL(ctrl, mode_set, BX_BUSM_THIS control.mode_set);
|
|
BXRS_HEX_PARAM_FIELD(ctrl, modeA_select, BX_BUSM_THIS control.modeA_select);
|
|
BXRS_PARAM_BOOL(ctrl, portA_dir, BX_BUSM_THIS control.portA_dir);
|
|
BXRS_PARAM_BOOL(ctrl, portC_upper_dir, BX_BUSM_THIS control.portC_upper_dir);
|
|
BXRS_PARAM_BOOL(ctrl, modeBC_select, BX_BUSM_THIS control.modeBC_select);
|
|
BXRS_PARAM_BOOL(ctrl, portB_dir, BX_BUSM_THIS control.portB_dir);
|
|
BXRS_PARAM_BOOL(ctrl, portC_lower_dir, BX_BUSM_THIS control.portC_lower_dir);
|
|
|
|
BXRS_PARAM_BOOL(list, interrupts, BX_BUSM_THIS interrupts);
|
|
BXRS_PARAM_BOOL(list, packet_update, BX_BUSM_THIS packet_update);
|
|
BXRS_HEX_PARAM_FIELD(list, cur_command, BX_BUSM_THIS cur_command);
|
|
BXRS_HEX_PARAM_FIELD(list, command_val, BX_BUSM_THIS command_val);
|
|
}
|
|
|
|
// static IO port read callback handler
|
|
// redirects to non-static class handler to avoid virtual functions
|
|
Bit32u bx_busm_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
|
{
|
|
#if !BX_USE_BUSM_SMF
|
|
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
|
|
return class_ptr->read(address, io_len);
|
|
}
|
|
|
|
Bit32u bx_busm_c::read(Bit32u address, unsigned io_len)
|
|
{
|
|
#else
|
|
UNUSED(this_ptr);
|
|
#endif // !BX_USE_BUSM_SMF
|
|
|
|
Bit8u value = 0;
|
|
|
|
switch (address) {
|
|
case 0x023C:
|
|
value = BX_BUSM_THIS control_val;
|
|
/* value = (BX_BUSM_THIS control.mode_set ? 1<<7 : 0)
|
|
* | (BX_BUSM_THIS control.modeA_select <<5)
|
|
* | (BX_BUSM_THIS control.portA_dir ? 1<<4 : 0)
|
|
* | (BX_BUSM_THIS control.portC_upper_dir ? 1<<3 : 0)
|
|
* | (BX_BUSM_THIS control.modeBC_select ? 1<<2 : 0)
|
|
* | (BX_BUSM_THIS control.portB_dir ? 1<<1 : 0)
|
|
* | (BX_BUSM_THIS control.portC_lower_dir ? 1<<0 : 0);
|
|
*/ break;
|
|
case 0x023D: // data
|
|
switch (BX_BUSM_THIS cur_command) {
|
|
case 0x00: // read buttons
|
|
value = BX_BUSM_THIS current_b;
|
|
break;
|
|
case 0x01: // read x
|
|
value = BX_BUSM_THIS current_x;
|
|
break;
|
|
case 0x02: // read y
|
|
value = BX_BUSM_THIS current_y;
|
|
break;
|
|
case 0x07: // command mode
|
|
value = BX_BUSM_THIS command_val;
|
|
break;
|
|
default:
|
|
BX_PANIC(("Unknown command to data port: %x", BX_BUSM_THIS cur_command));
|
|
}
|
|
break;
|
|
case 0x023E: // sig
|
|
if (!(BX_BUSM_THIS sig_port_sequ & 1))
|
|
value = 0xDE;
|
|
else
|
|
value = 0x22; // Manufacture id?
|
|
BX_BUSM_THIS sig_port_sequ++;
|
|
break;
|
|
case 0x023F:
|
|
BX_PANIC(("Read from port 0x023F"));
|
|
break;
|
|
}
|
|
|
|
BX_INFO(("read from address 0x%04x, value = 0x%02x ", address, value));
|
|
|
|
return value;
|
|
}
|
|
|
|
// static IO port write callback handler
|
|
// redirects to non-static class handler to avoid virtual functions
|
|
|
|
void bx_busm_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
|
{
|
|
#if !BX_USE_BUSM_SMF
|
|
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
|
|
class_ptr->write(address, value, io_len);
|
|
}
|
|
|
|
void bx_busm_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
|
{
|
|
#else
|
|
UNUSED(this_ptr);
|
|
#endif // !BX_USE_BUSM_SMF
|
|
|
|
BX_INFO(("write to address 0x%04x, value = 0x%02x ", address, value));
|
|
|
|
switch (address) {
|
|
case 0x023C: // control
|
|
BX_BUSM_THIS control.mode_set = (value & 0x80) ? 1 : 0;
|
|
BX_BUSM_THIS control.modeA_select = (value & 0x60) >> 5;
|
|
BX_BUSM_THIS control.portA_dir = (value & 0x10) ? 1 : 0;
|
|
BX_BUSM_THIS control.portC_upper_dir = (value & 0x08) ? 1 : 0;
|
|
BX_BUSM_THIS control.modeBC_select = (value & 0x04) ? 1 : 0;
|
|
BX_BUSM_THIS control.portB_dir = (value & 0x02) ? 1 : 0;
|
|
BX_BUSM_THIS control.portC_lower_dir = (value & 0x01) ? 1 : 0;
|
|
BX_BUSM_THIS control_val = value;
|
|
|
|
/*
|
|
switch (value) {
|
|
case 0x00: // read buttons
|
|
case 0x01: // read x
|
|
case 0x02: // read y
|
|
case 0x07:
|
|
BX_BUSM_THIS cur_command = (Bit8u) value;
|
|
break;
|
|
case 0x80: // reset
|
|
BX_BUSM_THIS cur_command = 0x00;
|
|
BX_BUSM_THIS command_val = 0x80;
|
|
break;
|
|
default:
|
|
BX_PANIC(("Unknown command to control port %x", value));
|
|
}
|
|
*/
|
|
break;
|
|
case 0x023D: // data port
|
|
switch (BX_BUSM_THIS cur_command) {
|
|
case 0x07: // command mode
|
|
switch (value) {
|
|
case 0x10: // interrupts off
|
|
BX_BUSM_THIS interrupts = 0;
|
|
break;
|
|
case 0x11: // interrupts on
|
|
BX_BUSM_THIS interrupts = 1;
|
|
break;
|
|
default:
|
|
BX_BUSM_THIS command_val = value;
|
|
if ((value & 0x20) == 0)
|
|
DEV_pic_lower_irq(BUS_MOUSE_IRQ);
|
|
}
|
|
break;
|
|
default:
|
|
BX_PANIC(("Unknown command written to data port: %x", BX_BUSM_THIS cur_command));
|
|
}
|
|
break;
|
|
case 0x023E:
|
|
BX_PANIC(("Write to port 0x023E"));
|
|
break;
|
|
case 0x023F:
|
|
BX_PANIC(("Write to port 0x023F"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void bx_busm_c::mouse_enq_static(void *dev, int delta_x, int delta_y, int delta_z, unsigned button_state)
|
|
{
|
|
((bx_busm_c*)dev)->mouse_enq(delta_x, delta_y, delta_z, button_state);
|
|
}
|
|
|
|
void bx_busm_c::mouse_enq(int delta_x, int delta_y, int delta_z, unsigned button_state)
|
|
{
|
|
// scale down the motion
|
|
if ((delta_x < -1) || (delta_x > 1))
|
|
delta_x /= 2;
|
|
if ((delta_y < -1) || (delta_y > 1))
|
|
delta_y /= 2;
|
|
|
|
if(delta_x>127) delta_x=127;
|
|
if(delta_y>127) delta_y=127;
|
|
if(delta_x<-128) delta_x=-128;
|
|
if(delta_y<-128) delta_y=-128;
|
|
|
|
BX_BUSM_THIS mouse_delayed_dx+=delta_x;
|
|
BX_BUSM_THIS mouse_delayed_dy-=delta_y;
|
|
|
|
if (BX_BUSM_THIS mouse_delayed_dx > 127) {
|
|
delta_x = 127;
|
|
BX_BUSM_THIS mouse_delayed_dx -= 127;
|
|
} else if (BX_BUSM_THIS mouse_delayed_dx < -128) {
|
|
delta_x = -128;
|
|
BX_BUSM_THIS mouse_delayed_dx += 128;
|
|
} else {
|
|
delta_x = BX_BUSM_THIS mouse_delayed_dx;
|
|
BX_BUSM_THIS mouse_delayed_dx = 0;
|
|
}
|
|
if (BX_BUSM_THIS mouse_delayed_dy > 127) {
|
|
delta_y = 127;
|
|
BX_BUSM_THIS mouse_delayed_dy -= 127;
|
|
} else if (BX_BUSM_THIS mouse_delayed_dy < -128) {
|
|
delta_y = -128;
|
|
BX_BUSM_THIS mouse_delayed_dy += 128;
|
|
} else {
|
|
delta_y = BX_BUSM_THIS mouse_delayed_dy;
|
|
BX_BUSM_THIS mouse_delayed_dy = 0;
|
|
}
|
|
|
|
if ((BX_BUSM_THIS cur_command & 0x20) == 0x00) {
|
|
BX_BUSM_THIS current_x = (Bit8u) delta_x;
|
|
BX_BUSM_THIS current_y = (Bit8u) delta_y;
|
|
BX_BUSM_THIS current_b = (Bit8u) ~(((button_state & 0x01)<<2) | ((button_state & 0x02) >> 1));
|
|
}
|
|
}
|
|
|
|
void bx_busm_c::timer_handler(void *this_ptr)
|
|
{
|
|
bx_busm_c *class_ptr = (bx_busm_c *) this_ptr;
|
|
class_ptr->busm_timer();
|
|
}
|
|
|
|
// Called at 30hz
|
|
void bx_busm_c::busm_timer(void)
|
|
{
|
|
// if interrupts are on, fire the interrupt
|
|
if (BX_BUSM_THIS interrupts) {
|
|
DEV_pic_raise_irq(BUS_MOUSE_IRQ);
|
|
}
|
|
}
|
|
|
|
#endif // BX_SUPPORT_BUSMOUSE
|