///////////////////////////////////////////////////////////////////////// // $Id$ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2023 Benjamin David Lunt // Copyright (C) 2003-2024 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "bochs.h" #include "siminterface.h" #include "param_names.h" #if BX_USB_DEBUGGER #include "usb_debug.h" // hack for xHCI #include "iodev.h" #include "iodev/usb/usb_common.h" #include "iodev/usb/usb_xhci.h" #include #include typedef struct { const char *name; GtkWidget *entry; Bit8u fmt_size; const struct S_ATTRIBUTES *attr; } usb_reg_t; const char *chkTxt[6] = {"Reset", "Enable", "Event", "Doorbell", "Start of Frame", "Non-Exist"}; const char *chkBXPN[6] = {BXPN_USB_DEBUG_RESET, BXPN_USB_DEBUG_ENABLE, BXPN_USB_DEBUG_EVENT, BXPN_USB_DEBUG_DOORBELL, BXPN_USB_DEBUG_START_FRAME, BXPN_USB_DEBUG_NON_EXIST}; GtkWidget *main_dialog; GtkWidget *uhci_entry[UHCI_REG_COUNT]; GtkWidget *DFframe, *DFvbox, *checkbox[6]; GtkWidget *apply_button; // multithreading using pure posix threads -- not glib threads static void * EventLp(void *data) { gtk_main(); return NULL; } static void MakeGTKthreads() { pthread_t hThread; pthread_create(&hThread, NULL, EventLp, NULL); } GtkWidget* usbdlg_create_label(GtkWidget *box, const char *text, bool expand = true) { GtkWidget *label = gtk_label_new(text); gtk_box_pack_start(GTK_BOX(box), label, expand, expand, 2); return label; } GtkWidget* usbdlg_create_entry_with_label(GtkWidget **box, const char *text, bool expand = true) { gtk_box_pack_start(GTK_BOX(box[0]), gtk_label_new(text), expand, expand, 2); GtkWidget *entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(box[1]), entry, expand, expand, 2); return entry; } GtkWidget* usbdlg_create_ro_entry(GtkWidget *box, bool expand = true) { GtkWidget *entry = gtk_entry_new(); gtk_widget_set_sensitive(entry, 0); gtk_box_pack_start(GTK_BOX(box), entry, expand, expand, 2); return entry; } GtkWidget* usbdlg_create_ro_entry_with_label(GtkWidget **box, const char *text, bool expand = true) { gtk_box_pack_start(GTK_BOX(box[0]), gtk_label_new(text), expand, expand, 2); GtkWidget *entry = gtk_entry_new(); gtk_widget_set_sensitive(entry, 0); gtk_box_pack_start(GTK_BOX(box[1]), entry, expand, expand, 2); return entry; } void usbdlg_create_debug_flags(GtkWidget *vbox) { DFframe = gtk_frame_new("Debug Flags"); gtk_box_pack_start(GTK_BOX(vbox), DFframe, FALSE, FALSE, 2); DFvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(DFframe), DFvbox); for (int i = 0; i < 6; i++) { checkbox[i] = gtk_check_button_new_with_label(chkTxt[i]); if (SIM->get_param_num(chkBXPN[i])->get() > 0) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox[i]), TRUE); } gtk_box_pack_start(GTK_BOX(DFvbox), checkbox[i], FALSE, FALSE, 2); } } void usbdlg_set_debug_flags() { for (int i = 0; i < 6; i++) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkbox[i]))) { SIM->get_param_num(chkBXPN[i])->set(1); } else { SIM->get_param_num(chkBXPN[i])->set(0); } } } static void usb_regview_dialog(GtkWidget *widget, gpointer data) { int i, ret; char buffer[32], format[10]; Bit32u oldval, value; usb_reg_t *usb_reg_def = (usb_reg_t*)data; GtkWidget *dialog = gtk_dialog_new_with_buttons(usb_reg_def->name, GTK_WINDOW(main_dialog), GTK_DIALOG_MODAL, g_dgettext("gtk30", "_OK"), GTK_RESPONSE_OK, g_dgettext("gtk30", "_Cancel"), GTK_RESPONSE_CANCEL, NULL); gtk_window_set_default_size(GTK_WINDOW(dialog), 250, 250); GtkWidget *listbox = gtk_list_box_new(); gtk_list_box_set_selection_mode(GTK_LIST_BOX(listbox), GTK_SELECTION_MULTIPLE); gtk_list_box_set_activate_on_single_click(GTK_LIST_BOX(listbox), 1); i = 0; while (usb_reg_def->attr[i].index > -1) { gtk_list_box_insert(GTK_LIST_BOX(listbox), gtk_label_new(usb_reg_def->attr[i].str), -1); i++; } gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), listbox, TRUE, TRUE, 2); // Show dialog gtk_widget_show_all(dialog); oldval = strtoul(gtk_entry_get_text(GTK_ENTRY(usb_reg_def->entry)), NULL, 16); i = 0; while (usb_reg_def->attr[i].index > -1) { if ((oldval & usb_reg_def->attr[i].mask) != 0) { gtk_list_box_select_row(GTK_LIST_BOX(listbox), gtk_list_box_get_row_at_index(GTK_LIST_BOX(listbox), i)); } else { gtk_list_box_unselect_row(GTK_LIST_BOX(listbox), gtk_list_box_get_row_at_index(GTK_LIST_BOX(listbox), i)); } i++; } ret = gtk_dialog_run(GTK_DIALOG(dialog)); if (ret == GTK_RESPONSE_OK) { value = 0; i = 0; while (usb_reg_def->attr[i].index > -1) { if (gtk_list_box_row_is_selected(gtk_list_box_get_row_at_index(GTK_LIST_BOX(listbox), i))) { value |= usb_reg_def->attr[i].mask; } i++; } if (value != oldval) { sprintf(format, "0x%%0%iX", usb_reg_def->fmt_size); sprintf(buffer, format, value); gtk_entry_set_text(GTK_ENTRY(usb_reg_def->entry), buffer); } } gtk_widget_destroy(dialog); } // Save UHCI state to controller int hc_uhci_save() { char buffer[COMMON_STR_SIZE]; if (u_changed[UHCI_REG_COMMAND]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_COMMAND]))); usb_io_write(pci_bar_address + 0, strtol(buffer, NULL, 0), 2); } if (u_changed[UHCI_REG_STATUS]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_STATUS]))); usb_io_write(pci_bar_address + 2, strtol(buffer, NULL, 0), 2); } if (u_changed[UHCI_REG_INTERRUPT]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_INTERRUPT]))); usb_io_write(pci_bar_address + 4, strtol(buffer, NULL, 0), 2); } if (u_changed[UHCI_REG_FRAME_NUM]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_FRAME_NUM]))); usb_io_write(pci_bar_address + 6, strtol(buffer, NULL, 0), 2); } if (u_changed[UHCI_REG_FRAME_ADDR]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_FRAME_ADDR]))); usb_io_write(pci_bar_address + 8, strtol(buffer, NULL, 0), 4); } if (u_changed[UHCI_REG_SOF]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_SOF]))); usb_io_write(pci_bar_address + 12, strtol(buffer, NULL, 0), 1); } if (u_changed[UHCI_REG_PORT0]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_PORT0]))); usb_io_write(pci_bar_address + 16, strtol(buffer, NULL, 0), 2); } if (u_changed[UHCI_REG_PORT1]) { strcpy(buffer, gtk_entry_get_text(GTK_ENTRY(uhci_entry[UHCI_REG_PORT1]))); usb_io_write(pci_bar_address + 18, strtol(buffer, NULL, 0), 2); } memset(u_changed, 0, sizeof(u_changed)); gtk_widget_set_sensitive(apply_button, 0); return 0; } // Apply button support static void on_entry_changed(GtkWidget *widget, gpointer data) { *((bool*)data) = 1; gtk_widget_set_sensitive(apply_button, 1); } static void apply_changes(GtkWidget *widget, gpointer data) { if (usb_debug_type == USB_DEBUG_UHCI) { hc_uhci_save(); } else { GtkWidget* error = gtk_message_dialog_new( GTK_WINDOW(main_dialog), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Saving changes to controller not implemented yet"); gtk_window_set_title(GTK_WINDOW(error), "WARNING"); gtk_dialog_run(GTK_DIALOG(error)); gtk_widget_destroy(error); } } void usbdlg_create_apply_button(GtkWidget *vbox) { GtkWidget *apply_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(vbox), apply_hbox, FALSE, FALSE, 2); apply_button = gtk_button_new_with_label(g_dgettext("gtk30", "_Apply")); gtk_widget_set_sensitive(apply_button, 0); g_signal_connect(apply_button, "clicked", G_CALLBACK(apply_changes), NULL); gtk_box_pack_start(GTK_BOX(apply_hbox), apply_button, FALSE, FALSE, 2); } // UHCI main dialog int uhci_debug_dialog(int type, int param1) { bx_list_c *UHCI_state = NULL; int i, ret; Bit32u frame_addr, frame_num; char buffer[COMMON_STR_SIZE]; GtkWidget *mainVbox, *BAhbox, *hbox[2], *vbox[3], *ro_entry[4]; GtkWidget *ORframe, *ORhbox, *ORvbox[3]; GtkWidget *PRframe, *PRhbox, *PRvbox[3]; GtkWidget *TVvbox, *FNhbox; GtkWidget *button[8], *FNlabel, *treeview; usb_reg_t uhci_reg_def[5] = { {"Command Register", NULL, 4, attribs_u_command}, {"Status Register", NULL, 4, attribs_u_status}, {"Interrupt Enable Register", NULL, 4, attribs_u_interrupt}, {"Port 0 Register", NULL, 4, attribs_u_ports}, {"Port 1 Register", NULL, 4, attribs_u_ports} }; UHCI_state = (bx_list_c*)SIM->get_param("usb_uhci", SIM->get_bochs_root()); if (UHCI_state == NULL) return -1; main_dialog = gtk_dialog_new(); switch (type) { case USB_DEBUG_FRAME: gtk_window_set_title(GTK_WINDOW(main_dialog), "UHCI Debug Dialog: Break Type: Start of Frame"); break; case USB_DEBUG_COMMAND: gtk_window_set_title(GTK_WINDOW(main_dialog), "UHCI Debug Dialog: Break Type: Doorbell"); break; case USB_DEBUG_NONEXIST: gtk_window_set_title(GTK_WINDOW(main_dialog), "UHCI Debug Dialog: Break Type: Non-Existant Port Write"); break; case USB_DEBUG_RESET: sprintf(buffer, "UHCI Debug Dialog: Break Type: Port %d Reset", param1); gtk_window_set_title(GTK_WINDOW(main_dialog), buffer); break; case USB_DEBUG_ENABLE: sprintf(buffer, "UHCI Debug Dialog: Break Type: Port %d Enable", param1); gtk_window_set_title(GTK_WINDOW(main_dialog), buffer); break; default: gtk_window_set_title(GTK_WINDOW(main_dialog), "UHCI Debug Dialog"); } gtk_window_set_default_size(GTK_WINDOW(main_dialog), 600, 500); button[0] = gtk_dialog_add_button(GTK_DIALOG(main_dialog), "Continue", GTK_RESPONSE_OK); button[1] = gtk_dialog_add_button(GTK_DIALOG(main_dialog), "Quit", GTK_RESPONSE_CANCEL); gtk_dialog_set_default_response(GTK_DIALOG(main_dialog), GTK_RESPONSE_OK); gtk_window_set_focus(GTK_WINDOW(main_dialog), button[0]); mainVbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(main_dialog))), mainVbox, TRUE, TRUE, 2); BAhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(mainVbox), BAhbox, FALSE, FALSE, 2); usbdlg_create_label(BAhbox, "UHCI at Base IO address", false); ro_entry[0] = usbdlg_create_ro_entry(BAhbox, false); hbox[0] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(mainVbox), hbox[0], TRUE, TRUE, 2); hbox[1] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(mainVbox), hbox[1], TRUE, TRUE, 2); for (i = 0; i < 3; i++) { vbox[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(hbox[0]), vbox[i], TRUE, TRUE, 2); } ORframe = gtk_frame_new("Operational Registers"); gtk_box_pack_start(GTK_BOX(vbox[0]), ORframe, FALSE, FALSE, 2); ORhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add(GTK_CONTAINER(ORframe), ORhbox); for (i = 0; i < 3; i++) { ORvbox[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(ORhbox), ORvbox[i], FALSE, FALSE, 2); } uhci_entry[UHCI_REG_COMMAND] = usbdlg_create_entry_with_label(ORvbox, "Command"); button[2] = gtk_button_new_with_label("<>"); uhci_reg_def[0].entry = uhci_entry[UHCI_REG_COMMAND]; g_signal_connect(button[2], "clicked", G_CALLBACK(usb_regview_dialog), &uhci_reg_def[0]); gtk_box_pack_start(GTK_BOX(ORvbox[2]), button[2], FALSE, FALSE, 2); uhci_entry[UHCI_REG_STATUS] = usbdlg_create_entry_with_label(ORvbox, "Status"); button[3] = gtk_button_new_with_label("<>"); uhci_reg_def[1].entry = uhci_entry[UHCI_REG_STATUS]; g_signal_connect(button[3], "clicked", G_CALLBACK(usb_regview_dialog), &uhci_reg_def[1]); gtk_box_pack_start(GTK_BOX(ORvbox[2]), button[3], FALSE, FALSE, 2); uhci_entry[UHCI_REG_INTERRUPT] = usbdlg_create_entry_with_label(ORvbox, "Interrupt Enable"); button[4] = gtk_button_new_with_label("<>"); uhci_reg_def[2].entry = uhci_entry[UHCI_REG_INTERRUPT]; g_signal_connect(button[4], "clicked", G_CALLBACK(usb_regview_dialog), &uhci_reg_def[2]); gtk_box_pack_start(GTK_BOX(ORvbox[2]), button[4], FALSE, FALSE, 2); uhci_entry[UHCI_REG_FRAME_NUM] = usbdlg_create_entry_with_label(ORvbox, "Frame Number"); uhci_entry[UHCI_REG_FRAME_ADDR] = usbdlg_create_entry_with_label(ORvbox, "Frame Address"); uhci_entry[UHCI_REG_SOF] = usbdlg_create_entry_with_label(ORvbox, "Start of Frame"); PRframe = gtk_frame_new("Port Registers"); gtk_box_pack_start(GTK_BOX(hbox[1]), PRframe, FALSE, FALSE, 2); PRhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add(GTK_CONTAINER(PRframe), PRhbox); for (i = 0; i < 3; i++) { PRvbox[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(PRhbox), PRvbox[i], FALSE, FALSE, 2); } for (i = 0; i < 2; i++) { sprintf(buffer, "Port %d", i); uhci_entry[UHCI_REG_PORT0 + i] = usbdlg_create_entry_with_label(PRvbox, buffer); ro_entry[i + 1] = usbdlg_create_ro_entry_with_label(PRvbox, "Emulation Type"); button[i + 5] = gtk_button_new_with_label("<>"); uhci_reg_def[i + 3].entry = uhci_entry[UHCI_REG_PORT0 + i]; g_signal_connect(button[i + 5], "clicked", G_CALLBACK(usb_regview_dialog), &uhci_reg_def[i + 3]); gtk_box_pack_start(GTK_BOX(PRvbox[2]), button[i + 5], FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(PRvbox[2]), gtk_label_new(" "), FALSE, FALSE, 8); // spacer } TVvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(hbox[1]), TVvbox, TRUE, TRUE, 2); FNhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(TVvbox), FNhbox, FALSE, FALSE, 2); FNlabel = usbdlg_create_label(FNhbox, "Frame at Address", false); ro_entry[3] = usbdlg_create_ro_entry(FNhbox, false); button[7] = gtk_button_new_with_label("View Item"); gtk_widget_set_sensitive(button[7], 0); gtk_box_pack_start(GTK_BOX(FNhbox), button[7], FALSE, FALSE, 2); treeview = gtk_tree_view_new(); gtk_box_pack_start(GTK_BOX(TVvbox), treeview, TRUE, TRUE, 2); usbdlg_create_apply_button(mainVbox); usbdlg_create_debug_flags(vbox[2]); // Set values pci_bar_address = get_pci_bar_addr((bx_shadow_data_c*)SIM->get_param("hub.pci_conf", UHCI_state), 4); sprintf(buffer, "0x%04X", pci_bar_address); gtk_entry_set_text(GTK_ENTRY(ro_entry[0]), buffer); sprintf(buffer, "0x%04X", usb_io_read(pci_bar_address + 0, 2)); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_COMMAND]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_COMMAND]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_COMMAND]); sprintf(buffer, "0x%04X", usb_io_read(pci_bar_address + 2, 2)); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_STATUS]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_STATUS]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_STATUS]); sprintf(buffer, "0x%04X", usb_io_read(pci_bar_address + 4, 2)); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_INTERRUPT]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_INTERRUPT]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_INTERRUPT]); frame_num = usb_io_read(pci_bar_address + 6, 2); sprintf(buffer, "0x%04X", frame_num); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_FRAME_NUM]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_FRAME_NUM]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_FRAME_NUM]); frame_addr = usb_io_read(pci_bar_address + 8, 4); sprintf(buffer, "0x%08X", frame_addr); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_FRAME_ADDR]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_FRAME_ADDR]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_FRAME_ADDR]); sprintf(buffer, "0x%02X", usb_io_read(pci_bar_address + 12, 1)); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_SOF]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_SOF]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_SOF]); sprintf(buffer, "0x%04X", usb_io_read(pci_bar_address + 16, 2)); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_PORT0]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_PORT0]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_PORT0]); SIM->get_param_enum("port1.device", host_param)->dump_param(buffer, COMMON_STR_SIZE, 1); gtk_entry_set_text(GTK_ENTRY(ro_entry[1]), buffer); sprintf(buffer, "0x%04X", usb_io_read(pci_bar_address + 18, 2)); gtk_entry_set_text(GTK_ENTRY(uhci_entry[UHCI_REG_PORT1]), buffer); g_signal_connect(GTK_EDITABLE(uhci_entry[UHCI_REG_PORT1]), "changed", G_CALLBACK(on_entry_changed), &u_changed[UHCI_REG_PORT1]); SIM->get_param_enum("port2.device", host_param)->dump_param(buffer, COMMON_STR_SIZE, 1); gtk_entry_set_text(GTK_ENTRY(ro_entry[2]), buffer); frame_addr += (frame_num * sizeof(Bit32u)); sprintf(buffer, "0x%08X", frame_addr); gtk_entry_set_text(GTK_ENTRY(ro_entry[3]), buffer); bool valid = 0; switch (type) { // The DoTransfer() function was called case USB_DEBUG_COMMAND: // The start of a frame timer was triggered case USB_DEBUG_FRAME: gtk_label_set_text(GTK_LABEL(FNlabel), "SOF Frame Address"); if (frame_addr != 0x00000000) { gtk_widget_set_sensitive(button[7], 1); valid = 1; } break; // an event triggered. We ignore these in the uhci //case USB_DEBUG_EVENT: // break; // first byte (word, dword, qword) of first non-existant port was written to case USB_DEBUG_NONEXIST: // port reset (non-root reset) case USB_DEBUG_RESET: // enable changed case USB_DEBUG_ENABLE: gtk_label_set_text(GTK_LABEL(FNlabel), "None"); gtk_entry_set_text(GTK_ENTRY(ro_entry[3]), "None"); break; } if (!valid) { gtk_widget_set_sensitive(treeview, 0); usbdlg_create_label(TVvbox, "This trigger does not populate the tree view", false); } else { usbdlg_create_label(TVvbox, "Tree view populated", false); } // Show dialog gtk_widget_show_all(main_dialog); ret = gtk_dialog_run(GTK_DIALOG(main_dialog)); if (ret == GTK_RESPONSE_OK) { usbdlg_set_debug_flags(); } gtk_widget_destroy(main_dialog); return ret; } // xHCI main dialog int xhci_debug_dialog(int type, int param1) { bx_list_c *xHCI_state = NULL; int i, n_ports, ret; Bit32u dword, offset; Bit64u RingPtr = 0; char buffer[COMMON_STR_SIZE], tmpbuf[32]; GtkWidget *mainVbox, *BAhbox, *hbox[2], *vbox[4], *entry[38]; GtkWidget *CRframe, *CRhbox, *CRvbox[2]; GtkWidget *ORframe, *ORhbox, *ORvbox[2]; GtkWidget *RTframe, *RThbox, *RTvbox[2]; GtkWidget *PRframe, *PRhbox, *PRvbox[3]; GtkWidget *TVvbox, *FNhbox; GtkWidget *button[13], *FNlabel, *treeview; usb_reg_t xhci_reg_def[10] = { {"Port 0 Register", NULL, 8, attribs_x_ports}, {"Port 1 Register", NULL, 8, attribs_x_ports}, {"Port 2 Register", NULL, 8, attribs_x_ports}, {"Port 3 Register", NULL, 8, attribs_x_ports}, {"Port 4 Register", NULL, 8, attribs_x_ports}, {"Port 5 Register", NULL, 8, attribs_x_ports}, {"Port 6 Register", NULL, 8, attribs_x_ports}, {"Port 7 Register", NULL, 8, attribs_x_ports}, {"Port 8 Register", NULL, 8, attribs_x_ports}, {"Port 9 Register", NULL, 8, attribs_x_ports} }; xHCI_state = (bx_list_c*)SIM->get_param("usb_xhci", SIM->get_bochs_root()); if (xHCI_state == NULL) return -1; main_dialog = gtk_dialog_new(); switch (type) { case USB_DEBUG_COMMAND: gtk_window_set_title(GTK_WINDOW(main_dialog), "xHCI Debug Dialog: Break Type: Command Ring"); break; case USB_DEBUG_EVENT: gtk_window_set_title(GTK_WINDOW(main_dialog), "xHCI Debug Dialog: Break Type: Event Ring"); break; case USB_DEBUG_FRAME: gtk_window_set_title(GTK_WINDOW(main_dialog), "xHCI Debug Dialog: Break Type: Frame"); break; default: gtk_window_set_title(GTK_WINDOW(main_dialog), "xHCI Debug Dialog"); } gtk_window_set_default_size(GTK_WINDOW(main_dialog), 600, 500); button[0] = gtk_dialog_add_button(GTK_DIALOG(main_dialog), "Continue", GTK_RESPONSE_OK); button[1] = gtk_dialog_add_button(GTK_DIALOG(main_dialog), "Quit", GTK_RESPONSE_CANCEL); gtk_dialog_set_default_response(GTK_DIALOG(main_dialog), GTK_RESPONSE_OK); gtk_window_set_focus(GTK_WINDOW(main_dialog), button[0]); mainVbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(main_dialog))), mainVbox, TRUE, TRUE, 2); BAhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(mainVbox), BAhbox, FALSE, FALSE, 2); usbdlg_create_label(BAhbox, "xHCI at Base MMIO address", false); entry[0] = usbdlg_create_ro_entry(BAhbox, false); hbox[0] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(mainVbox), hbox[0], TRUE, TRUE, 2); hbox[1] = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(mainVbox), hbox[1], TRUE, TRUE, 2); for (i = 0; i < 4; i++) { vbox[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(hbox[0]), vbox[i], TRUE, TRUE, 2); } CRframe = gtk_frame_new("Capability Registers"); gtk_box_pack_start(GTK_BOX(vbox[0]), CRframe, FALSE, FALSE, 2); CRhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add(GTK_CONTAINER(CRframe), CRhbox); CRvbox[0] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(CRhbox), CRvbox[0], FALSE, FALSE, 2); CRvbox[1] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(CRhbox), CRvbox[1], FALSE, FALSE, 2); entry[1] = usbdlg_create_entry_with_label(CRvbox, "Cap Length"); entry[2] = usbdlg_create_entry_with_label(CRvbox, "HCSParams1"); entry[3] = usbdlg_create_ro_entry_with_label(CRvbox, "HCSParams2"); entry[4] = usbdlg_create_entry_with_label(CRvbox, "HCSParams3"); entry[5] = usbdlg_create_entry_with_label(CRvbox, "HCCParams1"); entry[6] = usbdlg_create_entry_with_label(CRvbox, "DB Offset"); entry[7] = usbdlg_create_entry_with_label(CRvbox, "RTS Offset"); entry[8] = usbdlg_create_entry_with_label(CRvbox, "HCCParams2"); ORframe = gtk_frame_new("Operational Registers"); gtk_box_pack_start(GTK_BOX(vbox[1]), ORframe, FALSE, FALSE, 2); ORhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add(GTK_CONTAINER(ORframe), ORhbox); ORvbox[0] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(ORhbox), ORvbox[0], FALSE, FALSE, 2); ORvbox[1] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(ORhbox), ORvbox[1], FALSE, FALSE, 2); entry[9] = usbdlg_create_ro_entry_with_label(ORvbox, "Command"); entry[10] = usbdlg_create_entry_with_label(ORvbox, "Status"); entry[11] = usbdlg_create_entry_with_label(ORvbox, "Page Size"); entry[12] = usbdlg_create_entry_with_label(ORvbox, "Device Notification"); entry[13] = usbdlg_create_entry_with_label(ORvbox, "Command Ring"); entry[14] = usbdlg_create_entry_with_label(ORvbox, "Device Context Base"); entry[15] = usbdlg_create_entry_with_label(ORvbox, "Configure"); RTframe = gtk_frame_new("Runtime Registers"); gtk_box_pack_start(GTK_BOX(vbox[2]), RTframe, FALSE, FALSE, 2); RThbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add(GTK_CONTAINER(RTframe), RThbox); RTvbox[0] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(RThbox), RTvbox[0], FALSE, FALSE, 2); RTvbox[1] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(RThbox), RTvbox[1], FALSE, FALSE, 2); entry[16] = usbdlg_create_entry_with_label(RTvbox, "Microframe Index"); PRframe = gtk_frame_new("Port Registers"); gtk_box_pack_start(GTK_BOX(hbox[1]), PRframe, FALSE, FALSE, 2); PRhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_container_add(GTK_CONTAINER(PRframe), PRhbox); for (i = 0; i < 3; i++) { PRvbox[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(PRhbox), PRvbox[i], FALSE, FALSE, 2); } n_ports = SIM->get_param_num(BXPN_XHCI_N_PORTS)->get(); for (i = 0; i < n_ports; i++) { sprintf(buffer, "Port %d", i); entry[i * 2 + 17] = usbdlg_create_entry_with_label(PRvbox, buffer); entry[i * 2 + 18] = usbdlg_create_ro_entry_with_label(PRvbox, "Emulation Type"); button[i + 2] = gtk_button_new_with_label("<>"); xhci_reg_def[i].entry = entry[i * 2 + 17]; g_signal_connect(button[i + 2], "clicked", G_CALLBACK(usb_regview_dialog), &xhci_reg_def[i]); gtk_box_pack_start(GTK_BOX(PRvbox[2]), button[i + 2], FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(PRvbox[2]), gtk_label_new(" "), FALSE, FALSE, 8); // spacer } TVvbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start(GTK_BOX(hbox[1]), TVvbox, TRUE, TRUE, 2); FNhbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(TVvbox), FNhbox, FALSE, FALSE, 2); FNlabel = usbdlg_create_label(FNhbox, "Ring Address", false); entry[n_ports * 2 + 17] = usbdlg_create_ro_entry(FNhbox, false); button[12] = gtk_button_new_with_label("View TRB"); gtk_widget_set_sensitive(button[12], 0); gtk_box_pack_start(GTK_BOX(FNhbox), button[12], FALSE, FALSE, 2); treeview = gtk_tree_view_new(); gtk_box_pack_start(GTK_BOX(TVvbox), treeview, TRUE, TRUE, 2); usbdlg_create_apply_button(mainVbox); usbdlg_create_debug_flags(vbox[3]); // Set values pci_bar_address = get_pci_bar_addr((bx_shadow_data_c*)SIM->get_param("hub.pci_conf", xHCI_state), 0); sprintf(buffer, "0x%08X", pci_bar_address); gtk_entry_set_text(GTK_ENTRY(entry[0]), buffer); for (i = 0; i < 8; i++) { dword = xhci_read_dword(pci_bar_address + (i * 4)); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[i + 1]), buffer); g_signal_connect(GTK_EDITABLE(entry[i + 1]), "changed", G_CALLBACK(on_entry_changed), NULL); } offset = xhci_read_dword(pci_bar_address + 0) & 0xFF; dword = xhci_read_dword(pci_bar_address + offset + 0x00); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[9]), buffer); g_signal_connect(GTK_EDITABLE(entry[9]), "changed", G_CALLBACK(on_entry_changed), NULL); dword = xhci_read_dword(pci_bar_address + offset + 0x04); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[10]), buffer); g_signal_connect(GTK_EDITABLE(entry[10]), "changed", G_CALLBACK(on_entry_changed), NULL); dword = xhci_read_dword(pci_bar_address + offset + 0x08); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[11]), buffer); g_signal_connect(GTK_EDITABLE(entry[11]), "changed", G_CALLBACK(on_entry_changed), NULL); dword = xhci_read_dword(pci_bar_address + offset + 0x14); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[12]), buffer); g_signal_connect(GTK_EDITABLE(entry[12]), "changed", G_CALLBACK(on_entry_changed), NULL); // we can't read this using DEV_MEM_READ_PHYSICAL since the handler will return zero sprintf(buffer, "0x" FMT_ADDRX64, SIM->get_param_num("hub.op_regs.HcCrcr.actual", xHCI_state)->get64()); gtk_entry_set_text(GTK_ENTRY(entry[13]), buffer); g_signal_connect(GTK_EDITABLE(entry[13]), "changed", G_CALLBACK(on_entry_changed), NULL); Bit64u qword = xhci_read_dword(pci_bar_address + offset + 0x30) | ((Bit64u) xhci_read_dword(pci_bar_address + offset + 0x34) << 32); sprintf(buffer, "0x" FMT_ADDRX64, qword); gtk_entry_set_text(GTK_ENTRY(entry[14]), buffer); g_signal_connect(GTK_EDITABLE(entry[14]), "changed", G_CALLBACK(on_entry_changed), NULL); dword = xhci_read_dword(pci_bar_address + offset + 0x38); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[15]), buffer); g_signal_connect(GTK_EDITABLE(entry[15]), "changed", G_CALLBACK(on_entry_changed), NULL); offset = xhci_read_dword(pci_bar_address + 0x18); dword = xhci_read_dword(pci_bar_address + offset + 0); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[16]), buffer); g_signal_connect(GTK_EDITABLE(entry[16]), "changed", G_CALLBACK(on_entry_changed), NULL); // show up to 10 port register sets for (i = 0; i < n_ports; i++) { dword = xhci_read_dword(pci_bar_address + XHCI_PORT_SET_OFFSET + (i * 16)); sprintf(buffer, "0x%08X", dword); gtk_entry_set_text(GTK_ENTRY(entry[i * 2 + 17]), buffer); g_signal_connect(GTK_EDITABLE(entry[i * 2 + 17]), "changed", G_CALLBACK(on_entry_changed), NULL); sprintf(tmpbuf, "port%d.device", i + 1); SIM->get_param_enum(tmpbuf, host_param)->dump_param(buffer, COMMON_STR_SIZE, 1); gtk_entry_set_text(GTK_ENTRY(entry[i * 2 + 18]), buffer); } bool valid = 0; switch (type) { // a command TRB was placed on the command ring case USB_DEBUG_COMMAND: gtk_label_set_text(GTK_LABEL(FNlabel), "Command Ring Address"); RingPtr = SIM->get_param_num("hub.op_regs.HcCrcr.crc", xHCI_state)->get(); sprintf(buffer, "0x" FMT_ADDRX64, RingPtr); gtk_entry_set_text(GTK_ENTRY(entry[n_ports * 2 + 17]), buffer); if (RingPtr != 0) { gtk_widget_set_sensitive(button[12], 1); valid = 1; } break; // an event TRB was placed on an event ring case USB_DEBUG_EVENT: gtk_label_set_text(GTK_LABEL(FNlabel), "Event Ring"); sprintf(buffer, "Interrupter %i", param1); gtk_entry_set_text(GTK_ENTRY(entry[n_ports * 2 + 17]), buffer); gtk_widget_set_sensitive(button[12], 1); valid = 1; break; case USB_DEBUG_FRAME: gtk_label_set_text(GTK_LABEL(FNlabel), "SOF Frame Address"); break; // first byte (word, dword, qword) of first non-existant port was written to case USB_DEBUG_NONEXIST: // port reset (non-root reset) case USB_DEBUG_RESET: // enable changed case USB_DEBUG_ENABLE: gtk_label_set_text(GTK_LABEL(FNlabel), "None"); gtk_entry_set_text(GTK_ENTRY(entry[n_ports * 2 + 17]), "None"); break; } if (!valid) { gtk_widget_set_sensitive(treeview, 0); usbdlg_create_label(TVvbox, "This trigger does not populate the tree view", false); } else { usbdlg_create_label(TVvbox, "Tree view populated", false); } // Show dialog gtk_widget_show_all(main_dialog); ret = gtk_dialog_run(GTK_DIALOG(main_dialog)); if (ret == GTK_RESPONSE_OK) { usbdlg_set_debug_flags(); } gtk_widget_destroy(main_dialog); return ret; } // USB debug dialog entry point int usb_debug_dialog(int type, int param1, int param2) { static bool first_call = true; int argc = 1, ret; char *argv[2], **argvp, buffer[COMMON_STR_SIZE]; if (first_call) { if (!SIM->is_wx_selected() && !SIM->has_debug_gui()) { // you MUST call gtk_init, even with faked arguments, because it inits GDK and Glib *buffer = 0; // gtk flames out if you pass in a NULL -- sheesh argv[0] = buffer; // so I really do have to fake up an "argv" list argv[1] = NULL; argvp = argv; if (gtk_init_check(&argc, &argvp) == false) { fprintf(stderr, "gtk init failed, can not access display?\n"); return -1; } MakeGTKthreads(); } first_call = false; } host_param = SIM->get_param(hc_param_str[usb_debug_type]); if (usb_debug_type == USB_DEBUG_UHCI) { ret = uhci_debug_dialog(type, param1); return (ret == GTK_RESPONSE_OK) ? 0 : -1; } else if (usb_debug_type == USB_DEBUG_XHCI) { ret = xhci_debug_dialog(type, param1); return (ret == GTK_RESPONSE_OK) ? 0 : -1; } else { GtkWidget* error = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK_CANCEL, "GTK version of USB debugger dialog not implemented yet"); gtk_window_set_title(GTK_WINDOW(error), "WARNING"); ret = gtk_dialog_run(GTK_DIALOG(error)); gtk_widget_destroy(error); return (ret == GTK_RESPONSE_OK) ? 0 : -1; } } #endif