- implemented new mechanism to update device config parameters that depend on

each other. Devices can register a handler to update it's state after runtime
  configuration. The new method update_runtime_options() executes all registered
  device handlers before the simulation continues.
- USB host controllers now using the new mechanism to handle the runtime device
  change (replaces the previous timer-based implementation). TODO: floppy and
  cdrom could use this feature, too)
- improved USB device change messages
This commit is contained in:
Volker Ruppert 2011-06-11 19:38:52 +00:00
parent 778154b3b2
commit cb8faeee52
12 changed files with 133 additions and 41 deletions

View File

@ -45,6 +45,12 @@ bx_list_c *root_param = NULL;
// bx_keyboard.s.internal_buffer[4] (or whatever) directly. -Bryce
//
typedef struct _rt_conf_entry_t {
void *device;
rt_conf_handler_t handler;
struct _rt_conf_entry_t *next;
} rt_conf_entry_t;
typedef struct _user_option_t {
const char *name;
user_option_parser_t parser;
@ -58,6 +64,7 @@ class bx_real_sim_c : public bx_simulator_interface_c {
const char *registered_ci_name;
config_interface_callback_t ci_callback;
void *ci_callback_data;
rt_conf_entry_t *rt_conf_entries;
user_option_t *user_options;
int init_done;
int enabled;
@ -148,6 +155,8 @@ public:
void *userdata);
virtual int configuration_interface(const char* name, ci_command_t command);
virtual int begin_simulation(int argc, char *argv[]);
virtual bx_bool register_runtime_config_handler(void *dev, rt_conf_handler_t handler);
virtual void update_runtime_options();
virtual void set_sim_thread_func(is_sim_thread_func_t func) {}
virtual bx_bool is_sim_thread();
virtual void set_debug_gui(bx_bool val) { wx_debug_gui = val; }
@ -317,6 +326,7 @@ bx_real_sim_c::bx_real_sim_c()
quit_context = NULL;
exit_code = 0;
param_id = BXP_NEW_PARAM_ID;
rt_conf_entries = NULL;
user_options = NULL;
}
@ -790,6 +800,43 @@ int bx_real_sim_c::begin_simulation(int argc, char *argv[])
return bx_begin_simulation(argc, argv);
}
bx_bool bx_real_sim_c::register_runtime_config_handler(void *dev, rt_conf_handler_t handler)
{
rt_conf_entry_t *rt_conf_entry;
rt_conf_entry = (rt_conf_entry_t *)malloc(sizeof(rt_conf_entry_t));
if (rt_conf_entry == NULL) {
BX_PANIC(("can't allocate rt_conf_entry_t"));
return 0;
}
rt_conf_entry->device = dev;
rt_conf_entry->handler = handler;
rt_conf_entry->next = NULL;
if (rt_conf_entries == NULL) {
rt_conf_entries = rt_conf_entry;
} else {
rt_conf_entry_t *temp = rt_conf_entries;
while (temp->next) {
temp = temp->next;
}
temp->next = rt_conf_entry;
}
return 1;
}
void bx_real_sim_c::update_runtime_options()
{
rt_conf_entry_t *temp = rt_conf_entries;
while (temp != NULL) {
temp->handler(temp->device);
temp = temp->next;
}
}
bx_bool bx_real_sim_c::is_sim_thread()
{
if (is_sim_thread_func == NULL) return 1;

View File

@ -566,6 +566,7 @@ enum ci_return_t {
};
typedef int (*config_interface_callback_t)(void *userdata, ci_command_t command);
typedef BxEvent* (*bxevent_handler)(void *theclass, BxEvent *event);
typedef void (*rt_conf_handler_t)(void *this_ptr);
typedef Bit32s (*user_option_parser_t)(const char *context, int num_params, char *params[]);
typedef Bit32s (*user_option_save_t)(FILE *fp);
@ -686,6 +687,8 @@ public:
void *userdata) {}
virtual int configuration_interface(const char* name, ci_command_t command) {return -1; }
virtual int begin_simulation(int argc, char *argv[]) {return -1;}
virtual bx_bool register_runtime_config_handler(void *dev, rt_conf_handler_t handler) {return 0;}
virtual void update_runtime_options() {}
typedef bx_bool (*is_sim_thread_func_t)();
is_sim_thread_func_t is_sim_thread_func;
virtual void set_sim_thread_func(is_sim_thread_func_t func) {

View File

@ -522,7 +522,10 @@ int bx_config_interface(int menu)
case BX_CI_RT_INST_TR: NOT_IMPLEMENTED(choice); break;
case BX_CI_RT_USB: do_menu(BXPN_MENU_RUNTIME_USB); break;
case BX_CI_RT_MISC: do_menu(BXPN_MENU_RUNTIME_MISC); break;
case BX_CI_RT_CONT: fprintf(stderr, "Continuing simulation\n"); return 0;
case BX_CI_RT_CONT:
SIM->update_runtime_options();
fprintf(stderr, "Continuing simulation\n");
return 0;
case BX_CI_RT_QUIT:
fprintf(stderr, "You chose quit on the configuration interface.\n");
bx_user_quit = 1;

View File

@ -638,6 +638,9 @@ static BOOL CALLBACK MainMenuDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
}
break;
case IDOK:
if (runtime) {
SIM->update_runtime_options();
}
EndDialog(hDlg, 1);
break;
case IDCANCEL:

View File

@ -1053,6 +1053,7 @@ void MyFrame::OnPauseResumeSim(wxCommandEvent& WXUNUSED(event))
wxCriticalSectionLocker lock(sim_thread_lock);
if (sim_thread) {
if (sim_thread->IsPaused()) {
SIM->update_runtime_options();
simStatusChanged(Resume);
sim_thread->Resume();
} else {

View File

@ -154,7 +154,7 @@ public:
virtual void after_restore_state() {}
virtual void cancel_packet(USBPacket *p) {}
virtual bx_bool set_option(const char *option) {return 0;}
virtual void timer() {}
virtual void runtime_config() {}
bx_bool get_connected() {return d.connected;}
usbdev_type get_type() {return d.type;}

View File

@ -625,22 +625,24 @@ void usb_hub_device_c::usb_set_connect_status(Bit8u port, int type, bx_bool conn
}
}
void usb_hub_device_c::timer()
void usb_hub_device_c::runtime_config()
{
int i;
int i, hubnum;
char pname[6];
for (i = 0; i < hub.n_ports; i++) {
// forward timer tick
if (hub.usb_port[i].device != NULL) {
hub.usb_port[i].device->timer();
}
// device change support
if ((hub.device_change & (1 << i)) != 0) {
hubnum = atoi(hub.config->get_name()+6);
BX_INFO(("USB hub #%d, port #%d: device connect", hubnum, i+1));
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, hub.config));
hub.device_change &= ~(1 << i);
}
// forward to connected device
if (hub.usb_port[i].device != NULL) {
hub.usb_port[i].device->runtime_config();
}
}
}
@ -664,8 +666,8 @@ const char *usb_hub_device_c::hub_param_handler(bx_param_string_c *param, int se
portnum = atoi(port->get_name()+4) - 1;
bx_bool empty = ((strlen(val) == 0) || (!strcmp(val, "none")));
if ((portnum >= 0) && (portnum < hub->hub.n_ports)) {
BX_INFO(("USB hub #%d, port #%d experimental device change", hubnum, portnum+1));
if (empty && (hub->hub.usb_port[portnum].PortStatus & PORT_STAT_CONNECTION)) {
BX_INFO(("USB hub #%d, port #%d: device disconnect", hubnum, portnum+1));
if (hub->hub.usb_port[portnum].device != NULL) {
type = hub->hub.usb_port[portnum].device->get_type();
}

View File

@ -38,7 +38,7 @@ public:
virtual int handle_data(USBPacket *p);
virtual void register_state_specific(bx_list_c *parent);
virtual void after_restore_state();
virtual void timer();
virtual void runtime_config();
private:
struct {

View File

@ -164,6 +164,9 @@ void bx_usb_ohci_c::init(void)
DEV_register_timer(this, iolight_timer_handler, 5000, 0,0, "OHCI i/o light");
}
BX_OHCI_THIS hub.iolight_counter = 0;
// register handler for correct device connect handling after runtime config
SIM->register_runtime_config_handler(BX_OHCI_THIS_PTR, runtime_config_handler);
BX_OHCI_THIS hub.device_change = 0;
BX_INFO(("USB OHCI initialized"));
@ -1002,8 +1005,6 @@ void bx_usb_ohci_c::usb_frame_timer(void)
struct OHCI_ED cur_ed;
Bit32u address, ed_address;
Bit16u zero = 0;
int i;
char pname[6];
if (BX_OHCI_THIS hub.op_regs.HcControl.hcfs == 2) {
// set remaining to the interval amount.
@ -1105,19 +1106,6 @@ do_iso_eds:
}
} // end run schedule
for (i = 0; i < BX_N_USB_OHCI_PORTS; i++) {
// forward timer tick
if (BX_OHCI_THIS hub.usb_port[i].device != NULL) {
BX_OHCI_THIS hub.usb_port[i].device->timer();
}
// device change support
if ((BX_OHCI_THIS hub.device_change & (1 << i)) != 0) {
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_OHCI)));
BX_OHCI_THIS hub.device_change &= ~(1 << i);
}
}
}
void bx_usb_ohci_c::process_ed(struct OHCI_ED *ed, const Bit32u ed_address)
@ -1363,6 +1351,32 @@ void bx_usb_ohci_c::iolight_timer()
}
}
void bx_usb_ohci_c::runtime_config_handler(void *this_ptr)
{
bx_usb_ohci_c *class_ptr = (bx_usb_ohci_c *) this_ptr;
class_ptr->runtime_config();
}
void bx_usb_ohci_c::runtime_config(void)
{
int i;
char pname[6];
for (i = 0; i < BX_N_USB_OHCI_PORTS; i++) {
// device change support
if ((BX_OHCI_THIS hub.device_change & (1 << i)) != 0) {
BX_INFO(("USB port #%d: device connect", i+1));
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_OHCI)));
BX_OHCI_THIS hub.device_change &= ~(1 << i);
}
// forward to connected device
if (BX_OHCI_THIS hub.usb_port[i].device != NULL) {
BX_OHCI_THIS hub.usb_port[i].device->runtime_config();
}
}
}
// pci configuration space read callback handler
Bit32u bx_usb_ohci_c::pci_read_handler(Bit8u address, unsigned io_len)
{
@ -1486,8 +1500,8 @@ const char *bx_usb_ohci_c::usb_param_handler(bx_param_string_c *param, int set,
portnum = atoi((param->get_parent())->get_name()+4) - 1;
bx_bool empty = ((strlen(val) == 0) || (!strcmp(val, "none")));
if ((portnum >= 0) && (portnum < BX_N_USB_OHCI_PORTS)) {
BX_INFO(("USB port #%d experimental device change", portnum+1));
if (empty && BX_OHCI_THIS hub.usb_port[portnum].HcRhPortStatus.ccs) {
BX_INFO(("USB port #%d: device disconnect", portnum+1));
if (BX_OHCI_THIS hub.usb_port[portnum].device != NULL) {
type = BX_OHCI_THIS hub.usb_port[portnum].device->get_type();
}

View File

@ -297,6 +297,8 @@ private:
static void iolight_timer_handler(void *);
void iolight_timer(void);
static void runtime_config_handler(void *);
void runtime_config(void);
};
#endif // BX_IODEV_USB_OHCI_H

View File

@ -136,6 +136,9 @@ void bx_usb_uhci_c::init(void)
DEV_register_timer(this, iolight_timer_handler, 5000, 0,0, "UHCI i/o light");
}
BX_UHCI_THIS hub.iolight_counter = 0;
// register handler for correct device connect handling after runtime config
SIM->register_runtime_config_handler(BX_UHCI_THIS_PTR, runtime_config_handler);
BX_UHCI_THIS hub.device_change = 0;
BX_INFO(("USB UHCI initialized"));
@ -638,7 +641,6 @@ void bx_usb_uhci_c::usb_timer_handler(void *this_ptr)
void bx_usb_uhci_c::usb_timer(void)
{
int i;
char pname[6];
// If the "global reset" bit was set by software
if (BX_UHCI_THIS global_reset) {
@ -814,19 +816,6 @@ void bx_usb_uhci_c::usb_timer(void)
// If in Global_Suspend mode and any of usb_port[i] bits 6,3, or 1 are set,
// we need to issue a Global_Resume (set the global resume bit).
// However, since we don't do anything, let's not.
for (i = 0; i < BX_N_USB_UHCI_PORTS; i++) {
// forward timer tick
if (BX_UHCI_THIS hub.usb_port[i].device != NULL) {
BX_UHCI_THIS hub.usb_port[i].device->timer();
}
// device change support
if ((BX_UHCI_THIS hub.device_change & (1 << i)) != 0) {
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_UHCI)));
BX_UHCI_THIS hub.device_change &= ~(1 << i);
}
}
}
bx_bool bx_usb_uhci_c::DoTransfer(Bit32u address, Bit32u queue_num, struct TD *td) {
@ -961,6 +950,32 @@ void bx_usb_uhci_c::iolight_timer()
}
}
void bx_usb_uhci_c::runtime_config_handler(void *this_ptr)
{
bx_usb_uhci_c *class_ptr = (bx_usb_uhci_c *) this_ptr;
class_ptr->runtime_config();
}
void bx_usb_uhci_c::runtime_config(void)
{
int i;
char pname[6];
for (i = 0; i < BX_N_USB_UHCI_PORTS; i++) {
// device change support
if ((BX_UHCI_THIS hub.device_change & (1 << i)) != 0) {
BX_INFO(("USB port #%d: device connect", i+1));
sprintf(pname, "port%d", i + 1);
init_device(i, (bx_list_c*)SIM->get_param(pname, SIM->get_param(BXPN_USB_UHCI)));
BX_UHCI_THIS hub.device_change &= ~(1 << i);
}
// forward to connected device
if (BX_UHCI_THIS hub.usb_port[i].device != NULL) {
BX_UHCI_THIS hub.usb_port[i].device->runtime_config();
}
}
}
// pci configuration space read callback handler
Bit32u bx_usb_uhci_c::pci_read_handler(Bit8u address, unsigned io_len)
{
@ -1100,8 +1115,8 @@ const char *bx_usb_uhci_c::usb_param_handler(bx_param_string_c *param, int set,
portnum = atoi((param->get_parent())->get_name()+4) - 1;
bx_bool empty = ((strlen(val) == 0) || (!strcmp(val, "none")));
if ((portnum >= 0) && (portnum < BX_N_USB_UHCI_PORTS)) {
BX_INFO(("USB port #%d experimental device change", portnum+1));
if (empty && BX_UHCI_THIS hub.usb_port[portnum].status) {
BX_INFO(("USB port #%d: device disconnect", portnum+1));
if (BX_UHCI_THIS hub.usb_port[portnum].device != NULL) {
type = BX_UHCI_THIS hub.usb_port[portnum].device->get_type();
}

View File

@ -228,6 +228,8 @@ private:
static void iolight_timer_handler(void *);
void iolight_timer(void);
static void runtime_config_handler(void *);
void runtime_config(void);
};
#endif