Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

chip_intel_82371AB.c

/*
 * $Id: chip_intel_82371AB.c,v 1.479 2009-02-26 15:51:36 potyra Exp $
 *
 * Copyright (C) 2003-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

/*
 * This is an implementation of the south bridge of the
 * Intel 440BX chipset.
 */

#include "config.h"
#include <inttypes.h>

#include <assert.h>
#include <errno.h>
#include "fixme.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>

#include "glue-log.h"
#include "glue-main.h"
#include "glue-shm.h"
#include "glue-storage.h"

#include "chip_intel_82371AB.h"

#define COMP      "chip_intel_82371AB"

struct cpssp {
      /*
       * Config
       */

      /*
       * Signals
       */
      /* External Signals */
      /* PCI Bus Interface */
      struct sig_pci_bus_main *sig_pci_bus_main;
      struct sig_boolean *sig_n_pcirst;

      /* ISA Bus Interface */
      struct sig_isa_bus_main *sig_isa_bus;
      struct sig_boolean *sig_n_rstdrv;

      /* X-Bus Interface */
      struct sig_boolean *sig_a20gate;
      int state_a20gate;
      struct sig_boolean *sig_n_rcin;
      unsigned int state_n_rcin;
      struct sig_cs *sig_n_bioscs;
      struct sig_cs *sig_n_kbccs;

      /* DMA Signals */
      struct sig_isa_bus_dma *sig_isa_bus_dma[8];

      /* Interrupt Controller / APIC Signals */
      struct sig_cs *sig_n_apiccs;
      struct sig_boolean_or *isa_bus_int[16];
      struct sig_boolean_or *pci_bus_int[4];

      /* CPU Interface Signals */
      struct sig_boolean *sig_a20m;
      struct sig_boolean *sig_n_cpurst;
      struct sig_boolean *sig_n_init;
      struct sig_boolean_or *sig_n_ferr;
      struct sig_boolean *sig_n_ignne;
      struct sig_boolean_or *sig_intr;
      struct sig_boolean_or *sig_nmi;
      struct sig_boolean *sig_smi;

      /* Clocking Signals */
      
      /* IDE Signals */
      struct sig_ide_bus *sig_ide[2];

      /* Universal Serial Bus Signals */
      struct sig_usb_bus_main *sig_usb[2];

      /* Power Management Signals */
      struct sig_std_logic *sig_n_pwrbtn;
      struct sig_std_logic *sig_n_rsmrst;
      unsigned int state_n_rsmrst;
      struct sig_i2c_bus *sig_i2cbus;
      struct sig_boolean *sig_n_susa;
      struct sig_boolean *sig_n_susb;
      struct sig_std_logic *sig_n_susc;

      /* Other System And Test Signals */
      struct sig_boolean *sig_pwrok;
      struct sig_sound *sig_spkr;

      /* Power And Ground Signals */
      struct sig_boolean *sig_vcc;
      unsigned int state_vcc;
#define state_power state_vcc
      struct sig_boolean *sig_vcc_rtc;
      struct sig_boolean *sig_vcc_sus;
      unsigned int state_vcc_sus;
      struct sig_boolean *sig_vcc_usb;
      struct sig_boolean *sig_vref;

      /* FIXME */
      struct sig_boolean *sig_ide_busy;

      /* Internal Signals */
      unsigned int speaker_data_enable;
      unsigned long long speaker_period;

      /*
       * State
       */
      unsigned int reset_triggered;
      unsigned int init_triggered;
      unsigned int memory_refresh;

      /* Config Space */
      /* Page 54 */
      uint16_t pcicmd;
      /* Page 55 */
      uint16_t pcists;
      /* Page 56 */
      uint8_t iort;
      /* Page 55 */
      uint16_t xbcs;
      /* Page 59 */
      uint8_t pirqrca;
      uint8_t pirqrcb;
      uint8_t pirqrcc;
      uint8_t pirqrcd;
      /* Page 59 */
      uint8_t serirqc;
      /* Page 60 */
      uint8_t tom;
      /* Page 61 */
      uint16_t mstat;
      /* Page 61 */
      uint8_t mbdma0;
      uint8_t mbdma1;
      /* Page 62 */
      uint8_t apicbase;
      /* Page 62 */
      uint8_t dlc;
      /* Page 63 */
      uint16_t pdmacfg;
      /* Page 64 */
      uint16_t ddmabp0;
      uint16_t ddmabp1;
      /* Page 65 */
      uint32_t gencfg;
      /* Page 67 */
      uint8_t rtccfg;

      /* I/O Space */
      unsigned char r92;

      uint8_t state_inta;

      unsigned char state_ferr;

      uint8_t dma_page[16];   /* 0: reserved */
                        /* 1: ctrl 0, chan 2 */
                        /* 2: ctrl 0, chan 3 */
                        /* 3: ctrl 0, chan 1 */
                        /* 4: reserved */
                        /* 5: reserved */
                        /* 6: reserved */
                        /* 7: ctrl 0, chan 0 */
                        /* 8: reserved */
                        /* 9: ctrl 1, chan 2 */
                        /* A: ctrl 1, chan 3 */
                        /* B: ctrl 1, chan 1 */
                        /* C: reserved */
                        /* D: reserved */
                        /* E: reserved */
                        /* F: ctrl 1, chan 0 */

#define STATE
      /* IDE */
#define NAME            ide
#define NAME_(x)  ide_ ## x
#define SNAME           "ide"
#include "arch_ide_controller.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* USB */
#define NAME            usb_controller
#define NAME_(x)  usb_controller_ ## x
#define SNAME           "usb_controller"
#include "arch_usb_controller.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* Power Management */
#define NAME            power
#define NAME_(x)  power_ ## x
#define SNAME           "power"
#include "arch_power_management.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* RTC */
#define NAME            rtc
#define NAME_(x)  rtc_ ## x
#define SNAME           "rtc"
#include "arch_rtc.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* DMA */
#define NAME            dma0
#define NAME_(x)  dma0_ ## x
#define SNAME           "dma0"
#include "arch_dma.c"
#undef SNAME
#undef NAME_
#undef NAME
#define NAME            dma1
#define NAME_(x)  dma1_ ## x
#define SNAME           "dma1"
#include "arch_dma.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* PICs */
#define NAME            pic0
#define NAME_(x)  pic0_ ## x
#define SNAME           "pic0"
#include "arch_pic.c"
#undef SNAME
#undef NAME_
#undef NAME
#define NAME            pic1
#define NAME_(x)  pic1_ ## x
#define SNAME           "pic1"
#include "arch_pic.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* PITs */
#define NAME            pit
#define NAME_(x)  pit_ ## x
#define SNAME           "pit"
#include "arch_pit.c"
#undef SNAME
#undef NAME_
#undef NAME

      /* PPI */
#define NAME            ppi
#define NAME_(x)  ppi_ ## x
#define SNAME           "ppi"
#include "arch_ppi.c"
#undef SNAME
#undef NAME_
#undef NAME

#undef STATE
};

#define min(x,y) ((x) < (y)) ? (x) : (y)

/* Forward target */
enum fw_target { IOAPIC, BIOS, ISA };


/*
 * Glue functions.
 */
/* forward */ static void
pic0_isa_bus_int2_set(struct cpssp *cpssp, unsigned int val);
/* forward */ static void
pic1_cas_in_set(struct cpssp *cpssp, unsigned int val);
/* forward */ static int
pit_timer_get(struct cpssp *cpssp, unsigned int ch);
/* forward */ static void
pit_gate_set(struct cpssp *cpssp, unsigned int ch, unsigned char val);

/*
 * DMA Output Functions
 */
static const unsigned int chanreg[8] = {
      0x7, 0x3, 0x1, 0x2,
      0xf, 0xb, 0x9, 0xa,
};

static inline void
dma0_ack_out(
      struct cpssp *cpssp,
      uint16_t offset,
      unsigned char chan,
      unsigned int tc
)
{
      uint8_t page;
      unsigned long pa;
      uint32_t val32;
      uint8_t val8;

      assert(/* 0 <= chan && */ chan < 4);

      page = cpssp->dma_page[chanreg[chan + 0]];

      pa = (page << 16) | offset;

      sig_pci_bus_mr(cpssp->sig_pci_bus_main, cpssp,
                  pa & ~3, 1 << (pa & 3), &val32);
      val8 = val32 >> ((pa & 3) * 8);
      sig_isa_bus_dma_ack_outb(cpssp->sig_isa_bus_dma[chan], cpssp, tc, val8);
}

static inline void
dma0_ack_in(
      struct cpssp *cpssp,
      uint16_t offset,
      unsigned char chan,
      unsigned int tc
)
{
      uint8_t page;
      unsigned long pa;
      uint32_t val32;
      uint8_t val8;

      assert(/* 0 <= chan && */ chan < 4);

      page = cpssp->dma_page[chanreg[chan + 0]];

      pa = (page << 16) | offset;

      sig_isa_bus_dma_ack_inb(cpssp->sig_isa_bus_dma[chan], cpssp, tc, &val8);
      val32 = val8 << ((pa & 3) * 8);
      sig_pci_bus_mw(cpssp->sig_pci_bus_main, cpssp,
                  pa & ~3, 1 << (pa & 3), val32);
}

static inline void
dma0_ack_verify(
      struct cpssp *cpssp,
      unsigned char chan,
      unsigned int tc
)
{
      sig_isa_bus_dma_ack_verifyb(cpssp->sig_isa_bus_dma[chan], cpssp, tc);
}

static inline void
dma1_ack_out(
      struct cpssp *cpssp,
      uint16_t offset,
      unsigned char chan,
      unsigned int tc
)
{
      uint8_t page;
      unsigned long pa;
      uint32_t val32;
      uint16_t val16;

      assert(/* 0 <= chan && */ chan < 4);

      page = cpssp->dma_page[chanreg[chan + 4]];

      pa = (page << 16) | (offset << 1);

      sig_pci_bus_mr(cpssp->sig_pci_bus_main, cpssp,
                  pa & ~3, 3 << (pa & 3), &val32);
      val16 = val32 >> ((pa & 3) * 8);
      sig_isa_bus_dma_ack_outw(cpssp->sig_isa_bus_dma[chan], cpssp, tc, val16);
}

static inline void
dma1_ack_in(
      struct cpssp *cpssp,
      uint16_t offset,
      unsigned char chan,
      unsigned int tc
)
{
      uint8_t page;
      unsigned long pa;
      uint32_t val32;
      uint16_t val16;

      assert(/* 0 <= chan && */ chan < 4);

      page = cpssp->dma_page[chanreg[chan + 4]];

      pa = (page << 16) | (offset << 1);

      sig_isa_bus_dma_ack_inw(cpssp->sig_isa_bus_dma[chan], cpssp, tc, &val16);
      val32 = val16 << ((pa & 3) * 8);
      sig_pci_bus_mw(cpssp->sig_pci_bus_main, cpssp,
                  pa & ~3, 3 << (pa & 3), val32);
}

static inline void
dma1_ack_verify(
      struct cpssp *cpssp,
      unsigned char chan,
      unsigned int tc
)
{
      sig_isa_bus_dma_ack_verifyw(cpssp->sig_isa_bus_dma[chan], cpssp, tc);
}

/*
 * IDE Output Functions
 */
static inline void
ide_0_irqrq_out_set(struct cpssp *cpssp, unsigned int val)
{
      sig_boolean_or_set(cpssp->isa_bus_int[14], cpssp, val);
}

static inline void
ide_1_irqrq_out_set(struct cpssp *cpssp, unsigned int val)
{
      sig_boolean_or_set(cpssp->isa_bus_int[15], cpssp, val);
}

static inline void
ide_0_inw(struct cpssp *cpssp, unsigned short *valp, unsigned short port)
{
      sig_ide_bus_inw(cpssp->sig_ide[0], port, valp);
}

static inline void
ide_1_inw(struct cpssp *cpssp, unsigned short *valp, unsigned short port)
{
      sig_ide_bus_inw(cpssp->sig_ide[1], port, valp);
}

static inline void
ide_0_outw(struct cpssp *cpssp, unsigned short val, unsigned short port)
{
      sig_ide_bus_outw(cpssp->sig_ide[0], port, val);
}

static inline void
ide_1_outw(struct cpssp *cpssp, unsigned short val, unsigned short port)
{
      sig_ide_bus_outw(cpssp->sig_ide[1], port, val);
}

static void
ide_busy_set(struct cpssp *cpssp, unsigned int val)
{
      sig_boolean_set(cpssp->sig_ide_busy, cpssp, val);
}

static inline int
ide_mem_write(
      struct cpssp *cpssp,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      return sig_pci_bus_mw(cpssp->sig_pci_bus_main, cpssp, addr, bs, val);
}

static inline int
ide_mem_read(
      struct cpssp *cpssp,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      return sig_pci_bus_mr(cpssp->sig_pci_bus_main, cpssp, addr, bs, valp);
}

/*
 * USB Output Functions
 */
static void
usb0_reset_set(struct cpssp *cpssp, int val)
{
      sig_usb_bus_reset_set(cpssp->sig_usb[0], cpssp, val);
}

static void
usb0_send_token(struct cpssp *cpssp, int pid, int addr, int endp)
{
      sig_usb_bus_send_token(cpssp->sig_usb[0], cpssp, pid, addr, endp);
}

static void
usb0_send_sof(
      struct cpssp *cpssp,
      int frame_num
)
{
      sig_usb_bus_send_sof(cpssp->sig_usb[0], cpssp, frame_num);
}

static void
usb0_send_data(
      struct cpssp *cpssp,
      int pid,
      uint8_t *data,
      unsigned int length,
      uint16_t crc16
)
{
      sig_usb_bus_send_data(cpssp->sig_usb[0], cpssp, pid, length, data, crc16);
}

static void
usb0_send_handshake(
      struct cpssp *cpssp,
      int pid
)
{
      sig_usb_bus_send_handshake(cpssp->sig_usb[0], cpssp, pid);
}

static void
usb1_reset_set(struct cpssp *cpssp, int val)
{
      sig_usb_bus_reset_set(cpssp->sig_usb[1], cpssp, val);
}

static void
usb1_send_token(struct cpssp *cpssp, int pid, int addr, int endp)
{
      sig_usb_bus_send_token(cpssp->sig_usb[1], cpssp, pid, addr, endp);
}

static void
usb1_send_sof(
      struct cpssp *cpssp,
      int frame_num
)
{
      sig_usb_bus_send_sof(cpssp->sig_usb[1], cpssp, frame_num);
}

static void
usb1_send_data(
      struct cpssp *cpssp,
      int pid,
      uint8_t *data,
      unsigned int length,
      uint16_t crc16
)
{
      sig_usb_bus_send_data(cpssp->sig_usb[1], cpssp, pid, length, data, crc16);
}

static void
usb1_send_handshake(
      struct cpssp *cpssp,
      int pid
)
{
      sig_usb_bus_send_handshake(cpssp->sig_usb[1], cpssp, pid);
}

static inline long
usb_mem_write(
      struct cpssp *cpssp,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      return sig_pci_bus_mw(cpssp->sig_pci_bus_main, cpssp, addr, bs, val);
}

static inline long
usb_mem_read(
      struct cpssp *cpssp,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      return sig_pci_bus_mr(cpssp->sig_pci_bus_main, cpssp, addr, bs, valp);
}

static inline void
usb_irqrq_out_set(struct cpssp *cpssp, unsigned int val)
{
      /* USB is hardwired to INTD */
      /* INTD is INOUT signal (wired or). */
      sig_boolean_or_set(cpssp->pci_bus_int[3], cpssp, val);
}

/*
 * Power Management Output Functions
 */
static inline void
power_smi_out_set(struct cpssp *cpssp, unsigned int val)
{
      sig_boolean_set(cpssp->sig_smi, cpssp, val);
}

static inline void
power_irqrq_out_set(struct cpssp *cpssp, unsigned int val)
{
      /* Power Management is hardwired to IRQ9 */
      sig_boolean_or_set(cpssp->isa_bus_int[9], cpssp, val);
}

static inline int
power_smbus_read_byte_data(
      struct cpssp *cpssp,
      unsigned char addr,
      unsigned char cmd,
      unsigned char *data
)
{
      int ret;

      ret = sig_i2c_bus_write_bytes(
            cpssp->sig_i2cbus, cpssp, addr & (~1), 1, &cmd);
      if (ret != 1) {
            return -1;
      }

      sig_i2c_bus_read_bytes(cpssp->sig_i2cbus, cpssp, addr | 1, 1, data);
      sig_i2c_bus_stop_transaction(cpssp->sig_i2cbus, cpssp);
      return 0;
}

static inline int
power_smbus_write_byte_data(
      struct cpssp *cpssp,
      unsigned char addr,
      unsigned char cmd,
      unsigned char data
)
{
      int ret;
      unsigned char buf[2];
      buf[0] = cmd;
      buf[1] = data;

      ret = sig_i2c_bus_write_bytes(
            cpssp->sig_i2cbus, cpssp, addr & (~1), 2, buf);
      sig_i2c_bus_stop_transaction(cpssp->sig_i2cbus, cpssp);

      if (ret == 2) {
            return 0;
      }

      return -1;
}

static inline int
power_smbus_read_block_data(
      struct cpssp *cpssp,
      unsigned char addr,
      unsigned char cmd,
      unsigned char *cnt,
      unsigned char *data
)
{
      /* FIXME potyra */
      assert(0);
      return -1;
}

static inline int
power_smbus_write_block_data(
      struct cpssp *cpssp,
      unsigned char addr,
      unsigned char cmd,
      unsigned char cnt,
      unsigned char *data
)
{
      /* FIXME potyra */
      assert(0);
      return -1;
}

static void
power_n_susc_set(struct cpssp *cpssp, unsigned int n_val)
{
      if (n_val) {
            sig_std_logic_set(cpssp->sig_n_susc, cpssp, SIG_STD_LOGIC_Z);
      } else {
            sig_std_logic_set(cpssp->sig_n_susc, cpssp, SIG_STD_LOGIC_0);
      }
}

/*
 * PIC Input/Output Functions
 */
extern inline void
pic0_irq_out_set(struct cpssp *cpssp, unsigned int value)
{
      sig_boolean_or_set(cpssp->sig_intr, cpssp, value);
}

static void
pic0_cas_out_set(struct cpssp *cpssp, unsigned int value)
{
      pic1_cas_in_set(cpssp, value);
}

static inline void
pic1_irq_out_set(struct cpssp *cpssp, unsigned int value)
{
      pic0_isa_bus_int2_set(cpssp, value);
}

static void
pic1_cas_out_set(struct cpssp *cpssp, unsigned int value)
{
      fixme();
}

/*
 * PIT Output Functions
 */
extern inline void
pit_out_val_set(struct cpssp *cpssp, unsigned int ch, unsigned int val)
{
      if (ch == 0) {
            /* interrupt timer */
            sig_boolean_or_set(cpssp->isa_bus_int[0], cpssp, val);
      } else if (ch == 1 && val == 0) {
            /* pulse of memory refresh timer */
            cpssp->memory_refresh ^= 1;
      }
}

static inline void
pit_out_period_set(struct cpssp *cpssp, unsigned int ch, unsigned long long val)
{
      if (ch == 2) {
            cpssp->speaker_period = val;
            sig_sound_attr_set(cpssp->sig_spkr, cpssp,
                  cpssp->speaker_data_enable, cpssp->speaker_period);
      }
}

/*
 * PPI Output Functions
 */
static inline unsigned int
ppi_in4_get(struct cpssp *cpssp)
{
      return cpssp->memory_refresh;
}

static inline unsigned int
ppi_in5_get(struct cpssp *cpssp)
{
      return pit_timer_get(cpssp, 2);
}

static inline void
ppi_out0_set(struct cpssp *cpssp, unsigned int val)
{
      pit_gate_set(cpssp, 2, val);
}

static inline void
ppi_out1_set(struct cpssp *cpssp, unsigned int val)
{
      cpssp->speaker_data_enable = val;
      sig_sound_attr_set(cpssp->sig_spkr, cpssp,
            cpssp->speaker_data_enable, cpssp->speaker_period);
}

/*
 * RTC output functions.
 */
static inline void
rtc_irq_set(struct cpssp *cpssp, unsigned int val)
{
      sig_boolean_or_set(cpssp->isa_bus_int[8], cpssp, val);
}

/* Include Core compenents */
#define BEHAVIOR

#define NAME            power
#define NAME_(x)  power_ ## x
#define SNAME           "power"
#include "arch_power_management.c"
#undef SNAME
#undef NAME_
#undef NAME

#define NAME            usb_controller
#define NAME_(x)  usb_controller_ ## x
#define SNAME           "usb_controller"
#include "arch_usb_controller.c"
#undef SNAME
#undef NAME_
#undef NAME

#define NAME            ide
#define NAME_(x)  ide_ ## x
#define SNAME           "ide"
#include "arch_ide_controller.c"
#undef SNAME
#undef NAME_
#undef NAME

/* First DMA Controller */
#define NAME            dma0
#define NAME_(x)  dma0_ ## x
#define SNAME           "dma0"
#include "arch_dma.c"
#undef SNAME
#undef NAME_
#undef NAME

/* Second DMA Controller */
#define NAME            dma1
#define NAME_(x)  dma1_ ## x
#define SNAME           "dma1"
#include "arch_dma.c"
#undef SNAME
#undef NAME_
#undef NAME

/* First PIC (master) */
#define MASTER          1
#define ELCR_MASK 0xf8  /* Can't set bits 0-2. */
#define NAME            pic0
#define NAME_(x)  pic0_ ## x
#define SNAME           "pic0"
#include "arch_pic.c"
#undef SNAME
#undef NAME_
#undef NAME
#undef ELCR_MASK
#undef MASTER

/* Second PIC (slave) */
#define MASTER          0
#define ELCR_MASK 0xde  /* Can't set bits 0 and 5. */
#define NAME            pic1
#define NAME_(x)  pic1_ ## x
#define SNAME           "pic1"
#include "arch_pic.c"
#undef SNAME
#undef NAME_
#undef NAME
#undef ELCR_MASK
#undef MASTER

/* PIT */
#define NAME            pit
#define NAME_(x)  pit_ ## x
#define SNAME           "pit"
#include "arch_pit.c"
#undef SNAME
#undef NAME_
#undef NAME

/* PPI */
#define NAME            ppi
#define NAME_(x)  ppi_ ## x
#define SNAME           "ppi"
#include "arch_ppi.c"
#undef SNAME
#undef NAME_
#undef NAME

#define NAME            rtc
#define NAME_(x)  rtc_ ## x
#define SNAME           "rtc"
#include "arch_rtc.c"
#undef SNAME
#undef NAME_
#undef NAME

#undef BEHAVIOR

static void
ide0_dmarq_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      ide_dmarq_set(cpssp, 0, val);
}

static void
ide1_dmarq_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      ide_dmarq_set(cpssp, 1, val);
}

static void
ide0_irqrq_in_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      ide_irqrq_in_set(cpssp, 0, val);
}

static void
ide1_irqrq_in_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      ide_irqrq_in_set(cpssp, 1, val);
}

static void
chip_intel_82371AB_a20m_update(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;
      unsigned int val0;
      unsigned int val1;

      val0 = (cpssp->r92 >> 1) & 1;
      val1 = cpssp->state_a20gate;

      sig_boolean_set(cpssp->sig_a20m, cpssp, val0 | val1);
}

static void
chip_intel_82371AB_reset_update(struct cpssp *cpssp)
{
      unsigned int n_reset;

      /* Reset ConfigSpace */
      cpssp->pcicmd = 0x0007; /* Some bits hard-wired to '1'. */
      cpssp->pcists = 0x0000 | (0x1 << 9) | (1 << 7);

      cpssp->iort = 0x4d;
      cpssp->xbcs = 0x0003;

      cpssp->pirqrca = 9;
      cpssp->pirqrcb = 10;
      cpssp->pirqrcc = 11;
      cpssp->pirqrcd = 12;

      cpssp->serirqc = 0x10;

      cpssp->tom = 0x02;

      cpssp->mstat = 0x0000;

      cpssp->mbdma0 = 0x04;
      cpssp->mbdma1 = 0x04;

      cpssp->apicbase = 0x00;

      cpssp->dlc = 0x00;

      cpssp->pdmacfg = 0x0000;

      cpssp->ddmabp0 = 0x0000;
      cpssp->ddmabp1 = 0x0000;

      cpssp->gencfg = 0x00000000;

      cpssp->rtccfg = 0x21;

      cpssp->memory_refresh = 1;

      cpssp->r92 = (1 << 1) | (0 << 1);

      cpssp->state_a20gate = 0;
      cpssp->state_ferr = 0;

      chip_intel_82371AB_a20m_update(cpssp);

      ide_reset(cpssp);
      pic0_reset(cpssp);
      pic1_reset(cpssp);
      pit_reset(cpssp);
      ppi_reset(cpssp);
      dma0_reset(cpssp);
      dma1_reset(cpssp);
      rtc_reset(cpssp);
      usb_controller_reset(cpssp);
      power_reset(cpssp);

      n_reset = ! cpssp->reset_triggered;

      sig_boolean_set(cpssp->sig_n_cpurst, cpssp, n_reset);
      sig_boolean_set(cpssp->sig_n_pcirst, cpssp, n_reset);
      sig_boolean_set(cpssp->sig_n_rstdrv, cpssp, n_reset);
}

static void
chip_intel_82371AB_reset_event(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (cpssp->reset_triggered) {
            cpssp->reset_triggered = 0;
            chip_intel_82371AB_reset_update(cpssp);
      }
}

static void
chip_intel_82371AB_reset_trigger(struct cpssp *cpssp)
{
      cpssp->reset_triggered = 1;
      chip_intel_82371AB_reset_update(cpssp);
      time_call_after(TIME_HZ / 500,
                  chip_intel_82371AB_reset_event, cpssp);
}

static void
chip_intel_82371AB_vcc_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      cpssp->state_vcc = val;
}

static void
chip_intel_82371AB_vcc_sus_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      cpssp->state_vcc_sus = val;

      power_power_set(cpssp, val);
}

static void
chip_intel_82371AB_n_rsmrst_set(void *_css, unsigned int n_val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      switch (n_val) {
      case SIG_STD_LOGIC_0: n_val = 0; break;
      case SIG_STD_LOGIC_H: n_val = 1; break;
      default: return; /* Might happen during startup. */
      }

      if (! n_val) {
            /* Resume Reset Event */
            chip_intel_82371AB_reset_trigger(cpssp);
      }
}

static void
chip_intel_82371AB_rcin_set(void *_css, unsigned int n_val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      cpssp->state_n_rcin = n_val;
      if (! n_val) {
            /* Keyboard Controller Reset Event */
            chip_intel_82371AB_reset_trigger(cpssp);
      }
}

static void
chip_intel_82371AB_n_ferr_set(void *_css, unsigned int n_val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if(cpssp->state_ferr == 0 && n_val) {
            cpssp->state_ferr = 1;
            sig_boolean_or_set(cpssp->isa_bus_int[13], cpssp, 1);
      } else if(cpssp->state_ferr == 2 && !n_val) {
            cpssp->state_ferr = 0;
            sig_boolean_set(cpssp->sig_n_ignne, cpssp, 0);
      }
}

static void
chip_intel_82371AB_init_update(struct cpssp *cpssp)
{
      unsigned int n_init;

      n_init = ! cpssp->init_triggered;

      sig_boolean_set(cpssp->sig_n_init, cpssp, n_init);
}

static void
chip_intel_82371AB_init_event(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (cpssp->init_triggered) {
            cpssp->init_triggered = 0;
            chip_intel_82371AB_init_update(cpssp);
      }
}

static void
chip_intel_82371AB_init_trigger(struct cpssp *cpssp)
{
      cpssp->init_triggered = 1;
      time_call_after(TIME_HZ / 500,
                  chip_intel_82371AB_init_event, cpssp);
      chip_intel_82371AB_init_update(cpssp);
}

static void
chip_intel_82371AB_pwrok_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (val) {
            /* Power On Event */
            chip_intel_82371AB_reset_trigger(cpssp);
            chip_intel_82371AB_init_trigger(cpssp);
      }
}

static enum fw_target
chip_intel_82371AB_get_forward(
      struct cpssp *cpssp,
      unsigned long pa,
      unsigned int rw,
      unsigned long *start,
      unsigned long *end
)
{
      uint32_t mask;
      uint32_t addr;

      /*
       * Test forwarding to APIC.
       */
      mask = ~(((cpssp->apicbase >> 6) & 1) << 12);
      addr = 0xfec00000 | (((cpssp->apicbase >> 0) & 0x3f) << 10);
      if ((pa & mask) == addr
       || (pa & mask) == addr + 0x10) {
            /* I/O-APIC selected. */
            *start = addr;
            *end = *start + 0x20;
            return IOAPIC;
      }

      /*
       * Test forwarding to BIOS.
       */
      if ((0x000f0000 <= pa && pa <= 0x000fffff)
       || (0xffff0000 <= pa && pa <= 0xffffffff)) {
            /* Accessing top 64kBytes of BIOS */
            pa |= 0xfff00000;
            goto bios;
      }
      if (((cpssp->xbcs >> 6) & 1)
       && ((0x000e0000 <= pa && pa <= 0x000effff)
        || (0xfffe0000 <= pa && pa <= 0xfffeffff))) {
            /* Accessing lower 64kBytes of BIOS */
            pa |= 0xfff00000;
            goto bios;
      }
      if (((cpssp->xbcs >> 7) & 1)
       && ((0xfff80000 <= pa && pa <= 0xfffdffff))) {
            /* Accessing 384kBytes Extended BIOS */
            goto bios;
      }
      if (((cpssp->xbcs >> 9) & 1)
       && ((0xfff00000 <= pa && pa <= 0xfff7ffff))) {
            /* Accessing 1MByte Extended BIOS */
      bios:;
            *start = pa & 0x000f0000;
            *end = *start + 0x10000;
            return BIOS;
      }

      /* Forward to ISA */

      *start = pa & 0xffff0000;
      *end = *start + 0x10000;
      return ISA;
}


static int
chip_intel_82371AB_inb(void *_css, uint8_t *valp, uint16_t port)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      /*
       * 82371AB, pp. 44
       */
      switch (port) {
      case 0x0000 ... 0x001f:
            dma0_inb(cpssp, valp, port & 0xf);
            return 0;

      case 0x0020: case 0x0021: case 0x0024: case 0x0025:
      case 0x0028: case 0x0029: case 0x002c: case 0x002d:
      case 0x0030: case 0x0031: case 0x0034: case 0x0035:
      case 0x0038: case 0x0039: case 0x003c: case 0x003d:
            pic0_inb(cpssp, valp, port & 0x1);
            return 0;

      case 0x0040 ... 0x0043:
      case 0x0050 ... 0x0053:
            /* PIT 0 */
            pit_inb(cpssp, valp, port & 0x3);
            return 0;

      case 0x0060:
            /* Reset X-Bus IRQ12/M and IRQ1 */
            /* FIXME VOSSI */

            /* FALLTRHOUGH */
      case 0x0064:
            /* Keyboard Controller */
            if (1) {
                  sig_cs_readb(cpssp->sig_n_kbccs, cpssp, valp, port);
                  return 0;
            } else {
                  /* Forward to ISA Bus */
                  break;
            }

      case 0x0061: case 0x0063: case 0x0065: case 0x0067:
            /* PPI */
            ppi_inb(cpssp, valp);
            return 0;

      case 0x0072:
      case 0x0073:
            /* RTC */
            if ((cpssp->rtccfg >> 2) & 1) {
                  rtc_inb(cpssp, valp, port & 3);
                  return 0;
            }
            /*FALLTHROUGH*/
      case 0x0070: case 0x0074: case 0x0076:
      case 0x0071: case 0x0075: case 0x0077:
            rtc_inb(cpssp, valp, port & 1);
            return 0;

      case 0x0080: case 0x0090:
      case 0x0081: case 0x0091:
      case 0x0082: /* 0x0092: See below! */
      case 0x0083: case 0x0093:
      case 0x0084: case 0x0094:
      case 0x0085: case 0x0095:
      case 0x0086: case 0x0096:
      case 0x0087: case 0x0097:
      case 0x0088: case 0x0098:
      case 0x0089: case 0x0099:
      case 0x008a: case 0x009a:
      case 0x008b: case 0x009b:
      case 0x008c: case 0x009c:
      case 0x008d: case 0x009d:
      case 0x008e: case 0x009e:
      case 0x008f: case 0x009f:
            *valp = cpssp->dma_page[port & 0xf];
            return 0;

      case 0x0092:
            /* A20 gate */
            *valp = cpssp->r92;
            return 0;

      case 0x00a0: case 0x00a1: case 0x00a4: case 0x00a5:
      case 0x00a8: case 0x00a9: case 0x00ac: case 0x00ad:
      case 0x00b0: case 0x00b1: case 0x00b4: case 0x00b5:
      case 0x00b8: case 0x00b9: case 0x00bc: case 0x00bd:
            pic1_inb(cpssp, valp, port & 0x1);
            return 0;

      case 0x00b2: case 0x00b3:
            /* Advanced Power Management */
            power_inb(cpssp, valp, port);
            return 0;

      case 0x00c0 ... 0x00df:
            dma1_inb(cpssp, valp, (port >> 1) & 0xf);
            return 0;

      case 0x00f0:
            /* Coprocessor Error */
            fprintf(stderr,
                  "WARNING: Reading from write-only Coprocessor Error Register 0x%02x\n",
                  port);

            /* Forward to ISA Bus */
            break;

      case 0x04d0:
            /* PIC0 ELCR - Edge/Level Control Register */
            pic0_inb(cpssp, valp, 2);
            return 0;
      case 0x04d1:
            /* PIC1 ELCR - Edge/Level Control Register */
            pic1_inb(cpssp, valp, 2);
            return 0;

      case 0x0cf9:
            /* Reset Control */
            /* 82371AB (PIIX4) Page 88 */
            *valp = 0;
            return 0;

      default:
            break;
      }

      if (power_inb(cpssp, valp, port) == 0
       || usb_controller_inb(cpssp, valp, port) == 0
       || sig_isa_bus_inb(cpssp->sig_isa_bus, cpssp, valp, port) == 0) {
            return 0;
      }
      
      return 1;
}

static int
chip_intel_82371AB_inw(void *_css, uint16_t *valp, uint16_t port)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (power_inw(cpssp, valp, port) == 0
       || usb_controller_inw(cpssp, valp, port) == 0
       || sig_isa_bus_inw(cpssp->sig_isa_bus, cpssp, valp, port) == 0) {
            return 0;
      }

      return 1;
}

static int
chip_intel_82371AB_inl(void *_css, uint32_t *valp, uint16_t port)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (power_inl(cpssp, valp, port) == 0
       || usb_controller_inl(cpssp, valp, port) == 0) {
            return 0;
      }

      return 1;
}

static int
chip_intel_82371AB_ior(
      void *_css,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;
      uint8_t val8;
      uint16_t val16;
      int ret;

      assert(! (addr & 3));

      if (ide_ior(cpssp, addr, bs, valp) == 0) {
            return 0;
      }

      /* FIXME VOSSI */
      switch (bs) {
      case 0x1 << 0:
            ret = chip_intel_82371AB_inb(cpssp, &val8, addr + 0);
            if (ret == 0) {
                  *valp &= ~(0xff << 0);
                  *valp |= val8 << 0;
                  return 0;
            }
            break;
      case 0x1 << 1:
            ret = chip_intel_82371AB_inb(cpssp, &val8, addr + 1);
            if (ret == 0) {
                  *valp &= ~(0xff << 8);
                  *valp |= val8 << 8;
                  return 0;
            }
            break;
      case 0x1 << 2:
            ret = chip_intel_82371AB_inb(cpssp, &val8, addr + 2);
            if (ret == 0) {
                  *valp &= ~(0xff << 16);
                  *valp |= val8 << 16;
                  return 0;
            }
            break;
      case 0x1 << 3:
            ret = chip_intel_82371AB_inb(cpssp, &val8, addr + 3);
            if (ret == 0) {
                  *valp &= ~(0xff << 24);
                  *valp |= val8 << 24;
                  return 0;
            }
            break;
      case 0x3 << 0:
            ret = chip_intel_82371AB_inw(cpssp, &val16, addr + 0);
            if (ret == 0) {
                  *valp &= ~(0xffff << 0);
                  *valp |= val16 << 0;
                  return 0;
            }
            break;
      case 0x3 << 1:
            ret = chip_intel_82371AB_inb(cpssp, &val8, addr + 1);
            if (ret != 0) break;
            val16 = val8 << 8;
            ret = chip_intel_82371AB_inb(cpssp, &val8, addr + 2);
            if (ret == 0) {
                  val16 |= val8;
                  *valp &= ~(0xffff << 8);
                  *valp |= val16 << 8;
                  return 0;
            }
            break;
      case 0x3 << 2:
            ret = chip_intel_82371AB_inw(cpssp, &val16, addr + 2);
            if (ret == 0) {
                  *valp &= ~(0xffff << 16);
                  *valp |= val16 << 16;
                  return 0;
            }
            break;
      case 0xf << 0:
            ret = chip_intel_82371AB_inl(cpssp, valp, addr + 0);
            if (ret == 0) {
                  return 0;
            }
            break;
      default:
            fprintf(stderr, "%s 0x%08lx 0x%x\n", __FUNCTION__,
                        (unsigned long) addr, bs);
            assert(0);
      }
      return -1;
}

static int
chip_intel_82371AB_io_responsible(
      struct cpssp *cpssp,
      uint32_t port,
      unsigned int bs,
      int wflag
)
{
      /*
       * 82371AB (PIIX4), page 44.
       */
      switch (port) {
      case 0x0000:
      case 0x0004:
      case 0x0008:
      case 0x000c:
            return 1;

      case 0x0020: case 0x0024: case 0x0028: case 0x002c:
      case 0x0030: case 0x0034: case 0x0038: case 0x003c:
            if (bs == (1 << 0)
             || bs == (1 << 1)) {
                  return 1;
            }
            break;

      case 0x0040:
      case 0x0050:
            return 1;

      case 0x0060:
            if (bs == (1 << 0)
             || bs == (1 << 1)
             || bs == (1 << 3)) {
                  return 1;
            }
            break;

      case 0x0064:
            if (bs == (1 << 1)
             || bs == (1 << 3)) {
                  return 1;
            }
            break;

      /* Some missing - FIXME */

      case 0x00a0: case 0x00a4:
      case 0x00a8: case 0x00ac:
      case 0x00b0: case 0x00b4:
      case 0x00b8: case 0x00bc:
            if (bs == (1 << 0)
             || bs == (1 << 1)) {
                  return 1;
            }
            break;

      /* Some missing - FIXME */

      case 0x04d0:
            if (bs == (1 << 0)
             || bs == (1 << 1)) {
                  return 1;
            }
            break;

      /* Some missing - FIXME */

      }

      return 0;
}

static int
chip_intel_82371AB_ior_info(
      void *_css,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
      void **csp
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (chip_intel_82371AB_io_responsible(cpssp, port, bs, 0)) {
            *cfp = chip_intel_82371AB_ior;
            *csp = cpssp;
            return 0;
      }

      return ide_ior_info(cpssp, port, bs, cfp, csp);
}

static int
chip_intel_82371AB_outb(void *_css, uint8_t val, uint16_t port)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      /*
       * 82371AB, pp. 44
       */
      switch (port) {
      case 0x0000 ... 0x001f:
            dma0_outb(cpssp, val, port & 0xf);
            return 0;
      case 0x0020: case 0x0021: case 0x0024: case 0x0025:
      case 0x0028: case 0x0029: case 0x002c: case 0x002d:
      case 0x0030: case 0x0031: case 0x0034: case 0x0035:
      case 0x0038: case 0x0039: case 0x003c: case 0x003d:
            pic0_outb(cpssp, val, port & 0x1);
            return 0;

      case 0x0040 ... 0x0043:
      case 0x0050 ... 0x0053:
            /* PIT 0 */
            pit_outb(cpssp, val, port & 0x3);
            return 0;

      case 0x0060:
            /* Reset X-Bus IRQ12/M and IRQ1 */
            /* FIXME VOSSI */

            /* FALLTRHOUGH */
      case 0x0064:
            /* Keyboard Controller */
            if (1) {
                  sig_cs_writeb(cpssp->sig_n_kbccs, cpssp, val, port);
                  return 0;
            } else {
                  /* Forward to ISA Bus */
                  break;
            }

      case 0x0061: case 0x0063: case 0x0065: case 0x0067:
            /* PPI */
            ppi_outb(cpssp, val);
            return 0;

      case 0x0072:
      case 0x0073:
            /* RTC */
            if ((cpssp->rtccfg >> 2) & 1) {
                  rtc_outb(cpssp, val, port & 3);
                  return 0;
            }
            /*FALLTHROUGH*/
      case 0x0070: case 0x0074: case 0x0076:
      case 0x0071: case 0x0075: case 0x0077:
            rtc_outb(cpssp, val, port & 1);
            return 0;

      case 0x0080: case 0x0090:
      case 0x0081: case 0x0091:
      case 0x0082: /* 0x0092: See below! */
      case 0x0083: case 0x0093:
      case 0x0084: case 0x0094:
      case 0x0085: case 0x0095:
      case 0x0086: case 0x0096:
      case 0x0087: case 0x0097:
      case 0x0088: case 0x0098:
      case 0x0089: case 0x0099:
      case 0x008a: case 0x009a:
      case 0x008b: case 0x009b:
      case 0x008c: case 0x009c:
      case 0x008d: case 0x009d:
      case 0x008e: case 0x009e:
      case 0x008f: case 0x009f:
            cpssp->dma_page[port & 0xf] = val;
            return 0;

      case 0x0092:
            /* P92 -- Port 92 Register */
            /* 82371AB (PIIX4) Page 87 */

            /*
             * FAST_INIT
             *
             * On 0->1 Edge Trigger CPU Init.
             */
            if (! ((cpssp->r92 >> 0) & 1)
             && (val >> 0) & 1) {
                  /* Trigger CPU Init */
                  chip_intel_82371AB_init_trigger(cpssp);
            }
            cpssp->r92 &= ~(1 << 0);
            cpssp->r92 |= val & (1 << 0);

            /*
             * FAST_A20
             */
            cpssp->r92 &= ~(1 << 1);
            cpssp->r92 |= val & (1 << 1);
            chip_intel_82371AB_a20m_update(cpssp);
            return 0;

      case 0x00a0: case 0x00a1: case 0x00a4: case 0x00a5:
      case 0x00a8: case 0x00a9: case 0x00ac: case 0x00ad:
      case 0x00b0: case 0x00b1: case 0x00b4: case 0x00b5:
      case 0x00b8: case 0x00b9: case 0x00bc: case 0x00bd:
            pic1_outb(cpssp, val, port & 0x1);
            return 0;

      case 0x00b2: case 0x00b3:
            /* Advanced Power Management Control */
            power_outb(cpssp, val, port);
            return 0;

      case 0x00c0 ... 0x00df:
            dma1_outb(cpssp, val, (port >> 1) & 0xf);
            return 0;

      case 0x00f0:
            /* Coprocessor Error */
            if(cpssp->state_ferr == 1) {
                  cpssp->state_ferr = 2;
                  sig_boolean_set(cpssp->sig_n_ignne, cpssp, 1);
                  sig_boolean_or_set(cpssp->isa_bus_int[13], cpssp, 0);
            }
            /* FIXME VOSSI */
            fprintf(stderr,
                  "WARNING: Writing to unimplemented Coprocessor Error Register 0x%02x\n",
                  port);

            /* Forward to ISA Bus */
            break;

      case 0x04d0:
            /* PIC0 ELCR - Edge/Level Control Register */
            pic0_outb(cpssp, val, 2);
            return 0;
      case 0x04d1:
            /* PIC1 ELCR - Edge/Level Control Register */
            pic1_outb(cpssp, val, 2);
            return 0;

      case 0x0cf9:
            /* Reset Control */
            /* 82371AB (PIIX4) Page 88 */
            if ((val >> 1) & 1) {
                  /* Initiate hard reset to CPU. */
                  /* Do reset of CPU only - FIXME */
                  chip_intel_82371AB_reset_trigger(cpssp);
            } else {
                  /* Initiate soft reset to CPU. */
                  chip_intel_82371AB_init_trigger(cpssp);
            }
            return 0;

      default:
            break;
      }

      if (power_outb(cpssp, val, port) == 0
       || usb_controller_outb(cpssp, val, port) == 0
       || sig_isa_bus_outb(cpssp->sig_isa_bus, cpssp, val, port) == 0) {
            return 0;
      }

      return 1;
}

static int
chip_intel_82371AB_outw(void *_css, uint16_t val, uint16_t port)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (power_outw(cpssp, val, port) == 0
       || usb_controller_outw(cpssp, val, port) == 0
       || sig_isa_bus_outw(cpssp->sig_isa_bus, cpssp, val, port) == 0) {
            return 0;
      }

      return 1;
}

static int
chip_intel_82371AB_outl(void *_css, uint32_t val, uint16_t port)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (power_outl(cpssp, val, port) == 0
       || usb_controller_outl(cpssp, val, port) == 0) {
            return 0;
      }

      return 1;
}

static int
chip_intel_82371AB_iow(
      void *_css,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;
      uint8_t val8;
      uint16_t val16;
      int ret;

      assert(! (addr & 3));

      if (ide_iow(cpssp, addr, bs, val) == 0) {
            return 0;
      }

      /* FIXME VOSSI */
      switch (bs) {
      case 0x1 << 0:
            val8 = val >> 0;
            ret = chip_intel_82371AB_outb(cpssp, val8, addr + 0);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0x1 << 1:
            val8 = val >> 8;
            ret = chip_intel_82371AB_outb(cpssp, val8, addr + 1);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0x1 << 2:
            val8 = val >> 16;
            ret = chip_intel_82371AB_outb(cpssp, val8, addr + 2);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0x1 << 3:
            val8 = val >> 24;
            ret = chip_intel_82371AB_outb(cpssp, val8, addr + 3);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0x3 << 0:
            val16 = val >> 0;
            ret = chip_intel_82371AB_outw(cpssp, val16, addr + 0);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0x3 << 1:
            val16 = val >> 8;
            ret = chip_intel_82371AB_outw(cpssp, val16, addr + 1);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0x3 << 2:
            val16 = val >> 16;
            ret = chip_intel_82371AB_outw(cpssp, val16, addr + 2);
            if (ret == 0) {
                  return 0;
            }
            break;
      case 0xf << 0:
            ret = chip_intel_82371AB_outl(cpssp, val, addr + 0);
            if (ret == 0) {
                  return 0;
            }
            break;
      default:
            fprintf(stderr, "Byteselect: %0x\n",bs);
            assert(0);
      }
      return -1;
}

static int
chip_intel_82371AB_iow_info(
      void *_css,
      uint32_t port,
      unsigned int bs,
      int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
      void **csp
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if (chip_intel_82371AB_io_responsible(cpssp, port, bs, 1)) {
            *cfp = chip_intel_82371AB_iow;
            *csp = cpssp;
            return 0;
      }

      return ide_iow_info(cpssp, port, bs, cfp, csp);
}

static int
chip_intel_82371AB_mr(
      void *_css,
      uint32_t addr,
      unsigned int bs,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;
      unsigned long start;
      unsigned long end;
      int forward;
      uint8_t val8;
      uint16_t val16;
      int ret;

      forward = chip_intel_82371AB_get_forward(cpssp, addr, 2, &start, &end);

      switch (forward) {
      case IOAPIC:
            if (bs == 0xf) {
                  ret = sig_cs_readl(cpssp->sig_n_apiccs, cpssp, valp, (addr >> 4) & 1);
                  assert(ret == 0);
                  return 0;
            } else {
                  return -1;
            }

      case BIOS:
            *valp = 0;
            addr &= 0x000fffff;
            if ((bs >> 0) & 1) {
                  sig_cs_readb(cpssp->sig_n_bioscs, cpssp, &val8, addr + 0);
                  *valp |= val8 << 0;
            }
            if ((bs >> 1) & 1) {
                  sig_cs_readb(cpssp->sig_n_bioscs, cpssp, &val8, addr + 1);
                  *valp |= val8 << 8;
            }
            if ((bs >> 2) & 1) {
                  sig_cs_readb(cpssp->sig_n_bioscs, cpssp, &val8, addr + 2);
                  *valp |= val8 << 16;
            }
            if ((bs >> 3) & 1) {
                  sig_cs_readb(cpssp->sig_n_bioscs, cpssp, &val8, addr + 3);
                  *valp |= val8 << 24;
            }
            return 0;

      case ISA:
            ret = -1;

            *valp = 0;
            if (((bs >> 0) & 3) == 3) {
                  ret &= sig_isa_bus_readw(cpssp->sig_isa_bus, cpssp, addr + 0, &val16);
                  *valp |= val16 << 0;
            } else {
                  if ((bs >> 0) & 1) {
                        ret &= sig_isa_bus_readb(cpssp->sig_isa_bus, cpssp, addr + 0, &val8);
                        *valp |= val8 << 0;
                  }
                  if ((bs >> 1) & 1) {
                        ret &= sig_isa_bus_readb(cpssp->sig_isa_bus, cpssp, addr + 1, &val8);
                        *valp |= val8 << 8;
                  }
            }
            if (((bs >> 2) & 3) == 3) {
                  ret &= sig_isa_bus_readw(cpssp->sig_isa_bus, cpssp, addr + 2, &val16);
                  *valp |= val16 << 16;
            } else {
                  if ((bs >> 2) & 1) {
                        ret &= sig_isa_bus_readb(cpssp->sig_isa_bus, cpssp, addr + 2, &val8);
                        *valp |= val8 << 16;
                  }
                  if ((bs >> 3) & 1) {
                        ret &= sig_isa_bus_readb(cpssp->sig_isa_bus, cpssp, addr + 3, &val8);
                        *valp |= val8 << 24;
                  }
            }
            return ret;

      default:
            assert (0);
      }
}

static int
chip_intel_82371AB_mw(
      void *_css,
      uint32_t addr,
      unsigned int bs,
      uint32_t val
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;
      unsigned long start;
      unsigned long end;
      int forward;
      uint8_t val8;
      uint16_t val16;
      int ret;

      forward = chip_intel_82371AB_get_forward(cpssp, addr, 1, &start, &end);

      switch(forward) {
      case IOAPIC:
            /* FIXME VOSSI */
            if (bs == 0xf) {
                  ret = sig_cs_writel(cpssp->sig_n_apiccs, cpssp,
                              val, (addr >> 4) & 1);
                  assert(ret == 0);
                  return 0;
            }
            return -1;

      case BIOS:
            addr &= 0x000fffff;

            if (! ((cpssp->xbcs >> 2) & 1)) {
                  /* Write access disabled. */
                  /* Don't generate BIOSCS# */
                  /* 82371AB (PIIX4) page 58 */
                  return 0;
            }

            if ((bs >> 0) & 1) {
                  val8 = val >> 0;
                  sig_cs_writeb(cpssp->sig_n_bioscs, cpssp, val8, addr + 0);
            }
            if ((bs >> 1) & 1) {
                  val8 = val >> 8;
                  sig_cs_writeb(cpssp->sig_n_bioscs, cpssp, val8, addr + 1);
            }
            if ((bs >> 2) & 1) {
                  val8 = val >> 16;
                  sig_cs_writeb(cpssp->sig_n_bioscs, cpssp, val8, addr + 2);
            }
            if ((bs >> 3) & 1) {
                  val8 = val >> 24;
                  sig_cs_writeb(cpssp->sig_n_bioscs, cpssp, val8, addr + 3);
            }
            return 0;

      case ISA:
            ret = -1;
            if ((0x000e0000UL <= addr && addr <= 0x000fffffUL) 
             || (0xfff00000UL <= addr /* && addr <= 0xffffffffUL */)) {
                  faum_log(FAUM_LOG_ERROR, "82371AB", "",
                        "Writing to ISA-bus on region usually reserved for BIOS.\n");
            }
            if (((bs >> 0) & 3) == 3) {
                  val16 = val >> 0;
                  ret &= sig_isa_bus_writew(cpssp->sig_isa_bus, cpssp,
                              addr + 0, val16);
            } else {
                  if ((bs >> 0) & 1) {
                        val8 = val >> 0;
                        ret &= sig_isa_bus_writeb(cpssp->sig_isa_bus, cpssp,
                                    addr + 0, val8);
                  }
                  if ((bs >> 1) & 1) {
                        val8 = val >> 8;
                        ret &= sig_isa_bus_writeb(cpssp->sig_isa_bus, cpssp,
                                    addr + 1, val8);
                  }
            }
            if (((bs >> 2) & 3) == 3) {
                  val16 = val >> 16;
                  ret &= sig_isa_bus_writew(cpssp->sig_isa_bus, cpssp,
                              addr + 2, val16);
            } else {
                  if ((bs >> 2) & 1) {
                        val8 = val >> 16;
                        ret &= sig_isa_bus_writeb(cpssp->sig_isa_bus, cpssp,
                                    addr + 2, val8);
                  }
                  if ((bs >> 3) & 1) {
                        val8 = val >> 24;
                        ret &= sig_isa_bus_writeb(cpssp->sig_isa_bus, cpssp,
                                    addr + 3, val8);
                  }
            }
            return ret;

      default:
            assert (0);
      }
}


static int
chip_intel_82371AB_map(
      void *_css,
      unsigned long pa,
      unsigned int len,
      char **haddr_mr_p,
      char **haddr_mw_p
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;
      unsigned long start;
      unsigned long end;
      /* Forward to what */
      int forward;

      forward = chip_intel_82371AB_get_forward(cpssp, pa, 2, &start, &end);
      
      /* Forward access */
      switch (forward) {
      case IOAPIC:
            *haddr_mr_p = NULL;
            *haddr_mw_p = NULL;
            return 0;
      case BIOS:
            /* BIOS */
            /* FIXME JOSEF: bios on isa bus or not ? */
            /* Forward to ISA 16MB MB Limit */
            pa &= 0x000fffff;
            if (sig_cs_map(cpssp->sig_n_bioscs, cpssp, pa, len,
                              haddr_mr_p, haddr_mw_p) == 0) {
                  return 0;
            }
            break;
      case ISA:
            /* ISA bus */
            if (sig_isa_bus_map(cpssp->sig_isa_bus, cpssp, pa, len,
                              haddr_mr_p, haddr_mw_p) == 0) {
                  return 0;
            }
            break;
      default:
            assert(0);
      }

      return 1;
}

#if 0
static const unsigned char *
chip_intel_82371AB_ide_report(unsigned char addr)
{
      switch (addr) {
      case 0x00 ... 0x01: return ("Vendor ID"); /* read only */
      case 0x02 ... 0x03: return ("Device ID"); /* read only */
      case 0x04 ... 0x05: return ("PCI Command");
      case 0x06 ... 0x07: return ("PCI Device Status");
      case 0x08:          return ("Revision ID"); /* read only */
      case 0x09 ... 0x0B: return ("Class Code"); /* read only */
      case 0x0D:          return ("Master Latency Timing");
      case 0x0E:          return ("Header Type"); /* read only */
      case 0x10 ... 0x1F: return ("PCI Base Address (unused)");
      case 0x20 ... 0x23: return ("Bus Master Interface Base Address");
      case 0x24 ... 0x27: return ("PCI Base Address (unused)");
      case 0x30 ... 0x33: return ("PCI ROM Address (unused)");
      case 0x40 ... 0x41: return ("IDE Timing (Primary)");
      case 0x42 ... 0x43: return ("IDE Timing (Secondary)");
      case 0x44:          return ("Slave IDE Timing");
      case 0x48:          return ("Ultra DMA/33 Control");
      case 0x4A ... 0x4B: return ("Ultra DMA/33 Timing");
      case 0xFF:          return ("PCI Base Class Others (unused)");

      default:            return ("unknown");
      }
}
#endif

/* ----------------------------------------------------------------- */
/* PCI to ISA/EIO Bridge                                             */
/* ----------------------------------------------------------------- */

static void
_chip_intel_82371AB_cread(
      struct cpssp *cpssp,
      uint8_t addr,
      unsigned int bsel,
      uint32_t *valp
)
{
      assert(/* 0x00 <= addr && addr <= 0x100 && */ (addr & 0x3) == 0);
      assert(1 <= bsel && bsel <= 0xf);

      *valp = 0x00000000;

      switch (addr) {
      case 0x00:
            /* Vendor Identification Register */
            /* Page 53 */
            if ((bsel >> 0) & 1) {
                  *valp |= 0x86 << 0;
            }
            if ((bsel >> 1) & 1) {
                  *valp |= 0x80 << 8;
            }

            /* Device Identification Register */
            /* Page 53 */
            if ((bsel >> 2) & 1) {
                  *valp |= 0x10 << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= 0x71 << 24;
            }
            break;

      case 0x04:
            /* PCI Command Register */
            /* Page 54 */
            if ((bsel >> 0) & 1) {
                  *valp |= ((cpssp->pcicmd >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  *valp |= ((cpssp->pcicmd >> 8) & 0xff) << 8;
            }

            /* PCI Device Status Register */
            /* Page 55 */
            if ((bsel >> 2) & 1) {
                  *valp |= ((cpssp->pcists >> 0) & 0xff) << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= ((cpssp->pcists >> 8) & 0xff) << 24;
            }
            break;

      case 0x08:
            /* Revision Identification Register */
            /* Page 55 */
            if ((bsel >> 0) & 1) {
                  *valp |= 0x02 << 0; /* FIXME */
            }

            /* Class Code Register */
            /* Page 56 */
            if ((bsel >> 1) & 1) {
                  *valp |= 0x00 << 8;
            }
            if ((bsel >> 2) & 1) {
                  *valp |= 0x01 << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= 0x06 << 24;
            }
            break;

      case 0x0c:
            /* Unused */
            /* Unused */

            /* Header Type Register */
            /* Page 56 */
            if ((bsel >> 2) & 1) {
                  *valp |= 0x80 << 16;
            }

            /* Unused */
            break;

      case 0x10:
            /* PCI Base Address Register 0 */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x14:
            /* PCI Base Address Register 1 */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x18:
            /* PCI Base Address Register 2 */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x1c:
            /* PCI Base Address Register 3 */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x20:
            /* PCI Base Address Register 4 */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x24:
            /* PCI Base Address Register 5 */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x2c:
            /* Subsystem Vendor ID Register */
            /* Unused */
            /* Unused */

            /* Subsystem ID Register */
            /* Unused */
            /* Unused */
            break;

      case 0x30:
            /* PCI ROM Address Register */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x34:
            /* PCI Capability List Register */
            /* Unused */
            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x3c:
            /* PCI Interrupt Line Register */
            /* Unused */

            /* PCI Interrupt Pin Register */
            /* Unused */

            /* PCI Min Gnt Register */
            /* Unused */

            /* PCI Max Lat Register */
            /* Unused */
            break;

      case 0x4c:
            /* ISA I/O Recovery Timer Register */
            /* Page 56 */
            if ((bsel >> 0) & 1) {
                  *valp |= cpssp->iort << 0;
            }

            /* Unused */

            /* X-Bus Chip Select Register */
            /* Page 57 */
            if ((bsel >> 2) & 1) {
                  *valp |= ((cpssp->xbcs >> 0) & 0xff) << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= ((cpssp->xbcs >> 8) & 0xff) << 24;
            }
            break;

      case 0x60:
            /* PIRQx Route Control Registers. */
            /* Page 59 */
            if ((bsel >> 0) & 1) {
                  *valp |= cpssp->pirqrca << 0;
            }
            if ((bsel >> 1) & 1) {
                  *valp |= cpssp->pirqrcb << 8;
            }
            if ((bsel >> 2) & 1) {
                  *valp |= cpssp->pirqrcc << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= cpssp->pirqrcd << 24;
            }
            break;

      case 0x64:
            /* Serial IRQ Control Register */
            /* Page 59 */
            if ((bsel >> 0) & 1) {
                  *valp |= cpssp->serirqc << 0;
            }

            /* Unused */
            /* Unused */
            /* Unused */
            break;

      case 0x68:
            /* Unused */

            /* Top of Memory Register */
            /* Page 60 */
            if ((bsel >> 1) & 1) {
                  *valp |= cpssp->tom << 8;
            }

            /* Miscellaneous Status Register */
            /* Page 61 */
            if ((bsel >> 2) & 1) {
                  *valp |= ((cpssp->mstat >> 0) & 0xff) << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= ((cpssp->mstat >> 8) & 0xff) << 24;
            }
            break;

      case 0x74:
            /* Unused */
            /* Unused */

            /* Motherboard Device DMA Control Registers */
            /* Page 61 */
            if ((bsel >> 2) & 1) {
                  *valp |= cpssp->mbdma0 << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= cpssp->mbdma1 << 24;
            }
            break;

      case 0x80:
            /* APIC Base Address Relocation Register */
            /* Page 62 */
            if ((bsel >> 0) & 1) {
                  *valp |= cpssp->apicbase << 0;
            }

            /* Unused */

            /* Deterministic Latency Control Register */
            /* Page 62 */
            if ((bsel >> 2) & 1) {
                  *valp |= cpssp->dlc << 16;
            }

            /* Unused */
            break;

      case 0x90:
            /* PCI DMA Configuration Register */
            /* Page 63 */
            if ((bsel >> 0) & 1) {
                  *valp |= ((cpssp->pdmacfg >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  *valp |= ((cpssp->pdmacfg >> 8) & 0xff) << 8;
            }

            /* Distributed DMA Slave Base Pointer Registers */
            /* Page 64 */
            if ((bsel >> 2) & 1) {
                  *valp |= ((cpssp->ddmabp0 >> 0) & 0xff) << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= ((cpssp->ddmabp0 >> 8) & 0xff) << 24;
            }
            break;

      case 0x94:
            /* Distributed DMA Slave Base Pointer Registers */
            /* Page 64 */
            if ((bsel >> 0) & 1) {
                  *valp |= ((cpssp->ddmabp1 >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  *valp |= ((cpssp->ddmabp1 >> 8) & 0xff) << 8;
            }

            /* Unused */
            /* Unused */
            break;

      case 0xb0:
            /* General Configuration Register */
            /* Page 65 */
            if ((bsel >> 0) & 1) {
                  *valp |= ((cpssp->gencfg >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  *valp |= ((cpssp->gencfg >> 8) & 0xff) << 8;
            }
            if ((bsel >> 2) & 1) {
                  *valp |= ((cpssp->gencfg >> 16) & 0xff) << 16;
            }
            if ((bsel >> 3) & 1) {
                  *valp |= ((cpssp->gencfg >> 24) & 0xff) << 24;
            }
            break;

      case 0xcb:
            /* Unused */
            /* Unused */
            /* Unused */

            /* Real Time Clock Configuration */
            /* Page 67 */
            if ((bsel >> 3) & 1) {
                  *valp |= cpssp->rtccfg << 24;
            }
            break;

      default:
            fprintf(stderr, "WARNING: 82371AB: Reading");
            if ((bsel >> 0) & 1) {
                  fprintf(stderr, " 0x%02x", addr + 0);
                  *valp |= 0 << 0;
            }
            if ((bsel >> 1) & 1) {
                  fprintf(stderr, " 0x%02x", addr + 1);
                  *valp |= 0 << 8;
            }
            if ((bsel >> 2) & 1) {
                  fprintf(stderr, " 0x%02x", addr + 2);
                  *valp |= 0 << 16;
            }
            if ((bsel >> 3) & 1) {
                  fprintf(stderr, " 0x%02x", addr + 3);
                  *valp |= 0 << 24;
            }
            fprintf(stderr, " (Returning 0)\n");
            break;
      }
}

static void
_chip_intel_82371AB_cwrite(
      struct cpssp *cpssp,
      uint8_t addr,
      unsigned int bsel,
      uint32_t val
)
{
      assert(/* 0x00 <= addr && addr < 0x100 && */ (addr & 0x3) == 0);
      assert(0x1 <= bsel && bsel <= 0xf);

      switch (addr) {
      case 0x00:
            /* Vendor Identification */
            /* Page 53 */
            /* Read-only */
            /* Read-only */

            /* Device Identification */
            /* Page 53 */
            /* Read-only */
            /* Read-only */
            break;

      case 0x04:
            /* PCI Command */
            /* Page 54 */
            /* Some bits are hardwired to '0'/'1'. */
            if ((bsel >> 0) & 1) {
                  val &= ~(1 << 7); /* Address and Data Stepping Enable */
                  val &= ~(1 << 6); /* Parity Error Detect Enable */
                  val &= ~(1 << 5); /* VGA Palette Snoop Enable */
                  val &= ~(1 << 4); /* Memory Write and Invalidate */
                  val |=  (1 << 2); /* Bus Master */
                  val |=  (1 << 1); /* Memory Access */
                  val |=  (1 << 0); /* I/O Space Access */
                  cpssp->pcicmd &= ~(0xff << 0);
                  cpssp->pcicmd |= ((val >> 0) & 0xff) << 0;
            }
            /* Some bits are hardwired to '0'. */
            if ((bsel >> 1) & 1) {
                  val &= ~(1 << 15);      /* Reserved */
                  val &= ~(1 << 14);      /* Reserved */
                  val &= ~(1 << 13);      /* Reserved */
                  val &= ~(1 << 12);      /* Reserved */
                  val &= ~(1 << 11);      /* Reserved */
                  val &= ~(1 << 10);      /* Reserved */
                  val &= ~(1 <<  9);      /* Fast Back-to-Back Enable */
                  cpssp->pcicmd &= ~(0xff << 8);
                  cpssp->pcicmd |= ((val >> 8) & 0xff) << 8;
            }
            break;

            /* PCI Device Status Register */
            /* Page 55 */
            if ((bsel >> 2) & 1) {
                  /* Bit 7 is read-only. */
                  /* Bits 6-0 are reserved. */
            }
            if ((bsel >> 3) & 1) {
                  /* Bit 15 is read-only. */
                  if ((val >> (14+16)) & 1) {
                        cpssp->pcists &= ~(1 << 14);
                  }
                  if ((val >> (13+16)) & 1) {
                        cpssp->pcists &= ~(1 << 13);
                  }
                  if ((val >> (12+16)) & 1) {
                        cpssp->pcists &= ~(1 << 12);
                  }
                  if ((val >> (11+16)) & 1) {
                        cpssp->pcists &= ~(1 << 11);
                  }
                  /* Bits 10-9 are read-only. */
                  /* Bit 8 is read-only. */
            }
            break;

      case 0x08:
            /* Revision Identification Register */
            /* Page 55 */
            if ((bsel >> 0) & 1) {
                  /* Read-only */
            }

            /* Class Code Register */
            /* Page 56 */
            if ((bsel >> 1) & 1) {
                  /* Read-only */
            }
            if ((bsel >> 2) & 1) {
                  /* Read-only */
            }

            /* Header Type Register */
            /* Page 56 */
            if ((bsel >> 3) & 1) {
                  /* Read-only */
            }
            break;

      case 0x4c:
            /* ISA I/O Recovery Timer. */
            /* Page 56 */
            if ((bsel >> 0) & 1) {
                  cpssp->iort = (val >> 0) & 0xff;
            }

            if ((bsel >> 1) & 1) {
                  /* Unused */
            }

            /* X-Bus Chip Select Register */
            /* Page 57 */

            /* FIXME: flushes required / sufficient? */

            if ((bsel >> 2) & 1) {
                  unsigned int n_xbcs;

                  n_xbcs = cpssp->xbcs & 0xc4;

                  cpssp->xbcs &= ~(0xff << 0);
                  cpssp->xbcs |= ((val >> 16) & 0xff) << 0;

                  if (n_xbcs != (cpssp->xbcs & 0xc4)) {
                        /* Flush ISA's BIOS area. */
                        sig_pci_bus_unmap(cpssp->sig_pci_bus_main,
                                    cpssp, 0x000e0000, 0x20000);
                        /* Flush PCI's BIOS area. */
                        sig_pci_bus_unmap(cpssp->sig_pci_bus_main,
                                    cpssp, 0xfff00000, 0x100000);
                  }
            }
            if ((bsel >> 3) & 1) {
                  unsigned int n_xbcs;

                  n_xbcs = (cpssp->xbcs >> 8) & 2;

                  cpssp->xbcs &= ~(0xff << 8);
                  cpssp->xbcs |= ((val >> 24) & 0xff) << 8;

                  if(n_xbcs != ((cpssp->xbcs >> 8) & 2)) {
                        /* Flush ISA's BIOS area. */
                        sig_pci_bus_unmap(cpssp->sig_pci_bus_main,
                                    cpssp, 0x000e0000, 0x20000);
                        /* Flush PCI's BIOS area. */
                        sig_pci_bus_unmap(cpssp->sig_pci_bus_main,
                                    cpssp, 0xfff00000, 0x100000);
                  }
            }
            break;

            /* PIRQx Route Control Registers */
            /* Page 59 */
      case 0x60:
            if ((bsel >> 0) & 1) {
                  val &= 0x8f << 0;
                  cpssp->pirqrca = (val >> 0) & 0xff;
            }
            if ((bsel >> 1) & 1) {
                  val &= 0x8f << 8;
                  cpssp->pirqrcb = (val >> 8) & 0xff;
            }
            if ((bsel >> 2) & 1) {
                  val &= 0x8f << 16;
                  cpssp->pirqrcc = (val >> 16) & 0xff;
            }
            if ((bsel >> 3) & 1) {
                  val &= 0x8f << 24;
                  cpssp->pirqrcd = (val >> 24) & 0xff;
            }
            break;

      case 0x64:
            /* Serial IRQ Control Register */
            /* Page 59 */
            if ((bsel >> 0) & 1) {
                  cpssp->serirqc = (val >> 0) & 0xff;
            }

            if ((bsel >> 1) & 1) {
                  /* Unused */
            }
            if ((bsel >> 2) & 1) {
                  /* Unused */
            }
            if ((bsel >> 3) & 1) {
                  /* Unused */
            }
            break;

      case 0x69:
            if ((bsel >> 0) & 1) {
                  /* Unused */
            }

            /* Top of Memory Register */
            /* Page 60 */
            if ((bsel >> 1) & 1) {
                  val &= ~((1 << 0) << 8); /* Reserved */
                  cpssp->tom = (val >> 8) & 0xff;
            }

            /* Miscellaneous Status Register */
            /* Page 61 */
            if ((bsel >> 2) & 1) {
                  if ((val >> (7 + 16)) & 1) {
                        cpssp->mstat &= ~(1 << 7);
                  }
            }
            if ((bsel >> 3) & 1) {
                  if ((val >> (15 + 16)) & 1) {
                        cpssp->mstat &= ~(1 << 15);
                  }
            }
            break;

      case 0x76:
            if ((bsel >> 0) & 1) {
                  /* Unused */
            }
            if ((bsel >> 1) & 1) {
                  /* Unused */
            }
            
            /* Motherboard Device DMA Control Register */
            /* Page 61 */
            if ((bsel >> 2) & 1) {
                  val &= 0x8f << 16; /* Masking "reserved" bits. */
                  val |= 0x04 << 16; /* Hard-wired to '1' */
                  cpssp->mbdma0 = (val >> 16) & 0xff;
            }
            if ((bsel >> 3) & 1) {
                  val &= (0x8f << 24); /* Masking "reserved" bits. */
                  val |= (0x04 << 24); /* Hard-wired to '1' */
                  cpssp->mbdma1 = (val >> 24) & 0xff;
            }
            break;

      case 0x80:
            /* APIC Base Address Relocation Register */
            /* Page 62 */
            if ((bsel >> 0) & 1) {
                  fprintf(stderr, "Setting apicbase to 0x%02x\n", val & 0xff);
                  cpssp->apicbase = (val >> 0) & 0xff;
            }

            if ((bsel >> 1) & 1) {
                  /* Unused */
            }

            /* Deterministic Latency Control */
            /* Page 62 */
            if ((bsel >> 2) & 1) {
                  val &= 0x0f << 16; /* Masking "reserved" bits. */
                  cpssp->dlc = (val >> 16) & 0xff;
            }

            if ((bsel >> 3) & 1) {
                  /* Unused */
            }
            break;

      case 0x90:
            /* PCI DMA Configuration Register */
            /* Page 63 */
            if ((bsel >> 0) & 1) {
                  cpssp->pdmacfg &= ~(0xff << 0);
                  cpssp->pdmacfg |= ((val >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  val &= 0xfc << 8; /* Masking "reserved" bits. */
                  cpssp->pdmacfg &= ~(0xff << 8);
                  cpssp->pdmacfg |= ((val >> 8) & 0xff) << 8;
            }

            /* Distributed DMA Slave Base Pointer Registers */
            /* Page 64 */
            if ((bsel >> 2) & 1) {
                  val &= 0xc0 << 16; /* Masking "reserved" bits. */
                  cpssp->ddmabp0 &= ~(0xff << 0);
                  cpssp->ddmabp0 |= ((val >> 16) & 0xff) << 0;
            }
            if ((bsel >> 3) & 1) {
                  cpssp->ddmabp0 &= ~(0xff << 8);
                  cpssp->ddmabp0 |= ((val >> 24) & 0xff) << 8;
            }
            break;

      case 0x94:
            if ((bsel >> 0) & 1) {
                  val &= 0xc0 << 0; /* Masking "reserved" bits. */
                  cpssp->ddmabp1 &= ~(0xff << 0);
                  cpssp->ddmabp1 |= ((val >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  cpssp->ddmabp1 &= ~(0xff << 8);
                  cpssp->ddmabp1 |= ((val >> 8) & 0xff) << 8;
            }

            if ((bsel >> 2) & 1) {
                  /* Unused */
            }
            if ((bsel >> 3) & 1) {
                  /* Unused */
            }
            break;

      case 0xb0:
            /* General Configuration Register */
            /* Page 65 */
            if ((bsel >> 0) & 1) {
                  val &= 0x7f << 0; /* Masking "reserved" bits. */
                  cpssp->gencfg &= ~(0xff << 0);
                  cpssp->gencfg |= ((val >> 0) & 0xff) << 0;
            }
            if ((bsel >> 1) & 1) {
                  val &= 0xdf << 8; /* Masking "reserved" bits. */
                  cpssp->gencfg &= ~(0xff << 8);
                  cpssp->gencfg |= ((val >> 8) & 0xff) << 8;
            }
            if ((bsel >> 2) & 1) {
                  cpssp->gencfg &= ~(0xff << 16);
                  cpssp->gencfg |= ((val >> 16) & 0xff) << 16;
            }
            if ((bsel >> 3) & 1) {
                  val &= 0xfb << 24; /* Masking "reserved" bits. */
                  cpssp->gencfg &= ~(0xff << 24);
                  cpssp->gencfg |= ((val >> 24) & 0xff) << 24;
            }
            break;

      case 0xc8:
            if ((bsel >> 0) & 1) {
                  /* Unused */
            }
            if ((bsel >> 1) & 1) {
                  /* Unused */
            }
            if ((bsel >> 2) & 1) {
                  /* Unused */
            }

            /* Real Time Clock Configuration */
            /* Page 67 */
            if ((bsel >> 3) & 1) {
                  val &= ~(1 << (7 + 24));      /* Reserved */
                  val &= ~(1 << (6 + 24));      /* Reserved */
                  cpssp->rtccfg = (val >> 24) & 0xff;
            }
            break;

      default:
            if (addr < 0x40) {
                  /*
                   * Writing to reserved config space registers
                   * *below* 0x40 is allowed. Value written is
                   * discarded.
                   */
                  /* Nothing to do... */

            } else {
                  /*
                   * Writing to reserved config space registers
                   * *above* 0x3f is *not* allowed. Programming error.
                   */
                  faum_log(FAUM_LOG_WARNING, "82371AB (PCI to ISA/EIO)", "",
                              "Writing 0x%02x to reserved register 0x%02x.\n",
                              val, addr);
            }
            break;
      };
}

/* ----------------------------------------------------------------- */
/* Dispatcher                                                        */
/* ----------------------------------------------------------------- */

static void
chip_intel_82371AB_a20gate_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      cpssp->state_a20gate = val;

      chip_intel_82371AB_a20m_update(cpssp);
}

static int
chip_intel_82371AB_c0r(
      void *_css,
      uint32_t addr,
      unsigned int bsel,
      uint32_t *valp
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      switch ((addr >> 8) & 7) {
      case 0:
            _chip_intel_82371AB_cread(cpssp, addr & 0xfc, bsel, valp);
            return 0;
      case 1:
            ide_cread(cpssp, addr & 0xfc, bsel, valp);
            return 0;
      case 2:
            usb_controller_cread(cpssp, addr & 0xfc, bsel, valp);
            return 0;
      case 3:
            power_cread(cpssp, addr & 0xfc, bsel, valp);
            return 0;
      default:
            return -1;
      }
}

static int
chip_intel_82371AB_c0w(
      void *_css,
      uint32_t addr,
      unsigned int bsel,
      uint32_t val
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      switch ((addr >> 8) & 7) {
      case 0:
            _chip_intel_82371AB_cwrite(cpssp, addr & 0xfc, bsel, val);
            return 0;
      case 1:
            ide_cwrite(cpssp, addr & 0xfc, bsel, val);
            return 0;
      case 2:
            usb_controller_cwrite(cpssp, addr & 0xfc, bsel, val);
            return 0;
      case 3:
            power_cwrite(cpssp, addr & 0xfc, bsel, val);
            return 0;
      default:
            return -1;
      }
}

static int
chip_intel_82371AB_inta_addr(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_inta_begin(cpssp, &cpssp->state_inta);
      pic1_inta_begin(cpssp, &cpssp->state_inta);

      return 0;
}

static int
chip_intel_82371AB_inta_data(void *_css, uint8_t *valp)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_inta_end(cpssp);
      pic0_inta_end(cpssp);

      *valp = cpssp->state_inta;

      return 0;
}

static void
chip_intel_82371AB_pci_bus_intA_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if ((cpssp->pirqrca >> 7) & 1) {
            /* IRQ Routing for this line disabled. */
            return;
      }

      sig_boolean_or_set(cpssp->isa_bus_int[cpssp->pirqrca & 0xf], cpssp, val);
}

static void
chip_intel_82371AB_pci_bus_intB_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if ((cpssp->pirqrcb >> 7) & 1) {
            /* IRQ Routing for this line disabled. */
            return;
      }

      sig_boolean_or_set(cpssp->isa_bus_int[cpssp->pirqrcb & 0xf], cpssp, val);
}

static void
chip_intel_82371AB_pci_bus_intC_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if ((cpssp->pirqrcc >> 7) & 1) {
            /* IRQ Routing for this line disabled. */
            return;
      }

      sig_boolean_or_set(cpssp->isa_bus_int[cpssp->pirqrcc & 0xf], cpssp, val);
}

static void
chip_intel_82371AB_pci_bus_intD_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      if ((cpssp->pirqrcd >> 7) & 1) {
            /* IRQ Routing for this line disabled. */
            return;
      }

      sig_boolean_or_set(cpssp->isa_bus_int[cpssp->pirqrcd & 0xf], cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int0_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int0_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int1_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int1_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int3_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int3_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int4_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int4_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int5_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int5_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int6_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int6_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int7_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic0_isa_bus_int7_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int8_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int0_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_int9_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int1_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_intA_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int2_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_intB_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int3_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_intC_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int4_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_intD_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int5_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_intE_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int6_set(cpssp, val);
}

static void
chip_intel_82371AB_isa_bus_intF_set(void *_css, unsigned int val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      pic1_isa_bus_int7_set(cpssp, val);
}

static int
chip_intel_82371AB_isa_bus_dma0_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma0_req(cpssp, 0);

      return 0;
}

static int
chip_intel_82371AB_isa_bus_dma1_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma0_req(cpssp, 1);

      return 0;
}

static int
chip_intel_82371AB_isa_bus_dma2_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma0_req(cpssp, 2);

      return 0;
}

static int
chip_intel_82371AB_isa_bus_dma3_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma0_req(cpssp, 3);

      return 0;
}

static int
chip_intel_82371AB_isa_bus_dma5_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma1_req(cpssp, 1);

      return 0;
}

static int
chip_intel_82371AB_isa_bus_dma6_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma1_req(cpssp, 2);

      return 0;
}

static int
chip_intel_82371AB_isa_bus_dma7_req(void *_css)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      dma1_req(cpssp, 3);

      return 0;
}

static __attribute__((__noreturn__)) void
chip_intel_82371AB_usb0_reset_set(
      void *_css,
      int val
)
{
      assert(0);
}

static void
chip_intel_82371AB_usb0_speed_set(
      void *_css,
      int val
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb0_speed_set(cpssp, val);
}

static void
chip_intel_82371AB_usb0_recv_token(void *_css, int pid, int addr, int endp)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb0_recv_token(cpssp, pid, addr, endp);
}

static void
chip_intel_82371AB_usb0_recv_sof(
      void *_css,
      int frame_num
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb0_recv_sof(cpssp, frame_num);
}

static void
chip_intel_82371AB_usb0_recv_data(
      void *_css,
      int pid,
      unsigned int length,
      uint8_t *data,
      uint16_t crc16
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb0_recv_data(cpssp, pid, length, data, crc16);
}

static void
chip_intel_82371AB_usb0_recv_handshake(void *_css, int pid)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb0_recv_handshake(cpssp, pid);
}

static __attribute__((__noreturn__)) void
chip_intel_82371AB_usb1_reset_set(
      void *_css,
      int val
)
{
      assert(0);
}

static void
chip_intel_82371AB_usb1_speed_set(
      void *_css,
      int val
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb1_speed_set(cpssp, val);
}

static void
chip_intel_82371AB_usb1_recv_token(void *_css, int pid, int addr, int endp)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb1_recv_token(cpssp, pid, addr, endp);
}

static void
chip_intel_82371AB_usb1_recv_sof(
      void *_css,
      int frame_num
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb1_recv_sof(cpssp, frame_num);
}

static void
chip_intel_82371AB_usb1_recv_data(
      void *_css,
      int pid,
      unsigned int length,
      uint8_t *data,
      uint16_t crc16
)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb1_recv_data(cpssp, pid, length, data, crc16);
}

static void
chip_intel_82371AB_usb1_recv_handshake(void *_css, int pid)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      usb_controller_usb1_recv_handshake(cpssp, pid);
}

static void
chip_intel_82371AB_n_pwrbtn_set(void *_css, unsigned int n_val)
{
      struct cpssp *cpssp = (struct cpssp *) _css;

      switch (n_val) {
      case SIG_STD_LOGIC_0: n_val = 0; break;
      case SIG_STD_LOGIC_H: n_val = 1; break;
      default: return; /* Might happen during startup. */
      }

      power_n_button_set(cpssp, n_val);
}

void
chip_intel_82371AB_init(
      unsigned int nr,
      struct sig_pci_bus_main *port_pci_bus,
      struct sig_pci_bus_idsel *port_idsel,
      struct sig_boolean *port_pcirst_hash_,
      struct sig_isa_bus_main *port_isa_bus,
      struct sig_boolean *port_rstdrv_hash_,
      struct sig_boolean *port_a20gate,
      struct sig_cs *port_n_bios_cs,
      struct sig_cs *port_n_kbccs,
      struct sig_boolean *port_kbc_reset_hash_,
      struct sig_isa_bus_dma *port_dma0,
      struct sig_isa_bus_dma *port_dma1,
      struct sig_isa_bus_dma *port_dma2,
      struct sig_isa_bus_dma *port_dma3,
      struct sig_isa_bus_dma *port_dma5,
      struct sig_isa_bus_dma *port_dma6,
      struct sig_isa_bus_dma *port_dma7,
      struct sig_cs *port_ioapic_cs,
      struct sig_boolean_or *port_irq0,
      struct sig_boolean_or *port_irq1,
      struct sig_boolean_or *port_irq3,
      struct sig_boolean_or *port_irq4,
      struct sig_boolean_or *port_irq5,
      struct sig_boolean_or *port_irq6,
      struct sig_boolean_or *port_irq7,
      struct sig_boolean_or *port_irq8,
      struct sig_boolean_or *port_irq9,
      struct sig_boolean_or *port_irq10,
      struct sig_boolean_or *port_irq11,
      struct sig_boolean_or *port_irq12,
      struct sig_boolean_or *port_irq13,
      struct sig_boolean_or *port_irq14,
      struct sig_boolean_or *port_irq15,
      struct sig_boolean_or *port_pirqA_hash_,
      struct sig_boolean_or *port_pirqB_hash_,
      struct sig_boolean_or *port_pirqC_hash_,
      struct sig_boolean_or *port_pirqD_hash_,
      struct sig_boolean *port_a20m,
      struct sig_boolean *port_cpurst_hash_,
      struct sig_boolean *port_init_hash_,
      struct sig_boolean_or *port_ferr_hash_,
      struct sig_boolean *port_ignne_hash_,
      struct sig_boolean_or *port_intr,
      struct sig_boolean_or *port_nmi,
      struct sig_boolean *port_smi,
      struct sig_ide_bus *port_ide0,
      struct sig_ide_bus *port_ide1,
      struct sig_usb_bus_main *port_usb0,
      struct sig_usb_bus_main *port_usb1,
      struct sig_std_logic *port_power_btn_hash_,
      struct sig_std_logic *port_reset_btn_hash_,
      struct sig_i2c_bus *port_i2cbus,
      struct sig_boolean *port_n_susa,
      struct sig_boolean *port_n_susb,
      struct sig_std_logic *port_n_susc,
      struct sig_boolean *port_pwr_ok,
      struct sig_sound *port_spkr,
      struct sig_boolean *port_vcc,
      struct sig_boolean *port_vcc_rtc,
      struct sig_boolean *port_vcc_sus,
      struct sig_boolean *port_vcc_usb,
      struct sig_boolean *port_vref,

      /* FIXME */
      struct sig_boolean *port_ide_busy


)
{
      static const struct sig_pci_bus_main_funcs pci_bus_funcs = {
            .ior_info = chip_intel_82371AB_ior_info,
            .iow_info = chip_intel_82371AB_iow_info,
            .ior =            chip_intel_82371AB_ior,
            .iow =            chip_intel_82371AB_iow,

            .mr =       chip_intel_82371AB_mr,
            .mw =       chip_intel_82371AB_mw,
            .map =            chip_intel_82371AB_map,

            .inta_addr =      chip_intel_82371AB_inta_addr,
            .inta_data =      chip_intel_82371AB_inta_data,
      };
      static const struct sig_pci_bus_idsel_funcs idsel_funcs = {
            .c0r =            chip_intel_82371AB_c0r,
            .c0w =            chip_intel_82371AB_c0w,
      };
      static const struct sig_boolean_funcs a20gate_funcs = {
            .set = chip_intel_82371AB_a20gate_set,
      };
      static const struct sig_boolean_funcs kbc_reset_hash__funcs = {
            .set =      chip_intel_82371AB_rcin_set,
      };
      static const struct sig_isa_bus_dma_funcs dma0_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma0_req,
      };
      static const struct sig_isa_bus_dma_funcs dma1_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma1_req,
      };
      static const struct sig_isa_bus_dma_funcs dma2_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma2_req,
      };
      static const struct sig_isa_bus_dma_funcs dma3_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma3_req,
      };
      static const struct sig_isa_bus_dma_funcs dma5_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma5_req,
      };
      static const struct sig_isa_bus_dma_funcs dma6_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma6_req,
      };
      static const struct sig_isa_bus_dma_funcs dma7_funcs = {
            .req = chip_intel_82371AB_isa_bus_dma7_req,
      };
      static const struct sig_boolean_or_funcs irq0_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int0_set,
      };
      static const struct sig_boolean_or_funcs irq1_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int1_set,
      };
      static const struct sig_boolean_or_funcs irq3_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int3_set,
      };
      static const struct sig_boolean_or_funcs irq4_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int4_set,
      };
      static const struct sig_boolean_or_funcs irq5_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int5_set,
      };
      static const struct sig_boolean_or_funcs irq6_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int6_set,
      };
      static const struct sig_boolean_or_funcs irq7_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int7_set,
      };
      static const struct sig_boolean_or_funcs irq8_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int8_set,
      };
      static const struct sig_boolean_or_funcs irq9_funcs = {
            .set =      chip_intel_82371AB_isa_bus_int9_set,
      };
      static const struct sig_boolean_or_funcs irq10_funcs = {
            .set =      chip_intel_82371AB_isa_bus_intA_set,
      };
      static const struct sig_boolean_or_funcs irq11_funcs = {
            .set =      chip_intel_82371AB_isa_bus_intB_set,
      };
      static const struct sig_boolean_or_funcs irq12_funcs = {
            .set =      chip_intel_82371AB_isa_bus_intC_set,
      };
      static const struct sig_boolean_or_funcs irq13_funcs = {
            .set =      chip_intel_82371AB_isa_bus_intD_set,
      };
      static const struct sig_boolean_or_funcs irq14_funcs = {
            .set =      chip_intel_82371AB_isa_bus_intE_set,
      };
      static const struct sig_boolean_or_funcs irq15_funcs = {
            .set =      chip_intel_82371AB_isa_bus_intF_set,
      };
      static const struct sig_boolean_or_funcs pirqA_hash__funcs = {
            .set =      chip_intel_82371AB_pci_bus_intA_set,
      };
      static const struct sig_boolean_or_funcs pirqB_hash__funcs = {
            .set =      chip_intel_82371AB_pci_bus_intB_set,
      };
      static const struct sig_boolean_or_funcs pirqC_hash__funcs = {
            .set =      chip_intel_82371AB_pci_bus_intC_set,
      };
      static const struct sig_boolean_or_funcs pirqD_hash__funcs = {
            .set =      chip_intel_82371AB_pci_bus_intD_set,
      };
      static const struct sig_boolean_or_funcs ferr_hash__funcs = {
            .set =      chip_intel_82371AB_n_ferr_set,
      };
      static const struct sig_ide_bus_controller_funcs ide0_funcs = {
            .irq = ide0_irqrq_in_set,
            .dmarq_set = ide0_dmarq_set,
      };
      static const struct sig_ide_bus_controller_funcs ide1_funcs = {
            .irq = ide1_irqrq_in_set,
            .dmarq_set = ide1_dmarq_set,
      };
      static const struct sig_usb_bus_main_funcs usb0_funcs = {
            .reset_set = chip_intel_82371AB_usb0_reset_set,
            .speed_set = chip_intel_82371AB_usb0_speed_set,
            .recv_token = chip_intel_82371AB_usb0_recv_token,
            .recv_sof = chip_intel_82371AB_usb0_recv_sof,
            .recv_data = chip_intel_82371AB_usb0_recv_data,
            .recv_handshake = chip_intel_82371AB_usb0_recv_handshake,
      };
      static const struct sig_usb_bus_main_funcs usb1_funcs = {
            .reset_set = chip_intel_82371AB_usb1_reset_set,
            .speed_set = chip_intel_82371AB_usb1_speed_set,
            .recv_token = chip_intel_82371AB_usb1_recv_token,
            .recv_sof = chip_intel_82371AB_usb1_recv_sof,
            .recv_data = chip_intel_82371AB_usb1_recv_data,
            .recv_handshake = chip_intel_82371AB_usb1_recv_handshake,
      };
      static const struct sig_std_logic_funcs power_btn_hash__funcs = {
            .set = chip_intel_82371AB_n_pwrbtn_set,
      };
      static const struct sig_std_logic_funcs reset_btn_hash__funcs = {
            .set =      chip_intel_82371AB_n_rsmrst_set,
      };
      static const struct sig_i2c_bus_funcs i2cbus_funcs = {
            /* only acts as i2c master, not interested in begin called back */
            .read_byte = NULL,
      };
      static const struct sig_boolean_funcs pwr_ok_funcs = {
            .set =      chip_intel_82371AB_pwrok_set,
      };
      static const struct sig_boolean_funcs vcc_funcs = {
            .set =      chip_intel_82371AB_vcc_set,
      };
#if 0 /* FIXME */
      static const struct sig_boolean_funcs vcc_rtc_funcs = {
            /* FIXME */
      };
#endif
      static const struct sig_boolean_funcs vcc_sus_funcs = {
            .set =      chip_intel_82371AB_vcc_sus_set,
      };
      struct cpssp *cpssp;

      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      cpssp->speaker_period = (unsigned long long) -1;

      pic0_init(cpssp);
      pic1_init(cpssp);
      pit_init(cpssp);
      ppi_init(cpssp);
      dma0_init(cpssp);
      dma1_init(cpssp);
      ide_init(cpssp);
      usb_controller_init(cpssp);
      power_init(cpssp);
      rtc_init(cpssp);

      /* Call */
      cpssp->sig_pci_bus_main = port_pci_bus;
      sig_pci_bus_main_connect(port_pci_bus, cpssp, &pci_bus_funcs);

      sig_pci_bus_idsel_connect(port_idsel, cpssp, &idsel_funcs);

      cpssp->sig_isa_bus = port_isa_bus;

      cpssp->sig_n_bioscs = port_n_bios_cs;

      cpssp->sig_n_kbccs = port_n_kbccs;

      cpssp->sig_isa_bus_dma[0x0] = port_dma0;
      sig_isa_bus_dma_connect(port_dma0, cpssp, &dma0_funcs);

      cpssp->sig_isa_bus_dma[0x1] = port_dma1;
      sig_isa_bus_dma_connect(port_dma1, cpssp, &dma1_funcs);

      cpssp->sig_isa_bus_dma[0x2] = port_dma2;
      sig_isa_bus_dma_connect(port_dma2, cpssp, &dma2_funcs);

      cpssp->sig_isa_bus_dma[0x3] = port_dma3;
      sig_isa_bus_dma_connect(port_dma3, cpssp, &dma3_funcs);

      cpssp->sig_isa_bus_dma[0x4] = (void *) 0;

      cpssp->sig_isa_bus_dma[0x5] = port_dma5;
      sig_isa_bus_dma_connect(port_dma5, cpssp, &dma5_funcs);

      cpssp->sig_isa_bus_dma[0x6] = port_dma6;
      sig_isa_bus_dma_connect(port_dma6, cpssp, &dma6_funcs);

      cpssp->sig_isa_bus_dma[0x7] = port_dma7;
      sig_isa_bus_dma_connect(port_dma7, cpssp, &dma7_funcs);

      cpssp->sig_n_apiccs = port_ioapic_cs;

      cpssp->sig_ide[0] = port_ide0;
      sig_ide_bus_connect_controller(port_ide0, cpssp, &ide0_funcs);

      cpssp->sig_ide[1] = port_ide1;
      sig_ide_bus_connect_controller(port_ide1, cpssp, &ide1_funcs);

      cpssp->sig_usb[0] = port_usb0;
      sig_usb_bus_main_connect(port_usb0, cpssp, &usb0_funcs);

      cpssp->sig_usb[1] = port_usb1;
      sig_usb_bus_main_connect(port_usb1, cpssp, &usb1_funcs);

      cpssp->sig_i2cbus = port_i2cbus;
      sig_i2c_bus_connect_cooked(port_i2cbus, cpssp, &i2cbus_funcs);

      /* Out */
      cpssp->sig_n_pcirst = port_pcirst_hash_;
      sig_boolean_connect_out(port_pcirst_hash_, cpssp, 0);

      cpssp->sig_n_rstdrv = port_rstdrv_hash_;
      sig_boolean_connect_out(port_rstdrv_hash_, cpssp, 0);

      cpssp->isa_bus_int[0x0] = port_irq0;
      sig_boolean_or_connect_out(port_irq0, cpssp, 0);

      cpssp->isa_bus_int[0x1] = port_irq1;
      sig_boolean_or_connect_out(port_irq1, cpssp, 0);

      cpssp->isa_bus_int[0x3] = port_irq3;
      sig_boolean_or_connect_out(port_irq3, cpssp, 0);

      cpssp->isa_bus_int[0x4] = port_irq4;
      sig_boolean_or_connect_out(port_irq4, cpssp, 0);

      cpssp->isa_bus_int[0x5] = port_irq5;
      sig_boolean_or_connect_out(port_irq5, cpssp, 0);

      cpssp->isa_bus_int[0x6] = port_irq6;
      sig_boolean_or_connect_out(port_irq6, cpssp, 0);

      cpssp->isa_bus_int[0x7] = port_irq7;
      sig_boolean_or_connect_out(port_irq7, cpssp, 0);

      cpssp->isa_bus_int[0x8] = port_irq8;
      sig_boolean_or_connect_out(port_irq8, cpssp, 0);

      cpssp->isa_bus_int[0x9] = port_irq9;
      sig_boolean_or_connect_out(port_irq9, cpssp, 0);

      cpssp->isa_bus_int[0xA] = port_irq10;
      sig_boolean_or_connect_out(port_irq10, cpssp, 0);

      cpssp->isa_bus_int[0xB] = port_irq11;
      sig_boolean_or_connect_out(port_irq11, cpssp, 0);

      cpssp->isa_bus_int[0xC] = port_irq12;
      sig_boolean_or_connect_out(port_irq12, cpssp, 0);

      cpssp->isa_bus_int[0xD] = port_irq13;
      sig_boolean_or_connect_out(port_irq13, cpssp, 0);

      cpssp->isa_bus_int[0xE] = port_irq14;
      sig_boolean_or_connect_out(port_irq14, cpssp, 0);

      cpssp->isa_bus_int[0xF] = port_irq15;
      sig_boolean_or_connect_out(port_irq15, cpssp, 0);

      cpssp->pci_bus_int[3] = port_pirqD_hash_;
      sig_boolean_or_connect_out(port_pirqD_hash_, cpssp, 0);

      cpssp->sig_a20m = port_a20m;
      sig_boolean_connect_out(port_a20m, cpssp, 0);

      cpssp->sig_n_cpurst = port_cpurst_hash_;
      sig_boolean_connect_out(port_cpurst_hash_, cpssp, 0);

      cpssp->sig_n_init = port_init_hash_;
      sig_boolean_connect_out(port_init_hash_, cpssp, 0);

      cpssp->sig_n_ignne = port_ignne_hash_;
      sig_boolean_connect_out(port_ignne_hash_, cpssp, 0);

      cpssp->sig_intr = port_intr;
      sig_boolean_or_connect_out(port_intr, cpssp, 0);

      cpssp->sig_nmi = port_nmi;
      sig_boolean_or_connect_out(port_nmi, cpssp, 0);

      cpssp->sig_smi = port_smi;
      sig_boolean_connect_out(port_smi, cpssp, 0);

      cpssp->sig_n_susa = port_n_susa;

      cpssp->sig_n_susb = port_n_susb;

      cpssp->sig_n_susc = port_n_susc;
      sig_std_logic_connect_out(port_n_susc, cpssp, SIG_STD_LOGIC_Z);

      cpssp->sig_spkr = port_spkr;

      cpssp->sig_ide_busy = port_ide_busy;
      sig_boolean_connect_out(port_ide_busy, cpssp, 0);

      /* In */
      cpssp->sig_a20gate = port_a20gate;
      sig_boolean_connect_in(port_a20gate, cpssp, &a20gate_funcs);

      cpssp->sig_n_rcin = port_kbc_reset_hash_;
      sig_boolean_connect_in(port_kbc_reset_hash_, cpssp, &kbc_reset_hash__funcs);

      sig_boolean_or_connect_in(port_irq0, cpssp, &irq0_funcs);

      sig_boolean_or_connect_in(port_irq1, cpssp, &irq1_funcs);

      sig_boolean_or_connect_in(port_irq3, cpssp, &irq3_funcs);

      sig_boolean_or_connect_in(port_irq4, cpssp, &irq4_funcs);

      sig_boolean_or_connect_in(port_irq5, cpssp, &irq5_funcs);

      sig_boolean_or_connect_in(port_irq6, cpssp, &irq6_funcs);

      sig_boolean_or_connect_in(port_irq7, cpssp, &irq7_funcs);

      sig_boolean_or_connect_in(port_irq8, cpssp, &irq8_funcs);

      sig_boolean_or_connect_in(port_irq9, cpssp, &irq9_funcs);

      sig_boolean_or_connect_in(port_irq10, cpssp, &irq10_funcs);

      sig_boolean_or_connect_in(port_irq11, cpssp, &irq11_funcs);

      sig_boolean_or_connect_in(port_irq12, cpssp, &irq12_funcs);

      sig_boolean_or_connect_in(port_irq13, cpssp, &irq13_funcs);

      sig_boolean_or_connect_in(port_irq14, cpssp, &irq14_funcs);

      sig_boolean_or_connect_in(port_irq15, cpssp, &irq15_funcs);

      cpssp->pci_bus_int[0] = port_pirqA_hash_;
      sig_boolean_or_connect_in(port_pirqA_hash_, cpssp, &pirqA_hash__funcs);

      cpssp->pci_bus_int[1] = port_pirqB_hash_;
      sig_boolean_or_connect_in(port_pirqB_hash_, cpssp, &pirqB_hash__funcs);

      cpssp->pci_bus_int[2] = port_pirqC_hash_;
      sig_boolean_or_connect_in(port_pirqC_hash_, cpssp, &pirqC_hash__funcs);

      sig_boolean_or_connect_in(port_pirqD_hash_, cpssp, &pirqD_hash__funcs);

      cpssp->sig_n_ferr = port_ferr_hash_;
      sig_boolean_or_connect_in(port_ferr_hash_, cpssp, &ferr_hash__funcs);

      cpssp->sig_n_pwrbtn = port_power_btn_hash_;
      sig_std_logic_connect_in(port_power_btn_hash_, cpssp, &power_btn_hash__funcs);

      cpssp->sig_n_rsmrst = port_reset_btn_hash_;
      sig_std_logic_connect_in(port_reset_btn_hash_, cpssp, &reset_btn_hash__funcs);

      cpssp->sig_pwrok = port_pwr_ok;
      sig_boolean_connect_in(port_pwr_ok, cpssp, &pwr_ok_funcs);

      cpssp->sig_vcc = port_vcc;
      sig_boolean_connect_in(port_vcc, cpssp, &vcc_funcs);

      cpssp->sig_vcc_rtc = port_vcc_rtc;
#if 0 /* FIXME */
      sig_boolean_connect_in(port_vcc_rtc, cpssp, &vcc_rtc_funcs);
#endif

      cpssp->sig_vcc_sus = port_vcc_sus;
      sig_boolean_connect_in(port_vcc_sus, cpssp, &vcc_sus_funcs);

      cpssp->sig_vcc_usb = port_vcc_usb;

      cpssp->sig_vref = port_vref;

}

unsigned int
chip_intel_82371AB_create(const char *rtc_start)
{
      static unsigned int nr = 0;
      struct cpssp *cpssp;

      shm_create(COMP, nr, sizeof(*cpssp));
      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      usb_controller_create(cpssp, "(82371AB)", PCI_INT_D);
      rtc_create(cpssp, rtc_start);

      shm_unmap(cpssp, sizeof(*cpssp));

      return nr++;
}

void
chip_intel_82371AB_destroy(unsigned int nr)
{
      struct cpssp *cpssp;

      cpssp = shm_map(COMP, nr, sizeof(*cpssp), 0);

      rtc_destroy(cpssp);
      usb_controller_destroy(cpssp);

      shm_unmap(cpssp, sizeof(*cpssp));
      shm_destroy(COMP, nr);
}

Generated by  Doxygen 1.6.0   Back to index