diff --git a/src/acpi.c b/src/acpi.c index a7301304c..da7c48796 100644 --- a/src/acpi.c +++ b/src/acpi.c @@ -63,13 +63,10 @@ acpi_log(const char *fmt, ...) #endif -static void -acpi_update_irq(void *priv) +void +acpi_update_irq(acpi_t *dev) { - acpi_t *dev = (acpi_t *) priv; - int sci_level; - - sci_level = (dev->regs.pmsts & dev->regs.pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN); + int sci_level = (dev->regs.pmsts & dev->regs.pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN); if (dev->vendor == VEN_SMC) sci_level |= (dev->regs.pmsts & BM_STS); @@ -87,11 +84,9 @@ acpi_update_irq(void *priv) } -static void -acpi_raise_smi(void *priv) +void +acpi_raise_smi(acpi_t *dev) { - acpi_t *dev = (acpi_t *) priv; - if (dev->regs.glbctl & 0x01) { if ((dev->vendor == VEN_VIA) || (dev->vendor == VEN_VIA_596B)) { if ((!dev->regs.smi_lock || !dev->regs.smi_active)) { @@ -530,10 +525,11 @@ acpi_reg_read_via_596b(int size, uint16_t addr, void *p) shift32 = (addr & 3) << 3; switch (addr) { - case 0x42: - /* GPIO port Output Value */ - if (size == 1) - ret = dev->regs.gpio_val & 0x13; + case 0x40: /* Extended I/O Trap Status (686A/B) */ + ret = dev->regs.extiotrapsts; + break; + case 0x42: /* Extended I/O Trap Enable (686A/B) */ + ret = dev->regs.extiotrapen; break; case 0x44: case 0x45: /* External SMI Input Value */ @@ -817,6 +813,8 @@ acpi_reg_write_intel(int size, uint16_t addr, uint8_t val, void *p) case 0x2c: case 0x2d: case 0x2e: case 0x2f: /* DEVCTL - Device Control Register (IO) */ dev->regs.devctl = ((dev->regs.devctl & ~(0xff << shift32)) | (val << shift32)) & 0x0fffffff; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); break; case 0x34: case 0x35: case 0x36: case 0x37: /* GPOREG - General Purpose Output Register (IO) */ @@ -957,14 +955,6 @@ acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) /* Power Supply Control */ dev->regs.pscntrl = ((dev->regs.pscntrl & ~(0xff << shift16)) | (val << shift16)) & 0x0701; break; - case 0x28: case 0x29: - /* GLBSTS - Global Status Register (IO) */ - dev->regs.glbsts &= ~((val << shift16) & 0x007f); - break; - case 0x2a: case 0x2b: - /* GLBEN - Global Enable Register (IO) */ - dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0x007f; - break; case 0x2c: /* GLBCTL - Global Control Register (IO) */ dev->regs.glbctl = (dev->regs.glbctl & ~0xff) | (val & 0xff); @@ -991,14 +981,6 @@ acpi_reg_write_via_common(int size, uint16_t addr, uint8_t val, void *p) acpi_raise_smi(dev); } break; - case 0x30: case 0x31: case 0x32: case 0x33: - /* Primary Activity Detect Status */ - dev->regs.padsts &= ~((val << shift32) & 0x000000fd); - break; - case 0x34: case 0x35: case 0x36: case 0x37: - /* Primary Activity Detect Enable */ - dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000000fd; - break; case 0x38: case 0x39: case 0x3a: case 0x3b: /* GP Timer Reload Enable */ dev->regs.gptren = ((dev->regs.gptren & ~(0xff << shift32)) | (val << shift32)) & 0x000000d9; @@ -1030,13 +1012,32 @@ static void acpi_reg_write_via(int size, uint16_t addr, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; - int shift16; + int shift16, shift32; addr &= 0xff; acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); shift16 = (addr & 1) << 3; + shift32 = (addr & 3) << 3; switch (addr) { + case 0x28: case 0x29: + /* GLBSTS - Global Status Register (IO) */ + dev->regs.glbsts &= ~((val << shift16) & 0x007f); + break; + case 0x2a: case 0x2b: + /* GLBEN - Global Enable Register (IO) */ + dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0x007f; + break; + case 0x30: case 0x31: case 0x32: case 0x33: + /* Primary Activity Detect Status */ + dev->regs.padsts &= ~((val << shift32) & 0x000000fd); + break; + case 0x34: case 0x35: case 0x36: case 0x37: + /* Primary Activity Detect Enable */ + dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000000fd; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); + break; case 0x40: /* GPIO Direction Control */ if (size == 1) { @@ -1066,17 +1067,37 @@ static void acpi_reg_write_via_596b(int size, uint16_t addr, uint8_t val, void *p) { acpi_t *dev = (acpi_t *) p; - int shift32; + int shift16, shift32; addr &= 0x7f; acpi_log("(%i) ACPI Write (%i) %02X: %02X\n", in_smm, size, addr, val); + shift16 = (addr & 1) << 3; shift32 = (addr & 3) << 3; switch (addr) { - case 0x42: - /* GPIO port Output Value */ - if (size == 1) - dev->regs.gpio_val = val & 0x13; + case 0x28: case 0x29: + /* GLBSTS - Global Status Register (IO) */ + dev->regs.glbsts &= ~((val << shift16) & 0xfdff); + break; + case 0x2a: case 0x2b: + /* GLBEN - Global Enable Register (IO) */ + dev->regs.glben = ((dev->regs.glben & ~(0xff << shift16)) | (val << shift16)) & 0xfdff; + break; + case 0x30: case 0x31: case 0x32: case 0x33: + /* Primary Activity Detect Status */ + dev->regs.padsts &= ~((val << shift32) & 0x000007ff); + break; + case 0x34: case 0x35: case 0x36: case 0x37: + /* Primary Activity Detect Enable */ + dev->regs.paden = ((dev->regs.paden & ~(0xff << shift32)) | (val << shift32)) & 0x000007ff; + if (dev->trap_update) + dev->trap_update(dev->trap_priv); + break; + case 0x40: /* Extended I/O Trap Status (686A/B) */ + dev->regs.extiotrapsts &= ~(val & 0x13); + break; + case 0x42: /* Extended I/O Trap Enable (686A/B) */ + dev->regs.extiotrapen = val & 0x13; break; case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* GPO Port Output Value */ @@ -1534,6 +1555,14 @@ acpi_set_nvr(acpi_t *dev, nvr_t *nvr) } +void +acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv) +{ + dev->trap_update = update; + dev->trap_priv = priv; +} + + static void acpi_apm_out(uint16_t port, uint8_t val, void *p) { @@ -1771,7 +1800,7 @@ const device_t acpi_via_device = const device_t acpi_via_596b_device = { - "VIA ACPI (VT82C596B)", + "VIA VT82C596 ACPI", DEVICE_PCI, VEN_VIA_596B, acpi_init, diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index a865e045a..d36109ffd 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -49,8 +49,14 @@ #include <86box/chipset.h> -typedef struct -{ +typedef struct { + struct _piix_ *dev; + void *trap; + uint8_t dev_id; + uint32_t *sts_reg, *en_reg, sts_mask, en_mask; +} piix_io_trap_t; + +typedef struct _piix_ { uint8_t cur_readout_reg, rev, type, func_shift, max_func, pci_slot, @@ -66,6 +72,7 @@ typedef struct ddma_t * ddma; usb_t * usb; acpi_t * acpi; + piix_io_trap_t io_traps[26]; port_92_t * port_92; pc_timer_t fast_off_timer; } piix_t; @@ -265,6 +272,148 @@ nvr_update_io_mapping(piix_t *dev) } +static void +piix_trap_io(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + piix_io_trap_t *trap = (piix_io_trap_t *) priv; + + if (*(trap->en_reg) & trap->en_mask) { + *(trap->sts_reg) |= trap->sts_mask; + acpi_raise_smi(trap->dev->acpi); + } +} + + +static void +piix_trap_update_devctl(piix_t *dev, uint8_t trap_id, uint8_t dev_id, + uint32_t devctl_mask, uint8_t enable, + uint16_t addr, uint16_t size) +{ + piix_io_trap_t *trap = &dev->io_traps[trap_id]; + enable = (dev->acpi->regs.devctl & devctl_mask) && enable; + + /* Set up Device I/O traps dynamically. */ + if (enable && !trap->trap) { + trap->dev = dev; + trap->trap = io_trap_add(piix_trap_io, trap); + trap->dev_id = dev_id; + trap->sts_reg = &dev->acpi->regs.devsts; + trap->sts_mask = 0x00010000 << dev_id; + trap->en_reg = &dev->acpi->regs.devctl; + trap->en_mask = devctl_mask; + } + +//#ifdef ENABLE_PIIX_LOG + if ((dev_id == 9) || (dev_id == 10) || (dev_id == 12) || (dev_id == 13)) + pclog("PIIX: Mapping trap device %d to %04X-%04X (enable %d)\n", dev_id, addr, addr + size - 1, enable); +//#endif + + /* Remap I/O trap. */ + io_trap_remap(trap->trap, enable, addr, size); +} + + +static void +piix_trap_update(void *priv) +{ + piix_t *dev = (piix_t *) priv; + uint8_t trap_id = 0, *fregs = dev->regs[3]; + uint16_t temp; + + piix_trap_update_devctl(dev, trap_id++, 0, 0x00000002, 1, 0x1f0, 8); + piix_trap_update_devctl(dev, trap_id++, 0, 0x00000002, 1, 0x3f6, 1); + + piix_trap_update_devctl(dev, trap_id++, 1, 0x00000008, 1, 0x1f0, 8); + piix_trap_update_devctl(dev, trap_id++, 1, 0x00000008, 1, 0x3f6, 1); + + piix_trap_update_devctl(dev, trap_id++, 2, 0x00000020, 1, 0x170, 8); + piix_trap_update_devctl(dev, trap_id++, 2, 0x00000020, 1, 0x376, 1); + + piix_trap_update_devctl(dev, trap_id++, 3, 0x00000080, 1, 0x170, 8); + piix_trap_update_devctl(dev, trap_id++, 3, 0x00000080, 1, 0x376, 1); + + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x08, 0x220 + (0x20 * ((fregs[0x5c] >> 5) & 0x03)), 20); + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x10, 0x200, 8); + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x08, 0x388, 4); + switch (fregs[0x5d] & 0x03) { + case 0x00: temp = 0x530; break; + case 0x01: temp = 0x604; break; + case 0x02: temp = 0xe80; break; + default: temp = 0xf40; break; + } + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x80, temp, 8); + piix_trap_update_devctl(dev, trap_id++, 4, 0x00000200, fregs[0x5c] & 0x01, 0x300 + (0x10 * ((fregs[0x5c] >> 1) & 0x03)), 4); + + piix_trap_update_devctl(dev, trap_id++, 5, 0x00000800, fregs[0x51] & 0x10, 0x370 + (0x80 * !(fregs[0x63] & 0x10)), 6); + piix_trap_update_devctl(dev, trap_id++, 5, 0x00000800, fregs[0x51] & 0x10, 0x377 + (0x80 * !(fregs[0x63] & 0x10)), 1); + + switch (fregs[0x67] & 0x07) { + case 0x00: temp = 0x3f8; break; + case 0x01: temp = 0x2f8; break; + case 0x02: temp = 0x220; break; + case 0x03: temp = 0x228; break; + case 0x04: temp = 0x238; break; + case 0x05: temp = 0x2e8; break; + case 0x06: temp = 0x338; break; + default: temp = 0x3e8; break; + } + piix_trap_update_devctl(dev, trap_id++, 6, 0x00002000, fregs[0x51] & 0x40, temp, 8); + + switch (fregs[0x67] & 0x70) { + case 0x00: temp = 0x3f8; break; + case 0x10: temp = 0x2f8; break; + case 0x20: temp = 0x220; break; + case 0x30: temp = 0x228; break; + case 0x40: temp = 0x238; break; + case 0x50: temp = 0x2e8; break; + case 0x60: temp = 0x338; break; + default: temp = 0x3e8; break; + } + piix_trap_update_devctl(dev, trap_id++, 7, 0x00008000, fregs[0x52] & 0x01, temp, 8); + + switch (fregs[0x63] & 0x06) { + case 0x00: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x3bc, 4); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x7bc, 3); + break; + + case 0x02: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x378, 8); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x778, 3); + break; + + case 0x04: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x278, 8); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0x678, 3); + break; + + default: + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0, 0); + piix_trap_update_devctl(dev, trap_id++, 8, 0x00020000, fregs[0x52] & 0x04, 0, 0); + break; + } + + temp = fregs[0x62] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 9, 0x00080000, fregs[0x62] & 0x20, (fregs[0x60] | (fregs[0x61] << 8)) & ~temp, temp + 1); + + temp = fregs[0x66] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 10, 0x00200000, fregs[0x66] & 0x20, (fregs[0x64] | (fregs[0x65] << 8)) & ~temp, temp + 1); + + piix_trap_update_devctl(dev, trap_id++, 11, 0x00800000, fregs[0x5f] & 0x04, 0x3b0, 48); + piix_trap_update_devctl(dev, trap_id++, 11, 0x00800000, fregs[0x5f] & 0x10, 0x60, 1); + piix_trap_update_devctl(dev, trap_id++, 11, 0x00800000, fregs[0x5f] & 0x10, 0x64, 1); + /* [A0000:BFFFF] memory trap not implemented. */ + + temp = fregs[0x6a] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 12, 0x01000000, fregs[0x6a] & 0x10, (fregs[0x68] | (fregs[0x69] << 8)) & ~temp, temp + 1); + /* Programmable memory trap not implemented. */ + + temp = fregs[0x72] & 0x0f; + piix_trap_update_devctl(dev, trap_id++, 13, 0x02000000, fregs[0x72] & 0x10, (fregs[0x70] | (fregs[0x71] << 8)) & ~temp, temp + 1); + /* Programmable memory trap not implemented. */ +} + + static void piix_write(int func, int addr, uint8_t val, void *priv) { @@ -835,6 +984,10 @@ piix_write(int func, int addr, uint8_t val, void *priv) case 0xd3: case 0xd4: case 0xd5: fregs[addr] = val; + if ((addr == 0x5c) || (addr == 0x60) || (addr == 0x61) || (addr == 0x62) || + (addr == 0x64) || (addr == 0x65) || (addr == 0x68) || (addr == 0x69) || + (addr == 0x70) || (addr == 0x71)) + piix_trap_update(dev); break; case 0x4a: fregs[addr] = val & 0x73; @@ -854,9 +1007,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) break; case 0x51: fregs[addr] = val & 0x58; + piix_trap_update(dev); break; case 0x52: fregs[addr] = val & 0x7f; + piix_trap_update(dev); break; case 0x58: fregs[addr] = val & 0x77; @@ -867,12 +1022,16 @@ piix_write(int func, int addr, uint8_t val, void *priv) break; case 0x63: fregs[addr] = val & 0xf7; + piix_trap_update(dev); break; case 0x66: fregs[addr] = val & 0xef; + piix_trap_update(dev); break; case 0x6a: case 0x72: case 0x7a: case 0x7e: fregs[addr] = val & 0x1f; + if ((addr == 0x6a) || (addr == 0x72)) + piix_trap_update(dev); break; case 0x6d: case 0x75: fregs[addr] = val & 0x80; @@ -1297,6 +1456,7 @@ static void acpi_set_slot(dev->acpi, dev->pci_slot); acpi_set_nvr(dev->acpi, dev->nvr); acpi_set_gpireg2_default(dev->acpi, (dev->type > 4) ? 0xf1 : 0xdd); + acpi_set_trap_update(dev->acpi, piix_trap_update, dev); dev->ddma = device_add(&ddma_device); } else diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 41667edfd..863388e2d 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -67,23 +67,69 @@ #define VIA_PIPC_8231 0x82311000 -typedef struct -{ +enum { + TRAP_DRQ = 0, + TRAP_PIRQ, + TRAP_PIDE_MAIN, + TRAP_PIDE_SIDE, + TRAP_SIDE_MAIN, + TRAP_SIDE_SIDE, + TRAP_FLP_MAIN, + TRAP_FLP_SIDE, + TRAP_COM1, + TRAP_COM3, + TRAP_COM2, + TRAP_COM4, + TRAP_LPT_LPT1, + TRAP_LPT_LPT2, + TRAP_VGA, + TRAP_KBC, + TRAP_AUD_MIDI_0, + TRAP_AUD_MIDI_1, + TRAP_AUD_MIDI_2, + TRAP_AUD_MIDI_3, + TRAP_AUD_SB_0, + TRAP_AUD_SB_1, + TRAP_AUD_SB_2, + TRAP_AUD_SB_3, + TRAP_AUD_GAME, + TRAP_AUD_WSS_0, + TRAP_AUD_WSS_1, + TRAP_AUD_WSS_2, + TRAP_AUD_WSS_3, + TRAP_GR0, + TRAP_GR1, + TRAP_GR2, + TRAP_GR3, + TRAP_MAX +}; + +typedef struct { + struct _pipc_ *dev; + void *trap; + uint32_t *sts_reg, *en_reg, mask; +} pipc_io_trap_t; + +typedef struct _pipc_ { uint32_t local; - uint8_t max_func; + uint8_t max_func, max_pcs; uint8_t pci_isa_regs[256], ide_regs[256], usb_regs[2][256], power_regs[256], ac97_regs[2][256], fmnmi_regs[4]; + sff8038i_t *bm[2]; nvr_t *nvr; int nvr_enabled, slot; ddma_t *ddma; smbus_piix4_t *smbus; usb_t *usb[2]; + acpi_t *acpi; + pipc_io_trap_t io_traps[TRAP_MAX]; + void *gameport, *ac97; sb_t *sb; uint16_t midigame_base, sb_base, fmnmi_base; @@ -117,6 +163,32 @@ static uint8_t pipc_read(int func, int addr, void *priv); static void pipc_write(int func, int addr, uint8_t val, void *priv); +static void +pipc_trap_io_pact(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + pipc_io_trap_t *trap = (pipc_io_trap_t *) priv; + + if (*(trap->en_reg) & trap->mask) { + *(trap->sts_reg) |= trap->mask; + trap->dev->acpi->regs.glbsts |= 0x0001; + if (trap->dev->acpi->regs.glben & 0x0001) + acpi_raise_smi(trap->dev->acpi); + } +} + + +static void +pipc_io_trap_glb(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv) +{ + pipc_io_trap_t *trap = (pipc_io_trap_t *) priv; + + if (*(trap->en_reg) & trap->mask) { + *(trap->sts_reg) |= trap->mask; + acpi_raise_smi(trap->dev->acpi); + } +} + + static void pipc_reset_hard(void *priv) { @@ -136,7 +208,7 @@ pipc_reset_hard(void *priv) memset(dev->power_regs, 0, 256); memset(dev->ac97_regs, 0, 512); - /* PCI-ISA bridge registers */ + /* 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; @@ -164,7 +236,9 @@ pipc_reset_hard(void *priv) pic_set_shadow(0); - /* IDE registers */ + dev->max_pcs = (dev->local >= VIA_PIPC_686A) ? 3 : 1; + + /* IDE registers. */ dev->max_func++; dev->ide_regs[0x00] = 0x06; dev->ide_regs[0x01] = 0x11; dev->ide_regs[0x02] = 0x71; dev->ide_regs[0x03] = 0x05; @@ -212,7 +286,7 @@ pipc_reset_hard(void *priv) dev->ide_regs[0xc2] = 0x02; } - /* USB registers */ + /* 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; @@ -260,7 +334,7 @@ pipc_reset_hard(void *priv) dev->usb_regs[i][0xc1] = 0x20; } - /* power management registers */ + /* Power management registers. */ if (dev->acpi) { dev->max_func++; dev->power_regs[0x00] = 0x06; dev->power_regs[0x01] = 0x11; @@ -317,9 +391,26 @@ pipc_reset_hard(void *priv) dev->power_regs[0x80] = 0x01; else if (dev->local >= VIA_PIPC_596B) dev->power_regs[0x90] = 0x01; + + /* Set up PCS I/O traps. */ + pipc_io_trap_t *trap; + for (i = 0; i <= dev->max_pcs; i++) { + trap = &dev->io_traps[TRAP_GR0 + i]; + trap->dev = dev; + trap->trap = io_trap_add(pipc_io_trap_glb, trap); + if (i & 2) { + trap->sts_reg = (uint32_t *) &dev->acpi->regs.extiotrapsts; + trap->en_reg = (uint32_t *) &dev->acpi->regs.extiotrapen; + trap->mask = 0x01 << (i & 1); + } else { + trap->sts_reg = &dev->acpi->regs.glbsts; + trap->en_reg = &dev->acpi->regs.glben; + trap->mask = 0x4000 << i; + } + } } - /* AC97/MC97 registers */ + /* AC97/MC97 registers. */ if (dev->local >= VIA_PIPC_686A) { for (i = 0; i <= 1; i++) { dev->max_func++; @@ -459,6 +550,139 @@ pipc_bus_master_handlers(pipc_t *dev) } +static void +pipc_pcs_update(pipc_t *dev) +{ + uint8_t i, io_base_reg, io_mask_reg, io_mask_shift, enable; + uint16_t io_base, io_mask; + + for (i = 0; i <= dev->max_pcs; i++) { + if (i & 2) { + io_base_reg = 0x8c; + io_mask_reg = 0x8a; + } else { + io_base_reg = 0x78; + io_mask_reg = 0x80; + } + io_base_reg |= (i & 1) << 1; + io_mask_shift = (i & 1) << 2; + + if (dev->local <= VIA_PIPC_596B) + enable = dev->pci_isa_regs[0x76] & (0x10 << i); + else + enable = dev->pci_isa_regs[0x8b] & (0x01 << i); + + io_base = dev->pci_isa_regs[io_base_reg] | (dev->pci_isa_regs[io_base_reg | 1] << 8); + io_mask = (dev->pci_isa_regs[io_mask_reg] >> io_mask_shift) & 0x000f; + + pipc_log("PIPC: Mapping PCS%d to %04X-%04X (enable %d)\n", i, io_base, io_base + io_mask, enable); + io_trap_remap(dev->io_traps[TRAP_GR0 + i].trap, enable, io_base & ~io_mask, io_mask + 1); + } +} + + +static void +pipc_trap_update_paden(pipc_t *dev, uint8_t trap_id, + uint32_t paden_mask, uint8_t enable, + uint16_t addr, uint16_t size) +{ + pipc_io_trap_t *trap = &dev->io_traps[trap_id]; + enable = (dev->acpi->regs.paden & paden_mask) && enable; + + /* Set up Primary Activity Detect I/O traps dynamically. */ + if (enable && !trap->trap) { + trap->dev = dev; + trap->trap = io_trap_add(pipc_trap_io_pact, trap); + trap->sts_reg = &dev->acpi->regs.padsts; + trap->en_reg = &dev->acpi->regs.paden; + trap->mask = paden_mask; + } + + /* Remap I/O trap. */ + io_trap_remap(trap->trap, enable, addr, size); +} + + +static void +pipc_trap_update_586(void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + + /* TRAP_DRQ (00000001) and TRAP_PIRQ (00000002) not implemented. */ + + pipc_trap_update_paden(dev, TRAP_PIDE_MAIN, 0x00000008, 1, 0x1f0, 8); + pipc_trap_update_paden(dev, TRAP_SIDE_MAIN, 0x00000008, 1, 0x170, 8); + pipc_trap_update_paden(dev, TRAP_FLP_MAIN, 0x00000008, 1, 0x3f5, 1); + + pipc_trap_update_paden(dev, TRAP_VGA, 0x00000010, 1, 0x3b0, 48); + /* [A0000:BFFFF] memory trap not implemented. */ + + pipc_trap_update_paden(dev, TRAP_LPT_LPT1, 0x00000020, 1, 0x378, 8); + pipc_trap_update_paden(dev, TRAP_LPT_LPT2, 0x00000020, 1, 0x278, 8); + + pipc_trap_update_paden(dev, TRAP_COM1, 0x00000040, 1, 0x3f8, 8); + pipc_trap_update_paden(dev, TRAP_COM2, 0x00000040, 1, 0x2f8, 8); + pipc_trap_update_paden(dev, TRAP_COM3, 0x00000040, 1, 0x3e8, 8); + pipc_trap_update_paden(dev, TRAP_COM4, 0x00000040, 1, 0x2e8, 8); + + pipc_trap_update_paden(dev, TRAP_KBC, 0x00000080, 1, 0x60, 1); +} + + +static void +pipc_trap_update_596(void *priv) +{ + pipc_t *dev = (pipc_t *) priv; + int i; + + /* TRAP_DRQ (00000001) and TRAP_PIRQ (00000002) not implemented. */ + + pipc_trap_update_paden(dev, TRAP_PIDE_MAIN, 0x00000004, 1, 0x1f0, 8); + pipc_trap_update_paden(dev, TRAP_PIDE_SIDE, 0x00000004, 1, 0x3f6, 1); + + pipc_trap_update_paden(dev, TRAP_SIDE_MAIN, 0x00000008, 1, 0x170, 8); + pipc_trap_update_paden(dev, TRAP_SIDE_SIDE, 0x00000008, 1, 0x376, 1); + + pipc_trap_update_paden(dev, TRAP_FLP_MAIN, 0x00000010, 1, 0x3f0, 6); + pipc_trap_update_paden(dev, TRAP_FLP_SIDE, 0x00000010, 1, 0x3f7, 1); + + pipc_trap_update_paden(dev, TRAP_COM1, 0x00000020, 1, 0x3f8, 8); + pipc_trap_update_paden(dev, TRAP_COM3, 0x00000020, 1, 0x3e8, 8); + + pipc_trap_update_paden(dev, TRAP_COM2, 0x00000040, 1, 0x2f8, 8); + pipc_trap_update_paden(dev, TRAP_COM4, 0x00000040, 1, 0x2e8, 8); + + pipc_trap_update_paden(dev, TRAP_LPT_LPT1, 0x00000080, 1, 0x378, 8); + pipc_trap_update_paden(dev, TRAP_LPT_LPT2, 0x00000080, 1, 0x278, 8); + + pipc_trap_update_paden(dev, TRAP_VGA, 0x00000100, 1, 0x3b0, 48); + /* [A0000:BFFFF] memory trap not implemented. */ + + pipc_trap_update_paden(dev, TRAP_KBC, 0x00000200, 1, 0x60, 1); + + /* The following traps are poorly documented and assumed to operate on all ranges allowed + by the Positive Decoding Control registers. I couldn't probe this behavior on hardware. + It's better to be safe and cover all of them than to assume Intel-like behavior (one range). */ + + for (i = 0; i < 3; i++) { + pipc_trap_update_paden(dev, TRAP_AUD_MIDI_0 + i, + 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x01), + 0x300 + (0x10 * i), 4); + + pipc_trap_update_paden(dev, TRAP_AUD_SB_0 + i, + 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x02), + 0x220 + (0x20 * i), 20); + } + + pipc_trap_update_paden(dev, TRAP_AUD_GAME, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x04), 0x200, 8); + + pipc_trap_update_paden(dev, TRAP_AUD_WSS_0, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0x530, 8); + pipc_trap_update_paden(dev, TRAP_AUD_WSS_1, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0x604, 8); + pipc_trap_update_paden(dev, TRAP_AUD_WSS_2, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0xe80, 8); + pipc_trap_update_paden(dev, TRAP_AUD_WSS_3, 0x00000400, (dev->local <= VIA_PIPC_596B) || (dev->power_regs[0x40] & 0x08), 0xf40, 8); +} + + static void pipc_sgd_handlers(pipc_t *dev, uint8_t modem) { @@ -882,17 +1106,21 @@ pipc_write(int func, int addr, uint8_t val, void *priv) dev->pci_isa_regs[(addr - 0x44)] = val; break; + case 0x74: case 0x8b: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x80: case 0x8a: + dev->pci_isa_regs[addr] = val; + pipc_pcs_update(dev); + break; + case 0x77: - if (val & 0x10) + if ((dev->local >= VIA_PIPC_686A) && (val & 0x10)) pclog("PIPC: Warning: Internal I/O APIC enabled.\n"); nvr_via_wp_set(!!(val & 0x04), 0x32, dev->nvr); nvr_via_wp_set(!!(val & 0x02), 0x0d, dev->nvr); break; - case 0x80: case 0x86: case 0x87: - dev->pci_isa_regs[addr] &= ~(val); - break; - default: dev->pci_isa_regs[addr] = val; break; @@ -1326,10 +1554,13 @@ pipc_init(const device_t *info) else if (dev->local >= VIA_PIPC_596A) dev->smbus = device_add(&piix4_smbus_device); - if (dev->local >= VIA_PIPC_596A) + if (dev->local >= VIA_PIPC_596A) { dev->acpi = device_add(&acpi_via_596b_device); - else if (dev->local >= VIA_PIPC_586B) + acpi_set_trap_update(dev->acpi, pipc_trap_update_596, dev); + } else if (dev->local >= VIA_PIPC_586B) { dev->acpi = device_add(&acpi_via_device); + acpi_set_trap_update(dev->acpi, pipc_trap_update_586, dev); + } dev->usb[0] = device_add_inst(&usb_device, 1); if (dev->local >= VIA_PIPC_686A) { @@ -1383,6 +1614,9 @@ pipc_close(void *p) pipc_log("PIPC: close()\n"); + for (int i = 0; i < TRAP_MAX; i++) + io_trap_remove(dev->io_traps[i].trap); + free(dev); } diff --git a/src/include/86box/acpi.h b/src/include/86box/acpi.h index 4637262f8..2cae4bb30 100644 --- a/src/include/86box/acpi.h +++ b/src/include/86box/acpi.h @@ -63,7 +63,8 @@ typedef struct smicmd, gpio_dir, gpio_val, muxcntrl, pad, timer32, smireg, - gpireg[3], gporeg[4]; + gpireg[3], gporeg[4], + extiotrapsts, extiotrapen; uint16_t pmsts, pmen, pmcntrl, gpsts, gpsts1, gpen, gpen1, gpscien, @@ -95,7 +96,8 @@ typedef struct pc_timer_t timer; nvr_t *nvr; apm_t *apm; - void *i2c; + void *i2c, + (*trap_update)(void *priv), *trap_priv; } acpi_t; @@ -111,6 +113,8 @@ extern const device_t acpi_via_596b_device; /* Functions */ +extern void acpi_update_irq(acpi_t *dev); +extern void acpi_raise_smi(acpi_t *dev); extern void acpi_update_io_mapping(acpi_t *dev, uint32_t base, int chipset_en); extern void acpi_update_aux_io_mapping(acpi_t *dev, uint32_t base, int chipset_en); extern void acpi_init_gporeg(acpi_t *dev, uint8_t val0, uint8_t val1, uint8_t val2, uint8_t val3); @@ -121,6 +125,7 @@ extern void acpi_set_irq_pin(acpi_t *dev, int irq_pin); extern void acpi_set_irq_line(acpi_t *dev, int irq_line); extern void acpi_set_gpireg2_default(acpi_t *dev, uint8_t gpireg2_default); extern void acpi_set_nvr(acpi_t *dev, nvr_t *nvr); +extern void acpi_set_trap_update(acpi_t *dev, void (*update)(void *priv), void *priv); #ifdef __cplusplus } diff --git a/src/include/86box/io.h b/src/include/86box/io.h index 6112ea8e4..c483819ce 100644 --- a/src/include/86box/io.h +++ b/src/include/86box/io.h @@ -111,5 +111,10 @@ extern void outw(uint16_t port, uint16_t val); extern uint32_t inl(uint16_t port); extern void outl(uint16_t port, uint32_t val); +extern void *io_trap_add(void (*func)(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv), + void *priv); +extern void io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size); +extern void io_trap_remove(void *handle); + #endif /*EMU_IO_H*/ diff --git a/src/io.c b/src/io.c index 2751cc639..0d3d1bb91 100644 --- a/src/io.c +++ b/src/io.c @@ -35,19 +35,26 @@ typedef struct _io_ { - uint8_t (*inb)(uint16_t addr, void *priv); - uint16_t (*inw)(uint16_t addr, void *priv); - uint32_t (*inl)(uint16_t addr, void *priv); + uint8_t (*inb)(uint16_t addr, void *priv); + uint16_t (*inw)(uint16_t addr, void *priv); + uint32_t (*inl)(uint16_t addr, void *priv); - void (*outb)(uint16_t addr, uint8_t val, void *priv); - void (*outw)(uint16_t addr, uint16_t val, void *priv); - void (*outl)(uint16_t addr, uint32_t val, void *priv); + void (*outb)(uint16_t addr, uint8_t val, void *priv); + void (*outw)(uint16_t addr, uint16_t val, void *priv); + void (*outl)(uint16_t addr, uint32_t val, void *priv); - void *priv; + void *priv; - struct _io_ *prev, *next; + struct _io_ *prev, *next; } io_t; +typedef struct { + uint8_t enable; + uint16_t base, size; + void (*func)(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv), + *priv; +} io_trap_t; + int initialized = 0; io_t *io[NPORTS], *io_last[NPORTS]; @@ -583,3 +590,116 @@ outl(uint16_t port, uint32_t val) return; } + + +static uint8_t +io_trap_readb(uint16_t addr, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(1, addr, 0, 0, trap->priv); + return 0xff; +} + + +static uint16_t +io_trap_readw(uint16_t addr, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(2, addr, 0, 0, trap->priv); + return 0xffff; +} + + +static uint32_t +io_trap_readl(uint16_t addr, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(4, addr, 0, 0, trap->priv); + return 0xffffffff; +} + + +static void +io_trap_writeb(uint16_t addr, uint8_t val, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(1, addr, 1, val, trap->priv); +} + + +static void +io_trap_writew(uint16_t addr, uint16_t val, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(2, addr, 1, val, trap->priv); +} + + +static void +io_trap_writel(uint16_t addr, uint32_t val, void *priv) +{ + io_trap_t *trap = (io_trap_t *) priv; + trap->func(4, addr, 1, val, trap->priv); +} + + +void * +io_trap_add(void (*func)(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv), + void *priv) +{ + /* Instantiate new I/O trap. */ + io_trap_t *trap = (io_trap_t *) malloc(sizeof(io_trap_t)); + trap->enable = 0; + trap->base = trap->size = 0; + trap->func = func; + trap->priv = priv; + + return trap; +} + + +void +io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size) +{ + io_trap_t *trap = (io_trap_t *) handle; + if (!trap) + return; + + io_log("I/O: Remapping trap from %04X-%04X (enable %d) to %04X-%04X (enable %d)\n", + trap->base, trap->base + trap->size, trap->enable, addr, addr + size, enable); + + /* Remove old I/O mapping. */ + if (trap->enable && trap->base && trap->size) { + io_removehandler(trap->base, trap->size, + io_trap_readb, io_trap_readw, io_trap_readl, + io_trap_writeb, io_trap_writew, io_trap_writel, + trap); + } + + /* Set trap enable flag, base address and size. */ + trap->enable = !!enable; + trap->base = addr; + trap->size = size; + + /* Add new I/O mapping. */ + if (trap->enable && trap->base && trap->size) { + io_sethandler(trap->base, trap->size, + io_trap_readb, io_trap_readw, io_trap_readl, + io_trap_writeb, io_trap_writew, io_trap_writel, + trap); + } +} + + +void +io_trap_remove(void *handle) +{ + io_trap_t *trap = (io_trap_t *) handle; + if (!trap) + return; + + /* Unmap I/O trap before freeing it. */ + io_trap_remap(trap, 0, 0, 0); + + free(trap); +}