diff --git a/doc/build.md b/doc/build.md index 0b226dc33..a816e5d98 100644 --- a/doc/build.md +++ b/doc/build.md @@ -2,7 +2,7 @@ Building ======== In order to compile 86Box from this repository, please follow this step-by-step guide: -1. Install the [MSYS2](https://www.msys2.org/) environment. The rest of the guide will refer to the directory that you install it to (C:\msys32 or C:\msys64 by default) as the MSYS2 root. +1. Install the [MSYS2](https://www.msys2.org/) environment. The rest of the guide will refer to the directory that you install it to (`C:\msys32` or `C:\msys64` by default) as the MSYS2 root. 2. Launch your MSYS2 environment using the `MSYS2 MinGW 32-bit` shortcut. If you do not want to use the shortcut, launch it using the `mingw32.exe` executable in the MSYS2 root. diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 2b3b1e812..2557c8a80 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -275,6 +275,7 @@ piix_write(int func, int addr, uint8_t val, void *priv) { piix_t *dev = (piix_t *) priv; uint8_t *fregs; + uint16_t base; int i; /* Return on unsupported function. */ @@ -443,8 +444,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) else fregs[addr] = val & 0xc0; + base = fregs[addr | 0x01] << 8; + base |= fregs[addr & 0xfe]; + for (i = 0; i < 4; i++) - ddma_update_io_mapping(dev->ddma, (addr & 4) + i, fregs[addr & 0xfe] + (i << 4), fregs[addr | 0x01], 1); + ddma_update_io_mapping(dev->ddma, (addr & 4) + i, fregs[addr & 0xfe] + (i << 4), fregs[addr | 0x01], (base != 0x0000)); } break; case 0xa0: diff --git a/src/config.c b/src/config.c index 8e23cb3a8..208673c0d 100644 --- a/src/config.c +++ b/src/config.c @@ -459,7 +459,8 @@ load_general(void) force_43 = !!config_get_int(cat, "force_43", 0); scale = config_get_int(cat, "scale", 1); if (scale > 3) - scale = 3; + scale = 3; + dpi_scale = config_get_int(cat, "dpi_scale", 1); enable_overscan = !!config_get_int(cat, "enable_overscan", 0); vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); @@ -1605,6 +1606,11 @@ save_general(void) else config_set_int(cat, "scale", scale); + if (dpi_scale == 1) + config_delete_var(cat, "dpi_scale"); + else + config_set_int(cat, "dpi_scale", dpi_scale); + if (enable_overscan == 0) config_delete_var(cat, "enable_overscan"); else diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 584d5a497..50283a713 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2069,7 +2069,8 @@ kbd_read(uint16_t port, void *priv) /* Only clear the transmit timeout flag on non-PS/2 controllers, as on PS/2 controller, it is the keyboard/mouse output source bit. */ dev->status &= ~STAT_RTIMEOUT; - if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) + if (((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) && + ((dev->flags & KBC_VEN_MASK) != KBC_VEN_IBM_MCA)) dev->status &= ~STAT_TTIMEOUT; break; diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index d4ca61b88..595bfa0e5 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -82,6 +82,7 @@ extern int window_w, window_h, /* (C) window size and */ invert_display, /* (C) invert the display */ suppress_overscan; /* (C) suppress overscans */ extern int scale; /* (C) screen scale factor */ +extern int dpi_scale; /* (C) DPI scaling of the emulated screen */ extern int vid_api; /* (C) video renderer */ extern int vid_cga_contrast, /* (C) video */ video_fullscreen, /* (C) video */ diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index c68108d42..4f4ca8e35 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -366,6 +366,7 @@ extern int machine_at_8500tuc_init(const machine_t *); extern int machine_at_m7shi_init(const machine_t *); extern int machine_at_tc430hx_init(const machine_t *); extern int machine_at_equium5200_init(const machine_t *); +extern int machine_at_pcv240_init(const machine_t *); extern int machine_at_p65up5_cp55t2d_init(const machine_t *); extern int machine_at_p55tvp4_init(const machine_t *); diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index b2c4810f6..b0422d18b 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -296,6 +296,7 @@ #define IDM_VID_SCALE_2X 40056 #define IDM_VID_SCALE_3X 40057 #define IDM_VID_SCALE_4X 40058 +#define IDM_VID_HIDPI 40059 #define IDM_VID_FULLSCREEN 40060 #define IDM_VID_FS_FULL 40061 #define IDM_VID_FS_43 40062 diff --git a/src/include/86box/scsi_pcscsi.h b/src/include/86box/scsi_pcscsi.h new file mode 100644 index 000000000..a6bfa6999 --- /dev/null +++ b/src/include/86box/scsi_pcscsi.h @@ -0,0 +1,32 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the AMD PCscsi and Tekram DC-390 SCSI + * controllers using the NCR 53c9x series of chips. + * + * + * + * + * Authors: Fabrice Bellard (QEMU) + * Herve Poussineau (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2005-2018 Fabrice Bellard. + * Copyright 2012-2018 Herve Poussineau. + * Copyright 2017,2018 Miran Grca. + */ + +#ifndef SCSI_PCSCSI_H +# define SCSI_PCSCSI_H + + +extern const device_t dc390_pci_device; + + +#endif /*SCSI_BUSLOGIC_H*/ diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index b66b600de..ee155f3fa 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -30,7 +30,9 @@ extern const device_t i82091aa_device; extern const device_t i82091aa_ide_device; extern const device_t pc87306_device; extern const device_t pc87307_device; +extern const device_t pc87307_15c_device; extern const device_t pc87309_device; +extern const device_t pc87309_15c_device; extern const device_t pc87332_device; extern const device_t pc87332_ps1_device; extern const device_t pc97307_device; diff --git a/src/include/86box/vid_ati_eeprom.h b/src/include/86box/vid_ati_eeprom.h index 786ae0c8b..dc370ee50 100644 --- a/src/include/86box/vid_ati_eeprom.h +++ b/src/include/86box/vid_ati_eeprom.h @@ -1,6 +1,35 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ + +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + + typedef struct ati_eeprom_t { uint16_t data[256]; @@ -10,6 +39,7 @@ typedef struct ati_eeprom_t int wp; uint32_t dat; int type; + int address; wchar_t fn[256]; } ati_eeprom_t; diff --git a/src/include/86box/win.h b/src/include/86box/win.h index 5537f4f30..9d3e8724b 100644 --- a/src/include/86box/win.h +++ b/src/include/86box/win.h @@ -33,6 +33,19 @@ # include "resource.h" # undef BITMAP +/* DPI Awareness Context, copied from MinGW-w64 windef.h */ +#ifndef _DPI_AWARENESS_CONTEXTS_ +DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); +#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1) +#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2) +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3) +#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) +#define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5) +#endif + +#ifndef WM_DPICHANGED_AFTERPARENT +#define WM_DPICHANGED_AFTERPARENT 0x02E3 +#endif /* Class names and such. */ #define CLASS_NAME L"86BoxMainWnd" @@ -119,6 +132,8 @@ extern void win_joystick_handle(PRAWINPUT raw); extern void win_notify_dlg_open(void); extern void win_notify_dlg_closed(void); +extern int win_get_dpi(HWND hwnd); +extern int win_get_system_metrics(int i, int dpi); extern LPARAM win_get_string(int id); diff --git a/src/machine/m_at_slot2.c b/src/machine/m_at_slot2.c index ab77c8006..525e26ea7 100644 --- a/src/machine/m_at_slot2.c +++ b/src/machine/m_at_slot2.c @@ -180,7 +180,7 @@ machine_at_fw6400gx_init(const machine_t *model) device_add(&i440gx_device); device_add(&piix4e_device); device_add(&keyboard_ps2_ami_pci_device); - device_add(&pc87309_device); + device_add(&pc87309_15c_device); device_add(&sst_flash_29ee020_device); spd_register(SPD_TYPE_SDRAM, 0xF, 512); diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7_s7.c index afbe1f701..029cca300 100644 --- a/src/machine/m_at_socket7_s7.c +++ b/src/machine/m_at_socket7_s7.c @@ -496,6 +496,40 @@ machine_at_equium5200_init(const machine_t *model) // Information about that mac return ret; } +int +machine_at_pcv240_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2(L"roms/machines/pcv240/1010DD04.BIO", + L"roms/machines/pcv240/1010DD04.BI1", + L"roms/machines/pcv240/1010DD04.BI2", + L"roms/machines/pcv240/1010DD04.BI3", + L"roms/machines/pcv240/1010DD04.RCV", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + int machine_at_p65up5_cp55t2d_init(const machine_t *model) { diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c index 41904d191..3d4b9c644 100644 --- a/src/machine/m_at_socket8.c +++ b/src/machine/m_at_socket8.c @@ -160,40 +160,6 @@ machine_at_vs440fx_init(const machine_t *model) return ret; } -int -machine_at_gw2kvs_init(const machine_t *model) -{ - int ret; - - ret = bios_load_linear_combined2(L"roms/machines/gw2kvs/1011CS1T.bio", - L"roms/machines/gw2kvs/1011CS1T.bi1", - L"roms/machines/gw2kvs/1011CS1T.bi2", - L"roms/machines/gw2kvs/1011CS1T.bi3", - L"roms/machines/gw2kvs/1011CS1T.rcv", - 0x3a000, 128); - - if (bios_only || !ret) - return ret; - - machine_at_common_init(model); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&i440fx_device); - device_add(&piix3_device); - device_add(&keyboard_ps2_intel_ami_pci_device); - device_add(&pc87307_device); - - device_add(&intel_flash_bxt_ami_device); - - return ret; -} - int machine_at_ap440fx_init(const machine_t *model) { diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 2543c5251..8ccc49014 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -59,6 +59,7 @@ #define MACHINE_CPUS_PENTIUM_S73V {{ "Intel", cpus_Pentium3V}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} #define MACHINE_CPUS_PENTIUM_S73VCH {{ "Intel", cpus_Pentium3V}, {"", NULL }, {"", NULL}, {"", NULL}, {"", NULL}} #define MACHINE_CPUS_PENTIUM_S7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"", NULL}, {"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7_INTEL {{"Intel", cpus_Pentium}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}} #define MACHINE_CPUS_PENTIUM_SS7 {{ "Intel", cpus_Pentium}, {"IDT", cpus_WinChip_SS7}, {"AMD", cpus_K56_SS7}, {"", NULL}, {"", NULL}} #endif #endif @@ -300,6 +301,7 @@ const machine_t machines[] = { { "[i430HX] Micronics M7S-Hi", "m7shi", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 511, machine_at_m7shi_init, NULL }, { "[i430HX] Intel TC430HX", "tc430hx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 255, machine_at_tc430hx_init, NULL }, { "[i430HX] Toshiba Equium 5200D", "equium5200", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_equium5200_init, NULL }, + { "[i430HX] Sony Vaio PCV-240", "pcv240", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_pcv240_init, NULL }, { "[i430HX] ASUS P/I-P65UP5 (C-P55T2D)", "p65up5_cp55t2d", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p65up5_cp55t2d_init, NULL }, /* 430VX */ @@ -307,8 +309,8 @@ const machine_t machines[] = { { "[i430VX] Shuttle HOT-557", "430vx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, { "[i430VX] Epox P55-VA", "p55va", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, { "[i430VX] HP Brio 80xx", "brio80xx", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_brio80xx_init, NULL }, - { "[i430VX] Biostar MB-8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, {{"Intel", cpus_Pentium}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_8500tvxa_init, NULL }, - { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, {{"Intel", cpus_Pentium}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_presario4500_init, NULL }, + { "[i430VX] Biostar MB-8500TVX-A", "8500tvxa", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_8500tvxa_init, NULL }, + { "[i430VX] Compaq Presario 4500", "presario4500", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_presario4500_init, NULL }, { "[i430VX] Packard Bell PB680", "pb680", MACHINE_TYPE_SOCKET7, MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_pb680_init, NULL }, /* 430TX */ diff --git a/src/pc.c b/src/pc.c index 488085301..db15ee617 100644 --- a/src/pc.c +++ b/src/pc.c @@ -116,6 +116,7 @@ int window_w, window_h, /* (C) window size and */ invert_display = 0, /* (C) invert the display */ suppress_overscan = 0; /* (C) suppress overscans */ int scale = 0; /* (C) screen scale factor */ +int dpi_scale = 0; /* (C) DPI scaling of the emulated screen */ int vid_api = 0; /* (C) video renderer */ int vid_cga_contrast = 0, /* (C) video */ video_fullscreen = 0, /* (C) video */ diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index 829e273c1..9a3fabcfd 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -38,6 +38,7 @@ #include <86box/scsi_buslogic.h> #include <86box/scsi_ncr5380.h> #include <86box/scsi_ncr53c8xx.h> +#include <86box/scsi_pcscsi.h> #include <86box/scsi_spock.h> #ifdef WALTJE # include "scsi_wd33c93.h" @@ -79,6 +80,7 @@ static SCSI_CARD scsi_cards[] = { { "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, { "[PCI] NCR 53C860", "ncr53c860", &ncr53c860_pci_device, }, { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, + { "[PCI] Tekram DC-390", "dc390", &dc390_pci_device, }, { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, { "", "", NULL, }, }; diff --git a/src/scsi/scsi_pcscsi.c b/src/scsi/scsi_pcscsi.c new file mode 100644 index 000000000..112cd3397 --- /dev/null +++ b/src/scsi/scsi_pcscsi.c @@ -0,0 +1,1484 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the AMD PCscsi and Tekram DC-390 SCSI + * controllers using the NCR 53c9x series of chips. + * + * + * + * + * Authors: Fabrice Bellard (QEMU) + * Herve Poussineau (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2005-2018 Fabrice Bellard. + * Copyright 2012-2018 Herve Poussineau. + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/dma.h> +#include <86box/pic.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/pci.h> +#include <86box/device.h> +#include <86box/nvr.h> +#include <86box/plat.h> +#include <86box/scsi.h> +#include <86box/scsi_device.h> +#include <86box/scsi_pcscsi.h> +#include <86box/vid_ati_eeprom.h> + +#define DC390_ROM L"roms/scsi/esp_pci/INT13.BIN" + +#define ESP_REGS 16 +#define TI_BUFSZ 32 +#define ESP_CMDBUF_SZ 32 + +#define ESP_TCLO 0x0 +#define ESP_TCMID 0x1 +#define ESP_FIFO 0x2 +#define ESP_CMD 0x3 +#define ESP_RSTAT 0x4 +#define ESP_WBUSID 0x4 +#define ESP_RINTR 0x5 +#define ESP_WSEL 0x5 +#define ESP_RSEQ 0x6 +#define ESP_WSYNTP 0x6 +#define ESP_RFLAGS 0x7 +#define ESP_WSYNO 0x7 +#define ESP_CFG1 0x8 +#define ESP_RRES1 0x9 +#define ESP_WCCF 0x9 +#define ESP_RRES2 0xa +#define ESP_WTEST 0xa +#define ESP_CFG2 0xb +#define ESP_CFG3 0xc +#define ESP_RES3 0xd +#define ESP_TCHI 0xe +#define ESP_RES4 0xf + +#define CMD_DMA 0x80 +#define CMD_CMD 0x7f + +#define CMD_NOP 0x00 +#define CMD_FLUSH 0x01 +#define CMD_RESET 0x02 +#define CMD_BUSRESET 0x03 +#define CMD_TI 0x10 +#define CMD_ICCS 0x11 +#define CMD_MSGACC 0x12 +#define CMD_PAD 0x18 +#define CMD_SATN 0x1a +#define CMD_RSTATN 0x1b +#define CMD_SEL 0x41 +#define CMD_SELATN 0x42 +#define CMD_SELATNS 0x43 +#define CMD_ENSEL 0x44 +#define CMD_DISSEL 0x45 + +#define STAT_DO 0x00 +#define STAT_DI 0x01 +#define STAT_CD 0x02 +#define STAT_ST 0x03 +#define STAT_MO 0x06 +#define STAT_MI 0x07 +#define STAT_PIO_MASK 0x06 + +#define STAT_TC 0x10 +#define STAT_PE 0x20 +#define STAT_GE 0x40 +#define STAT_INT 0x80 + +#define BUSID_DID 0x07 + +#define INTR_FC 0x08 +#define INTR_BS 0x10 +#define INTR_DC 0x20 +#define INTR_RST 0x80 + +#define SEQ_0 0x0 +#define SEQ_CD 0x4 + +#define CFG1_RESREPT 0x40 + +#define TCHI_AM53C974 0x12 + +#define DMA_CMD 0x0 +#define DMA_STC 0x1 +#define DMA_SPA 0x2 +#define DMA_WBC 0x3 +#define DMA_WAC 0x4 +#define DMA_STAT 0x5 +#define DMA_SMDLA 0x6 +#define DMA_WMAC 0x7 + +#define DMA_CMD_MASK 0x03 +#define DMA_CMD_DIAG 0x04 +#define DMA_CMD_MDL 0x10 +#define DMA_CMD_INTE_P 0x20 +#define DMA_CMD_INTE_D 0x40 +#define DMA_CMD_DIR 0x80 + +#define DMA_STAT_PWDN 0x01 +#define DMA_STAT_ERROR 0x02 +#define DMA_STAT_ABORT 0x04 +#define DMA_STAT_DONE 0x08 +#define DMA_STAT_SCSIINT 0x10 +#define DMA_STAT_BCMBLT 0x20 + +#define SBAC_STATUS (1 << 24) +#define SBAC_PABTEN (1 << 25) + +typedef struct { + mem_mapping_t mmio_mapping; + wchar_t *nvr_path; + uint8_t pci_slot; + int has_bios; + int BIOSBase; + int MMIOBase; + rom_t bios; + ati_eeprom_t eeprom; + int PCIBase; + + uint8_t rregs[ESP_REGS]; + uint8_t wregs[ESP_REGS]; + int irq; + int tchi_written; + uint32_t ti_size; + uint32_t ti_rptr, ti_wptr; + uint32_t status; + uint32_t deferred_status; + int deferred_complete; + uint32_t dma; + uint8_t ti_buf[TI_BUFSZ]; + uint8_t id, lun; + uint8_t cmdbuf[ESP_CMDBUF_SZ]; + uint32_t cmdlen; + uint32_t do_cmd; + + uint32_t dma_counter; + uint32_t dma_left; + int32_t xfer_counter; + int dma_enabled; + + uint32_t buffer_pos; + uint32_t async_len; + uint32_t dma_regs[8]; + uint32_t sbac; + + double period; + + pc_timer_t timer; +} esp_t; + + +#ifdef ENABLE_ESP_LOG +int esp_do_log = ENABLE_ESP_LOG; + + +static void +esp_log(const char *fmt, ...) +{ + va_list ap; + + if (esp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define esp_log(fmt, ...) +#endif + +static void esp_do_dma(esp_t *dev, scsi_device_t *sd); +static void esp_pci_dma_memory_rw(esp_t *dev, uint8_t *buf, uint32_t len, int dir); +static void esp_timer_on(esp_t *dev, scsi_device_t *sd, double p); +static void esp_command_complete(void *priv, uint32_t status); +static void esp_pci_command_complete(void *priv, uint32_t status); +static void esp_pci_soft_reset(esp_t *dev); +static void esp_pci_hard_reset(esp_t *dev); +static void handle_ti(void *priv); + +static void +esp_irq(esp_t *dev, int level) +{ + if (level) { + pci_set_irq(dev->pci_slot, PCI_INTA); + esp_log("Raising IRQ...\n"); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + esp_log("Lowering IRQ...\n"); + } +} + + +static void +esp_raise_irq(esp_t *dev) +{ + if (!(dev->rregs[ESP_RSTAT] & STAT_INT)) { + dev->rregs[ESP_RSTAT] |= STAT_INT; + esp_irq(dev, 1); + } +} + +static void +esp_lower_irq(esp_t *dev) +{ + if (dev->rregs[ESP_RSTAT] & STAT_INT) { + dev->rregs[ESP_RSTAT] &= ~STAT_INT; + esp_irq(dev, 0); + } +} + +static void +esp_dma_done(esp_t *dev) +{ + dev->rregs[ESP_RSTAT] |= STAT_TC; + dev->rregs[ESP_RINTR] = INTR_BS; + dev->rregs[ESP_RSEQ] = 0; + dev->rregs[ESP_RFLAGS] = 0; + dev->rregs[ESP_TCLO] = 0; + dev->rregs[ESP_TCMID] = 0; + dev->rregs[ESP_TCHI] = 0; + esp_log("ESP DMA Finished\n"); + esp_raise_irq(dev); +} + +static uint32_t +esp_get_cmd(esp_t *dev, uint8_t *buf, uint8_t buflen) +{ + uint32_t dmalen; + + dev->id = dev->wregs[ESP_WBUSID] & BUSID_DID; + if (dev->dma) { + dmalen = dev->rregs[ESP_TCLO]; + dmalen |= dev->rregs[ESP_TCMID] << 8; + dmalen |= dev->rregs[ESP_TCHI] << 16; + esp_log("ESP Get data, dmalen = %d\n", dmalen); + if (dmalen > buflen) + return 0; + esp_pci_dma_memory_rw(dev, buf, dmalen, 0); + } else { + dmalen = dev->ti_size; + esp_log("ESP Get command, dmalen = %d\n", dmalen); + if (dmalen > TI_BUFSZ) + return 0; + memcpy(buf, dev->ti_buf, dmalen); + } + + dev->ti_size = 0; + dev->ti_rptr = 0; + dev->ti_wptr = 0; + + return dmalen; +} + +static void +esp_do_busid_cmd(esp_t *dev, uint8_t *buf, uint8_t busid) +{ + scsi_device_t *sd; + + sd = &scsi_devices[busid]; + + sd->buffer_length = -1; + + scsi_device_command_phase0(sd, buf); + + dev->buffer_pos = 0; + dev->ti_size = sd->buffer_length; + dev->xfer_counter = sd->buffer_length; + + esp_log("ESP SCSI Command = %02x, ID = %d, len = %d\n", buf[0], busid, sd->buffer_length); + + if (sd->buffer_length > 0) { + /* This should be set to the underlying device's buffer by command phase 0. */ + dev->rregs[ESP_RSTAT] = STAT_TC; + dev->dma_left = 0; + dev->dma_counter = 0; + + if (sd->phase == SCSI_PHASE_DATA_IN) { + dev->rregs[ESP_RSTAT] |= STAT_DI; + esp_log("ESP Data In\n"); + esp_timer_on(dev, sd, scsi_device_get_callback(sd)); + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + dev->rregs[ESP_RSTAT] |= STAT_DO; + esp_log("ESP Data Out\n"); + dev->ti_size = -sd->buffer_length; + esp_timer_on(dev, sd, scsi_device_get_callback(sd)); + } + esp_log("ESP SCSI Start reading/writing\n"); + esp_do_dma(dev, sd); + } else { + esp_log("ESP SCSI Command with no length\n"); + esp_pci_command_complete(dev, sd->status); + } + + dev->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + esp_raise_irq(dev); +} + +static void +esp_do_cmd(esp_t *dev, uint8_t *buf) +{ + esp_do_busid_cmd(dev, &buf[1], dev->id); +} + +static void +esp_dma_enable(esp_t *dev, int level) +{ + if (level) { + esp_log("ESP DMA Enabled\n"); + dev->dma_enabled = 1; + if ((dev->rregs[ESP_CMD] & CMD_CMD) != CMD_TI) + timer_on_auto(&dev->timer, 40.0); + else + timer_on_auto(&dev->timer, dev->period); + } else { + esp_log("ESP DMA Disabled\n"); + dev->dma_enabled = 0; + } +} + +static void +esp_hard_reset(esp_t *dev) +{ + memset(dev->rregs, 0, ESP_REGS); + memset(dev->wregs, 0, ESP_REGS); + dev->tchi_written = 0; + dev->ti_size = 0; + dev->ti_rptr = 0; + dev->ti_wptr = 0; + dev->dma = 0; + dev->do_cmd = 0; + dev->rregs[ESP_CFG1] = 7; + esp_log("ESP Reset\n"); + timer_stop(&dev->timer); + + for (int i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[i]); +} + +static void +esp_do_dma(esp_t *dev, scsi_device_t *sd) +{ + uint32_t tdbc; + int count; + + esp_log("ESP SCSI Actual DMA len = %d\n", dev->dma_left); + + if (!scsi_device_present(sd)) { + esp_log("ESP SCSI no devices on ID %d, LUN %d\n", dev->id, dev->cmdbuf[8] >> 5); + /* No such drive */ + dev->rregs[ESP_RSTAT] = 0; + dev->rregs[ESP_RINTR] = INTR_DC; + dev->rregs[ESP_RSEQ] = SEQ_0; + esp_raise_irq(dev); + return; + } else { + esp_log("ESP SCSI device found on ID %d, LUN %d\n", dev->id, dev->cmdbuf[8] >> 5); + } + + count = tdbc = dev->dma_left; + + if (dev->xfer_counter == 0) { + /* Wait until data is available. */ + esp_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", dev->id, dev->cmdbuf[8] >> 5, dev->cmdbuf[7]); + return; + } + + esp_log("ESP SCSI dmaleft = %d, async_len = %i, buffer length = %d\n", dev->dma_counter, dev->async_len, sd->buffer_length); + + /* Make sure count is never bigger than buffer_length. */ + if (count > dev->xfer_counter) + count = dev->xfer_counter; + + if (dev->do_cmd) { + esp_log("ESP Command on DMA\n"); + esp_pci_dma_memory_rw(dev, &dev->cmdbuf[dev->cmdlen], count, 1); + dev->ti_size = 0; + dev->cmdlen = 0; + dev->do_cmd = 0; + esp_do_cmd(dev, dev->cmdbuf); + return; + } + + if (sd->phase == SCSI_PHASE_DATA_IN) { + esp_log("ESP SCSI Read, dma cnt = %i, ti size = %i, positive len = %i\n", dev->dma_counter, dev->ti_size, count); + esp_pci_dma_memory_rw(dev, sd->sc->temp_buffer + dev->buffer_pos, count, 1); + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + esp_log("ESP SCSI Write, negative len = %i, ti size = %i, dma cnt = %i\n", count, -dev->ti_size, dev->dma_counter); + esp_pci_dma_memory_rw(dev, sd->sc->temp_buffer + dev->buffer_pos, count, 0); + } + + dev->dma_left -= count; + dev->buffer_pos += count; + dev->xfer_counter -= count; + if (sd->phase == SCSI_PHASE_DATA_IN) { + dev->ti_size -= count; + } else if (sd->phase == SCSI_PHASE_DATA_OUT) { + dev->ti_size += count; + } + + esp_log("ESP SCSI Transfer bytes = %d\n", dev->xfer_counter); + if (dev->xfer_counter <= 0) { + if (sd->phase == SCSI_PHASE_DATA_OUT) { + if (dev->ti_size < 0) { + esp_log("ESP SCSI Keep writing\n"); + esp_do_dma(dev, sd); + } else { + esp_log("ESP SCSI Write finished\n"); + scsi_device_command_phase1(sd); + esp_pci_command_complete(dev, sd->status); + } + } else if (sd->phase == SCSI_PHASE_DATA_IN) { + /* If there is still data to be read from the device then + complete the DMA operation immediately. Otherwise defer + until the scsi layer has completed. */ + if (dev->ti_size <= 0) { + esp_log("ESP SCSI Read finished\n"); + scsi_device_command_phase1(sd); + esp_pci_command_complete(dev, sd->status); + } else { + esp_log("ESP SCSI Keep reading\n"); + esp_do_dma(dev, sd); + } + } + } else { + /* Partially filled a scsi buffer. Complete immediately. */ + esp_log("ESP SCSI Partially filled the SCSI buffer\n"); + esp_dma_done(dev); + } +} + + +static void +esp_report_command_complete(esp_t *dev, uint32_t status) +{ + esp_log("ESP Command complete\n"); + dev->ti_size = 0; + dev->dma_counter = 0; + dev->status = status; + dev->rregs[ESP_RSTAT] = STAT_ST; + esp_dma_done(dev); +} + +/* Callback to indicate that the SCSI layer has completed a command. */ +static void +esp_command_complete(void *priv, uint32_t status) +{ + esp_t *dev = (esp_t *)priv; + + if (dev->rregs[ESP_RSTAT] & STAT_INT) { + /* Defer handling command complete until the previous + * interrupt has been handled. + */ + esp_log("ESP Deferred status\n"); + dev->deferred_status = status; + dev->deferred_complete = 1; + return; + } + esp_report_command_complete(dev, status); +} + +static void +esp_pci_command_complete(void *priv, uint32_t status) +{ + esp_t *dev = (esp_t *)priv; + + esp_command_complete(dev, status); + dev->dma_regs[DMA_WBC] = 0; + dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE; +} + +static void +esp_timer_on(esp_t *dev, scsi_device_t *sd, double p) +{ + /* Fast SCSI: 10000000 bytes per second */ + dev->period = (p > 0.0) ? p : (((double) sd->buffer_length) * 0.1); + + timer_on_auto(&dev->timer, dev->period + 40.0); +} + +static void +handle_ti(void *priv) +{ + esp_t *dev = (esp_t *)priv; + scsi_device_t *sd = &scsi_devices[dev->id]; + uint32_t dmalen; + + if (dev->dma) { + dmalen = dev->rregs[ESP_TCLO]; + dmalen |= dev->rregs[ESP_TCMID] << 8; + dmalen |= dev->rregs[ESP_TCHI] << 16; + + dev->dma_counter = dmalen; + dev->dma_left = dmalen; + + esp_log("ESP Handle TI, do data, minlen = %i, tclo = %02x, tcmid = %02x, tchi = %02x\n", dev->dma_counter, dev->rregs[ESP_TCLO], dev->rregs[ESP_TCMID], dev->rregs[ESP_TCHI]); + esp_do_dma(dev, sd); + } else if (dev->do_cmd) { + dev->ti_size = 0; + dev->cmdlen = 0; + dev->do_cmd = 0; + esp_log("ESP Handle TI, do cmd, CDB[0] = 0x%02x\n", dev->cmdbuf[7]); + esp_do_cmd(dev, dev->cmdbuf); + } +} + +static void +handle_s_without_atn(void *priv) +{ + esp_t *dev = (esp_t *)priv; + uint8_t buf[32]; + int len; + + len = esp_get_cmd(dev, buf, sizeof(buf)); + if (len) { + esp_log("ESP SEL without ATN\n"); + esp_do_busid_cmd(dev, buf, 0); + } +} + +static void +handle_satn(void *priv) +{ + esp_t *dev = (esp_t *)priv; + uint8_t buf[32]; + int len; + + len = esp_get_cmd(dev, buf, sizeof(buf)); + esp_log("ESP SEL with ATN len = %d, id = %d\n", len, dev->id); + if (len) { + esp_do_cmd(dev, buf); + } +} + +static void +handle_satn_stop(void *priv) +{ + esp_t *dev = (esp_t *)priv; + + dev->cmdlen = esp_get_cmd(dev, dev->cmdbuf, sizeof(dev->cmdbuf)); + if (dev->cmdlen) { + dev->do_cmd = 1; + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; + dev->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + esp_log("ESP SCSI Command len = %d, raising IRQ\n", dev->cmdlen); + esp_raise_irq(dev); + timer_on_auto(&dev->timer, 10.0); + } +} + +static void +esp_write_response(esp_t *dev) +{ + dev->ti_buf[0] = dev->status; + dev->ti_buf[1] = 0; + if (dev->dma) { + esp_pci_dma_memory_rw(dev, dev->ti_buf, 2, 0); + dev->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; + dev->rregs[ESP_RINTR] = INTR_BS | INTR_FC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + } else { + dev->ti_size = 2; + dev->ti_rptr = 0; + dev->ti_wptr = 2; + dev->rregs[ESP_RFLAGS] = 2; + } + esp_log("ESP SCSI ICCS IRQ\n"); + esp_raise_irq(dev); +} + +static void +esp_callback(void *p) +{ + esp_t *dev = (esp_t *) p; + + if (dev->dma_enabled || dev->do_cmd) { + if ((dev->rregs[ESP_CMD] & CMD_CMD) == CMD_TI) { + esp_log("ESP SCSI Handle TI Callback\n"); + handle_ti(dev); + } + } + esp_log("ESP DMA activated = %d, CMD activated = %d\n", dev->dma_enabled, dev->do_cmd); +} + +static uint32_t +esp_reg_read(esp_t *dev, uint32_t saddr) +{ + uint32_t old_val; + + switch (saddr) { + case ESP_FIFO: + esp_log("ESP FIFO decrease = %d, readsize = %d, writesize = %d\n", dev->ti_size, dev->ti_rptr, dev->ti_wptr); + if (dev->ti_rptr < dev->ti_wptr) { + dev->ti_size--; + dev->rregs[ESP_FIFO] = dev->ti_buf[dev->ti_rptr++]; + } + if (dev->ti_rptr == dev->ti_wptr) { + dev->ti_rptr = 0; + dev->ti_wptr = 0; + } + break; + case ESP_RINTR: + /* Clear sequence step, interrupt register and all status bits + except TC */ + old_val = dev->rregs[ESP_RINTR]; + dev->rregs[ESP_RINTR] = 0; + dev->rregs[ESP_RSTAT] &= ~STAT_TC; + dev->rregs[ESP_RSEQ] = SEQ_CD; + esp_log("ESP SCSI Clear sequence step\n"); + esp_lower_irq(dev); + if (dev->deferred_complete) { + esp_report_command_complete(dev, dev->deferred_status); + dev->deferred_complete = 0; + } + esp_log("ESP RINTR read old val = %02x\n", old_val); + return old_val; + case ESP_TCHI: + /* Return the unique id if the value has never been written */ + if (!dev->tchi_written) { + esp_log("ESP TCHI read id 0x12\n"); + return TCHI_AM53C974; + } + default: + break; + + } + esp_log("Read reg %02x = %02x\n", saddr, dev->rregs[saddr]); + return dev->rregs[saddr]; +} + + +static void +esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val) +{ + esp_log("Write reg %02x = %02x\n", saddr, val); + + switch (saddr) { + case ESP_TCHI: + dev->tchi_written = 1; + /* fall through */ + case ESP_TCLO: + case ESP_TCMID: + esp_log("Transfer count regs %02x = %02x\n", saddr, val); + dev->rregs[ESP_RSTAT] &= ~STAT_TC; + break; + case ESP_FIFO: + if (dev->do_cmd) { + if (dev->cmdlen < ESP_CMDBUF_SZ) { + dev->cmdbuf[dev->cmdlen++] = val & 0xff; + esp_log("ESP CmdBuf Write len = %d, = %02x\n", dev->cmdlen, val & 0xff); + } + } else { + esp_log("ESP FIFO increase = %d\n", dev->ti_size); + dev->ti_size++; + dev->ti_buf[dev->ti_wptr++] = val & 0xff; + } + break; + case ESP_CMD: + dev->rregs[saddr] = val; + + if (val & CMD_DMA) { + dev->dma = 1; + /* Reload DMA counter.*/ + dev->rregs[ESP_TCLO] = dev->wregs[ESP_TCLO]; + dev->rregs[ESP_TCMID] = dev->wregs[ESP_TCMID]; + dev->rregs[ESP_TCHI] = dev->wregs[ESP_TCHI]; + esp_log("ESP Command for DMA, wregs: TCLO = %02x, TCMID = %02x, TCHI = %02x\n", dev->wregs[ESP_TCLO], + dev->wregs[ESP_TCMID], dev->wregs[ESP_TCHI]); + } else { + dev->dma = 0; + esp_log("ESP Command not for DMA\n"); + } + esp_log("ESP Command = %02x, DMA ena1 = %d, DMA ena2 = %d\n", val & CMD_CMD, dev->dma, dev->dma_enabled); + switch (val & CMD_CMD) { + case CMD_NOP: + break; + case CMD_FLUSH: + dev->rregs[ESP_RINTR] = INTR_FC; + dev->rregs[ESP_RSEQ] = 0; + dev->rregs[ESP_RFLAGS] = 0; + break; + case CMD_RESET: + esp_pci_soft_reset(dev); + break; + case CMD_BUSRESET: + dev->rregs[ESP_RINTR] = INTR_RST; + if (!(dev->wregs[ESP_CFG1] & CFG1_RESREPT)) { + esp_log("ESP Bus Reset with IRQ\n"); + esp_raise_irq(dev); + } + break; + case CMD_SEL: + handle_s_without_atn(dev); + break; + case CMD_SELATN: + handle_satn(dev); + break; + case CMD_SELATNS: + handle_satn_stop(dev); + break; + case CMD_ICCS: + esp_write_response(dev); + dev->rregs[ESP_RINTR] = INTR_FC; + dev->rregs[ESP_RSTAT] |= STAT_MI; + break; + case CMD_MSGACC: + dev->rregs[ESP_RINTR] = INTR_DC; + dev->rregs[ESP_RSEQ] = 0; + dev->rregs[ESP_RFLAGS] = 0; + esp_log("ESP SCSI MSGACC IRQ\n"); + esp_raise_irq(dev); + break; + case CMD_PAD: + dev->rregs[ESP_RSTAT] = STAT_TC; + dev->rregs[ESP_RINTR] = INTR_FC; + dev->rregs[ESP_RSEQ] = 0; + esp_log("ESP Transfer Pad\n"); + break; + case CMD_SATN: + case CMD_RSTATN: + break; + case CMD_ENSEL: + dev->rregs[ESP_RINTR] = 0; + esp_log("ESP Enable Selection, do cmd = %d\n", dev->do_cmd); + break; + case CMD_DISSEL: + dev->rregs[ESP_RINTR] = 0; + esp_log("ESP Disable Selection\n"); + esp_raise_irq(dev); + break; + } + break; + case ESP_WBUSID: + case ESP_WSEL: + case ESP_WSYNTP: + case ESP_WSYNO: + break; + case ESP_CFG1: + case ESP_CFG2: + case ESP_CFG3: + case ESP_RES3: + case ESP_RES4: + dev->rregs[saddr] = val; + break; + case ESP_WCCF: + case ESP_WTEST: + break; + default: + esp_log("Unhandled writeb 0x%x = 0x%x\n", saddr, val); + break; + } + dev->wregs[saddr] = val; +} + + +static void +esp_pci_dma_memory_rw(esp_t *dev, uint8_t *buf, uint32_t len, int dir) +{ + int expected_dir; + + if (dev->dma_regs[DMA_CMD] & DMA_CMD_DIR) + expected_dir = 1; + else + expected_dir = 0; + + if (dir != expected_dir) { + esp_log("ESP unexpected direction\n"); + return; + } + + esp_log("ESP DMA WBC = %d, addr = %06x, dir = %d\n", dev->dma_regs[DMA_WBC], dev->dma_regs[DMA_SPA], expected_dir); + + if (dev->dma_regs[DMA_WBC] < len) + len = dev->dma_regs[DMA_WBC]; + + if (expected_dir) { + dma_bm_write(dev->dma_regs[DMA_SPA], buf, len, 4); + } else { + dma_bm_read(dev->dma_regs[DMA_SPA], buf, len, 4); + } + + /* update status registers */ + dev->dma_regs[DMA_WBC] -= len; + dev->dma_regs[DMA_WAC] += len; + if (dev->dma_regs[DMA_WBC] == 0) + dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE; +} + +static uint32_t +esp_pci_dma_read(esp_t *dev, uint16_t saddr) +{ + uint32_t ret; + + ret = dev->dma_regs[saddr]; + + if (saddr == DMA_STAT) { + if (dev->rregs[ESP_RSTAT] & STAT_INT) { + ret |= DMA_STAT_SCSIINT; + esp_log("ESP PCI DMA Read SCSI interrupt issued\n"); + } + if (!(dev->sbac & SBAC_STATUS)) { + dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT | + DMA_STAT_DONE); + esp_log("ESP PCI DMA Read done cleared\n"); + } + } + + esp_log("ESP PCI DMA Read regs addr = %04x, temp = %06x\n", saddr, ret); + return ret; +} + +static void +esp_pci_dma_write(esp_t *dev, uint16_t saddr, uint32_t val) +{ + uint32_t mask; + + switch (saddr) { + case DMA_CMD: + dev->dma_regs[saddr] = val; + esp_log("ESP PCI DMA Write CMD = %02x\n", val & DMA_CMD_MASK); + switch (val & DMA_CMD_MASK) { + case 0: /*IDLE*/ + esp_dma_enable(dev, 0); + break; + case 1: /*BLAST*/ + break; + case 2: /*ABORT*/ + break; + case 3: /*START*/ + dev->dma_regs[DMA_WBC] = dev->dma_regs[DMA_STC]; + dev->dma_regs[DMA_WAC] = dev->dma_regs[DMA_SPA]; + dev->dma_regs[DMA_WMAC] = dev->dma_regs[DMA_SMDLA]; + dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT | + DMA_STAT_DONE | DMA_STAT_ABORT | + DMA_STAT_ERROR | DMA_STAT_PWDN); + esp_dma_enable(dev, 1); + break; + default: /* can't happen */ + abort(); + } + break; + case DMA_STC: + case DMA_SPA: + case DMA_SMDLA: + dev->dma_regs[saddr] = val; + break; + case DMA_STAT: + if (dev->sbac & SBAC_STATUS) { + /* clear some bits on write */ + mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE; + dev->dma_regs[DMA_STAT] &= ~(val & mask); + } + break; + } +} + +static void +esp_pci_soft_reset(esp_t *dev) +{ + esp_irq(dev, 0); + esp_pci_hard_reset(dev); +} + +static void +esp_pci_hard_reset(esp_t *dev) +{ + esp_hard_reset(dev); + dev->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P + | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK); + dev->dma_regs[DMA_WBC] &= ~0xffff; + dev->dma_regs[DMA_WAC] = 0xffffffff; + dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT + | DMA_STAT_DONE | DMA_STAT_ABORT + | DMA_STAT_ERROR); + dev->dma_regs[DMA_WMAC] = 0xfffffffd; +} + +static uint32_t +esp_io_pci_read(esp_t *dev, uint32_t addr, unsigned int size) +{ + uint32_t ret; + + addr &= 0x7f; + + if (addr < 0x40) { + /* SCSI core reg */ + ret = esp_reg_read(dev, addr >> 2); + } else if (addr < 0x60) { + /* PCI DMA CCB */ + ret = esp_pci_dma_read(dev, (addr - 0x40) >> 2); + esp_log("ESP PCI DMA CCB read addr = %02x, ret = %02x\n", (addr - 0x40) >> 2, ret); + } else if (addr == 0x70) { + /* DMA SCSI Bus and control */ + ret = dev->sbac; + esp_log("ESP PCI SBAC read = %02x\n", ret); + } else { + /* Invalid region */ + ret = 0; + } + + /* give only requested data */ + ret >>= (addr & 3) * 8; + ret &= ~(~(uint64_t)0 << (8 * size)); + + esp_log("ESP PCI I/O read: addr = %02x, val = %02x\n", addr, ret); + return ret; +} + +static void +esp_io_pci_write(esp_t *dev, uint32_t addr, uint32_t val, unsigned int size) +{ + uint32_t current, mask; + int shift; + + addr &= 0x7f; + + if (size < 4 || addr & 3) { + /* need to upgrade request: we only support 4-bytes accesses */ + current = 0; + + if (addr < 0x40) { + current = dev->wregs[addr >> 2]; + } else if (addr < 0x60) { + current = dev->dma_regs[(addr - 0x40) >> 2]; + } else if (addr < 0x74) { + current = dev->sbac; + } + + shift = (4 - size) * 8; + mask = (~(uint32_t)0 << shift) >> shift; + + shift = ((4 - (addr & 3)) & 3) * 8; + val <<= shift; + val |= current & ~(mask << shift); + addr &= ~3; + size = 4; + } + + esp_log("ESP PCI I/O write: addr = %02x, val = %02x\n", addr, val); + + if (addr < 0x40) { + /* SCSI core reg */ + esp_reg_write(dev, addr >> 2, val); + } else if (addr < 0x60) { + /* PCI DMA CCB */ + esp_pci_dma_write(dev, (addr - 0x40) >> 2, val); + } else if (addr == 0x70) { + /* DMA SCSI Bus and control */ + dev->sbac = val; + } +} + + +static void +esp_pci_io_writeb(uint16_t addr, uint8_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + esp_io_pci_write(dev, addr, val, 1); +} + +static void +esp_pci_io_writew(uint16_t addr, uint16_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + esp_io_pci_write(dev, addr, val, 2); +} + +static void +esp_pci_io_writel(uint16_t addr, uint32_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + esp_io_pci_write(dev, addr, val, 4); +} + +static uint8_t +esp_pci_io_readb(uint16_t addr, void *p) +{ + esp_t *dev = (esp_t *)p; + return esp_io_pci_read(dev, addr, 1); +} + +static uint16_t +esp_pci_io_readw(uint16_t addr, void *p) +{ + esp_t *dev = (esp_t *)p; + return esp_io_pci_read(dev, addr, 2); +} + +static uint32_t +esp_pci_io_readl(uint16_t addr, void *p) +{ + esp_t *dev = (esp_t *)p; + return esp_io_pci_read(dev, addr, 4); +} + +static void +esp_io_set(esp_t *dev, uint32_t base, uint16_t len) +{ + esp_log("ESP: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + esp_pci_io_readb, esp_pci_io_readw, esp_pci_io_readl, + esp_pci_io_writeb, esp_pci_io_writew, esp_pci_io_writel, dev); +} + + +static void +esp_io_remove(esp_t *dev, uint32_t base, uint16_t len) +{ + esp_log("ESP: [PCI] Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + esp_pci_io_readb, esp_pci_io_readw, esp_pci_io_readl, + esp_pci_io_writeb, esp_pci_io_writew, esp_pci_io_writel, dev); +} + +static void +esp_bios_set_addr(esp_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->bios.mapping, base, 0x8000); +} + +static void +esp_bios_disable(esp_t *dev) +{ + mem_mapping_disable(&dev->bios.mapping); +} + +#define EE_ADAPT_SCSI_ID 64 +#define EE_MODE2 65 +#define EE_DELAY 66 +#define EE_TAG_CMD_NUM 67 +#define EE_ADAPT_OPTIONS 68 +#define EE_BOOT_SCSI_ID 69 +#define EE_BOOT_SCSI_LUN 70 +#define EE_CHKSUM1 126 +#define EE_CHKSUM2 127 + +#define EE_ADAPT_OPTION_F6_F8_AT_BOOT 0x01 +#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02 +#define EE_ADAPT_OPTION_INT13 0x04 +#define EE_ADAPT_OPTION_SCAM_SUPPORT 0x08 + +/*To do: make this separate from the SCSI card*/ +static void +dc390_save_eeprom(esp_t *dev) +{ + FILE *f = nvr_fopen(dev->nvr_path, L"wb"); + if (!f) return; + fwrite(dev->eeprom.data, 1, 128, f); + fclose(f); +} + +static void +dc390_write_eeprom(esp_t *dev, int ena, int clk, int dat) +{ + /*Actual EEPROM is the same as the one used by the ATI cards, the 93cxx series.*/ + ati_eeprom_t *eeprom = &dev->eeprom; + uint8_t tick = eeprom->count; + uint8_t eedo = eeprom->out; + uint16_t address = eeprom->address; + uint8_t command = eeprom->opcode; + + esp_log("EEPROM CS=%02x,SK=%02x,DI=%02x,DO=%02x,tick=%d\n", + ena, clk, dat, eedo, tick); + + if (!eeprom->oldena && ena) { + esp_log("EEPROM Start chip select cycle\n"); + tick = 0; + command = 0; + address = 0; + } else if (eeprom->oldena && !ena) { + if (!eeprom->wp) { + uint8_t subcommand = address >> 4; + if (command == 0 && subcommand == 2) { + esp_log("EEPROM Erase All\n"); + for (address = 0; address < 64; address++) + eeprom->data[address] = 0xffff; + dc390_save_eeprom(dev); + } else if (command == 3) { + esp_log("EEPROM Erase Word\n"); + eeprom->data[address] = 0xffff; + dc390_save_eeprom(dev); + } else if (tick >= 26) { + if (command == 1) { + esp_log("EEPROM Write Word\n"); + eeprom->data[address] &= eeprom->dat; + dc390_save_eeprom(dev); + } else if (command == 0 && subcommand == 1) { + esp_log("EEPROM Write All\n"); + for (address = 0; address < 64; address++) + eeprom->data[address] &= eeprom->dat; + dc390_save_eeprom(dev); + } + } + } + eedo = 1; + esp_log("EEPROM DO read\n"); + } else if (ena && !eeprom->oldclk && clk) { + if (tick == 0) { + if (dat == 0) { + esp_log("EEPROM Got correct 1st start bit, waiting for 2nd start bit (1)\n"); + tick++; + } else { + esp_log("EEPROM Wrong 1st start bit (is 1, should be 0)\n"); + tick = 2; + } + } else if (tick == 1) { + if (dat != 0) { + esp_log("EEPROM Got correct 2nd start bit, getting command + address\n"); + tick++; + } else { + esp_log("EEPROM 1st start bit is longer than needed\n"); + } + } else if (tick < 4) { + tick++; + command <<= 1; + if (dat) + command += 1; + } else if (tick < 10) { + tick++; + address = (address << 1) | dat; + if (tick == 10) { + esp_log("EEPROM command = %02x, address = %02x (val = %04x)\n", command, + address, eeprom->data[address]); + if (command == 2) + eedo = 0; + address = address % 64; + if (command == 0) { + switch (address >> 4) { + case 0: + esp_log("EEPROM Write disable command\n"); + eeprom->wp = 1; + break; + case 1: + esp_log("EEPROM Write all command\n"); + break; + case 2: + esp_log("EEPROM Erase all command\n"); + break; + case 3: + esp_log("EEPROM Write enable command\n"); + eeprom->wp = 0; + break; + } + } else { + esp_log("EEPROM Read, write or erase word\n"); + eeprom->dat = eeprom->data[address]; + } + } + } else if (tick < 26) { + tick++; + if (command == 2) { + esp_log("EEPROM Read Word\n"); + eedo = ((eeprom->dat & 0x8000) != 0); + } + eeprom->dat <<= 1; + eeprom->dat += dat; + } else { + esp_log("EEPROM Additional unneeded tick, not processed\n"); + } + } + + eeprom->count = tick; + eeprom->oldena = ena; + eeprom->oldclk = clk; + eeprom->out = eedo; + eeprom->address = address; + eeprom->opcode = command; + esp_log("EEPROM EEDO = %d\n", eeprom->out); +} + +static void +dc390_load_eeprom(esp_t *dev) +{ + ati_eeprom_t *eeprom = &dev->eeprom; + uint8_t *nvr = (uint8_t *)eeprom->data; + int i; + uint16_t checksum = 0; + FILE *f; + + eeprom->out = 1; + + f = nvr_fopen(dev->nvr_path, L"rb"); + if (f) { + esp_log("EEPROM Load\n"); + if (fread(nvr, 1, 128, f) != 128) + fatal("dc390_eeprom_load(): Error reading data\n"); + fclose(f); + } else { + for (i = 0; i < 16; i++) { + nvr[i * 2] = 0x57; + nvr[i * 2 + 1] = 0x00; + } + + esp_log("EEPROM Defaults\n"); + + nvr[EE_ADAPT_SCSI_ID] = 7; + nvr[EE_MODE2] = 0x0f; + nvr[EE_TAG_CMD_NUM] = 0x04; + nvr[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT | + EE_ADAPT_OPTION_BOOT_FROM_CDROM | + EE_ADAPT_OPTION_INT13; + for (i = 0; i < EE_CHKSUM1; i += 2) { + checksum += ((nvr[i] & 0xff) | (nvr[i + 1] << 8)); + esp_log("Checksum calc = %04x, nvr = %02x\n", checksum, nvr[i]); + } + + checksum = 0x1234 - checksum; + nvr[EE_CHKSUM1] = checksum & 0xff; + nvr[EE_CHKSUM2] = checksum >> 8; + esp_log("EEPROM Checksum = %04x\n", checksum); + } +} + +uint8_t esp_pci_regs[256]; +bar_t esp_pci_bar[2]; + + +static uint8_t +esp_pci_read(int func, int addr, void *p) +{ + esp_t *dev = (esp_t *)p; + + esp_log("ESP PCI: Reading register %02X\n", addr & 0xff); + + switch (addr) { + case 0x00: + esp_log("ESP PCI: Read DO line = %02x\n", dev->eeprom.out); + if (!dev->has_bios) + return 0x22; + else { + if (dev->eeprom.out) + return 0x22; + else { + dev->eeprom.out = 1; + return 2; + } + } + break; + case 0x01: + return 0x10; + case 0x02: + return 0x20; + case 0x03: + return 0x20; + case 0x04: + return esp_pci_regs[0x04] & 3; /*Respond to IO*/ + case 0x07: + return 2; + case 0x08: + return 0; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return esp_pci_bar[0].addr_regs[1]; + case 0x12: + return esp_pci_bar[0].addr_regs[2]; + case 0x13: + return esp_pci_bar[0].addr_regs[3]; + case 0x30: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[0]; + case 0x31: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[1]; + case 0x32: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[2]; + case 0x33: + if (!dev->has_bios) + return 0; + return esp_pci_bar[1].addr_regs[3]; + case 0x3C: + return dev->irq; + case 0x3D: + return PCI_INTA; + } + + return(0); +} + + +static void +esp_pci_write(int func, int addr, uint8_t val, void *p) +{ + esp_t *dev = (esp_t *)p; + uint8_t valxor; + int eesk; + int eedi; + + esp_log("ESP PCI: Write value %02X to register %02X\n", val, addr); + + if ((addr >= 0x80) && (addr <= 0xFF)) { + if (addr == 0x80) { + eesk = val & 0x80 ? 1 : 0; + eedi = val & 0x40 ? 1 : 0; + dc390_write_eeprom(dev, 1, eesk, eedi); + } else if (addr == 0xc0) + dc390_write_eeprom(dev, 0, 0, 0); + esp_log("ESP PCI: Write value %02X to register %02X\n", val, addr); + return; + } + + switch (addr) { + case 0x04: + valxor = (val & 3) ^ esp_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + esp_io_remove(dev, dev->PCIBase, 0x80); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) + esp_io_set(dev, dev->PCIBase, 0x80); + } + esp_pci_regs[addr] = val & 3; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + esp_io_remove(dev, dev->PCIBase, 0x80); + /* Then let's set the PCI regs. */ + esp_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + esp_pci_bar[0].addr &= 0xff00; + dev->PCIBase = esp_pci_bar[0].addr; + /* Log the new base. */ + esp_log("ESP PCI: New I/O base is %04X\n" , dev->PCIBase); + /* We're done, so get out of the here. */ + if (esp_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) { + esp_io_set(dev, dev->PCIBase, 0x80); + } + } + return; + + case 0x30: case 0x31: case 0x32: case 0x33: + if (!dev->has_bios) + return; + /* BIOS Base set. */ + /* First, remove the old I/O. */ + esp_bios_disable(dev); + /* Then let's set the PCI regs. */ + esp_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + esp_pci_bar[1].addr &= 0xfffec001; + dev->BIOSBase = esp_pci_bar[1].addr & 0xfffec000; + /* Log the new base. */ + esp_log("ESP PCI: New BIOS base is %08X\n" , dev->BIOSBase); + /* We're done, so get out of the here. */ + if (esp_pci_bar[1].addr & 0x00000001) + esp_bios_set_addr(dev, dev->BIOSBase); + return; + + case 0x3C: + esp_pci_regs[addr] = val; + dev->irq = val; + esp_log("ESP IRQ now: %i\n", val); + return; + } +} + +static void * +dc390_init(const device_t *info) +{ + esp_t *dev; + + dev = malloc(sizeof(esp_t)); + memset(dev, 0x00, sizeof(esp_t)); + + dev->PCIBase = 0; + dev->MMIOBase = 0; + + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, esp_pci_read, esp_pci_write, dev); + + esp_pci_bar[0].addr_regs[0] = 1; + esp_pci_regs[0x04] = 3; + + dev->has_bios = device_get_config_int("bios"); + if (dev->has_bios) + rom_init(&dev->bios, DC390_ROM, 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + /* Enable our BIOS space in PCI, if needed. */ + if (dev->has_bios) { + esp_pci_bar[1].addr = 0xfffec000; + } else { + esp_pci_bar[1].addr = 0; + } + + if (dev->has_bios) + esp_bios_disable(dev); + + dev->nvr_path = L"dc390.nvr"; + + /* Load the serial EEPROM. */ + dc390_load_eeprom(dev); + + esp_pci_hard_reset(dev); + + timer_add(&dev->timer, esp_callback, dev, 0); + + return(dev); +} + + +static void +esp_close(void *priv) +{ + esp_t *dev = (esp_t *)priv; + + if (dev) { + free(dev); + dev = NULL; + } +} + + +static const device_config_t dc390_pci_config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t dc390_pci_device = +{ + "Tekram DC-390 PCI (SCSI)", + DEVICE_PCI, + 0, + dc390_init, esp_close, NULL, + NULL, NULL, NULL, + dc390_pci_config +}; diff --git a/src/sio/sio_pc87307.c b/src/sio/sio_pc87307.c index 0a1578c76..787a540f2 100644 --- a/src/sio/sio_pc87307.c +++ b/src/sio/sio_pc87307.c @@ -157,7 +157,7 @@ fdc_handler(pc87307_t *dev) addr = ((dev->ld_regs[0x03][0x30] << 8) | dev->ld_regs[0x03][0x31]) - 0x0002; irq = (dev->ld_regs[0x03][0x40] & 0x0f); - if (active && (addr <= 0xfff2)) { + if (active && (addr <= 0xfff8)) { fdc_set_base(dev->fdc, addr); fdc_set_irq(dev->fdc, irq); } @@ -322,7 +322,7 @@ pc87307_write(uint16_t port, uint8_t val, void *priv) dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfb; break; case 0x03: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; fdc_handler(dev); break; case 0x04: @@ -542,8 +542,13 @@ pc87307_init(const device_t *info) pc87307_reset(dev); - io_sethandler(0x02e, 0x0002, - pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + if (info->local & 0x100) { + io_sethandler(0x15c, 0x0002, + pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + } else { + io_sethandler(0x02e, 0x0002, + pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, dev); + } return dev; } @@ -559,6 +564,16 @@ const device_t pc87307_device = { }; +const device_t pc87307_15c_device = { + "National Semiconductor PC87307 Super I/O (Port 15Ch)", + 0, + 0x1c0, + pc87307_init, pc87307_close, NULL, + NULL, NULL, NULL, + NULL +}; + + const device_t pc97307_device = { "National Semiconductor PC97307 Super I/O", 0, diff --git a/src/sio/sio_pc87309.c b/src/sio/sio_pc87309.c index 0b55b9655..ecbc76de7 100644 --- a/src/sio/sio_pc87309.c +++ b/src/sio/sio_pc87309.c @@ -255,7 +255,7 @@ pc87309_write(uint16_t port, uint8_t val, void *priv) case 0x61: switch (dev->regs[0x07]) { case 0x00: - dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = val & 0xfa; + dev->ld_regs[dev->regs[0x07]][dev->cur_reg - 0x30] = (val & 0xfa) | 0x02; fdc_handler(dev); break; case 0x01: @@ -460,8 +460,13 @@ pc87309_init(const device_t *info) pc87309_reset(dev); - io_sethandler(0x02e, 0x0002, - pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + if (info->local & 0x100) { + io_sethandler(0x15c, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + } else { + io_sethandler(0x02e, 0x0002, + pc87309_read, NULL, NULL, pc87309_write, NULL, NULL, dev); + } return dev; } @@ -475,3 +480,13 @@ const device_t pc87309_device = { NULL, NULL, NULL, NULL }; + + +const device_t pc87309_15c_device = { + "National Semiconductor PC87309 Super I/O (Port 15Ch)", + 0, + 0x1e0, + pc87309_init, pc87309_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 83f713c89..392d4948a 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -28,33 +28,6 @@ #include <86box/vid_ati_eeprom.h> -enum -{ - EEPROM_IDLE, - EEPROM_WAIT, - EEPROM_OPCODE, - EEPROM_INPUT, - EEPROM_OUTPUT -}; - -enum -{ - EEPROM_OP_EW = 4, - EEPROM_OP_WRITE = 5, - EEPROM_OP_READ = 6, - EEPROM_OP_ERASE = 7, - - EEPROM_OP_WRALMAIN = -1 -}; - -enum -{ - EEPROM_OP_EWDS = 0, - EEPROM_OP_WRAL = 1, - EEPROM_OP_ERAL = 2, - EEPROM_OP_EWEN = 3 -}; - void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) { FILE *f; diff --git a/src/win/86Box.manifest b/src/win/86Box.manifest index ebccd7674..cf0e13b91 100644 --- a/src/win/86Box.manifest +++ b/src/win/86Box.manifest @@ -1,21 +1,27 @@  - - + + - + - + + + + true + permonitorv2 + + diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 845b65844..61cb789d3 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -80,6 +80,7 @@ BEGIN MENUITEM "1.&5x", IDM_VID_SCALE_3X MENUITEM "&2x", IDM_VID_SCALE_4X END + MENUITEM "Hi&DPI scaling", IDM_VID_HIDPI MENUITEM SEPARATOR MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Fullscreen &stretch mode" @@ -316,7 +317,7 @@ BEGIN WS_BORDER,53,45,166,14 END -DLG_CONFIG DIALOG DISCARDABLE 0, 0, 366, 256 +DLG_CONFIG DIALOG DISCARDABLE 0, 0, 376, 256 STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "86Box Settings" FONT 9, "Segoe UI" @@ -324,8 +325,8 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,246,235,50,14 PUSHBUTTON "Cancel",IDCANCEL,307,235,50,14 CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_LIST | - LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,90,212 - CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,363,1 + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,100,212 + CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,226,373,1 /* Leave this commented out until we get into localization. */ #if 0 LTEXT "Language:",IDT_1700,7,237,41,10 @@ -334,7 +335,7 @@ BEGIN #endif END -DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 305, 199 +DLG_CFG_MACHINE DIALOG DISCARDABLE 107, 0, 305, 199 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -376,7 +377,7 @@ BEGIN #endif END -DLG_CFG_VIDEO DIALOG DISCARDABLE 97, 0, 267, 45 +DLG_CFG_VIDEO DIALOG DISCARDABLE 107, 0, 267, 45 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -389,7 +390,7 @@ BEGIN PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,222,26,38,12 END -DLG_CFG_INPUT DIALOG DISCARDABLE 97, 0, 267, 65 +DLG_CFG_INPUT DIALOG DISCARDABLE 107, 0, 267, 65 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -406,7 +407,7 @@ BEGIN PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 END -DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 199 +DLG_CFG_SOUND DIALOG DISCARDABLE 107, 0, 267, 199 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -442,7 +443,7 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,7,115,94,10 END -DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 +DLG_CFG_NETWORK DIALOG DISCARDABLE 107, 0, 267, 63 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -460,7 +461,7 @@ BEGIN PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 END -DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 135 +DLG_CFG_PORTS DIALOG DISCARDABLE 107, 0, 267, 135 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -493,7 +494,7 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,7,118,94,10 END -DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 220 +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 107, 0, 267, 220 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -550,7 +551,7 @@ BEGIN PUSHBUTTON "Configure",IDC_CONFIGURE_ISAMEM_4,217,190,38,12 END -DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 97, 0, 267, 154 +DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 107, 0, 267, 154 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -611,7 +612,7 @@ BEGIN WS_BORDER,7,16,204,12 END -DLG_CFG_FLOPPY_AND_CDROM_DRIVES DIALOG DISCARDABLE 97, 0, 267, 222 +DLG_CFG_FLOPPY_AND_CDROM_DRIVES DIALOG DISCARDABLE 107, 0, 267, 222 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -645,7 +646,7 @@ BEGIN LTEXT "Speed:",IDT_1758,7,207,24,8 END -DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 97, 0, 267, 222 +DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 107, 0, 267, 222 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index a1fa60d51..bdcaf3c6b 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -697,7 +697,7 @@ SCSIOBJ := scsi.o scsi_device.o \ scsi_x54x.o \ scsi_aha154x.o scsi_buslogic.o \ scsi_ncr5380.o scsi_ncr53c8xx.o \ - scsi_spock.o + scsi_pcscsi.o scsi_spock.o NETOBJ := network.o \ net_pcap.o \ diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 961f2b255..846e069ba 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -71,6 +71,7 @@ static int first_cat = 0; +static int dpi = 96; /* Machine category */ static int temp_machine_type, temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_fpu, temp_sync; @@ -153,8 +154,11 @@ image_list_init(HWND hwndList, const uint8_t *icon_ids) int i = 0; - hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON), + hSmall = ListView_GetImageList(hwndList, LVSIL_SMALL); + if (hSmall != 0) ImageList_Destroy(hSmall); + + hSmall = ImageList_Create(win_get_system_metrics(SM_CXSMICON, dpi), + win_get_system_metrics(SM_CYSMICON, dpi), ILC_MASK | ILC_COLOR32, 1, 1); while(1) { @@ -2680,6 +2684,16 @@ win_settings_hard_disks_recalc_list(HWND hwndList) return TRUE; } +static void +win_settings_hard_disks_resize_columns(HWND hwndList) +{ + int iCol; + /* Bus, File, Cylinders, Heads, Sectors, Size */ + int width[C_COLUMNS_HARD_DISKS] = {130, 130, 41, 25, 25, 41}; + for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) { + ListView_SetColumnWidth(hwndList, iCol, MulDiv(width[iCol], dpi, 96)); + } +} static BOOL win_settings_hard_disks_init_columns(HWND hwndList) @@ -2695,7 +2709,7 @@ win_settings_hard_disks_init_columns(HWND hwndList) switch(iCol) { case 0: /* Bus */ - lvc.cx = 135; + lvc.cx = 130; lvc.fmt = LVCFMT_LEFT; break; case 2: /* Cylinders */ @@ -2708,7 +2722,7 @@ win_settings_hard_disks_init_columns(HWND hwndList) lvc.fmt = LVCFMT_RIGHT; break; case 1: /* File */ - lvc.cx = 150; + lvc.cx = 130; lvc.fmt = LVCFMT_LEFT; break; case 5: /* Size (MB) 8 */ @@ -2721,6 +2735,7 @@ win_settings_hard_disks_init_columns(HWND hwndList) return FALSE; } + win_settings_hard_disks_resize_columns(hwndList); return TRUE; } @@ -3682,6 +3697,11 @@ hd_bus_skip: return FALSE; } + case WM_DPICHANGED_AFTERPARENT: + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_resize_columns(h); + image_list_init(h, (const uint8_t *) hd_icons); + break; default: return FALSE; } @@ -3920,6 +3940,14 @@ win_settings_zip_drives_recalc_list(HWND hwndList) } +static void +win_settings_floppy_drives_resize_columns(HWND hwndList) +{ + ListView_SetColumnWidth(hwndList, 0, MulDiv(250, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(50, dpi, 96)); + ListView_SetColumnWidth(hwndList, 2, MulDiv(75, dpi, 96)); +} + static BOOL win_settings_floppy_drives_init_columns(HWND hwndList) { @@ -3930,7 +3958,7 @@ win_settings_floppy_drives_init_columns(HWND hwndList) lvc.iSubItem = 0; lvc.pszText = plat_get_string(IDS_2092); - lvc.cx = 292; + lvc.cx = 250; lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) @@ -3952,12 +3980,20 @@ win_settings_floppy_drives_init_columns(HWND hwndList) lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 2, &lvc) == -1) - return FALSE; + return FALSE; + win_settings_floppy_drives_resize_columns(hwndList); return TRUE; } +static void +win_settings_cdrom_drives_resize_columns(HWND hwndList) +{ + ListView_SetColumnWidth(hwndList, 0, MulDiv(342, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(50, dpi, 96)); +} + static BOOL win_settings_cdrom_drives_init_columns(HWND hwndList) { @@ -3981,11 +4017,18 @@ win_settings_cdrom_drives_init_columns(HWND hwndList) lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) - return FALSE; + return FALSE; + win_settings_cdrom_drives_resize_columns(hwndList); return TRUE; } +static void +win_settings_mo_drives_resize_columns(HWND hwndList) +{ + ListView_SetColumnWidth(hwndList, 0, MulDiv(120, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(260, dpi, 96)); +} static BOOL win_settings_mo_drives_init_columns(HWND hwndList) @@ -4010,11 +4053,18 @@ win_settings_mo_drives_init_columns(HWND hwndList) lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) - return FALSE; + return FALSE; + win_settings_mo_drives_resize_columns(hwndList); return TRUE; } +static void +win_settings_zip_drives_resize_columns(HWND hwndList) +{ + ListView_SetColumnWidth(hwndList, 0, MulDiv(342, dpi, 96)); + ListView_SetColumnWidth(hwndList, 1, MulDiv(50, dpi, 96)); +} static BOOL win_settings_zip_drives_init_columns(HWND hwndList) @@ -4039,8 +4089,9 @@ win_settings_zip_drives_init_columns(HWND hwndList) lvc.fmt = LVCFMT_LEFT; if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) - return FALSE; + return FALSE; + win_settings_zip_drives_resize_columns(hwndList); return TRUE; } @@ -4856,6 +4907,14 @@ win_settings_floppy_and_cdrom_drives_proc(HWND hdlg, UINT message, WPARAM wParam } ignore_change = 0; + case WM_DPICHANGED_AFTERPARENT: + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_resize_columns(h); + image_list_init(h, (const uint8_t *) fd_icons); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_resize_columns(h); + image_list_init(h, (const uint8_t *) cd_icons); + break; default: return FALSE; } @@ -5122,6 +5181,14 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam } ignore_change = 0; + case WM_DPICHANGED_AFTERPARENT: + h = GetDlgItem(hdlg, IDC_LIST_MO_DRIVES); + win_settings_mo_drives_resize_columns(h); + image_list_init(h, (const uint8_t *) mo_icons); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_resize_columns(h); + image_list_init(h, (const uint8_t *) zip_icons); + break; default: return FALSE; } @@ -5244,6 +5311,7 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: + dpi = win_get_dpi(hdlg); win_settings_init(); displayed_category = -1; h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); @@ -5277,6 +5345,11 @@ win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) return TRUE; } break; + case WM_DPICHANGED: + dpi = HIWORD(wParam); + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + image_list_init(h, (const uint8_t *) cat_icons); + break; default: return FALSE; } diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index 67add30f1..f29ff2523 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -70,6 +70,8 @@ static uint8_t *sb_part_icons; static int sb_parts = 0; static int sb_ready = 0; static uint8_t sb_map[256]; +static int dpi = 96; +static int icon_width = 24; /* Also used by win_settings.c */ intptr_t @@ -537,7 +539,7 @@ ui_sb_update_panes(void) sb_parts = 0; for (i=0; i= (sb_parts - 1)) return; - pt.x = id * SB_ICON_WIDTH; /* Justify to the left. */ + pt.x = id * icon_width; /* Justify to the left. */ pt.y = 0; /* Justify to the top. */ ClientToScreen(hwnd, (LPPOINT) &pt); @@ -744,6 +745,48 @@ StatusBarPopupMenu(HWND hwnd, POINT pt, int id) pt.x, pt.y, 0, hwndSBAR, NULL); } +/* API: Load status bar icons */ +void +StatusBarLoadIcon(HINSTANCE hInst) { + int i; + int x = win_get_system_metrics(SM_CXSMICON, dpi); + + for (i=0; i<256; i++) { + if (hIcon[i] != 0) + DestroyIcon(hIcon[i]); + } + + for (i = 16; i < 18; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 24; i < 26; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 32; i < 34; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 48; i < 50; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 56; i < 58; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 64; i < 66; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 80; i < 82; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 96; i < 98; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 144; i < 146; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 152; i < 154; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 160; i < 162; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 176; i < 178; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 184; i < 186; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 192; i < 194; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); + for (i = 243; i < 244; i++) + hIcon[i] = LoadImage(hInst, MAKEINTRESOURCE(i), IMAGE_ICON, x, x, LR_DEFAULTCOLOR); +} /* Handle messages for the Status Bar window. */ #if defined(__amd64__) || defined(__aarch64__) @@ -756,6 +799,8 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) RECT rc; POINT pt; int item_id = 0; + int i; + HINSTANCE hInst; switch (message) { case WM_COMMAND: @@ -768,20 +813,38 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); if (PtInRect((LPRECT) &rc, pt)) - StatusBarPopupMenu(hwnd, pt, (pt.x / SB_ICON_WIDTH)); + StatusBarPopupMenu(hwnd, pt, (pt.x / icon_width)); break; case WM_LBUTTONDBLCLK: GetClientRect(hwnd, (LPRECT)& rc); pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); - item_id = (pt.x / SB_ICON_WIDTH); + item_id = (pt.x / icon_width); if (PtInRect((LPRECT) &rc, pt) && (item_id < sb_parts)) { if (sb_part_meanings[item_id] == SB_SOUND) SoundGainDialogCreate(hwndMain); } break; + case WM_DPICHANGED_AFTERPARENT: + /* DPI changed, reload icons */ + hInst = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); + dpi = win_get_dpi(hwnd); + icon_width = MulDiv(SB_ICON_WIDTH, dpi, 96); + StatusBarLoadIcon(hInst); + + for (i=0; i // for update_overscan #include <86box/plat.h> #include <86box/plat_midi.h> +#include <86box/plat_dynld.h> #include <86box/ui.h> #include <86box/win.h> #include <86box/version.h> @@ -69,10 +70,67 @@ static wchar_t wTitle[512]; static HHOOK hKeyboardHook; static int hook_enabled = 0, manager_wm = 0; static int save_window_pos = 0, pause_state = 0; +static int dpi = 96; +static int padded_frame = 0; static int vis = -1; +/* Per Monitor DPI Aware v2 APIs, Windows 10 v1703+ */ +void* user32_handle = NULL; +static UINT (WINAPI *pGetDpiForWindow)(HWND); +static UINT (WINAPI *pGetSystemMetricsForDpi)(int i, UINT dpi); +static DPI_AWARENESS_CONTEXT (WINAPI *pGetWindowDpiAwarenessContext)(HWND); +static BOOL (WINAPI *pAreDpiAwarenessContextsEqual)(DPI_AWARENESS_CONTEXT A, DPI_AWARENESS_CONTEXT B); +static dllimp_t user32_imports[] = { +{ "GetDpiForWindow", &pGetDpiForWindow }, +{ "GetSystemMetricsForDpi", &pGetSystemMetricsForDpi }, +{ "GetWindowDpiAwarenessContext", &pGetWindowDpiAwarenessContext }, +{ "AreDpiAwarenessContextsEqual", &pAreDpiAwarenessContextsEqual }, +{ NULL, NULL } +}; + +int +win_get_dpi(HWND hwnd) { + if (user32_handle != NULL) { + return pGetDpiForWindow(hwnd); + } else { + HDC dc = GetDC(hwnd); + UINT dpi = GetDeviceCaps(dc, LOGPIXELSX); + ReleaseDC(hwnd, dc); + return dpi; + } +} + +int win_get_system_metrics(int index, int dpi) { + if (user32_handle != NULL) { + /* Only call GetSystemMetricsForDpi when we are using PMv2 */ + DPI_AWARENESS_CONTEXT c = pGetWindowDpiAwarenessContext(hwndMain); + if (pAreDpiAwarenessContextsEqual(c, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) + return pGetSystemMetricsForDpi(index, dpi); + } + + return GetSystemMetrics(index); +} + +void +ResizeWindowByClientArea(HWND hwnd, int width, int height) +{ + if (vid_resize || padded_frame) { + int padding = win_get_system_metrics(SM_CXPADDEDBORDER, dpi); + width += (win_get_system_metrics(SM_CXFRAME, dpi) + padding) * 2; + height += (win_get_system_metrics(SM_CYFRAME, dpi) + padding) * 2; + } else { + width += win_get_system_metrics(SM_CXFIXEDFRAME, dpi) * 2; + height += win_get_system_metrics(SM_CYFIXEDFRAME, dpi) * 2; + } + + height += win_get_system_metrics(SM_CYCAPTION, dpi); + height += win_get_system_metrics(SM_CYBORDER, dpi) + win_get_system_metrics(SM_CYMENUSIZE, dpi); + + SetWindowPos(hwnd, NULL, 0, 0, width, height, SWP_NOMOVE); +} + /* Set host cursor visible or not. */ void show_cursor(int val) @@ -168,6 +226,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_SCALE_1X+1, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+2, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+3, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_HIDPI, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_CGACON, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+0, MF_UNCHECKED); @@ -217,6 +276,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); CheckMenuItem(menuMain, IDM_VID_REMEMBER, window_remember?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_SCALE_1X+scale, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_HIDPI, dpi_scale?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_CGACON, vid_cga_contrast?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); @@ -290,8 +350,8 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HMENU hmenu; - int i, sb_borders[3]; - RECT rect; + int i; + RECT rect, *rect_p; int temp_x, temp_y; @@ -392,42 +452,28 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW) | WS_VISIBLE); - else - SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX) | WS_VISIBLE); + else + SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX) | WS_VISIBLE); - SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); - - GetWindowRect(hwnd, &rect); - - /* Main Window. */ - if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { - /* For platforms that subsystem version < 6.0 (default on mingw/msys2) */ - /* In this case, border sizes are different between resizable and non-resizable window */ - MoveWindow(hwnd, rect.left, rect.top, - unscaled_size_x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), - unscaled_size_y + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); + /* scale the screen base on DPI */ + if (dpi_scale) { + temp_x = MulDiv(unscaled_size_x, dpi, 96); + temp_y = MulDiv(unscaled_size_y, dpi, 96); } else { - /* For platforms that subsystem version >= 6.0 (default on llvm-mingw, mainly for Windows/ARM) */ - /* In this case, border sizes are the same between resizable and non-resizable window */ - MoveWindow(hwnd, rect.left, rect.top, - unscaled_size_x + ((GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2), - unscaled_size_y + ((GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); + temp_x = unscaled_size_x; + temp_y = unscaled_size_y; } + /* Main Window. */ + ResizeWindowByClientArea(hwnd, temp_x, temp_y + sbar_height); /* Render window. */ - MoveWindow(hwndRender, 0, 0, unscaled_size_x, unscaled_size_y, TRUE); + MoveWindow(hwndRender, 0, 0, temp_x, temp_y, TRUE); GetWindowRect(hwndRender, &rect); /* Status bar. */ - MoveWindow(hwndSBAR, - 0, rect.bottom + GetSystemMetrics(SM_CYEDGE), - unscaled_size_x, 17, TRUE); + MoveWindow(hwndSBAR, 0, rect.bottom, temp_x, 17, TRUE); if (mouse_capture) { - GetWindowRect(hwndRender, &rect); - ClipCursor(&rect); } @@ -440,6 +486,9 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); + + scrnsz_x = unscaled_size_x; + scrnsz_y = unscaled_size_y; doresize = 1; config_save(); break; @@ -496,6 +545,13 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) config_save(); break; + case IDM_VID_HIDPI: + dpi_scale = !dpi_scale; + CheckMenuItem(hmenu, IDM_VID_HIDPI, dpi_scale ? MF_CHECKED : MF_UNCHECKED); + doresize = 1; + config_save(); + break; + case IDM_VID_FORCE43: video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); video_force_resize_set(1); @@ -624,12 +680,22 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_ENTERMENULOOP: break; + case WM_DPICHANGED: + dpi = HIWORD(wParam); + GetWindowRect(hwndSBAR, &rect); + sbar_height = rect.bottom - rect.top; + rect_p = (RECT*)lParam; + if (vid_resize) { + MoveWindow(hwnd, rect_p->left, rect_p->top, rect_p->right - rect_p->left, rect_p->bottom - rect_p->top, TRUE); + } else if (!user_resize) { + doresize = 1; + } + break; + case WM_SIZE: if (user_resize && !vid_resize) break; - SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); - temp_x = (lParam & 0xFFFF); temp_y = (lParam >> 16); @@ -646,26 +712,22 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (temp_y < 1) temp_y = 1; - if ((temp_x != scrnsz_x) || (temp_y != scrnsz_y)) + if (vid_resize && ((temp_x != scrnsz_x) || (temp_y != scrnsz_y))) { + scrnsz_x = temp_x; + scrnsz_y = temp_y; doresize = 1; + } - scrnsz_x = temp_x; - scrnsz_y = temp_y; - - MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); + MoveWindow(hwndRender, 0, 0, temp_x, temp_y, TRUE); GetWindowRect(hwndRender, &rect); /* Status bar. */ - MoveWindow(hwndSBAR, - 0, rect.bottom + GetSystemMetrics(SM_CYEDGE), - scrnsz_x, 17, TRUE); + MoveWindow(hwndSBAR, 0, rect.bottom, temp_x, 17, TRUE); - plat_vidsize(scrnsz_x, scrnsz_y); + plat_vidsize(temp_x, temp_y); if (mouse_capture) { - GetWindowRect(hwndRender, &rect); - ClipCursor(&rect); } @@ -894,6 +956,9 @@ ui_init(int nCmdShow) TASKDIALOGCONFIG tdconfig = {0}; TASKDIALOG_BUTTON tdbuttons[] = {{IDCANCEL, MAKEINTRESOURCE(IDS_2119)}}; + /* Load DPI related Windows 10 APIs */ + user32_handle = dynld_module("user32.dll", user32_imports); + /* Set up TaskDialog configuration. */ tdconfig.cbSize = sizeof(tdconfig); tdconfig.dwFlags = TDF_ENABLE_HYPERLINKS; @@ -973,6 +1038,19 @@ ui_init(int nCmdShow) ui_window_title(title); + /* Get the current DPI */ + dpi = win_get_dpi(hwndMain); + + /* Check if we have a padded window frame */ + padded_frame = (GetSystemMetrics(SM_CXPADDEDBORDER) != 0); + + /* Create the status bar window. */ + StatusBarCreate(hwndMain, IDC_STATUS, hinstance); + + /* Get the actual height of the status bar */ + GetWindowRect(hwndSBAR, &sbar_rect); + sbar_height = sbar_rect.bottom - sbar_rect.top; + /* Set up main window for resizing if configured. */ if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, @@ -1019,15 +1097,6 @@ ui_init(int nCmdShow) /* Initialize the mouse module. */ win_mouse_init(); - /* Create the status bar window. */ - StatusBarCreate(hwndMain, IDC_STATUS, hinstance); - - /* Get the actual height of the statusbar, - * since that is not something we can change. - */ - GetWindowRect(hwndSBAR, &sbar_rect); - sbar_height = sbar_rect.bottom - sbar_rect.top; - /* * Before we can create the Render window, we first have * to prepare some other things that it depends on. @@ -1137,6 +1206,9 @@ ui_init(int nCmdShow) discord_close(); #endif + if (user32_handle != NULL) + dynld_close(user32_handle); + return(messages.wParam); } @@ -1218,42 +1290,26 @@ plat_pause(int p) void plat_resize(int x, int y) { - int sb_borders[3]; RECT r; /* First, see if we should resize the UI window. */ if (!vid_resize) { video_wait_for_blit(); - SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); - GetWindowRect(hwndMain, &r); - - if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { - /* For platforms that subsystem version < 6.0 (gcc on mingw/msys2) */ - /* In this case, border sizes are different between resizable and non-resizable window */ - MoveWindow(hwndMain, r.left, r.top, - x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), - y + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); - } else { - /* For platforms that subsystem version >= 6.0 (clang/llvm on llvm-mingw, mainly for Windows/ARM) */ - /* In this case, border sizes are the same between resizable and non-resizable window */ - MoveWindow(hwndMain, r.left, r.top, - x + ((GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2), - y + ((GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2) + (GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYMENUSIZE)) + GetSystemMetrics(SM_CYCAPTION) + sbar_height, - TRUE); + /* scale the screen base on DPI */ + if (dpi_scale) { + x = MulDiv(x, dpi, 96); + y = MulDiv(y, dpi, 96); } + ResizeWindowByClientArea(hwndMain, x, y + sbar_height); MoveWindow(hwndRender, 0, 0, x, y, TRUE); GetWindowRect(hwndRender, &r); - MoveWindow(hwndSBAR, - 0, r.bottom + GetSystemMetrics(SM_CYEDGE), - x, 17, TRUE); + MoveWindow(hwndSBAR, 0, y, x, 17, TRUE); if (mouse_capture) { - GetWindowRect(hwndRender, &r); ClipCursor(&r); } }