#include "ibm.h" #include "fdc.h" #include "io.h" #include "lpt.h" #include "serial.h" #include "pc87307.h" typedef struct pc87307_t { int cur_reg; int cur_device; uint8_t superio_cfg1, superio_cfg2; struct { int enable; uint16_t addr; int irq; int dma; } dev[9]; } pc87307_t; static pc87307_t pc87307_global; #define DEV_KBC 0 #define DEV_MOUSE 1 #define DEV_RTC 2 #define DEV_FDC 3 #define DEV_LPT 4 #define DEV_COM2 5 #define DEV_COM1 6 #define DEV_GPIO 7 #define DEV_POWER 8 #define REG_DEVICE 0x07 #define REG_SID 0x20 #define REG_SUPERIO_CFG1 0x21 #define REG_SUPERIO_CFG2 0x22 #define REG_ENABLE 0x30 #define REG_ADDRHI 0x60 #define REG_ADDRLO 0x61 #define REG_IRQ 0x70 #define REG_DMA 0x74 void pc87307_write(uint16_t port, uint8_t val, void *p) { pc87307_t *pc87307 = (pc87307_t *)p; if (port == 0x2e) pc87307->cur_reg = val; else { if (pc87307->cur_reg == REG_DEVICE) pc87307->cur_device = val & 0xf; else { // pclog("Write pc87307 %02x [%02x] %02x\n", pc87307->cur_reg, pc87307->cur_device, val); switch (pc87307->cur_reg) { case REG_ENABLE: if (pc87307->cur_device <= DEV_POWER) pc87307->dev[pc87307->cur_device].enable = val; break; case REG_ADDRLO: if (pc87307->cur_device <= DEV_POWER) pc87307->dev[pc87307->cur_device].addr = (pc87307->dev[pc87307->cur_device].addr & 0xff00) | val; break; case REG_ADDRHI: if (pc87307->cur_device <= DEV_POWER) pc87307->dev[pc87307->cur_device].addr = (pc87307->dev[pc87307->cur_device].addr & 0x00ff) | (val << 8); break; case REG_IRQ: if (pc87307->cur_device <= DEV_POWER) pc87307->dev[pc87307->cur_device].irq = val; break; case REG_DMA: if (pc87307->cur_device <= DEV_POWER) pc87307->dev[pc87307->cur_device].dma = val; break; } switch (pc87307->cur_device) { case DEV_FDC: fdc_remove(); if (pc87307->dev[DEV_FDC].enable & 1) fdc_add(); break; case DEV_COM1: serial1_remove(); if (pc87307->dev[DEV_COM1].enable & 1) serial1_set(pc87307->dev[DEV_COM1].addr, pc87307->dev[DEV_COM1].irq); break; case DEV_COM2: serial2_remove(); if (pc87307->dev[DEV_COM2].enable & 1) serial2_set(pc87307->dev[DEV_COM2].addr, pc87307->dev[DEV_COM2].irq); break; case DEV_LPT: lpt1_remove(); lpt2_remove(); if (pc87307->dev[DEV_LPT].enable & 1) lpt1_init(pc87307->dev[DEV_LPT].addr); break; } } } } uint8_t pc87307_read(uint16_t port, void *p) { pc87307_t *pc87307 = (pc87307_t *)p; // pclog("Read pc87307 %02x\n", pc87307->cur_reg); switch (pc87307->cur_reg) { case REG_DEVICE: return pc87307->cur_device; case REG_SID: return 0x20; /*PC87307*/ case REG_SUPERIO_CFG1: return pc87307->superio_cfg1; case REG_SUPERIO_CFG2: return pc87307->superio_cfg2; case REG_ENABLE: return pc87307->dev[pc87307->cur_device].enable; case REG_ADDRLO: return pc87307->dev[pc87307->cur_device].addr & 0xff; case REG_ADDRHI: return pc87307->dev[pc87307->cur_device].addr >> 8; case REG_IRQ: return pc87307->dev[pc87307->cur_device].irq; case REG_DMA: return pc87307->dev[pc87307->cur_device].dma; } return 0xff; } void pc87307_init(uint16_t base) { memset(&pc87307_global, 0, sizeof(pc87307_t)); pc87307_global.superio_cfg1 = 0x04; pc87307_global.superio_cfg2 = 0x03; io_sethandler(base, 0x0002, pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, &pc87307_global); }