2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2011-02-25 01:05:47 +03:00
|
|
|
// $Id$
|
2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2020-03-03 01:04:10 +03:00
|
|
|
// Copyright (C) 2002-2020 The Bochs Project
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
2004-01-15 05:08:37 +03:00
|
|
|
// I/O port handlers API Copyright (C) 2003 by Frank Cornelis
|
2008-01-27 01:24:03 +03:00
|
|
|
//
|
2001-04-10 05:04:59 +04:00
|
|
|
// 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
|
2009-02-08 12:05:52 +03:00
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2008-04-17 18:39:33 +04:00
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
2004-06-19 19:20:15 +04:00
|
|
|
#include "iodev.h"
|
2020-12-19 14:00:36 +03:00
|
|
|
#include "gui/keymap.h"
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-12-29 23:16:08 +03:00
|
|
|
#include "iodev/virt_timer.h"
|
|
|
|
#include "iodev/slowdown_timer.h"
|
2017-02-20 21:21:19 +03:00
|
|
|
#include "iodev/sound/soundmod.h"
|
2017-03-12 10:48:08 +03:00
|
|
|
#include "iodev/network/netmod.h"
|
2017-05-28 11:13:06 +03:00
|
|
|
#include "iodev/usb/usb_common.h"
|
2008-12-29 23:16:08 +03:00
|
|
|
|
|
|
|
#define LOG_THIS bx_devices.
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* main memory size (in Kbytes)
|
|
|
|
* subtract 1k for extended BIOS area
|
|
|
|
* report only base memory, not extended mem
|
|
|
|
*/
|
|
|
|
#define BASE_MEMORY_IN_K 640
|
|
|
|
|
|
|
|
|
|
|
|
bx_devices_c bx_devices;
|
|
|
|
|
|
|
|
|
2002-08-27 23:54:46 +04:00
|
|
|
// constructor for bx_devices_c
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_devices_c::bx_devices_c()
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2012-02-23 21:16:35 +04:00
|
|
|
put("devices", "DEV");
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
read_port_to_handler = NULL;
|
|
|
|
write_port_to_handler = NULL;
|
2006-09-20 22:24:17 +04:00
|
|
|
io_read_handlers.next = NULL;
|
|
|
|
io_read_handlers.handler_name = NULL;
|
|
|
|
io_write_handlers.next = NULL;
|
|
|
|
io_write_handlers.handler_name = NULL;
|
2006-09-10 21:18:44 +04:00
|
|
|
init_stubs();
|
2006-09-13 22:51:25 +04:00
|
|
|
|
|
|
|
for (unsigned i=0; i < BX_MAX_IRQS; i++) {
|
|
|
|
irq_handler_name[i] = NULL;
|
|
|
|
}
|
2006-09-10 21:18:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bx_devices_c::~bx_devices_c()
|
|
|
|
{
|
|
|
|
timer_handle = BX_NULL_TIMER_HANDLE;
|
2020-12-19 14:00:36 +03:00
|
|
|
// remove runtime parameter handlers
|
|
|
|
SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->set_handler(NULL);
|
|
|
|
SIM->get_param_num(BXPN_MOUSE_ENABLED)->set_handler(NULL);
|
|
|
|
if (paste.buf != NULL) {
|
|
|
|
delete [] paste.buf;
|
|
|
|
}
|
2006-09-10 21:18:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void bx_devices_c::init_stubs()
|
|
|
|
{
|
2017-03-26 11:09:28 +03:00
|
|
|
pluginCmosDevice = &stubCmos;
|
2002-10-25 01:07:56 +04:00
|
|
|
pluginDmaDevice = &stubDma;
|
|
|
|
pluginHardDrive = &stubHardDrive;
|
2017-03-26 11:09:28 +03:00
|
|
|
pluginPicDevice = &stubPic;
|
2017-04-15 23:31:07 +03:00
|
|
|
pluginPitDevice = &stubPit;
|
2004-02-03 00:47:26 +03:00
|
|
|
pluginSpeaker = &stubSpeaker;
|
2017-03-26 11:09:28 +03:00
|
|
|
pluginVgaDevice = &stubVga;
|
2004-08-06 19:49:55 +04:00
|
|
|
#if BX_SUPPORT_IODEBUG
|
2008-12-30 21:11:13 +03:00
|
|
|
pluginIODebug = &stubIODebug;
|
2001-09-14 19:01:29 +04:00
|
|
|
#endif
|
2009-11-20 17:58:48 +03:00
|
|
|
#if BX_SUPPORT_APIC
|
2009-02-22 13:44:50 +03:00
|
|
|
pluginIOAPIC = &stubIOAPIC;
|
|
|
|
#endif
|
2011-03-31 20:54:06 +04:00
|
|
|
#if BX_SUPPORT_GAMEPORT
|
|
|
|
pluginGameport = &stubGameport;
|
|
|
|
#endif
|
2017-03-26 11:09:28 +03:00
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
pluginPci2IsaBridge = &stubPci2Isa;
|
|
|
|
pluginPciIdeController = &stubPciIde;
|
|
|
|
pluginACPIController = &stubACPIController;
|
|
|
|
#endif
|
2002-08-27 21:25:18 +04:00
|
|
|
}
|
|
|
|
|
2006-03-14 21:11:22 +03:00
|
|
|
void bx_devices_c::init(BX_MEM_C *newmem)
|
2002-08-27 21:25:18 +04:00
|
|
|
{
|
2017-03-26 11:09:28 +03:00
|
|
|
#if BX_SUPPORT_PCI
|
2018-02-25 23:59:30 +03:00
|
|
|
unsigned chipset = SIM->get_param_enum(BXPN_PCI_CHIPSET)->get();
|
|
|
|
unsigned max_pci_slots = BX_N_PCI_SLOTS;
|
2017-03-26 11:09:28 +03:00
|
|
|
#endif
|
2020-12-03 23:30:10 +03:00
|
|
|
unsigned i, argc;
|
2006-09-20 22:24:17 +04:00
|
|
|
const char def_name[] = "Default";
|
2020-12-03 23:30:10 +03:00
|
|
|
const char *vga_ext, *options;
|
|
|
|
char *argv[16];
|
2002-08-27 21:25:18 +04:00
|
|
|
|
2011-02-25 01:05:47 +03:00
|
|
|
BX_DEBUG(("Init $Id$"));
|
2002-08-27 21:25:18 +04:00
|
|
|
mem = newmem;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2009-01-15 20:34:20 +03:00
|
|
|
/* set builtin default handlers, will be overwritten by the real default handler */
|
2006-09-21 00:52:23 +04:00
|
|
|
register_default_io_read_handler(NULL, &default_read_handler, def_name, 7);
|
2004-01-15 05:08:37 +03:00
|
|
|
io_read_handlers.next = &io_read_handlers;
|
|
|
|
io_read_handlers.prev = &io_read_handlers;
|
|
|
|
io_read_handlers.usage_count = 0; // not used with the default handler
|
2006-09-21 00:52:23 +04:00
|
|
|
|
|
|
|
register_default_io_write_handler(NULL, &default_write_handler, def_name, 7);
|
2004-01-15 05:08:37 +03:00
|
|
|
io_write_handlers.next = &io_write_handlers;
|
|
|
|
io_write_handlers.prev = &io_write_handlers;
|
|
|
|
io_write_handlers.usage_count = 0; // not used with the default handler
|
|
|
|
|
|
|
|
if (read_port_to_handler)
|
2006-09-20 22:24:17 +04:00
|
|
|
delete [] read_port_to_handler;
|
2004-01-15 05:08:37 +03:00
|
|
|
if (write_port_to_handler)
|
2006-09-20 22:24:17 +04:00
|
|
|
delete [] write_port_to_handler;
|
2004-01-15 05:08:37 +03:00
|
|
|
read_port_to_handler = new struct io_handler_struct *[PORTS];
|
|
|
|
write_port_to_handler = new struct io_handler_struct *[PORTS];
|
2002-10-25 01:07:56 +04:00
|
|
|
|
|
|
|
/* set handlers to the default one */
|
2004-01-15 05:08:37 +03:00
|
|
|
for (i=0; i < PORTS; i++) {
|
2008-01-27 01:24:03 +03:00
|
|
|
read_port_to_handler[i] = &io_read_handlers;
|
|
|
|
write_port_to_handler[i] = &io_write_handlers;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
for (i=0; i < BX_MAX_IRQS; i++) {
|
2006-09-13 22:51:25 +04:00
|
|
|
delete [] irq_handler_name[i];
|
2001-04-10 05:04:59 +04:00
|
|
|
irq_handler_name[i] = NULL;
|
2006-05-18 23:57:11 +04:00
|
|
|
}
|
|
|
|
|
2009-03-03 21:29:51 +03:00
|
|
|
// removable devices init
|
2020-12-13 00:27:43 +03:00
|
|
|
for (i=0; i < 2; i++) {
|
|
|
|
bx_keyboard[i].dev = NULL;
|
|
|
|
bx_keyboard[i].gen_scancode = NULL;
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_keyboard[i].led_mask = 0;
|
2020-12-13 00:27:43 +03:00
|
|
|
}
|
2017-04-22 18:32:07 +03:00
|
|
|
for (i = 0; i < BX_KEY_NBKEYS; i++) {
|
2020-12-13 00:27:43 +03:00
|
|
|
bx_keyboard[0].bxkey_state[i] = 0;
|
2017-04-22 18:32:07 +03:00
|
|
|
}
|
2009-03-03 23:34:50 +03:00
|
|
|
for (i=0; i < 2; i++) {
|
|
|
|
bx_mouse[i].dev = NULL;
|
|
|
|
bx_mouse[i].enq_event = NULL;
|
|
|
|
bx_mouse[i].enabled_changed = NULL;
|
|
|
|
}
|
2009-01-13 22:01:19 +03:00
|
|
|
// common mouse settings
|
|
|
|
mouse_captured = SIM->get_param_bool(BXPN_MOUSE_ENABLED)->get();
|
|
|
|
mouse_type = SIM->get_param_enum(BXPN_MOUSE_TYPE)->get();
|
|
|
|
|
2020-12-19 14:00:36 +03:00
|
|
|
// initialize paste feature
|
|
|
|
paste.buf = NULL;
|
|
|
|
paste.buf_len = 0;
|
|
|
|
paste.buf_ptr = 0;
|
|
|
|
paste.service = 0;
|
|
|
|
paste.stop = 0;
|
|
|
|
paste_delay_changed(SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->get());
|
|
|
|
|
|
|
|
// init runtime parameters
|
|
|
|
SIM->get_param_num(BXPN_KBD_PASTE_DELAY)->set_handler(param_handler);
|
|
|
|
SIM->get_param_num(BXPN_MOUSE_ENABLED)->set_handler(param_handler);
|
|
|
|
|
2006-05-18 23:57:11 +04:00
|
|
|
// register as soon as possible - the devices want to have their timers !
|
|
|
|
bx_virt_timer.init();
|
|
|
|
bx_slowdown_timer.init();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-10-25 16:28:34 +04:00
|
|
|
// BBD: At present, the only difference between "core" and "optional"
|
|
|
|
// plugins is that initialization and reset of optional plugins is handled
|
|
|
|
// by the plugin device list (). Init and reset of core plugins is done
|
|
|
|
// "by hand" in this file. Basically, we're using core plugins when we
|
|
|
|
// want to control the init order.
|
|
|
|
//
|
2011-01-13 01:34:42 +03:00
|
|
|
PLUG_load_plugin(hdimage, PLUGTYPE_CORE);
|
2011-08-16 21:27:27 +04:00
|
|
|
#if BX_NETWORKING
|
2012-08-20 11:35:30 +04:00
|
|
|
network_enabled = is_network_enabled();
|
|
|
|
if (network_enabled)
|
2017-03-12 10:48:08 +03:00
|
|
|
bx_netmod_ctl.init();
|
2012-01-13 21:04:47 +04:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_SOUNDLOW
|
2012-08-20 11:35:30 +04:00
|
|
|
sound_enabled = is_sound_enabled();
|
2013-06-24 23:19:12 +04:00
|
|
|
if (sound_enabled) {
|
2017-02-20 21:21:19 +03:00
|
|
|
bx_soundmod_ctl.init();
|
2013-06-24 23:19:12 +04:00
|
|
|
}
|
2011-08-16 21:27:27 +04:00
|
|
|
#endif
|
2009-02-21 14:43:18 +03:00
|
|
|
// PCI logic (i440FX)
|
2020-12-03 23:30:10 +03:00
|
|
|
memset(argv, 0, sizeof(argv));
|
2012-11-11 12:11:17 +04:00
|
|
|
pci.enabled = SIM->get_param_bool(BXPN_PCI_ENABLED)->get();
|
2012-11-08 23:12:26 +04:00
|
|
|
if (pci.enabled) {
|
2009-02-21 14:43:18 +03:00
|
|
|
#if BX_SUPPORT_PCI
|
2020-12-04 20:04:40 +03:00
|
|
|
if (chipset == BX_PCI_CHIPSET_I430FX) {
|
|
|
|
pci.advopts = (BX_PCI_ADVOPT_NOHPET | BX_PCI_ADVOPT_NOACPI);
|
|
|
|
} else {
|
|
|
|
pci.advopts = 0;
|
|
|
|
}
|
|
|
|
options = SIM->get_param_string(BXPN_PCI_ADV_OPTS)->getptr();
|
|
|
|
argc = bx_split_option_list("PCI advanced options", options, argv, 16);
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (!strcmp(argv[i], "noacpi")) {
|
|
|
|
if (chipset == BX_PCI_CHIPSET_I440FX) {
|
|
|
|
pci.advopts = BX_PCI_ADVOPT_NOACPI;
|
|
|
|
} else {
|
|
|
|
BX_ERROR(("Disabling ACPI not supported by PCI chipset"));
|
|
|
|
}
|
|
|
|
} else if (!strcmp(argv[i], "nohpet")) {
|
|
|
|
pci.advopts = BX_PCI_ADVOPT_NOHPET;
|
|
|
|
} else {
|
|
|
|
BX_ERROR(("Unknown advanced PCI option '%s'", argv[i]));
|
|
|
|
}
|
|
|
|
free(argv[i]);
|
|
|
|
argv[i] = NULL;
|
|
|
|
}
|
2009-02-21 14:43:18 +03:00
|
|
|
PLUG_load_plugin(pci, PLUGTYPE_CORE);
|
|
|
|
PLUG_load_plugin(pci2isa, PLUGTYPE_CORE);
|
2011-01-13 01:34:42 +03:00
|
|
|
#if BX_SUPPORT_PCIUSB
|
2017-05-28 11:13:06 +03:00
|
|
|
usb_enabled = is_usb_enabled();
|
|
|
|
if (usb_enabled)
|
|
|
|
bx_usbdev_ctl.init();
|
2018-02-24 21:04:36 +03:00
|
|
|
if ((chipset == BX_PCI_CHIPSET_I440FX) ||
|
|
|
|
(chipset == BX_PCI_CHIPSET_I440BX)) {
|
|
|
|
// UHCI is a part of the PIIX3/PIIX4, so load / enable it
|
2012-12-14 20:10:25 +04:00
|
|
|
if (!PLUG_device_present("usb_uhci")) {
|
|
|
|
PLUG_load_plugin(usb_uhci, PLUGTYPE_OPTIONAL);
|
|
|
|
}
|
|
|
|
SIM->get_param_bool(BXPN_UHCI_ENABLED)->set(1);
|
|
|
|
}
|
2011-01-13 01:34:42 +03:00
|
|
|
#endif
|
2020-12-04 20:04:40 +03:00
|
|
|
if ((pci.advopts & BX_PCI_ADVOPT_NOACPI) == 0) {
|
2012-11-11 12:11:17 +04:00
|
|
|
PLUG_load_plugin(acpi, PLUGTYPE_STANDARD);
|
2018-02-24 21:04:36 +03:00
|
|
|
}
|
2020-12-04 20:04:40 +03:00
|
|
|
if ((pci.advopts & BX_PCI_ADVOPT_NOHPET) == 0) {
|
2017-04-17 10:26:00 +03:00
|
|
|
PLUG_load_plugin(hpet, PLUGTYPE_STANDARD);
|
2012-11-11 12:11:17 +04:00
|
|
|
}
|
2009-02-21 14:43:18 +03:00
|
|
|
#else
|
|
|
|
BX_ERROR(("Bochs is not compiled with PCI support"));
|
2009-05-05 20:13:13 +04:00
|
|
|
#endif
|
2009-02-21 14:43:18 +03:00
|
|
|
}
|
2012-01-13 21:04:47 +04:00
|
|
|
PLUG_load_plugin(cmos, PLUGTYPE_CORE);
|
|
|
|
PLUG_load_plugin(dma, PLUGTYPE_CORE);
|
|
|
|
PLUG_load_plugin(pic, PLUGTYPE_CORE);
|
|
|
|
PLUG_load_plugin(pit, PLUGTYPE_CORE);
|
2012-01-25 01:58:24 +04:00
|
|
|
vga_ext = SIM->get_param_string(BXPN_VGA_EXTENSION)->getptr();
|
|
|
|
if (!strcmp(vga_ext, "cirrus")) {
|
|
|
|
#if BX_SUPPORT_CLGD54XX
|
|
|
|
PLUG_load_plugin(svga_cirrus, PLUGTYPE_CORE);
|
|
|
|
#else
|
2013-09-05 11:38:22 +04:00
|
|
|
BX_PANIC(("Bochs is not compiled with Cirrus support"));
|
2012-01-25 01:58:24 +04:00
|
|
|
#endif
|
2017-10-10 21:06:16 +03:00
|
|
|
} else if (!strcmp(vga_ext, "vbe") || !strcmp(vga_ext, "none")) {
|
2012-01-25 01:58:24 +04:00
|
|
|
PLUG_load_plugin(vga, PLUGTYPE_CORE);
|
2017-10-10 21:06:16 +03:00
|
|
|
} else if (pluginVgaDevice == &stubVga) {
|
|
|
|
BX_PANIC(("No VGA compatible display adapter present"));
|
2012-01-25 01:58:24 +04:00
|
|
|
}
|
2014-05-26 21:04:02 +04:00
|
|
|
PLUG_load_plugin(floppy, PLUGTYPE_CORE);
|
2009-02-21 14:43:18 +03:00
|
|
|
|
2011-12-27 17:02:35 +04:00
|
|
|
#if BX_SUPPORT_APIC
|
2012-01-10 21:45:18 +04:00
|
|
|
PLUG_load_plugin(ioapic, PLUGTYPE_STANDARD);
|
2011-12-27 17:02:35 +04:00
|
|
|
#endif
|
2012-01-10 21:45:18 +04:00
|
|
|
PLUG_load_plugin(keyboard, PLUGTYPE_STANDARD);
|
2004-12-11 11:35:33 +03:00
|
|
|
#if BX_SUPPORT_BUSMOUSE
|
2016-03-31 20:24:34 +03:00
|
|
|
if ((mouse_type == BX_MOUSE_TYPE_INPORT) ||
|
|
|
|
(mouse_type == BX_MOUSE_TYPE_BUS)) {
|
2004-12-11 11:35:33 +03:00
|
|
|
PLUG_load_plugin(busmouse, PLUGTYPE_OPTIONAL);
|
|
|
|
}
|
|
|
|
#endif
|
2011-12-22 14:35:49 +04:00
|
|
|
if (is_harddrv_enabled()) {
|
2012-01-10 21:45:18 +04:00
|
|
|
PLUG_load_plugin(harddrv, PLUGTYPE_STANDARD);
|
2011-12-22 14:35:49 +04:00
|
|
|
#if BX_SUPPORT_PCI
|
2012-11-08 23:12:26 +04:00
|
|
|
if (pci.enabled) {
|
2012-01-10 21:45:18 +04:00
|
|
|
PLUG_load_plugin(pci_ide, PLUGTYPE_STANDARD);
|
2011-12-22 14:35:49 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// system hardware
|
2005-10-01 21:40:07 +04:00
|
|
|
register_io_read_handler(this, &read_handler, 0x0092,
|
|
|
|
"Port 92h System Control", 1);
|
|
|
|
register_io_write_handler(this, &write_handler, 0x0092,
|
|
|
|
"Port 92h System Control", 1);
|
2012-11-08 23:12:26 +04:00
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
if (pci.enabled) {
|
|
|
|
pci.num_pci_handlers = 0;
|
|
|
|
|
|
|
|
/* set unused elements to appropriate values */
|
|
|
|
for (i=0; i < BX_MAX_PCI_DEVICES; i++) {
|
|
|
|
pci.pci_handler[i].handler = NULL;
|
|
|
|
}
|
|
|
|
|
2018-02-25 23:59:30 +03:00
|
|
|
for (i=0; i < 0x101; i++) {
|
2012-11-08 23:12:26 +04:00
|
|
|
pci.handler_id[i] = BX_MAX_PCI_DEVICES; // not assigned
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i < BX_N_PCI_SLOTS; i++) {
|
|
|
|
pci.slot_used[i] = 0; // no device connected
|
|
|
|
}
|
|
|
|
|
2020-12-01 22:47:27 +03:00
|
|
|
if (chipset == BX_PCI_CHIPSET_I440BX) {
|
|
|
|
pci.map_slot_to_dev = 8;
|
|
|
|
} else {
|
|
|
|
pci.map_slot_to_dev = 2;
|
|
|
|
}
|
|
|
|
|
2012-11-08 23:12:26 +04:00
|
|
|
// confAddr accepts dword i/o only
|
2020-12-01 22:47:27 +03:00
|
|
|
DEV_register_ioread_handler(this, read_handler, 0x0CF8, "PCI confAddr", 4);
|
|
|
|
DEV_register_iowrite_handler(this, write_handler, 0x0CF8, "PCI confAddr", 4);
|
2012-11-08 23:12:26 +04:00
|
|
|
|
|
|
|
for (i=0x0CFC; i<=0x0CFF; i++) {
|
2020-12-01 22:47:27 +03:00
|
|
|
DEV_register_ioread_handler(this, read_handler, i, "PCI confData", 7);
|
|
|
|
DEV_register_iowrite_handler(this, write_handler, i, "PCI confData", 7);
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
// misc. CMOS
|
2011-06-13 00:27:36 +04:00
|
|
|
Bit64u memory_in_k = mem->get_memory_len() / 1024;
|
|
|
|
Bit64u extended_memory_in_k = memory_in_k > 1024 ? (memory_in_k - 1024) : 0;
|
2005-02-16 20:53:40 +03:00
|
|
|
if (extended_memory_in_k > 0xfc00) extended_memory_in_k = 0xfc00;
|
2003-04-26 02:06:27 +04:00
|
|
|
|
2002-10-25 01:07:56 +04:00
|
|
|
DEV_cmos_set_reg(0x15, (Bit8u) BASE_MEMORY_IN_K);
|
|
|
|
DEV_cmos_set_reg(0x16, (Bit8u) (BASE_MEMORY_IN_K >> 8));
|
2008-02-16 01:05:43 +03:00
|
|
|
DEV_cmos_set_reg(0x17, (Bit8u) (extended_memory_in_k & 0xff));
|
|
|
|
DEV_cmos_set_reg(0x18, (Bit8u) ((extended_memory_in_k >> 8) & 0xff));
|
|
|
|
DEV_cmos_set_reg(0x30, (Bit8u) (extended_memory_in_k & 0xff));
|
|
|
|
DEV_cmos_set_reg(0x31, (Bit8u) ((extended_memory_in_k >> 8) & 0xff));
|
2003-04-26 02:06:27 +04:00
|
|
|
|
2011-06-13 00:27:36 +04:00
|
|
|
Bit64u extended_memory_in_64k = memory_in_k > 16384 ? (memory_in_k - 16384) / 64 : 0;
|
2011-06-10 10:38:11 +04:00
|
|
|
// Limit to 3 GB - 16 MB. PCI Memory Address Space starts at 3 GB.
|
|
|
|
if (extended_memory_in_64k > 0xbf00) extended_memory_in_64k = 0xbf00;
|
2003-04-26 02:06:27 +04:00
|
|
|
|
2008-02-16 01:05:43 +03:00
|
|
|
DEV_cmos_set_reg(0x34, (Bit8u) (extended_memory_in_64k & 0xff));
|
|
|
|
DEV_cmos_set_reg(0x35, (Bit8u) ((extended_memory_in_64k >> 8) & 0xff));
|
2002-10-16 11:38:37 +04:00
|
|
|
|
2011-06-13 00:27:36 +04:00
|
|
|
Bit64u memory_above_4gb = (mem->get_memory_len() > BX_CONST64(0x100000000)) ?
|
|
|
|
(mem->get_memory_len() - BX_CONST64(0x100000000)) : 0;
|
|
|
|
if (memory_above_4gb) {
|
2011-06-19 09:37:30 +04:00
|
|
|
DEV_cmos_set_reg(0x5b, (Bit8u)(memory_above_4gb >> 16));
|
|
|
|
DEV_cmos_set_reg(0x5c, (Bit8u)(memory_above_4gb >> 24));
|
2011-06-13 00:27:36 +04:00
|
|
|
DEV_cmos_set_reg(0x5d, memory_above_4gb >> 32);
|
|
|
|
}
|
|
|
|
|
2020-12-03 23:30:10 +03:00
|
|
|
options = SIM->get_param_string(BXPN_ROM_OPTIONS)->getptr();
|
|
|
|
argc = bx_split_option_list("ROM image options", options, argv, 16);
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
if (!strcmp(argv[i], "fastboot")) {
|
|
|
|
DEV_cmos_set_reg(0x3f, 0x01);
|
|
|
|
} else {
|
|
|
|
BX_ERROR(("Unknown ROM image option '%s'", argv[i]));
|
|
|
|
}
|
|
|
|
free(argv[i]);
|
|
|
|
argv[i] = NULL;
|
2017-02-17 00:43:52 +03:00
|
|
|
}
|
|
|
|
|
2002-10-06 23:04:47 +04:00
|
|
|
if (timer_handle != BX_NULL_TIMER_HANDLE) {
|
2017-03-30 21:08:15 +03:00
|
|
|
timer_handle = DEV_register_timer(this, timer_handler,
|
2002-10-06 23:04:47 +04:00
|
|
|
(unsigned) BX_IODEV_HANDLER_PERIOD, 1, 1, "devices.cc");
|
|
|
|
}
|
2002-09-09 20:56:56 +04:00
|
|
|
|
|
|
|
// Clear fields for bulk IO acceleration transfers.
|
|
|
|
bulkIOHostAddr = 0;
|
|
|
|
bulkIOQuantumsRequested = 0;
|
|
|
|
bulkIOQuantumsTransferred = 0;
|
2002-10-25 01:07:56 +04:00
|
|
|
|
|
|
|
bx_init_plugins();
|
2003-01-03 14:43:24 +03:00
|
|
|
|
|
|
|
/* now perform checksum of CMOS memory */
|
|
|
|
DEV_cmos_checksum();
|
2012-11-08 23:12:26 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
// verify PCI slot configuration
|
|
|
|
char devname[80];
|
|
|
|
char *device;
|
|
|
|
|
|
|
|
if (pci.enabled) {
|
2018-02-25 23:59:30 +03:00
|
|
|
if (chipset == BX_PCI_CHIPSET_I440BX) {
|
|
|
|
device = SIM->get_param_string("pci.slot.5")->getptr();
|
|
|
|
if ((strlen(device) > 0) && !pci.slot_used[4]) {
|
|
|
|
BX_PANIC(("Unknown plugin '%s' at AGP slot", device));
|
|
|
|
}
|
|
|
|
max_pci_slots = 4;
|
|
|
|
}
|
|
|
|
for (i = 0; i < max_pci_slots; i++) {
|
2012-11-08 23:12:26 +04:00
|
|
|
sprintf(devname, "pci.slot.%d", i+1);
|
|
|
|
device = SIM->get_param_string(devname)->getptr();
|
|
|
|
if ((strlen(device) > 0) && !pci.slot_used[i]) {
|
|
|
|
BX_PANIC(("Unknown plugin '%s' at PCI slot #%d", device, i+1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-14 21:11:22 +03:00
|
|
|
void bx_devices_c::reset(unsigned type)
|
2002-08-01 16:19:01 +04:00
|
|
|
{
|
2012-11-08 23:12:26 +04:00
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
if (pci.enabled) {
|
|
|
|
pci.confAddr = 0;
|
|
|
|
}
|
|
|
|
#endif
|
2006-03-27 02:15:07 +04:00
|
|
|
mem->disable_smram();
|
2002-10-25 01:07:56 +04:00
|
|
|
bx_reset_plugins(type);
|
2017-04-22 18:32:07 +03:00
|
|
|
release_keys();
|
2020-12-19 14:00:36 +03:00
|
|
|
if (paste.buf != NULL) {
|
|
|
|
paste.stop = 1;
|
|
|
|
}
|
2002-08-01 16:19:01 +04:00
|
|
|
}
|
|
|
|
|
2006-04-15 21:03:59 +04:00
|
|
|
void bx_devices_c::register_state()
|
|
|
|
{
|
2012-11-08 23:12:26 +04:00
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
if (pci.enabled) {
|
2012-11-09 17:30:52 +04:00
|
|
|
bx_list_c *list = new bx_list_c(SIM->get_bochs_root(), "pcicore", "Generic PCI State");
|
2012-11-08 23:12:26 +04:00
|
|
|
BXRS_HEX_PARAM_FIELD(list, confAddr, pci.confAddr);
|
|
|
|
}
|
|
|
|
#endif
|
2006-05-27 19:54:49 +04:00
|
|
|
bx_virt_timer.register_state();
|
2006-04-15 21:03:59 +04:00
|
|
|
bx_plugins_register_state();
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_devices_c::after_restore_state()
|
|
|
|
{
|
2006-05-27 19:54:49 +04:00
|
|
|
bx_slowdown_timer.after_restore_state();
|
2011-08-15 14:37:41 +04:00
|
|
|
bx_virt_timer.set_realtime_delay();
|
2006-04-15 21:03:59 +04:00
|
|
|
bx_plugins_after_restore_state();
|
|
|
|
}
|
|
|
|
|
2006-09-07 22:50:51 +04:00
|
|
|
void bx_devices_c::exit()
|
|
|
|
{
|
2006-09-20 22:24:17 +04:00
|
|
|
// delete i/o handlers before unloading plugins
|
|
|
|
struct io_handler_struct *io_read_handler = io_read_handlers.next;
|
|
|
|
struct io_handler_struct *curr = NULL;
|
|
|
|
while (io_read_handler != &io_read_handlers) {
|
|
|
|
io_read_handler->prev->next = io_read_handler->next;
|
|
|
|
io_read_handler->next->prev = io_read_handler->prev;
|
|
|
|
curr = io_read_handler;
|
|
|
|
io_read_handler = io_read_handler->next;
|
|
|
|
delete [] curr->handler_name;
|
|
|
|
delete curr;
|
|
|
|
}
|
|
|
|
struct io_handler_struct *io_write_handler = io_write_handlers.next;
|
|
|
|
while (io_write_handler != &io_write_handlers) {
|
|
|
|
io_write_handler->prev->next = io_write_handler->next;
|
|
|
|
io_write_handler->next->prev = io_write_handler->prev;
|
|
|
|
curr = io_write_handler;
|
|
|
|
io_write_handler = io_write_handler->next;
|
|
|
|
delete [] curr->handler_name;
|
|
|
|
delete curr;
|
|
|
|
}
|
|
|
|
|
2006-09-18 22:10:49 +04:00
|
|
|
bx_virt_timer.setup();
|
2006-09-16 23:30:56 +04:00
|
|
|
bx_slowdown_timer.exit();
|
|
|
|
|
2011-12-18 14:47:26 +04:00
|
|
|
// unload optional and user plugins first
|
|
|
|
bx_unload_plugins();
|
2012-02-12 12:37:42 +04:00
|
|
|
bx_unload_core_plugins();
|
2012-08-14 23:33:24 +04:00
|
|
|
PLUG_unload_plugin(hdimage);
|
2012-08-16 01:29:32 +04:00
|
|
|
#if BX_NETWORKING
|
2012-08-20 11:35:30 +04:00
|
|
|
if (network_enabled)
|
2017-03-12 10:48:08 +03:00
|
|
|
bx_netmod_ctl.exit();
|
2012-08-16 01:29:32 +04:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_SOUNDLOW
|
2012-08-20 11:35:30 +04:00
|
|
|
if (sound_enabled)
|
2017-02-20 21:21:19 +03:00
|
|
|
bx_soundmod_ctl.exit();
|
2012-08-16 01:29:32 +04:00
|
|
|
#endif
|
|
|
|
#if BX_SUPPORT_PCIUSB
|
2012-08-20 11:35:30 +04:00
|
|
|
if (usb_enabled)
|
2017-05-28 11:13:06 +03:00
|
|
|
bx_usbdev_ctl.exit();
|
2012-08-16 01:29:32 +04:00
|
|
|
#endif
|
2006-09-10 21:18:44 +04:00
|
|
|
init_stubs();
|
2006-09-07 22:50:51 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
Bit32u bx_devices_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if !BX_USE_DEV_SMF
|
|
|
|
bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
|
2012-11-08 23:12:26 +04:00
|
|
|
return class_ptr->read(address, io_len);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2012-11-08 23:12:26 +04:00
|
|
|
Bit32u bx_devices_c::read(Bit32u address, unsigned io_len)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#else
|
|
|
|
UNUSED(this_ptr);
|
|
|
|
#endif // !BX_USE_DEV_SMF
|
|
|
|
|
2012-11-08 23:12:26 +04:00
|
|
|
switch (address) {
|
|
|
|
case 0x0092:
|
|
|
|
BX_DEBUG(("port92h read partially supported!!!"));
|
|
|
|
BX_DEBUG((" returning %02x", (unsigned) (BX_GET_ENABLE_A20() << 1)));
|
|
|
|
return(BX_GET_ENABLE_A20() << 1);
|
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
case 0x0CF8:
|
|
|
|
return BX_DEV_THIS pci.confAddr;
|
|
|
|
case 0x0CFC:
|
|
|
|
case 0x0CFD:
|
|
|
|
case 0x0CFE:
|
|
|
|
case 0x0CFF:
|
|
|
|
{
|
2018-02-25 23:59:30 +03:00
|
|
|
Bit32u handle, retval = 0xffffffff;
|
|
|
|
Bit8u regnum;
|
|
|
|
Bit16u bus_devfunc;
|
2012-11-08 23:12:26 +04:00
|
|
|
|
2018-02-25 23:59:30 +03:00
|
|
|
if ((BX_DEV_THIS pci.confAddr & 0x80fe0000) == 0x80000000) {
|
|
|
|
bus_devfunc = (BX_DEV_THIS pci.confAddr >> 8) & 0x1ff;
|
2012-11-08 23:12:26 +04:00
|
|
|
regnum = (BX_DEV_THIS pci.confAddr & 0xfc) + (address & 0x03);
|
2018-02-25 23:59:30 +03:00
|
|
|
if (bus_devfunc <= 0x100) {
|
|
|
|
handle = BX_DEV_THIS pci.handler_id[bus_devfunc];
|
|
|
|
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES)) {
|
|
|
|
retval = BX_DEV_THIS pci.pci_handler[handle].handler->pci_read_handler(regnum, io_len);
|
|
|
|
}
|
|
|
|
}
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
BX_PANIC(("unsupported IO read to port 0x%x", (unsigned) address));
|
|
|
|
return(0xffffffff);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
void bx_devices_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if !BX_USE_DEV_SMF
|
|
|
|
bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
|
2012-11-08 23:12:26 +04:00
|
|
|
class_ptr->write(address, value, io_len);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2012-11-08 23:12:26 +04:00
|
|
|
void bx_devices_c::write(Bit32u address, Bit32u value, unsigned io_len)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#else
|
|
|
|
UNUSED(this_ptr);
|
|
|
|
#endif // !BX_USE_DEV_SMF
|
2019-12-30 10:16:46 +03:00
|
|
|
#if BX_SUPPORT_PCI
|
2018-02-25 23:59:30 +03:00
|
|
|
Bit8u bus, devfunc, handle;
|
|
|
|
Bit16u bus_devfunc;
|
2018-02-18 10:41:42 +03:00
|
|
|
bx_pci_device_c *dev = NULL;
|
2019-12-30 10:16:46 +03:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2012-11-08 23:12:26 +04:00
|
|
|
switch (address) {
|
|
|
|
case 0x0092:
|
|
|
|
BX_DEBUG(("port92h write of %02x partially supported!!!", (unsigned) value));
|
|
|
|
BX_DEBUG(("A20: set_enable_a20() called"));
|
|
|
|
BX_SET_ENABLE_A20((value & 0x02) >> 1);
|
|
|
|
BX_DEBUG(("A20: now %u", (unsigned) BX_GET_ENABLE_A20()));
|
|
|
|
if (value & 0x01) { /* high speed reset */
|
|
|
|
BX_INFO(("iowrite to port0x92 : reset resquested"));
|
|
|
|
bx_pc_system.Reset(BX_RESET_SOFTWARE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#if BX_SUPPORT_PCI
|
|
|
|
case 0xCF8:
|
|
|
|
BX_DEV_THIS pci.confAddr = value;
|
2018-02-18 10:41:42 +03:00
|
|
|
if ((value & 0x80000000) == 0x80000000) {
|
|
|
|
bus = (BX_DEV_THIS pci.confAddr >> 16) & 0xff;
|
|
|
|
devfunc = (BX_DEV_THIS pci.confAddr >> 8) & 0xff;
|
2018-02-25 23:59:30 +03:00
|
|
|
bus_devfunc = (bus << 8) | devfunc;
|
|
|
|
if (bus_devfunc <= 0x100) {
|
|
|
|
handle = BX_DEV_THIS pci.handler_id[bus_devfunc];
|
|
|
|
if (handle != BX_MAX_PCI_DEVICES) {
|
|
|
|
dev = BX_DEV_THIS pci.pci_handler[handle].handler;
|
|
|
|
}
|
2018-02-18 10:41:42 +03:00
|
|
|
}
|
|
|
|
if ((bus == 0) && (devfunc == 0x00)) {
|
|
|
|
BX_DEBUG(("%s register 0x%02x selected", dev->get_name(), value & 0xfc));
|
|
|
|
} else if (dev != NULL) {
|
|
|
|
BX_DEBUG(("PCI: request for bus %d device %d function %d (%s)", bus,
|
|
|
|
(devfunc >> 3), devfunc & 0x07, dev->get_name()));
|
2018-02-24 21:04:36 +03:00
|
|
|
} else if (bus == 1) {
|
|
|
|
BX_DEBUG(("PCI: request for AGP bus device %d function %d", (devfunc >> 3),
|
|
|
|
devfunc & 0x07));
|
2018-02-18 10:41:42 +03:00
|
|
|
} else {
|
|
|
|
BX_DEBUG(("PCI: request for bus %d device %d function %d", bus,
|
|
|
|
(devfunc >> 3), devfunc & 0x07));
|
|
|
|
}
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0xCFC:
|
|
|
|
case 0xCFD:
|
|
|
|
case 0xCFE:
|
|
|
|
case 0xCFF:
|
2018-02-25 23:59:30 +03:00
|
|
|
if ((BX_DEV_THIS pci.confAddr & 0x80fe0000) == 0x80000000) {
|
|
|
|
bus_devfunc = (BX_DEV_THIS pci.confAddr >> 8) & 0x1ff;
|
2012-11-08 23:12:26 +04:00
|
|
|
Bit8u regnum = (BX_DEV_THIS pci.confAddr & 0xfc) + (address & 0x03);
|
2018-02-25 23:59:30 +03:00
|
|
|
if (bus_devfunc <= 0x100) {
|
|
|
|
handle = BX_DEV_THIS pci.handler_id[bus_devfunc];
|
|
|
|
if ((io_len <= 4) && (handle < BX_MAX_PCI_DEVICES)) {
|
|
|
|
BX_DEV_THIS pci.pci_handler[handle].handler->pci_write_handler_common(regnum, value, io_len);
|
|
|
|
}
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
BX_PANIC(("IO write to port 0x%x", (unsigned) address));
|
2004-04-09 01:23:41 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2009-01-15 20:34:20 +03:00
|
|
|
// This defines the builtin default read handler,
|
2002-10-25 01:07:56 +04:00
|
|
|
// so Bochs does not segfault if unmapped is not loaded
|
2006-03-07 01:03:16 +03:00
|
|
|
Bit32u bx_devices_c::default_read_handler(void *this_ptr, Bit32u address, unsigned io_len)
|
2002-10-25 01:07:56 +04:00
|
|
|
{
|
|
|
|
UNUSED(this_ptr);
|
|
|
|
return 0xffffffff;
|
|
|
|
}
|
|
|
|
|
2009-01-15 20:34:20 +03:00
|
|
|
// This defines the builtin default write handler,
|
2002-10-25 01:07:56 +04:00
|
|
|
// so Bochs does not segfault if unmapped is not loaded
|
2006-03-07 01:03:16 +03:00
|
|
|
void bx_devices_c::default_write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
|
2002-10-25 01:07:56 +04:00
|
|
|
{
|
|
|
|
UNUSED(this_ptr);
|
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
void bx_devices_c::timer_handler(void *this_ptr)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
bx_devices_c *class_ptr = (bx_devices_c *) this_ptr;
|
|
|
|
class_ptr->timer();
|
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
void bx_devices_c::timer()
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2020-12-19 14:00:36 +03:00
|
|
|
if (++paste.counter >= paste.delay) {
|
|
|
|
// after the paste delay, consider adding moving more chars
|
|
|
|
// from the paste buffer to the keyboard buffer.
|
|
|
|
service_paste_buf();
|
|
|
|
paste.counter = 0;
|
|
|
|
}
|
2012-10-30 21:25:33 +04:00
|
|
|
SIM->periodic();
|
|
|
|
if (!bx_pc_system.kill_bochs_request)
|
|
|
|
bx_gui->handle_events();
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_irq(unsigned irq, const char *name)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
if (irq >= BX_MAX_IRQS) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("IO device %s registered with IRQ=%d above %u",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
name, irq, (unsigned) BX_MAX_IRQS-1));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2006-03-07 01:03:16 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if (irq_handler_name[irq]) {
|
2008-12-29 21:02:01 +03:00
|
|
|
BX_PANIC(("IRQ %u conflict, %s with %s", irq, irq_handler_name[irq], name));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2006-03-07 01:03:16 +03:00
|
|
|
}
|
2006-09-13 22:51:25 +04:00
|
|
|
irq_handler_name[irq] = new char[strlen(name)+1];
|
|
|
|
strcpy(irq_handler_name[irq], name);
|
|
|
|
return 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::unregister_irq(unsigned irq, const char *name)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
if (irq >= BX_MAX_IRQS) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("IO device %s tried to unregister IRQ %d above %u",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
name, irq, (unsigned) BX_MAX_IRQS-1));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2006-03-07 01:03:16 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
if (!irq_handler_name[irq]) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("IO device %s tried to unregister IRQ %d, not registered",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
name, irq));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(irq_handler_name[irq], name)) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("IRQ %u not registered to %s but to %s", irq,
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
name, irq_handler_name[irq]));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2006-03-07 01:03:16 +03:00
|
|
|
}
|
2006-09-13 22:51:25 +04:00
|
|
|
delete [] irq_handler_name[irq];
|
2001-04-10 05:04:59 +04:00
|
|
|
irq_handler_name[irq] = NULL;
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_io_read_handler(void *this_ptr, bx_read_handler_t f,
|
2006-09-20 22:24:17 +04:00
|
|
|
Bit32u addr, const char *name, Bit8u mask)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2008-12-29 21:02:01 +03:00
|
|
|
addr &= 0xffff;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!f)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
|
|
|
|
/* first check if the port already has a handlers != the default handler */
|
|
|
|
if (read_port_to_handler[addr] &&
|
2005-10-01 21:40:07 +04:00
|
|
|
read_port_to_handler[addr] != &io_read_handlers) { // the default
|
|
|
|
BX_ERROR(("IO device address conflict(read) at IO address %Xh",
|
|
|
|
(unsigned) addr));
|
|
|
|
BX_ERROR((" conflicting devices: %s & %s",
|
|
|
|
read_port_to_handler[addr]->handler_name, name));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* first find existing handle for function or create new one */
|
2004-01-15 05:08:37 +03:00
|
|
|
struct io_handler_struct *curr = &io_read_handlers;
|
|
|
|
struct io_handler_struct *io_read_handler = NULL;
|
|
|
|
do {
|
2008-01-27 01:24:03 +03:00
|
|
|
if (curr->funct == f &&
|
|
|
|
curr->mask == mask &&
|
2005-10-01 21:40:07 +04:00
|
|
|
curr->this_ptr == this_ptr &&
|
2009-05-01 13:12:07 +04:00
|
|
|
!strcmp(curr->handler_name, name)) { // really want the same name too
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handler = curr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
curr = curr->next;
|
2004-01-15 05:08:37 +03:00
|
|
|
} while (curr->next != &io_read_handlers);
|
2005-10-01 21:40:07 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!io_read_handler) {
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handler = new struct io_handler_struct;
|
|
|
|
io_read_handler->funct = (void *)f;
|
|
|
|
io_read_handler->this_ptr = this_ptr;
|
2006-09-20 22:24:17 +04:00
|
|
|
io_read_handler->handler_name = new char[strlen(name)+1];
|
|
|
|
strcpy(io_read_handler->handler_name, name);
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handler->mask = mask;
|
|
|
|
io_read_handler->usage_count = 0;
|
|
|
|
// add the handler to the double linked list of handlers
|
|
|
|
io_read_handlers.prev->next = io_read_handler;
|
|
|
|
io_read_handler->next = &io_read_handlers;
|
|
|
|
io_read_handler->prev = io_read_handlers.prev;
|
|
|
|
io_read_handlers.prev = io_read_handler;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
io_read_handler->usage_count++;
|
|
|
|
read_port_to_handler[addr] = io_read_handler;
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1; // address mapped successfully
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_io_write_handler(void *this_ptr, bx_write_handler_t f,
|
2006-09-20 22:24:17 +04:00
|
|
|
Bit32u addr, const char *name, Bit8u mask)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2008-12-29 21:02:01 +03:00
|
|
|
addr &= 0xffff;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!f)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
/* first check if the port already has a handlers != the default handler */
|
|
|
|
if (write_port_to_handler[addr] &&
|
2005-10-01 21:40:07 +04:00
|
|
|
write_port_to_handler[addr] != &io_write_handlers) { // the default
|
|
|
|
BX_ERROR(("IO device address conflict(write) at IO address %Xh",
|
|
|
|
(unsigned) addr));
|
|
|
|
BX_ERROR((" conflicting devices: %s & %s",
|
|
|
|
write_port_to_handler[addr]->handler_name, name));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
/* first find existing handle for function or create new one */
|
|
|
|
struct io_handler_struct *curr = &io_write_handlers;
|
|
|
|
struct io_handler_struct *io_write_handler = NULL;
|
|
|
|
do {
|
2008-01-27 01:24:03 +03:00
|
|
|
if (curr->funct == f &&
|
|
|
|
curr->mask == mask &&
|
2005-10-01 21:40:07 +04:00
|
|
|
curr->this_ptr == this_ptr &&
|
2009-05-01 13:12:07 +04:00
|
|
|
!strcmp(curr->handler_name, name)) { // really want the same name too
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handler = curr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
curr = curr->next;
|
2004-01-15 05:08:37 +03:00
|
|
|
} while (curr->next != &io_write_handlers);
|
2005-10-01 21:40:07 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!io_write_handler) {
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handler = new struct io_handler_struct;
|
|
|
|
io_write_handler->funct = (void *)f;
|
|
|
|
io_write_handler->this_ptr = this_ptr;
|
2006-09-20 22:24:17 +04:00
|
|
|
io_write_handler->handler_name = new char[strlen(name)+1];
|
|
|
|
strcpy(io_write_handler->handler_name, name);
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handler->mask = mask;
|
|
|
|
io_write_handler->usage_count = 0;
|
|
|
|
// add the handler to the double linked list of handlers
|
|
|
|
io_write_handlers.prev->next = io_write_handler;
|
|
|
|
io_write_handler->next = &io_write_handlers;
|
|
|
|
io_write_handler->prev = io_write_handlers.prev;
|
|
|
|
io_write_handlers.prev = io_write_handler;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
io_write_handler->usage_count++;
|
|
|
|
write_port_to_handler[addr] = io_write_handler;
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1; // address mapped successfully
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_io_read_handler_range(void *this_ptr, bx_read_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u begin_addr, Bit32u end_addr,
|
|
|
|
const char *name, Bit8u mask)
|
2004-01-15 05:08:37 +03:00
|
|
|
{
|
2004-02-03 00:47:26 +03:00
|
|
|
Bit32u addr;
|
2008-12-29 21:02:01 +03:00
|
|
|
begin_addr &= 0xffff;
|
|
|
|
end_addr &= 0xffff;
|
2004-01-15 05:08:37 +03:00
|
|
|
|
|
|
|
if (end_addr < begin_addr) {
|
2005-10-01 21:40:07 +04:00
|
|
|
BX_ERROR(("!!! end_addr < begin_addr !!!"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2008-01-27 01:24:03 +03:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!f) {
|
2005-10-01 21:40:07 +04:00
|
|
|
BX_ERROR(("!!! f == NULL !!!"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* first check if the port already has a handlers != the default handler */
|
|
|
|
for (addr = begin_addr; addr <= end_addr; addr++)
|
2005-10-01 21:40:07 +04:00
|
|
|
if (read_port_to_handler[addr] &&
|
|
|
|
read_port_to_handler[addr] != &io_read_handlers) { // the default
|
|
|
|
BX_ERROR(("IO device address conflict(read) at IO address %Xh",
|
|
|
|
(unsigned) addr));
|
|
|
|
BX_ERROR((" conflicting devices: %s & %s",
|
|
|
|
read_port_to_handler[addr]->handler_name, name));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
2004-01-15 05:08:37 +03:00
|
|
|
|
|
|
|
/* first find existing handle for function or create new one */
|
|
|
|
struct io_handler_struct *curr = &io_read_handlers;
|
|
|
|
struct io_handler_struct *io_read_handler = NULL;
|
|
|
|
do {
|
2008-01-27 01:24:03 +03:00
|
|
|
if (curr->funct == f &&
|
|
|
|
curr->mask == mask &&
|
2005-10-01 21:40:07 +04:00
|
|
|
curr->this_ptr == this_ptr &&
|
2009-05-01 13:12:07 +04:00
|
|
|
!strcmp(curr->handler_name, name)) {
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handler = curr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
curr = curr->next;
|
2004-01-15 05:08:37 +03:00
|
|
|
} while (curr->next != &io_read_handlers);
|
2005-10-01 21:40:07 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!io_read_handler) {
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handler = new struct io_handler_struct;
|
|
|
|
io_read_handler->funct = (void *)f;
|
|
|
|
io_read_handler->this_ptr = this_ptr;
|
2006-09-20 22:24:17 +04:00
|
|
|
io_read_handler->handler_name = new char[strlen(name)+1];
|
|
|
|
strcpy(io_read_handler->handler_name, name);
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handler->mask = mask;
|
|
|
|
io_read_handler->usage_count = 0;
|
|
|
|
// add the handler to the double linked list of handlers
|
|
|
|
io_read_handlers.prev->next = io_read_handler;
|
|
|
|
io_read_handler->next = &io_read_handlers;
|
|
|
|
io_read_handler->prev = io_read_handlers.prev;
|
|
|
|
io_read_handlers.prev = io_read_handler;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
io_read_handler->usage_count += end_addr - begin_addr + 1;
|
|
|
|
for (addr = begin_addr; addr <= end_addr; addr++)
|
|
|
|
read_port_to_handler[addr] = io_read_handler;
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1; // address mapped successfully
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_io_write_handler_range(void *this_ptr, bx_write_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u begin_addr, Bit32u end_addr,
|
|
|
|
const char *name, Bit8u mask)
|
2002-10-25 01:07:56 +04:00
|
|
|
{
|
2004-02-03 00:47:26 +03:00
|
|
|
Bit32u addr;
|
2008-12-29 21:02:01 +03:00
|
|
|
begin_addr &= 0xffff;
|
|
|
|
end_addr &= 0xffff;
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (end_addr < begin_addr) {
|
2005-10-01 21:40:07 +04:00
|
|
|
BX_ERROR(("!!! end_addr < begin_addr !!!"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2008-01-27 01:24:03 +03:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!f) {
|
2005-10-01 21:40:07 +04:00
|
|
|
BX_ERROR(("!!! f == NULL !!!"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
/* first check if the port already has a handlers != the default handler */
|
|
|
|
for (addr = begin_addr; addr <= end_addr; addr++)
|
2005-10-01 21:40:07 +04:00
|
|
|
if (write_port_to_handler[addr] &&
|
|
|
|
write_port_to_handler[addr] != &io_write_handlers) { // the default
|
|
|
|
BX_ERROR(("IO device address conflict(read) at IO address %Xh",
|
|
|
|
(unsigned) addr));
|
|
|
|
BX_ERROR((" conflicting devices: %s & %s",
|
|
|
|
write_port_to_handler[addr]->handler_name, name));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
2004-01-15 05:08:37 +03:00
|
|
|
|
|
|
|
/* first find existing handle for function or create new one */
|
|
|
|
struct io_handler_struct *curr = &io_write_handlers;
|
|
|
|
struct io_handler_struct *io_write_handler = NULL;
|
|
|
|
do {
|
2008-01-27 01:24:03 +03:00
|
|
|
if (curr->funct == f &&
|
|
|
|
curr->mask == mask &&
|
2005-10-01 21:40:07 +04:00
|
|
|
curr->this_ptr == this_ptr &&
|
2009-05-01 13:12:07 +04:00
|
|
|
!strcmp(curr->handler_name, name)) {
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handler = curr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
curr = curr->next;
|
2004-01-15 05:08:37 +03:00
|
|
|
} while (curr->next != &io_write_handlers);
|
2005-10-01 21:40:07 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
if (!io_write_handler) {
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handler = new struct io_handler_struct;
|
|
|
|
io_write_handler->funct = (void *)f;
|
|
|
|
io_write_handler->this_ptr = this_ptr;
|
2006-09-20 22:24:17 +04:00
|
|
|
io_write_handler->handler_name = new char[strlen(name)+1];
|
|
|
|
strcpy(io_write_handler->handler_name, name);
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handler->mask = mask;
|
|
|
|
io_write_handler->usage_count = 0;
|
|
|
|
// add the handler to the double linked list of handlers
|
|
|
|
io_write_handlers.prev->next = io_write_handler;
|
|
|
|
io_write_handler->next = &io_write_handlers;
|
|
|
|
io_write_handler->prev = io_write_handlers.prev;
|
|
|
|
io_write_handlers.prev = io_write_handler;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
io_write_handler->usage_count += end_addr - begin_addr + 1;
|
|
|
|
for (addr = begin_addr; addr <= end_addr; addr++)
|
|
|
|
write_port_to_handler[addr] = io_write_handler;
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1; // address mapped successfully
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
|
|
|
|
// Registration of default handlers (mainly be the unmapped device)
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_default_io_read_handler(void *this_ptr, bx_read_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
const char *name, Bit8u mask)
|
2004-01-15 05:08:37 +03:00
|
|
|
{
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handlers.funct = (void *)f;
|
|
|
|
io_read_handlers.this_ptr = this_ptr;
|
2006-09-20 22:24:17 +04:00
|
|
|
if (io_read_handlers.handler_name) {
|
|
|
|
delete [] io_read_handlers.handler_name;
|
|
|
|
}
|
|
|
|
io_read_handlers.handler_name = new char[strlen(name)+1];
|
|
|
|
strcpy(io_read_handlers.handler_name, name);
|
2005-10-01 21:40:07 +04:00
|
|
|
io_read_handlers.mask = mask;
|
2008-12-29 21:02:01 +03:00
|
|
|
|
2008-01-27 01:24:03 +03:00
|
|
|
return 1;
|
2002-10-25 01:07:56 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::register_default_io_write_handler(void *this_ptr, bx_write_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
const char *name, Bit8u mask)
|
2002-10-25 01:07:56 +04:00
|
|
|
{
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handlers.funct = (void *)f;
|
|
|
|
io_write_handlers.this_ptr = this_ptr;
|
2006-09-20 22:24:17 +04:00
|
|
|
if (io_write_handlers.handler_name) {
|
|
|
|
delete [] io_write_handlers.handler_name;
|
|
|
|
}
|
|
|
|
io_write_handlers.handler_name = new char[strlen(name)+1];
|
|
|
|
strcpy(io_write_handlers.handler_name, name);
|
2005-10-01 21:40:07 +04:00
|
|
|
io_write_handlers.mask = mask;
|
2008-12-29 21:02:01 +03:00
|
|
|
|
2008-01-27 01:24:03 +03:00
|
|
|
return 1;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::unregister_io_read_handler(void *this_ptr, bx_read_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u addr, Bit8u mask)
|
2004-01-15 05:08:37 +03:00
|
|
|
{
|
2008-12-29 21:02:01 +03:00
|
|
|
addr &= 0xffff;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
struct io_handler_struct *io_read_handler = read_port_to_handler[addr];
|
|
|
|
|
|
|
|
//BX_INFO(("Unregistering I/O read handler at %#x", addr));
|
|
|
|
|
|
|
|
if (!io_read_handler) {
|
|
|
|
BX_ERROR((">>> NO IO_READ_HANDLER <<<"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (io_read_handler == &io_read_handlers) {
|
|
|
|
BX_ERROR((">>> CANNOT UNREGISTER THE DEFAULT IO_READ_HANDLER <<<"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0; // cannot unregister the default handler
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (io_read_handler->funct != f) {
|
|
|
|
BX_ERROR((">>> NOT THE SAME IO_READ_HANDLER FUNC <<<"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (io_read_handler->this_ptr != this_ptr) {
|
|
|
|
BX_ERROR((">>> NOT THE SAME IO_READ_HANDLER THIS_PTR <<<"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (io_read_handler->mask != mask) {
|
|
|
|
BX_ERROR((">>> NOT THE SAME IO_READ_HANDLER MASK <<<"));
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
read_port_to_handler[addr] = &io_read_handlers; // reset to default
|
|
|
|
io_read_handler->usage_count--;
|
|
|
|
|
|
|
|
if (!io_read_handler->usage_count) { // kill this handler entry
|
|
|
|
io_read_handler->prev->next = io_read_handler->next;
|
|
|
|
io_read_handler->next->prev = io_read_handler->prev;
|
2006-09-20 22:24:17 +04:00
|
|
|
delete [] io_read_handler->handler_name;
|
2005-10-01 21:40:07 +04:00
|
|
|
delete io_read_handler;
|
|
|
|
}
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::unregister_io_write_handler(void *this_ptr, bx_write_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u addr, Bit8u mask)
|
2004-01-15 05:08:37 +03:00
|
|
|
{
|
2008-12-29 21:02:01 +03:00
|
|
|
addr &= 0xffff;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
struct io_handler_struct *io_write_handler = write_port_to_handler[addr];
|
|
|
|
|
|
|
|
if (!io_write_handler)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
if (io_write_handler == &io_write_handlers)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0; // cannot unregister the default handler
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
if (io_write_handler->funct != f)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
if (io_write_handler->this_ptr != this_ptr)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
if (io_write_handler->mask != mask)
|
2006-09-13 22:51:25 +04:00
|
|
|
return 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
write_port_to_handler[addr] = &io_write_handlers; // reset to default
|
|
|
|
io_write_handler->usage_count--;
|
|
|
|
|
|
|
|
if (!io_write_handler->usage_count) { // kill this handler entry
|
|
|
|
io_write_handler->prev->next = io_write_handler->next;
|
|
|
|
io_write_handler->next->prev = io_write_handler->prev;
|
2006-09-20 22:24:17 +04:00
|
|
|
delete [] io_write_handler->handler_name;
|
2005-10-01 21:40:07 +04:00
|
|
|
delete io_write_handler;
|
|
|
|
}
|
2006-09-13 22:51:25 +04:00
|
|
|
return 1;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::unregister_io_read_handler_range(void *this_ptr, bx_read_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u begin, Bit32u end, Bit8u mask)
|
2004-01-15 05:08:37 +03:00
|
|
|
{
|
2008-12-29 21:02:01 +03:00
|
|
|
begin &= 0xffff;
|
|
|
|
end &= 0xffff;
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u addr;
|
2006-09-13 22:51:25 +04:00
|
|
|
bx_bool ret = 1;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* the easy way this time
|
|
|
|
*/
|
|
|
|
for (addr = begin; addr <= end; addr++)
|
|
|
|
if (!unregister_io_read_handler(this_ptr, f, addr, mask))
|
2006-09-13 22:51:25 +04:00
|
|
|
ret = 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
return ret;
|
2002-10-25 01:07:56 +04:00
|
|
|
}
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
bx_bool bx_devices_c::unregister_io_write_handler_range(void *this_ptr, bx_write_handler_t f,
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u begin, Bit32u end, Bit8u mask)
|
2004-01-15 05:08:37 +03:00
|
|
|
{
|
2008-12-29 21:02:01 +03:00
|
|
|
begin &= 0xffff;
|
|
|
|
end &= 0xffff;
|
2005-10-01 21:40:07 +04:00
|
|
|
Bit32u addr;
|
2006-09-13 22:51:25 +04:00
|
|
|
bx_bool ret = 1;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* the easy way this time
|
|
|
|
*/
|
|
|
|
for (addr = begin; addr <= end; addr++)
|
|
|
|
if (!unregister_io_write_handler(this_ptr, f, addr, mask))
|
2006-09-13 22:51:25 +04:00
|
|
|
ret = 0;
|
2005-10-01 21:40:07 +04:00
|
|
|
|
|
|
|
return ret;
|
2004-01-15 05:08:37 +03:00
|
|
|
}
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Read a byte of data from the IO memory address space
|
|
|
|
*/
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
Bit32u BX_CPP_AttrRegparmN(2)
|
2001-04-10 05:04:59 +04:00
|
|
|
bx_devices_c::inp(Bit16u addr, unsigned io_len)
|
|
|
|
{
|
2004-01-15 05:08:37 +03:00
|
|
|
struct io_handler_struct *io_read_handler;
|
2001-04-10 05:04:59 +04:00
|
|
|
Bit32u ret;
|
|
|
|
|
|
|
|
BX_INSTR_INP(addr, io_len);
|
2008-01-27 01:24:03 +03:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
io_read_handler = read_port_to_handler[addr];
|
|
|
|
if (io_read_handler->mask & io_len) {
|
2012-11-08 23:12:26 +04:00
|
|
|
ret = ((bx_read_handler_t)io_read_handler->funct)(io_read_handler->this_ptr, (Bit32u)addr, io_len);
|
2003-07-31 16:04:48 +04:00
|
|
|
} else {
|
|
|
|
switch (io_len) {
|
|
|
|
case 1: ret = 0xff; break;
|
|
|
|
case 2: ret = 0xffff; break;
|
|
|
|
default: ret = 0xffffffff; break;
|
|
|
|
}
|
2005-10-01 21:40:07 +04:00
|
|
|
if (addr != 0x0cf8) { // don't flood the logfile when probing PCI
|
|
|
|
BX_ERROR(("read from port 0x%04x with len %d returns 0x%x", addr, io_len, ret));
|
|
|
|
}
|
2003-07-31 16:04:48 +04:00
|
|
|
}
|
2008-12-29 21:02:01 +03:00
|
|
|
|
2001-06-28 23:48:04 +04:00
|
|
|
BX_INSTR_INP2(addr, io_len, ret);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_DBG_IO_REPORT(addr, io_len, BX_READ, ret);
|
2008-12-29 21:02:01 +03:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write a byte of data to the IO memory address space.
|
|
|
|
*/
|
|
|
|
|
2003-03-03 02:59:12 +03:00
|
|
|
void BX_CPP_AttrRegparmN(3)
|
2001-04-10 05:04:59 +04:00
|
|
|
bx_devices_c::outp(Bit16u addr, Bit32u value, unsigned io_len)
|
|
|
|
{
|
2004-01-15 05:08:37 +03:00
|
|
|
struct io_handler_struct *io_write_handler;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-12-29 21:02:01 +03:00
|
|
|
BX_INSTR_OUTP(addr, io_len, value);
|
2001-04-10 05:04:59 +04:00
|
|
|
BX_DBG_IO_REPORT(addr, io_len, BX_WRITE, value);
|
2008-01-27 01:24:03 +03:00
|
|
|
|
2004-01-15 05:08:37 +03:00
|
|
|
io_write_handler = write_port_to_handler[addr];
|
|
|
|
if (io_write_handler->mask & io_len) {
|
2012-11-08 23:12:26 +04:00
|
|
|
((bx_write_handler_t)io_write_handler->funct)(io_write_handler->this_ptr, (Bit32u)addr, value, io_len);
|
2005-10-01 21:40:07 +04:00
|
|
|
} else if (addr != 0x0cf8) { // don't flood the logfile when probing PCI
|
2003-07-31 16:04:48 +04:00
|
|
|
BX_ERROR(("write to port 0x%04x with len %d ignored", addr, io_len));
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2002-10-25 01:07:56 +04:00
|
|
|
|
2009-02-23 21:38:25 +03:00
|
|
|
bx_bool bx_devices_c::is_harddrv_enabled(void)
|
|
|
|
{
|
|
|
|
char pname[24];
|
|
|
|
|
|
|
|
for (int i=0; i<BX_MAX_ATA_CHANNEL; i++) {
|
|
|
|
sprintf(pname, "ata.%d.resources.enabled", i);
|
|
|
|
if (SIM->get_param_bool(pname)->get())
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-01-13 21:04:47 +04:00
|
|
|
bx_bool bx_devices_c::is_network_enabled(void)
|
|
|
|
{
|
|
|
|
if (PLUG_device_present("e1000") ||
|
|
|
|
PLUG_device_present("ne2k") ||
|
|
|
|
PLUG_device_present("pcipnic")) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bx_bool bx_devices_c::is_sound_enabled(void)
|
|
|
|
{
|
|
|
|
if (PLUG_device_present("es1370") ||
|
2013-06-24 23:19:12 +04:00
|
|
|
PLUG_device_present("sb16") ||
|
|
|
|
PLUG_device_present("speaker")) {
|
2012-01-13 21:04:47 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bx_bool bx_devices_c::is_usb_enabled(void)
|
|
|
|
{
|
|
|
|
if (PLUG_device_present("usb_ohci") ||
|
|
|
|
PLUG_device_present("usb_uhci") ||
|
2015-12-06 23:03:42 +03:00
|
|
|
PLUG_device_present("usb_ehci") ||
|
2012-01-13 21:04:47 +04:00
|
|
|
PLUG_device_present("usb_xhci")) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-03 21:29:51 +03:00
|
|
|
// removable keyboard/mouse registration
|
2020-12-13 00:27:43 +03:00
|
|
|
void bx_devices_c::register_default_keyboard(void *dev, bx_kbd_gen_scancode_t kbd_gen_scancode,
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_kbd_get_elements_t kbd_get_elements)
|
2020-12-13 00:27:43 +03:00
|
|
|
{
|
|
|
|
if (bx_keyboard[0].dev == NULL) {
|
|
|
|
bx_keyboard[0].dev = dev;
|
|
|
|
bx_keyboard[0].gen_scancode = kbd_gen_scancode;
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_keyboard[0].get_elements = kbd_get_elements;
|
2020-12-20 12:07:49 +03:00
|
|
|
bx_keyboard[0].led_mask = BX_KBD_LED_MASK_ALL;
|
2020-12-15 14:29:36 +03:00
|
|
|
// add keyboard LEDs to the statusbar
|
|
|
|
statusbar_id[BX_KBD_LED_NUM] = bx_gui->register_statusitem("NUM");
|
|
|
|
statusbar_id[BX_KBD_LED_CAPS] = bx_gui->register_statusitem("CAPS");
|
|
|
|
statusbar_id[BX_KBD_LED_SCRL] = bx_gui->register_statusitem("SCRL");
|
2020-12-13 00:27:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_devices_c::register_removable_keyboard(void *dev, bx_kbd_gen_scancode_t kbd_gen_scancode,
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_kbd_get_elements_t kbd_get_elements,
|
|
|
|
Bit8u led_mask)
|
2009-03-03 21:29:51 +03:00
|
|
|
{
|
2020-12-13 00:27:43 +03:00
|
|
|
if (bx_keyboard[1].dev == NULL) {
|
|
|
|
bx_keyboard[1].dev = dev;
|
|
|
|
bx_keyboard[1].gen_scancode = kbd_gen_scancode;
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_keyboard[1].get_elements = kbd_get_elements;
|
2020-12-20 12:07:49 +03:00
|
|
|
bx_keyboard[0].led_mask &= ~led_mask;
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_keyboard[1].led_mask = led_mask;
|
2009-03-03 21:29:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_devices_c::unregister_removable_keyboard(void *dev)
|
|
|
|
{
|
2020-12-13 00:27:43 +03:00
|
|
|
if (dev == bx_keyboard[1].dev) {
|
|
|
|
bx_keyboard[1].dev = NULL;
|
|
|
|
bx_keyboard[1].gen_scancode = NULL;
|
2020-12-20 12:07:49 +03:00
|
|
|
bx_keyboard[0].led_mask |= bx_keyboard[1].led_mask;
|
2020-12-19 14:00:36 +03:00
|
|
|
bx_keyboard[1].led_mask = 0;
|
2009-03-03 21:29:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-03 23:34:50 +03:00
|
|
|
void bx_devices_c::register_default_mouse(void *dev, bx_mouse_enq_t mouse_enq,
|
|
|
|
bx_mouse_enabled_changed_t mouse_enabled_changed)
|
|
|
|
{
|
|
|
|
if (bx_mouse[0].dev == NULL) {
|
|
|
|
bx_mouse[0].dev = dev;
|
|
|
|
bx_mouse[0].enq_event = mouse_enq;
|
|
|
|
bx_mouse[0].enabled_changed = mouse_enabled_changed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-03 00:21:16 +03:00
|
|
|
void bx_devices_c::register_removable_mouse(void *dev, bx_mouse_enq_t mouse_enq,
|
|
|
|
bx_mouse_enabled_changed_t mouse_enabled_changed)
|
|
|
|
{
|
2009-03-03 23:34:50 +03:00
|
|
|
if (bx_mouse[1].dev == NULL) {
|
|
|
|
bx_mouse[1].dev = dev;
|
|
|
|
bx_mouse[1].enq_event = mouse_enq;
|
|
|
|
bx_mouse[1].enabled_changed = mouse_enabled_changed;
|
2009-03-03 00:21:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_devices_c::unregister_removable_mouse(void *dev)
|
|
|
|
{
|
2009-03-03 23:34:50 +03:00
|
|
|
if (dev == bx_mouse[1].dev) {
|
|
|
|
bx_mouse[1].dev = NULL;
|
|
|
|
bx_mouse[1].enq_event = NULL;
|
|
|
|
bx_mouse[1].enabled_changed = NULL;
|
2009-03-03 00:21:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-22 18:32:07 +03:00
|
|
|
// common keyboard device handlers
|
2017-04-01 00:32:58 +03:00
|
|
|
void bx_devices_c::gen_scancode(Bit32u key)
|
2009-03-03 21:29:51 +03:00
|
|
|
{
|
2017-04-01 00:32:58 +03:00
|
|
|
bx_bool ret = 0;
|
|
|
|
|
2020-12-13 00:27:43 +03:00
|
|
|
bx_keyboard[0].bxkey_state[key & 0xff] = ((key & BX_KEY_RELEASED) == 0);
|
2020-12-19 14:00:36 +03:00
|
|
|
if ((paste.buf != NULL) && (!paste.service)) {
|
|
|
|
paste.stop = 1;
|
|
|
|
return;
|
|
|
|
}
|
2020-12-13 00:27:43 +03:00
|
|
|
if (bx_keyboard[1].dev != NULL) {
|
|
|
|
ret = bx_keyboard[1].gen_scancode(bx_keyboard[1].dev, key);
|
2017-04-01 00:32:58 +03:00
|
|
|
}
|
2020-12-13 00:27:43 +03:00
|
|
|
if ((ret == 0) && (bx_keyboard[0].dev != NULL)) {
|
2020-12-13 19:30:42 +03:00
|
|
|
bx_keyboard[0].gen_scancode(bx_keyboard[0].dev, key);
|
2009-03-03 21:29:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 14:00:36 +03:00
|
|
|
Bit8u bx_devices_c::kbd_get_elements(void)
|
|
|
|
{
|
|
|
|
if (bx_keyboard[1].dev != NULL) {
|
|
|
|
return bx_keyboard[1].get_elements(bx_keyboard[1].dev);
|
|
|
|
}
|
|
|
|
if (bx_keyboard[0].dev != NULL) {
|
|
|
|
return bx_keyboard[0].get_elements(bx_keyboard[0].dev);
|
|
|
|
}
|
|
|
|
return BX_KBD_ELEMENTS;
|
|
|
|
}
|
|
|
|
|
2017-04-22 18:32:07 +03:00
|
|
|
void bx_devices_c::release_keys()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < BX_KEY_NBKEYS; i++) {
|
2020-12-13 00:27:43 +03:00
|
|
|
if (bx_keyboard[0].bxkey_state[i]) {
|
2017-04-22 18:32:07 +03:00
|
|
|
gen_scancode(i | BX_KEY_RELEASED);
|
2020-12-13 00:27:43 +03:00
|
|
|
bx_keyboard[0].bxkey_state[i] = 0;
|
2017-04-22 18:32:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-19 14:00:36 +03:00
|
|
|
// service_paste_buf() transfers data from the paste buffer to the hardware
|
|
|
|
// keyboard buffer. It tries to transfer as many chars as possible at a
|
|
|
|
// time, but because different chars require different numbers of scancodes
|
|
|
|
// we have to be conservative. Note that this process depends on the
|
|
|
|
// keymap tables to know what chars correspond to what keys, and which
|
|
|
|
// chars require a shift or other modifier.
|
|
|
|
void bx_devices_c::service_paste_buf()
|
2020-12-13 00:27:43 +03:00
|
|
|
{
|
2020-12-19 14:00:36 +03:00
|
|
|
if (!paste.buf) return;
|
|
|
|
BX_DEBUG(("service_paste_buf: ptr at %d out of %d", paste.buf_ptr, paste.buf_len));
|
|
|
|
int fill_threshold = 8;
|
|
|
|
paste.service = 1;
|
|
|
|
while ((paste.buf_ptr < paste.buf_len) && !paste.stop) {
|
|
|
|
if (kbd_get_elements() >= fill_threshold) {
|
|
|
|
paste.service = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// there room in the buffer for a keypress and a key release.
|
|
|
|
// send one keypress and a key release.
|
|
|
|
Bit8u byte = paste.buf[paste.buf_ptr];
|
|
|
|
BXKeyEntry *entry = bx_keymap.findAsciiChar(byte);
|
|
|
|
if (!entry) {
|
|
|
|
BX_ERROR(("paste character 0x%02x ignored", byte));
|
|
|
|
} else {
|
|
|
|
BX_DEBUG(("pasting character 0x%02x. baseKey is %04x", byte, entry->baseKey));
|
|
|
|
if (entry->modKey != BX_KEYMAP_UNKNOWN)
|
|
|
|
gen_scancode(entry->modKey);
|
|
|
|
gen_scancode(entry->baseKey);
|
|
|
|
gen_scancode(entry->baseKey | BX_KEY_RELEASED);
|
|
|
|
if (entry->modKey != BX_KEYMAP_UNKNOWN)
|
|
|
|
gen_scancode(entry->modKey | BX_KEY_RELEASED);
|
|
|
|
}
|
|
|
|
paste.buf_ptr++;
|
2020-12-13 00:27:43 +03:00
|
|
|
}
|
2020-12-19 14:00:36 +03:00
|
|
|
// reached end of pastebuf. free the memory it was using.
|
|
|
|
delete [] paste.buf;
|
|
|
|
paste.buf = NULL;
|
|
|
|
paste.stop = 0;
|
|
|
|
paste.service = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// paste_bytes schedules an arbitrary number of ASCII characters to be
|
|
|
|
// inserted into the hardware queue as it become available. Any previous
|
|
|
|
// paste which is still in progress will be thrown out. BYTES is a pointer
|
|
|
|
// to a region of memory containing the chars to be pasted. When the paste
|
|
|
|
// is complete, the keyboard code will call delete [] bytes;
|
|
|
|
void bx_devices_c::paste_bytes(Bit8u *data, Bit32s length)
|
|
|
|
{
|
|
|
|
BX_DEBUG(("paste_bytes: %d bytes", length));
|
|
|
|
if (paste.buf) {
|
|
|
|
BX_ERROR(("previous paste was not completed! %d chars lost",
|
|
|
|
paste.buf_len - paste.buf_ptr));
|
|
|
|
delete [] paste.buf; // free the old paste buffer
|
|
|
|
}
|
|
|
|
paste.buf = data;
|
|
|
|
paste.buf_ptr = 0;
|
|
|
|
paste.buf_len = length;
|
|
|
|
service_paste_buf();
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit64s bx_devices_c::param_handler(bx_param_c *param, int set, Bit64s val)
|
|
|
|
{
|
|
|
|
if (set) {
|
|
|
|
char pname[BX_PATHNAME_LEN];
|
|
|
|
param->get_param_path(pname, BX_PATHNAME_LEN);
|
|
|
|
if (set) {
|
|
|
|
if (!strcmp(pname, BXPN_KBD_PASTE_DELAY)) {
|
|
|
|
bx_devices.paste_delay_changed((Bit32u)val);
|
|
|
|
} else if (!strcmp(pname, BXPN_MOUSE_ENABLED)) {
|
|
|
|
bx_gui->mouse_enabled_changed(val!=0);
|
|
|
|
bx_devices.mouse_enabled_changed(val!=0);
|
|
|
|
} else {
|
|
|
|
BX_PANIC(("param_handler called with unexpected parameter '%s'", pname));
|
|
|
|
}
|
|
|
|
}
|
2020-12-13 00:27:43 +03:00
|
|
|
}
|
2020-12-19 14:00:36 +03:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_devices_c::paste_delay_changed(Bit32u value)
|
|
|
|
{
|
|
|
|
paste.delay = value / BX_IODEV_HANDLER_PERIOD;
|
|
|
|
paste.counter = 0;
|
|
|
|
BX_INFO(("will paste characters every %d iodev timer ticks", paste.delay));
|
2020-12-13 00:27:43 +03:00
|
|
|
}
|
|
|
|
|
2020-12-15 14:29:36 +03:00
|
|
|
void bx_devices_c::kbd_set_indicator(Bit8u devid, Bit8u ledid, bx_bool state)
|
|
|
|
{
|
2020-12-20 12:07:49 +03:00
|
|
|
if (bx_keyboard[devid].led_mask & (1 << ledid)) {
|
|
|
|
bx_gui->statusbar_setitem(statusbar_id[ledid], state, devid);
|
|
|
|
}
|
2020-12-15 14:29:36 +03:00
|
|
|
}
|
|
|
|
|
2009-03-03 21:29:51 +03:00
|
|
|
// common mouse device handlers
|
2009-01-13 22:01:19 +03:00
|
|
|
void bx_devices_c::mouse_enabled_changed(bx_bool enabled)
|
|
|
|
{
|
|
|
|
mouse_captured = enabled;
|
2009-03-03 23:34:50 +03:00
|
|
|
|
|
|
|
if ((bx_mouse[1].dev != NULL) && (bx_mouse[1].enabled_changed != NULL)) {
|
|
|
|
bx_mouse[1].enabled_changed(bx_mouse[1].dev, enabled);
|
2009-01-19 12:48:12 +03:00
|
|
|
return;
|
|
|
|
}
|
2009-01-13 22:01:19 +03:00
|
|
|
|
2009-03-03 23:34:50 +03:00
|
|
|
if ((bx_mouse[0].dev != NULL) && (bx_mouse[0].enabled_changed != NULL)) {
|
|
|
|
bx_mouse[0].enabled_changed(bx_mouse[0].dev, enabled);
|
|
|
|
}
|
2009-01-13 22:01:19 +03:00
|
|
|
}
|
|
|
|
|
2012-06-21 21:33:37 +04:00
|
|
|
void bx_devices_c::mouse_motion(int delta_x, int delta_y, int delta_z, unsigned button_state, bx_bool absxy)
|
2009-01-13 22:01:19 +03:00
|
|
|
{
|
|
|
|
// If mouse events are disabled on the GUI headerbar, don't
|
|
|
|
// generate any mouse data
|
|
|
|
if (!mouse_captured)
|
|
|
|
return;
|
|
|
|
|
2009-03-03 00:21:16 +03:00
|
|
|
// if a removable mouse is connected, redirect mouse data to the device
|
2009-03-03 23:34:50 +03:00
|
|
|
if (bx_mouse[1].dev != NULL) {
|
2012-06-21 21:33:37 +04:00
|
|
|
bx_mouse[1].enq_event(bx_mouse[1].dev, delta_x, delta_y, delta_z, button_state, absxy);
|
2009-01-19 12:48:12 +03:00
|
|
|
return;
|
|
|
|
}
|
2009-01-13 22:01:19 +03:00
|
|
|
|
2009-03-03 23:34:50 +03:00
|
|
|
// if a mouse is connected, direct mouse data to the device
|
|
|
|
if (bx_mouse[0].dev != NULL) {
|
2012-06-21 21:33:37 +04:00
|
|
|
bx_mouse[0].enq_event(bx_mouse[0].dev, delta_x, delta_y, delta_z, button_state, absxy);
|
2009-01-13 22:01:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 11:09:28 +03:00
|
|
|
#if BX_SUPPORT_PCI
|
2012-11-08 23:12:26 +04:00
|
|
|
// generic PCI support
|
2017-03-26 11:09:28 +03:00
|
|
|
bx_bool bx_devices_c::register_pci_handlers(bx_pci_device_c *dev,
|
2012-11-08 23:12:26 +04:00
|
|
|
Bit8u *devfunc, const char *name,
|
2018-02-25 23:59:30 +03:00
|
|
|
const char *descr, Bit8u bus)
|
2012-11-08 23:12:26 +04:00
|
|
|
{
|
2020-12-01 22:47:27 +03:00
|
|
|
unsigned i, handle, max_pci_slots = BX_N_PCI_SLOTS;
|
2012-11-08 23:12:26 +04:00
|
|
|
int first_free_slot = -1;
|
2018-02-25 23:59:30 +03:00
|
|
|
Bit16u bus_devfunc = *devfunc;
|
2012-11-08 23:12:26 +04:00
|
|
|
char devname[80];
|
|
|
|
char *device;
|
|
|
|
|
|
|
|
if (strcmp(name, "pci") && strcmp(name, "pci2isa") && strcmp(name, "pci_ide")
|
2015-11-04 19:32:16 +03:00
|
|
|
&& ((*devfunc & 0xf8) == 0x00)) {
|
2018-02-24 21:04:36 +03:00
|
|
|
if (SIM->get_param_enum(BXPN_PCI_CHIPSET)->get() == BX_PCI_CHIPSET_I440BX) {
|
2018-02-25 23:59:30 +03:00
|
|
|
max_pci_slots = 4;
|
2018-02-24 21:04:36 +03:00
|
|
|
}
|
2018-02-25 23:59:30 +03:00
|
|
|
if (bus == 0) {
|
|
|
|
for (i = 0; i < max_pci_slots; i++) {
|
|
|
|
sprintf(devname, "pci.slot.%d", i+1);
|
|
|
|
device = SIM->get_param_string(devname)->getptr();
|
|
|
|
if (strlen(device) > 0) {
|
2020-03-03 01:04:10 +03:00
|
|
|
if (!strcmp(name, device) && !pci.slot_used[i]) {
|
2020-12-01 22:47:27 +03:00
|
|
|
*devfunc = ((i + pci.map_slot_to_dev) << 3) | (*devfunc & 0x07);
|
2018-02-25 23:59:30 +03:00
|
|
|
pci.slot_used[i] = 1;
|
|
|
|
BX_INFO(("PCI slot #%d used by plugin '%s'", i+1, name));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (first_free_slot == -1) {
|
|
|
|
first_free_slot = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((*devfunc & 0xf8) == 0x00) {
|
|
|
|
// auto-assign device to PCI slot if possible
|
|
|
|
if (first_free_slot != -1) {
|
|
|
|
i = (unsigned)first_free_slot;
|
|
|
|
sprintf(devname, "pci.slot.%d", i+1);
|
|
|
|
SIM->get_param_string(devname)->set(name);
|
2020-12-01 22:47:27 +03:00
|
|
|
*devfunc = ((i + pci.map_slot_to_dev) << 3) | (*devfunc & 0x07);
|
2012-11-08 23:12:26 +04:00
|
|
|
pci.slot_used[i] = 1;
|
|
|
|
BX_INFO(("PCI slot #%d used by plugin '%s'", i+1, name));
|
2018-02-25 23:59:30 +03:00
|
|
|
} else {
|
|
|
|
BX_ERROR(("Plugin '%s' not connected to a PCI slot", name));
|
|
|
|
return 0;
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
}
|
2018-02-25 23:59:30 +03:00
|
|
|
bus_devfunc = *devfunc;
|
|
|
|
} else if ((bus == 1) && (max_pci_slots == 4)) {
|
|
|
|
pci.slot_used[4] = 1;
|
|
|
|
bus_devfunc = 0x100;
|
|
|
|
} else {
|
|
|
|
BX_PANIC(("Invalid bus number #%d", bus));
|
|
|
|
return 0;
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* check if device/function is available */
|
2018-02-25 23:59:30 +03:00
|
|
|
if (pci.handler_id[bus_devfunc] == BX_MAX_PCI_DEVICES) {
|
2012-11-08 23:12:26 +04:00
|
|
|
if (pci.num_pci_handlers >= BX_MAX_PCI_DEVICES) {
|
|
|
|
BX_INFO(("too many PCI devices installed."));
|
|
|
|
BX_PANIC((" try increasing BX_MAX_PCI_DEVICES"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
handle = pci.num_pci_handlers++;
|
|
|
|
pci.pci_handler[handle].handler = dev;
|
2018-02-25 23:59:30 +03:00
|
|
|
pci.handler_id[bus_devfunc] = handle;
|
|
|
|
if (bus_devfunc < 0x100) {
|
|
|
|
BX_INFO(("%s present at device %d, function %d", descr, *devfunc >> 3,
|
|
|
|
*devfunc & 0x07));
|
|
|
|
} else {
|
|
|
|
BX_INFO(("%s present on AGP bus device #0", descr));
|
|
|
|
}
|
2018-02-04 12:41:50 +03:00
|
|
|
dev->set_name(descr);
|
2012-11-08 23:12:26 +04:00
|
|
|
return 1; // device/function mapped successfully
|
|
|
|
} else {
|
|
|
|
return 0; // device/function not available, return false.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bx_bool bx_devices_c::pci_set_base_mem(void *this_ptr, memory_handler_t f1, memory_handler_t f2,
|
|
|
|
Bit32u *addr, Bit8u *pci_conf, unsigned size)
|
|
|
|
{
|
2019-10-16 23:46:00 +03:00
|
|
|
Bit32u oldbase = *addr, newbase;
|
2012-11-08 23:12:26 +04:00
|
|
|
Bit32u mask = ~(size - 1);
|
|
|
|
Bit8u pci_flags = pci_conf[0x00] & 0x0f;
|
|
|
|
if ((pci_flags & 0x06) > 0) {
|
2018-03-26 23:58:40 +03:00
|
|
|
BX_ERROR(("Ignoring PCI base memory flag 0x%02x for now", pci_flags));
|
2012-11-08 23:12:26 +04:00
|
|
|
}
|
|
|
|
pci_conf[0x00] &= (mask & 0xf0);
|
|
|
|
pci_conf[0x01] &= (mask >> 8) & 0xff;
|
|
|
|
pci_conf[0x02] &= (mask >> 16) & 0xff;
|
|
|
|
pci_conf[0x03] &= (mask >> 24) & 0xff;
|
2019-10-16 23:46:00 +03:00
|
|
|
newbase = ReadHostDWordFromLittleEndian((Bit32u*)pci_conf);
|
2012-11-08 23:12:26 +04:00
|
|
|
pci_conf[0x00] |= pci_flags;
|
|
|
|
if (newbase != mask && newbase != oldbase) { // skip PCI probe
|
|
|
|
if (oldbase > 0) {
|
|
|
|
DEV_unregister_memory_handlers(this_ptr, oldbase, oldbase + size - 1);
|
|
|
|
}
|
|
|
|
if (newbase > 0) {
|
|
|
|
DEV_register_memory_handlers(this_ptr, f1, f2, newbase, newbase + size - 1);
|
|
|
|
}
|
|
|
|
*addr = newbase;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bx_bool bx_devices_c::pci_set_base_io(void *this_ptr, bx_read_handler_t f1, bx_write_handler_t f2,
|
|
|
|
Bit32u *addr, Bit8u *pci_conf, unsigned size,
|
|
|
|
const Bit8u *iomask, const char *name)
|
|
|
|
{
|
|
|
|
unsigned i;
|
2019-10-16 23:46:00 +03:00
|
|
|
Bit32u oldbase = *addr, newbase;
|
2012-11-08 23:12:26 +04:00
|
|
|
Bit16u mask = ~(size - 1);
|
|
|
|
Bit8u pci_flags = pci_conf[0x00] & 0x03;
|
|
|
|
pci_conf[0x00] &= (mask & 0xfc);
|
|
|
|
pci_conf[0x01] &= (mask >> 8);
|
2019-10-16 23:46:00 +03:00
|
|
|
newbase = ReadHostDWordFromLittleEndian((Bit32u*)pci_conf);
|
2012-11-08 23:12:26 +04:00
|
|
|
pci_conf[0x00] |= pci_flags;
|
|
|
|
if (((newbase & 0xfffc) != mask) && (newbase != oldbase)) { // skip PCI probe
|
|
|
|
if (oldbase > 0) {
|
|
|
|
for (i=0; i<size; i++) {
|
|
|
|
if (iomask[i] > 0) {
|
|
|
|
DEV_unregister_ioread_handler(this_ptr, f1, oldbase + i, iomask[i]);
|
|
|
|
DEV_unregister_iowrite_handler(this_ptr, f2, oldbase + i, iomask[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (newbase > 0) {
|
|
|
|
for (i=0; i<size; i++) {
|
|
|
|
if (iomask[i] > 0) {
|
|
|
|
DEV_register_ioread_handler(this_ptr, f1, newbase + i, name, iomask[i]);
|
|
|
|
DEV_register_iowrite_handler(this_ptr, f2, newbase + i, name, iomask[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*addr = newbase;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2017-04-28 21:45:45 +03:00
|
|
|
|
|
|
|
// PCI device base class (common methods)
|
|
|
|
#undef LOG_THIS
|
|
|
|
#define LOG_THIS
|
|
|
|
|
2018-02-04 21:17:28 +03:00
|
|
|
void bx_pci_device_c::init_pci_conf(Bit16u vid, Bit16u did, Bit8u rev,
|
|
|
|
Bit32u classc, Bit8u headt, Bit8u intpin)
|
2017-04-28 21:45:45 +03:00
|
|
|
{
|
|
|
|
memset(pci_conf, 0, 256);
|
|
|
|
pci_conf[0x00] = (Bit8u)(vid & 0xff);
|
|
|
|
pci_conf[0x01] = (Bit8u)(vid >> 8);
|
|
|
|
pci_conf[0x02] = (Bit8u)(did & 0xff);
|
|
|
|
pci_conf[0x03] = (Bit8u)(did >> 8);
|
|
|
|
pci_conf[0x08] = rev;
|
|
|
|
pci_conf[0x09] = (Bit8u)(classc & 0xff);
|
|
|
|
pci_conf[0x0a] = (Bit8u)((classc >> 8) & 0xff);
|
|
|
|
pci_conf[0x0b] = (Bit8u)((classc >> 16) & 0xff);
|
|
|
|
pci_conf[0x0e] = headt;
|
2018-02-04 21:17:28 +03:00
|
|
|
pci_conf[0x3d] = intpin;
|
2017-04-28 21:45:45 +03:00
|
|
|
}
|
|
|
|
|
2018-02-04 12:41:50 +03:00
|
|
|
void bx_pci_device_c::init_bar_io(Bit8u num, Bit16u size, bx_read_handler_t rh,
|
|
|
|
bx_write_handler_t wh, const Bit8u *mask)
|
|
|
|
{
|
|
|
|
if (num < 6) {
|
|
|
|
pci_bar[num].type = BX_PCI_BAR_TYPE_IO;
|
|
|
|
pci_bar[num].size = size;
|
|
|
|
pci_bar[num].io.rh = rh;
|
|
|
|
pci_bar[num].io.wh = wh;
|
|
|
|
pci_bar[num].io.mask = mask;
|
|
|
|
pci_conf[0x10 + num * 4] = 0x01;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bx_pci_device_c::init_bar_mem(Bit8u num, Bit32u size, memory_handler_t rh,
|
|
|
|
memory_handler_t wh)
|
|
|
|
{
|
|
|
|
if (num < 6) {
|
|
|
|
pci_bar[num].type = BX_PCI_BAR_TYPE_MEM;
|
|
|
|
pci_bar[num].size = size;
|
|
|
|
pci_bar[num].mem.rh = rh;
|
|
|
|
pci_bar[num].mem.wh = wh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:45:45 +03:00
|
|
|
void bx_pci_device_c::register_pci_state(bx_list_c *list)
|
|
|
|
{
|
|
|
|
new bx_shadow_data_c(list, "pci_conf", pci_conf, 256, 1);
|
|
|
|
}
|
|
|
|
|
2017-10-08 18:54:21 +03:00
|
|
|
void bx_pci_device_c::after_restore_pci_state(memory_handler_t mem_read_handler)
|
|
|
|
{
|
2018-02-04 12:41:50 +03:00
|
|
|
for (int i = 0; i < 6; i++) {
|
|
|
|
if (pci_bar[i].type == BX_PCI_BAR_TYPE_MEM) {
|
|
|
|
if (DEV_pci_set_base_mem(this, pci_bar[i].mem.rh, pci_bar[i].mem.wh,
|
|
|
|
&pci_bar[i].addr, &pci_conf[0x10 + i * 4],
|
|
|
|
pci_bar[i].size)) {
|
|
|
|
BX_INFO(("BAR #%d: mem base address = 0x%08x", i, pci_bar[i].addr));
|
|
|
|
pci_bar_change_notify();
|
|
|
|
}
|
|
|
|
} else if (pci_bar[i].type == BX_PCI_BAR_TYPE_IO) {
|
|
|
|
if (DEV_pci_set_base_io(this, pci_bar[i].io.rh, pci_bar[i].io.wh,
|
|
|
|
&pci_bar[i].addr, &pci_conf[0x10 + i * 4],
|
|
|
|
pci_bar[i].size, pci_bar[i].io.mask, pci_name)) {
|
|
|
|
BX_INFO(("BAR #%d: i/o base address = 0x%04x", i, pci_bar[i].addr));
|
|
|
|
pci_bar_change_notify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-08 18:54:21 +03:00
|
|
|
if (pci_rom_size > 0) {
|
|
|
|
if (DEV_pci_set_base_mem(this, mem_read_handler, NULL, &pci_rom_address,
|
|
|
|
&pci_conf[0x30], pci_rom_size)) {
|
|
|
|
BX_INFO(("new ROM address: 0x%08x", pci_rom_address));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:45:45 +03:00
|
|
|
void bx_pci_device_c::load_pci_rom(const char *path)
|
|
|
|
{
|
|
|
|
struct stat stat_buf;
|
|
|
|
int fd, ret;
|
|
|
|
unsigned long size, max_size;
|
|
|
|
|
|
|
|
if (*path == '\0') {
|
|
|
|
BX_PANIC(("PCI ROM image undefined"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// read in PCI ROM image file
|
|
|
|
fd = open(path, O_RDONLY
|
|
|
|
#ifdef O_BINARY
|
|
|
|
| O_BINARY
|
|
|
|
#endif
|
|
|
|
);
|
|
|
|
if (fd < 0) {
|
|
|
|
BX_PANIC(("couldn't open PCI ROM image file '%s'.", path));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ret = fstat(fd, &stat_buf);
|
|
|
|
if (ret) {
|
|
|
|
close(fd);
|
|
|
|
BX_PANIC(("couldn't stat PCI ROM image file '%s'.", path));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
max_size = 0x20000;
|
|
|
|
size = (unsigned long)stat_buf.st_size;
|
|
|
|
if (size > max_size) {
|
|
|
|
close(fd);
|
|
|
|
BX_PANIC(("PCI ROM image too large"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((size % 512) != 0) {
|
|
|
|
close(fd);
|
|
|
|
BX_PANIC(("PCI ROM image size must be multiple of 512 (size = %ld)", size));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while ((size - 1) < max_size) {
|
|
|
|
max_size >>= 1;
|
|
|
|
}
|
|
|
|
pci_rom_size = (max_size << 1);
|
|
|
|
pci_rom = new Bit8u[pci_rom_size];
|
|
|
|
|
|
|
|
while (size > 0) {
|
|
|
|
ret = read(fd, (bx_ptr_t) pci_rom, size);
|
|
|
|
if (ret <= 0) {
|
|
|
|
BX_PANIC(("read failed on PCI ROM image: '%s'", path));
|
|
|
|
}
|
|
|
|
size -= ret;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
BX_INFO(("loaded PCI ROM '%s' (size=%u / PCI=%uk)", path, (unsigned) stat_buf.st_size, pci_rom_size >> 10));
|
|
|
|
}
|
|
|
|
|
2018-02-04 21:17:28 +03:00
|
|
|
// pci configuration space write callback handler (common registers)
|
2018-02-04 12:41:50 +03:00
|
|
|
void bx_pci_device_c::pci_write_handler_common(Bit8u address, Bit32u value, unsigned io_len)
|
|
|
|
{
|
|
|
|
Bit8u bnum, value8, oldval;
|
|
|
|
bx_bool bar_change = 0, rom_change = 0;
|
|
|
|
|
2018-02-24 21:04:36 +03:00
|
|
|
// ignore readonly registers
|
2018-02-04 21:17:28 +03:00
|
|
|
if ((address < 4) || ((address > 7) && (address < 12)) || (address == 14) ||
|
|
|
|
(address == 0x3d)) {
|
2018-02-12 01:40:30 +03:00
|
|
|
BX_DEBUG(("write to r/o PCI register 0x%02x ignored", address));
|
2018-02-04 21:17:28 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-24 21:04:36 +03:00
|
|
|
// handle base address registers if header type bit #0 and #1 are clear
|
|
|
|
if (((pci_conf[0x0e] & 0x03) == 0) && (address >= 0x10) && (address < 0x28)) {
|
2018-02-04 12:41:50 +03:00
|
|
|
bnum = ((address - 0x10) >> 2);
|
|
|
|
if (pci_bar[bnum].type != BX_PCI_BAR_TYPE_NONE) {
|
2018-05-01 18:54:37 +03:00
|
|
|
BX_DEBUG_PCI_WRITE(address, value, io_len);
|
2018-02-04 12:41:50 +03:00
|
|
|
for (unsigned i=0; i<io_len; i++) {
|
|
|
|
value8 = (value >> (i*8)) & 0xff;
|
|
|
|
oldval = pci_conf[address+i];
|
|
|
|
if (((address+i) & 0x03) == 0) {
|
|
|
|
if (pci_bar[bnum].type == BX_PCI_BAR_TYPE_IO) {
|
|
|
|
value8 = (value8 & 0xfc) | 0x01;
|
|
|
|
} else {
|
|
|
|
value8 = (value8 & 0xf0) | (oldval & 0x0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bar_change |= (value8 != oldval);
|
|
|
|
pci_conf[address+i] = value8;
|
|
|
|
}
|
|
|
|
if (bar_change) {
|
|
|
|
if (pci_bar[bnum].type == BX_PCI_BAR_TYPE_IO) {
|
|
|
|
if (DEV_pci_set_base_io(this, pci_bar[bnum].io.rh, pci_bar[bnum].io.wh,
|
|
|
|
&pci_bar[bnum].addr, &pci_conf[0x10 + bnum * 4],
|
|
|
|
pci_bar[bnum].size, pci_bar[bnum].io.mask, pci_name)) {
|
|
|
|
BX_INFO(("BAR #%d: i/o base address = 0x%04x", bnum, pci_bar[bnum].addr));
|
|
|
|
pci_bar_change_notify();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (DEV_pci_set_base_mem(this, pci_bar[bnum].mem.rh, pci_bar[bnum].mem.wh,
|
|
|
|
&pci_bar[bnum].addr, &pci_conf[0x10 + bnum * 4],
|
|
|
|
pci_bar[bnum].size)) {
|
|
|
|
BX_INFO(("BAR #%d: mem base address = 0x%08x", bnum, pci_bar[bnum].addr));
|
|
|
|
pci_bar_change_notify();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ((address & 0xfc) == 0x30) {
|
2018-05-01 18:54:37 +03:00
|
|
|
BX_DEBUG_PCI_WRITE(address, value, io_len);
|
2018-02-04 12:41:50 +03:00
|
|
|
value &= (0xfffffc01 >> ((address & 0x03) * 8));
|
|
|
|
for (unsigned i=0; i<io_len; i++) {
|
|
|
|
value8 = (value >> (i*8)) & 0xff;
|
|
|
|
oldval = pci_conf[address+i];
|
|
|
|
rom_change |= (value8 != oldval);
|
|
|
|
pci_conf[address+i] = value8;
|
|
|
|
}
|
|
|
|
if (rom_change) {
|
|
|
|
if (DEV_pci_set_base_mem(this, pci_rom_read_handler, NULL,
|
|
|
|
&pci_rom_address, &pci_conf[0x30],
|
|
|
|
pci_rom_size)) {
|
|
|
|
BX_INFO(("new ROM address = 0x%08x", pci_rom_address));
|
|
|
|
}
|
|
|
|
}
|
2018-02-04 21:17:28 +03:00
|
|
|
} else if (address == 0x3c) {
|
2018-02-12 01:40:30 +03:00
|
|
|
value8 = (Bit8u)value;
|
|
|
|
if (value8 != pci_conf[0x3c]) {
|
2018-02-04 21:17:28 +03:00
|
|
|
if (pci_conf[0x3d] != 0) {
|
2018-02-12 01:40:30 +03:00
|
|
|
BX_INFO(("new IRQ line = %d", value8));
|
2018-02-04 21:17:28 +03:00
|
|
|
}
|
2018-02-12 01:40:30 +03:00
|
|
|
pci_conf[0x3c] = value8;
|
2018-02-04 21:17:28 +03:00
|
|
|
}
|
2018-02-04 12:41:50 +03:00
|
|
|
} else {
|
|
|
|
pci_write_handler(address, value, io_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 21:45:45 +03:00
|
|
|
// pci configuration space read callback handler
|
|
|
|
Bit32u bx_pci_device_c::pci_read_handler(Bit8u address, unsigned io_len)
|
|
|
|
{
|
|
|
|
Bit32u value = 0;
|
|
|
|
|
|
|
|
for (unsigned i=0; i<io_len; i++) {
|
|
|
|
value |= (pci_conf[address+i] << (i*8));
|
|
|
|
}
|
|
|
|
|
2018-05-01 18:54:37 +03:00
|
|
|
BX_DEBUG_PCI_READ(address, value, io_len);
|
2017-04-28 21:45:45 +03:00
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
2012-11-08 23:12:26 +04:00
|
|
|
#endif
|