Merge pull request #1538 from richardg867/feature/savquest
Savage Quest LPT dongle + some fixes
This commit is contained in:
@@ -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 <stdarg.h>
|
||||
@@ -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,
|
||||
|
@@ -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
|
||||
|
310
src/device/hasp.c
Normal file
310
src/device/hasp.c
Normal file
@@ -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, <richardg867@gmail.com>
|
||||
* Peter Ferrie
|
||||
*
|
||||
* Copyright 2021 RichardG.
|
||||
* Copyright Peter Ferrie.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#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
|
||||
};
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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*/
|
||||
|
@@ -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
|
||||
|
37
src/lpt.c
37
src/lpt.c
@@ -17,32 +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},
|
||||
{"", "", 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;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
};
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
@@ -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 \
|
||||
|
Reference in New Issue
Block a user