From 2eba22295accee0fb8247c8e50d66fa1cdf4f464 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 8 Jul 2021 18:54:31 -0300 Subject: [PATCH 1/3] VIA southbridge fixes, including dynamic SMBus clock --- src/chipset/via_pipc.c | 162 ++++++++++++++++++++++++-------- src/device/smbus_piix4.c | 16 +++- src/include/86box/chipset.h | 3 +- src/include/86box/smbus_piix4.h | 3 + src/machine/m_at_slot1.c | 2 +- 5 files changed, 142 insertions(+), 44 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index d488035ee..46d2f8597 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -16,7 +16,7 @@ * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. * Copyright 2020 Melissa Goad. - * Copyright 2020 RichardG. + * Copyright 2020-2021 RichardG. */ #include @@ -58,6 +58,7 @@ #define VIA_PIPC_596B 0x05962300 #define VIA_PIPC_686A 0x06861400 #define VIA_PIPC_686B 0x06864000 +#define VIA_PIPC_8231 0x82311000 typedef struct @@ -118,6 +119,7 @@ pipc_reset_hard(void *priv) memset(dev->power_regs, 0, 256); memset(dev->ac97_regs, 0, 512); + /* PCI-ISA bridge registers */ dev->pci_isa_regs[0x00] = 0x06; dev->pci_isa_regs[0x01] = 0x11; dev->pci_isa_regs[0x02] = dev->local >> 16; dev->pci_isa_regs[0x03] = dev->local >> 24; @@ -167,19 +169,23 @@ pipc_reset_hard(void *priv) if (dev->local <= VIA_PIPC_586B) dev->ide_regs[0x40] = 0x04; - dev->ide_regs[0x41] = (dev->local <= VIA_PIPC_686A) ? 0x06 : 0x02; + dev->ide_regs[0x41] = (dev->local == VIA_PIPC_686B) ? 0x06 : 0x02; dev->ide_regs[0x42] = 0x09; dev->ide_regs[0x43] = (dev->local >= VIA_PIPC_686A) ? 0x0a : 0x3a; dev->ide_regs[0x44] = 0x68; + if (dev->local == VIA_PIPC_686B) + dev->ide_regs[0x45] = 0x20; + else if (dev->local >= VIA_PIPC_8231) + dev->ide_regs[0x45] = 0x03; dev->ide_regs[0x46] = 0xc0; dev->ide_regs[0x48] = 0xa8; dev->ide_regs[0x49] = 0xa8; dev->ide_regs[0x4a] = 0xa8; dev->ide_regs[0x4b] = 0xa8; dev->ide_regs[0x4c] = 0xff; - dev->ide_regs[0x4e] = 0xff; - dev->ide_regs[0x4f] = 0xff; - dev->ide_regs[0x50] = dev->ide_regs[0x51] = dev->ide_regs[0x52] = dev->ide_regs[0x53] = (dev->local >= VIA_PIPC_686A) ? 0x07 : 0x03; + if (dev->local != VIA_PIPC_686B) + dev->ide_regs[0x4e] = dev->ide_regs[0x4f] = 0xff; + dev->ide_regs[0x50] = dev->ide_regs[0x51] = dev->ide_regs[0x52] = dev->ide_regs[0x53] = ((dev->local == VIA_PIPC_686A) || (dev->local == VIA_PIPC_686B)) ? 0x07 : 0x03; if (dev->local >= VIA_PIPC_596A) - dev->ide_regs[0x54] = 0x06; + dev->ide_regs[0x54] = ((dev->local == VIA_PIPC_686A) || (dev->local == VIA_PIPC_686B)) ? 0x04 : 0x06; dev->ide_regs[0x61] = 0x02; dev->ide_regs[0x69] = 0x02; @@ -189,6 +195,7 @@ pipc_reset_hard(void *priv) dev->ide_regs[0xc2] = 0x02; } + /* USB registers */ for (i = 0; i <= (dev->local >= VIA_PIPC_686A); i++) { dev->max_func++; dev->usb_regs[i][0x00] = 0x06; dev->usb_regs[i][0x01] = 0x11; @@ -213,6 +220,10 @@ pipc_reset_hard(void *priv) case VIA_PIPC_686B: dev->usb_regs[i][0x08] = 0x1a; break; + + case VIA_PIPC_8231: + dev->usb_regs[i][0x08] = 0x1e; + break; } dev->usb_regs[i][0x0a] = 0x03; @@ -220,6 +231,8 @@ pipc_reset_hard(void *priv) dev->usb_regs[i][0x0d] = 0x16; dev->usb_regs[i][0x20] = 0x01; dev->usb_regs[i][0x21] = 0x03; + if (dev->local == VIA_PIPC_686B) + dev->usb_regs[i][0x34] = 0x80; dev->usb_regs[i][0x3d] = 0x04; dev->usb_regs[i][0x60] = 0x10; @@ -230,21 +243,29 @@ pipc_reset_hard(void *priv) dev->usb_regs[i][0xc1] = 0x20; } + /* power management registers */ if (dev->acpi) { dev->max_func++; dev->power_regs[0x00] = 0x06; dev->power_regs[0x01] = 0x11; - if (dev->local <= VIA_PIPC_586B) - dev->power_regs[0x02] = 0x40; - else if (dev->local <= VIA_PIPC_596B) - dev->power_regs[0x02] = 0x50; - else - dev->power_regs[0x02] = 0x57; - dev->power_regs[0x03] = 0x30; + if (dev->local >= VIA_PIPC_8231) { + /* The VT8231 preliminary datasheet lists *two* inaccurate + device IDs (3068 and 3057). Real dumps have 8235. */ + dev->power_regs[0x02] = 0x35; dev->power_regs[0x03] = 0x82; + } else { + if (dev->local <= VIA_PIPC_586B) + dev->power_regs[0x02] = 0x40; + else if (dev->local <= VIA_PIPC_596B) + dev->power_regs[0x02] = 0x50; + else + dev->power_regs[0x02] = 0x57; + dev->power_regs[0x03] = 0x30; + } dev->power_regs[0x04] = 0x00; dev->power_regs[0x05] = 0x00; dev->power_regs[0x06] = (dev->local == VIA_PIPC_686B) ? 0x90 : 0x80; dev->power_regs[0x07] = 0x02; switch (dev->local) { case VIA_PIPC_586B: case VIA_PIPC_686A: + case VIA_PIPC_8231: dev->power_regs[0x08] = 0x10; break; @@ -260,11 +281,18 @@ pipc_reset_hard(void *priv) dev->power_regs[0x08] = 0x40; break; } + if (dev->local == VIA_PIPC_686B) + dev->power_regs[0x34] = 0x68; dev->power_regs[0x40] = 0x20; dev->power_regs[0x42] = 0xd0; dev->power_regs[0x48] = 0x01; + if (dev->local == VIA_PIPC_686B) { + dev->power_regs[0x68] = 0x01; + dev->power_regs[0x6a] = 0x02; + } + if (dev->local >= VIA_PIPC_686A) dev->power_regs[0x70] = 0x01; @@ -274,13 +302,26 @@ pipc_reset_hard(void *priv) dev->power_regs[0x90] = 0x01; } + /* AC97/MC97 registers */ if (dev->local >= VIA_PIPC_686A) { for (i = 0; i <= 1; i++) { dev->max_func++; dev->ac97_regs[i][0x00] = 0x06; dev->ac97_regs[i][0x01] = 0x11; dev->ac97_regs[i][0x02] = 0x58 + (0x10 * i); dev->ac97_regs[i][0x03] = 0x30; dev->ac97_regs[i][0x06] = 0x10 * (1 - i); dev->ac97_regs[i][0x07] = 0x02; - dev->ac97_regs[i][0x08] = (dev->local == VIA_PIPC_686A) ? 0x12 : 0x50; + switch (dev->local) { + case VIA_PIPC_686A: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x12 : 0x01; + break; + + case VIA_PIPC_686B: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x50 : 0x30; + break; + + case VIA_PIPC_8231: + dev->ac97_regs[i][0x08] = (i == 0) ? 0x40 : 0x20; + break; + } if (i == 0) { dev->ac97_regs[i][0x0a] = 0x01; @@ -291,7 +332,12 @@ pipc_reset_hard(void *priv) } dev->ac97_regs[i][0x10] = 0x01; - dev->ac97_regs[i][0x14] = 0x01; + dev->ac97_regs[i][(dev->local >= VIA_PIPC_8231) ? 0x1c : 0x14] = 0x01; + + if ((i == 0) && (dev->local >= VIA_PIPC_8231)) { + dev->ac97_regs[i][0x18] = 0x31; + dev->ac97_regs[i][0x19] = 0x03; + } dev->ac97_regs[i][0x3d] = 0x03; @@ -413,7 +459,7 @@ pipc_read(int func, int addr, void *priv) if (ret & 0x80) /* bit 7 set = use bit 6 */ c = ret & 0x40; else if (ide_drives[c]) /* bit 7 clear = use SET FEATURES mode */ - c = (ide_drives[c]->mdma_mode & 0xf00) == 0x300; + c = (ide_drives[c]->mdma_mode & 0x300) == 0x300; else /* no drive here */ c = 0; /* 586A/B datasheet claims bit 5 must be clear for UDMA, unlike later models where @@ -433,6 +479,12 @@ pipc_read(int func, int addr, void *priv) ret |= 0x10; else ret &= ~0x10; + } else if ((addr == 0xd2) && (dev->local == VIA_PIPC_686B)) { + /* SMBus clock select bit. */ + if (dev->smbus->clock == 16384) + ret &= ~0x10; + else + ret |= 0x10; } } else if ((func <= (pm_func + 2)) && !(dev->pci_isa_regs[0x85] & ((func == (pm_func + 1)) ? 0x04 : 0x08))) /* AC97 / MC97 */ @@ -512,9 +564,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) cpu_set_isa_pci_div(2); break; - case 0xa: - cpu_set_isa_pci_div(4); - break; + /* case 0xa: same as default */ case 0xb: cpu_set_isa_pci_div(6); @@ -532,7 +582,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) cpu_set_isa_pci_div(12); break; - /* Half PIT clock. */ + /* Half oscillator clock. */ case 0xf: cpu_set_isa_speed(7159091); break; @@ -735,6 +785,8 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x41: if (dev->local <= VIA_PIPC_686A) dev->ide_regs[0x41] = val; + else if (dev->local == VIA_PIPC_8231) + dev->ide_regs[0x41] = val & 0xf6; else dev->ide_regs[0x41] = val & 0xf2; break; @@ -755,7 +807,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) dev->ide_regs[0x44] = val & 0x7b; else if (dev->local <= VIA_PIPC_596B) dev->ide_regs[0x44] = val & 0x7f; - else if (dev->local <= VIA_PIPC_686A) + else if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[0x44] = val & 0x69; else dev->ide_regs[0x44] = val & 0x7d; @@ -764,7 +816,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) case 0x45: if (dev->local <= VIA_PIPC_586B) dev->ide_regs[0x45] = val & 0x40; - else if (dev->local <= VIA_PIPC_596B) + else if ((dev->local <= VIA_PIPC_596B) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[0x45] = val & 0x4f; else if (dev->local <= VIA_PIPC_686A) dev->ide_regs[0x45] = val & 0x5f; @@ -773,7 +825,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) break; case 0x46: - if (dev->local <= VIA_PIPC_686A) + if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[0x46] = val & 0xf3; else dev->ide_regs[0x46] = val & 0xc0; @@ -784,7 +836,7 @@ pipc_write(int func, int addr, uint8_t val, void *priv) dev->ide_regs[addr] = val & 0xc3; else if (dev->local <= VIA_PIPC_596B) dev->ide_regs[addr] = val & ((addr & 1) ? 0xc3 : 0xcb); - else if (dev->local <= VIA_PIPC_686A) + else if ((dev->local <= VIA_PIPC_686A) || (dev->local == VIA_PIPC_8231)) dev->ide_regs[addr] = val & ((addr & 1) ? 0xc7 : 0xcf); else dev->ide_regs[addr] = val & 0xd7; @@ -803,13 +855,16 @@ pipc_write(int func, int addr, uint8_t val, void *priv) if ((addr < 4) || (addr == 5) || (addr == 6) || ((addr >= 8) && (addr < 0xd)) || ((addr >= 0xe) && (addr < 0x20)) || ((addr >= 0x22) && (addr < 0x3c)) || ((addr >= 0x3e) && (addr < 0x40)) || ((addr >= 0x42) && (addr < 0x44)) || - ((addr >= 0x46) && (addr < 0xc0)) || (addr >= 0xc2)) + ((addr >= 0x46) && (addr < 0x84)) || ((addr >= 0x85) && (addr < 0xc0)) || (addr >= 0xc2)) return; /* Check disable bits for both controllers */ if ((func == 2) ? (dev->pci_isa_regs[0x48] & 0x04) : (dev->pci_isa_regs[0x85] & 0x10)) return; + if ((dev->local <= VIA_PIPC_596B) && (addr == 0x84)) + return; + switch (addr) { case 0x04: dev->usb_regs[func - 2][0x04] = val & 0x97; @@ -872,6 +927,13 @@ pipc_write(int func, int addr, uint8_t val, void *priv) acpi_set_irq_line(dev->acpi, dev->power_regs[addr]); break; + case 0x54: + if (dev->local <= VIA_PIPC_596B) + dev->power_regs[addr] = val; /* write-only on 686A+ */ + else + smbus_piix4_setclock(dev->smbus, (val & 0x80) ? 65536 : 16384); /* final clock undocumented on 686A, assume RTC*2 like 686B */ + break; + case 0x61: case 0x62: case 0x63: dev->power_regs[(addr - 0x58)] = val; break; @@ -883,12 +945,17 @@ pipc_write(int func, int addr, uint8_t val, void *priv) vt82c686_hwm_write(addr, val, subdev); break; - case 0x80: case 0x81: case 0x84: /* 596(A) has the SMBus I/O base here instead. Enable bit is assumed. */ + case 0x80: case 0x81: case 0x84: /* 596A has the SMBus I/O base and enable bit here instead. */ dev->power_regs[addr] = val; smbus_piix4_remap(dev->smbus, (dev->power_regs[0x81] << 8) | (dev->power_regs[0x80] & 0xf0), dev->power_regs[0x84] & 0x01); break; - case 0x90: case 0x91: case 0xd2: + case 0xd2: + if (dev->local == VIA_PIPC_686B) + smbus_piix4_setclock(dev->smbus, (val & 0x04) ? 65536 : 16384); + /* fall-through */ + + case 0x90: case 0x91: dev->power_regs[addr] = val; smbus_piix4_remap(dev->smbus, (dev->power_regs[0x91] << 8) | (dev->power_regs[0x90] & 0xf0), dev->power_regs[0xd2] & 0x01); break; @@ -974,7 +1041,7 @@ pipc_init(const device_t *info) dev->nvr = device_add(&via_nvr_device); - if (dev->local >= VIA_PIPC_686B) + if (dev->local == VIA_PIPC_686B) dev->smbus = device_add(&via_smbus_device); else if (dev->local >= VIA_PIPC_596A) dev->smbus = device_add(&piix4_smbus_device); @@ -1030,8 +1097,8 @@ const device_t via_vt82c586b_device = "VIA VT82C586B", DEVICE_PCI, VIA_PIPC_586B, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1039,13 +1106,13 @@ const device_t via_vt82c586b_device = NULL }; -const device_t via_vt82c596_device = +const device_t via_vt82c596a_device = { - "VIA VT82C596(A)", + "VIA VT82C596A", DEVICE_PCI, VIA_PIPC_596A, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1059,8 +1126,8 @@ const device_t via_vt82c596b_device = "VIA VT82C596B", DEVICE_PCI, VIA_PIPC_596B, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1074,8 +1141,8 @@ const device_t via_vt82c686a_device = "VIA VT82C686A", DEVICE_PCI, VIA_PIPC_686A, - pipc_init, - pipc_close, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, @@ -1089,8 +1156,23 @@ const device_t via_vt82c686b_device = "VIA VT82C686B", DEVICE_PCI, VIA_PIPC_686B, - pipc_init, - pipc_close, + pipc_init, + pipc_close, + pipc_reset, + { NULL }, + NULL, + NULL, + NULL +}; + + +const device_t via_vt8231_device = +{ + "VIA VT8231", + DEVICE_PCI, + VIA_PIPC_8231, + pipc_init, + pipc_close, pipc_reset, { NULL }, NULL, diff --git a/src/device/smbus_piix4.c b/src/device/smbus_piix4.c index f3b14eda0..91ee5566e 100644 --- a/src/device/smbus_piix4.c +++ b/src/device/smbus_piix4.c @@ -313,8 +313,8 @@ unknown_protocol: if (dev->next_stat) { /* schedule dispatch of any pending status register update */ dev->stat = 0x01; /* raise HOST_BUSY while waiting */ timer_disable(&dev->response_timer); - /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * 60us period measured on real VIA 686B */ - timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * 60 * TIMER_USEC); + /* delay = ((half clock for start + half clock for stop) + (bytes * (8 bits + ack))) * bit period in usecs */ + timer_set_delay_u64(&dev->response_timer, (1 + (timer_bytes * 9)) * dev->bit_period * TIMER_USEC); } } @@ -343,6 +343,16 @@ smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable) } +void +smbus_piix4_setclock(smbus_piix4_t *dev, int clock) +{ + dev->clock = clock; + + /* Set the bit period in usecs. */ + dev->bit_period = 1000000.0 / dev->clock; +} + + static void * smbus_piix4_init(const device_t *info) { @@ -356,6 +366,8 @@ smbus_piix4_init(const device_t *info) timer_add(&dev->response_timer, smbus_piix4_response, dev, 0); + smbus_piix4_setclock(dev, 16384); /* default to 16.384 KHz */ + return dev; } diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 2cc8078b1..6e9b04d24 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -144,10 +144,11 @@ extern const device_t via_apro133_device; extern const device_t via_apro133a_device; extern const device_t via_vt8601_device; extern const device_t via_vt82c586b_device; -extern const device_t via_vt82c596_device; +extern const device_t via_vt82c596a_device; extern const device_t via_vt82c596b_device; extern const device_t via_vt82c686a_device; extern const device_t via_vt82c686b_device; +extern const device_t via_vt8231_device; /* VLSI */ extern const device_t vl82c480_device; diff --git a/src/include/86box/smbus_piix4.h b/src/include/86box/smbus_piix4.h index 3173ead4e..cf55dd210 100644 --- a/src/include/86box/smbus_piix4.h +++ b/src/include/86box/smbus_piix4.h @@ -30,6 +30,8 @@ enum { typedef struct { uint32_t local; uint16_t io_base; + int clock; + double bit_period; uint8_t stat, next_stat, ctl, cmd, addr, data0, data1, index, data[SMBUS_PIIX4_BLOCK_DATA_SIZE]; @@ -39,6 +41,7 @@ typedef struct { extern void smbus_piix4_remap(smbus_piix4_t *dev, uint16_t new_io_base, uint8_t enable); +extern void smbus_piix4_setclock(smbus_piix4_t *dev, int clock); #ifdef EMU_DEVICE_H diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index 1ab48f7b4..a14d75cd7 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -540,7 +540,7 @@ machine_at_ficka6130_init(const machine_t *model) pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); pci_register_slot(0x01, PCI_CARD_AGPBRIDGE, 1, 2, 3, 4); device_add(&via_apro_device); - device_add(&via_vt82c596_device); + device_add(&via_vt82c596a_device); device_add(&w83877tf_device); device_add(&keyboard_ps2_ami_pci_device); device_add(&sst_flash_29ee020_device); From f88650eea5e82806e0b9f2b736fb51ac1e3b2ad3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 8 Jul 2021 21:49:08 -0300 Subject: [PATCH 2/3] Add Savage Quest protection dongle emulation from MAME --- src/device/CMakeLists.txt | 2 +- src/device/hasp.c | 310 ++++++++++++++++++++++++++++++++++++++ src/include/86box/lpt.h | 2 + src/lpt.c | 5 +- src/win/Makefile.mingw | 5 +- 5 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 src/device/hasp.c diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt index f09051ac9..ae8cd867d 100644 --- a/src/device/CMakeLists.txt +++ b/src/device/CMakeLists.txt @@ -13,7 +13,7 @@ # Copyright 2020,2021 David Hrdlička. # -add_library(dev OBJECT bugger.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c +add_library(dev OBJECT bugger.c hasp.c hwm.c hwm_lm75.c hwm_lm78.c hwm_gl518sm.c hwm_vt82c686.c ibm_5161.c isamem.c isartc.c ../lpt.c pci_bridge.c postcard.c serial.c vpc2007.c clock_ics9xxx.c isapnp.c i2c.c i2c_gpio.c smbus_piix4.c keyboard.c keyboard_xt.c keyboard_at.c mouse.c mouse_bus.c diff --git a/src/device/hasp.c b/src/device/hasp.c new file mode 100644 index 000000000..2c6aca190 --- /dev/null +++ b/src/device/hasp.c @@ -0,0 +1,310 @@ +/* + * 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. + * + * HASP parallel port copy protection dongle emulation. + * + * Based on the MAME driver for Savage Quest. This incomplete + * emulation is enough to satisfy that game, but not Aladdin's + * DiagnostiX utility. + * + * + * + * Author: RichardG, + * Peter Ferrie + * + * Copyright 2021 RichardG. + * Copyright Peter Ferrie. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/lpt.h> +#include <86box/device.h> + +#define HASP_BYTEARRAY(...) {__VA_ARGS__} +#define HASP_TYPE(type, password_arr, prodinfo_arr) [type] = { \ + .password = (const uint8_t[]) password_arr, \ + .prodinfo = (const uint8_t[]) prodinfo_arr, \ + .password_size = sizeof((uint8_t[]) password_arr), \ + .prodinfo_size = sizeof((uint8_t[]) prodinfo_arr) \ + }, + + +enum { + HASP_STATE_NONE = 0, + HASP_STATE_PASSWORD_BEGIN, + HASP_STATE_PASSWORD_END, + HASP_STATE_READ +}; + +enum { + HASP_TYPE_SAVQUEST = 0 +}; + +typedef struct { + const uint8_t *password, *prodinfo; + const uint8_t password_size, prodinfo_size; +} hasp_type_t; + +typedef struct +{ + void *lpt; + const hasp_type_t *type; + + int index, state, passindex, passmode, prodindex; + uint8_t tmppass[0x29], status; +} hasp_t; + +static const hasp_type_t hasp_types[] = { + HASP_TYPE(HASP_TYPE_SAVQUEST, + HASP_BYTEARRAY(0xc3, 0xd9, 0xd3, 0xfb, 0x9d, 0x89, 0xb9, 0xa1, 0xb3, 0xc1, 0xf1, 0xcd, 0xdf, 0x9d), + HASP_BYTEARRAY(0x51, 0x4c, 0x52, 0x4d, 0x53, 0x4e, 0x53, 0x4e, 0x53, 0x49, 0x53, 0x48, 0x53, 0x4b, 0x53, 0x4a, + 0x53, 0x43, 0x53, 0x45, 0x52, 0x46, 0x53, 0x43, 0x53, 0x41, 0xac, 0x40, 0x53, 0xbc, 0x53, 0x42, + 0x53, 0x57, 0x53, 0x5d, 0x52, 0x5e, 0x53, 0x5b, 0x53, 0x59, 0xac, 0x58, 0x53, 0xa4)) +}; + + +#ifdef ENABLE_HASP_LOG +int hasp_do_log = ENABLE_HASP_LOG; + +static void +hasp_log(const char *fmt, ...) +{ + va_list ap; + + if (hasp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define hasp_log(fmt, ...) +#endif + + +static void +hasp_write_data(uint8_t val, void *priv) +{ + hasp_t *dev = (hasp_t *) priv; + + hasp_log("HASP: write_data(%02X)\n", val); + + switch (dev->index) { + case 0: + if (val == 0xc6) + dev->index++; + else + dev->index = 0; + break; + + case 1: + if (val == 0xc7) + dev->index++; + else + dev->index = 0; + break; + + case 2: + if (val == 0xc6) { + dev->index++; + } else { + dev->index = 0; + dev->state = HASP_STATE_NONE; + } + break; + + case 3: + dev->index = 0; + if (val == 0x80) { + dev->state = HASP_STATE_PASSWORD_BEGIN; + dev->passindex = 0; + return; + } + break; + } + + dev->status = 0; + + if (dev->state == HASP_STATE_READ) { + /* different passwords cause different values to be returned + but there are really only two passwords of interest + passmode 2 is used to verify that the dongle is responding correctly */ + if (dev->passmode == 2) { + switch (val) { + case 0x94: case 0x9e: case 0xa4: + case 0xb2: case 0xbe: case 0xd0: + return; + + case 0x8a: case 0x8e: case 0xca: case 0xd2: + case 0xe2: case 0xf0: case 0xfc: + /* someone with access to the actual dongle could dump the true values + I've never seen it so I just determined the relevant bits instead + from the disassembly of the software + some of the keys are verified explicitly, the others implicitly + I guessed the implicit ones with a bit of trial and error */ + dev->status = 0x20; + return; + } + } + + switch (val) { + /* in passmode 0, some values remain unknown: 8a, 8e (inconclusive), 94, 96, 9a, a4, b2, be, c4, d2, d4 (inconclusive), e2, ec, f8, fc + this is less of a concern since the contents seem to decrypt correctly */ + case 0x88: + case 0x94: case 0x98: case 0x9c: case 0x9e: + case 0xa0: case 0xa4: case 0xaa: case 0xae: + case 0xb0: case 0xb2: case 0xbc: case 0xbe: + case 0xc2: case 0xc6: case 0xc8: case 0xce: + case 0xd0: case 0xd6: case 0xd8: case 0xdc: + case 0xe0: case 0xe6: case 0xea: case 0xee: + case 0xf2: case 0xf6: + /* again, just the relevant bits instead of the true values */ + dev->status = 0x20; + break; + } + } else if (dev->state == HASP_STATE_PASSWORD_END) { + if (val & 1) { + if ((dev->passmode == 1) && (val == 0x9d)) + dev->passmode = 2; + dev->state = HASP_STATE_READ; + } else if (dev->passmode == 1) { + dev->tmppass[dev->passindex++] = val; + + if (dev->passindex == sizeof(dev->tmppass)) { + if ((dev->tmppass[0] == 0x9c) && (dev->tmppass[1] == 0x9e)) { + int i = 2; + dev->prodindex = 0; + + do { + dev->prodindex = (dev->prodindex << 1) + ((dev->tmppass[i] >> 6) & 1); + } while ((i += 3) < sizeof(dev->tmppass)); + + dev->prodindex = (dev->prodindex - 0xc08) << 4; + + hasp_log("HASP: Password prodindex = %d\n", dev->prodindex); + + if (dev->prodindex < (0x38 << 4)) + dev->passmode = 3; + } + + dev->state = HASP_STATE_READ; + } + } + } else if ((dev->state == HASP_STATE_PASSWORD_BEGIN) && (val & 1)) { + dev->tmppass[dev->passindex++] = val; + + if (dev->passindex == dev->type->password_size) { + dev->state = HASP_STATE_PASSWORD_END; + dev->passindex = 0; + dev->passmode = (int) !memcmp(dev->tmppass, dev->type->password, dev->type->password_size); + hasp_log("HASP: Password comparison result = %d\n", dev->passmode); + } + } +} + + +static uint8_t +hasp_read_status(void *priv) +{ + hasp_t *dev = (hasp_t *) priv; + + if ((dev->state == HASP_STATE_READ) && (dev->passmode == 3)) { + /* passmode 3 is used to retrieve the product(s) information + it comes in two parts: header and product + the header has this format: + offset range purpose + 00 01 header type + 01 01-05 count of used product slots, must be 2 + 02 01-05 count of unused product slots + this is assumed to be 6-(count of used slots) + but it is not enforced here + however a total of 6 structures will be checked + 03 01-02 unknown + 04 01-46 country code + 05-0f 00 reserved + the used product slots have this format: + (the unused product slots must be entirely zeroes) + 00-01 0001-000a product ID, one must be 6, the other 0a + 02 0001-0003 unknown but must be 0001 + 04 01-05 HASP plug country ID + 05 01-02 unknown but must be 01 + 06 05 unknown + 07-0a any unknown, not used + 0b ff unknown + 0c ff unknown + 0d-0f 00 reserved + the read is performed by accessing an array of 16-bit big-endian values + and returning one bit at a time into bit 5 of the result + the 16-bit value is then XORed with 0x534d and the register index */ + + if (dev->prodindex <= (dev->type->prodinfo_size * 8)) + dev->status = ((dev->type->prodinfo[(dev->prodindex - 1) >> 3] >> ((8 - dev->prodindex) & 7)) & 1) << 5; /* return defined info */ + else + dev->status = (((0x534d ^ ((dev->prodindex - 1) >> 4)) >> ((16 - dev->prodindex) & 15)) & 1) << 5; /* then just alternate between the two key values */ + + hasp_log("HASP: Reading %02X from prodindex %d\n", dev->status, dev->prodindex); + + dev->prodindex++; + } + + hasp_log("HASP: read_status() = %02X\n", dev->status); + + return dev->status; +} + + +static void * +hasp_init(void *lpt, int type) +{ + hasp_t *dev = (hasp_t *) malloc(sizeof(hasp_t)); + memset(dev, 0, sizeof(hasp_t)); + + hasp_log("HASP: init(%d)\n", type); + + dev->lpt = lpt; + dev->type = &hasp_types[type]; + + dev->status = 0x80; + + return dev; +} + + +static void * +hasp_init_savquest(void *lpt) +{ + return hasp_init(lpt, HASP_TYPE_SAVQUEST); +} + + +static void +hasp_close(void *priv) +{ + hasp_t *dev = (hasp_t *) priv; + + hasp_log("HASP: close()\n"); + + free(dev); +} + + +const lpt_device_t lpt_hasp_savquest_device = { + .name = "Protection Dongle for Savage Quest", + .init = hasp_init_savquest, + .close = hasp_close, + .write_data = hasp_write_data, + .write_ctrl = NULL, + .read_data = NULL, + .read_status = hasp_read_status, + .read_ctrl = NULL +}; diff --git a/src/include/86box/lpt.h b/src/include/86box/lpt.h index 3a2ac2959..7fecd4ce7 100644 --- a/src/include/86box/lpt.h +++ b/src/include/86box/lpt.h @@ -62,4 +62,6 @@ extern const lpt_device_t lpt_dac_stereo_device; extern const lpt_device_t dss_device; +extern const lpt_device_t lpt_hasp_savquest_device; + #endif /*EMU_LPT_H*/ diff --git a/src/lpt.c b/src/lpt.c index 6332417d3..31088f984 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -28,10 +28,11 @@ static const struct {"Disney Sound Source", "dss", &dss_device}, {"LPT DAC / Covox Speech Thing", "lpt_dac", &lpt_dac_device}, {"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device}, - {"Generic Text Printer", "text_prt", &lpt_prt_text_device}, + {"Generic Text Printer", "text_prt", &lpt_prt_text_device}, {"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device}, {"Generic PostScript Printer", "postscript", &lpt_prt_ps_device}, - {"PLIP Network", "plip", &lpt_plip_device}, + {"PLIP Network", "plip", &lpt_plip_device}, + {"Protection Dongle for Savage Quest","dongle_savquest",&lpt_hasp_savquest_device}, {"", "", NULL} }; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 33686f07e..3fa401f1e 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -636,8 +636,9 @@ MCHOBJ := machine.o machine_table.o \ m_at_socket8.o m_at_slot1.o m_at_slot2.o m_at_socket370.o \ m_at_misc.o -DEVOBJ := bugger.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o ibm_5161.o isamem.o isartc.o \ - lpt.o pci_bridge.o postcard.o serial.o vpc2007.o clock_ics9xxx.o isapnp.o \ +DEVOBJ := bugger.o hasp.o hwm.o hwm_lm75.o hwm_lm78.o hwm_gl518sm.o hwm_vt82c686.o \ + ibm_5161.o isamem.o isartc.o lpt.o pci_bridge.o postcard.o serial.o \ + vpc2007.o clock_ics9xxx.o isapnp.o \ i2c.o i2c_gpio.o smbus_piix4.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ From c39587cfab8a78a71b41610efa59e9a53b1c704e Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Thu, 8 Jul 2021 22:55:56 -0300 Subject: [PATCH 3/3] Remove device names from LPT table --- src/lpt.c | 38 ++++++++++++++++++-------------------- src/network/net_plip.c | 13 ++++++------- src/printer/prt_escp.c | 2 +- src/printer/prt_ps.c | 2 +- src/printer/prt_text.c | 2 +- 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/lpt.c b/src/lpt.c index 31088f984..d528c2911 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -17,33 +17,31 @@ lpt_port_t lpt_ports[3]; -static const struct -{ - const char *name; - const char *internal_name; - const lpt_device_t *device; -} lpt_devices[] = -{ - {"None", "none", NULL}, - {"Disney Sound Source", "dss", &dss_device}, - {"LPT DAC / Covox Speech Thing", "lpt_dac", &lpt_dac_device}, - {"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device}, - {"Generic Text Printer", "text_prt", &lpt_prt_text_device}, - {"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device}, - {"Generic PostScript Printer", "postscript", &lpt_prt_ps_device}, - {"PLIP Network", "plip", &lpt_plip_device}, - {"Protection Dongle for Savage Quest","dongle_savquest",&lpt_hasp_savquest_device}, - {"", "", NULL} +static const struct { + const char *internal_name; + const lpt_device_t *device; +} lpt_devices[] = { + {"none", NULL}, + {"dss", &dss_device}, + {"lpt_dac", &lpt_dac_device}, + {"lpt_dac_stereo", &lpt_dac_stereo_device}, + {"text_prt", &lpt_prt_text_device}, + {"dot_matrix", &lpt_prt_escp_device}, + {"postscript", &lpt_prt_ps_device}, + {"plip", &lpt_plip_device}, + {"dongle_savquest", &lpt_hasp_savquest_device}, + {"", NULL} }; char * lpt_device_get_name(int id) { - if (strlen((char *) lpt_devices[id].name) == 0) + if (strlen((char *) lpt_devices[id].internal_name) == 0) return NULL; - - return (char *) lpt_devices[id].name; + if (!lpt_devices[id].device) + return "None"; + return (char *) lpt_devices[id].device->name; } diff --git a/src/network/net_plip.c b/src/network/net_plip.c index 25610ef78..c71cf77d1 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -492,7 +492,7 @@ plip_close(void *priv) const lpt_device_t lpt_plip_device = { - .name = "Parallel Line Internet Protocol (LPT)", + .name = "Parallel Line Internet Protocol", .init = plip_lpt_init, .close = plip_close, .write_data = plip_write_data, @@ -502,10 +502,9 @@ const lpt_device_t lpt_plip_device = { .read_ctrl = NULL }; -const device_t plip_device = -{ - "Parallel Line Internet Protocol", - DEVICE_LPT, 0, - plip_net_init, NULL, - NULL, { NULL }, NULL, NULL +const device_t plip_device = { + "Parallel Line Internet Protocol", + DEVICE_LPT, 0, + plip_net_init, NULL, + NULL, { NULL }, NULL, NULL }; diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 029d2d492..8e490e9e1 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -2143,7 +2143,7 @@ escp_close(void *priv) const lpt_device_t lpt_prt_escp_device = { - "EPSON ESC/P compatible printer", + "Generic ESC/P Dot-Matrix", escp_init, escp_close, write_data, diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index f66d17f80..de30a962c 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -389,7 +389,7 @@ ps_close(void *p) const lpt_device_t lpt_prt_ps_device = { - .name = "Generic PostScript printer", + .name = "Generic PostScript Printer", .init = ps_init, .close = ps_close, .write_data = ps_write_data, diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index e11d4f734..b0f0b5daa 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -483,7 +483,7 @@ prnt_close(void *priv) const lpt_device_t lpt_prt_text_device = { - "Generic TEXT printer", + "Generic Text Printer", prnt_init, prnt_close, write_data,