# HG changeset patch # User Michael Pavone # Date 1663464564 25200 # Node ID 0a107b2d5837daa1d9b90a8e976731b4ae9d80ec # Parent f82c090c1e89189c19d17d79b5fb41623f7f5b64 Add support for EA 4-way Play diff -r f82c090c1e89 -r 0a107b2d5837 config.c --- a/config.c Sat Sep 17 15:38:40 2022 -0700 +++ b/config.c Sat Sep 17 18:29:24 2022 -0700 @@ -285,7 +285,7 @@ *pads = tern_insert_node(*pads, key, dupe_tree(val.ptrval)); } -#define CONFIG_VERSION 4 +#define CONFIG_VERSION 5 static tern_node *migrate_config(tern_node *config, int from_version) { tern_node *def_config = parse_bundled_config("default.cfg"); @@ -351,6 +351,16 @@ config = tern_insert_path(config, "io\0sega_multitap.1\0""3\0", (tern_val){.ptrval = strdup(tap13)}, TVAL_PTR); config = tern_insert_path(config, "io\0sega_multitap.1\0""4\0", (tern_val){.ptrval = strdup(tap14)}, TVAL_PTR); } + case 4: { + char *tap11 = tern_find_path_default(config, "io\0ea_multitap\0""1\0", (tern_val){.ptrval = "gamepad6.1"}, TVAL_PTR).ptrval; + char *tap12 = tern_find_path_default(config, "io\0ea_multitap\0""2\0", (tern_val){.ptrval = "gamepad6.2"}, TVAL_PTR).ptrval; + char *tap13 = tern_find_path_default(config, "io\0ea_multitap\0""3\0", (tern_val){.ptrval = "gamepad6.3"}, TVAL_PTR).ptrval; + char *tap14 = tern_find_path_default(config, "io\0ea_multitap\0""4\0", (tern_val){.ptrval = "gamepad6.4"}, TVAL_PTR).ptrval; + config = tern_insert_path(config, "io\0ea_multitap\0""1\0", (tern_val){.ptrval = strdup(tap11)}, TVAL_PTR); + config = tern_insert_path(config, "io\0ea_multitap\0""2\0", (tern_val){.ptrval = strdup(tap12)}, TVAL_PTR); + config = tern_insert_path(config, "io\0ea_multitap\0""3\0", (tern_val){.ptrval = strdup(tap13)}, TVAL_PTR); + config = tern_insert_path(config, "io\0ea_multitap\0""4\0", (tern_val){.ptrval = strdup(tap14)}, TVAL_PTR); + } } char buffer[16]; sprintf(buffer, "%d", CONFIG_VERSION); diff -r f82c090c1e89 -r 0a107b2d5837 default.cfg --- a/default.cfg Sat Sep 17 15:38:40 2022 -0700 +++ b/default.cfg Sat Sep 17 18:29:24 2022 -0700 @@ -282,6 +282,12 @@ 3 gamepad6.4 4 gamepad6.5 } + ea_multitap { + 1 gamepad6.1 + 2 gamepad6.2 + 3 gamepad6.3 + 4 gamepad6.4 + } } video { diff -r f82c090c1e89 -r 0a107b2d5837 io.c --- a/io.c Sat Sep 17 15:38:40 2022 -0700 +++ b/io.c Sat Sep 17 18:29:24 2022 -0700 @@ -36,8 +36,8 @@ "Menacer", "Justifier", "Sega Multi-tap", - "EA 4-way Play cable A", - "EA 4-way Play cable B", + "EA 4-way Play", + "EA 4-way Play", "Sega Parallel Transfer Board", "Generic Device", "Generic Serial", @@ -67,6 +67,8 @@ HBPT_REPLY }; +#define EA_PASSTHRU_MODE 0xFF + typedef struct { uint8_t states[2], value; } gp_button_def; @@ -98,7 +100,7 @@ if (port->device_type == IO_HEARTBEAT_TRAINER && port->device.heartbeat_trainer.device_num == gamepad_num) { return port; } - if (port->device_type == IO_SEGA_MULTI) { + if (port->device_type == IO_SEGA_MULTI || port->device_type == IO_EA_MULTI_A) { for (int j = 0; j < 4; j++) { io_port *tap_port = port->device.multitap.ports + j; @@ -119,6 +121,15 @@ if (port->device_type == IO_MOUSE && port->device.mouse.mouse_num == mouse_num) { return port; } + if (port->device_type == IO_SEGA_MULTI) { + for (int j = 0; j < 4; j++) + { + io_port *tap_port = port->device.multitap.ports + j; + if (tap_port->device_type == IO_MOUSE && tap_port->device.mouse.mouse_num == mouse_num) { + return tap_port; + } + } + } } return NULL; } @@ -251,7 +262,7 @@ return; } io_port *old_ports = NULL; - if (port->device_type == IO_SEGA_MULTI) { + if (port->device_type == IO_SEGA_MULTI || port->device_type == IO_EA_MULTI_A) { old_ports = port->device.multitap.ports; } @@ -331,6 +342,18 @@ } old_ports = NULL; } + } else if(!strcmp(device_type, "ea_multitap_port_a")) { + if (port->device_type != IO_EA_MULTI_A) { + port->device_type = IO_EA_MULTI_A; + port->device.multitap.ports = old_ports ? old_ports : calloc(4, sizeof(io_port)); + port->device.multitap.tap_num = 1; + port->device.multitap.cur_port = EA_PASSTHRU_MODE; + old_ports = NULL; + } + } else if(!strcmp(device_type, "ea_multitap_port_b")) { + port->device_type = IO_EA_MULTI_B; + port->device.multitap.ports = NULL; + port->device.multitap.tap_num = 1; } free(old_ports); } @@ -492,7 +515,28 @@ io_data_write(ports[i].device.multitap.ports + j, 0x40, 0); } } - + } else if (ports[i].device_type == IO_EA_MULTI_A) { + char path[] = "io\0ea_multitap\0"; + tern_node *port_defs = tern_find_path(config, path, TVAL_NODE).ptrval; + debug_message("IO port %s connected to EA 4-way Play A-side\n", io_name(i)); + for (int j = 0; j < 4; j++) + { + char port_num[] = {'1' + j, 0, 0}; + char *dev_type = tern_find_ptr(port_defs, port_num); + process_device(dev_type, ports[i].device.multitap.ports + j); + debug_message("\tTap port %d connected to device '%s'\n", j + 1, device_type_names[ports[i].device.multitap.ports[j].device_type]); + io_control_write(ports[i].device.multitap.ports + j, 0x40, 0); + io_data_write(ports[i].device.multitap.ports + j, 0, 0); + } + } else if (ports[i].device_type == IO_EA_MULTI_B) { + debug_message("IO port %s connected to EA 4-way Play B-side\n", io_name(i)); + for (int j = 0; j < 3; j++) + { + if (ports[j].device_type == IO_EA_MULTI_A) { + ports[i].device.multitap.ports = ports + j; + break; + } + } } else { debug_message("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]); } @@ -1375,6 +1419,37 @@ } } break; + case IO_EA_MULTI_A: + if ((output & TH) != (old_output & TH)) { + uint8_t port_num = port->device.multitap.cur_port == EA_PASSTHRU_MODE ? 1 : port->device.multitap.cur_port; + if (port_num < 4) { + io_data_write(port->device.multitap.ports + port_num, output & 0x40, current_cycle); + } + } + break; + case IO_EA_MULTI_B: { + io_port *main_port = port->device.multitap.ports; + io_port *passthru = main_port->device.multitap.ports + 1; + if (main_port->device.multitap.cur_port == EA_PASSTHRU_MODE) { + output &= port->control | 0x40; + output |= io_data_read(passthru, current_cycle) & ~(port->control | 0x40); + } + uint8_t old_port = main_port->device.multitap.cur_port; + if ((output & 0xF) == 0xC) { + main_port->device.multitap.cur_port = output >> 4 & 7; + } else { + main_port->device.multitap.cur_port = EA_PASSTHRU_MODE; + } + if (old_port == EA_PASSTHRU_MODE && main_port->device.multitap.cur_port < 4) { + //switched from passthru to multitap mode, set TH for selected controller to port A value + output = get_output_value(main_port, current_cycle, SLOW_RISE_DEVICE); + io_data_write(main_port->device.multitap.ports + main_port->device.multitap.cur_port, output & 0x40, current_cycle); + } else if (main_port->device.multitap.cur_port == EA_PASSTHRU_MODE) { + //in passhtru mode, set TH to controller 2 to port B value + io_data_write(main_port->device.multitap.ports + 1, output & 0x40, current_cycle); + } + break; + } #ifndef _WIN32 case IO_GENERIC: wait_for_connection(port); @@ -1674,6 +1749,27 @@ device_driven = 0x1F; input = port->input[0]; break; + case IO_EA_MULTI_A: + device_driven = 0x3F; + if (port->device.multitap.cur_port == EA_PASSTHRU_MODE) { + input = io_data_read(port->device.multitap.ports, current_cycle); + } else if (port->device.multitap.cur_port < 4) { + input = io_data_read(port->device.multitap.ports + port->device.multitap.cur_port, current_cycle); + } else { + input = 0x3C; + } + break; + case IO_EA_MULTI_B: { + io_port *main_port = port->device.multitap.ports; + if (main_port->device.multitap.cur_port == EA_PASSTHRU_MODE) { + input = io_data_read(main_port->device.multitap.ports + 1, current_cycle); + device_driven = 0x3F; + } else { + input = 0; + device_driven = 0; + } + break; + } #ifndef _WIN32 case IO_SEGA_PARALLEL: if (!th) diff -r f82c090c1e89 -r 0a107b2d5837 nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Sat Sep 17 15:38:40 2022 -0700 +++ b/nuklear_ui/blastem_nuklear.c Sat Sep 17 18:29:24 2022 -0700 @@ -2059,6 +2059,7 @@ "gamepad3.1", "gamepad6.1", "sega_multitap.1", + "ea_multitap_port_a", "mouse.1", "saturn keyboard", "xband keyboard" @@ -2069,6 +2070,7 @@ "gamepad3.2", "gamepad6.2", "sega_multitap.1", + "ea_multitap_port_b", "mouse.1", "saturn keyboard", "xband keyboard" @@ -2083,9 +2085,10 @@ type_names[2] = device_type_names[IO_GAMEPAD3]; type_names[3] = device_type_names[IO_GAMEPAD6]; type_names[4] = device_type_names[IO_SEGA_MULTI]; - type_names[5] = device_type_names[IO_MOUSE]; - type_names[6] = device_type_names[IO_SATURN_KEYBOARD]; - type_names[7] = device_type_names[IO_XBAND_KEYBOARD]; + type_names[5] = device_type_names[IO_EA_MULTI_A]; + type_names[6] = device_type_names[IO_MOUSE]; + type_names[7] = device_type_names[IO_SATURN_KEYBOARD]; + type_names[8] = device_type_names[IO_XBAND_KEYBOARD]; if (show_sms) { selected_io_1 = find_match(io_opts_1, num_io, "sms\0io\0devices\0""1\0", "gamepad2.1"); selected_io_2 = find_match(io_opts_2, num_io, "sms\0io\0devices\0""2\0", "gamepad2.2"); @@ -2107,8 +2110,26 @@ } else { selected_model = settings_dropdown_ex(context, "Model", model_opts, model_names, num_models, selected_model, "system\0model\0"); } - selected_io_1 = settings_dropdown_ex(context, "IO Port 1 Device", io_opts_1, type_names, num_io, selected_io_1, show_sms ? "sms\0io\0devices\0""1\0" : "io\0devices\0""1\0"); - selected_io_2 = settings_dropdown_ex(context, "IO Port 2 Device", io_opts_2, type_names, num_io, selected_io_2, show_sms ? "sms\0io\0devices\0""2\0" : "io\0devices\0""2\0"); + int32_t old_selected = selected_io_1; + char *config_path1, *config_path2; + if (show_sms) { + config_path1 = "sms\0io\0devices\0""1\0"; + config_path2 = "sms\0io\0devices\0""2\0"; + } else { + config_path1 = "io\0devices\0""1\0"; + config_path2 = "io\0devices\0""2\0"; + } + selected_io_1 = settings_dropdown_ex(context, "IO Port 1 Device", io_opts_1, type_names, num_io, selected_io_1, config_path1); + if (old_selected != selected_io_1 && selected_io_1 != selected_io_2 && !strcmp(io_opts_1[selected_io_1], "ea_multitap_port_a")) { + selected_io_2 = selected_io_1; + config = tern_insert_path(config, config_path2, (tern_val){.ptrval = strdup(io_opts_2[selected_io_2])}, TVAL_PTR); + } + old_selected = selected_io_2; + selected_io_2 = settings_dropdown_ex(context, "IO Port 2 Device", io_opts_2, type_names, num_io, selected_io_2, config_path2); + if (old_selected != selected_io_2 && selected_io_1 != selected_io_2 && !strcmp(io_opts_2[selected_io_2], "ea_multitap_port_b")) { + selected_io_1 = selected_io_2; + config = tern_insert_path(config, config_path1, (tern_val){.ptrval = strdup(io_opts_1[selected_io_1])}, TVAL_PTR); + } selected_region = settings_dropdown_ex(context, "Default Region", region_codes, regions, num_regions, selected_region, "system\0default_region\0"); selected_sync = settings_dropdown(context, "Sync Source", sync_opts, num_sync_opts, selected_sync, "system\0sync_source\0"); if (!show_sms) {