From 8ef54202f9aefdee931d26ba558bae9dea518259 Mon Sep 17 00:00:00 2001 From: waltje Date: Sun, 1 Apr 2018 22:00:58 -0400 Subject: [PATCH] Another load of cleanups. Also, all filename handling is now Unicode. Fixes for many items on the bugs list. New logo and main icon for the project. --- src/cdrom/cdrom.c | 4 +- src/config.c | 228 +++------ src/crcspeed/crcspeed.c | 4 +- src/disk/hdc_esdi_at.c | 4 +- src/disk/hdc_esdi_mca.c | 6 +- src/disk/hdc_mfm_xt.c | 710 +++++++++++++------------- src/disk/hdc_xtide.c | 10 +- src/disk/hdd.h | 21 +- src/disk/hdd_image.c | 27 +- src/disk/hdd_table.c | 4 +- src/emu.h | 14 +- src/intel_flash.c | 6 +- src/machine/m_ps1.c | 8 +- src/machine/m_tandy.c | 11 +- src/machine/m_xt.c | 53 +- src/machine/m_xt_t1000.c | 21 +- src/machine/machine.c | 1 + src/machine/machine.h | 5 +- src/machine/machine_table.c | 16 +- src/mem.c | 6 +- src/mouse.c | 4 +- src/network/net_ne2000.c | 13 +- src/network/pcap_if.c | 2 +- src/nvr.c | 70 ++- src/nvr.h | 201 ++++---- src/nvr_ps2.c | 15 +- src/pc.c | 75 ++- src/plat.h | 5 +- src/rom.c | 52 +- src/rom.h | 6 +- src/rom_load.c | 106 ++-- src/scsi/scsi_aha154x.c | 406 +++++++-------- src/scsi/scsi_buslogic.c | 620 ++++++++++++---------- src/scsi/scsi_ncr5380.c | 10 +- src/sound/midi_fluidsynth.c | 22 +- src/sound/midi_fluidsynth.h | 5 +- src/sound/midi_mt32.c | 562 ++++++++++---------- src/sound/snd_adlibgold.c | 15 +- src/sound/snd_emu8k.c | 10 +- src/sound/snd_sb.c | 4 +- src/sound/sound.c | 15 +- src/sound/sound.h | 3 +- src/version.h | 5 +- src/video/vid_ati18800.c | 8 +- src/video/vid_ati28800.c | 14 +- src/video/vid_ati_eeprom.c | 26 +- src/video/vid_ati_mach64.c | 10 +- src/video/vid_cl54xx.c | 24 +- src/video/vid_ega.c | 12 +- src/video/vid_et4000.c | 4 +- src/video/vid_et4000w32.c | 6 +- src/video/vid_genius.c | 4 +- src/video/vid_oak_oti.c | 8 +- src/video/vid_paradise.c | 22 +- src/video/vid_s3.c | 26 +- src/video/vid_s3_virge.c | 18 +- src/video/vid_table.c | 8 +- src/video/vid_tgui9440.c | 10 +- src/video/vid_tvga.c | 6 +- src/video/vid_vga.c | 8 +- src/video/vid_voodoo.c | 20 +- src/video/video.c | 4 +- src/video/video.h | 4 +- src/win/VARCem.rc | 21 +- src/win/icons/.attic/amu_2.ico | Bin 0 -> 67646 bytes src/win/icons/.attic/chip-32x32.ico | Bin 0 -> 73070 bytes src/win/icons/.attic/chip2-32x32.ico | Bin 0 -> 126740 bytes src/win/icons/{ => .attic}/emu-rb.ico | Bin src/win/icons/{ => .attic}/emu.ico | Bin src/win/icons/varcem.ico | Bin 0 -> 36450 bytes src/win/mingw/Makefile.MinGW | 12 +- src/win/msvc/vc14/VARCem.vcxproj | 12 +- src/win/msvc/vc14/global.props | 2 +- src/win/msvc/vc15/VARCem.vcxproj | 6 +- src/win/msvc/vc15/global.props | 2 +- src/win/pcap_if.rc | 36 +- src/win/resource.h | 4 +- src/win/win.c | 143 +++--- src/win/win.h | 17 +- src/win/win_devconf.c | 507 +++++++++--------- src/win/win_dialog.c | 148 ++---- src/win/win_new_floppy.c | 4 +- src/win/win_settings.c | 46 +- src/win/win_stbar.c | 12 +- src/win/win_ui.c | 35 +- 85 files changed, 2353 insertions(+), 2281 deletions(-) create mode 100644 src/win/icons/.attic/amu_2.ico create mode 100644 src/win/icons/.attic/chip-32x32.ico create mode 100644 src/win/icons/.attic/chip2-32x32.ico rename src/win/icons/{ => .attic}/emu-rb.ico (100%) rename src/win/icons/{ => .attic}/emu.ico (100%) create mode 100644 src/win/icons/varcem.ico diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 134f614..87492f8 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.10 2018/03/21 + * Version: @(#)cdrom.c 1.0.11 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -2866,7 +2866,7 @@ uint8_t cdrom_phase_data_out(uint8_t id) switch(dev->current_cdb[0]) { case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: - f = nvr_fopen(L"modeselect.bin", L"wb"); + f = plat_fopen(nvr_path(L"modeselect.bin"), L"wb"); fwrite(cdbufferb, 1, dev->total_length, f); fclose(f); diff --git a/src/config.c b/src/config.c index 46b1059..dc9d979 100644 --- a/src/config.c +++ b/src/config.c @@ -12,7 +12,7 @@ * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. * - * Version: @(#)config.c 1.0.7 2018/03/20 + * Version: @(#)config.c 1.0.9 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -76,6 +76,9 @@ #include "ui.h" +#define ANSI_CFG 1 /* for now, always */ + + typedef struct _list_ { struct _list_ *next; } list_t; @@ -450,6 +453,7 @@ load_general(void) video_graytype = config_get_int(cat, "video_graytype", 0); rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); + update_icons = config_get_int(cat, "update_icons", 1); window_remember = config_get_int(cat, "window_remember", 0); @@ -492,20 +496,6 @@ load_machine(void) if (machine >= machine_count()) machine = machine_count() - 1; - /* This is for backwards compatibility. */ - p = config_get_string(cat, "model", NULL); - if (p != NULL) { - /* Detect the old model typos and fix them. */ - if (! strcmp(p, "p55r2p4")) { - machine = machine_get_machine_from_internal_name("p55t2p4"); - } else { - machine = machine_get_machine_from_internal_name(p); - } - config_delete_var(cat, "model"); - } - if (machine >= machine_count()) - machine = machine_count() - 1; - romset = machine_getromset(); cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); cpu = config_get_int(cat, "cpu", 0); @@ -523,9 +513,6 @@ load_machine(void) enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); enable_sync = !!config_get_int(cat, "enable_sync", 1); - - /* Remove this after a while.. */ - config_delete_var(cat, "nvr_path"); } @@ -542,6 +529,8 @@ load_video(void) vid_card = VID_INTERNAL; } else { p = config_get_string(cat, "video_card", NULL); + + /* Remove this after 01-JUL-2018. --FvK */ if (p == NULL) { p = config_get_string(cat, "gfxcard", NULL); if (p != NULL) @@ -614,7 +603,15 @@ load_sound(void) char temp[512]; char *p; - p = config_get_string(cat, "sndcard", NULL); + p = config_get_string(cat, "sound_card", NULL); + + /* Remove this after 01-JUL-2018. --FvK */ + if (p == NULL) { + p = config_get_string(cat, "sndcard", NULL); + if (p != NULL) + config_delete_var(cat, "sndcard"); + } + if (p != NULL) sound_card_current = sound_card_get_from_internal_name(p); else @@ -706,9 +703,9 @@ load_ports(void) char *cat = "Ports (COM & LPT)"; char *p; - serial_enabled[0] = !!config_get_int(cat, "serial1_enabled", 1); - serial_enabled[1] = !!config_get_int(cat, "serial2_enabled", 1); - lpt_enabled = !!config_get_int(cat, "lpt_enabled", 1); + serial_enabled[0] = !!config_get_int(cat, "serial1_enabled", 0); + serial_enabled[1] = !!config_get_int(cat, "serial2_enabled", 0); + lpt_enabled = !!config_get_int(cat, "lpt_enabled", 0); p = (char *)config_get_string(cat, "lpt1_device", NULL); if (p != NULL) @@ -738,7 +735,15 @@ load_other_peripherals(void) char temp[512], *p; int c; - p = config_get_string(cat, "scsicard", NULL); + p = config_get_string(cat, "scsi_card", NULL); + + /* Remove this after 01-JUL-2018. --FvK */ + if (p == NULL) { + p = config_get_string(cat, "scsicard", NULL); + if (p != NULL) + config_delete_var(cat, "scsicard"); + } + if (p != NULL) scsi_card_current = scsi_card_get_from_internal_name(p); else @@ -749,11 +754,6 @@ load_other_peripherals(void) hdc_name = NULL; } p = config_get_string(cat, "hdc", NULL); - if (p == NULL) { - p = config_get_string(cat, "hdd_controller", NULL); - if (p != NULL) - config_delete_var(cat, "hdd_controller"); - } if (p == NULL) { if (machines[machine].flags & MACHINE_HDC) { hdc_name = (char *) malloc((strlen("internal") + 1) * sizeof(char)); @@ -778,8 +778,8 @@ load_other_peripherals(void) } bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); -#ifdef WALTJE +#ifdef WALTJE romdos_enabled = !!config_get_int(cat, "romdos_enabled", 0); #endif } @@ -818,12 +818,12 @@ load_hard_disks(void) sprintf(temp, "hdd_%02i_parameters", c+1); p = config_get_string(cat, temp, "0, 0, 0, 0, none"); if (tally_char(p, ',') == 3) { - sscanf(p, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %s", - &hdd[c].spt, &hdd[c].hpc, &hdd[c].tracks, s); + sscanf(p, "%u, %u, %u, %s", + (int *)&hdd[c].spt, (int *)&hdd[c].hpc, (int *)&hdd[c].tracks, s); hdd[c].wp = 0; } else { - sscanf(p, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %i, %s", - &hdd[c].spt, &hdd[c].hpc, &hdd[c].tracks, (int *)&hdd[c].wp, s); + sscanf(p, "%u, %u, %u, %d, %s", + (int *)&hdd[c].spt, (int *)&hdd[c].hpc, (int *)&hdd[c].tracks, (int *)&hdd[c].wp, s); } hdd[c].bus = hdd_string_to_bus(s, 0); @@ -935,24 +935,8 @@ load_hard_disks(void) sprintf(temp, "hdd_%02i_fn", c+1); wp = config_get_wstring(cat, temp, L""); -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the CFG path. Just strip - * that off for now... - */ - wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); - } else -#endif - wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); + /* Try to make relative, and copy to destination. */ + pc_path(hdd[c].fn, sizeof_w(hdd[c].fn), wp); /* If disk is empty or invalid, mark it for deletion. */ if (! hdd_is_valid(c)) { @@ -1005,24 +989,8 @@ load_removable_devices(void) sprintf(temp, "fdd_%02i_fn", c + 1); wp = config_get_wstring(cat, temp, L""); -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); - } else -#endif - wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); + /* Try to make relative, and copy to destination. */ + pc_path(floppyfns[c], sizeof_w(floppyfns[c]), wp); sprintf(temp, "fdd_%02i_writeprot", c+1); ui_writeprot[c] = !!config_get_int(cat, temp, 0); @@ -1104,24 +1072,8 @@ load_removable_devices(void) sprintf(temp, "cdrom_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); - } else -#endif - wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + /* Try to make relative, and copy to destination. */ + pc_path(cdrom_image[c].image_path, sizeof_w(cdrom_image[c].image_path), wp); if (cdrom_drives[c].host_drive < 'A') cdrom_drives[c].host_drive = 0; @@ -1173,24 +1125,8 @@ load_floppy_drives(void) sprintf(temp, "fdd_%02i_fn", c + 1); wp = config_get_wstring(cat, temp, L""); -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); - } else -#endif - wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); + /* Try to make relative, and copy to destination. */ + pc_path(floppyfns[c], sizeof_w(floppyfns[c]), wp); sprintf(temp, "fdd_%02i_writeprot", c+1); ui_writeprot[c] = !!config_get_int(cat, temp, 0); @@ -1294,24 +1230,8 @@ load_other_removable_devices(void) sprintf(temp, "cdrom_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); - } else -#endif - wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + /* Try to make relative, and copy to destination. */ + pc_path(cdrom_image[c].image_path, sizeof_w(cdrom_image[c].image_path), wp); if (cdrom_drives[c].host_drive < 'A') cdrom_drives[c].host_drive = 0; @@ -1394,24 +1314,8 @@ load_other_removable_devices(void) sprintf(temp, "zip_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); - } else -#endif - wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); + /* Try to make relative, and copy to destination. */ + pc_path(zip_drives[c].image_path, sizeof_w(zip_drives[c].image_path), wp); /* If the CD-ROM is disabled, delete all its variables. */ if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { @@ -1719,9 +1623,9 @@ save_sound(void) char *cat = "Sound"; if (sound_card_current == 0) - config_delete_var(cat, "sndcard"); + config_delete_var(cat, "sound_card"); else - config_set_string(cat, "sndcard", sound_card_get_internal_name(sound_card_current)); + config_set_string(cat, "sound_card", sound_card_get_internal_name(sound_card_current)); if (!strcmp(midi_device_get_internal_name(midi_device_current), "none")) config_delete_var(cat, "midi_device"); @@ -1800,34 +1704,34 @@ save_ports(void) char *cat = "Ports (COM & LPT)"; if (serial_enabled[0]) - config_delete_var(cat, "serial1_enabled"); - else config_set_int(cat, "serial1_enabled", serial_enabled[0]); + else + config_delete_var(cat, "serial1_enabled"); if (serial_enabled[1]) - config_delete_var(cat, "serial2_enabled"); - else config_set_int(cat, "serial2_enabled", serial_enabled[1]); + else + config_delete_var(cat, "serial2_enabled"); if (lpt_enabled) - config_delete_var(cat, "lpt_enabled"); - else config_set_int(cat, "lpt_enabled", lpt_enabled); - - if (!strcmp(lpt_device_names[0], "none")) - config_delete_var(cat, "lpt1_device"); else + config_delete_var(cat, "lpt_enabled"); + + if (strcmp(lpt_device_names[0], "none")) config_set_string(cat, "lpt1_device", lpt_device_names[0]); - - if (!strcmp(lpt_device_names[1], "none")) - config_delete_var(cat, "lpt2_device"); else + config_delete_var(cat, "lpt1_device"); + + if (strcmp(lpt_device_names[1], "none")) config_set_string(cat, "lpt2_device", lpt_device_names[1]); - - if (!strcmp(lpt_device_names[2], "none")) - config_delete_var(cat, "lpt3_device"); else + config_delete_var(cat, "lpt2_device"); + + if (strcmp(lpt_device_names[2], "none")) config_set_string(cat, "lpt3_device", lpt_device_names[2]); + else + config_delete_var(cat, "lpt3_device"); delete_section_if_empty(cat); } @@ -1842,9 +1746,9 @@ save_other_peripherals(void) int c; if (scsi_card_current == 0) - config_delete_var(cat, "scsicard"); + config_delete_var(cat, "scsi_card"); else - config_set_string(cat, "scsicard", + config_set_string(cat, "scsi_card", scsi_card_get_internal_name(scsi_card_current)); config_set_string(cat, "hdc", hdc_name); @@ -1882,7 +1786,7 @@ save_hard_disks(void) sprintf(temp, "hdd_%02i_parameters", c+1); if (hdd_is_valid(c)) { p = hdd_bus_to_string(hdd[c].bus, 0); - sprintf(tmp2, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %i, %s", + sprintf(tmp2, "%u, %u, %u, %d, %s", hdd[c].spt, hdd[c].hpc, hdd[c].tracks, hdd[c].wp, p); config_set_string(cat, temp, tmp2); } else { @@ -2105,7 +2009,7 @@ config_save(void) save_other_removable_devices(); /* Other removable devices */ /* Not if we are running readonly! */ - if (config_ro) + if (! config_ro) config_write(cfg_path); } diff --git a/src/crcspeed/crcspeed.c b/src/crcspeed/crcspeed.c index d2d97a8..ecb58f4 100644 --- a/src/crcspeed/crcspeed.c +++ b/src/crcspeed/crcspeed.c @@ -98,7 +98,7 @@ void crcspeed16big_init(crcfn16 fn, uint16_t big_table[8][256]) { crcspeed16little_init(fn, big_table); for (int k = 0; k < 8; k++) { for (int n = 0; n < 256; n++) { - big_table[k][n] = rev8(big_table[k][n]); + big_table[k][n] = (uint16_t)rev8(big_table[k][n]); } } } @@ -242,7 +242,7 @@ uint16_t crcspeed16big(uint16_t big_table[8][256], uint16_t crc_in, void *buf, len--; } - return rev8(crc); + return (uint16_t)rev8(crc); } /* Return the CRC of buf[0..len-1] with initial crc, processing eight bytes diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index b31a934..13e22b6 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -8,7 +8,7 @@ * * Driver for the ESDI controller (WD1007-vse1) for PC/AT. * - * Version: @(#)hdc_esdi_at.c 1.0.4 2018/03/27 + * Version: @(#)hdc_esdi_at.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -60,7 +60,7 @@ #define HDC_TIME (TIMER_USEC*10LL) -#define ESDI_BIOS_FILE L"roms/hdd/esdi_at/62-000279-061.bin" +#define ESDI_BIOS_FILE L"hdd/esdi_at/62-000279-061.bin" #define STAT_ERR 0x01 #define STAT_INDEX 0x02 diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index 1aad2fc..a0331b4 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -52,7 +52,7 @@ * however, are auto-configured by the system software as * shown above. * - * Version: @(#)hdc_esdi_mca.c 1.0.3 2018/03/27 + * Version: @(#)hdc_esdi_mca.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -102,8 +102,8 @@ #define ESDI_IOADDR_SEC 0x3518 #define ESDI_IRQCHAN 14 -#define BIOS_FILE_L L"roms/hdd/esdi/90x8969.bin" -#define BIOS_FILE_H L"roms/hdd/esdi/90x8970.bin" +#define BIOS_FILE_L L"hdd/esdi/90x8969.bin" +#define BIOS_FILE_H L"hdd/esdi/90x8970.bin" #define ESDI_TIME (200LL*TIMER_USEC) diff --git a/src/disk/hdc_mfm_xt.c b/src/disk/hdc_mfm_xt.c index 2478f87..1035c88 100644 --- a/src/disk/hdc_mfm_xt.c +++ b/src/disk/hdc_mfm_xt.c @@ -41,7 +41,7 @@ * Since all controllers (including the ones made by DTC) use * (mostly) the same API, we keep them all in this module. * - * Version: @(#)hdc_mfm_xt.c 1.0.3 2018/03/27 + * Version: @(#)hdc_mfm_xt.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -90,8 +90,8 @@ #define MFM_TIME (2000LL*TIMER_USEC) -#define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin" -#define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin" +#define XEBEC_BIOS_FILE L"hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin" +#define DTC_BIOS_FILE L"hdd/mfm_xebec/dtc_cxd21a.bin" enum { @@ -108,34 +108,38 @@ enum { typedef struct { - int spt, hpc; - int tracks; - int cfg_spt; - int cfg_hpc; - int cfg_cyl; - int current_cylinder; - int present; - int hdd_num; + int spt, + hpc; + int tracks; + int cfg_spt; + int cfg_hpc; + int cfg_cyl; + int current_cylinder; + int present; + int hdd_num; } drive_t; typedef struct { - rom_t bios_rom; - int64_t callback; - int state; - uint8_t status; - uint8_t command[6]; - int command_pos; - uint8_t data[512]; - int data_pos, data_len; - uint8_t sector_buf[512]; - uint8_t irq_dma_mask; - uint8_t completion_byte; - uint8_t error; - int drive_sel; - drive_t drives[2]; - int sector, head, cylinder; - int sector_count; - uint8_t switches; + rom_t bios_rom; + int64_t callback; + int state; + uint8_t status; + uint8_t command[6]; + int command_pos; + uint8_t data[512]; + int data_pos, + data_len; + uint8_t sector_buf[512]; + uint8_t irq_dma_mask; + uint8_t completion_byte; + uint8_t error; + int drive_sel; + drive_t drives[2]; + int sector, + head, + cylinder; + int sector_count; + uint8_t switches; } mfm_t; #define STAT_IRQ 0x20 @@ -173,46 +177,46 @@ typedef struct { static uint8_t mfm_read(uint16_t port, void *priv) { - mfm_t *mfm = (mfm_t *)priv; + mfm_t *dev = (mfm_t *)priv; uint8_t temp = 0xff; switch (port) { case 0x320: /*Read data*/ - mfm->status &= ~STAT_IRQ; - switch (mfm->state) { + dev->status &= ~STAT_IRQ; + switch (dev->state) { case STATE_COMPLETION_BYTE: - if ((mfm->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); + if ((dev->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", dev->status); - temp = mfm->completion_byte; - mfm->status = 0; - mfm->state = STATE_IDLE; + temp = dev->completion_byte; + dev->status = 0; + dev->state = STATE_IDLE; break; case STATE_SEND_DATA: - if ((mfm->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); - if (mfm->data_pos >= mfm->data_len) + if ((dev->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", dev->status); + if (dev->data_pos >= dev->data_len) fatal("Data write with full data!\n"); - temp = mfm->data[mfm->data_pos++]; - if (mfm->data_pos == mfm->data_len) { - mfm->status = STAT_BSY; - mfm->state = STATE_SENT_DATA; - mfm->callback = MFM_TIME; + temp = dev->data[dev->data_pos++]; + if (dev->data_pos == dev->data_len) { + dev->status = STAT_BSY; + dev->state = STATE_SENT_DATA; + dev->callback = MFM_TIME; } break; default: - fatal("Read data register - %i, %02x\n", mfm->state, mfm->status); + fatal("Read data register - %i, %02x\n", dev->state, dev->status); } break; case 0x321: /*Read status*/ - temp = mfm->status; + temp = dev->status; break; case 0x322: /*Read option jumpers*/ - temp = mfm->switches; + temp = dev->switches; break; } @@ -223,129 +227,130 @@ mfm_read(uint16_t port, void *priv) static void mfm_write(uint16_t port, uint8_t val, void *priv) { - mfm_t *mfm = (mfm_t *)priv; + mfm_t *dev = (mfm_t *)priv; switch (port) { case 0x320: /*Write data*/ - switch (mfm->state) { + switch (dev->state) { case STATE_RECEIVE_COMMAND: - if ((mfm->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) - fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", mfm->status); - if (mfm->command_pos >= 6) + if ((dev->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) + fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", dev->status); + if (dev->command_pos >= 6) fatal("Command write with full command!\n"); /*Command data*/ - mfm->command[mfm->command_pos++] = val; - if (mfm->command_pos == 6) { - mfm->status = STAT_BSY; - mfm->state = STATE_START_COMMAND; - mfm->callback = MFM_TIME; + dev->command[dev->command_pos++] = val; + if (dev->command_pos == 6) { + dev->status = STAT_BSY; + dev->state = STATE_START_COMMAND; + dev->callback = MFM_TIME; } break; case STATE_RECEIVE_DATA: - if ((mfm->status & 0xf) != (STAT_BSY | STAT_REQ)) - fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", mfm->status); - if (mfm->data_pos >= mfm->data_len) + if ((dev->status & 0xf) != (STAT_BSY | STAT_REQ)) + fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", dev->status); + if (dev->data_pos >= dev->data_len) fatal("Data write with full data!\n"); /*Command data*/ - mfm->data[mfm->data_pos++] = val; - if (mfm->data_pos == mfm->data_len) { - mfm->status = STAT_BSY; - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; + dev->data[dev->data_pos++] = val; + if (dev->data_pos == dev->data_len) { + dev->status = STAT_BSY; + dev->state = STATE_RECEIVED_DATA; + dev->callback = MFM_TIME; } break; default: - fatal("Write data unknown state - %i %02x\n", mfm->state, mfm->status); + fatal("Write data unknown state - %i %02x\n", dev->state, dev->status); } break; case 0x321: /*Controller reset*/ - mfm->status = 0; + dev->status = 0; break; case 0x322: /*Generate controller-select-pulse*/ - mfm->status = STAT_BSY | STAT_CD | STAT_REQ; - mfm->command_pos = 0; - mfm->state = STATE_RECEIVE_COMMAND; + dev->status = STAT_BSY | STAT_CD | STAT_REQ; + dev->command_pos = 0; + dev->state = STATE_RECEIVE_COMMAND; break; case 0x323: /*DMA/IRQ mask register*/ - mfm->irq_dma_mask = val; + dev->irq_dma_mask = val; break; } } -static void mfm_complete(mfm_t *mfm) +static void +mfm_complete(mfm_t *dev) { - mfm->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; - mfm->state = STATE_COMPLETION_BYTE; + dev->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; + dev->state = STATE_COMPLETION_BYTE; - if (mfm->irq_dma_mask & IRQ_ENA) { - mfm->status |= STAT_IRQ; + if (dev->irq_dma_mask & IRQ_ENA) { + dev->status |= STAT_IRQ; picint(1 << 5); } } static void -mfm_error(mfm_t *mfm, uint8_t error) +mfm_error(mfm_t *dev, uint8_t error) { - mfm->completion_byte |= 0x02; - mfm->error = error; + dev->completion_byte |= 0x02; + dev->error = error; - pclog("mfm_error - %02x\n", mfm->error); + pclog("mfm_error - %02x\n", dev->error); } static int -get_sector(mfm_t *mfm, off64_t *addr) +get_sector(mfm_t *dev, off64_t *addr) { - drive_t *drive = &mfm->drives[mfm->drive_sel]; + drive_t *drive = &dev->drives[dev->drive_sel]; int heads = drive->cfg_hpc; - if (drive->current_cylinder != mfm->cylinder) { + if (drive->current_cylinder != dev->cylinder) { pclog("mfm_get_sector: wrong cylinder\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + dev->error = ERR_ILLEGAL_SECTOR_ADDRESS; return(1); } - if (mfm->head > heads) { + if (dev->head > heads) { pclog("mfm_get_sector: past end of configured heads\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + dev->error = ERR_ILLEGAL_SECTOR_ADDRESS; return(1); } - if (mfm->head > drive->hpc) { + if (dev->head > drive->hpc) { pclog("mfm_get_sector: past end of heads\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + dev->error = ERR_ILLEGAL_SECTOR_ADDRESS; return(1); } - if (mfm->sector >= 17) { + if (dev->sector >= 17) { pclog("mfm_get_sector: past end of sectors\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + dev->error = ERR_ILLEGAL_SECTOR_ADDRESS; return(1); } - *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * - 17) + mfm->sector; + *addr = ((((off64_t) dev->cylinder * heads) + dev->head) * + 17) + dev->sector; return(0); } static void -next_sector(mfm_t *mfm) +next_sector(mfm_t *dev) { - drive_t *drive = &mfm->drives[mfm->drive_sel]; + drive_t *drive = &dev->drives[dev->drive_sel]; - mfm->sector++; - if (mfm->sector >= 17) { - mfm->sector = 0; - mfm->head++; - if (mfm->head >= drive->cfg_hpc) { - mfm->head = 0; - mfm->cylinder++; + dev->sector++; + if (dev->sector >= 17) { + dev->sector = 0; + dev->head++; + if (dev->head >= drive->cfg_hpc) { + dev->head = 0; + dev->cylinder++; drive->current_cylinder++; if (drive->current_cylinder >= drive->cfg_cyl) drive->current_cylinder = drive->cfg_cyl-1; @@ -357,423 +362,422 @@ next_sector(mfm_t *mfm) static void mfm_callback(void *priv) { - mfm_t *mfm = (mfm_t *)priv; + mfm_t *dev = (mfm_t *)priv; drive_t *drive; off64_t addr; - mfm->callback = 0LL; + dev->callback = 0LL; - mfm->drive_sel = (mfm->command[1] & 0x20) ? 1 : 0; - mfm->completion_byte = mfm->drive_sel & 0x20; - drive = &mfm->drives[mfm->drive_sel]; + dev->drive_sel = (dev->command[1] & 0x20) ? 1 : 0; + dev->completion_byte = dev->drive_sel & 0x20; + drive = &dev->drives[dev->drive_sel]; - switch (mfm->command[0]) { + switch (dev->command[0]) { case CMD_TEST_DRIVE_READY: if (!drive->present) - mfm_error(mfm, ERR_NOT_READY); - mfm_complete(mfm); + mfm_error(dev, ERR_NOT_READY); + mfm_complete(dev); break; case CMD_RECALIBRATE: if (!drive->present) - mfm_error(mfm, ERR_NOT_READY); + mfm_error(dev, ERR_NOT_READY); else { - mfm->cylinder = 0; + dev->cylinder = 0; drive->current_cylinder = 0; } - mfm_complete(mfm); + mfm_complete(dev); break; case CMD_READ_STATUS: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 4; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - mfm->data[0] = mfm->error; - mfm->data[1] = mfm->drive_sel ? 0x20 : 0; - mfm->data[2] = mfm->data[3] = 0; - mfm->error = 0; + dev->state = STATE_SEND_DATA; + dev->data_pos = 0; + dev->data_len = 4; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->data[0] = dev->error; + dev->data[1] = dev->drive_sel ? 0x20 : 0; + dev->data[2] = dev->data[3] = 0; + dev->error = 0; break; case STATE_SENT_DATA: - mfm_complete(mfm); + mfm_complete(dev); break; } break; case CMD_VERIFY_SECTORS: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; + dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); + drive->current_cylinder = (dev->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : dev->cylinder; + dev->head = dev->command[1] & 0x1f; + dev->sector = dev->command[2] & 0x1f; + dev->sector_count = dev->command[4]; do { - if (get_sector(mfm, &addr)) { + if (get_sector(dev, &addr)) { pclog("get_sector failed\n"); - mfm_error(mfm, mfm->error); - mfm_complete(mfm); + mfm_error(dev, dev->error); + mfm_complete(dev); return; } - next_sector(mfm); + next_sector(dev); - mfm->sector_count = (mfm->sector_count-1) & 0xff; - } while (mfm->sector_count); + dev->sector_count = (dev->sector_count-1) & 0xff; + } while (dev->sector_count); - mfm_complete(mfm); + mfm_complete(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); break; default: - fatal("CMD_VERIFY_SECTORS: bad state %i\n", mfm->state); + fatal("CMD_VERIFY_SECTORS: bad state %i\n", dev->state); } break; case CMD_FORMAT_TRACK: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; + dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); + drive->current_cylinder = (dev->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : dev->cylinder; + dev->head = dev->command[1] & 0x1f; - if (get_sector(mfm, &addr)) { + if (get_sector(dev, &addr)) { pclog("get_sector failed\n"); - mfm_error(mfm, mfm->error); - mfm_complete(mfm); + mfm_error(dev, dev->error); + mfm_complete(dev); return; } hdd_image_zero(drive->hdd_num, addr, 17); - mfm_complete(mfm); + mfm_complete(dev); break; case CMD_READ_SECTORS: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; + dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); + drive->current_cylinder = (dev->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : dev->cylinder; + dev->head = dev->command[1] & 0x1f; + dev->sector = dev->command[2] & 0x1f; + dev->sector_count = dev->command[4]; + dev->state = STATE_SEND_DATA; + dev->data_pos = 0; + dev->data_len = 512; - if (get_sector(mfm, &addr)) { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); + if (get_sector(dev, &addr)) { + mfm_error(dev, dev->error); + mfm_complete(dev); return; } hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); + (uint8_t *) dev->sector_buf); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; + if (dev->irq_dma_mask & DMA_ENA) + dev->callback = MFM_TIME; else { - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memcpy(mfm->data, mfm->sector_buf, 512); + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + memcpy(dev->data, dev->sector_buf, 512); } break; case STATE_SEND_DATA: - mfm->status = STAT_BSY; - if (mfm->irq_dma_mask & DMA_ENA) { - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_write(3, mfm->sector_buf[mfm->data_pos]); + dev->status = STAT_BSY; + if (dev->irq_dma_mask & DMA_ENA) { + for (; dev->data_pos < 512; dev->data_pos++) { + int val = dma_channel_write(3, dev->sector_buf[dev->data_pos]); if (val == DMA_NODATA) { pclog("CMD_READ_SECTORS out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; + dev->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + dev->callback = MFM_TIME; return; } } - mfm->state = STATE_SENT_DATA; - mfm->callback = MFM_TIME; + dev->state = STATE_SENT_DATA; + dev->callback = MFM_TIME; } else fatal("Read sectors no DMA! - shouldn't get here\n"); break; case STATE_SENT_DATA: - next_sector(mfm); + next_sector(dev); - mfm->data_pos = 0; + dev->data_pos = 0; - mfm->sector_count = (mfm->sector_count-1) & 0xff; + dev->sector_count = (dev->sector_count-1) & 0xff; - if (mfm->sector_count) { - if (get_sector(mfm, &addr)) { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); + if (dev->sector_count) { + if (get_sector(dev, &addr)) { + mfm_error(dev, dev->error); + mfm_complete(dev); return; } hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); + (uint8_t *) dev->sector_buf); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - mfm->state = STATE_SEND_DATA; + dev->state = STATE_SEND_DATA; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; + if (dev->irq_dma_mask & DMA_ENA) + dev->callback = MFM_TIME; else { - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memcpy(mfm->data, mfm->sector_buf, 512); + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + memcpy(dev->data, dev->sector_buf, 512); } } else { - mfm_complete(mfm); + mfm_complete(dev); ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); } break; default: - fatal("CMD_READ_SECTORS: bad state %i\n", mfm->state); + fatal("CMD_READ_SECTORS: bad state %i\n", dev->state); } break; case CMD_WRITE_SECTORS: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; + dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); + drive->current_cylinder = (dev->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : dev->cylinder; + dev->head = dev->command[1] & 0x1f; + dev->sector = dev->command[2] & 0x1f; + dev->sector_count = dev->command[4]; + dev->state = STATE_RECEIVE_DATA; + dev->data_pos = 0; + dev->data_len = 512; + if (dev->irq_dma_mask & DMA_ENA) + dev->callback = MFM_TIME; else - mfm->status = STAT_BSY | STAT_REQ; + dev->status = STAT_BSY | STAT_REQ; break; case STATE_RECEIVE_DATA: - mfm->status = STAT_BSY; - if (mfm->irq_dma_mask & DMA_ENA) { - for (; mfm->data_pos < 512; mfm->data_pos++) { + dev->status = STAT_BSY; + if (dev->irq_dma_mask & DMA_ENA) { + for (; dev->data_pos < 512; dev->data_pos++) { int val = dma_channel_read(3); if (val == DMA_NODATA) { pclog("CMD_WRITE_SECTORS out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; + dev->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + dev->callback = MFM_TIME; return; } - mfm->sector_buf[mfm->data_pos] = val & 0xff; + dev->sector_buf[dev->data_pos] = val & 0xff; } - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; + dev->state = STATE_RECEIVED_DATA; + dev->callback = MFM_TIME; } else fatal("Write sectors no DMA! - should never get here\n"); break; case STATE_RECEIVED_DATA: - if (! (mfm->irq_dma_mask & DMA_ENA)) - memcpy(mfm->sector_buf, mfm->data, 512); + if (! (dev->irq_dma_mask & DMA_ENA)) + memcpy(dev->sector_buf, dev->data, 512); - if (get_sector(mfm, &addr)) - { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); + if (get_sector(dev, &addr)) { + mfm_error(dev, dev->error); + mfm_complete(dev); return; } hdd_image_write(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); + (uint8_t *) dev->sector_buf); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - next_sector(mfm); - mfm->data_pos = 0; - mfm->sector_count = (mfm->sector_count-1) & 0xff; + next_sector(dev); + dev->data_pos = 0; + dev->sector_count = (dev->sector_count-1) & 0xff; - if (mfm->sector_count) { - mfm->state = STATE_RECEIVE_DATA; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; + if (dev->sector_count) { + dev->state = STATE_RECEIVE_DATA; + if (dev->irq_dma_mask & DMA_ENA) + dev->callback = MFM_TIME; else - mfm->status = STAT_BSY | STAT_REQ; + dev->status = STAT_BSY | STAT_REQ; } else - mfm_complete(mfm); + mfm_complete(dev); break; default: - fatal("CMD_WRITE_SECTORS: bad state %i\n", mfm->state); + fatal("CMD_WRITE_SECTORS: bad state %i\n", dev->state); } break; case CMD_SEEK: if (! drive->present) - mfm_error(mfm, ERR_NOT_READY); + mfm_error(dev, ERR_NOT_READY); else { - int cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); + int cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); drive->current_cylinder = (cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : cylinder; if (cylinder != drive->current_cylinder) - mfm_error(mfm, ERR_SEEK_ERROR); + mfm_error(dev, ERR_SEEK_ERROR); } - mfm_complete(mfm); + mfm_complete(dev); break; case CMD_INIT_DRIVE_PARAMS: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 8; - mfm->status = STAT_BSY | STAT_REQ; + dev->state = STATE_RECEIVE_DATA; + dev->data_pos = 0; + dev->data_len = 8; + dev->status = STAT_BSY | STAT_REQ; break; case STATE_RECEIVED_DATA: - drive->cfg_cyl = mfm->data[1] | (mfm->data[0] << 8); - drive->cfg_hpc = mfm->data[2]; - pclog("Drive %i: cylinders=%i, heads=%i\n", mfm->drive_sel, drive->cfg_cyl, drive->cfg_hpc); - mfm_complete(mfm); + drive->cfg_cyl = dev->data[1] | (dev->data[0] << 8); + drive->cfg_hpc = dev->data[2]; + pclog("Drive %i: cylinders=%i, heads=%i\n", dev->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + mfm_complete(dev); break; default: - fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", dev->state); } break; case CMD_WRITE_SECTOR_BUFFER: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; + dev->state = STATE_RECEIVE_DATA; + dev->data_pos = 0; + dev->data_len = 512; + if (dev->irq_dma_mask & DMA_ENA) + dev->callback = MFM_TIME; else - mfm->status = STAT_BSY | STAT_REQ; + dev->status = STAT_BSY | STAT_REQ; break; case STATE_RECEIVE_DATA: - if (mfm->irq_dma_mask & DMA_ENA) { - mfm->status = STAT_BSY; + if (dev->irq_dma_mask & DMA_ENA) { + dev->status = STAT_BSY; - for (; mfm->data_pos < 512; mfm->data_pos++) { + for (; dev->data_pos < 512; dev->data_pos++) { int val = dma_channel_read(3); if (val == DMA_NODATA) { pclog("CMD_WRITE_SECTOR_BUFFER out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; + dev->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + dev->callback = MFM_TIME; return; } - mfm->data[mfm->data_pos] = val & 0xff; + dev->data[dev->data_pos] = val & 0xff; } - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; + dev->state = STATE_RECEIVED_DATA; + dev->callback = MFM_TIME; } else fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n"); break; case STATE_RECEIVED_DATA: - memcpy(mfm->sector_buf, mfm->data, 512); - mfm_complete(mfm); + memcpy(dev->sector_buf, dev->data, 512); + mfm_complete(dev); break; default: - fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", mfm->state); + fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", dev->state); } break; case CMD_BUFFER_DIAGNOSTIC: case CMD_CONTROLLER_DIAGNOSTIC: - mfm_complete(mfm); + mfm_complete(dev); break; case 0xfa: - mfm_complete(mfm); + mfm_complete(dev); break; case CMD_DTC_SET_STEP_RATE: - mfm_complete(mfm); + mfm_complete(dev); break; case CMD_DTC_GET_DRIVE_PARAMS: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 4; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memset(mfm->data, 0, 4); - mfm->data[0] = drive->tracks & 0xff; - mfm->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); - mfm->data[2] = drive->hpc-1; - pclog("Get drive params %02x %02x %02x %i\n", mfm->data[0], mfm->data[1], mfm->data[2], drive->tracks); + dev->state = STATE_SEND_DATA; + dev->data_pos = 0; + dev->data_len = 4; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + memset(dev->data, 0, 4); + dev->data[0] = drive->tracks & 0xff; + dev->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); + dev->data[2] = drive->hpc-1; + pclog("Get drive params %02x %02x %02x %i\n", dev->data[0], dev->data[1], dev->data[2], drive->tracks); break; case STATE_SENT_DATA: - mfm_complete(mfm); + mfm_complete(dev); break; default: - fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", dev->state); } break; case CMD_DTC_GET_GEOMETRY: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 16; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memset(mfm->data, 0, 16); - mfm->data[0x4] = drive->tracks & 0xff; - mfm->data[0x5] = (drive->tracks >> 8) & 0xff; - mfm->data[0xa] = drive->hpc; + dev->state = STATE_SEND_DATA; + dev->data_pos = 0; + dev->data_len = 16; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + memset(dev->data, 0, 16); + dev->data[0x4] = drive->tracks & 0xff; + dev->data[0x5] = (drive->tracks >> 8) & 0xff; + dev->data[0xa] = drive->hpc; break; case STATE_SENT_DATA: - mfm_complete(mfm); + mfm_complete(dev); break; } break; case CMD_DTC_SET_GEOMETRY: - switch (mfm->state) { + switch (dev->state) { case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 16; - mfm->status = STAT_BSY | STAT_REQ; + dev->state = STATE_RECEIVE_DATA; + dev->data_pos = 0; + dev->data_len = 16; + dev->status = STAT_BSY | STAT_REQ; break; case STATE_RECEIVED_DATA: /*Bit of a cheat here - we always report the actual geometry of the drive in use*/ - mfm_complete(mfm); + mfm_complete(dev); break; } break; default: fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n", - mfm->command[0], mfm->command[1], - mfm->command[2], mfm->command[3], - mfm->command[4], mfm->command[5]); + dev->command[0], dev->command[1], + dev->command[2], dev->command[3], + dev->command[4], dev->command[5]); } } static void -loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) +loadhd(mfm_t *dev, int c, int d, const wchar_t *fn) { - drive_t *drive = &mfm->drives[d]; + drive_t *drive = &dev->drives[d]; if (! hdd_image_load(d)) { drive->present = 0; @@ -782,14 +786,15 @@ loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) drive->spt = (uint8_t)hdd[c].spt; drive->hpc = (uint8_t)hdd[c].hpc; - drive->tracks = (uint8_t)hdd[c].tracks; + drive->tracks = (uint16_t)hdd[c].tracks; drive->hdd_num = c; drive->present = 1; } -static struct { - int tracks, hpc; +static const struct { + uint16_t tracks; + uint8_t hpc; } hd_types[4] = { { 306, 4 }, /* Type 0 */ { 612, 4 }, /* Type 16 */ @@ -799,14 +804,14 @@ static struct { static void -mfm_set_switches(mfm_t *mfm) +mfm_set_switches(mfm_t *dev) { int c, d; - mfm->switches = 0; + dev->switches = 0; for (d=0; d<2; d++) { - drive_t *drive = &mfm->drives[d]; + drive_t *drive = &dev->drives[d]; if (! drive->present) continue; @@ -814,118 +819,88 @@ mfm_set_switches(mfm_t *mfm) if (drive->spt == 17 && drive->hpc == hd_types[c].hpc && drive->tracks == hd_types[c].tracks) { - mfm->switches |= (c << (d ? 0 : 2)); + dev->switches |= (c << (d ? 0 : 2)); break; } } if (c == 4) - pclog("WARNING: Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C'); + pclog("WARNING: drive %d has unsupported format %d/%d/%d !\n", + d, drive->tracks, drive->hpc, drive->spt); } } static void * -xebec_init(const device_t *info) +mfm_init(const device_t *info) { - int i, c = 0; + wchar_t *fn = NULL; + mfm_t *dev; + int i, c; - mfm_t *xebec = malloc(sizeof(mfm_t)); - memset(xebec, 0x00, sizeof(mfm_t)); + dev = malloc(sizeof(mfm_t)); + memset(dev, 0x00, sizeof(mfm_t)); pclog("MFM: looking for disks..\n"); + c = 0; for (i=0; i MFM_NUM) break; } } pclog("MFM: %d disks loaded.\n", c); - mfm_set_switches(xebec); + switch(info->local) { + case 0: /* Xebec */ + fn = XEBEC_BIOS_FILE; + mfm_set_switches(dev); + break; - rom_init(&xebec->bios_rom, XEBEC_BIOS_FILE, + case 1: /* DTC5150 */ + fn = DTC_BIOS_FILE; + dev->switches = 0xff; + dev->drives[0].cfg_cyl = dev->drives[0].tracks; + dev->drives[0].cfg_hpc = dev->drives[0].hpc; + dev->drives[1].cfg_cyl = dev->drives[1].tracks; + dev->drives[1].cfg_hpc = dev->drives[1].hpc; + break; + } + + rom_init(&dev->bios_rom, fn, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - + io_sethandler(0x0320, 4, - mfm_read, NULL, NULL, mfm_write, NULL, NULL, xebec); + mfm_read,NULL,NULL, mfm_write,NULL,NULL, dev); - timer_add(mfm_callback, &xebec->callback, &xebec->callback, xebec); - - return(xebec); + timer_add(mfm_callback, &dev->callback, &dev->callback, dev); + + return(dev); } static void mfm_close(void *priv) { - mfm_t *mfm = (mfm_t *)priv; + mfm_t *dev = (mfm_t *)priv; int d; for (d=0; d<2; d++) { - drive_t *drive = &mfm->drives[d]; + drive_t *drive = &dev->drives[d]; hdd_image_close(drive->hdd_num); } - - free(mfm); + + free(dev); } static int xebec_available(void) { - return(rom_present(XEBEC_BIOS_FILE)); -} - - -const device_t mfm_xt_xebec_device = { - "IBM PC Fixed Disk Adapter", - DEVICE_ISA, - 0, - xebec_init, mfm_close, NULL, - xebec_available, NULL, NULL, NULL, - NULL -}; - - -static void * -dtc5150x_init(const device_t *info) -{ - int i, c = 0; - - mfm_t *dtc = malloc(sizeof(mfm_t)); - memset(dtc, 0x00, sizeof(mfm_t)); - - pclog("MFM: looking for disks..\n"); - for (i=0; i MFM_NUM) break; - } - } - pclog("MFM: %d disks loaded.\n", c); - - dtc->switches = 0xff; - - dtc->drives[0].cfg_cyl = dtc->drives[0].tracks; - dtc->drives[0].cfg_hpc = dtc->drives[0].hpc; - dtc->drives[1].cfg_cyl = dtc->drives[1].tracks; - dtc->drives[1].cfg_hpc = dtc->drives[1].hpc; - - rom_init(&dtc->bios_rom, DTC_BIOS_FILE, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - io_sethandler(0x0320, 4, - mfm_read, NULL, NULL, mfm_write, NULL, NULL, dtc); - - timer_add(mfm_callback, &dtc->callback, &dtc->callback, dtc); - - return(dtc); + return(rom_present(XEBEC_BIOS_FILE)); } @@ -936,11 +911,20 @@ dtc5150x_available(void) } +const device_t mfm_xt_xebec_device = { + "IBM PC Fixed Disk Adapter", + DEVICE_ISA, + 0, + mfm_init, mfm_close, NULL, + xebec_available, NULL, NULL, NULL, + NULL +}; + const device_t mfm_xt_dtc5150x_device = { "DTC 5150X", DEVICE_ISA, - 0, - dtc5150x_init, mfm_close, NULL, + 1, + mfm_init, mfm_close, NULL, dtc5150x_available, NULL, NULL, NULL, NULL }; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index 52b5cd6..2cf6ef5 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -21,7 +21,7 @@ * already on their way out, the newer IDE standard based on the * PC/AT controller and 16b design became the IDE we now know. * - * Version: @(#)hdc_xtide.c 1.0.3 2018/03/15 + * Version: @(#)hdc_xtide.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -61,10 +61,10 @@ #include "hdc_ide.h" -#define ROM_PATH_XT L"roms/hdd/xtide/ide_xt.bin" -#define ROM_PATH_AT L"roms/hdd/xtide/ide_at.bin" -#define ROM_PATH_PS2 L"roms/hdd/xtide/side1v12.bin" -#define ROM_PATH_PS2AT L"roms/hdd/xtide/ide_at_1_1_5.bin" +#define ROM_PATH_XT L"hdd/xtide/ide_xt.bin" +#define ROM_PATH_AT L"hdd/xtide/ide_at.bin" +#define ROM_PATH_PS2 L"hdd/xtide/side1v12.bin" +#define ROM_PATH_PS2AT L"hdd/xtide/ide_at_1_1_5.bin" typedef struct { diff --git a/src/disk/hdd.h b/src/disk/hdd.h index b5b9f6a..768ad73 100644 --- a/src/disk/hdd.h +++ b/src/disk/hdd.h @@ -8,7 +8,7 @@ * * Definitions for the hard disk image handler. * - * Version: @(#)hdd.h 1.0.1 2018/02/14 + * Version: @(#)hdd.h 1.0.3 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -55,6 +55,13 @@ enum { }; +/* Define a hard disk table entry. */ +typedef struct { + uint16_t cyls; + uint8_t head; + uint8_t sect; +} hddtab_t; + /* Define the virtual Hard Disk. */ typedef struct { int8_t is_hdi; /* image type (should rename) */ @@ -71,11 +78,11 @@ typedef struct { uint32_t base; - uint64_t spt, - hpc, /* physical geometry parameters */ - tracks; + uint8_t spt, /* physical geometry parameters */ + hpc; + uint16_t tracks; - uint64_t at_spt, /* [Translation] parameters */ + uint8_t at_spt, /* [Translation] parameters */ at_hpc; FILE *f; /* current file handle to image */ @@ -86,7 +93,7 @@ typedef struct { extern hard_disk_t hdd[HDD_NUM]; -extern uint64_t hdd_table[128][3]; +extern const hddtab_t hdd_table[128]; extern int hdd_init(void); @@ -104,7 +111,7 @@ extern void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count); extern int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count); extern uint32_t hdd_image_get_last_sector(uint8_t id); extern uint8_t hdd_image_get_type(uint8_t id); -extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt); +extern void hdd_image_specify(uint8_t id, int hpc, int spt); extern void hdd_image_unload(uint8_t id, int fn_preserve); extern void hdd_image_close(uint8_t id); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index 74da7db..feeb7db 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -8,7 +8,7 @@ * * Handling of hard disk image files. * - * Version: @(#)hdd_image.c 1.0.2 2018/03/27 + * Version: @(#)hdd_image.c 1.0.3 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -144,10 +144,9 @@ int hdd_image_load(int id) uint32_t sector_size = 512; uint32_t zero = 0; uint64_t signature = 0xD778A82044445459ll; - uint64_t full_size = 0; - uint64_t spt = 0, hpc = 0, tracks = 0; - int c; - uint64_t i = 0, s = 0, t = 0; + uint64_t s = 0, t, full_size = 0; + int spt = 0, hpc = 0, tracks = 0; + int c, i; wchar_t *fn = hdd[id].fn; int is_hdx[2] = { 0, 0 }; @@ -260,9 +259,9 @@ int hdd_image_load(int id) return 0; } } - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; + hdd[id].spt = (uint8_t)spt; + hdd[id].hpc = (uint8_t)hpc; + hdd[id].tracks = (uint16_t)tracks; hdd_images[id].type = 1; } else if (is_hdx[1]) { hdd_images[id].base = 0x28; @@ -290,9 +289,9 @@ int hdd_image_load(int id) return 0; } } - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; + hdd[id].spt = (uint8_t)spt; + hdd[id].hpc = (uint8_t)hpc; + hdd[id].tracks = (uint16_t)tracks; fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); hdd_images[id].type = 2; @@ -435,11 +434,11 @@ uint8_t hdd_image_get_type(uint8_t id) return hdd_images[id].type; } -void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) +void hdd_image_specify(uint8_t id, int hpc, int spt) { if (hdd_images[id].type == 2) { - hdd[id].at_hpc = hpc; - hdd[id].at_spt = spt; + hdd[id].at_hpc = (uint8_t)hpc; + hdd[id].at_spt = (uint8_t)spt; fseeko64(hdd_images[id].file, 0x20, SEEK_SET); fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); diff --git a/src/disk/hdd_table.c b/src/disk/hdd_table.c index 98395b4..6386144 100644 --- a/src/disk/hdd_table.c +++ b/src/disk/hdd_table.c @@ -8,7 +8,7 @@ * * Define the available hard disk types. * - * Version: @(#)hdd_table.c 1.0.1 2018/02/14 + * Version: @(#)hdd_table.c 1.0.2 2018/03/29 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -43,7 +43,7 @@ #include "hdd.h" -uint64_t hdd_table[128][3] = { +const hddtab_t hdd_table[128] = { { 306, 4, 17 }, /* 0 - 7 */ { 615, 2, 17 }, { 306, 4, 26 }, diff --git a/src/emu.h b/src/emu.h index 40fffb9..6854f07 100644 --- a/src/emu.h +++ b/src/emu.h @@ -8,7 +8,7 @@ * * Main include file for the application. * - * Version: @(#)emu.h 1.0.10 2018/03/20 + * Version: @(#)emu.h 1.0.12 2018/03/31 * * Author: Fred N. van Kempen, * @@ -58,10 +58,11 @@ #define NVR_PATH L"nvr" #define ROMS_PATH L"roms" #define MACHINES_PATH L"machines" -#define VIDEO_PATH L"machines" +#define VIDEO_PATH L"video" #define SCREENSHOT_PATH L"screenshots" -#define CONFIG_FILE L"varcem.cfg" +#define CONFIG_FILE L"config.varc" +#define CONFIG_FILE_EXT L".varc" #define BIOS_FILE L"bios.txt" @@ -94,8 +95,6 @@ extern int do_dump_config; /* (O) dump cfg after load */ extern int start_in_fullscreen; /* (O) start in fullscreen */ #ifdef _WIN32 extern int force_debug; /* (O) force debug output */ -extern uint64_t unique_id; /* (O) -H id */ -extern uint64_t source_hwnd; /* (O) -H hwnd */ #endif #ifdef USE_WX extern int video_fps; /* (O) render speed in fps */ @@ -176,10 +175,11 @@ extern int config_changed; /* config has changed */ extern void pclog_ex(const char *fmt, va_list); #endif extern void pclog(const char *fmt, ...); -extern void pc_version(const char *platform); extern void fatal(const char *fmt, ...); -extern int pc_init_modules(void); +extern void pc_version(const char *platform); +extern void pc_path(wchar_t *dest, int dest_sz, wchar_t *src); extern int pc_init(int argc, wchar_t *argv[]); +extern int pc_init_modules(void); extern void pc_close(void *threadid); extern void pc_reset_hard_close(void); extern void pc_reset_hard_init(void); diff --git a/src/intel_flash.c b/src/intel_flash.c index 1adc41c..b25d94a 100644 --- a/src/intel_flash.c +++ b/src/intel_flash.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 2 Mbit 8-bit flash devices. * - * Version: @(#)intel_flash.c 1.0.4 2018/03/15 + * Version: @(#)intel_flash.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -256,7 +256,7 @@ void *intel_flash_init(uint8_t type) flash->command = CMD_READ_ARRAY; flash->status = 0; - f = nvr_fopen(flash_path, L"rb"); + f = plat_fopen(nvr_path(flash_path), L"rb"); if (f) { fread(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); fread(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); @@ -298,7 +298,7 @@ void intel_flash_close(void *p) FILE *f; flash_t *flash = (flash_t *)p; - f = nvr_fopen(flash_path, L"wb"); + f = plat_fopen(nvr_path(flash_path), L"wb"); fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); fwrite(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); fwrite(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 2fbbb0c..e454417 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -28,7 +28,7 @@ * boot. Sometimes, they do, and then it shows an "Incorrect * DOS" error message?? --FvK * - * Version: @(#)m_ps1.c 1.0.7 2018/03/27 + * Version: @(#)m_ps1.c 1.0.8 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -508,7 +508,7 @@ ps1_setup(int model) #if 0 rom_init(&ps->high_rom, - L"roms/machines/ibmps1es/f80000_shell.bin", + L"machines/ibmps1es/f80000_shell.bin", 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); #endif @@ -532,11 +532,11 @@ ps1_setup(int model) #if 1 rom_init(&ps->high_rom, - L"roms/machines/ibmps1_2121/fc0000.bin", + L"machines/ibmps1_2121/fc0000.bin", 0xfc0000, 0x20000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); #else rom_init(&ps->high_rom, - L"roms/machines/ibmps1_2121/fc0000_shell.bin", + L"machines/ibmps1_2121/fc0000_shell.bin", 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); #endif diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index df301e4..2a89519 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -8,7 +8,7 @@ * * Emulation of Tandy models 1000, 1000HX and 1000SL2. * - * Version: @(#)m_tandy.c 1.0.4 2018/03/21 + * Version: @(#)m_tandy.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -60,6 +60,7 @@ #include "../sound/snd_sn76489.h" #include "../video/video.h" #include "../video/vid_cga_comp.h" +#include "../plat.h" #include "machine.h" @@ -1540,7 +1541,7 @@ eep_init(const device_t *info) } - f = nvr_fopen(eep->path, L"rb"); + f = plat_fopen(nvr_path(eep->path), L"rb"); if (f != NULL) { fread(eep->store, 128, 1, f); (void)fclose(f); @@ -1558,7 +1559,7 @@ eep_close(void *priv) t1keep_t *eep = (t1keep_t *)priv; FILE *f = NULL; - f = nvr_fopen(eep->path, L"rb"); + f = plat_fopen(nvr_path(eep->path), L"rb"); if (f != NULL) { (void)fwrite(eep->store, 128, 1, f); (void)fclose(f); @@ -1685,8 +1686,8 @@ init_rom(tandy_t *dev) { dev->rom = (uint8_t *)malloc(0x80000); - if (! rom_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", - L"roms/machines/tandy1000sl2/8079048.hu2", + if (! rom_load_interleaved(L"machines/tandy1000sl2/8079047.hu1", + L"machines/tandy1000sl2/8079048.hu2", 0x000000, 0x80000, 0, dev->rom)) { pclog("TANDY: unable to load BIOS for 1000/SL2 !\n"); free(dev->rom); diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index aaed126..0f18cc8 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -8,7 +8,7 @@ * * Implementation of standard IBM PC/XT class machine. * - * Version: @(#)m_xt.c 1.0.4 2018/03/21 + * Version: @(#)m_xt.c 1.0.5 2018/03/29 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,11 +52,55 @@ #include "machine.h" +/* Nasty, used by config.sys. Will re-do later. --FvK */ +int rom_basic = 0; /* is ROM BASIC enabled? */ + + +static const device_config_t xt_config[] = { + { + "rom_basic", "ROM BASIC", CONFIG_SELECTION, "", 0, + { + { + "Disabled", 0 + }, + { + "Enabled", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_t m_xt_device = { + "PC/XT Configuration Device", + MACHINE_ISA, + 0, + NULL, NULL, NULL, + NULL, + NULL, NULL, NULL, + xt_config +}; + + void machine_xt_init(const machine_t *model, void *arg) { machine_common_init(model, arg); + /* Check if we support a BASIC ROM. */ + if (model->get_device != NULL) { + pclog("This (%s) machine supports a BASIC ROM.\n", model->name); + + rom_basic = machine_get_config_int("rom_basic"); + pclog("ROM BASIC is currently %sabled.\n", (rom_basic)?"en":"dis"); + } + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_device); @@ -68,3 +112,10 @@ machine_xt_init(const machine_t *model, void *arg) if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); } + + +const device_t * +xt_get_device(void) +{ + return(&m_xt_device); +} diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 07e798a..f815622 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -48,7 +48,9 @@ * hold a single BCD digit. Hence everything has 'ones' and * 'tens' digits. * - * Version: @(#)m_xt_t1000.c 1.0.6 2018/03/21 + * FIXME: The ROM drive should be re-done using the "option file". + * + * Version: @(#)m_xt_t1000.c 1.0.7 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -102,7 +104,8 @@ #include "m_xt_t1000.h" -#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */ +#define T1000_ROMDOS_SIZE (512*1024UL) /* Max romdrive size is 512k */ +#define T1000_ROMDOS_PATH L"machines/toshiba/t1000/t1000dos.rom" enum TC8521_ADDR { @@ -814,7 +817,7 @@ t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) sys->rom_ctl = val; if (sys->romdrive && (val & 0x80)) { /* Enable */ - sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; + sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMDOS_SIZE; mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); mem_mapping_enable(&sys->rom_mapping); @@ -876,7 +879,7 @@ machine_xt_t1000_init(const machine_t *model, void *arg) t1000.ems_port_index = 7; /* EMS disabled */ /* Load the T1000 CGA Font ROM. */ - loadfont(L"roms/machines/toshiba/t1000/t1000font.rom", 2); + loadfont(L"machines/toshiba/t1000/t1000font.rom", 2); /* * The ROM drive is optional. @@ -884,12 +887,12 @@ machine_xt_t1000_init(const machine_t *model, void *arg) * If the file is missing, continue to boot; the BIOS will * complain 'No ROM drive' but boot normally from floppy. */ - f = rom_fopen(L"roms/machines/toshiba/t1000/t1000dos.rom"); + f = plat_fopen(rom_path(T1000_ROMDOS_PATH), L"rb"); if (f != NULL) { - t1000.romdrive = malloc(T1000_ROMSIZE); + t1000.romdrive = malloc(T1000_ROMDOS_SIZE); if (t1000.romdrive) { - memset(t1000.romdrive, 0xff, T1000_ROMSIZE); - fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + memset(t1000.romdrive, 0xff, T1000_ROMDOS_SIZE); + fread(t1000.romdrive, T1000_ROMDOS_SIZE, 1, f); } fclose(f); } @@ -976,7 +979,7 @@ machine_xt_t1200_init(const machine_t *model, void *arg) t1000.ems_port_index = 7; /* EMS disabled */ /* Load the T1200 CGA Font ROM. */ - loadfont(L"roms/machines/toshiba/t1200/t1000font.bin", 2); + loadfont(L"machines/toshiba/t1200/t1000font.bin", 2); /* Map the EMS page frame */ for (pg = 0; pg < 4; pg++) { diff --git a/src/machine/machine.c b/src/machine/machine.c index ada19dc..d86e2dd 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -85,6 +85,7 @@ machine_init(void) /* Activate the ROM BIOS. */ mem_add_bios(); + /* Reset the IDE bus master pointers. */ ide_set_bus_master(NULL, NULL, NULL); /* All good, boot the machine! */ diff --git a/src/machine/machine.h b/src/machine/machine.h index e8d1a47..3bd7a21 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.12 2018/03/21 + * Version: @(#)machine.h 1.0.13 2018/03/29 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -341,6 +341,9 @@ extern void machine_tandy1k_init(const machine_t *, void *); extern int tandy1k_eeprom_read(void); extern void machine_xt_init(const machine_t *, void *); +#ifdef EMU_DEVICE_H +extern const device_t *xt_get_device(void); +#endif extern void machine_xt_compaq_init(const machine_t *, void *); #if defined(DEV_BRANCH) && defined(USE_LASERXT) extern void machine_xt_laserxt_init(const machine_t *, void *); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 0ffa963..d30cac7 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.14 2018/03/22 + * Version: @(#)machine_table.c 1.0.15 2018/03/29 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,13 +53,13 @@ const machine_t machines[] = { - { "[8088] AMI XT clone", ROM_AMIXT, "ami_xt", L"generic/ami/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Compaq Portable", ROM_PORTABLE, "compaq_portable", L"compaq/portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL, NULL }, - { "[8088] DTK XT clone", ROM_DTKXT, "dtk_xt", L"dtk/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] IBM PC", ROM_IBMPC, "ibm_pc", L"ibm/pc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL, NULL }, + { "[8088] IBM PC", ROM_IBMPC, "ibm_pc", L"ibm/pc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, xt_get_device, NULL }, { "[8088] IBM PCjr", ROM_IBMPCJR, "ibm_pcjr", L"ibm/pcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device, NULL }, - { "[8088] IBM XT", ROM_IBMXT, "ibm_xt", L"ibm/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Generic XT clone", ROM_GENXT, "open_xt", L"generic/open_xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, + { "[8088] IBM XT", ROM_IBMXT, "ibm_xt", L"ibm/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, xt_get_device, NULL }, + { "[8088] OpenXT Generic Clone", ROM_GENXT, "open_xt", L"generic/open_xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, xt_get_device, NULL }, + { "[8088] AMI XT clone", ROM_AMIXT, "ami_xt", L"generic/ami/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, xt_get_device, NULL }, + { "[8088] Compaq Portable", ROM_PORTABLE, "compaq_portable", L"compaq/portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL, NULL }, + { "[8088] DTK XT clone", ROM_DTKXT, "dtk_xt", L"dtk/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, xt_get_device, NULL }, { "[8088] Juko XT clone", ROM_JUKOPC, "juko_pc", L"juko/pc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, { "[8088] Phoenix XT clone", ROM_PXXT, "phoenix_xt", L"generic/phoenix/xt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, { "[8088] Schneider EuroPC", ROM_EUROPC, "schneider_europc", L"schneider/europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 16, machine_europc_init, NULL, NULL }, @@ -69,8 +69,8 @@ const machine_t machines[] = { #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8088] VTech Laser Turbo XT", ROM_LTXT, "vtech_ltxt", L"vtech/ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, #endif - { "[8088] Xi8088", ROM_XI8088, "malinov_xi8088", L"malinov/xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA /*| MACDHINE_AT*/ | MACHINE_PS2, 64, 1024, 128, 128, machine_xt_xi8088_init, NULL, NULL }, + { "[8086] Amstrad PC1512", ROM_PC1512, "amstrad_pc1512", L"amstrad/pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 64, machine_amstrad_init, NULL, NULL }, { "[8086] Amstrad PC1640", ROM_PC1640, "amstrad_pc1640", L"amstrad/pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 64, machine_amstrad_init, NULL, NULL }, { "[8086] Amstrad PC2086", ROM_PC2086, "amstrad_pc2086", L"amstrad/pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 64, machine_amstrad_init, NULL, NULL }, diff --git a/src/mem.c b/src/mem.c index 3b775bd..e3f4aa2 100644 --- a/src/mem.c +++ b/src/mem.c @@ -12,7 +12,7 @@ * the DYNAMIC_TABLES=1 enables this. Will eventually go * away, either way... * - * Version: @(#)mem.c 1.0.10 2018/03/27 + * Version: @(#)mem.c 1.0.11 2018/03/30 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -77,7 +77,7 @@ mem_mapping_t romext_mapping; page_t *pages, /* RAM page table */ **page_lookup; /* pagetable lookup */ -uint32_t pages_sz; /* #pages in table */ +uint32_t pages_sz = 0; /* #pages in table */ uint8_t isram[0x10000]; @@ -1614,7 +1614,7 @@ mem_reset(void) #if DYNAMIC_TABLES pclog("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); #endif - if (pages_sz != m) { + if (pages_sz != m || pages_sz == 0) { pages_sz = m; free(pages); pages = (page_t *)malloc(m*sizeof(page_t)); diff --git a/src/mouse.c b/src/mouse.c index 62397ae..4ce6fa4 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -11,7 +11,7 @@ * TODO: Add the Genius bus- and serial mouse. * Remove the '3-button' flag from mouse types. * - * Version: @(#)mouse.c 1.0.3 2018/03/18 + * Version: @(#)mouse.c 1.0.4 2018/03/29 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -164,7 +164,7 @@ mouse_process(void) { static int poll_delay = 2; - if (mouse_devices[mouse_type].device == NULL) return; + if (mouse_type == MOUSE_TYPE_NONE) return; if (--poll_delay) return; diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 05b2ec6..62f9e35 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -12,7 +12,7 @@ * - Realtek RTL8019AS (ISA 16-bit, PnP); * - Realtek RTL8029AS (PCI). * - * Version: @(#)net_ne2000.c 1.0.3 2018/03/15 + * Version: @(#)net_ne2000.c 1.0.4 2018/03/31 * * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy * @@ -61,6 +61,7 @@ #include "../pic.h" #include "../random.h" #include "../device.h" +#include "../plat.h" #include "../ui.h" #include "network.h" #include "net_ne2000.h" @@ -76,10 +77,10 @@ enum { /* ROM BIOS file paths. */ -#define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom" -#define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom" -#define ROM_PATH_RTL8019 L"roms/network/rtl8019as/rtl8019as.rom" -#define ROM_PATH_RTL8029 L"roms/network/rtl8029as/rtl8029as.rom" +#define ROM_PATH_NE1000 L"network/ne1000/ne1000.rom" +#define ROM_PATH_NE2000 L"network/ne2000/ne2000.rom" +#define ROM_PATH_RTL8019 L"network/rtl8019as/rtl8019as.rom" +#define ROM_PATH_RTL8029 L"network/rtl8029as/rtl8029as.rom" /* PCI info. */ #define PNP_VENDID 0x4a8c /* Realtek, Inc */ @@ -2348,7 +2349,7 @@ nic_rom_init(nic_t *dev, wchar_t *s) if (dev->bios_addr == 0) return; - if ((f = rom_fopen(s)) != NULL) { + if ((f = plat_fopen(rom_path(s), L"rb")) != NULL) { fseek(f, 0L, SEEK_END); temp = ftell(f); fclose(f); diff --git a/src/network/pcap_if.c b/src/network/pcap_if.c index defb7b1..6dbe4af 100644 --- a/src/network/pcap_if.c +++ b/src/network/pcap_if.c @@ -10,7 +10,7 @@ * * Based on the "libpcap" examples. * - * Version: @(#)pcap_if.c 1.0.12 2018/03/26 + * Version: @(#)pcap_if.c 1.0.3 2018/03/30 * * Author: Fred N. van Kempen, * diff --git a/src/nvr.c b/src/nvr.c index 148f699..b14e08f 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -10,7 +10,7 @@ * * NOTE: I should re-do 'intclk' using a TM struct. * - * Version: @(#)nvr.c 1.0.3 2018/03/20 + * Version: @(#)nvr.c 1.0.4 2018/03/31 * * Author: Fred N. van Kempen, * @@ -197,6 +197,31 @@ nvr_init(nvr_t *nvr) } +/* Get path to the NVR folder. */ +wchar_t * +nvr_path(wchar_t *str) +{ + static wchar_t temp[1024]; + + /* Get the full prefix in place. */ + wcscpy(temp, usr_path); + wcscat(temp, NVR_PATH); + + /* Create the directory if needed. */ + if (! plat_dir_check(temp)) + plat_dir_create(temp); + + /* Now append the actual filename. */ + plat_append_slash(temp); + wcscat(temp, str); + + /* Make sure path is clean. */ + pc_path(temp, sizeof_w(temp), NULL); + + return(temp); +} + + /* * Load an NVR from file. * @@ -211,6 +236,7 @@ nvr_init(nvr_t *nvr) int nvr_load(void) { + wchar_t *path; FILE *f; /* Make sure we have been initialized. */ @@ -225,8 +251,9 @@ nvr_load(void) /* Load the (relevant) part of the NVR contents. */ if (saved_nvr->size != 0) { - pclog("NVR: loading from '%ls'\n", nvr_path(saved_nvr->fn)); - f = plat_fopen(nvr_path(saved_nvr->fn), L"rb"); + path = nvr_path(saved_nvr->fn); + pclog("NVR: loading from '%ls'\n", path); + f = plat_fopen(path, L"rb"); if (f != NULL) { /* Read NVR contents from file. */ (void)fread(saved_nvr->regs, saved_nvr->size, 1, f); @@ -246,14 +273,16 @@ nvr_load(void) int nvr_save(void) { + wchar_t *path; FILE *f; /* Make sure we have been initialized. */ if (config_ro || saved_nvr == NULL) return(0); if (saved_nvr->size != 0) { - pclog("NVR: saving to '%ls'\n", nvr_path(saved_nvr->fn)); - f = plat_fopen(nvr_path(saved_nvr->fn), L"wb"); + path = nvr_path(saved_nvr->fn); + pclog("NVR: saving to '%ls'\n", path); + f = plat_fopen(path, L"wb"); if (f != NULL) { /* Save NVR contents to file. */ (void)fwrite(saved_nvr->regs, saved_nvr->size, 1, f); @@ -302,34 +331,3 @@ nvr_time_set(struct tm *tm) intclk.mon = (tm->tm_mon + 1); intclk.year = (tm->tm_year + 1900); } - - -/* Get an absolute path to the NVR folder. */ -wchar_t * -nvr_path(wchar_t *str) -{ - static wchar_t temp[1024]; - - /* Get the full prefix in place. */ - memset(temp, 0x00, sizeof(temp)); - wcscpy(temp, usr_path); - wcscat(temp, NVR_PATH); - - /* Create the directory if needed. */ - if (! plat_dir_check(temp)) - plat_dir_create(temp); - - /* Now append the actual filename. */ - plat_append_slash(temp); - wcscat(temp, str); - - return(temp); -} - - -/* Open or create a file in the NVR area. */ -FILE * -nvr_fopen(wchar_t *str, wchar_t *mode) -{ - return(plat_fopen(nvr_path(str), mode)); -} diff --git a/src/nvr.h b/src/nvr.h index 50b06d4..8b5110f 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -1,105 +1,98 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Definitions for the generic NVRAM/CMOS driver. - * - * Version: @(#)nvr.h 1.0.4 2018/03/19 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017,2018 Fred N. van Kempen. - * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef EMU_NVR_H -# define EMU_NVR_H - - -#define NVR_MAXSIZE 128 /* max size of NVR data */ - -/* Conversion from BCD to Binary and vice versa. */ -#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4)) -#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) -#define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y) - - -/* Define a generic RTC/NVRAM device. */ -typedef struct _nvr_ { - uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ - wchar_t *fn; /* pathname of image file */ - uint16_t size; /* device configuration */ - int8_t irq; - - int8_t upd_stat, /* FIXME: move to private struct */ - addr; - int64_t upd_ecount, /* FIXME: move to private struct */ - onesec_time, - onesec_cnt, - rtctime; - - /* Hooks to device functions. */ - void (*reset)(struct _nvr_ *); - void (*start)(struct _nvr_ *); - void (*tick)(struct _nvr_ *); -} nvr_t; - - -extern int nvr_dosave; -#ifdef EMU_DEVICE_H -extern const device_t at_nvr_device; -extern const device_t amstrad_nvr_device; -#endif - - -extern void nvr_init(nvr_t *); -extern int nvr_load(void); -extern int nvr_save(void); - -extern int nvr_is_leap(int year); -extern int nvr_get_days(int month, int year); -extern void nvr_time_get(struct tm *); -extern void nvr_time_set(struct tm *); - -extern wchar_t *nvr_path(wchar_t *str); -extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); - -#if 0 -extern void nvr_at_init(int irq); -extern void nvr_at_close(void); +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the generic NVRAM/CMOS driver. + * + * Version: @(#)nvr.h 1.0.5 2018/03/31 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EMU_NVR_H +# define EMU_NVR_H + + +#define NVR_MAXSIZE 128 /* max size of NVR data */ + +/* Conversion from BCD to Binary and vice versa. */ +#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4)) +#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) +#define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y) + + +/* Define a generic RTC/NVRAM device. */ +typedef struct _nvr_ { + uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ + wchar_t *fn; /* pathname of image file */ + uint16_t size; /* device configuration */ + int8_t irq; + + int8_t upd_stat, /* FIXME: move to private struct */ + addr; + int64_t upd_ecount, /* FIXME: move to private struct */ + onesec_time, + onesec_cnt, + rtctime; + + /* Hooks to device functions. */ + void (*reset)(struct _nvr_ *); + void (*start)(struct _nvr_ *); + void (*tick)(struct _nvr_ *); +} nvr_t; + + +extern int nvr_dosave; +#ifdef EMU_DEVICE_H +extern const device_t at_nvr_device; +extern const device_t amstrad_nvr_device; #endif - - -#endif /*EMU_NVR_H*/ + + +extern void nvr_init(nvr_t *); +extern wchar_t *nvr_path(wchar_t *fn); +extern int nvr_load(void); +extern int nvr_save(void); + +extern int nvr_is_leap(int year); +extern int nvr_get_days(int month, int year); +extern void nvr_time_get(struct tm *); +extern void nvr_time_set(struct tm *); + + +#endif /*EMU_NVR_H*/ diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index 844b975..d4b1780 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -8,7 +8,7 @@ * * Handling of the PS/2 series CMOS devices. * - * Version: @(#)nvr_ps2.c 1.0.5 2018/03/15 + * Version: @(#)nvr_ps2.c 1.0.6 2018/03/31 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -45,6 +45,7 @@ #include "device.h" #include "io.h" #include "nvr.h" +#include "plat.h" #include "nvr_ps2.h" @@ -114,15 +115,15 @@ ps2_nvr_init(const device_t *info) switch (romset) { case ROM_IBMPS2_M70_TYPE3: - f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"rb"); + f = plat_fopen(nvr_path(L"ibmps2_m70_type3_sec.nvr"), L"rb"); break; case ROM_IBMPS2_M70_TYPE4: - f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"rb"); + f = plat_fopen(nvr_path(L"ibmps2_m70_type4_sec.nvr"), L"rb"); break; case ROM_IBMPS2_M80: - f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb"); + f = plat_fopen(nvr_path(L"ibmps2_m80_sec.nvr"), L"rb"); break; } @@ -144,15 +145,15 @@ ps2_nvr_close(void *priv) switch (romset) { case ROM_IBMPS2_M70_TYPE3: - f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"wb"); + f = plat_fopen(nvr_path(L"ibmps2_m70_type3_sec.nvr"), L"wb"); break; case ROM_IBMPS2_M70_TYPE4: - f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"wb"); + f = plat_fopen(nvr_path(L"ibmps2_m70_type4_sec.nvr"), L"wb"); break; case ROM_IBMPS2_M80: - f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb"); + f = plat_fopen(nvr_path(L"ibmps2_m80_sec.nvr"), L"wb"); break; } diff --git a/src/pc.c b/src/pc.c index beebf07..5705950 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.16 2018/03/27 + * Version: @(#)pc.c 1.0.17 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -102,8 +102,6 @@ int do_dump_config = 0; /* (O) dump config on load */ int start_in_fullscreen = 0; /* (O) start in fullscreen */ #ifdef _WIN32 int force_debug = 0; /* (O) force debug output */ -uint64_t unique_id = 0; /* (O) -H id */ -uint64_t source_hwnd = 0; /* (O) -H hwnd */ #endif #ifdef USE_WX int video_fps = RENDER_FPS; /* (O) render speed in fps */ @@ -325,6 +323,45 @@ pc_version(const char *platform) } +/* + * NOTE: + * + * Although we now use relative pathnames in the code, + * we may still bump into old configuration files that + * still have old, absolute pathnames. + * + * We try to "fix" those by stripping the "usr_path" + * component from them, if they have that. If another + * path, well, nothing we can do here. + */ +void +pc_path(wchar_t *dst, int sz, wchar_t *src) +{ + if ((src != NULL) && !wcsnicmp(src, usr_path, wcslen(usr_path))) + src += wcslen(usr_path); + + /* + * Fix all the slashes. + * + * Since Windows will handle both \ and / paths, we + * now convert ALL paths to the latter format, so it + * is always the same. + */ + if (src == NULL) + src = dst; + while ((sz > 0) && (*src != L'\0')) { + if (*src == L'\\') + *dst = L'/'; + else + *dst = *src; + src++; + dst++; + sz--; + } + *dst = L'\0'; +} + + /* * Perform initial startup of the PC. * @@ -387,6 +424,9 @@ pc_init(int argc, wchar_t *argv[]) if (!wcscasecmp(argv[c], L"--help") || !wcscasecmp(argv[c], L"-?")) { usage: +#ifdef _WIN32 + plat_console(1); +#endif printf("\n%s %s\n", emu_title, emu_fullversion); printf("\nUsage: varcem [options] [cfg-file]\n\n"); printf("Valid options are:\n\n"); @@ -403,9 +443,6 @@ usage: printf(" -R or --fps num - set render speed to 'num' fps\n"); #endif printf(" -S or --settings - show only the settings dialog\n"); -#ifdef _WIN32 - printf(" -H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); -#endif printf(" -W or --readonly - do not modify the config file\n"); printf("\nA config file can be specified. If none is, the default file will be used.\n"); return(0); @@ -442,15 +479,6 @@ usage: } else if (!wcscasecmp(argv[c], L"--settings") || !wcscasecmp(argv[c], L"-S")) { settings_only = 1; -#ifdef _WIN32 - } else if (!wcscasecmp(argv[c], L"--hwnd") || - !wcscasecmp(argv[c], L"-H")) { - - if ((c+1) == argc) goto usage; - - wcstombs(temp, argv[++c], sizeof(temp)); - sscanf(temp, "%016" PRIX64 ",%016" PRIX64, &unique_id, &source_hwnd); -#endif } else if (!wcscasecmp(argv[c], L"--readonly") || !wcscasecmp(argv[c], L"-W")) { config_ro = 1; @@ -537,10 +565,22 @@ usage: /* At this point, we can safely create the full path name. */ plat_append_filename(cfg_path, usr_path, p); + /* If no extension was given, tack on the default one. */ + if ((cfg = wcschr(p, L'.')) == NULL) + wcscat(cfg_path, CONFIG_FILE_EXT); + /* * This is where we start outputting to the log file, * if there is one. Create a little info header first. + * + * For the Windows version, if we do not have a console + * meaning, not logging to file..), request one if we + * have force_debug set. */ +#ifdef _WIN32 + if (force_debug) + plat_console(1); +#endif (void)time(&now); info = localtime(&now); strftime(temp, sizeof(temp), "%Y/%m/%d %H:%M:%S", info); @@ -556,11 +596,12 @@ usage: * disks are an example) so we have to initialize those * modules before we load the config.. */ - hdd_init(); - network_init(); mouse_init(); + sound_global_init(); + hdd_init(); cdrom_global_init(); zip_global_init(); + network_init(); /* Load the configuration file. */ config_load(); diff --git a/src/plat.h b/src/plat.h index 521c6b6..d3ee116 100644 --- a/src/plat.h +++ b/src/plat.h @@ -8,7 +8,7 @@ * * Define the various platform support functions. * - * Version: @(#)plat.h 1.0.6 2018/03/28 + * Version: @(#)plat.h 1.0.7 2018/03/31 * * Author: Fred N. van Kempen, * @@ -100,6 +100,9 @@ GLOBAL int infocus; /* System-related functions. */ +#ifdef _WIN32 +extern void plat_console(int on); +#endif extern wchar_t *fix_emu_path(wchar_t *str); extern FILE *plat_fopen(wchar_t *path, wchar_t *mode); extern void plat_remove(wchar_t *path); diff --git a/src/rom.c b/src/rom.c index 8279713..2072957 100644 --- a/src/rom.c +++ b/src/rom.c @@ -12,7 +12,7 @@ * - pc2386 video BIOS is underdumped (16k instead of 24k) * - c386sx16 BIOS fails checksum * - * Version: @(#)rom.c 1.0.8 2018/03/12 + * Version: @(#)rom.c 1.0.10 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,44 +53,32 @@ #include "plat.h" -FILE * -rom_fopen(wchar_t *fn) +/* Return the base path for ROM images. */ +wchar_t * +rom_path(wchar_t *str) { - wchar_t temp[1024]; + static wchar_t temp[1024]; + /* Get the full path in place. */ wcscpy(temp, emu_path); + wcscat(temp, ROMS_PATH); plat_append_slash(temp); - wcscat(temp, fn); + wcscat(temp, str); - return(plat_fopen(temp, L"rb")); -} - - -int -rom_getfile(wchar_t *fn, wchar_t *s, int size) -{ - FILE *f; - - wcscpy(s, emu_path); - plat_append_slash(s); - wcscat(s, fn); - - f = plat_fopen(s, L"rb"); - if (f != NULL) { - (void)fclose(f); - return(1); - } - - return(0); + /* Make sure path is clean. */ + pc_path(temp, sizeof_w(temp), NULL); + + return(temp); } +/* Used by the available() functions to check if a file exists. */ int rom_present(wchar_t *fn) { FILE *f; - f = rom_fopen(fn); + f = plat_fopen(rom_path(fn), L"rb"); if (f != NULL) { (void)fclose(f); return(1); @@ -149,8 +137,9 @@ rom_readl(uint32_t addr, void *priv) int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { - FILE *f = rom_fopen(fn); - + FILE *f; + + f = plat_fopen(rom_path(fn), L"rb"); if (f == NULL) { pclog("ROM: image '%ls' not found\n", fn); return(0); @@ -174,8 +163,9 @@ rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) int rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) { - FILE *f = rom_fopen(fn); + FILE *f; + f = plat_fopen(rom_path(fn), L"rb"); if (f == NULL) { pclog("ROM: image '%ls' not found\n", fn); return(0); @@ -206,8 +196,8 @@ rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *p int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, uint8_t *ptr) { - FILE *fl = rom_fopen(fnl); - FILE *fh = rom_fopen(fnh); + FILE *fl = plat_fopen(rom_path(fnl), L"rb"); + FILE *fh = plat_fopen(rom_path(fnh), L"rb"); int c; if (fl == NULL || fh == NULL) { diff --git a/src/rom.h b/src/rom.h index 3e46561..9da5672 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,7 +8,7 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.7 2018/03/21 + * Version: @(#)rom.h 1.0.9 2018/03/31 * * Authors: Fred N. van Kempen, * @@ -71,6 +71,7 @@ typedef struct { int mode; uint32_t offset; uint32_t skip; + uint32_t size; } files[ROMDEF_NFILES]; } romdef_t; @@ -79,8 +80,7 @@ extern uint8_t rom_read(uint32_t addr, void *p); extern uint16_t rom_readw(uint32_t addr, void *p); extern uint32_t rom_readl(uint32_t addr, void *p); -extern FILE *rom_fopen(wchar_t *fn); -extern int rom_getfile(wchar_t *fn, wchar_t *s, int size); +extern wchar_t *rom_path(wchar_t *fn); extern int rom_present(wchar_t *fn); extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, diff --git a/src/rom_load.c b/src/rom_load.c index 15f5243..d1b85f6 100644 --- a/src/rom_load.c +++ b/src/rom_load.c @@ -17,7 +17,7 @@ * or to use a generic handler, and then pass it a pointer * to a command table. For now, we don't. * - * Version: @(#)rom_load.c 1.0.5 2018/03/21 + * Version: @(#)rom_load.c 1.0.6 2018/03/31 * * Author: Fred N. van Kempen, * @@ -62,23 +62,40 @@ #include "emu.h" #include "mem.h" #include "rom.h" +#include "device.h" #include "plat.h" -#define PATH_BIOS "bios.txt" /* name of the script we run */ #define MAX_ARGS 16 /* max number of arguments */ +/* Grab the value from a string. */ +static uint32_t +get_val(char *str) +{ + long unsigned int l = 0UL; + + if ((strlen(str) > 1) && /* hex always is 0x... */ + (sscanf(str, "0x%lx", &l) == 0)) /* no valid field found */ + sscanf(str, "%i", (int *)&l); /* try decimal.. */ + + return(l); +} + + /* Process a single (logical) command line. */ static int process(int ln, int argc, char **argv, romdef_t *r) { +again: if (! strcmp(argv[0], "size")) { - sscanf(argv[1], "%i", &r->total); + /* Total size of image. */ + r->total = get_val(argv[1]); } else if (! strcmp(argv[0], "offset")) { - if (sscanf(argv[1], "0x%lx", (long unsigned int *)&r->offset) == 0) - sscanf(argv[1], "%i", &r->offset); + /* Offset into the ROM area. */ + r->offset = get_val(argv[1]); } else if (! strcmp(argv[0], "mode")) { + /* Loading method to use for this image. */ if (! strcmp(argv[1], "linear")) r->mode = 0; else if (! strcmp(argv[1], "interleaved")) @@ -87,23 +104,46 @@ process(int ln, int argc, char **argv, romdef_t *r) pclog("ROM: invalid mode '%s' on line %d.\n", argv[1], ln); return(0); } + } else if (! strcmp(argv[0], "optional")) { + /* + * This is an optional file. + * Next word is the name of the configuration + * variable this depends on, for example "basic" + * or "romdos". + */ + if (! machine_get_config_int(argv[1])) return(1); + + /* Skip the keyword and variable name, and re-parse. */ + argv += 2; + argc -= 2; + goto again; } else if (! strcmp(argv[0], "file")) { + /* Specify the image filename and/or additional parameters. */ mbstowcs(r->files[r->nfiles].path, argv[1], sizeof_w(r->files[r->nfiles].path)); - if (argc >= 3) - sscanf(argv[2], "%i", &r->files[r->nfiles].skip); - else - r->files[r->nfiles].skip = 0; - if (argc == 4) { - if (sscanf(argv[3], "0x%lx", (long unsigned int *)&r->files[r->nfiles].offset) == 0) - sscanf(argv[3], "%i", &r->files[r->nfiles].offset); - } else - r->files[r->nfiles].offset = r->offset; + r->files[r->nfiles].skip = 0; + r->files[r->nfiles].offset = r->offset; + r->files[r->nfiles].size = r->total; + switch(argc) { + case 5: + r->files[r->nfiles].size = get_val(argv[4]); + /*FALLTHROUGH*/ + + case 4: + r->files[r->nfiles].offset = get_val(argv[3]); + /*FALLTHROUGH*/ + + case 3: + r->files[r->nfiles].skip = get_val(argv[2]); + break; + } r->nfiles++; } else if (! strcmp(argv[0], "font")) { + /* Load a video controller font. */ r->fontnum = atoi(argv[1]); mbstowcs(r->fontfn, argv[2], sizeof_w(r->fontfn)); } else if (! strcmp(argv[0], "video")) { + /* Load a video controller BIOS. */ mbstowcs(r->vidfn, argv[1], sizeof_w(r->vidfn)); sscanf(argv[2], "%i", &r->vidsz); } else { @@ -313,19 +353,23 @@ parser(FILE *fp, romdef_t *r) int rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) { - wchar_t path[1024], script[1024]; + wchar_t path[1024]; wchar_t temp[1024]; + wchar_t script[1024]; FILE *fp; int c, i; + /* Generate the BIOS pathname. */ + wcscpy(path, fn); + plat_append_slash(path); + /* Generate the full script pathname. */ - wcscpy(script, ROMS_PATH); plat_append_slash(script); - wcscat(script, fn); plat_append_slash(script); - wcscpy(path, script); + wcscpy(script, path); wcscat(script, BIOS_FILE); + pc_path(script, sizeof_w(script), NULL); if (! test_only) { - pclog("ROM: loading script '%ls'\n", fn); + pclog("ROM: loading script '%ls'\n", rom_path(script)); /* If not done yet, allocate a 128KB buffer for the BIOS ROM. */ if (rom == NULL) @@ -341,8 +385,8 @@ rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) } /* Open the script file. */ - if ((fp = rom_fopen(script)) == NULL) { - pclog("ROM: unable to open '%ls'\n", script); + if ((fp = plat_fopen(rom_path(script), L"rb")) == NULL) { + pclog("ROM: unable to open '%ls'\n", rom_path(script)); return(0); } @@ -362,8 +406,9 @@ rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) pclog("Mode : %s\n", (r->mode == 1)?"interleaved":"linear"); pclog("Files : %d\n", r->nfiles); for (c=0; cnfiles; c++) { - pclog(" [%d] : '%ls', %d, 0x%06lx\n", c+1, - r->files[c].path, r->files[c].skip, r->files[c].offset); + pclog(" [%d] : '%ls', %i, 0x%06lx, %i\n", c+1, + r->files[c].path, r->files[c].skip, + r->files[c].offset, r->files[c].size); } if (r->fontnum != -1) pclog("Font : %i, '%ls'\n", r->fontnum, r->fontfn); @@ -377,11 +422,12 @@ rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) for (c=0; cnfiles; c++) { wcscpy(script, path); wcscat(script, r->files[c].path); + pc_path(script, sizeof_w(script), NULL); i = rom_load_linear(script, r->files[c].offset, - r->total, + r->files[c].size, r->files[c].skip, rom); - if (i != 0) break; + if (i != 1) break; } if (r->total >= 0x010000) biosmask = (r->total - 1); @@ -392,13 +438,15 @@ rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) for (c=0; cnfiles/2; c+=2) { wcscpy(script, path); wcscat(script, r->files[c].path); + pc_path(script, sizeof_w(script), NULL); wcscpy(temp, path); wcscat(temp, r->files[c+1].path); + pc_path(temp, sizeof_w(temp), NULL); i = rom_load_interleaved(script, temp, r->files[c].offset, - r->total, + r->files[c].size, r->files[c].skip, rom); - if (i != 0) break; + if (i != 1) break; } if (r->total >= 0x010000) biosmask = (r->total - 1); @@ -409,14 +457,14 @@ rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) if (r->fontnum != -1) { wcscpy(temp, path); wcscat(temp, r->fontfn); - wcscpy(r->fontfn, temp); + pc_path(r->fontfn, sizeof_w(r->fontfn), temp); } /* Create a full pathname for the video BIOS file. */ if (r->vidsz != 0) { wcscpy(temp, path); wcscat(temp, r->vidfn); - wcscpy(r->vidfn, temp); + pc_path(r->vidfn, sizeof_w(r->vidfn), temp); } pclog("ROM: status %d, tot %u, mask 0x%06lx\n", diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 68b5a89..d6e2a97 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -10,7 +10,7 @@ * made by Adaptec, Inc. These controllers were designed for * the ISA bus. * - * Version: @(#)scsi_aha154x.c 1.0.5 2018/03/15 + * Version: @(#)scsi_aha154x.c 1.0.6 2018/03/31 * * Based on original code from TheCollector1995 and Miran Grca. * @@ -47,7 +47,6 @@ #include #define HAVE_STDARG_H #include "../emu.h" -#include "../cpu/cpu.h" // for debug, temporary #include "../io.h" #include "../mca.h" #include "../mem.h" @@ -64,6 +63,14 @@ #include "scsi_x54x.h" +#define AHA1540B_330_BIOS_PATH L"scsi/adaptec/aha1540b320_330.bin" +#define AHA1540B_334_BIOS_PATH L"scsi/adaptec/aha1540b320_334.bin" +#define AHA1540C_BIOS_PATH L"scsi/adaptec/aha1542c102.bin" +#define AHA1540CF_BIOS_PATH L"scsi/adaptec/aha1542cf211.bin" +#define AHA1540CP_BIOS_PATH L"scsi/adaptec/aha1542cp102.bin" +#define AHA1640_BIOS_PATH L"scsi/adaptec/aha1640.bin" + + enum { AHA_154xB, AHA_154xC, @@ -73,12 +80,12 @@ enum { }; -#define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ -#define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ +#define CMD_WR_EEPROM 0x22 /* UNDOC: Write EEPROM */ +#define CMD_RD_EEPROM 0x23 /* UNDOC: Read EEPROM */ #define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ #define CMD_BIOS_MBINIT 0x25 /* UNDOC: BIOS mailbox initialization */ -#define CMD_MEMORY_MAP_1 0x26 /* UNDOC: Memory Mapper */ -#define CMD_MEMORY_MAP_2 0x27 /* UNDOC: Memory Mapper */ +#define CMD_MEM_MAP_1 0x26 /* UNDOC: Memory Mapper */ +#define CMD_MEM_MAP_2 0x27 /* UNDOC: Memory Mapper */ #define CMD_EXTBIOS 0x28 /* UNDOC: return extended BIOS info */ #define CMD_MBENABLE 0x29 /* set mailbox interface enable */ #define CMD_BIOS_SCSI 0x82 /* start ROM BIOS SCSI command */ @@ -114,8 +121,6 @@ aha_log(const char *fmt, ...) va_list ap; if (aha_do_log) { -// for debug, temporary -pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); @@ -135,7 +140,7 @@ pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); * We enable/disable this memory through AHA command 0x24. */ static void -aha_mem_write(uint32_t addr, uint8_t val, void *priv) +mem_write(uint32_t addr, uint8_t val, void *priv) { x54x_t *dev = (x54x_t *)priv; @@ -147,7 +152,7 @@ aha_mem_write(uint32_t addr, uint8_t val, void *priv) static uint8_t -aha_mem_read(uint32_t addr, void *priv) +mem_read(uint32_t addr, void *priv) { x54x_t *dev = (x54x_t *)priv; rom_t *rom = &dev->bios; @@ -162,7 +167,7 @@ aha_mem_read(uint32_t addr, void *priv) static uint8_t -aha154x_shram(x54x_t *dev, uint8_t cmd) +shram_cmd(x54x_t *dev, uint8_t cmd) { /* If not supported, give up. */ if (dev->rom_shram == 0x0000) return(0x04); @@ -177,13 +182,12 @@ aha154x_shram(x54x_t *dev, uint8_t cmd) static void -aha_eeprom_save(x54x_t *dev) +eeprom_save(x54x_t *dev) { FILE *f; - f = nvr_fopen(dev->nvr_path, L"wb"); - if (f) - { + f = plat_fopen(nvr_path(dev->nvr_path), L"wb"); + if (f != NULL) { fwrite(dev->nvr, 1, NVR_SIZE, f); fclose(f); f = NULL; @@ -192,7 +196,7 @@ aha_eeprom_save(x54x_t *dev) static uint8_t -aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) +eeprom_cmd(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) { uint8_t r = 0xff; int c; @@ -209,7 +213,7 @@ aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint dev->nvr[(off + c) & 0xff] = bufp[c]; r = 0; - aha_eeprom_save(dev); + eeprom_save(dev); } if (cmd == 0x23) { @@ -225,7 +229,7 @@ aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint /* Map either the main or utility (Select) ROM into the memory space. */ static uint8_t -aha154x_mmap(x54x_t *dev, uint8_t cmd) +mmap_cmd(x54x_t *dev, uint8_t cmd) { aha_log("%s: MEMORY cmd=%02x\n", dev->name, cmd); @@ -246,211 +250,208 @@ aha154x_mmap(x54x_t *dev, uint8_t cmd) static uint8_t -aha_get_host_id(void *p) +get_host_id(void *p) { x54x_t *dev = (x54x_t *)p; - return dev->nvr[0] & 0x07; + return(dev->nvr[0] & 0x07); } static uint8_t -aha_get_irq(void *p) +get_irq(void *p) { x54x_t *dev = (x54x_t *)p; - return (dev->nvr[1] & 0x07) + 9; + return((dev->nvr[1] & 0x07) + 9); } static uint8_t -aha_get_dma(void *p) +get_dma(void *p) { x54x_t *dev = (x54x_t *)p; - return (dev->nvr[1] >> 4) & 0x07; + return((dev->nvr[1] >> 4) & 0x07); } static uint8_t -aha_cmd_is_fast(void *p) +cmd_is_fast(void *p) { x54x_t *dev = (x54x_t *)p; if (dev->Command == CMD_BIOS_SCSI) - return 1; - else - return 0; + return(1); + + return(0); } static uint8_t -aha_fast_cmds(void *p, uint8_t cmd) +fast_cmds(void *p, uint8_t cmd) { x54x_t *dev = (x54x_t *)p; if (cmd == CMD_BIOS_SCSI) { dev->BIOSMailboxReq++; - return 1; + return(1); } - return 0; + return(0); } static uint8_t -aha_param_len(void *p) +param_len(void *p) { x54x_t *dev = (x54x_t *)p; switch (dev->Command) { case CMD_BIOS_MBINIT: /* Same as 0x01 for AHA. */ - return sizeof(MailboxInit_t); + return(sizeof(MailboxInit_t)); break; case CMD_SHADOW_RAM: - return 1; + return(1); break; - case CMD_WRITE_EEPROM: - return 3+32; + case CMD_WR_EEPROM: + return(3+32); break; - case CMD_READ_EEPROM: - return 3; + case CMD_RD_EEPROM: + return(3); case CMD_MBENABLE: - return 2; + return(2); default: - return 0; + break; } + + return(0); } static uint8_t -aha_cmds(void *p) +aha_cmds(void *priv) { - x54x_t *dev = (x54x_t *)p; + x54x_t *dev = (x54x_t *)priv; MailboxInit_t *mbi; - if (! dev->CmdParamLeft) { - aha_log("Running Operation Code 0x%02X\n", dev->Command); - switch (dev->Command) { - case CMD_WRITE_EEPROM: /* write EEPROM */ - /* Sent by CF BIOS. */ - dev->DataReplyLeft = - aha154x_eeprom(dev, - dev->Command, - dev->CmdBuf[0], - dev->CmdBuf[1], - dev->CmdBuf[2], - &(dev->CmdBuf[3])); - if (dev->DataReplyLeft == 0xff) { - dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; - } - break; + if (dev->CmdParamLeft) return(0); - case CMD_READ_EEPROM: /* read EEPROM */ - /* Sent by CF BIOS. */ - dev->DataReplyLeft = - aha154x_eeprom(dev, - dev->Command, - dev->CmdBuf[0], - dev->CmdBuf[1], - dev->CmdBuf[2], - dev->DataBuf); - if (dev->DataReplyLeft == 0xff) { - dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; - } - break; - - case CMD_SHADOW_RAM: /* Shadow RAM */ - /* - * For AHA1542CF, this is the command - * to play with the Shadow RAM. BIOS - * gives us one argument (00,02,03) - * and expects a 0x04 back in the INTR - * register. --FvK - */ - /* dev->Interrupt = aha154x_shram(dev,val); */ - dev->Interrupt = aha154x_shram(dev, dev->CmdBuf[0]); - break; - - case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ - /* Sent by CF BIOS. */ - dev->Mbx24bit = 1; - - mbi = (MailboxInit_t *)dev->CmdBuf; - - dev->BIOSMailboxInit = 1; - dev->BIOSMailboxCount = mbi->Count; - dev->BIOSMailboxOutAddr = ADDR_TO_U32(mbi->Address); - - aha_log("Initialize BIOS Mailbox: MBO=0x%08lx, %d entries at 0x%08lx\n", - dev->BIOSMailboxOutAddr, - mbi->Count, - ADDR_TO_U32(mbi->Address)); - - dev->Status &= ~STAT_INIT; - dev->DataReplyLeft = 0; - break; - - case CMD_MEMORY_MAP_1: /* AHA memory mapper */ - case CMD_MEMORY_MAP_2: /* AHA memory mapper */ - /* Sent by CF BIOS. */ - dev->DataReplyLeft = - aha154x_mmap(dev, dev->Command); - break; - - case CMD_EXTBIOS: /* Return extended BIOS information */ - dev->DataBuf[0] = 0x08; - dev->DataBuf[1] = dev->Lock; - dev->DataReplyLeft = 2; - break; - - case CMD_MBENABLE: /* Mailbox interface enable Command */ - dev->DataReplyLeft = 0; - if (dev->CmdBuf[1] == dev->Lock) { - if (dev->CmdBuf[0] & 1) { - dev->Lock = 1; - } else { - dev->Lock = 0; - } - } - break; - - case 0x2C: /* AHA-1542CP sends this */ - dev->DataBuf[0] = 0x00; - dev->DataReplyLeft = 1; - break; - - case 0x33: /* AHA-1542CP sends this */ - dev->DataBuf[0] = 0x00; - dev->DataBuf[1] = 0x00; - dev->DataBuf[2] = 0x00; - dev->DataBuf[3] = 0x00; - dev->DataReplyLeft = 256; - break; - - default: + aha_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_WR_EEPROM: /* write EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = eeprom_cmd(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + &(dev->CmdBuf[3])); + if (dev->DataReplyLeft == 0xff) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; - break; - } + } + break; + + case CMD_RD_EEPROM: /* read EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = eeprom_cmd(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + dev->DataBuf); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case CMD_SHADOW_RAM: /* Shadow RAM */ + /* + * For AHA1542CF, this is the command + * to play with the Shadow RAM. BIOS + * gives us one argument (00,02,03) + * and expects a 0x04 back in the INTR + * register. --FvK + */ + dev->Interrupt = shram_cmd(dev, dev->CmdBuf[0]); + break; + + case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ + /* Sent by CF BIOS. */ + dev->Mbx24bit = 1; + + mbi = (MailboxInit_t *)dev->CmdBuf; + + dev->BIOSMailboxInit = 1; + dev->BIOSMailboxCount = mbi->Count; + dev->BIOSMailboxOutAddr = ADDR_TO_U32(mbi->Address); + + aha_log("Initialize BIOS Mailbox: MBO=0x%08lx, %d entries at 0x%08lx\n", + dev->BIOSMailboxOutAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + break; + + case CMD_MEM_MAP_1: /* AHA memory mapper */ + case CMD_MEM_MAP_2: /* AHA memory mapper */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = mmap_cmd(dev, dev->Command); + break; + + case CMD_EXTBIOS: /* Return extended BIOS information */ + dev->DataBuf[0] = 0x08; + dev->DataBuf[1] = dev->Lock; + dev->DataReplyLeft = 2; + break; + + case CMD_MBENABLE: /* Mailbox interface enable Command */ + dev->DataReplyLeft = 0; + if (dev->CmdBuf[1] == dev->Lock) { + if (dev->CmdBuf[0] & 1) + dev->Lock = 1; + else + dev->Lock = 0; + } + break; + + case 0x2c: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 1; + break; + + case 0x33: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataBuf[1] = 0x00; + dev->DataBuf[2] = 0x00; + dev->DataBuf[3] = 0x00; + dev->DataReplyLeft = 256; + break; + + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; } - return 0; + return(0); } static void -aha_setup_data(void *p) +setup_data(void *priv) { - x54x_t *dev = (x54x_t *)p; + x54x_t *dev = (x54x_t *)priv; ReplyInquireSetupInformation *ReplyISI; aha_setup_t *aha_setup; @@ -461,17 +462,17 @@ aha_setup_data(void *p) ReplyISI->fParityCheckingEnabled = dev->parity & 1; U32_TO_ADDR(aha_setup->BIOSMailboxAddress, dev->BIOSMailboxOutAddr); - aha_setup->uChecksum = 0xA3; - aha_setup->uUnknown = 0xC2; + aha_setup->uChecksum = 0xa3; + aha_setup->uUnknown = 0xc2; } static void -aha_do_bios_mail(x54x_t *dev) +do_bios_mail(x54x_t *dev) { dev->MailboxIsBIOS = 1; - if (!dev->BIOSMailboxCount) { + if (! dev->BIOSMailboxCount) { aha_log("aha_do_bios_mail(): No BIOS Mailboxes\n"); return; } @@ -485,12 +486,12 @@ aha_do_bios_mail(x54x_t *dev) static void -aha_callback(void *p) +call_back(void *priv) { - x54x_t *dev = (x54x_t *)p; + x54x_t *dev = (x54x_t *)priv; if (dev->BIOSMailboxInit && dev->BIOSMailboxReq) - aha_do_bios_mail(dev); + do_bios_mail(dev); } @@ -528,27 +529,27 @@ aha_mca_write(int port, uint8_t val, void *priv) /* Extract the BIOS ROM address info. */ if (! (dev->pos_regs[2] & 0x80)) switch(dev->pos_regs[3] & 0x38) { case 0x38: /* [1]=xx11 1xxx */ - dev->rom_addr = 0xDC000; + dev->rom_addr = 0xdc000; break; case 0x30: /* [1]=xx11 0xxx */ - dev->rom_addr = 0xD8000; + dev->rom_addr = 0xd8000; break; case 0x28: /* [1]=xx10 1xxx */ - dev->rom_addr = 0xD4000; + dev->rom_addr = 0xd4000; break; case 0x20: /* [1]=xx10 0xxx */ - dev->rom_addr = 0xD0000; + dev->rom_addr = 0xd0000; break; case 0x18: /* [1]=xx01 1xxx */ - dev->rom_addr = 0xCC000; + dev->rom_addr = 0xcc000; break; case 0x10: /* [1]=xx01 0xxx */ - dev->rom_addr = 0xC8000; + dev->rom_addr = 0xc8000; break; } else { /* Disabled. */ @@ -604,7 +605,7 @@ aha_mca_write(int port, uint8_t val, void *priv) /* Initialize the board's ROM BIOS. */ static void -aha_setbios(x54x_t *dev) +set_bios(x54x_t *dev) { uint32_t size; uint32_t mask; @@ -617,7 +618,7 @@ aha_setbios(x54x_t *dev) /* Open the BIOS image file and make sure it exists. */ aha_log("%s: loading BIOS from '%ls'\n", dev->name, dev->bios_path); - if ((f = rom_fopen(dev->bios_path)) == NULL) { + if ((f = plat_fopen(rom_path(dev->bios_path), L"rb")) == NULL) { aha_log("%s: BIOS ROM not found!\n", dev->name); return; } @@ -680,8 +681,8 @@ aha_setbios(x54x_t *dev) /* Map this system into the memory map. */ mem_mapping_add(&dev->bios.mapping, dev->rom_addr, size, - aha_mem_read, NULL, NULL, /* aha_mem_readw, aha_mem_readl, */ - aha_mem_write, NULL, NULL, + mem_read, NULL, NULL, /* aha_mem_readw, aha_mem_readl, */ + mem_write, NULL, NULL, dev->bios.rom, MEM_MAPPING_EXTERNAL, dev); mem_mapping_disable(&dev->bios.mapping); @@ -704,6 +705,7 @@ aha_setbios(x54x_t *dev) return; } dev->bios.rom[dev->rom_ioaddr] = (uint8_t)i; + /* Negation of the DIP switches to satify the checksum. */ dev->bios.rom[dev->rom_ioaddr + 1] = (uint8_t)((i ^ 0xff) + 1); } @@ -711,7 +713,7 @@ aha_setbios(x54x_t *dev) static void -aha_initnvr(x54x_t *dev) +init_nvr(x54x_t *dev) { /* Initialize the on-board EEPROM. */ dev->nvr[0] = dev->HostID; /* SCSI ID 7 */ @@ -729,7 +731,7 @@ aha_initnvr(x54x_t *dev) /* Initialize the board's EEPROM (NVR.) */ static void -aha_setnvr(x54x_t *dev) +set_nvr(x54x_t *dev) { FILE *f; @@ -740,13 +742,13 @@ aha_setnvr(x54x_t *dev) dev->nvr = (uint8_t *)malloc(NVR_SIZE); memset(dev->nvr, 0x00, NVR_SIZE); - f = nvr_fopen(dev->nvr_path, L"rb"); + f = plat_fopen(nvr_path(dev->nvr_path), L"rb"); if (f != NULL) { - fread(dev->nvr, 1, NVR_SIZE, f); + (void)fread(dev->nvr, 1, NVR_SIZE, f); fclose(f); f = NULL; } else { - aha_initnvr(dev); + init_nvr(dev); } } @@ -779,12 +781,12 @@ aha_init(const device_t *info) dev->bit32 = 0; dev->lba_bios = 0; - dev->ven_callback = aha_callback; - dev->ven_cmd_is_fast = aha_cmd_is_fast; - dev->ven_fast_cmds = aha_fast_cmds; - dev->get_ven_param_len = aha_param_len; + dev->ven_callback = call_back; + dev->ven_cmd_is_fast = cmd_is_fast; + dev->ven_fast_cmds = fast_cmds; + dev->get_ven_param_len = param_len; dev->ven_cmds = aha_cmds; - dev->get_ven_data = aha_setup_data; + dev->get_ven_data = setup_data; strcpy(dev->vendor, "Adaptec"); @@ -794,88 +796,86 @@ aha_init(const device_t *info) strcpy(dev->name, "AHA-154xB"); switch(dev->Base) { case 0x0330: - dev->bios_path = - L"roms/scsi/adaptec/aha1540b320_330.bin"; + dev->bios_path = AHA1540B_330_BIOS_PATH; break; case 0x0334: - dev->bios_path = - L"roms/scsi/adaptec/aha1540b320_334.bin"; + dev->bios_path = AHA1540B_334_BIOS_PATH; break; } dev->fw_rev = "A005"; /* The 3.2 microcode says A012. */ dev->HostID = device_get_config_int("hostid"); - dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shram = 0x3f80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->ha_bps = 5000000.0; /* normal SCSI */ break; case AHA_154xC: strcpy(dev->name, "AHA-154xC"); - dev->bios_path = L"roms/scsi/adaptec/aha1542c102.bin"; + dev->bios_path = AHA1540C_BIOS_PATH; dev->nvr_path = L"aha1542c.nvr"; dev->fw_rev = "D001"; - dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shram = 0x3f80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ - dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_ioaddr = 0x3f7e; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ - dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ - dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ - dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ven_get_host_id = get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = get_dma; /* function to return DMA channel from EEPROM */ dev->ha_bps = 5000000.0; /* normal SCSI */ break; case AHA_154xCF: strcpy(dev->name, "AHA-154xCF"); - dev->bios_path = L"roms/scsi/adaptec/aha1542cf211.bin"; + dev->bios_path = AHA1540CF_BIOS_PATH; dev->nvr_path = L"aha1542cf.nvr"; dev->fw_rev = "E001"; - dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shram = 0x3f80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ - dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_ioaddr = 0x3f7e; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ dev->cdrom_boot = 1; - dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ - dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ - dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ven_get_host_id = get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = get_dma; /* function to return DMA channel from EEPROM */ dev->ha_bps = 10000000.0; /* fast SCSI */ break; case AHA_154xCP: strcpy(dev->name, "AHA-154xCP"); - dev->bios_path = L"roms/scsi/adaptec/aha1542cp102.bin"; + dev->bios_path = AHA1540CP_BIOS_PATH; dev->nvr_path = L"aha1540cp.nvr"; dev->fw_rev = "F001"; - dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shram = 0x3f80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ - dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_ioaddr = 0x3f7e; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0055; /* firmware version (hi/lo) */ - dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ - dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ - dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ven_get_host_id = get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = get_dma; /* function to return DMA channel from EEPROM */ dev->ha_bps = 10000000.0; /* fast SCSI */ break; case AHA_1640: strcpy(dev->name, "AHA-1640"); - dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; + dev->bios_path = AHA1640_BIOS_PATH; dev->fw_rev = "BB01"; dev->lba_bios = 1; /* Enable MCA. */ - dev->pos_regs[0] = 0x1F; /* MCA board ID */ - dev->pos_regs[1] = 0x0F; + dev->pos_regs[0] = 0x1f; /* MCA board ID */ + dev->pos_regs[1] = 0x0f; mca_add(aha_mca_read, aha_mca_write, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ break; } /* Initialize ROM BIOS if needed. */ - aha_setbios(dev); + set_bios(dev); /* Initialize EEPROM (NVR) if needed. */ - aha_setnvr(dev); + set_nvr(dev); if (dev->Base != 0) { /* Initialize the device. */ diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index e5f09f9..07d7d05 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -13,7 +13,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.7 2018/03/27 + * Version: @(#)scsi_buslogic.c 1.0.8 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -66,6 +66,17 @@ #include "scsi_x54x.h" +#define BT542_BIOS_PATH L"scsi/buslogic/bt-542bh_bios.rom" +#define BT545_BIOS_PATH L"scsi/buslogic/bt-545s_bios.rom" +#define BT545_AUTO_BIOS_PATH L"scsi/buslogic/bt-545s_autoscsi.rom" +#define BT640A_BIOS_PATH L"scsi/buslogic/bt-640a_bios.rom" +#define BT445S_BIOS_PATH L"scsi/buslogic/bt-445s_bios.rom" +#define BT445S_AUTO_BIOS_PATH L"scsi/buslogic/bt-445s_autoscsi.rom" +#define BT958D_BIOS_PATH L"scsi/buslogic/bt-958d_bios.rom" +#define BT958D_AUTO_BIOS_PATH L"scsi/buslogic/bt-958d_autoscsi.rom" +#define BT958D_SCAM_BIOS_PATH L"scsi/buslogic/bt-958d_scam.rom" + + /* * Auto SCSI structure which is located * in host adapter RAM and contains several @@ -77,15 +88,15 @@ typedef struct { uint8_t cbInformation; uint8_t aHostAdaptertype[6]; uint8_t uReserved1; - uint8_t fFloppyEnabled :1, - fFloppySecondary :1, - fLevelSensitiveInterrupt:1, - uReserved2 :2, - uSystemRAMAreForBIOS :3; - uint8_t uDMAChannel :7, - fDMAAutoConfiguration :1, - uIrqChannel :7, - fIrqAutoConfiguration :1; + uint8_t fFloppyEnabled : 1, + fFloppySecondary : 1, + fLevelSensitiveInterrupt : 1, + uReserved2 : 2, + uSystemRAMAreForBIOS : 3; + uint8_t uDMAChannel : 7, + fDMAAutoConfiguration : 1, + uIrqChannel : 7, + fIrqAutoConfiguration : 1; uint8_t uDMATransferRate; uint8_t uSCSIId; uint8_t uSCSIConfiguration; @@ -99,36 +110,36 @@ typedef struct { uint16_t u16DisconnectPermittedMask; uint16_t u16SendStartUnitCommandMask; uint16_t u16IgnoreInBIOSScanMask; - unsigned char uPCIInterruptPin : 2; - unsigned char uHostAdapterIoPortAddress : 2; - uint8_t fRoundRobinScheme : 1; - uint8_t fVesaBusSpeedGreaterThan33MHz : 1; - uint8_t fVesaBurstWrite : 1; - uint8_t fVesaBurstRead : 1; - uint16_t u16UltraPermittedMask; - uint32_t uReserved5; - uint8_t uReserved6; - uint8_t uAutoSCSIMaximumLUN; - uint8_t fReserved7 : 1; - uint8_t fSCAMDominant : 1; - uint8_t fSCAMenabled : 1; - uint8_t fSCAMLevel2 : 1; - unsigned char uReserved8 : 4; - uint8_t fInt13Extension : 1; - uint8_t fReserved9 : 1; - uint8_t fCDROMBoot : 1; - unsigned char uReserved10 : 2; - uint8_t fMultiBoot : 1; - unsigned char uReserved11 : 2; - unsigned char uBootTargetId : 4; - unsigned char uBootChannel : 4; - uint8_t fForceBusDeviceScanningOrder : 1; - unsigned char uReserved12 : 7; - uint16_t u16NonTaggedToAlternateLunPermittedMask; - uint16_t u16RenegotiateSyncAfterCheckConditionMask; - uint8_t aReserved14[10]; - uint8_t aManufacturingDiagnostic[2]; - uint16_t u16Checksum; + uint8_t uPCIInterruptPin : 2, + uHostAdapterIoPortAddress : 2, + fRoundRobinScheme : 1, + fVesaBusSpeedGreaterThan33MHz : 1, + fVesaBurstWrite : 1, + fVesaBurstRead : 1; + uint16_t u16UltraPermittedMask; + uint32_t uReserved5; + uint8_t uReserved6; + uint8_t uAutoSCSIMaximumLUN; + uint8_t fReserved7 : 1, + fSCAMDominant : 1, + fSCAMenabled : 1, + fSCAMLevel2 : 1, + uReserved8 : 4; + uint8_t fInt13Extension : 1, + fReserved9 : 1, + fCDROMBoot : 1, + uReserved10 : 2, + fMultiBoot : 1, + uReserved11 : 2; + uint8_t uBootTargetId : 4, + uBootChannel : 4; + uint8_t fForceBusDeviceScanningOrder : 1, + uReserved12 : 7; + uint16_t u16NonTaggedToAlternateLunPermittedMask; + uint16_t u16RenegotiateSyncAfterCheckConditionMask; + uint8_t aReserved14[10]; + uint8_t aManufacturingDiagnostic[2]; + uint16_t u16Checksum; } AutoSCSIRam; #pragma pack(pop) @@ -199,26 +210,16 @@ typedef struct { #pragma pack(pop) #pragma pack(push,1) -typedef struct -{ - /** Data length. */ - uint32_t DataLength; - /** Data pointer. */ - uint32_t DataPointer; - /** The device the request is sent to. */ - uint8_t TargetId; - /** The LUN in the device. */ - uint8_t LogicalUnit; - /** Reserved */ - unsigned char Reserved1 : 3; - /** Data direction for the request. */ - unsigned char DataDirection : 2; - /** Reserved */ - unsigned char Reserved2 : 3; - /** Length of the SCSI CDB. */ - uint8_t CDBLength; - /** The SCSI CDB. (A CDB can be 12 bytes long.) */ - uint8_t CDB[12]; +typedef struct { + uint32_t DataLength; /* data length */ + uint32_t DataPointer; /* data pointer */ + uint8_t TargetId; /* device request is sent to */ + uint8_t LogicalUnit; /* LUN in the device */ + uint8_t Reserved1 : 3, /* reserved */ + DataDirection : 2, /* data direction for the request */ + Reserved2 : 3; /* reserved */ + uint8_t CDBLength; /* length of the SCSI CDB */ + uint8_t CDB[12]; /* the SCSI CDB */ } ESCMD; #pragma pack(pop) @@ -279,181 +280,198 @@ buslogic_log(const char *fmt, ...) static wchar_t * -BuslogicGetNVRFileName(buslogic_data_t *bl) +GetNVRFileName(buslogic_data_t *bl) { - switch(bl->chip) - { - case CHIP_BUSLOGIC_ISA_542: - return L"bt542bh.nvr"; - case CHIP_BUSLOGIC_ISA: - return L"bt545s.nvr"; - case CHIP_BUSLOGIC_MCA: - return L"bt640a.nvr"; - case CHIP_BUSLOGIC_VLB: - return L"bt445s.nvr"; - case CHIP_BUSLOGIC_PCI: - return L"bt958d.nvr"; - default: - fatal("Unrecognized BusLogic chip: %i\n", bl->chip); - return NULL; - } + switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + return L"bt542bh.nvr"; + + case CHIP_BUSLOGIC_ISA: + return L"bt545s.nvr"; + + case CHIP_BUSLOGIC_MCA: + return L"bt640a.nvr"; + + case CHIP_BUSLOGIC_VLB: + return L"bt445s.nvr"; + + case CHIP_BUSLOGIC_PCI: + return L"bt958d.nvr"; + + default: + fatal("Unrecognized BusLogic chip: %i\n", bl->chip); + return NULL; + } } static void -BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) +AutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) { buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - HALocalRAM *HALR = &bl->LocalRAM; + HALocalRAM *halr = &bl->LocalRAM; - memset(&(HALR->structured.autoSCSIData), 0, sizeof(AutoSCSIRam)); + memset(&(halr->structured.autoSCSIData), 0, sizeof(AutoSCSIRam)); - HALR->structured.autoSCSIData.aInternalSignature[0] = 'F'; - HALR->structured.autoSCSIData.aInternalSignature[1] = 'A'; + halr->structured.autoSCSIData.aInternalSignature[0] = 'F'; + halr->structured.autoSCSIData.aInternalSignature[1] = 'A'; - HALR->structured.autoSCSIData.cbInformation = 64; + halr->structured.autoSCSIData.cbInformation = 64; - HALR->structured.autoSCSIData.uReserved1 = 6; + halr->structured.autoSCSIData.uReserved1 = 6; - HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; - HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; + halr->structured.autoSCSIData.aHostAdaptertype[0] = ' '; + halr->structured.autoSCSIData.aHostAdaptertype[5] = ' '; switch (bl->chip) { case CHIP_BUSLOGIC_ISA_542: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); + memcpy(&(halr->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); break; + case CHIP_BUSLOGIC_ISA: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "545S", 4); + memcpy(&(halr->structured.autoSCSIData.aHostAdaptertype[1]), "545S", 4); break; + case CHIP_BUSLOGIC_MCA: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); + memcpy(&(halr->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); break; + case CHIP_BUSLOGIC_VLB: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "445S", 4); + memcpy(&(halr->structured.autoSCSIData.aHostAdaptertype[1]), "445S", 4); break; + case CHIP_BUSLOGIC_PCI: - memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "958D", 4); + memcpy(&(halr->structured.autoSCSIData.aHostAdaptertype[1]), "958D", 4); break; } - HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; - HALR->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; + halr->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + halr->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; if (bl->chip != CHIP_BUSLOGIC_PCI) { switch(dev->DmaChannel) { case 5: - HALR->structured.autoSCSIData.uDMAChannel = 1; + halr->structured.autoSCSIData.uDMAChannel = 1; break; + case 6: - HALR->structured.autoSCSIData.uDMAChannel = 2; + halr->structured.autoSCSIData.uDMAChannel = 2; break; + case 7: - HALR->structured.autoSCSIData.uDMAChannel = 3; + halr->structured.autoSCSIData.uDMAChannel = 3; break; + default: - HALR->structured.autoSCSIData.uDMAChannel = 0; + + halr->structured.autoSCSIData.uDMAChannel = 0; break; } } - HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + halr->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; if (bl->chip != CHIP_BUSLOGIC_PCI) { switch(dev->Irq) { case 9: - HALR->structured.autoSCSIData.uIrqChannel = 1; + halr->structured.autoSCSIData.uIrqChannel = 1; break; + case 10: - HALR->structured.autoSCSIData.uIrqChannel = 2; + halr->structured.autoSCSIData.uIrqChannel = 2; break; + case 11: - HALR->structured.autoSCSIData.uIrqChannel = 3; + halr->structured.autoSCSIData.uIrqChannel = 3; break; + case 12: - HALR->structured.autoSCSIData.uIrqChannel = 4; + halr->structured.autoSCSIData.uIrqChannel = 4; break; + case 14: - HALR->structured.autoSCSIData.uIrqChannel = 5; + halr->structured.autoSCSIData.uIrqChannel = 5; break; + case 15: - HALR->structured.autoSCSIData.uIrqChannel = 6; + halr->structured.autoSCSIData.uIrqChannel = 6; break; + default: - HALR->structured.autoSCSIData.uIrqChannel = 0; + halr->structured.autoSCSIData.uIrqChannel = 0; break; } } - HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + halr->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; - HALR->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + halr->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; - HALR->structured.autoSCSIData.uSCSIId = 7; - HALR->structured.autoSCSIData.uSCSIConfiguration = 0x3F; - HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; - HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; - HALR->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; + halr->structured.autoSCSIData.uSCSIId = 7; + halr->structured.autoSCSIData.uSCSIConfiguration = 0x3F; + halr->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; + halr->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; + halr->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; if (!safe) - HALR->structured.autoSCSIData.uBIOSConfiguration |= 0x04; + halr->structured.autoSCSIData.uBIOSConfiguration |= 0x04; - HALR->structured.autoSCSIData.u16DeviceEnabledMask = 0xffff; - HALR->structured.autoSCSIData.u16WidePermittedMask = 0xffff; - HALR->structured.autoSCSIData.u16FastPermittedMask = 0xffff; - HALR->structured.autoSCSIData.u16DisconnectPermittedMask = 0xffff; + halr->structured.autoSCSIData.u16DeviceEnabledMask = 0xffff; + halr->structured.autoSCSIData.u16WidePermittedMask = 0xffff; + halr->structured.autoSCSIData.u16FastPermittedMask = 0xffff; + halr->structured.autoSCSIData.u16DisconnectPermittedMask = 0xffff; - HALR->structured.autoSCSIData.uPCIInterruptPin = PCI_INTA; - HALR->structured.autoSCSIData.fVesaBusSpeedGreaterThan33MHz = 1; + halr->structured.autoSCSIData.uPCIInterruptPin = PCI_INTA; + halr->structured.autoSCSIData.fVesaBusSpeedGreaterThan33MHz = 1; - HALR->structured.autoSCSIData.uAutoSCSIMaximumLUN = 7; + halr->structured.autoSCSIData.uAutoSCSIMaximumLUN = 7; - HALR->structured.autoSCSIData.fForceBusDeviceScanningOrder = 1; - HALR->structured.autoSCSIData.fInt13Extension = safe ? 0 : 1; - HALR->structured.autoSCSIData.fCDROMBoot = safe ? 0 : 1; - HALR->structured.autoSCSIData.fMultiBoot = safe ? 0 : 1; - HALR->structured.autoSCSIData.fRoundRobinScheme = safe ? 1 : 0; /* 1 = aggressive, 0 = strict */ + halr->structured.autoSCSIData.fForceBusDeviceScanningOrder = 1; + halr->structured.autoSCSIData.fInt13Extension = safe ? 0 : 1; + halr->structured.autoSCSIData.fCDROMBoot = safe ? 0 : 1; + halr->structured.autoSCSIData.fMultiBoot = safe ? 0 : 1; + halr->structured.autoSCSIData.fRoundRobinScheme = safe ? 1 : 0; /* 1 = aggressive, 0 = strict */ - HALR->structured.autoSCSIData.uHostAdapterIoPortAddress = 2; /* 0 = primary (330h), 1 = secondary (334h), 2 = disable, 3 = reserved */ + halr->structured.autoSCSIData.uHostAdapterIoPortAddress = 2; /* 0 = primary (330h), 1 = secondary (334h), 2 = disable, 3 = reserved */ } static void -BuslogicInitializeAutoSCSIRam(x54x_t *dev) +InitializeAutoSCSIRam(x54x_t *dev) { buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - HALocalRAM *HALR = &bl->LocalRAM; + HALocalRAM *halr = &bl->LocalRAM; FILE *f; - f = nvr_fopen(BuslogicGetNVRFileName(bl), L"rb"); - if (f) - { - fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + f = plat_fopen(nvr_path(GetNVRFileName(bl)), L"rb"); + if (f != NULL) { + (void)fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); fclose(f); f = NULL; if (bl->chip == CHIP_BUSLOGIC_PCI) { x54x_io_remove(dev, dev->Base, 4); - switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { + switch(halr->structured.autoSCSIData.uHostAdapterIoPortAddress) { case 0: dev->Base = 0x330; break; + case 1: dev->Base = 0x334; break; + default: dev->Base = 0; break; } x54x_io_set(dev, dev->Base, 4); } - } - else - { - BuslogicAutoSCSIRamSetDefaults(dev, 0); + } else { + AutoSCSIRamSetDefaults(dev, 0); } } static void -buslogic_cmd_phase1(void *p) +cmd_phase1(void *priv) { - x54x_t *dev = (x54x_t *)p; + x54x_t *dev = (x54x_t *)priv; if ((dev->CmdParam == 2) && (dev->Command == 0x90)) { dev->CmdParamLeft = dev->CmdBuf[1]; @@ -476,63 +494,59 @@ buslogic_cmd_phase1(void *p) static uint8_t -buslogic_get_host_id(void *p) +get_host_id(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - - HALocalRAM *HALR = &bl->LocalRAM; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; + HALocalRAM *halr = &bl->LocalRAM; if (bl->chip == CHIP_BUSLOGIC_ISA_542) return dev->HostID; else - return HALR->structured.autoSCSIData.uSCSIId; + return halr->structured.autoSCSIData.uSCSIId; } static uint8_t -buslogic_get_irq(void *p) +get_irq(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; uint8_t bl_irq[7] = { 0, 9, 10, 11, 12, 14, 15 }; - - HALocalRAM *HALR = &bl->LocalRAM; + HALocalRAM *halr = &bl->LocalRAM; if (bl->chip == CHIP_BUSLOGIC_PCI) return dev->Irq; else - return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; + return bl_irq[halr->structured.autoSCSIData.uIrqChannel]; } static uint8_t -buslogic_get_dma(void *p) +get_dma(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; uint8_t bl_dma[4] = { 0, 5, 6, 7 }; - - HALocalRAM *HALR = &bl->LocalRAM; + HALocalRAM *halr = &bl->LocalRAM; if (bl->chip == CHIP_BUSLOGIC_PCI) return (dev->Base ? 7 : 0); else - return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; + return bl_dma[halr->structured.autoSCSIData.uDMAChannel]; } static uint8_t -buslogic_param_len(void *p) +param_len(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; switch (dev->Command) { case 0x21: return 5; + case 0x25: case 0x8B: case 0x8C: @@ -541,33 +555,43 @@ buslogic_param_len(void *p) case 0x92: case 0x96: return 1; + case 0x81: return sizeof(MailboxInitExtended_t); + case 0x83: return 12; + case 0x90: case 0x91: return 2; + case 0x94: return 3; + case 0x93: /* Valid only for VLB */ return (bl->chip == CHIP_BUSLOGIC_VLB) ? 1 : 0; + case 0x95: /* Valid only for PCI */ return (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + case 0x97: /* Valid only for PCI */ case 0xA7: /* Valid only for PCI */ return (bl->chip == CHIP_BUSLOGIC_PCI) ? 10 : 0; + case 0xA8: /* Valid only for PCI */ case 0xA9: /* Valid only for PCI */ return (bl->chip == CHIP_BUSLOGIC_PCI) ? 4 : 0; default: - return 0; + break; } + + return 0; } static void -BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int dir) +SCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int dir) { uint32_t DataPointer = ESCSICmd->DataPointer; uint32_t DataLength = ESCSICmd->DataLength; @@ -576,11 +600,11 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int if (ESCSICmd->DataDirection == 0x03) { /* Non-data command. */ - buslogic_log("BuslogicSCSIBIOSDMATransfer(): Non-data control byte\n"); + buslogic_log("SCSIBIOSDMATransfer(): Non-data control byte\n"); return; } - buslogic_log("BuslogicSCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); + buslogic_log("SCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both read/write commands. */ @@ -600,7 +624,7 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int static void -BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) +SCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) { ESCMD *ESCSICmd = (ESCMD *)CmdBuf; uint32_t i; @@ -663,7 +687,7 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u if (phase != SCSI_PHASE_STATUS) { if (phase == SCSI_PHASE_DATA_IN) scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, (phase == SCSI_PHASE_DATA_OUT)); + SCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, (phase == SCSI_PHASE_DATA_OUT)); if (phase == SCSI_PHASE_DATA_OUT) scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); } @@ -685,13 +709,11 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u static uint8_t -buslogic_cmds(void *p) +buslogic_cmds(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - - HALocalRAM *HALR = &bl->LocalRAM; - + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; + HALocalRAM *halr = &bl->LocalRAM; FILE *f; uint16_t TargetsPresentMask = 0; uint32_t Offset; @@ -707,37 +729,42 @@ buslogic_cmds(void *p) dev->DataReplyLeft = 0; x54x_reset_ctrl(dev, 1); break; + case 0x21: if (dev->CmdParam == 1) dev->CmdParamLeft = dev->CmdBuf[0]; dev->DataReplyLeft = 0; break; + case 0x23: memset(dev->DataBuf, 0, 8); for (i = 8; i < 15; i++) { dev->DataBuf[i-8] = 0; for (j=0; j<8; j++) { - if (scsi_device_present(i, j) && (i != buslogic_get_host_id(dev))) + if (scsi_device_present(i, j) && (i != get_host_id(dev))) dev->DataBuf[i-8] |= (1<DataReplyLeft = 8; break; + case 0x24: for (i=0; i<15; i++) { - if (scsi_device_present(i, 0) && (i != buslogic_get_host_id(dev))) + if (scsi_device_present(i, 0) && (i != get_host_id(dev))) TargetsPresentMask |= (1 << i); } dev->DataBuf[0] = TargetsPresentMask & 0xFF; dev->DataBuf[1] = TargetsPresentMask >> 8; dev->DataReplyLeft = 2; break; + case 0x25: if (dev->CmdBuf[0] == 0) dev->IrqEnabled = 0; else dev->IrqEnabled = 1; return 1; + case 0x81: dev->Mbx24bit = 0; @@ -756,19 +783,22 @@ buslogic_cmds(void *p) dev->Status &= ~STAT_INIT; dev->DataReplyLeft = 0; break; + case 0x83: if (dev->CmdParam == 12) { dev->CmdParamLeft = dev->CmdBuf[11]; buslogic_log("Execute SCSI BIOS Command: %u more bytes follow\n", dev->CmdParamLeft); } else { buslogic_log("Execute SCSI BIOS Command: received %u bytes\n", dev->CmdBuf[0]); - BuslogicSCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); + SCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); } break; + case 0x84: dev->DataBuf[0] = dev->fw_rev[4]; dev->DataReplyLeft = 1; break; + case 0x85: if (strlen(dev->fw_rev) == 6) dev->DataBuf[0] = dev->fw_rev[5]; @@ -776,6 +806,7 @@ buslogic_cmds(void *p) dev->DataBuf[0] = ' '; dev->DataReplyLeft = 1; break; + case 0x86: if (bl->chip == CHIP_BUSLOGIC_PCI) { ReplyPI = (BuslogicPCIInformation_t *) dev->DataBuf; @@ -785,21 +816,27 @@ buslogic_cmds(void *p) case 0x330: ReplyPI->IsaIOPort = 0; break; + case 0x334: ReplyPI->IsaIOPort = 1; break; + case 0x230: ReplyPI->IsaIOPort = 2; break; + case 0x234: ReplyPI->IsaIOPort = 3; break; + case 0x130: ReplyPI->IsaIOPort = 4; break; + case 0x134: ReplyPI->IsaIOPort = 5; break; + default: ReplyPI->IsaIOPort = 6; break; @@ -811,6 +848,7 @@ buslogic_cmds(void *p) dev->Status |= STAT_INVCMD; } break; + case 0x8B: /* The reply length is set by the guest and is found in the first byte of the command buffer. */ dev->DataReplyLeft = dev->CmdBuf[0]; @@ -823,10 +861,12 @@ buslogic_cmds(void *p) memcpy(dev->DataBuf, &(bl->LocalRAM.structured.autoSCSIData.aHostAdaptertype[1]), cCharsToTransfer); break; + case 0x8C: dev->DataReplyLeft = dev->CmdBuf[0]; memset(dev->DataBuf, 0, dev->DataReplyLeft); break; + case 0x8D: dev->DataReplyLeft = dev->CmdBuf[0]; ReplyIESI = (ReplyInquireExtendedSetupInformation *)dev->DataBuf; @@ -836,13 +876,15 @@ buslogic_cmds(void *p) case CHIP_BUSLOGIC_ISA_542: case CHIP_BUSLOGIC_ISA: case CHIP_BUSLOGIC_VLB: - ReplyIESI->uBusType = 'A'; /* ISA style */ + ReplyIESI->uBusType = 'A'; /* ISA style */ break; + case CHIP_BUSLOGIC_MCA: - ReplyIESI->uBusType = 'M'; /* MCA style */ + ReplyIESI->uBusType = 'M'; /* MCA style */ break; + case CHIP_BUSLOGIC_PCI: - ReplyIESI->uBusType = 'E'; /* PCI style */ + ReplyIESI->uBusType = 'E'; /* PCI style */ break; } ReplyIESI->uBiosAddress = 0xd8; @@ -857,11 +899,13 @@ buslogic_cmds(void *p) memcpy(ReplyIESI->aFirmwareRevision, &(dev->fw_rev[strlen(dev->fw_rev) - 3]), sizeof(ReplyIESI->aFirmwareRevision)); buslogic_log("Return Extended Setup Information: %d\n", dev->CmdBuf[0]); break; + case 0x8F: bl->fAggressiveRoundRobinMode = dev->CmdBuf[0] & 1; dev->DataReplyLeft = 0; break; + case 0x90: buslogic_log("Store Local RAM\n"); Offset = dev->CmdBuf[0]; @@ -870,6 +914,7 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; + case 0x91: buslogic_log("Fetch Local RAM\n"); Offset = dev->CmdBuf[0]; @@ -878,12 +923,14 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; + case 0x93: if (bl->chip != CHIP_BUSLOGIC_VLB) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; } + case 0x92: if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { dev->DataReplyLeft = 0; @@ -896,19 +943,22 @@ buslogic_cmds(void *p) switch (dev->CmdBuf[0]) { case 0: case 2: - BuslogicAutoSCSIRamSetDefaults(dev, 0); + AutoSCSIRamSetDefaults(dev, 0); break; + case 3: - BuslogicAutoSCSIRamSetDefaults(dev, 3); + AutoSCSIRamSetDefaults(dev, 3); break; + case 1: - f = nvr_fopen(BuslogicGetNVRFileName(bl), L"wb"); - if (f) { - fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + f = plat_fopen(nvr_path(GetNVRFileName(bl)), L"wb"); + if (f != NULL) { + (void)fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); fclose(f); f = NULL; } break; + default: dev->Status |= STAT_INVCMD; break; @@ -916,13 +966,15 @@ buslogic_cmds(void *p) if ((bl->chip == CHIP_BUSLOGIC_PCI) && !(dev->Status & STAT_INVCMD)) { x54x_io_remove(dev, dev->Base, 4); - switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { + switch(halr->structured.autoSCSIData.uHostAdapterIoPortAddress) { case 0: dev->Base = 0x330; break; + case 1: dev->Base = 0x334; break; + default: dev->Base = 0; break; @@ -930,6 +982,7 @@ buslogic_cmds(void *p) x54x_io_set(dev, dev->Base, 4); } break; + case 0x94: if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { dev->DataReplyLeft = 0; @@ -949,6 +1002,7 @@ buslogic_cmds(void *p) buslogic_log("Returning AutoSCSI ROM (%04X %04X %04X %04X)\n", dev->DataBuf[0], dev->DataBuf[1], dev->DataBuf[2], dev->DataBuf[3]); } break; + case 0x95: if (bl->chip == CHIP_BUSLOGIC_PCI) { if (dev->Base != 0) @@ -965,6 +1019,7 @@ buslogic_cmds(void *p) dev->Status |= STAT_INVCMD; } break; + case 0x96: if (dev->CmdBuf[0] == 0) bl->ExtendedLUNCCBFormat = 0; @@ -973,11 +1028,13 @@ buslogic_cmds(void *p) dev->DataReplyLeft = 0; break; + case 0x97: case 0xA7: /* TODO: Actually correctly implement this whole SCSI BIOS Flash stuff. */ dev->DataReplyLeft = 0; break; + case 0xA8: if (bl->chip != CHIP_BUSLOGIC_PCI) { dev->DataReplyLeft = 0; @@ -997,6 +1054,7 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; + case 0xA9: if (bl->chip != CHIP_BUSLOGIC_PCI) { dev->DataReplyLeft = 0; @@ -1017,47 +1075,51 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; + default: dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; } + return 0; } static void -buslogic_setup_data(void *p) +setup_data(void *priv) { - x54x_t *dev = (x54x_t *)p; + x54x_t *dev = (x54x_t *)priv; ReplyInquireSetupInformation *ReplyISI; buslogic_setup_t *bl_setup; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - HALocalRAM *HALR = &bl->LocalRAM; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; + HALocalRAM *halr = &bl->LocalRAM; ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; bl_setup = (buslogic_setup_t *)ReplyISI->VendorSpecificData; - ReplyISI->fSynchronousInitiationEnabled = HALR->structured.autoSCSIData.u16SynchronousPermittedMask ? 1 : 0; - ReplyISI->fParityCheckingEnabled = (HALR->structured.autoSCSIData.uSCSIConfiguration & 2) ? 1 : 0; + ReplyISI->fSynchronousInitiationEnabled = halr->structured.autoSCSIData.u16SynchronousPermittedMask ? 1 : 0; + ReplyISI->fParityCheckingEnabled = (halr->structured.autoSCSIData.uSCSIConfiguration & 2) ? 1 : 0; bl_setup->uSignature = 'B'; /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too * friendly with Adaptec hardware and upsetting the HBA state. */ bl_setup->uCharacterD = 'D'; /* BusLogic model. */ - switch(bl->chip) - { + switch(bl->chip) { case CHIP_BUSLOGIC_ISA_542: case CHIP_BUSLOGIC_ISA: bl_setup->uHostBusType = 'A'; break; + case CHIP_BUSLOGIC_MCA: bl_setup->uHostBusType = 'B'; break; + case CHIP_BUSLOGIC_VLB: bl_setup->uHostBusType = 'E'; break; + case CHIP_BUSLOGIC_PCI: bl_setup->uHostBusType = 'F'; break; @@ -1066,20 +1128,20 @@ buslogic_setup_data(void *p) static uint8_t -buslogic_is_aggressive_mode(void *p) +is_aggressive_mode(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; return bl->fAggressiveRoundRobinMode; } static uint8_t -buslogic_interrupt_type(void *p) +interrupt_type(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) return 0; @@ -1089,10 +1151,10 @@ buslogic_interrupt_type(void *p) static void -buslogic_reset(void *p) +buslogic_reset(void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; bl->ExtendedLUNCCBFormat = 0; } @@ -1103,7 +1165,7 @@ bar_t buslogic_pci_bar[3]; static void -BuslogicBIOSUpdate(buslogic_data_t *bl) +BIOSUpdate(buslogic_data_t *bl) { int bios_enabled = buslogic_pci_bar[2].addr_regs[0] & 0x01; @@ -1123,80 +1185,108 @@ BuslogicBIOSUpdate(buslogic_data_t *bl) } } + static uint8_t -BuslogicPCIRead(int func, int addr, void *p) +PCIRead(int func, int addr, void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; buslogic_log("BT-958D: Reading register %02X\n", addr & 0xff); switch (addr) { case 0x00: return 0x4b; + case 0x01: return 0x10; + case 0x02: return 0x40; + case 0x03: return 0x10; + case 0x04: return buslogic_pci_regs[0x04] & 0x03; /*Respond to IO and memory accesses*/ + case 0x05: return 0; + case 0x07: return 2; + case 0x08: return 1; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + case 0x0A: return 0; /*Subclass*/ + case 0x0B: return 1; /*Class code*/ + case 0x0E: return 0; /*Header type */ + case 0x10: return (buslogic_pci_bar[0].addr_regs[0] & 0xe0) | 1; /*I/O space*/ + case 0x11: return buslogic_pci_bar[0].addr_regs[1]; + case 0x12: return buslogic_pci_bar[0].addr_regs[2]; + case 0x13: return buslogic_pci_bar[0].addr_regs[3]; + case 0x14: return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + case 0x15: return buslogic_pci_bar[1].addr_regs[1]; + case 0x16: return buslogic_pci_bar[1].addr_regs[2]; + case 0x17: return buslogic_pci_bar[1].addr_regs[3]; + case 0x2C: return 0x4b; + case 0x2D: return 0x10; + case 0x2E: return 0x40; + case 0x2F: return 0x10; + case 0x30: /* PCI_ROMBAR */ buslogic_log("BT-958D: BIOS BAR 00 = %02X\n", buslogic_pci_bar[2].addr_regs[0] & 0x01); return buslogic_pci_bar[2].addr_regs[0] & 0x01; + + case 0x31: /* PCI_ROMBAR 15:11 */ buslogic_log("BT-958D: BIOS BAR 01 = %02X\n", (buslogic_pci_bar[2].addr_regs[1] & bl->bios_mask)); return buslogic_pci_bar[2].addr_regs[1]; - break; + case 0x32: /* PCI_ROMBAR 23:16 */ buslogic_log("BT-958D: BIOS BAR 02 = %02X\n", buslogic_pci_bar[2].addr_regs[2]); return buslogic_pci_bar[2].addr_regs[2]; - break; + case 0x33: /* PCI_ROMBAR 31:24 */ buslogic_log("BT-958D: BIOS BAR 03 = %02X\n", buslogic_pci_bar[2].addr_regs[3]); return buslogic_pci_bar[2].addr_regs[3]; - break; + case 0x3C: return dev->Irq; + case 0x3D: return PCI_INTA; } @@ -1206,11 +1296,10 @@ BuslogicPCIRead(int func, int addr, void *p) static void -BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) +PCIWrite(int func, int addr, uint8_t val, void *priv) { - x54x_t *dev = (x54x_t *)p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; uint8_t valxor; buslogic_log("BT-958D: Write value %02X to register %02X\n", val, addr & 0xff); @@ -1284,7 +1373,7 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) buslogic_pci_bar[2].addr &= 0xffffc001; bl->bios_addr = buslogic_pci_bar[2].addr & 0xffffc000; buslogic_log("BT-958D: BIOS BAR %02X = NOW %02X (%02X)\n", addr & 3, buslogic_pci_bar[2].addr_regs[addr & 3], val); - BuslogicBIOSUpdate(bl); + BIOSUpdate(bl); return; case 0x3C: @@ -1300,7 +1389,7 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) static void -BuslogicInitializeLocalRAM(buslogic_data_t *bl) +InitializeLocalRAM(buslogic_data_t *bl) { memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); if (bl->chip == CHIP_BUSLOGIC_PCI) { @@ -1332,9 +1421,8 @@ static void buslogic_mca_write(int port, uint8_t val, void *priv) { x54x_t *dev = (x54x_t *) priv; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - - HALocalRAM *HALR = &bl->LocalRAM; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; + HALocalRAM *halr = &bl->LocalRAM; /* MCA does not write registers below 0x0100. */ if (port < 0x0102) return; @@ -1359,35 +1447,35 @@ buslogic_mca_write(int port, uint8_t val, void *priv) /* Extract the BIOS ROM address info. */ if (dev->pos_regs[2] & 0xe0) switch(dev->pos_regs[2] & 0xe0) { - case 0xe0: /* [0]=111x xxxx */ + case 0xe0: /* [0]=111x xxxx */ bl->bios_addr = 0xDC000; break; - case 0x00: /* [0]=000x xxxx */ + case 0x00: /* [0]=000x xxxx */ bl->bios_addr = 0; break; - case 0xc0: /* [0]=110x xxxx */ + case 0xc0: /* [0]=110x xxxx */ bl->bios_addr = 0xD8000; break; - case 0xa0: /* [0]=101x xxxx */ + case 0xa0: /* [0]=101x xxxx */ bl->bios_addr = 0xD4000; break; - case 0x80: /* [0]=100x xxxx */ + case 0x80: /* [0]=100x xxxx */ bl->bios_addr = 0xD0000; break; - case 0x60: /* [0]=011x xxxx */ + case 0x60: /* [0]=011x xxxx */ bl->bios_addr = 0xCC000; break; - case 0x40: /* [0]=010x xxxx */ + case 0x40: /* [0]=010x xxxx */ bl->bios_addr = 0xC8000; break; - case 0x20: /* [0]=001x xxxx */ + case 0x20: /* [0]=001x xxxx */ bl->bios_addr = 0xC4000; break; } else { @@ -1412,15 +1500,15 @@ buslogic_mca_write(int port, uint8_t val, void *priv) * DOS Disk Space > 1GBytes is pos[2] = xxxx1xxx. */ /* Parity. */ - HALR->structured.autoSCSIData.uSCSIConfiguration &= ~2; - HALR->structured.autoSCSIData.uSCSIConfiguration |= (dev->pos_regs[4] & 2); + halr->structured.autoSCSIData.uSCSIConfiguration &= ~2; + halr->structured.autoSCSIData.uSCSIConfiguration |= (dev->pos_regs[4] & 2); /* Sync. */ - HALR->structured.autoSCSIData.u16SynchronousPermittedMask = (dev->pos_regs[4] & 0x10) ? 0xffff : 0x0000; + halr->structured.autoSCSIData.u16SynchronousPermittedMask = (dev->pos_regs[4] & 0x10) ? 0xffff : 0x0000; /* DOS Disk Space > 1GBytes */ - HALR->structured.autoSCSIData.uBIOSConfiguration &= ~4; - HALR->structured.autoSCSIData.uBIOSConfiguration |= (dev->pos_regs[4] & 8) ? 4 : 0; + halr->structured.autoSCSIData.uBIOSConfiguration &= ~4; + halr->structured.autoSCSIData.uBIOSConfiguration |= (dev->pos_regs[4] & 8) ? 4 : 0; /* * The PS/2 Model 80 BIOS always enables a card if it finds one, @@ -1453,15 +1541,15 @@ buslogic_mca_write(int port, uint8_t val, void *priv) void -BuslogicDeviceReset(void *p) +BuslogicDeviceReset(void *priv) { - x54x_t *dev = (x54x_t *) p; - buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + x54x_t *dev = (x54x_t *)priv; + buslogic_data_t *bl = (buslogic_data_t *)dev->ven_data; x54x_device_reset(dev); - BuslogicInitializeLocalRAM(bl); - BuslogicInitializeAutoSCSIRam(dev); + InitializeLocalRAM(bl); + InitializeAutoSCSIRam(dev); } @@ -1488,7 +1576,7 @@ buslogic_init(const device_t *info) dev->ven_data = malloc(sizeof(buslogic_data_t)); memset(dev->ven_data, 0x00, sizeof(buslogic_data_t)); - bl = (buslogic_data_t *) dev->ven_data; + bl = (buslogic_data_t *)dev->ven_data; dev->bus = info->flags; if (!(info->flags & DEVICE_MCA) && !(info->flags & DEVICE_PCI)) { @@ -1521,26 +1609,25 @@ buslogic_init(const device_t *info) bl->has_bios = !!bios_rom_addr; } - dev->ven_cmd_phase1 = buslogic_cmd_phase1; - dev->ven_get_host_id = buslogic_get_host_id; - dev->ven_get_irq = buslogic_get_irq; - dev->ven_get_dma = buslogic_get_dma; - dev->get_ven_param_len = buslogic_param_len; + dev->ven_cmd_phase1 = cmd_phase1; + dev->ven_get_host_id = get_host_id; + dev->ven_get_irq = get_irq; + dev->ven_get_dma = get_dma; + dev->get_ven_param_len = param_len; dev->ven_cmds = buslogic_cmds; - dev->interrupt_type = buslogic_interrupt_type; - dev->is_aggressive_mode = buslogic_is_aggressive_mode; - dev->get_ven_data = buslogic_setup_data; + dev->interrupt_type = interrupt_type; + dev->is_aggressive_mode = is_aggressive_mode; + dev->get_ven_data = setup_data; dev->ven_reset = buslogic_reset; strcpy(dev->vendor, "BusLogic"); bl->fAggressiveRoundRobinMode = 1; - switch(bl->chip) - { + switch(bl->chip) { case CHIP_BUSLOGIC_ISA_542: strcpy(dev->name, "BT-542BH"); - bios_rom_name = L"roms/scsi/buslogic/bt-542bh_bios.rom"; + bios_rom_name = BT542_BIOS_PATH; bios_rom_size = 0x4000; bios_rom_mask = 0x3fff; has_autoscsi_rom = 0; @@ -1552,11 +1639,11 @@ buslogic_init(const device_t *info) case CHIP_BUSLOGIC_ISA: default: strcpy(dev->name, "BT-545S"); - bios_rom_name = L"roms/scsi/buslogic/bt-545s_bios.rom"; + bios_rom_name = BT545_BIOS_PATH; bios_rom_size = 0x4000; bios_rom_mask = 0x3fff; has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/bt-545s_autoscsi.rom"; + autoscsi_rom_name = BT545_AUTO_BIOS_PATH; autoscsi_rom_size = 0x4000; has_scam_rom = 0; dev->fw_rev = "AA421E"; @@ -1565,7 +1652,7 @@ buslogic_init(const device_t *info) case CHIP_BUSLOGIC_MCA: strcpy(dev->name, "BT-640A"); - bios_rom_name = L"roms/scsi/buslogic/bt-640a_bios.rom"; + bios_rom_name = BT640A_BIOS_PATH; bios_rom_size = 0x4000; bios_rom_mask = 0x3fff; has_autoscsi_rom = 0; @@ -1580,11 +1667,11 @@ buslogic_init(const device_t *info) case CHIP_BUSLOGIC_VLB: strcpy(dev->name, "BT-445S"); - bios_rom_name = L"roms/scsi/buslogic/bt-445s_bios.rom"; + bios_rom_name = BT445S_BIOS_PATH; bios_rom_size = 0x4000; bios_rom_mask = 0x3fff; has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/bt-445s_autoscsi.rom"; + autoscsi_rom_name = BT445S_AUTO_BIOS_PATH; autoscsi_rom_size = 0x4000; has_scam_rom = 0; dev->fw_rev = "AA421E"; @@ -1594,14 +1681,14 @@ buslogic_init(const device_t *info) case CHIP_BUSLOGIC_PCI: strcpy(dev->name, "BT-958D"); - bios_rom_name = L"roms/scsi/buslogic/bt-958d_bios.rom"; + bios_rom_name = BT958D_BIOS_PATH; bios_rom_size = 0x4000; bios_rom_mask = 0x3fff; has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/bt-958d_autoscsi.rom"; + autoscsi_rom_name = BT958D_AUTO_BIOS_PATH; autoscsi_rom_size = 0x8000; has_scam_rom = 1; - scam_rom_name = L"roms/scsi/buslogic/bt-958d_scam.rom"; + scam_rom_name = BT958D_SCAM_BIOS_PATH; scam_rom_size = 0x0200; dev->fw_rev = "AA507B"; dev->cdrom_boot = 1; @@ -1627,18 +1714,18 @@ buslogic_init(const device_t *info) rom_init(&bl->bios, bios_rom_name, bios_rom_addr, bios_rom_size, bios_rom_mask, 0, MEM_MAPPING_EXTERNAL); if (has_autoscsi_rom) { - f = rom_fopen(autoscsi_rom_name); - if (f) { - fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); + f = plat_fopen(rom_path(autoscsi_rom_name), L"rb"); + if (f != NULL) { + (void)fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); fclose(f); f = NULL; } } if (has_scam_rom) { - f = rom_fopen(scam_rom_name); - if (f) { - fread(bl->SCAMData, 1, scam_rom_size, f); + f = plat_fopen(rom_path(scam_rom_name), L"rb"); + if (f != NULL) { + (void)fread(bl->SCAMData, 1, scam_rom_size, f); fclose(f); f = NULL; } @@ -1646,12 +1733,11 @@ buslogic_init(const device_t *info) } else { bl->bios_size = 0; - bl->bios_mask = 0; } if (bl->chip == CHIP_BUSLOGIC_PCI) { - dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, BuslogicPCIRead, BuslogicPCIWrite, dev); + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, PCIRead, PCIWrite, dev); buslogic_pci_bar[0].addr_regs[0] = 1; buslogic_pci_bar[1].addr_regs[0] = 0; @@ -1676,8 +1762,8 @@ buslogic_init(const device_t *info) x54x_device_reset(dev); if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) { - BuslogicInitializeLocalRAM(bl); - BuslogicInitializeAutoSCSIRam(dev); + InitializeLocalRAM(bl); + InitializeAutoSCSIRam(dev); } return(dev); diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 82b3067..eb8361a 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,7 +9,7 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.4 2018/03/15 + * Version: @(#)scsi_ncr5380.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -62,10 +62,10 @@ #include "scsi_ncr5380.h" -#define LCS6821N_ROM L"roms/scsi/ncr5380/longshine lcs-6821n - bios version 1.04.bin" -#define RT1000B_ROM L"roms/scsi/ncr5380/rancho_rt1000_rtbios_version_8.10r.bin" -#define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" -#define SCSIAT_ROM L"roms/scsi/ncr5380/sumo_scsiat_bios_v6.3.bin" +#define LCS6821N_ROM L"scsi/ncr5380/longshine lcs-6821n - bios version 1.04.bin" +#define RT1000B_ROM L"scsi/ncr5380/rancho_rt1000_rtbios_version_8.10r.bin" +#define T130B_ROM L"scsi/ncr5380/trantor_t130b_bios_v2.14.bin" +#define SCSIAT_ROM L"scsi/ncr5380/sumo_scsiat_bios_v6.3.bin" #define NCR_CURDATA 0 /* current SCSI data (read only) */ diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index e8e9ea1..5ebee57 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -17,7 +17,7 @@ * website (for 32bit and 64bit Windows) are working, and * need no additional support files other than sound fonts. * - * Version: @(#)midi_fluidsynth.c 1.0.5 2018/03/19 + * Version: @(#)midi_fluidsynth.c 1.0.6 2018/03/31 * * Code borrowed from scummvm. * @@ -286,13 +286,6 @@ fluidsynth_init(const device_t *info) memset(data, 0x00, sizeof(fluidsynth_t)); - /* Try loading the DLL. */ - fluidsynth_handle = dynld_module(PATH_FS_DLL, fluidsynth_imports); - if (fluidsynth_handle == NULL) { - ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2171); - return(NULL); - } - data->settings = f_new_fluid_settings(); f_fluid_settings_setnum(data->settings, "synth.sample-rate", 44100); @@ -386,6 +379,11 @@ fluidsynth_close(void* priv) { if (priv == NULL) return; + if (fluidsynth_handle == NULL) { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2171); + return; + } + fluidsynth_t* data = &fsdev; if (data->sound_font != -1) { @@ -423,6 +421,14 @@ fluidsynth_close(void* priv) } +void +fluidsynth_global_init(void) +{ + /* Try loading the DLL. */ + fluidsynth_handle = dynld_module(PATH_FS_DLL, fluidsynth_imports); +} + + static const device_config_t fluidsynth_config[] = { { .name = "sound_font", diff --git a/src/sound/midi_fluidsynth.h b/src/sound/midi_fluidsynth.h index 3c0efe5..0a77edd 100644 --- a/src/sound/midi_fluidsynth.h +++ b/src/sound/midi_fluidsynth.h @@ -8,7 +8,7 @@ * * Definitions for the FluidSynth driver. * - * Version: @(#)midi_fluidsynth.h 1.0.2 2018/03/15 + * Version: @(#)midi_fluidsynth.h 1.0.3 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -41,4 +41,7 @@ extern const device_t fluidsynth_device; +extern void fluidsynth_global_init(void); + + #endif /*SOUND_MIDI_FLUIDSYNTH_H*/ diff --git a/src/sound/midi_mt32.c b/src/sound/midi_mt32.c index f9fb78f..848de59 100644 --- a/src/sound/midi_mt32.c +++ b/src/sound/midi_mt32.c @@ -8,7 +8,7 @@ * * Interface to the MuNT32 MIDI synthesizer. * - * Version: @(#)midi_mt32.c 1.0.2 2018/03/15 + * Version: @(#)midi_mt32.c 1.0.3 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,330 +52,350 @@ #include "midi_mt32.h" +#define MT32_CTRL_ROM_PATH L"sound/mt32/mt32_control.rom" +#define MT32_PCM_ROM_PATH L"sound/mt32/mt32_pcm.rom" +#define CM32_CTRL_ROM_PATH L"sound/cm32l/cm32l_control.rom" +#define CM32_PCM_ROM_PATH L"sound/cm32l/cm32l_pcm.rom" + + extern void givealbuffer_midi(void *buf, uint32_t size); extern void pclog(const char *format, ...); extern void al_set_midi(int freq, int buf_size); -static const mt32emu_report_handler_i_v0 handler_v0 = { - /** Returns the actual interface version ID */ - NULL, //mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); +extern int soundon; - /** Callback for debug messages, in vprintf() format */ - NULL, //void (*printDebug)(void *instance_data, const char *fmt, va_list list); - /** Callbacks for reporting errors */ - NULL, //void (*onErrorControlROM)(void *instance_data); - NULL, //void (*onErrorPCMROM)(void *instance_data); - /** Callback for reporting about displaying a new custom message on LCD */ - NULL, //void (*showLCDMessage)(void *instance_data, const char *message); - /** Callback for reporting actual processing of a MIDI message */ - NULL, //void (*onMIDIMessagePlayed)(void *instance_data); - /** - * Callback for reporting an overflow of the input MIDI queue. - * Returns MT32EMU_BOOL_TRUE if a recovery action was taken - * and yet another attempt to enqueue the MIDI event is desired. - */ - NULL, //mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); - /** - * Callback invoked when a System Realtime MIDI message is detected in functions - * mt32emu_parse_stream and mt32emu_play_short_message and the likes. - */ - NULL, //void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); - /** Callbacks for reporting system events */ - NULL, //void (*onDeviceReset)(void *instance_data); - NULL, //void (*onDeviceReconfig)(void *instance_data); - /** Callbacks for reporting changes of reverb settings */ - NULL, //void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); - NULL, //void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); - NULL, //void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); - /** Callbacks for reporting various information */ - NULL, //void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); - NULL, //void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); + +static const mt32emu_report_handler_i_v0 handler_v0 = { + /** Returns the actual interface version ID */ + NULL, //mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); + + /** Callback for debug messages, in vprintf() format */ + NULL, //void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + NULL, //void (*onErrorControlROM)(void *instance_data); + NULL, //void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + NULL, //void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + NULL, //void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + NULL, //mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + NULL, //void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + NULL, //void (*onDeviceReset)(void *instance_data); + NULL, //void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + NULL, //void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + NULL, //void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + NULL, //void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + NULL, //void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + NULL, //void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); }; -static const mt32emu_report_handler_i handler = { &handler_v0 }; - -static mt32emu_context context = NULL; -static int roms_present[2] = {-1, -1}; - -mt32emu_return_code mt32_check(const char* func, mt32emu_return_code ret, mt32emu_return_code expected) -{ - if (ret != expected) - { - /* pclog("%s() failed, expected %d but returned %d\n", func, expected, ret); */ - return 0; - } - return 1; -} - -int mt32_available() -{ - if (roms_present[0] < 0) - roms_present[0] = (rom_present(L"roms/sound/mt32/mt32_control.rom") && rom_present(L"roms/sound/mt32/mt32_pcm.rom")); - return roms_present[0]; -} - -int cm32l_available() -{ - if (roms_present[1] < 0) - roms_present[1] = (rom_present(L"roms/sound/cm32l/cm32l_control.rom") && rom_present(L"roms/sound/cm32l/cm32l_pcm.rom")); - return roms_present[1]; -} - -static thread_t *thread_h = NULL; -static event_t *event = NULL; #define RENDER_RATE 100 #define BUFFER_SEGMENTS 10 + +static thread_t *thread_h = NULL; +static event_t *event = NULL; static uint32_t samplerate = 44100; static int buf_size = 0; static float* buffer = NULL; static int16_t* buffer_int16 = NULL; static int midi_pos = 0; +static const mt32emu_report_handler_i handler = { &handler_v0 }; +static mt32emu_context context = NULL; +static int mtroms_present[2] = {-1, -1}; -void mt32_stream(float* stream, int len) + +mt32emu_return_code +mt32_check(const char *func, mt32emu_return_code ret, mt32emu_return_code expected) { - if (context) mt32emu_render_float(context, stream, len); + if (ret != expected) { +#if 0 + pclog("%s() failed, expected %d but returned %d\n", func, expected, ret); +#endif + return 0; + } + + return 1; } -void mt32_stream_int16(int16_t* stream, int len) + +int +mt32_available(void) { - if (context) mt32emu_render_bit16s(context, stream, len); + if (mtroms_present[0] < 0) + mtroms_present[0] = (rom_present(MT32_CTRL_ROM_PATH) && + rom_present(MT32_PCM_ROM_PATH)); + return mtroms_present[0]; } -void mt32_poll() + +int +cm32l_available(void) { - midi_pos++; - if (midi_pos == 48000/RENDER_RATE) - { - midi_pos = 0; - thread_set_event(event); - } + if (mtroms_present[1] < 0) + mtroms_present[1] = (rom_present(CM32_CTRL_ROM_PATH) && + rom_present(CM32_PCM_ROM_PATH)); + return mtroms_present[1]; } -extern int soundon; -static void mt32_thread(void *param) +void +mt32_stream(float* stream, int len) { - int buf_pos = 0; - int bsize = buf_size / BUFFER_SEGMENTS; - while (1) - { - thread_wait_event(event, -1); + if (context) mt32emu_render_float(context, stream, len); +} - if (sound_is_float) - { - float *buf = (float *) ((uint8_t*)buffer + buf_pos); - memset(buf, 0, bsize); - mt32_stream(buf, bsize / (2 * sizeof(float))); - buf_pos += bsize; - if (buf_pos >= buf_size) - { - if (soundon) - givealbuffer_midi(buffer, buf_size / sizeof(float)); - buf_pos = 0; - } + +void +mt32_stream_int16(int16_t* stream, int len) +{ + if (context) mt32emu_render_bit16s(context, stream, len); +} + + +void +mt32_poll(void) +{ + midi_pos++; + if (midi_pos == 48000/RENDER_RATE) { + midi_pos = 0; + thread_set_event(event); + } +} + + +static void +mt32_thread(void *param) +{ + int buf_pos = 0; + int bsize = buf_size / BUFFER_SEGMENTS; + + while (1) { + thread_wait_event(event, -1); + + if (sound_is_float) { + float *buf = (float *) ((uint8_t*)buffer + buf_pos); + + memset(buf, 0, bsize); + mt32_stream(buf, bsize / (2 * sizeof(float))); + buf_pos += bsize; + if (buf_pos >= buf_size) { + if (soundon) + givealbuffer_midi(buffer, buf_size / sizeof(float)); + buf_pos = 0; } - else - { - int16_t *buf = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); - memset(buf, 0, bsize); - mt32_stream_int16(buf, bsize / (2 * sizeof(int16_t))); - buf_pos += bsize; - if (buf_pos >= buf_size) - { - if (soundon) - givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); - buf_pos = 0; - } + } else { + int16_t *buf = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); + + memset(buf, 0, bsize); + mt32_stream_int16(buf, bsize / (2 * sizeof(int16_t))); + buf_pos += bsize; + if (buf_pos >= buf_size) { + if (soundon) + givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); + buf_pos = 0; } - } -} - -void mt32_msg(uint8_t* val) -{ - if (context) mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t*)val), MT32EMU_RC_OK); -} - -void mt32_sysex(uint8_t* data, unsigned int len) -{ - if (context) mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); -} - -void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) -{ - wchar_t s[512]; - char fn[512]; - context = mt32emu_create_context(handler, NULL); - if (!rom_getfile(control_rom, s, 512)) return 0; - wcstombs(fn, s, (wcslen(s) << 1) + 2); - if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; - if (!rom_getfile(pcm_rom, s, 512)) return 0; - wcstombs(fn, s, (wcslen(s) << 1) + 2); - if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) return 0; - - if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; - - event = thread_create_event(); - thread_h = thread_create(mt32_thread, 0); - samplerate = mt32emu_get_actual_stereo_output_samplerate(context); - /* buf_size = samplerate/RENDER_RATE*2; */ - if (sound_is_float) - { - buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(float); - buffer = malloc(buf_size); - buffer_int16 = NULL; } - else - { - buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(int16_t); - buffer = NULL; - buffer_int16 = malloc(buf_size); - } - - mt32emu_set_output_gain(context, device_get_config_int("output_gain")/100.0f); - mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); - mt32emu_set_reverb_output_gain(context, device_get_config_int("reverb_output_gain")/100.0f); - mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); - mt32emu_set_nice_amp_ramp_enabled(context, device_get_config_int("nice_ramp")); - - /* pclog("mt32 output gain: %f\n", mt32emu_get_output_gain(context)); - pclog("mt32 reverb output gain: %f\n", mt32emu_get_reverb_output_gain(context)); - pclog("mt32 reverb: %d\n", mt32emu_is_reverb_enabled(context)); - pclog("mt32 reversed stereo: %d\n", mt32emu_is_reversed_stereo_enabled(context)); */ - - al_set_midi(samplerate, buf_size); - - /* pclog("mt32 (Munt %s) initialized, samplerate %d, buf_size %d\n", mt32emu_get_library_version_string(), samplerate, buf_size); */ - - midi_device_t* dev = malloc(sizeof(midi_device_t)); - memset(dev, 0, sizeof(midi_device_t)); - - dev->play_msg = mt32_msg; - dev->play_sysex = mt32_sysex; - dev->poll = mt32_poll; - - midi_init(dev); - - return dev; + } } -void *mt32_init(const device_t *info) + +void +mt32_msg(uint8_t* val) { - return mt32emu_init(L"roms/sound/mt32/mt32_control.rom", L"roms/sound/mt32/mt32_pcm.rom"); + if (context) mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t*)val), MT32EMU_RC_OK); } -void *cm32l_init(const device_t *info) + +void +mt32_sysex(uint8_t* data, unsigned int len) { - return mt32emu_init(L"roms/sound/cm32l/cm32l_control.rom", L"roms/sound/cm32l/cm32l_pcm.rom"); + if (context) mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); } -void mt32_close(void* p) + +static void * +mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) { - if (!p) return; + wchar_t path[1024]; + char fn[1024]; - if (thread_h) - thread_kill(thread_h); - if (event) - thread_destroy_event(event); - event = NULL; - thread_h = NULL; + context = mt32emu_create_context(handler, NULL); - if (context) - { - mt32emu_close_synth(context); - mt32emu_free_context(context); - } - context = NULL; + pc_path(path, sizeof_w(path), rom_path(control_rom)); + wcstombs(fn, path, sizeof(fn)); + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; - if (buffer) - free(buffer); - buffer = NULL; + pc_path(path, sizeof_w(path), rom_path(pcm_rom)); + wcstombs(fn, path, sizeof(fn)); + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) return 0; - if (buffer_int16) - free(buffer_int16); - buffer_int16 = NULL; + if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; - midi_close(); + event = thread_create_event(); + thread_h = thread_create(mt32_thread, 0); + samplerate = mt32emu_get_actual_stereo_output_samplerate(context); - free((midi_device_t*)p); + /* buf_size = samplerate/RENDER_RATE*2; */ + if (sound_is_float) { + buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(float); + buffer = malloc(buf_size); + buffer_int16 = NULL; + } else { + buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(int16_t); + buffer = NULL; + buffer_int16 = malloc(buf_size); + } - /* pclog("mt32 closed\n"); */ + mt32emu_set_output_gain(context, device_get_config_int("output_gain")/100.0f); + mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); + mt32emu_set_reverb_output_gain(context, device_get_config_int("reverb_output_gain")/100.0f); + mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); + mt32emu_set_nice_amp_ramp_enabled(context, device_get_config_int("nice_ramp")); + + /* pclog("mt32 output gain: %f\n", mt32emu_get_output_gain(context)); + pclog("mt32 reverb output gain: %f\n", mt32emu_get_reverb_output_gain(context)); + pclog("mt32 reverb: %d\n", mt32emu_is_reverb_enabled(context)); + pclog("mt32 reversed stereo: %d\n", mt32emu_is_reversed_stereo_enabled(context)); */ + + al_set_midi(samplerate, buf_size); + + /* pclog("mt32 (Munt %s) initialized, samplerate %d, buf_size %d\n", mt32emu_get_library_version_string(), samplerate, buf_size); */ + + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = mt32_msg; + dev->play_sysex = mt32_sysex; + dev->poll = mt32_poll; + + midi_init(dev); + + return dev; } + +static void * +mt32_init(const device_t *info) +{ + return mt32emu_init(MT32_CTRL_ROM_PATH, MT32_PCM_ROM_PATH); +} + + +static void * +cm32l_init(const device_t *info) +{ + return mt32emu_init(CM32_CTRL_ROM_PATH, CM32_PCM_ROM_PATH); +} + + +static void +mt32_close(void *priv) +{ + if (priv == NULL) return; + + if (thread_h) + thread_kill(thread_h); + if (event) + thread_destroy_event(event); + event = NULL; + thread_h = NULL; + + if (context) { + mt32emu_close_synth(context); + mt32emu_free_context(context); + } + context = NULL; + + if (buffer) + free(buffer); + buffer = NULL; + + if (buffer_int16) + free(buffer_int16); + buffer_int16 = NULL; + + midi_close(); + + free((midi_device_t*)priv); +} + + static const device_config_t mt32_config[] = { - { - .name = "output_gain", - .description = "Output Gain", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 100 - }, - { - .name = "reverb", - .description = "Reverb", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .name = "reverb_output_gain", - .description = "Reverb Output Gain", - .type = CONFIG_SPINNER, - .spinner = - { - .min = 0, - .max = 100 - }, - .default_int = 100 - }, - { - .name = "reversed_stereo", - .description = "Reversed stereo", - .type = CONFIG_BINARY, - .default_int = 0 - }, - { - .name = "nice_ramp", - .description = "Nice ramp", - .type = CONFIG_BINARY, - .default_int = 1 - }, - { - .type = -1 - } + { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 100 + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "reverb_output_gain", + .description = "Reverb Output Gain", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 100 + }, + { + .name = "reversed_stereo", + .description = "Reversed stereo", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "nice_ramp", + .description = "Nice ramp", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } }; -const device_t mt32_device = -{ - "Roland MT-32 Emulation", - 0, - 0, - mt32_init, - mt32_close, - NULL, - mt32_available, - NULL, - NULL, - NULL, - mt32_config + +const device_t mt32_device = { + "Roland MT-32 Emulation", + 0, 0, + mt32_init, mt32_close, NULL, + mt32_available, + NULL, NULL, NULL, + mt32_config }; -const device_t cm32l_device = -{ - "Roland CM-32L Emulation", - 0, - 0, - cm32l_init, - mt32_close, - NULL, - cm32l_available, - NULL, - NULL, - NULL, - mt32_config +const device_t cm32l_device = { + "Roland CM-32L Emulation", + 0, 0, + cm32l_init, mt32_close, NULL, + cm32l_available, + NULL, NULL, NULL, + mt32_config }; diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index e38f609..fa2adbd 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -10,7 +10,7 @@ * * TODO: Stack allocation of big buffers (line 688 et al.) * - * Version: @(#)snd_adlibgold.c 1.0.5 2018/03/28 + * Version: @(#)snd_adlibgold.c 1.0.6 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,6 +53,7 @@ #include "../nvr.h" #include "../timer.h" #include "../device.h" +#include "../plat.h" #include "sound.h" #include "filters.h" #include "snd_opl.h" @@ -827,10 +828,10 @@ void *adgold_init(const device_t *info) for (; c >= 0; c--) attenuation[c] = 0; - f = nvr_fopen(L"adgold.bin", L"rb"); - if (f) + f = plat_fopen(nvr_path(L"adgold.bin"), L"rb"); + if (f != NULL) { - fread(adgold->adgold_eeprom, 0x18, 1, f); + (void)fread(adgold->adgold_eeprom, 0x18, 1, f); fclose(f); } @@ -867,10 +868,10 @@ void adgold_close(void *p) FILE *f; adgold_t *adgold = (adgold_t *)p; - f = nvr_fopen(L"adgold.bin", L"wb"); - if (f) + f = plat_fopen(nvr_path(L"adgold.bin"), L"wb"); + if (f != NULL) { - fwrite(adgold->adgold_eeprom, 0x18, 1, f); + (void)fwrite(adgold->adgold_eeprom, 0x18, 1, f); fclose(f); } diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index 2ab3f60..e5014c6 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -8,7 +8,7 @@ * * Implementation of Emu8000 emulator. * - * Version: @(#)snd_emu8k.c 1.0.6 2018/03/28 + * Version: @(#)snd_emu8k.c 1.0.7 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -51,10 +51,14 @@ #include "../mem.h" #include "../rom.h" #include "../timer.h" +#include "../plat.h" #include "sound.h" #include "snd_emu8k.h" +#define EMU8K_ROM_PATH L"sound/awe32.raw" + + #if !defined FILTER_INITIAL && !defined FILTER_MOOG && !defined FILTER_CONSTANT //#define FILTER_INITIAL #define FILTER_MOOG @@ -2176,8 +2180,8 @@ void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) int c; double out; - f = rom_fopen(L"roms/sound/awe32.raw"); - if (!f) + f = plat_fopen(rom_path(EMU8K_ROM_PATH), L"rb"); + if (f == NULL) fatal("AWE32.RAW not found\n"); emu8k->rom = malloc(1024 * 1024); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 5f11bec..30c5fe2 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -8,7 +8,7 @@ * * Sound Blaster emulation. * - * Version: @(#)sound_sb.c 1.0.3 2018/03/15 + * Version: @(#)sound_sb.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1277,7 +1277,7 @@ void *sb_16_init(const device_t *info) int sb_awe32_available() { - return rom_present(L"roms/sound/awe32.raw"); + return rom_present(L"sound/awe32.raw"); } void *sb_awe32_init(const device_t *info) diff --git a/src/sound/sound.c b/src/sound/sound.c index 442f51c..49e8f7c 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.3 2018/03/28 + * Version: @(#)sound.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,6 +53,9 @@ #include "snd_adlibgold.h" #include "snd_audiopci.h" #include "snd_mpu401.h" +#ifdef USE_FLUIDSYNTH +# include "midi_fluidsynth.h" +#endif #if defined(DEV_BRANCH) && defined(USE_PAS16) # include "snd_pas16.h" #endif @@ -540,3 +543,13 @@ void sound_cd_thread_reset(void) cd_thread_enable = available_cdrom_drives ? 1 : 0; } + + +/* Called once, at application startup. */ +void +sound_global_init(void) +{ +#ifdef USE_FLUIDSYNTH + fluidsynth_global_init(); +#endif +} diff --git a/src/sound/sound.h b/src/sound/sound.h index d3137b4..ce335cc 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -8,7 +8,7 @@ * * Definitions for the Sound Emulation core. * - * Version: @(#)sound.h 1.0.2 2018/03/15 + * Version: @(#)sound.h 1.0.3 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -77,6 +77,7 @@ extern void sound_speed_changed(void); extern void sound_realloc_buffers(void); +extern void sound_global_init(void); extern void sound_init(void); extern void sound_reset(void); diff --git a/src/version.h b/src/version.h index 0dce06a..09f2f15 100644 --- a/src/version.h +++ b/src/version.h @@ -8,7 +8,7 @@ * * Define application version and build info. * - * Version: @(#)version.h 1.0.2 2018/03/20 + * Version: @(#)version.h 1.0.3 2018/03/30 * * Author: Fred N. van Kempen, * @@ -55,6 +55,7 @@ #define EMU_VER_MAJOR 0 #define EMU_VER_MINOR 1 #define EMU_VER_REV 3 +#define EMU_VER_PATCH 4 /* Standard C preprocessor macros. */ @@ -64,7 +65,7 @@ /* These are used in the application. */ #define EMU_VER_NUM EMU_VER_MAJOR.EMU_VER_MINOR.EMU_VER_REV -#define EMU_VER_NUM_4 EMU_VER_MAJOR.EMU_VER_MINOR.EMU_VER_REV.0 +#define EMU_VER_NUM_4 EMU_VER_MAJOR.EMU_VER_MINOR.EMU_VER_REV.EMU_VER_PATCH #define EMU_VERSION STR(EMU_VER_NUM) #define EMU_VERSION_4 STR(EMU_VER_NUM_4) diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 497becf..528c069 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,7 +8,7 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.5 2018/03/26 + * Version: @(#)vid_ati18800.c 1.0.6 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -54,9 +54,9 @@ #include "vid_svga_render.h" -#define BIOS_ROM_PATH_WONDER L"roms/video/ati/ati18800/vga_wonder_v3-1.02.bin" -#define BIOS_ROM_PATH_VGA88 L"roms/video/ati/ati18800/vga88.bin" -#define BIOS_ROM_PATH_EDGE16 L"roms/video/ati/ati18800/vgaedge16.vbi" +#define BIOS_ROM_PATH_WONDER L"video/ati/ati18800/vga_wonder_v3-1.02.bin" +#define BIOS_ROM_PATH_VGA88 L"video/ati/ati18800/vga88.bin" +#define BIOS_ROM_PATH_EDGE16 L"video/ati/ati18800/vgaedge16.vbi" enum { ATI18800_WONDER = 0, diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 8fbd541..7180683 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.10 2018/03/26 + * Version: @(#)vid_ati28800.c 1.0.11 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -57,17 +57,17 @@ #include "vid_svga_render.h" -#define BIOS_ATIKOR_PATH L"roms/video/ati/ati28800/atikorvga.bin" +#define BIOS_ATIKOR_PATH L"video/ati/ati28800/atikorvga.bin" -#define BIOS_VGAXL_EVEN_PATH L"roms/video/ati/ati28800/xleven.bin" -#define BIOS_VGAXL_ODD_PATH L"roms/video/ati/ati28800/xlodd.bin" +#define BIOS_VGAXL_EVEN_PATH L"video/ati/ati28800/xleven.bin" +#define BIOS_VGAXL_ODD_PATH L"video/ati/ati28800/xlodd.bin" #if defined(DEV_BRANCH) && defined(USE_XL24) -#define BIOS_XL24_EVEN_PATH L"roms/video/ati/ati28800/112-14318-102.bin" -#define BIOS_XL24_ODD_PATH L"roms/video/ati/ati28800/112-14319-102.bin" +#define BIOS_XL24_EVEN_PATH L"video/ati/ati28800/112-14318-102.bin" +#define BIOS_XL24_ODD_PATH L"video/ati/ati28800/112-14319-102.bin" #endif -#define BIOS_ROM_PATH L"roms/video/ati/ati28800/bios.bin" +#define BIOS_ROM_PATH L"video/ati/ati28800/bios.bin" typedef struct ati28800_t diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index dc7191d..0f71671 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -8,7 +8,7 @@ * * Emulation of the EEPROM on select ATI cards. * - * Version: @(#)vid_ati_eeprom.c 1.0.1 2018/02/14 + * Version: @(#)vid_ati_eeprom.c 1.0.2 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -43,6 +43,7 @@ #include "../emu.h" #include "../mem.h" #include "../nvr.h" +#include "../plat.h" #include "vid_ati_eeprom.h" @@ -76,24 +77,27 @@ enum void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) { FILE *f; + eeprom->type = type; + memset(eeprom->data, 0, eeprom->type ? 512 : 128); + wcscpy(eeprom->fn, fn); - f = nvr_fopen(eeprom->fn, L"rb"); - if (!f) + f = plat_fopen(nvr_path(eeprom->fn), L"rb"); + if (f != NULL) { - memset(eeprom->data, 0, eeprom->type ? 512 : 128); - return; + (void)fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); } - fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); - fclose(f); } void ati_eeprom_save(ati_eeprom_t *eeprom) { - FILE *f = nvr_fopen(eeprom->fn, L"wb"); - if (!f) return; - fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); - fclose(f); + FILE *f = plat_fopen(nvr_path(eeprom->fn), L"wb"); + + if (f != NULL) { + (void)fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); + } } void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index b8cb89c..b182a5d 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,7 +8,7 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.8 2018/03/26 + * Version: @(#)vid_ati_mach64.c 1.0.9 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -60,10 +60,10 @@ #undef CLAMP #endif -#define BIOS_ROM_PATH L"roms/video/ati/mach64/bios.bin" -#define BIOS_ISA_ROM_PATH L"roms/video/ati/mach64/m64-1994.vbi" -#define BIOS_VLB_ROM_PATH L"roms/video/ati/mach64/mach64_vlb_vram.bin" -#define BIOS_ROMVT2_PATH L"roms/video/ati/mach64/atimach64vt2pci.bin" +#define BIOS_ROM_PATH L"video/ati/mach64/bios.bin" +#define BIOS_ISA_ROM_PATH L"video/ati/mach64/m64-1994.vbi" +#define BIOS_VLB_ROM_PATH L"video/ati/mach64/mach64_vlb_vram.bin" +#define BIOS_ROMVT2_PATH L"video/ati/mach64/atimach64vt2pci.bin" #define FIFO_SIZE 65536 diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index e107ca0..aa846d5 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, 5430, 5434 and 5436 are supported). * - * Version: @(#)vid_cl54xx.c 1.0.13 2018/03/26 + * Version: @(#)vid_cl54xx.c 1.0.14 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -59,17 +59,17 @@ #include "vid_cl54xx.h" -#define BIOS_GD5426_PATH L"roms/video/cirruslogic/diamond speedstar pro vlb v3.04.bin" -#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/gd5428.bin" -#define BIOS_GD5428_VLB_PATH L"roms/video/cirruslogic/vlbusjapan.bin" -#define BIOS_GD5429_PATH L"roms/video/cirruslogic/gd5429.vbi" -#define BIOS_GD5430_VLB_PATH L"roms/video/cirruslogic/diamondvlbus.bin" -#define BIOS_GD5430_PCI_PATH L"roms/video/cirruslogic/gd5430pci.bin" -#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" -#define BIOS_GD5436_PATH L"roms/video/cirruslogic/gd5436.vbi" -#define BIOS_GD5446_PATH L"roms/video/cirruslogic/gd5446bv.vbi" -#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb_nitro64v.bin" -#define BIOS_GD5480_PATH L"roms/video/cirruslogic/gd5480.rom" +#define BIOS_GD5426_PATH L"video/cirruslogic/diamond speedstar pro vlb v3.04.bin" +#define BIOS_GD5428_ISA_PATH L"video/cirruslogic/gd5428.bin" +#define BIOS_GD5428_VLB_PATH L"video/cirruslogic/vlbusjapan.bin" +#define BIOS_GD5429_PATH L"video/cirruslogic/gd5429.vbi" +#define BIOS_GD5430_VLB_PATH L"video/cirruslogic/diamondvlbus.bin" +#define BIOS_GD5430_PCI_PATH L"video/cirruslogic/gd5430pci.bin" +#define BIOS_GD5434_PATH L"video/cirruslogic/gd5434.bin" +#define BIOS_GD5436_PATH L"video/cirruslogic/gd5436.vbi" +#define BIOS_GD5446_PATH L"video/cirruslogic/gd5446bv.vbi" +#define BIOS_GD5446_STB_PATH L"video/cirruslogic/stb_nitro64v.bin" +#define BIOS_GD5480_PATH L"video/cirruslogic/gd5480.rom" #define CIRRUS_ID_CLGD5426 0x90 #define CIRRUS_ID_CLGD5428 0x98 diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 241dc68..e377040 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -9,7 +9,7 @@ * Emulation of the EGA, Chips & Technologies SuperEGA, and * AX JEGA graphics cards. * - * Version: @(#)vid_ega.c 1.0.4 2018/03/15 + * Version: @(#)vid_ega.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -55,9 +55,9 @@ #include "vid_ega_render.h" -#define BIOS_IBM_PATH L"roms/video/ibm/ega/ibm_6277356_ega_card_u44_27128.bin" -#define BIOS_CPQ_PATH L"roms/video/compaq/ega/108281-001.bin" -#define BIOS_SEGA_PATH L"roms/video/phoenix/ega/lega.vbi" +#define BIOS_IBM_PATH L"video/ibm/ega/ibm_6277356_ega_card_u44_27128.bin" +#define BIOS_CPQ_PATH L"video/compaq/ega/108281-001.bin" +#define BIOS_SEGA_PATH L"video/phoenix/ega/lega.vbi" enum { @@ -1158,8 +1158,8 @@ void *jega_standalone_init(const device_t *info) { ega_t *ega = (ega_t *)ega_standalone_init(info); - LoadFontxFile(L"roms/video/ibm/ega/JPNHN19X.FNT"); - LoadFontxFile(L"roms/video/ibm/ega/JPNZN16X.FNT"); + LoadFontxFile(L"video/ibm/ega/jpnhn19x.fnt"); + LoadFontxFile(L"video/ibm/ega/jpnzn16x.fnt"); ega->is_jega = 1; diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 90d161e..60ae459 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -8,7 +8,7 @@ * * Emulation of the Tseng Labs ET4000. * - * Version: @(#)vid_et4000.c 1.0.4 2018/03/15 + * Version: @(#)vid_et4000.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,7 +52,7 @@ #include "vid_et4000.h" -#define BIOS_ROM_PATH L"roms/video/tseng/et4000/et4000.bin" +#define BIOS_ROM_PATH L"video/tseng/et4000/et4000.bin" typedef struct et4000_t diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index b723d5f..8217e9d 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -10,7 +10,7 @@ * * Known bugs: Accelerator doesn't work in planar modes * - * Version: @(#)vid_et4000w32.c 1.0.5 2018/03/26 + * Version: @(#)vid_et4000w32.c 1.0.6 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -60,9 +60,9 @@ #if defined(DEV_BRANCH) && defined(USE_STEALTH32) -# define BIOS_ROM_PATH_DIAMOND L"roms/video/tseng/et4000w32/et4000w32.bin" +# define BIOS_ROM_PATH_DIAMOND L"video/tseng/et4000w32/et4000w32.bin" #endif -#define BIOS_ROM_PATH_CARDEX L"roms/video/tseng/et4000w32/cardex.vbi" +#define BIOS_ROM_PATH_CARDEX L"video/tseng/et4000w32/cardex.vbi" #define FIFO_SIZE 65536 diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index abcd9d0..e2eb41d 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -63,7 +63,7 @@ * reducing the height of characters so they fit in an 8x12 cell * if necessary. * - * Version: @(#)vid_genius.c 1.0.3 2018/03/15 + * Version: @(#)vid_genius.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -108,7 +108,7 @@ #include "vid_genius.h" -#define BIOS_ROM_PATH L"roms/video/mdsi/genius/8x12.bin" +#define BIOS_ROM_PATH L"video/mdsi/genius/8x12.bin" #define GENIUS_XSIZE 728 diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index a85d945..91945c3 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -8,7 +8,7 @@ * * Oak OTI037C/67/077 emulation. * - * Version: @(#)vid_oak_oti.c 1.0.7 2018/03/26 + * Version: @(#)vid_oak_oti.c 1.0.8 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -51,11 +51,11 @@ #include "vid_svga.h" -#define BIOS_37C_PATH L"roms/video/oti/oti037c/bios.bin" +#define BIOS_37C_PATH L"video/oti/oti037c/bios.bin" #if 0 -# define BIOS_67_PATH L"roms/video/oti/bios.bin" +# define BIOS_67_PATH L"video/oti/bios.bin" #endif -#define BIOS_77_PATH L"roms/video/oti/oti077.vbi" +#define BIOS_77_PATH L"video/oti/oti077.vbi" typedef struct { diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index 6c79450..9661fe9 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -13,7 +13,7 @@ * NOTE: The MegaPC video device should be moved to the MegaPC * machine file. * - * Version: @(#)vid_paradise.c 1.0.3 2018/03/15 + * Version: @(#)vid_paradise.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -410,7 +410,7 @@ static void *paradise_pvga1a_pc2086_init(const device_t *info) paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); if (paradise) - rom_init(¶dise->bios_rom, L"roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } @@ -419,7 +419,7 @@ static void *paradise_pvga1a_pc3086_init(const device_t *info) paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); if (paradise) - rom_init(¶dise->bios_rom, L"roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } @@ -435,14 +435,14 @@ static void *paradise_pvga1a_standalone_init(const device_t *info) paradise = paradise_pvga1a_init(info, memory); if (paradise) - rom_init(¶dise->bios_rom, L"roms/video/paradise/pvga1a/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"video/paradise/pvga1a/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } static int paradise_pvga1a_standalone_available(void) { - return rom_present(L"roms/video/paradise/pvga1a/bios.bin"); + return rom_present(L"video/paradise/pvga1a/bios.bin"); } static void *paradise_wd90c11_megapc_init(const device_t *info) @@ -451,8 +451,8 @@ static void *paradise_wd90c11_megapc_init(const device_t *info) if (paradise) rom_init_interleaved(¶dise->bios_rom, - L"roms/machines/amstrad/megapc/41651-bios lo.u18", - L"roms/machines/amstrad/megapc/211253-bios hi.u19", + L"machines/amstrad/megapc/41651-bios lo.u18", + L"machines/amstrad/megapc/211253-bios hi.u19", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; @@ -463,14 +463,14 @@ static void *paradise_wd90c11_standalone_init(const device_t *info) paradise_t *paradise = paradise_wd90c11_init(info); if (paradise) - rom_init(¶dise->bios_rom, L"roms/video/wd/wd90c11/wd90c11.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"video/wd/wd90c11/wd90c11.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } static int paradise_wd90c11_standalone_available(void) { - return rom_present(L"roms/video/wd/wd90c11/wd90c11.vbi"); + return rom_present(L"video/wd/wd90c11/wd90c11.vbi"); } static void *paradise_wd90c30_standalone_init(const device_t *info) @@ -484,14 +484,14 @@ static void *paradise_wd90c30_standalone_init(const device_t *info) paradise = paradise_wd90c30_init(info, memory); if (paradise) - rom_init(¶dise->bios_rom, L"roms/video/wd/wd90c30/90c30-lr.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(¶dise->bios_rom, L"video/wd/wd90c30/90c30-lr.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } static int paradise_wd90c30_standalone_available(void) { - return rom_present(L"roms/video/wd/wd90c30/90c30-lr.vbi"); + return rom_present(L"video/wd/wd90c30/90c30-lr.vbi"); } void paradise_close(void *p) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index d9d051f..65db5ee 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -10,7 +10,7 @@ * * NOTE: ROM images need more/better organization per chipset. * - * Version: @(#)vid_s3.c 1.0.6 2018/03/21 + * Version: @(#)vid_s3.c 1.0.7 2018/03/11 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -2366,29 +2366,29 @@ void *s3_vision864_init(const device_t *info, wchar_t *bios_fn) static void *s3_bahamas64_init(const device_t *info) { - s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/s3/bahamas64.bin"); + s3_t *s3 = s3_vision864_init(info, L"video/s3/s3/bahamas64.bin"); return s3; } static void *s3_phoenix_vision864_init(const device_t *info) { - s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/s3/86c864p.bin"); + s3_t *s3 = s3_vision864_init(info, L"video/s3/s3/86c864p.bin"); return s3; } static int s3_bahamas64_available(void) { - return rom_present(L"roms/video/s3/s3/bahamas64.bin"); + return rom_present(L"video/s3/s3/bahamas64.bin"); } static int s3_phoenix_vision864_available(void) { - return rom_present(L"roms/video/s3/s3/86c864p.bin"); + return rom_present(L"video/s3/s3/86c864p.bin"); } static void *s3_phoenix_trio32_init(const device_t *info) { - s3_t *s3 = s3_init(info, L"roms/video/s3/s3/86c732p.bin", S3_TRIO32); + s3_t *s3 = s3_init(info, L"video/s3/s3/86c732p.bin", S3_TRIO32); s3->id = 0xe1; /*Trio32*/ s3->id_ext = 0x10; @@ -2403,7 +2403,7 @@ static void *s3_phoenix_trio32_init(const device_t *info) static int s3_phoenix_trio32_available(void) { - return rom_present(L"roms/video/s3/s3/86c732p.bin"); + return rom_present(L"video/s3/s3/86c732p.bin"); } static void *s3_trio64_init(const device_t *info, wchar_t *bios_fn) @@ -2422,13 +2422,13 @@ static void *s3_trio64_init(const device_t *info, wchar_t *bios_fn) static void *s3_9fx_init(const device_t *info) { - s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/s3/s3_764.bin"); + s3_t *s3 = s3_trio64_init(info, L"video/s3/s3/s3_764.bin"); return s3; } static void *s3_phoenix_trio64_init(const device_t *info) { - s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/s3/86c764x1.bin"); + s3_t *s3 = s3_trio64_init(info, L"video/s3/s3/86c764x1.bin"); if (device_get_config_int("memory") == 1) s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ return s3; @@ -2444,7 +2444,7 @@ static void *s3_phoenix_trio64_onboard_init(const device_t *info) static void *s3_diamond_stealth64_init(const device_t *info) { - s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/s3/stealt64.bin"); + s3_t *s3 = s3_trio64_init(info, L"video/s3/s3/stealt64.bin"); if (device_get_config_int("memory") == 1) s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ return s3; @@ -2452,17 +2452,17 @@ static void *s3_diamond_stealth64_init(const device_t *info) static int s3_9fx_available(void) { - return rom_present(L"roms/video/s3/s3/s3_764.bin"); + return rom_present(L"video/s3/s3/s3_764.bin"); } static int s3_phoenix_trio64_available(void) { - return rom_present(L"roms/video/s3/s3/86c764x1.bin"); + return rom_present(L"video/s3/s3/86c764x1.bin"); } static int s3_diamond_stealth64_available(void) { - return rom_present(L"roms/video/s3/s3/stealt64.bin"); + return rom_present(L"video/s3/s3/stealt64.bin"); } static void s3_close(void *p) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 018fdfc..5bde40e 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -8,7 +8,7 @@ * * S3 ViRGE emulation. * - * Version: @(#)vid_s3_virge.c 1.0.6 2018/03/22 + * Version: @(#)vid_s3_virge.c 1.0.7 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -3838,7 +3838,7 @@ static void *s3_virge_init(const device_t *info) virge->pci = !!(info->flags & DEVICE_PCI); - rom_init(&virge->bios_rom, L"roms/video/s3/s3virge/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, L"video/s3/s3virge/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (info->flags & DEVICE_PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -3937,7 +3937,7 @@ static void *s3_virge_988_init(const device_t *info) virge->pci = !!(info->flags & DEVICE_PCI); - rom_init(&virge->bios_rom, L"roms/video/s3/s3virge/diamondstealth3000.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, L"video/s3/s3virge/diamondstealth3000.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (info->flags & DEVICE_PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -4121,12 +4121,12 @@ static void *s3_virge_375_init(const device_t *info, wchar_t *romfn) static void *s3_virge_375_1_init(const device_t *info) { - return s3_virge_375_init(info, L"roms/video/s3/s3virge/86c375_1.bin"); + return s3_virge_375_init(info, L"video/s3/s3virge/86c375_1.bin"); } static void *s3_virge_375_4_init(const device_t *info) { - return s3_virge_375_init(info, L"roms/video/s3/s3virge/86c375_4.bin"); + return s3_virge_375_init(info, L"video/s3/s3virge/86c375_4.bin"); } static void s3_virge_close(void *p) @@ -4149,22 +4149,22 @@ static void s3_virge_close(void *p) static int s3_virge_available(void) { - return rom_present(L"roms/video/s3/s3virge/s3virge.bin"); + return rom_present(L"video/s3/s3virge/s3virge.bin"); } static int s3_virge_988_available(void) { - return rom_present(L"roms/video/s3/s3virge/diamondstealth3000.vbi"); + return rom_present(L"video/s3/s3virge/diamondstealth3000.vbi"); } static int s3_virge_375_1_available(void) { - return rom_present(L"roms/video/s3/s3virge/86c375_1.bin"); + return rom_present(L"video/s3/s3virge/86c375_1.bin"); } static int s3_virge_375_4_available(void) { - return rom_present(L"roms/video/s3/s3virge/86c375_4.bin"); + return rom_present(L"video/s3/s3virge/86c375_4.bin"); } static void s3_virge_speed_changed(void *p) diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 2d323d4..c50df91 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,7 +8,7 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.12 2018/03/21 + * Version: @(#)vid_table.c 1.0.13 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -214,9 +214,9 @@ video_reset(int card) cgapal_rebuild(); /* Initialize the video font tables. */ - loadfont(L"roms/video/ibm/mda/mda.rom", 0); - loadfont(L"roms/video/wyse/wyse700/wy700.rom", 3); - loadfont(L"roms/video/mdsi/genius/8x12.bin", 4); + loadfont(L"video/ibm/mda/mda.rom", 0); + loadfont(L"video/wyse/wyse700/wy700.rom", 3); + loadfont(L"video/mdsi/genius/8x12.bin", 4); /* Do not initialize internal cards here. */ if ((card == VID_NONE) || \ diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index c4299db..cdc5ad4 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -47,7 +47,7 @@ * access size or host data has any affect, but the Windows 3.1 * driver always reads bytes and write words of 0xffff. * - * Version: @(#)vid_tgui9440.c 1.0.4 2018/03/15 + * Version: @(#)vid_tgui9440.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -832,22 +832,22 @@ static void *tgui_init(const device_t *info, wchar_t *bios_fn, int type) static void *tgui9400cxi_init(const device_t *info) { - return tgui_init(info, L"roms/video/trident/tgui9440/9400cxi.vbi", TGUI_9400CXI); + return tgui_init(info, L"video/trident/tgui9440/9400cxi.vbi", TGUI_9400CXI); } static void *tgui9440_init(const device_t *info) { - return tgui_init(info, L"roms/video/trident/tgui9440/9440.vbi", TGUI_9440); + return tgui_init(info, L"video/trident/tgui9440/9440.vbi", TGUI_9440); } static int tgui9400cxi_available() { - return rom_present(L"roms/video/trident/tgui9440/9400cxi.vbi"); + return rom_present(L"video/trident/tgui9440/9400cxi.vbi"); } static int tgui9440_available() { - return rom_present(L"roms/video/trident/tgui9440/9440.vbi"); + return rom_present(L"video/trident/tgui9440/9440.vbi"); } void tgui_close(void *p) diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 40c49f3..d3369c5 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -8,7 +8,7 @@ * * Trident TVGA (8900D) emulation. * - * Version: @(#)vid_tvga.c 1.0.4 2018/03/15 + * Version: @(#)vid_tvga.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -321,7 +321,7 @@ static void *tvga8900d_init(const device_t *info) tvga->vram_size = device_get_config_int("memory") << 10; tvga->vram_mask = tvga->vram_size - 1; - rom_init(&tvga->bios_rom, L"roms/video/trident/tvga/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&tvga->bios_rom, L"video/trident/tvga/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&tvga->svga, tvga, tvga->vram_size, tvga_recalctimings, @@ -336,7 +336,7 @@ static void *tvga8900d_init(const device_t *info) static int tvga8900d_available(void) { - return rom_present(L"roms/video/trident/tvga/trident.bin"); + return rom_present(L"video/trident/tvga/trident.bin"); } void tvga_close(void *p) diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index c916c23..22819f3 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -8,7 +8,7 @@ * * IBM VGA emulation. * - * Version: @(#)vid_vga.c 1.0.3 2018/03/15 + * Version: @(#)vid_vga.c 1.0.4 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -122,7 +122,7 @@ static void *vga_init(const device_t *info) vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); - rom_init(&vga->bios_rom, L"roms/video/ibm/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + rom_init(&vga->bios_rom, L"video/ibm/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, @@ -145,7 +145,7 @@ static void *trigem_unk_init(const device_t *info) vga_t *vga = malloc(sizeof(vga_t)); memset(vga, 0, sizeof(vga_t)); - rom_init(&vga->bios_rom, L"roms/video/ibm/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + rom_init(&vga->bios_rom, L"video/ibm/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, @@ -188,7 +188,7 @@ void *ps1vga_init(const device_t *info) static int vga_available(void) { - return rom_present(L"roms/video/ibm/vga/ibm_vga.bin"); + return rom_present(L"video/ibm/vga/ibm_vga.bin"); } void vga_close(void *p) diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 6b7b845..01a547a 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -8,7 +8,7 @@ * * Emulation of the 3DFX Voodoo Graphics controller. * - * Version: @(#)vid_voodoo.c 1.0.5 2018/03/17 + * Version: @(#)vid_voodoo.c 1.0.6 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -7860,14 +7860,20 @@ void voodoo_card_close(voodoo_t *voodoo) int c; #ifndef RELEASE_BUILD - f = nvr_fopen(L"texram.dmp", L"wb"); - fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); - fclose(f); + f = plat_fopen(nvr_path(L"texram.dmp"), L"wb"); + if (f != NULL) + { + (void)fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + } if (voodoo->dual_tmus) { - f = nvr_fopen(L"texram2.dmp", L"wb"); - fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); - fclose(f); + f = plat_fopen(nvr_path(L"texram2.dmp"), L"wb"); + if (f != NULL) + { + (void)fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + } } #endif diff --git a/src/video/video.c b/src/video/video.c index a608027..c0b6cc8 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -40,7 +40,7 @@ * W = 3 bus clocks * L = 4 bus clocks * - * Version: @(#)video.c 1.0.8 2018/03/21 + * Version: @(#)video.c 1.0.10 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -713,7 +713,7 @@ loadfont(wchar_t *s, int format) FILE *f; int c,d; - f = rom_fopen(s); + f = plat_fopen(rom_path(s), L"rb"); if (f == NULL) { pclog("VIDEO: cannot load font '%ls', fmt=%d\n", s, format); return; diff --git a/src/video/video.h b/src/video/video.h index 6a65114..5fa3b2a 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -8,7 +8,7 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.11 2018/03/27 + * Version: @(#)video.h 1.0.12 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -40,7 +40,7 @@ # define EMU_VIDEO_H -#define FONT_ATIKOR_PATH L"roms/video/ati/ati28800/ati_ksc5601.rom" +#define FONT_ATIKOR_PATH L"video/ati/ati28800/ati_ksc5601.rom" #define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) diff --git a/src/win/VARCem.rc b/src/win/VARCem.rc index 95af334..db6f95a 100644 --- a/src/win/VARCem.rc +++ b/src/win/VARCem.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)VARCem.rc 1.0.9 2018/03/28 + * Version: @(#)VARCem.rc 1.0.11 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -66,8 +66,6 @@ MainMenu MENU DISCARDABLE BEGIN POPUP "&Action" BEGIN - MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT - MENUITEM SEPARATOR MENUITEM "&Hard Reset", IDM_ACTION_HRESET MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD MENUITEM SEPARATOR @@ -133,6 +131,8 @@ BEGIN MENUITEM SEPARATOR MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON + MENUITEM SEPARATOR + MENUITEM "R&ight CTRL is left ALT", IDM_KBD_RCTRL_IS_LALT END POPUP "&Tools" BEGIN @@ -631,13 +631,7 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -#ifdef RELEASE_BUILD -/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png */ -100 ICON DISCARDABLE "win/icons/emu-rb.ico" -#else -/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ -100 ICON DISCARDABLE "win/icons/emu.ico" -#endif +100 ICON DISCARDABLE "win/icons/varcem.ico" 128 ICON DISCARDABLE "win/icons/floppy_525.ico" 129 ICON DISCARDABLE "win/icons/floppy_525_active.ico" 144 ICON DISCARDABLE "win/icons/floppy_35.ico" @@ -966,7 +960,7 @@ BEGIN IDS_2154 "Unable to register Raw Input!" IDS_2155 "IRQ %i" IDS_2156 "%" PRIu64 - IDS_2157 "%" PRIu64 " MB (CHS: %" PRIu64 ", %" PRIu64 ", %" PRIu64 ")" + IDS_2157 "%" PRIu64 " MB (CHS: %u, %u, %u)" IDS_2158 "Floppy %i (%s): %ls" IDS_2159 "All images (*.0??;*.1??;*.360;*.720;*.86F;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF)\0*.0??;*.1??;*.360;*.720;*.86F;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.360;*.720;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.360;*.720;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F)\0*.86F\0All files (*.*)\0*.*\0" IDS_2160 "Configuration files (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0" @@ -1077,8 +1071,13 @@ END // VS_VERSION_INFO VERSIONINFO +#ifdef EMU_VER_PATCH + FILEVERSION EMU_VER_MAJOR,EMU_VER_MINOR,EMU_VER_REV,EMU_VER_PATCH + PRODUCTVERSION EMU_VER_MAJOR,EMU_VER_MINOR,EMU_VER_REV,EMU_VER_PATCH +#else FILEVERSION EMU_VER_MAJOR,EMU_VER_MINOR,EMU_VER_REV,0 PRODUCTVERSION EMU_VER_MAJOR,EMU_VER_MINOR,EMU_VER_REV,0 +#endif FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L diff --git a/src/win/icons/.attic/amu_2.ico b/src/win/icons/.attic/amu_2.ico new file mode 100644 index 0000000000000000000000000000000000000000..8d98359f3c46859c4886299a2261dc13a0547237 GIT binary patch literal 67646 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�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 F0RSzB|40A; literal 0 HcmV?d00001 diff --git a/src/win/icons/.attic/chip2-32x32.ico b/src/win/icons/.attic/chip2-32x32.ico new file mode 100644 index 0000000000000000000000000000000000000000..a64b20ddf958b09424f16fb02aae1c62f99834cc GIT binary patch literal 126740 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 b;KM&4XMy|y?W6nu|NlSO!8#yCg9ZZt9a{Fo literal 0 HcmV?d00001 diff --git a/src/win/icons/emu-rb.ico b/src/win/icons/.attic/emu-rb.ico similarity index 100% rename from src/win/icons/emu-rb.ico rename to src/win/icons/.attic/emu-rb.ico diff --git a/src/win/icons/emu.ico b/src/win/icons/.attic/emu.ico similarity index 100% rename from src/win/icons/emu.ico rename to src/win/icons/.attic/emu.ico diff --git a/src/win/icons/varcem.ico b/src/win/icons/varcem.ico new file mode 100644 index 0000000000000000000000000000000000000000..8d179fe4753cba4d73011185817a5d3ea34ec1cb GIT binary patch literal 36450 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 literal 0 HcmV?d00001 diff --git a/src/win/mingw/Makefile.MinGW b/src/win/mingw/Makefile.MinGW index a0241c9..9622da2 100644 --- a/src/win/mingw/Makefile.MinGW +++ b/src/win/mingw/Makefile.MinGW @@ -8,7 +8,7 @@ # # Makefile for Windows systems using the MinGW32 environment. # -# Version: @(#)Makefile.mingw 1.0.17 2018/03/27 +# Version: @(#)Makefile.mingw 1.0.18 2018/03/31 # # Author: Fred N. van Kempen, # @@ -240,6 +240,9 @@ else endif PREPROC := cpp WINDRES := windres + ifndef CAT + CAT := cat + endif SYSINC := -Iwin/mingw/include SYSLIB := @@ -688,6 +691,9 @@ ifneq ($(DEBUG), y) @strip hello.exe endif +foo.exe: foo.o + @$(CC) $(LDFLAGS) -o foo.exe \ + foo.o $(LIBS) clean: @echo Cleaning objects.. @@ -712,8 +718,8 @@ depclean: depends: DEPOBJ=$(OBJ:%.o=%.d) depends: depclean $(OBJ:%.o=%.d) - @-cat $(DEPOBJ) >>$(DEPFILE) - @-rm -f $(DEPOBJ) + @$(CAT) $(DEPOBJ) >>$(DEPFILE) +# @-rm -f $(DEPOBJ) $(DEPFILE): endif diff --git a/src/win/msvc/vc14/VARCem.vcxproj b/src/win/msvc/vc14/VARCem.vcxproj index c151fd4..f3e8086 100644 --- a/src/win/msvc/vc14/VARCem.vcxproj +++ b/src/win/msvc/vc14/VARCem.vcxproj @@ -659,25 +659,21 @@ true - $(ProjectDir)\..\Include;$(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) - $(ProjectDir)\..\Lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86 + $(ProjectDir)\..\Lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) true false - $(ProjectDir)\..\Include;$(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) - $(ProjectDir)\..\Lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64 + $(ProjectDir)\..\Lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) false - $(ProjectDir)\..\Include;$(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) - $(ProjectDir)\..\Lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86 + $(ProjectDir)\..\Lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) false false - $(ProjectDir)\..\Include;$(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) - $(ProjectDir)\..\Lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64 + $(ProjectDir)\..\Lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) diff --git a/src/win/msvc/vc14/global.props b/src/win/msvc/vc14/global.props index 1384760..d29a058 100644 --- a/src/win/msvc/vc14/global.props +++ b/src/win/msvc/vc14/global.props @@ -3,7 +3,7 @@ - $(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) + $(ProjectDir)\..\Include;$(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) diff --git a/src/win/msvc/vc15/VARCem.vcxproj b/src/win/msvc/vc15/VARCem.vcxproj index 7f36393..a006272 100644 --- a/src/win/msvc/vc15/VARCem.vcxproj +++ b/src/win/msvc/vc15/VARCem.vcxproj @@ -659,16 +659,20 @@ true + $(ProjectDir)\..\Lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) true + $(ProjectDir)\..\Lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) false false + $(ProjectDir)\..\Lib\x86;$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86) false + $(ProjectDir)\..\Lib\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64) false @@ -756,4 +760,4 @@ - \ No newline at end of file + diff --git a/src/win/msvc/vc15/global.props b/src/win/msvc/vc15/global.props index 1384760..d29a058 100644 --- a/src/win/msvc/vc15/global.props +++ b/src/win/msvc/vc15/global.props @@ -3,7 +3,7 @@ - $(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) + $(ProjectDir)\..\Include;$(ProjectDir)\..\..\mingw\include;$(ProjectDir)\..\..\mingw\include\pcap;$(IncludePath) diff --git a/src/win/pcap_if.rc b/src/win/pcap_if.rc index 92ecd74..6d83bb5 100644 --- a/src/win/pcap_if.rc +++ b/src/win/pcap_if.rc @@ -10,7 +10,7 @@ * * NOTE: Will be moved to the tools/ folder soon. * - * Version: @(#)pcap_if.rc 1.0.1 2018/02/14 + * Version: @(#)pcap_if.rc 1.0.3 2018/03/30 * * Author: Fred N. van Kempen, * @@ -53,20 +53,12 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #endif //_WIN32 -/* - * Icons by Devcore - * - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png - */ -#ifdef RELEASE_BUILD -100 ICON DISCARDABLE "win/icons/emu-rb.ico" -#else -100 ICON DISCARDABLE "win/icons/emu.ico" -#endif +100 ICON DISCARDABLE "win/icons/varcem.ico" VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,2,0 - PRODUCTVERSION 1,0,2,0 + FILEVERSION 1,0,3,0 + PRODUCTVERSION 1,0,3,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -81,18 +73,14 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "Comments", "\0" - VALUE "CompanyName", "IRC #VARCem on FreeNode\0" - VALUE "FileDescription", "PCap_IF - test tool for WinPcap\0" - VALUE "FileVersion", "1.0.2\0" - VALUE "InternalName", "pcap_if\0" - VALUE "LegalCopyright", "Copyright 2017,2018 Fred N. van Kempen\0" - VALUE "LegalTrademarks", "\0" - VALUE "OriginalFilename", "pcap_if.exe\0" - VALUE "PrivateBuild", "\0" - VALUE "ProductName", "WinPcap Test Tool\0" - VALUE "ProductVersion", "1.0.2\0" - VALUE "SpecialBuild", "\0" + VALUE "CompanyName", "IRC #VARCem on FreeNode" + VALUE "FileDescription", "PCap_IF - test tool for WinPcap" + VALUE "FileVersion", "1.0.3" + VALUE "InternalName", "pcap_if" + VALUE "LegalCopyright", "Copyright 2017,2018 Fred N. van Kempen" + VALUE "OriginalFilename", "pcap_if.exe" + VALUE "ProductName", "WinPcap Test Tool" + VALUE "ProductVersion", "1.0.3" END END BLOCK "VarFileInfo" diff --git a/src/win/resource.h b/src/win/resource.h index 5ebb120..af2c251 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -8,7 +8,7 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.6 2018/03/25 + * Version: @(#)resource.h 1.0.7 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -249,7 +249,6 @@ #define IDM_ABOUT 40001 #define IDC_ABOUT_ICON 65535 -#define IDM_ACTION_RCTRL_IS_LALT 40010 #define IDM_ACTION_SCREENSHOT 40011 #define IDM_ACTION_HRESET 40012 #define IDM_ACTION_RESET_CAD 40013 @@ -289,6 +288,7 @@ #define IDM_VID_GRAY_AMBER 40092 #define IDM_VID_GRAY_GREEN 40093 #define IDM_VID_GRAY_WHITE 40094 +#define IDM_KBD_RCTRL_IS_LALT 40101 #define IDM_LOG_BREAKPOINT 51201 #define IDM_DUMP_VRAM 51202 // should be an Action diff --git a/src/win/win.c b/src/win/win.c index 5df4f1d..97967af 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.9 2018/03/20 + * Version: @(#)win.c 1.0.10 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -249,10 +249,75 @@ plat_get_string(int i) } +/* Process the commandline, and create standard argc/argv array. */ +static int +ProcessCommandLine(wchar_t ***argw) +{ + WCHAR *cmdline; + wchar_t *argbuf; + wchar_t **args; + int argc_max; + int i, q, argc; + + cmdline = GetCommandLine(); + i = wcslen(cmdline) + 1; + argbuf = (wchar_t *)malloc(sizeof(wchar_t)*i); + wcscpy(argbuf, cmdline); + + argc = 0; + argc_max = 64; + args = (wchar_t **)malloc(sizeof(wchar_t *) * argc_max); + if (args == NULL) { + free(argbuf); + return(0); + } + + /* parse commandline into argc/argv format */ + i = 0; + while (argbuf[i]) { + while (argbuf[i] == L' ') + i++; + + if (argbuf[i]) { + if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) { + q = argbuf[i++]; + if (!argbuf[i]) + break; + } else + q = 0; + + args[argc++] = &argbuf[i]; + + if (argc >= argc_max) { + argc_max += 64; + args = realloc(args, sizeof(wchar_t *)*argc_max); + if (args == NULL) { + free(argbuf); + return(0); + } + } + + while ((argbuf[i]) && ((q) + ? (argbuf[i]!=q) : (argbuf[i]!=L' '))) i++; + + if (argbuf[i]) { + argbuf[i] = 0; + i++; + } + } + } + + args[argc] = NULL; + *argw = args; + + return(argc); +} + + #ifndef USE_WX /* Create a console if we don't already have one. */ -static void -CreateConsole(int init) +void +plat_console(int init) { HANDLE h; FILE *fp; @@ -334,71 +399,6 @@ CreateConsole(int init) } -/* Process the commandline, and create standard argc/argv array. */ -static int -ProcessCommandLine(wchar_t ***argw) -{ - WCHAR *cmdline; - wchar_t *argbuf; - wchar_t **args; - int argc_max; - int i, q, argc; - - cmdline = GetCommandLine(); - i = wcslen(cmdline) + 1; - argbuf = (wchar_t *)malloc(sizeof(wchar_t)*i); - wcscpy(argbuf, cmdline); - - argc = 0; - argc_max = 64; - args = (wchar_t **)malloc(sizeof(wchar_t *) * argc_max); - if (args == NULL) { - free(argbuf); - return(0); - } - - /* parse commandline into argc/argv format */ - i = 0; - while (argbuf[i]) { - while (argbuf[i] == L' ') - i++; - - if (argbuf[i]) { - if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) { - q = argbuf[i++]; - if (!argbuf[i]) - break; - } else - q = 0; - - args[argc++] = &argbuf[i]; - - if (argc >= argc_max) { - argc_max += 64; - args = realloc(args, sizeof(wchar_t *)*argc_max); - if (args == NULL) { - free(argbuf); - return(0); - } - } - - while ((argbuf[i]) && ((q) - ? (argbuf[i]!=q) : (argbuf[i]!=L' '))) i++; - - if (argbuf[i]) { - argbuf[i] = 0; - i++; - } - } - } - - args[argc] = NULL; - *argw = args; - - return(argc); -} - - /* For the Windows platform, this is the start of the application. */ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) @@ -424,7 +424,8 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) set_language(0x0409); /* Create console window. */ - CreateConsole(1); + if (force_debug) + plat_console(1); /* Process the command line for options. */ argc = ProcessCommandLine(&argw); @@ -432,13 +433,13 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) /* Pre-initialize the system, this loads the config file. */ if (! pc_init(argc, argw)) { /* Detach from console. */ - CreateConsole(0); + plat_console(0); return(1); } /* Cleanup: we may no longer need the console. */ if (! force_debug) - CreateConsole(0); + plat_console(0); /* Handle our GUI. */ i = ui_init(nCmdShow); diff --git a/src/win/win.h b/src/win/win.h index 72fc1f2..d33181d 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -8,7 +8,7 @@ * * Platform support defintions for Win32. * - * Version: @(#)win.h 1.0.5 2018/03/08 + * Version: @(#)win.h 1.0.6 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -72,9 +72,8 @@ extern HICON hIcon[512]; extern int status_is_open; -extern char openfilestring[260]; -extern WCHAR wopenfilestring[260]; - +extern char openfilestring[]; +extern WCHAR wopenfilestring[]; extern DWORD filterindex; @@ -144,14 +143,8 @@ extern void StatusBarCreate(HWND hwndParent, uintptr_t idStatus, /* Functions in win_dialog.c: */ extern void dialog_center(HWND hdlg); - -extern wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title); - -extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save); -extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save); -extern int file_dlg_mb(HWND hwnd, char *f, char *fn, int save); -extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save); -extern int file_dlg_st(HWND hwnd, int i, char *fn, int save); +extern int file_dlg(HWND hwnd, WCHAR *filt, WCHAR *ifn, int save); +extern int file_dlg_st(HWND hwnd, int i, WCHAR *fn, int save); #ifdef __cplusplus diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 1ed2081..46192f6 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -8,7 +8,11 @@ * * Imlementation of the Device Configuration dialog. * - * Version: @(#)win_devconf.c 1.0.6 2018/03/20 + * This module takes a standard 'device_config_t' structure, + * and builds a complete Win32 DIALOG resource block in a + * buffer in memory, and then passes that to the API handler. + * + * Version: @(#)win_devconf.c 1.0.7 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -52,9 +56,8 @@ #include "win.h" -static device_t *config_device; - -static uint8_t deviceconfig_changed = 0; +static device_t *config_device; +static uint8_t deviceconfig_changed = 0; #ifdef __amd64__ @@ -62,10 +65,11 @@ static LRESULT CALLBACK #else static BOOL CALLBACK #endif -deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +dlg_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { + wchar_t ws[512]; + char s[512]; HWND h; - int val_int; int id; int c; @@ -73,26 +77,20 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) int changed; int cid; const device_config_t *config; - char s[80]; - wchar_t ws[512]; LPTSTR lptsTemp; switch (message) { - case WM_INITDIALOG: - { - id = IDC_CONFIG_BASE; - config = config_device->config; + case WM_INITDIALOG: + id = IDC_CONFIG_BASE; + config = config_device->config; + lptsTemp = (LPTSTR)malloc(512); - lptsTemp = (LPTSTR) malloc(512); + while (config->type != -1) { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); - while (config->type != -1) - { - const device_config_selection_t *selection = config->selection; - h = GetDlgItem(hdlg, id); - - switch (config->type) - { - case CONFIG_BINARY: + switch (config->type) { + case CONFIG_BINARY: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); SendMessage(h, BM_SETCHECK, val_int, 0); @@ -100,12 +98,11 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id++; break; - case CONFIG_SELECTION: + case CONFIG_SELECTION: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); c = 0; - while (selection->description && selection->description[0]) - { + while (selection->description && selection->description[0]) { mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); if (val_int == selection->value) @@ -113,50 +110,45 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) selection++; c++; } - id += 2; break; - case CONFIG_MIDI: + case CONFIG_MIDI: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); num = plat_midi_get_num_devs(); - for (c = 0; c < num; c++) - { + for (c = 0; c < num; c++) { plat_midi_get_dev_name(c, s); mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); if (val_int == c) SendMessage(h, CB_SETCURSEL, c, 0); } - id += 2; break; - case CONFIG_SPINNER: + case CONFIG_SPINNER: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); _swprintf(ws, L"%i", val_int); SendMessage(h, WM_SETTEXT, 0, (LPARAM)ws); - id += 2; break; - case CONFIG_FNAME: + case CONFIG_FNAME: { - wchar_t* str = config_get_wstring((char *)config_device->name, (char *)config->name, 0); - if (str) - SendMessage(h, WM_SETTEXT, 0, (LPARAM)str); - id += 3; + wchar_t* str = config_get_wstring((char *)config_device->name, (char *)config->name, 0); + if (str) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)str); + id += 3; } break; - case CONFIG_HEX16: + case CONFIG_HEX16: val_int = config_get_hex16((char *)config_device->name, (char *)config->name, config->default_int); c = 0; - while (selection->description && selection->description[0]) - { + while (selection->description && selection->description[0]) { mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); if (val_int == selection->value) @@ -164,16 +156,14 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) selection++; c++; } - id += 2; break; - case CONFIG_HEX20: + case CONFIG_HEX20: val_int = config_get_hex20((char *)config_device->name, (char *)config->name, config->default_int); c = 0; - while (selection->description && selection->description[0]) - { + while (selection->description && selection->description[0]) { mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); if (val_int == selection->value) @@ -181,44 +171,36 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) selection++; c++; } - id += 2; break; - } - config++; } - - free(lptsTemp); + config++; } + + free(lptsTemp); return TRUE; - case WM_COMMAND: - { - cid = LOWORD(wParam); - if (cid == IDOK) - { - id = IDC_CONFIG_BASE; - config = config_device->config; - changed = 0; - char s[512]; + case WM_COMMAND: + cid = LOWORD(wParam); + if (cid == IDOK) { + id = IDC_CONFIG_BASE; + config = config_device->config; + changed = 0; - while (config->type != -1) - { - const device_config_selection_t *selection = config->selection; - h = GetDlgItem(hdlg, id); + while (config->type != -1) { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); - switch (config->type) - { - case CONFIG_BINARY: + switch (config->type) { + case CONFIG_BINARY: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) changed = 1; - id++; break; - case CONFIG_SELECTION: + case CONFIG_SELECTION: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); c = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -228,33 +210,30 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (val_int != selection->value) changed = 1; - id += 2; break; - case CONFIG_MIDI: + case CONFIG_MIDI: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); c = SendMessage(h, CB_GETCURSEL, 0, 0); if (val_int != c) changed = 1; - id += 2; break; - case CONFIG_FNAME: + case CONFIG_FNAME: { - char* str = config_get_string((char *)config_device->name, (char *)config->name, (char*)""); - SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); - if (strcmp(str, s)) + char* str = config_get_string((char *)config_device->name, (char *)config->name, (char*)""); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); + if (strcmp(str, s)) changed = 1; - id += 3; } break; - case CONFIG_SPINNER: + case CONFIG_SPINNER: val_int = config_get_int((char *)config_device->name, (char *)config->name, config->default_int); if (val_int > config->spinner.max) val_int = config->spinner.max; @@ -267,11 +246,10 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (val_int != c) changed = 1; - id += 2; break; - case CONFIG_HEX16: + case CONFIG_HEX16: val_int = config_get_hex16((char *)config_device->name, (char *)config->name, config->default_int); c = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -281,11 +259,10 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (val_int != selection->value) changed = 1; - id += 2; break; - case CONFIG_HEX20: + case CONFIG_HEX20: val_int = config_get_hex20((char *)config_device->name, (char *)config->name, config->default_int); c = SendMessage(h, CB_GETCURSEL, 0, 0); @@ -295,39 +272,35 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (val_int != selection->value) changed = 1; - id += 2; break; - } - config++; } + config++; + } - if (!changed) - { - deviceconfig_changed = 0; - EndDialog(hdlg, 0); - return TRUE; - } + if (! changed) { + deviceconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } - deviceconfig_changed = 1; + deviceconfig_changed = 1; - id = IDC_CONFIG_BASE; - config = config_device->config; + id = IDC_CONFIG_BASE; + config = config_device->config; - while (config->type != -1) - { - const device_config_selection_t *selection = config->selection; - h = GetDlgItem(hdlg, id); + while (config->type != -1) { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); - switch (config->type) - { - case CONFIG_BINARY: + switch (config->type) { + case CONFIG_BINARY: config_set_int((char *)config_device->name, (char *)config->name, SendMessage(h, BM_GETCHECK, 0, 0)); id++; break; - case CONFIG_SELECTION: + case CONFIG_SELECTION: c = SendMessage(h, CB_GETCURSEL, 0, 0); for (; c > 0; c--) selection++; @@ -336,21 +309,21 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - case CONFIG_MIDI: + case CONFIG_MIDI: c = SendMessage(h, CB_GETCURSEL, 0, 0); config_set_int((char *)config_device->name, (char *)config->name, c); id += 2; break; - case CONFIG_FNAME: + case CONFIG_FNAME: SendMessage(h, WM_GETTEXT, 511, (LPARAM)ws); config_set_wstring((char *)config_device->name, (char *)config->name, ws); id += 3; break; - case CONFIG_SPINNER: + case CONFIG_SPINNER: SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); wcstombs(s, ws, 79); sscanf(s, "%i", &c); @@ -364,7 +337,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - case CONFIG_HEX16: + case CONFIG_HEX16: c = SendMessage(h, CB_GETCURSEL, 0, 0); for (; c > 0; c--) selection++; @@ -373,7 +346,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - case CONFIG_HEX20: + case CONFIG_HEX20: c = SendMessage(h, CB_GETCURSEL, 0, 0); for (; c > 0; c--) selection++; @@ -381,139 +354,127 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; - } - config++; } + config++; + } - EndDialog(hdlg, 0); - return TRUE; - } - else if (cid == IDCANCEL) - { - deviceconfig_changed = 0; - EndDialog(hdlg, 0); - return TRUE; - } - else - { - int id = IDC_CONFIG_BASE; - const device_config_t *config = config_device->config; + EndDialog(hdlg, 0); + return TRUE; + } else if (cid == IDCANCEL) { + deviceconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } else { + int id = IDC_CONFIG_BASE; + const device_config_t *config = config_device->config; - while (config->type != -1) - { - switch (config->type) - { - case CONFIG_BINARY: + while (config->type != -1) { + switch (config->type) { + case CONFIG_BINARY: id++; break; - case CONFIG_SELECTION: - case CONFIG_MIDI: - case CONFIG_SPINNER: + case CONFIG_SELECTION: + case CONFIG_MIDI: + case CONFIG_SPINNER: id += 2; break; - case CONFIG_FNAME: - { - if (cid == id+1) - { - char s[512]; - s[0] = 0; - int c, d; - HWND h = GetDlgItem(hdlg, id); - SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); - char file_filter[512]; - file_filter[0] = 0; + case CONFIG_FNAME: + if (cid == id+1) { + int c, d; + HWND h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); + char file_filter[512]; + file_filter[0] = 0; - c = 0; - while (config->file_filter[c].description && config->file_filter[c].description[0]) - { - if (c > 0) - strcat(file_filter, "|"); - strcat(file_filter, config->file_filter[c].description); - strcat(file_filter, " ("); - d = 0; - while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) - { + c = 0; + while (config->file_filter[c].description && config->file_filter[c].description[0]) { + if (c > 0) + strcat(file_filter, "|"); + strcat(file_filter, config->file_filter[c].description); + strcat(file_filter, " ("); + d = 0; + while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) { if (d > 0) - strcat(file_filter, ";"); - strcat(file_filter, "*."); - strcat(file_filter, config->file_filter[c].extensions[d]); - d++; - } - strcat(file_filter, ")|"); - d = 0; - while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) - { - if (d > 0) - strcat(file_filter, ";"); - strcat(file_filter, "*."); - strcat(file_filter, config->file_filter[c].extensions[d]); - d++; - } - c++; + strcat(file_filter, ";"); + strcat(file_filter, "*."); + strcat(file_filter, config->file_filter[c].extensions[d]); + d++; } - strcat(file_filter, "|All files (*.*)|*.*|"); - mbstowcs(ws, file_filter, strlen(file_filter) + 1); - d = strlen(file_filter); - - /* replace | with \0 */ - for (c = 0; c < d; ++c) - if (ws[c] == L'|') - ws[c] = 0; - - if (!file_dlg(hdlg, ws, s, 0)) - SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); + strcat(file_filter, ")|"); + d = 0; + while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) { + if (d > 0) + strcat(file_filter, ";"); + strcat(file_filter, "*."); + strcat(file_filter, config->file_filter[c].extensions[d]); + d++; + } + c++; } - } - break; - } - config++; + strcat(file_filter, "|All files (*.*)|*.*|"); + mbstowcs(ws, file_filter, strlen(file_filter) + 1); + d = strlen(file_filter); + + /* replace | with \0 */ + for (c = 0; c < d; ++c) + if (ws[c] == L'|') + ws[c] = 0; + + if (! file_dlg(hdlg, ws, L"", 0)) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); + } + break; } - } - } - break; - } - return FALSE; + config++; + } + } + break; + } + + return FALSE; } -uint8_t deviceconfig_open(HWND hwnd, device_t *device) + +uint8_t +deviceconfig_open(HWND hwnd, device_t *device) { - const device_config_t *config = device->config; - uint16_t *data_block = malloc(16384); - uint16_t *data; - DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; - DLGITEMTEMPLATE *item; - int y = 10; - int id = IDC_CONFIG_BASE; + const device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; - deviceconfig_changed = 0; + deviceconfig_changed = 0; - memset(data_block, 0, 4096); + memset(data_block, 0x00, sizeof(16384)); - dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; - dlg->x = 10; - dlg->y = 10; - dlg->cx = 220; - dlg->cy = 70; + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | \ + WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; - data = (uint16_t *)(dlg + 1); + data = (uint16_t *)(dlg + 1); - *data++ = 0; /*no menu*/ - *data++ = 0; /*predefined dialog box class*/ - data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, + "Device Configuration", -1, data, 50); - *data++ = 9; /*Point*/ - data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 50); + *data++ = 9; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 50); - if (((uintptr_t)data) & 2) - data++; + if (((uintptr_t)data) & 2) + data++; - while (config->type != -1) - { - switch (config->type) - { - case CONFIG_BINARY: + while (config->type != -1) { + switch (config->type) { + case CONFIG_BINARY: item = (DLGITEMTEMPLATE *)data; item->x = 10; item->y = y; @@ -528,16 +489,17 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) *data++ = 0xFFFF; *data++ = 0x0080; /* button class */ - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + config->description, -1, data, 256); *data++ = 0; /* no creation data */ y += 20; break; - case CONFIG_SELECTION: - case CONFIG_MIDI: - case CONFIG_HEX16: - case CONFIG_HEX20: + case CONFIG_SELECTION: + case CONFIG_MIDI: + case CONFIG_HEX16: + case CONFIG_HEX20: /*Combo box*/ item = (DLGITEMTEMPLATE *)data; item->x = 70; @@ -547,13 +509,15 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) item->cx = 140; item->cy = 150; - item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + item->style = WS_CHILD | WS_VISIBLE | \ + CBS_DROPDOWN | WS_VSCROLL; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; *data++ = 0x0085; /* combo box class */ - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + config->description, -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -574,7 +538,8 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) *data++ = 0xFFFF; *data++ = 0x0082; /* static class */ - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + config->description, -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -583,7 +548,7 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) y += 20; break; - case CONFIG_SPINNER: + case CONFIG_SPINNER: /*Spinner*/ item = (DLGITEMTEMPLATE *)data; item->x = 70; @@ -593,14 +558,16 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) item->cx = 140; item->cy = 14; - item->style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER; + item->style = WS_CHILD | WS_VISIBLE | \ + ES_AUTOHSCROLL | ES_NUMBER; item->dwExtendedStyle = WS_EX_CLIENTEDGE; data = (uint16_t *)(item + 1); *data++ = 0xFFFF; *data++ = 0x0081; /* edit text class */ - data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + "", -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -622,7 +589,8 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) *data++ = 0xFFFF; *data++ = 0x0082; /* static class */ - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + config->description, -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -631,7 +599,7 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) y += 20; break; - case CONFIG_FNAME: + case CONFIG_FNAME: /*File*/ item = (DLGITEMTEMPLATE *)data; item->x = 70; @@ -648,7 +616,8 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) *data++ = 0xFFFF; *data++ = 0x0081; /* edit text class */ - data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + "", -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -669,7 +638,8 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) *data++ = 0xFFFF; *data++ = 0x0080; /* button class */ - data += MultiByteToWideChar(CP_ACP, 0, "Browse", -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + "Browse", -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -690,7 +660,8 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) *data++ = 0xFFFF; *data++ = 0x0082; /* static class */ - data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + data += MultiByteToWideChar(CP_ACP, 0, + config->description, -1, data, 256); *data++ = 0; /* no creation data */ if (((uintptr_t)data) & 2) @@ -698,56 +669,56 @@ uint8_t deviceconfig_open(HWND hwnd, device_t *device) y += 20; break; - } - - if (((uintptr_t)data) & 2) - data++; - - config++; } - dlg->cdit = (id - IDC_CONFIG_BASE) + 2; - - item = (DLGITEMTEMPLATE *)data; - item->x = 20; - item->y = y; - item->cx = 50; - item->cy = 14; - item->id = IDOK; /* OK button identifier */ - item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; - - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0080; /* button class */ - - data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); - *data++ = 0; /* no creation data */ - if (((uintptr_t)data) & 2) data++; - item = (DLGITEMTEMPLATE *)data; - item->x = 80; - item->y = y; - item->cx = 50; - item->cy = 14; - item->id = IDCANCEL; /* OK button identifier */ - item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + config++; + } - data = (uint16_t *)(item + 1); - *data++ = 0xFFFF; - *data++ = 0x0080; /* button class */ + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; - data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); - *data++ = 0; /* no creation data */ + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; - dlg->cy = y + 20; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ - config_device = device; + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; /* no creation data */ - DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + if (((uintptr_t)data) & 2) + data++; - free(data_block); + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; - return deviceconfig_changed; + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; /* no creation data */ + + dlg->cy = y + 20; + + config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, dlg_proc); + + free(data_block); + + return deviceconfig_changed; } diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index ae4066a..8a2e6f0 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -8,7 +8,7 @@ * * Implementation of server several dialogs. * - * Version: @(#)win_dialog.c 1.0.4 2018/03/08 + * Version: @(#)win_dialog.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,22 +53,12 @@ #include "win.h" -WCHAR path[MAX_PATH]; -WCHAR wopenfilestring[260]; -char openfilestring[260]; +WCHAR wopenfilestring[1024]; +char openfilestring[1024]; DWORD filterindex = 0; -static int CALLBACK -BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - if (uMsg == BFFM_INITIALIZED) - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); - - return(0); -} - - +/* Center a dialog window with respect to the main window. */ void dialog_center(HWND hdlg) { @@ -96,37 +86,6 @@ dialog_center(HWND hdlg) } -wchar_t * -BrowseFolder(wchar_t *saved_path, wchar_t *title) -{ - BROWSEINFO bi = { 0 }; - LPITEMIDLIST pidl; - IMalloc *imalloc; - - bi.lpszTitle = title; - bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; - bi.lpfn = BrowseCallbackProc; - bi.lParam = (LPARAM) saved_path; - - pidl = SHBrowseForFolder(&bi); - if (pidl != 0) { - /* Get the name of the folder and put it in path. */ - SHGetPathFromIDList(pidl, path); - - /* Free memory used. */ - imalloc = 0; - if (SUCCEEDED(SHGetMalloc(&imalloc))) { - imalloc->lpVtbl->Free(imalloc, pidl); - imalloc->lpVtbl->Release(imalloc); - } - - return(path); - } - - return(L""); -} - - int ui_msgbox(int flags, void *arg) { @@ -209,101 +168,78 @@ ui_msgbox(int flags, void *arg) } -#if 0 int -msgbox_reset_yn(HWND hwnd) -{ - return(MessageBox(hwnd, plat_get_string(IDS_2051), -#endif - - -int -file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) +file_dlg(HWND hwnd, WCHAR *filt, WCHAR *ifn, int save) { OPENFILENAME ofn; + wchar_t fn[1024]; + char temp[1024]; BOOL r; - /* DWORD err; */ + DWORD err; - /* Initialize OPENFILENAME */ - ZeroMemory(&ofn, sizeof(ofn)); + /* Clear out the ("initial") pathname. */ + memset(fn, 0x00, sizeof(fn)); + + /* Initialize OPENFILENAME. */ + memset(&ofn, 0x00, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; - ofn.lpstrFile = wopenfilestring; - /* - * Set lpstrFile[0] to '\0' so that GetOpenFileName does - * not use the contents of szFile to initialize itself. - */ - memcpy(ofn.lpstrFile, fn, (wcslen(fn) << 1) + 2); - ofn.nMaxFile = 259; - ofn.lpstrFilter = f; + /* This is the buffer in which to place the resulting filename. */ + ofn.lpstrFile = fn; + ofn.nMaxFile = sizeof_w(fn); + + /* Set up the "file types" filter. */ + ofn.lpstrFilter = filt; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = NULL; + + /* Tell the dialog where to go initially. */ + ofn.lpstrInitialDir = usr_path; + + /* Set up the flags for this dialog. */ ofn.Flags = OFN_PATHMUSTEXIST; if (! save) ofn.Flags |= OFN_FILEMUSTEXIST; /* Display the Open dialog box. */ - if (save) { -// pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); + if (save) r = GetSaveFileName(&ofn); - } else { -// pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); + else r = GetOpenFileName(&ofn); - } + /* OK, just to make sure the dialog did not change our CWD. */ plat_chdir(usr_path); if (r) { + /* All good, see if we can make this a relative path. */ + pc_path(wopenfilestring, sizeof_w(wopenfilestring), fn); + + /* All good, create an ASCII copy of the string as well. */ wcstombs(openfilestring, wopenfilestring, sizeof(openfilestring)); + + /* Remember the file type for next time. */ filterindex = ofn.nFilterIndex; -// pclog("File dialog return true\n"); return(0); } - /* pclog("File dialog return false\n"); */ - /* err = CommDlgExtendedError(); - pclog("CommDlgExtendedError return %04X\n", err); */ + /* If an error occurred, log this. */ + err = CommDlgExtendedError(); + if (err != NO_ERROR) { + sprintf(temp, "OpenFile(%ls, %d):\n\n error 0x%08lx", + usr_path, save, err); + pclog("%s\n", temp); + (void)ui_msgbox(MBX_ERROR|MBX_ANSI, temp); + } return(1); } int -file_dlg(HWND hwnd, WCHAR *f, char *fn, int save) -{ - WCHAR ufn[512]; - - mbstowcs(ufn, fn, strlen(fn) + 1); - - return(file_dlg_w(hwnd, f, ufn, save)); -} - - -int -file_dlg_mb(HWND hwnd, char *f, char *fn, int save) -{ - WCHAR uf[512], ufn[512]; - - mbstowcs(uf, f, strlen(fn) + 1); - mbstowcs(ufn, fn, strlen(fn) + 1); - - return(file_dlg_w(hwnd, uf, ufn, save)); -} - - -int -file_dlg_w_st(HWND hwnd, int id, WCHAR *fn, int save) -{ - return(file_dlg_w(hwnd, plat_get_string(id), fn, save)); -} - - -int -file_dlg_st(HWND hwnd, int id, char *fn, int save) +file_dlg_st(HWND hwnd, int id, WCHAR *fn, int save) { return(file_dlg(hwnd, plat_get_string(id), fn, save)); } diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index 518b53f..670eec0 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -8,7 +8,7 @@ * * Implementation of the New Floppy Image dialog. * - * Version: @(#)win_new_floppy.c 1.0.8 2018/03/18 + * Version: @(#)win_new_floppy.c 1.0.9 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -643,7 +643,7 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; case IDC_CFILE: - if (!file_dlg_w(hdlg, plat_get_string(is_zip ? IDS_2176 : IDS_2174), L"", 1)) { + if (!file_dlg(hdlg, plat_get_string(is_zip ? IDS_2176 : IDS_2174), L"", 1)) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { twcs = &wopenfilestring[wcslen(wopenfilestring)]; diff --git a/src/win/win_settings.c b/src/win/win_settings.c index e3359fc..9ba530a 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Implementation of the Settings dialog. * - * Version: @(#)win_settings.c 1.0.15 2018/03/28 + * Version: @(#)win_settings.c 1.0.17 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -2122,11 +2122,11 @@ static uint8_t next_free_ide_channel(void) static void next_free_scsi_id_and_lun(uint8_t *id, uint8_t *lun) { - uint8_t i, j; + int i, j; - for (j = 0; j < 8; j++) { - for (i = 0; i < 16; i++) { - if (!(scsi_tracking[i] & (0xffLL << (j << 3LL)))) { + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + if (! (scsi_tracking[i] & (0xffULL << (j << 3LL)))) { *id = i; *lun = j; return; @@ -2697,11 +2697,12 @@ static uint64_t hdconf_initialize_hdt_combo(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); for (i = 0; i < 127; i++) { - temp_size = hdd_table[i][0] * hdd_table[i][1] * hdd_table[i][2]; + temp_size = hdd_table[i].cyls * hdd_table[i].head * hdd_table[i].sect; size_mb = temp_size >> 11; - swprintf(szText, 255, plat_get_string(IDS_2157), size_mb, hdd_table[i][0], hdd_table[i][1], hdd_table[i][2]); + swprintf(szText, 255, plat_get_string(IDS_2157), size_mb, + hdd_table[i].cyls, hdd_table[i].head, hdd_table[i].sect); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); - if ((tracks == hdd_table[i][0]) && (hpc == hdd_table[i][1]) && (spt == hdd_table[i][2])) + if ((tracks == hdd_table[i].cyls) && (hpc == hdd_table[i].head) && (spt == hdd_table[i].sect)) { selection = i; } @@ -2721,7 +2722,7 @@ static void recalc_selection(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); for (i = 0; i < 127; i++) { - if ((tracks == hdd_table[i][0]) && (hpc == hdd_table[i][1]) && (spt == hdd_table[i][2])) + if ((tracks == hdd_table[i].cyls) && (hpc == hdd_table[i].head) && (spt == hdd_table[i].sect)) { selection = i; } @@ -2742,6 +2743,7 @@ static BOOL CALLBACK #endif hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { + char buf[512], *big_buf; HWND h = INVALID_HANDLE_VALUE; uint64_t i = 0; uint64_t temp; @@ -2750,8 +2752,6 @@ hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) uint32_t zero = 0; uint32_t base = 0x1000; uint64_t signature = 0xD778A82044445459ll; - char buf[512]; - char *big_buf; int b = 0; uint64_t r = 0; uint8_t channel = 0; @@ -2784,6 +2784,7 @@ hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); size = (tracks * hpc * spt) << 9; set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + hdconf_initialize_hdt_combo(hdlg); if (existing & 1) { @@ -2803,7 +2804,9 @@ hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { chs_enabled = 1; } + add_locations(hdlg); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); if (existing & 2) { @@ -2820,6 +2823,7 @@ hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, CB_SETCURSEL, hdd_ptr->bus, 0); max_tracks = 266305; recalc_location_controls(hdlg, 1, 0); + if (existing & 2) { /* We're functioning as a load image dialog for a removable SCSI hard disk, @@ -2898,15 +2902,19 @@ hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) else if ((wcslen(hd_file_name) == 0) && (hdd_ptr->bus == HDD_BUS_SCSI_REMOVABLE)) { /* Mark hard disk added but return empty - it will signify the disk was ejected. */ - hdd_ptr->spt = hdd_ptr->hpc = hdd_ptr->tracks = 0; + hdd_ptr->tracks = 0; + hdd_ptr->spt = hdd_ptr->hpc = 0; memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); goto hd_add_ok_common; } - get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &(hdd_ptr->spt)); - get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &(hdd_ptr->hpc)); - get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &(hdd_ptr->tracks)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &i); + hdd_ptr->spt = (uint8_t)i; + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &i); + hdd_ptr->hpc = (uint8_t)i; + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &i); + hdd_ptr->tracks = (uint16_t)i; spt = hdd_ptr->spt; hpc = hdd_ptr->hpc; tracks = hdd_ptr->tracks; @@ -3071,7 +3079,7 @@ hd_add_ok_common: return TRUE; case IDC_CFILE: - if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", !(existing & 1))) + if (!file_dlg(hdlg, plat_get_string(IDS_4106), L"", !(existing & 1))) { if (!wcschr(wopenfilestring, L'.')) { if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { @@ -3324,9 +3332,9 @@ hdd_add_file_open_error: if ((temp != selection) && (temp != 127) && (temp != 128)) { selection = temp; - tracks = hdd_table[selection][0]; - hpc = hdd_table[selection][1]; - spt = hdd_table[selection][2]; + tracks = hdd_table[selection].cyls; + hpc = hdd_table[selection].head; + spt = hdd_table[selection].sect; size = (tracks * hpc * spt) << 9; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index eda867f..814589f 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -8,7 +8,7 @@ * * Implementation of the Status Bar module. * - * Version: @(#)win_stbar.c 1.0.4 2018/03/18 + * Version: @(#)win_stbar.c 1.0.5 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1023,7 +1023,7 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if ((part == -1) || (sb_menu_handles == NULL)) break; - ret = file_dlg_w_st(hwnd, IDS_2159, floppyfns[id], 0); + ret = file_dlg_st(hwnd, IDS_2159, floppyfns[id], 0); if (! ret) ui_sb_mount_floppy_img(id, part, (item_id == IDM_FLOPPY_IMAGE_EXISTING_WP) ? 1 : 0, wopenfilestring); break; @@ -1048,7 +1048,7 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if ((part == -1) || (sb_menu_handles == NULL)) break; - ret = file_dlg_w_st(hwnd, IDS_2173, floppyfns[id], 1); + ret = file_dlg_st(hwnd, IDS_2173, floppyfns[id], 1); if (! ret) { plat_pause(1); ret = d86f_export(id, wopenfilestring); @@ -1086,7 +1086,7 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if ((part == -1) || (sb_menu_handles == NULL)) break; - if (!file_dlg_w_st(hwnd, IDS_2075, cdrom_image[id].image_path, 0)) { + if (!file_dlg_st(hwnd, IDS_2075, cdrom_image[id].image_path, 0)) { cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; wcscpy(temp_path, wopenfilestring); if (!cdrom_image[id].prev_image_path) @@ -1164,7 +1164,7 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if ((part == -1) || (sb_menu_handles == NULL)) break; - ret = file_dlg_w_st(hwnd, IDS_2175, zip_drives[id].image_path, 0); + ret = file_dlg_st(hwnd, IDS_2175, zip_drives[id].image_path, 0); if (! ret) ui_sb_mount_zip_img(id, part, (item_id == IDM_ZIP_IMAGE_EXISTING_WP) ? 1 : 0, wopenfilestring); break; @@ -1197,7 +1197,7 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_RDISK_IMAGE: case IDM_RDISK_IMAGE_WP: id = item_params & 0x001f; - ret = file_dlg_w_st(hwnd, IDS_4106, hdd[id].fn, id); + ret = file_dlg_st(hwnd, IDS_4106, hdd[id].fn, id); if (!ret) { removable_disk_unload(id); memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 3eea816..60b30c0 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * Implement the user Interface module. * - * Version: @(#)win_ui.c 1.0.7 2018/03/20 + * Version: @(#)win_ui.c 1.0.8 2018/03/31 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -151,7 +151,7 @@ ResetAllMenus(void) EnableMenuItem(menuMain, IDM_CONFIG_SAVE, MF_DISABLED); #endif - CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_KBD_RCTRL_IS_LALT, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, MF_UNCHECKED); @@ -213,7 +213,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+3, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+4, MF_UNCHECKED); - CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_KBD_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); @@ -331,12 +331,6 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) keyboard_send_cae(); break; - case IDM_ACTION_RCTRL_IS_LALT: - rctrl_is_lalt ^= 1; - CheckMenuItem(hmenu, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); - config_save(); - break; - case IDM_ACTION_PAUSE: plat_pause(dopause ^ 1); CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); @@ -510,6 +504,12 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) config_save(); break; + case IDM_KBD_RCTRL_IS_LALT: + rctrl_is_lalt ^= 1; + CheckMenuItem(hmenu, IDM_KBD_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + #ifdef ENABLE_LOG_TOGGLES # ifdef ENABLE_BUSLOGIC_LOG case IDM_LOG_BUSLOGIC: @@ -575,7 +575,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_CONFIG_LOAD: plat_pause(1); - if (!file_dlg_st(hwnd, IDS_2160, "", 0) && + if (! file_dlg_st(hwnd, IDS_2160, L"", 0) && (ui_msgbox(MBX_QUESTION, (wchar_t *)IDS_2051) == IDYES)) { pc_reload(wopenfilestring); ResetAllMenus(); @@ -585,7 +585,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_CONFIG_SAVE: plat_pause(1); - if (! file_dlg_st(hwnd, IDS_2160, "", 1)) { + if (! file_dlg_st(hwnd, IDS_2160, L"", 1)) { config_write(wopenfilestring); } plat_pause(0); @@ -891,7 +891,6 @@ ui_init(int nCmdShow) /* Create the Machine Rendering window. */ hwndRender = CreateWindow(L"STATIC", NULL, WS_CHILD|SS_BITMAP, 0, 0, 1, 1, hwnd, NULL, hinstance, NULL); - MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); /* That looks good, now continue setting up the machine. */ switch (pc_init_modules()) { @@ -928,8 +927,13 @@ ui_init(int nCmdShow) if (start_in_fullscreen) plat_setfullscreen(1); + /* Activate the render window, this will also set the screen size. */ + MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); + +#if 0 /* Set up the current window size. */ plat_resize(scrnsz_x, scrnsz_y); +#endif /* Fire up the machine. */ pc_reset_hard(); @@ -937,13 +941,6 @@ ui_init(int nCmdShow) /* Set the PAUSE mode depending on the renderer. */ plat_pause(0); - /* If so requested via the command line, inform the - * application that started us of our HWND, using the - * the hWnd and unique ID the application has given - * us. */ - if (source_hwnd) - SendMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) hwndMain); - /* * Everything has been configured, and all seems to work, * so now it is time to start the main thread to do some