/*
 * 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 host controller of the
 * Intel 440LX chipset.
 */

#ifdef STATE

struct {
	/*
	 * Config
	 */

	/*
	 * State
	 */
	uint8_t cache_line_size;
	uint8_t latency_timer;
	/* Aperture Base Address Register */
	uint32_t apbase;
	/* FIXME */
	/* DRAM Timing Register */
	uint8_t dramt;
	/* Programable Attribute Map Register */
	uint8_t pam0;
	uint8_t pam1[12];
	/* DRAM Boundary Register */
	uint8_t dbr[8];
	/* FIXME */
	/* Multi Transaction Timer Register */
	/* 56 */
	uint8_t mtt;
	/* System Management RAM Control Register */
	/* 55 */
	uint8_t dbaseseg;
	uint8_t smrame;
	uint8_t dlck;
	uint8_t dcls;
	uint8_t dopen;
	/* FIXME */
	/* Aperture Size Register */
	uint8_t apsize;
	/* FIXME */
	uint8_t confsp[0x100];

	int selected_smm;
	uint32_t selected_addr;
	uint32_t selected_type;

	uint32_t confadd; /* Currently addressed device/register */
} NAME;

#endif /* STATE */

#ifdef BEHAVIOR

enum NAME_(orig) {
	ORIG_HOST_BUS,
	ORIG_PCI_BUS,
};

/* ----------------------------------------------------------------- */
/* Built-In Functions                                                */
/* ----------------------------------------------------------------- */

/*
 * FIXME:
 * This (optional, for ACPI) register is used to disable both
 * the PCI and AGP arbiters in the chip to prevent any
 * external bus masters from acquiring the PCI or AGP bus.
 */
static int
NAME_(pm2_ctl_read)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int *bsp,
	uint32_t *datap
)
{
	if (((cpssp->NAME.confsp[0x7a] >> 6) & 1)
	 && addr == 0x0020
	 && (*bsp >> 2) & 1) {
		fprintf(stderr, "%s: Reading from unimplemented PM2_CTL register.\n",
				__FUNCTION__);

		*datap &= ~(0xff << 16);
		*datap |= 0x00 << 16;
		*bsp &= ~(1 << 2);
		return 0;
	}
	return 1;
}

static int
NAME_(pm2_ctl_write)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int *bsp,
	uint32_t data
)
{
	if (((cpssp->NAME.confsp[0x7a] >> 6) & 1)
	 && addr == 0x0020
	 && (*bsp >> 2) & 1) {
		data >>= 16;
		data &= 0xff;

		fprintf(stderr, "%s: writing 0x%02x%s to unimplemented PM2_CTL register\n",
				__FUNCTION__, data, (data & ~0x01) ? " (reserved bits!)" : "");

		*bsp &= ~(1 << 2);
		return 0;
	}
	return 1;
}

static int
NAME_(confadd_read)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int *bsp,
	uint32_t *datap
)
{
	if (addr == 0x0cf8
	 && *bsp == 0xf) {
		*datap = cpssp->NAME.confadd;
		*bsp &= ~0xf;
		return 0;
	}
	return 1;
}

static int
NAME_(confadd_write)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int *bsp,
	uint32_t data
)
{
	if (addr == 0x0cf8
	 && *bsp == 0xf) {
		uint32_t odata;

		data &= ~(1 << 30); /* Clear reserved bits. */
		data &= ~(1 << 29);
		data &= ~(1 << 28);
		data &= ~(1 << 27);
		data &= ~(1 << 26);
		data &= ~(1 << 25);
		data &= ~(1 << 24);
		data &= ~(1 <<  1);
		data &= ~(1 <<  0);

		odata = cpssp->NAME.confadd;
		cpssp->NAME.confadd = data;

		if (((odata >> 31) & 1) != ((data >> 31) & 1)) {
			NAME_(host_out_ior_info_flush)(cpssp, 0x0cfc, 0);
			NAME_(host_out_iow_info_flush)(cpssp, 0x0cfc, 0);
		}
		*bsp &= ~0xf;
		return 0;
	}
	return 1;
}

static void
NAME_(confdata_type_addr)(
	struct cpssp *cpssp,
	unsigned int *typep,
	uint32_t *addrp
)
{
	if ((*typep == SIG_HOST_BUS_IOR
	  || *typep == SIG_HOST_BUS_IOW)
	 && *addrp == 0x0cfc) {
		/*
		 * CONFDATA Register
		 */
		if (((cpssp->NAME.confadd >> 16) & 0xff) == 0x00) {
			/* Config Space Type 0 */
			uint32_t dev;
			uint32_t reg;

			dev = (cpssp->NAME.confadd >> 11) & 0x1f;
			reg = (cpssp->NAME.confadd >>  0) & 0x7fc;

			if (dev < 32 - 11) {
				dev = 1 << (11 + dev);
			} else {
				dev = 0;
			}

			*addrp = dev | reg;
			*typep = (*typep == SIG_HOST_BUS_IOR)
				? SIG_PCI_BUS_C0R : SIG_PCI_BUS_C0W;

		} else {
			/* Config Space Type 1 */
			*addrp = cpssp->NAME.confadd & ~3;
			*typep = (*typep == SIG_HOST_BUS_IOR)
				? SIG_PCI_BUS_C1R : SIG_PCI_BUS_C1W;
		}
	}
}

/*
 * This are helper functions - all config spaces writes, no matter if they
 * are byte, word or long accesses, get mapped to this.
 */
static void
NAME_(_pci_bus_cwriteb)(
	struct cpssp *cpssp,
	unsigned char addr,
	unsigned char val
)
{
	switch (addr) {
	case 0x00 ... 0x3f:
		/*
		 * Writing to reserved config space registers *below* 0x40
		 * is allowed. Value written is discarded.
		 */
		/* Nothing to do... */
		break;

		/* NBX Configuration Register */
		/* 3-16 */
	case 0x50: /* Bit 7-0 */
		val &= 0xec; /* Mask "reserved" bits */
		cpssp->NAME.confsp[addr] = val;
		break;
	case 0x51: /* Bit 15-8 */
		val &= 0xbf; /* Mask "reserved" bits */
		cpssp->NAME.confsp[addr] = val;
		break;
	case 0x52: /* Bit 23-16 */
		val &= 0x07; /* Mask "reserved" bits */
		cpssp->NAME.confsp[addr] = val;
		break;
	case 0x53: /* Bit 31-24 */
		cpssp->NAME.confsp[addr] = val;
		break;

		/* DRAM Control Register */
		/* 3-19 */
	case 0x57:
		/* Just remember settings. Not used by simulation. */
		val &= 0x3f;
		cpssp->NAME.confsp[addr] = val;
		break;

		/* Fixed DRAM Hole Control Register */
		/* 3-24 */
	case 0x68:
		val &= 0xc0; /* Mask "reserved" bits. */
		if (val != 0) {
			/* FIXME */
			fixme();
		}
		cpssp->NAME.confsp[addr] = val;
		break;

		/* Memory Buffer Strength Control Register */
		/* 3-25 */
	case 0x69 ... 0x6e:
		/* Just remember settings. Not used by simulation. */
		cpssp->NAME.confsp[addr] = val;
		break;

		/* Extended System Management RAM Control Register */
		/* 3-29 */
	case 0x73:
		goto unimplemented;

		/* SDRAM Row Page Size Register */
		/* 3-30 */
	case 0x74 ... 0x75:
		goto unimplemented;

		/* SDRAM Control Register */
		/* 3-30 */
	case 0x76 ... 0x77:
		goto unimplemented;

		/* Paging Policy Register */
		/* 3-32 */
	case 0x78 ... 0x79:
		goto unimplemented;

		/* Power Management Control Register */
		/* 3-33 */
	case 0x7A:
		val &= ~0x02; /* Bit 1 is read only */
		cpssp->NAME.confsp[addr] = val;

		NAME_(host_out_ior_info_flush)(cpssp, 0x0020, 1 << 2);
		NAME_(host_out_iow_info_flush)(cpssp, 0x0020, 1 << 2);
		break;

		/* Suspend CBR Refresh Rate Register */
		/* 3-34 */
	case 0x7b ... 0x7c:
		goto unimplemented;

		/* Error Address Pointer Register */
		/* 3-35 */
	case 0x80 ... 0x83:
		goto unimplemented;

		/* Error Command Register */
		/* 3-36 */
	case 0x90:
		/* Just remember settings. Not used by simulation. */
		cpssp->NAME.confsp[addr] = val;
		break;

		/* Error Status Register */
		/* 3-37 */
	case 0x91 ... 0x92:
		/* As we don't set any error bits we don't need to
		 * reset them... */
		break;

		/* AGP Capability Identifier Register */
		/* 3-38 */
	case 0xa0 ... 0xa3:
		goto unimplemented;

		/* AGP Status Register */
		/* 3-38 */
	case 0xa4 ... 0xa7:
		goto unimplemented;

		/* AGP Command Register */
		/* 3-39 */
	case 0xa8 ... 0xab:
		goto unimplemented;

		/* AGP Control Register */
		/* 3-40 */
	case 0xb0 ... 0xb3:
		goto unimplemented;

		/* Aperture Size Register */
		/* 3-41 */
	case 0xb4:
		val &= 0x3f; /* Masking "reserved" bits. */
		cpssp->NAME.confsp[addr] = val;
		break;

		/* Aperture Translation Table Base Register */
		/* 3-41 */
	case 0xb8 ... 0xbb:
		goto unimplemented;

		/* Memory Buffer Frequency Select Register */
		/* 3-42 */
	case 0xca ... 0xcc:
		goto unimplemented;

		/* BIOS Scratch Pad Register */
		/* 3-44 */
	case 0xd0 ... 0xd7:
		goto unimplemented;

		/* DRAM Write Thermal Throttling Control Register */
		/* 3-44 */
		/* Just remember settings. Not used by simulation. */
	case 0xe0: /* Bit 7-0 */
	case 0xe1: /* Bit 15-8 */
	case 0xe2: /* Bit 23-16 */
	case 0xe3: /* Bit 31-24 */
	case 0xe4: /* Bit 39-32 */
		if (! ((cpssp->NAME.confsp[0xe7] >> 7) & 1)) {
			cpssp->NAME.confsp[addr] = val;
		}
		break;
	case 0xe5: /* Bit 47-40 */
		if (! ((cpssp->NAME.confsp[0xe7] >> 7) & 1)) {
			val &= 0x3f; /* Masking "reserved" bits. */
			cpssp->NAME.confsp[addr] = val;
		}
		break;
	case 0xe6: /* Bit 55-48 */
		/* All bits "reserved". */
		break;
	case 0xe7: /* Bit 63-56 */
		if (! ((cpssp->NAME.confsp[0xe7] >> 7) & 1)) {
			val &= 0x80; /* Masking "reserved" bits. */
			cpssp->NAME.confsp[addr] = val;
		}
		break;

		/* DRAM Read Thermal Throttling Control Register */
		/* 3-46 */
		/* Just remember settings. Not used by simulation. */
	case 0xe8: /* Bit 7-0 */
	case 0xe9: /* Bit 15-8 */
	case 0xea: /* Bit 23-16 */
	case 0xeb: /* Bit 31-24 */
	case 0xec: /* Bit 39-32 */
		if (! ((cpssp->NAME.confsp[0xe7] >> 7) & 1)) {
			cpssp->NAME.confsp[addr] = val;
		}
		break;
	case 0xed: /* Bit 47-40 */
		if (! ((cpssp->NAME.confsp[0xe7] >> 7) & 1)) {
			val &= 0x3f; /* Masking "reserved" bits. */
			cpssp->NAME.confsp[addr] = val;
		}
		break;
	case 0xee: /* Bit 55-48 */
	case 0xef: /* Bit 63-56 */
		/* All bits "reserved". */
		break;

		/* Buffer Control Register */
		/* 3-47 */
	case 0xf0 ... 0xf1:
		goto unimplemented;

	unimplemented:;
		fprintf(stderr, "%s: Writing 0x%02x to unimplemented register 0x%02x.\n",
				__FUNCTION__, val, addr);
		break;

	default:
		fprintf(stderr, "%s: Writing 0x%02x to reserved register 0x%02x.\n",
				__FUNCTION__, val, addr);
		break;
	}
}

static void
NAME_(host_pci_bridge_c0r)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int bs,
	uint32_t *valp
)
{
	*valp = 0;
	switch (addr) {
	case 0x00:
		/* Vendor ID Register */
		*valp |= 0x8086 << 0;

		/* Device ID Register */
#if 1
		/* Device ID for LX chipset with AGP disabled */
		*valp |= 0x7180 << 16;
#else
		/* Device ID for BX chipset with AGP disabled */
		*valp |= 0x7192 << 16;
#endif
		break;

	case 0x04:
		/* Command Register */
		*valp |= 0x0006 << 0; /* FIXME */

		/* Status Register */
		*valp |= 0x2210 << 16; /* FIXME */
		break;

	case 0x08:
		/* Revision ID Register */
#if 1
		*valp |= 0x03 << 0;
#else
		*valp |= 0x02 << 0;
#endif

		/* Class Prog Register */
		*valp |= 0x00 << 8;

		/* Class Code Register */
		*valp |= 0x0600 << 16;
		break;

	case 0x0c:
		/* Cache Line Size Register */
		*valp |= cpssp->NAME.cache_line_size << 0;

		/* Latency Timer Register */
		*valp |= cpssp->NAME.latency_timer << 8;

		/* Header Type Register */
		*valp |= 0x00 << 16;

		/* BIST Register */
		*valp |= 0x00 << 24;
		break;

	case 0x10:
		/* APBASE Register */
		*valp |= 0b1000 << 0;
		*valp |= cpssp->NAME.apbase << (4-4);
		break;

	case 0x14:
		/* Reserved */
		*valp |= 0x00000000 << 0;
		break;

	/* FIXME */

	case 0x58:
		/* DRAM Timing Register */
		/* 3-20 */
		*valp |= cpssp->NAME.dramt << 0;

		*valp |= 0b0000 << 8; /* Reserved */

		/* Programable Attribute Map Register 0[7:4] */
		*valp |= cpssp->NAME.pam0 << 12;
		*valp |= 0b00 << 14; /* Reserved */

		/* Programable Attribute Map Register 1[3:0] */
		*valp |= cpssp->NAME.pam1[0] << 16;
		*valp |= 0b00 << 18; /* Reserved */

		/* Programable Attribute Map Register 1[7:4] */
		*valp |= cpssp->NAME.pam1[1] << 20;
		*valp |= 0b00 << 22; /* Reserved */

		/* Programable Attribute Map Register 2[3:0] */
		*valp |= cpssp->NAME.pam1[2] << 24;
		*valp |= 0b00 << 26; /* Reserved */

		/* Programable Attribute Map Register 2[7:4] */
		*valp |= cpssp->NAME.pam1[3] << 28;
		*valp |= 0b00 << 30; /* Reserved */
		break;

	case 0x5c:
		/* Programable Attribute Map Register 3[3:0] */
		*valp |= cpssp->NAME.pam1[4] << 0;
		*valp |= 0b00 << 2; /* Reserved */

		/* Programable Attribute Map Register 3[7:4] */
		*valp |= cpssp->NAME.pam1[5] << 4;
		*valp |= 0b00 << 6; /* Reserved */

		/* Programable Attribute Map Register 4[3:0] */
		*valp |= cpssp->NAME.pam1[6] << 8;
		*valp |= 0b00 << 10; /* Reserved */

		/* Programable Attribute Map Register 4[7:4] */
		*valp |= cpssp->NAME.pam1[7] << 12;
		*valp |= 0b00 << 14; /* Reserved */

		/* Programable Attribute Map Register 5[3:0] */
		*valp |= cpssp->NAME.pam1[8] << 16;
		*valp |= 0b00 << 18; /* Reserved */

		/* Programable Attribute Map Register 5[7:4] */
		*valp |= cpssp->NAME.pam1[9] << 20;
		*valp |= 0b00 << 22; /* Reserved */

		/* Programable Attribute Map Register 6[3:0] */
		*valp |= cpssp->NAME.pam1[10] << 24;
		*valp |= 0b00 << 26; /* Reserved */

		/* Programable Attribute Map Register 6[7:4] */
		*valp |= cpssp->NAME.pam1[11] << 28;
		*valp |= 0b00 << 30; /* Reserved */
		break;

	case 0x60:
		/* DRAM Boundary Register 0 */
		*valp |= cpssp->NAME.dbr[0] << 0;
		/* DRAM Boundary Register 1 */
		*valp |= cpssp->NAME.dbr[1] << 8;
		/* DRAM Boundary Register 2 */
		*valp |= cpssp->NAME.dbr[2] << 16;
		/* DRAM Boundary Register 3 */
		*valp |= cpssp->NAME.dbr[3] << 24;
		break;

	case 0x64:
		/* DRAM Boundary Register 4 */
		*valp |= cpssp->NAME.dbr[4] << 0;
		/* DRAM Boundary Register 5 */
		*valp |= cpssp->NAME.dbr[5] << 8;
		/* DRAM Boundary Register 6 */
		*valp |= cpssp->NAME.dbr[6] << 16;
		/* DRAM Boundary Register 7 */
		*valp |= cpssp->NAME.dbr[7] << 24;
		break;

	/* FIXME */

	case 0x70:
		/* Multi-Transaction Timer Register */
		/* 54 */
		*valp |= 0b000 << 0; /* Reserved */
		*valp |= cpssp->NAME.mtt << 3;

		*valp |= 0x00 << 8; /* Reserved */

		/* System Management RAM Control Register */
		/* 55 */
		*valp |= cpssp->NAME.dbaseseg << (0 + 16);
		*valp |= cpssp->NAME.smrame << (3 + 16);
		*valp |= cpssp->NAME.dlck << (4 + 16);
		*valp |= cpssp->NAME.dcls << (5 + 16);
		*valp |= cpssp->NAME.dopen << (6 + 16);
		*valp |= 0b0 << (7 + 16); /* Reserved */

		*valp |= 0x00 << 24; /* Reserved */
		break;

	case 0x74:
		/* Reserved */
		*valp |= 0x00000000 << 0;
		break;

	/* FIXME */

	case 0xb4:
		/* APSIZE Register */
		*valp |= cpssp->NAME.apsize << 0;
		*valp |= 0b00 << 6;

		/* Reserved */
		*valp |= 0b000000000000000000000000 << 8;
		break;

	case 0xb8:
		/* Aperture Translation Table Base Register */
		goto standard4;

	/* FIXME */

	default:
		/* FIXME */
	standard4:;
		*valp |= cpssp->NAME.confsp[addr + 0] << 0;
		*valp |= cpssp->NAME.confsp[addr + 1] << 8;
		*valp |= cpssp->NAME.confsp[addr + 2] << 16;
		*valp |= cpssp->NAME.confsp[addr + 3] << 24;
		break;
	}
}

static void
NAME_(host_pci_bridge_c0w)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int bs,
	uint32_t val
)
{
	switch (addr) {
	case 0x00:
		/* Vendor ID Register */
		if ((bs >> 0) & 1) {
			/* Read-only */
		}
		if ((bs >> 1) & 1) {
			/* Read-only */
		}

		/* Device ID Register */
		if ((bs >> 2) & 1) {
			/* Read-only */
		}
		if ((bs >> 3) & 1) {
			/* Read-only */
		}
		break;

	case 0x04:
		/* Command Register */
		/* FIXME */

		/* Status Register */
		/* FIXME */
		break;

	case 0x08:
		/* Revision ID Register */
		if ((bs >> 0) & 1) {
			/* Read-only */
		}

		/* Class Prog Register */
		if ((bs >> 1) & 1) {
			/* Read-only */
		}

		/* Class Code Register */
		if ((bs >> 2) & 1) {
			/* Read-only */
		}
		if ((bs >> 3) & 1) {
			/* Read-only */
		}
		break;

	case 0x0c:
		/* Cache Line Size Register */
		if ((bs >> 0) & 1) {
			cpssp->NAME.cache_line_size = (val >> 0) & 0xff;
		}

		/* Latency Timer Register */
		if ((bs >> 1) & 1) {
			cpssp->NAME.latency_timer = (val >> 8) & 0xff;
		}

		/* Header Type Register */
		if ((bs >> 2) & 1) {
			/* Read-only */
		}

		/* BIST Register */
		if ((bs >> 3) & 1) {
			/* Read-only */
		}
		break;

	case 0x10:
		/* APBASE Register */
		if ((bs >> 0) & 1) {
			cpssp->NAME.apbase &= ~(0xff << 0);
			cpssp->NAME.apbase |= val & (0x00 << 0);
		}
		if ((bs >> 1) & 1) {
			cpssp->NAME.apbase &= ~(0xff << 8);
			cpssp->NAME.apbase |= val & (0x00 << 8);
		}
		if ((bs >> 2) & 1) {
			cpssp->NAME.apbase &= ~(0xff << 16);
			cpssp->NAME.apbase |= val & ((0xc0 << 16) & (cpssp->NAME.apsize << 22));
		}
		if ((bs >> 3) & 1) {
			cpssp->NAME.apbase &= ~(0xff << 24);
			cpssp->NAME.apbase |= val & ((0xf0 << 24) | (cpssp->NAME.apsize << 2));
		}
		break;

	case 0x14:
		/* Reserved */
		if ((bs >> 0) & 1) {
			/* Reserved */
		}
		if ((bs >> 1) & 1) {
			/* Reserved */
		}
		if ((bs >> 2) & 1) {
			/* Reserved */
		}
		if ((bs >> 3) & 1) {
			/* Reserved */
		}
		break;

	/* FIXME */

	case 0x58:
		/* DRAM Timing Register */
		/* 3-20 */
		if ((bs >> 0) & 1) {
			cpssp->NAME.dramt = (val >> 0) & 0xff;
		}

		if ((bs >> 1) & 1) {
			/* Programable Attribute Map Register 0[7:4] */
			/* 46 */
			/* Bit 0-3: Reserved */
			cpssp->NAME.pam0 = (val >> 12) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000f0000, 0x10000);
			NAME_(pci_out_unmap)(cpssp, 0x000f0000, 0x10000);
		}
		if ((bs >> 2) & 1) {
			/* Programable Attribute Map Register 1[3:0] */
			/* 46 */
			cpssp->NAME.pam1[0] = (val >> 16) & 0b11;
			/* Bit 2-3: Reserved */

			/* Programable Attribute Map Register 1[7:4] */
			/* 46 */
			cpssp->NAME.pam1[1] = (val >> 20) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000c0000, 0x8000);
			NAME_(pci_out_unmap)(cpssp, 0x000c0000, 0x8000);
		}
		if ((bs >> 3) & 1) {
			/* Programable Attribute Map Register 2[3:0] */
			/* 46 */
			cpssp->NAME.pam1[2] = (val >> 24) & 0b11;
			/* Bit 2-3: Reserved */

			/* Programable Attribute Map Register 2[7:4] */
			/* 46 */
			cpssp->NAME.pam1[3] = (val >> 28) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000c8000, 0x8000);
			NAME_(pci_out_unmap)(cpssp, 0x000c8000, 0x8000);
		}
		break;

	case 0x5c:
		if ((bs >> 0) & 1) {
			/* Programable Attribute Map Register 3[3:0] */
			/* 46 */
			cpssp->NAME.pam1[4] = (val >> 0) & 0b11;
			/* Bit 2-3: Reserved */

			/* Programable Attribute Map Register 3[7:4] */
			/* 46 */
			cpssp->NAME.pam1[5] = (val >> 4) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000d0000, 0x8000);
			NAME_(pci_out_unmap)(cpssp, 0x000d0000, 0x8000);
		}
		if ((bs >> 1) & 1) {
			/* Programable Attribute Map Register 4[3:0] */
			/* 46 */
			cpssp->NAME.pam1[6] = (val >> 8) & 0b11;
			/* Bit 2-3: Reserved */

			/* Programable Attribute Map Register 4[7:4] */
			/* 46 */
			cpssp->NAME.pam1[7] = (val >> 12) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000d8000, 0x8000);
			NAME_(pci_out_unmap)(cpssp, 0x000d8000, 0x8000);
		}
		if ((bs >> 2) & 1) {
			/* Programable Attribute Map Register 5[3:0] */
			/* 46 */
			cpssp->NAME.pam1[8] = (val >> 16) & 0b11;
			/* Bit 2-3: Reserved */

			/* Programable Attribute Map Register 5[7:4] */
			/* 46 */
			cpssp->NAME.pam1[9] = (val >> 20) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000e0000, 0x8000);
			NAME_(pci_out_unmap)(cpssp, 0x000e0000, 0x8000);
		}
		if ((bs >> 3) & 1) {
			/* Programable Attribute Map Register 6[3:0] */
			/* 46 */
			cpssp->NAME.pam1[10] = (val >> 24) & 0b11;
			/* Bit 2-3: Reserved */

			/* Programable Attribute Map Register 6[7:4] */
			/* 46 */
			cpssp->NAME.pam1[11] = (val >> 28) & 0b11;
			/* Bit 6-7: Reserved */

			NAME_(host_out_unmap)(cpssp, 0x000e8000, 0x8000);
			NAME_(pci_out_unmap)(cpssp, 0x000e8000, 0x8000);
		}
		break;

	case 0x60:
		/* DRAM Boundary Register 0 */
		if ((bs >> 0) & 1) {
			cpssp->NAME.dbr[0] = (val >> 0) & 0xff;
		}
		/* DRAM Boundary Register 1 */
		if ((bs >> 1) & 1) {
			cpssp->NAME.dbr[1] = (val >> 8) & 0xff;
		}
		/* DRAM Boundary Register 2 */
		if ((bs >> 2) & 1) {
			cpssp->NAME.dbr[2] = (val >> 16) & 0xff;
		}
		/* DRAM Boundary Register 3 */
		if ((bs >> 3) & 1) {
			cpssp->NAME.dbr[3] = (val >> 24) & 0xff;
		}
		NAME_(host_out_unmap)(cpssp, 0x00000000, 0x40000000);
		NAME_(pci_out_unmap)(cpssp, 0x00000000, 0x40000000);
		break;

	case 0x64:
		/* DRAM Boundary Register 4 */
		if ((bs >> 0) & 1) {
			cpssp->NAME.dbr[4] = (val >> 0) & 0xff;
		}
		/* DRAM Boundary Register 5 */
		if ((bs >> 1) & 1) {
			cpssp->NAME.dbr[5] = (val >> 8) & 0xff;
		}
		/* DRAM Boundary Register 6 */
		if ((bs >> 2) & 1) {
			cpssp->NAME.dbr[6] = (val >> 16) & 0xff;
		}
		/* DRAM Boundary Register 7 */
		if ((bs >> 3) & 1) {
			cpssp->NAME.dbr[7] = (val >> 24) & 0xff;
		}
		NAME_(host_out_unmap)(cpssp, 0x00000000, 0x40000000);
		NAME_(pci_out_unmap)(cpssp, 0x00000000, 0x40000000);
		break;

	/* FIXME */

	case 0x70:
		/* Multi-Transaction Timer Register */
		/* 54 */
		if ((bs >> 0) & 1) {
			/* Bit 0-2: Reserved */
			cpssp->NAME.mtt = (val >> 3) & 0b11111;
		}

		if ((bs >> 1) & 1) {
			/* Reserved */
		}

		/* System Management RAM Control Register */
		/* 3-28, 55 */
		if ((bs >> 2) & 1) {
			cpssp->NAME.dbaseseg = (val >> (0 + 16)) & 0b111;
			cpssp->NAME.smrame = (val >> (3 + 16)) & 0b1;
			cpssp->NAME.dlck |= (val >> (4 + 16)) & 0b1;
			cpssp->NAME.dcls = (val >> (5 + 16)) & 0b1;
			cpssp->NAME.dopen = (! cpssp->NAME.dlck)
					& (val >> (6 + 16)) & 0b1;
			/* Bit 7: Reserved */

			/* SMRAM mapping may have changed */
			NAME_(host_out_unmap)(cpssp, 0x000a0000, 0x00020000);
			NAME_(pci_out_unmap)(cpssp, 0x000a0000, 0x00020000);
		}

		if ((bs >> 3) & 1) {
			/* Reserved */
		}
		break;

	case 0x74:
		/* Reserved */
		if ((bs >> 0) & 1) {
			/* Reserved */
		}
		if ((bs >> 1) & 1) {
			/* Reserved */
		}
		if ((bs >> 2) & 1) {
			/* Reserved */
		}
		if ((bs >> 3) & 1) {
			/* Reserved */
		}
		break;

	/* FIXME */

	case 0xb4:
		/* APSIZE Register */
		if ((bs >> 0) & 1) {
			cpssp->NAME.apsize = (val >> 0) & 0b111111;
			/* Bit 6-7: Reserved */
		}

		/* Reserved */
		if ((bs >> 1) & 1) {
			/* Reserved */
		}
		if ((bs >> 2) & 1) {
			/* Reserved */
		}
		if ((bs >> 3) & 1) {
			/* Reserved */
		}
		break;

	case 0xb8:
		/* Aperture Translation Table Base Register */
		goto standard4; /* FIXME */

	/* FIXME */

	default:
	standard4:;
		if ((bs >> 0) & 1) {
			NAME_(_pci_bus_cwriteb)(cpssp,
				addr + 0, (val >>  0) & 0xff);
		}
		if ((bs >> 1) & 1) {
			NAME_(_pci_bus_cwriteb)(cpssp,
				addr + 1, (val >>  8) & 0xff);
		}
		if ((bs >> 2) & 1) {
			NAME_(_pci_bus_cwriteb)(cpssp,
				addr + 2, (val >>  16) & 0xff);
		}
		if ((bs >> 3) & 1) {
			NAME_(_pci_bus_cwriteb)(cpssp,
				addr + 3, (val >>  24) & 0xff);
		}
		break;
	}
}

static int
NAME_(c0r)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int *bsp,
	uint32_t *valp
)
{
	if (((addr >> 11) & 1)		/* Device 0 */
	 && ((addr >> 8) & 7) == 0) {	/* Function 0 */
		/* Host/PCI Bridge */
		addr &= 0xff;
		NAME_(host_pci_bridge_c0r)(cpssp, addr, *bsp, valp);
		*bsp &= ~0xf;
		return 0;

	} else if (((addr >> 12) & 1)		/* Device 1 */
		&& ((addr >> 8) & 7) == 0) {	/* Function 0 */
		/* AGP - FIXME VOSSI */
		return -1;

	} else {
		return -1;
	}
}

static int
NAME_(c0w)(
	struct cpssp *cpssp,
	uint32_t addr,
	unsigned int *bsp,
	uint32_t val
)
{
	if (((addr >> 11) & 1)		/* Device 0 */
	 && ((addr >> 8) & 7) == 0) {	/* Function 0 */
		/* Host/PCI Bridge */
		addr &= 0xff;
		NAME_(host_pci_bridge_c0w)(cpssp, addr, *bsp, val);
		*bsp &= ~0xf;
		return 0;

	} else if (((addr >> 12) & 1)		/* Device 1 */
		&& ((addr >> 8) & 7) == 0) {	/* Function 0 */
		/* AGP - FIXME VOSSI */
		return -1;

	} else {
		return -1;
	}
}

/* --------------------------------------------------------------------- */
/* Memory Interface                                                      */
/* --------------------------------------------------------------------- */

static int
NAME_(region)(
	struct cpssp *cpssp,
	int wflag,
	unsigned int smm,
	uint32_t addr
)
{
	int region;
	unsigned int rw;

	if ((addr >> 23) < cpssp->NAME.dbr[0]) {
		region = 0;
	} else if ((addr >> 23) < cpssp->NAME.dbr[1]) {
		region = 1;
	} else if ((addr >> 23) < cpssp->NAME.dbr[2]) {
		region = 2;
	} else if ((addr >> 23) < cpssp->NAME.dbr[3]) {
		region = 3;
	} else if ((addr >> 23) < cpssp->NAME.dbr[4]) {
		region = 4;
	} else if ((addr >> 23) < cpssp->NAME.dbr[5]) {
		region = 5;
	} else if ((addr >> 23) < cpssp->NAME.dbr[6]) {
		region = 6;
	} else if ((addr >> 23) < cpssp->NAME.dbr[7]) {
		region = 7;
	} else {
		/* Shortcut */
		return -1;
	}

	if (/* 0x00000000 <= addr && */ addr < 0x000a0000) {
		/*
		 * Low memory.
		 */
		rw = 3;

	} else if (0x000a0000 <= addr && addr < 0x000c0000) {
		/*
		 * VGA hole / SMRAM
		 */
		if (cpssp->NAME.smrame
		 && (smm || cpssp->NAME.dopen)) {
			/* SMRAM */
			rw = 3;
		} else {
			/* VGA Hole */
			/* Shortcut */
			return -1;
		}

	} else if (0x000c0000 <= addr && addr < 0x000c4000) {
		rw = cpssp->NAME.pam1[0];

	} else if (0x000c4000 <= addr && addr < 0x000c8000) {
		rw = cpssp->NAME.pam1[1];

	} else if (0x000c8000 <= addr && addr < 0x000cc000) {
		rw = cpssp->NAME.pam1[2];

	} else if (0x000cc000 <= addr && addr < 0x000d0000) {
		rw = cpssp->NAME.pam1[3];

	} else if (0x000d0000 <= addr && addr < 0x000d4000) {
		rw = cpssp->NAME.pam1[4];

	} else if (0x000d4000 <= addr && addr < 0x000d8000) {
		rw = cpssp->NAME.pam1[5];

	} else if (0x000d8000 <= addr && addr < 0x000dc000) {
		rw = cpssp->NAME.pam1[6];

	} else if (0x000dc000 <= addr && addr < 0x000e0000) {
		rw = cpssp->NAME.pam1[7];

	} else if (0x000e0000 <= addr && addr < 0x000e4000) {
		rw = cpssp->NAME.pam1[8];

	} else if (0x000e4000 <= addr && addr < 0x000e8000) {
		rw = cpssp->NAME.pam1[9];

	} else if (0x000e8000 <= addr && addr < 0x000ec000) {
		rw = cpssp->NAME.pam1[10];

	} else if (0x000ec000 <= addr && addr < 0x000f0000) {
		rw = cpssp->NAME.pam1[11];

	} else if (0x000f0000 <= addr && addr < 0x00100000) {
		/*
		 * BIOS Area configured by PAM register 0x59.
		 */
		rw = cpssp->NAME.pam0;

	} else {
		/*
		 * High memory.
		 */
		rw = 3;
	}

	if (! (rw & (1 << wflag))) {
		return -1;
	}

	return region;
}

static int
NAME_(mem_mr)(
	struct cpssp *cpssp,
	int smm,
	uint32_t addr,
	unsigned int bs,
	uint32_t *valp
)
{
	int region;

	region = NAME_(region)(cpssp, 0, smm, addr);
	if (0 <= region
	 && region <= 7) {
		return NAME_(mem_out_read)(cpssp, region, addr, bs, valp);
	}
	return 1;
}

static int
NAME_(mem_mw)(
	struct cpssp *cpssp,
	int smm,
	uint32_t addr,
	unsigned int bs,
	uint32_t val
)
{
	int region;

	region = NAME_(region)(cpssp, 1, smm, addr);
	if (0 <= region
	 && region <= 7) {
		return NAME_(mem_out_write)(cpssp, region, addr, bs, val);
	}
	return 1;
}

static int
NAME_(mem_map_r)(
	struct cpssp *cpssp,
	enum NAME_(orig) orig,
	unsigned int smm,
	uint32_t addr,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
	void **csp,
	char **haddr_p
)
{
	int region;

	region = NAME_(region)(cpssp, 0, smm, addr);
	if (0 <= region
	 && region <= 7) {
		return NAME_(mem_out_map_r)(cpssp, region, addr,
				cfp, csp, haddr_p);
	}
	return 1;
}

static int
NAME_(mem_map_w)(
	struct cpssp *cpssp,
	enum NAME_(orig) orig,
	unsigned int smm,
	uint32_t addr,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
	void **csp,
	char **haddr_p
)
{
	int region;

	region = NAME_(region)(cpssp, 1, smm, addr);
	if (0 <= region
	 && region <= 7) {
		return NAME_(mem_out_map_w)(cpssp, region, addr,
				cfp, csp, haddr_p);
	}
	return 1;
}

static void
NAME_(memX_unmap)(void *_cpssp, uint32_t pa, uint32_t len)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	/* Should unmap interval [pa, pa + len) only - FIXME VOSSI */
	NAME_(host_out_unmap)(cpssp, 0, 1024*1024*1024);
	NAME_(pci_out_unmap)(cpssp, 0, 1024*1024*1024);
}

/* --------------------------------------------------------------------- */
/* DMI Interface                                                         */
/* --------------------------------------------------------------------- */

static int
NAME_(pci_read)(
	struct cpssp *cpssp,
	unsigned int type,
	uint32_t addr,
	unsigned int bs,
	uint32_t *valp
)
{
	int ret;

	switch (type) {
	case SIG_PCI_BUS_IOR:
		ret = NAME_(pci_out_ior)(cpssp, addr, bs, valp);
		break;
	case SIG_PCI_BUS_C0R:
		ret = NAME_(pci_out_main_c0r)(cpssp, addr, bs, valp);
		break;
	case SIG_PCI_BUS_C1R:
		ret = NAME_(pci_out_c1r)(cpssp, addr, bs, valp);
		break;
	case SIG_PCI_BUS_MR:
		ret = NAME_(pci_out_mr)(cpssp, addr, bs, valp);
		break;
	default:
		assert(0);
	}
	if (ret) {
		NAME_(pci_out_main_addr_type)(cpssp, addr, type);
		ret = NAME_(pci_out_main_read_data)(cpssp, bs, valp);
	}
	return ret;
}

static int
NAME_(pci_write)(
	struct cpssp *cpssp,
	unsigned int type,
	uint32_t addr,
	unsigned int bs,
	uint32_t val
)
{
	int ret;

	switch (type) {
	case SIG_PCI_BUS_IOW:
		ret = NAME_(pci_out_iow)(cpssp, addr, bs, val);
		break;
	case SIG_PCI_BUS_C0W:
		ret = NAME_(pci_out_main_c0w)(cpssp, addr, bs, val);
		break;
	case SIG_PCI_BUS_C1W:
		ret = NAME_(pci_out_c1w)(cpssp, addr, bs, val);
		break;
	case SIG_PCI_BUS_MW:
		ret = NAME_(pci_out_mw)(cpssp, addr, bs, val);
		break;
	default:
		assert(0);
	}
	if (ret) {
		NAME_(pci_out_main_addr_type)(cpssp, addr, type);
		ret = NAME_(pci_out_main_write_data)(cpssp, bs, val);
	}
	return ret;
}

static int
NAME_(pci_map_r)(
	struct cpssp *cpssp,
	uint32_t addr,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
	void **csp,
	char **haddr_p
)
{
	return NAME_(pci_out_map_r)(cpssp, addr, cfp, csp, haddr_p);
}

static int
NAME_(pci_map_w)(
	struct cpssp *cpssp,
	uint32_t addr,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
	void **csp,
	char **haddr_p
)
{
	return NAME_(pci_out_map_w)(cpssp, addr, cfp, csp, haddr_p);
}

/* --------------------------------------------------------------------- */
/* Internal Bus                                                          */
/* --------------------------------------------------------------------- */

static int
NAME_(ior)(
	void *_cpssp,
	uint32_t port,
	unsigned int bs,
	uint32_t *valp
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;
	unsigned int type;
	int ret;

	type = SIG_HOST_BUS_IOR;
	ret = 1;
	ret &= NAME_(pm2_ctl_read)(cpssp, port, &bs, valp);
	ret &= NAME_(confadd_read)(cpssp, port, &bs, valp);
	NAME_(confdata_type_addr)(cpssp, &type, &port);
	if (type == SIG_PCI_BUS_C0R) {
		ret &= NAME_(c0r)(cpssp, port, &bs, valp);
	}
	if (bs) {
		ret &= NAME_(pci_read)(cpssp, type, port, bs, valp);
	}

	return ret;
}

static int
NAME_(iow)(
	void *_cpssp,
	uint32_t port,
	unsigned int bs,
	uint32_t val
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;
	unsigned int type;
	int ret;

	type = SIG_HOST_BUS_IOW;
	ret = 1;
	ret &= NAME_(pm2_ctl_write)(cpssp, port, &bs, val);
	ret &= NAME_(confadd_write)(cpssp, port, &bs, val);
	NAME_(confdata_type_addr)(cpssp, &type, &port);
	if (type == SIG_PCI_BUS_C0W) {
		ret &= NAME_(c0w)(cpssp, port, &bs, val);
	}
	if (bs) {
		ret &= NAME_(pci_write)(cpssp, type, port, bs, val);
	}

	return ret;
}

static int
NAME_(ior_info)(
	struct cpssp *cpssp,
	enum NAME_(orig) orig,
	uint32_t port,
	unsigned int bs,
	int (**cf)(void *, uint32_t, unsigned int, uint32_t *),
	void **cs
)
{
	if (port == 0x0020
	 || port == 0x0cf8
	 || port == 0x0cfc) {
		*cf = NAME_(ior);
		*cs = cpssp;
		return 0;
	} else {
		return NAME_(pci_out_ior_info)(cpssp, port, bs, cf, cs);
	}
}

static int
NAME_(iow_info)(
	struct cpssp *cpssp,
	enum NAME_(orig) orig,
	uint32_t port,
	unsigned int bs,
	int (**cf)(void *, uint32_t, unsigned int, uint32_t),
	void **cs
)
{
	if (port == 0x0020
	 || port == 0x0cf8
	 || port == 0x0cfc) {
		*cf = NAME_(iow);
		*cs = cpssp;
		return 0;
	} else {
		return NAME_(pci_out_iow_info)(cpssp, port, bs, cf, cs);
	}
}

static int
NAME_(mem_read)(
	struct cpssp *cpssp,
	enum NAME_(orig) orig,
	unsigned int smm,
	uint32_t addr,
	unsigned int bs,
	uint32_t *valp
)
{
	if (NAME_(mem_mr)(cpssp, smm, addr, bs, valp) == 0
	 || (orig != ORIG_PCI_BUS
	  && NAME_(pci_read)(cpssp, SIG_PCI_BUS_MR, addr, bs, valp) == 0)) {
		return 0;
	}
	return 1;
}

static int
NAME_(mem_write)(
	struct cpssp *cpssp,
	enum NAME_(orig) orig,
	unsigned int smm,
	uint32_t addr,
	unsigned int bs,
	uint32_t val
)
{
	if (NAME_(mem_mw)(cpssp, smm, addr, bs, val) == 0
	 || (orig != ORIG_PCI_BUS
	  && NAME_(pci_write)(cpssp, SIG_PCI_BUS_MW, addr, bs, val) == 0)) {
		return 0;
	}
	return 1;
}

static int
NAME_(map_r)(
	void *_cpssp,
	enum NAME_(orig) orig,
	unsigned int smm,
	uint32_t addr,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
	void **csp,
	char **haddr_p
)
{
	struct cpssp *cpssp = _cpssp;

	if (NAME_(mem_map_r)(cpssp, ORIG_HOST_BUS, smm, addr, cfp, csp, haddr_p) == 0
	 || NAME_(pci_map_r)(cpssp, addr, cfp, csp, haddr_p) == 0) {
		return 0;
	}
	return 1;
}

static int
NAME_(map_w)(
	void *_cpssp,
	enum NAME_(orig) orig,
	unsigned int smm,
	uint32_t addr,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
	void **csp,
	char **haddr_p
)
{
	struct cpssp *cpssp = _cpssp;

	if (NAME_(mem_map_w)(cpssp, ORIG_HOST_BUS, smm, addr, cfp, csp, haddr_p) == 0
	 || NAME_(pci_map_w)(cpssp, addr, cfp, csp, haddr_p) == 0) {
		return 0;
	}
	return 1;
}

/* ----------------------------------------------------------------- */
/* Host Bus Interface                                                */
/* ----------------------------------------------------------------- */

static int
NAME_(host_bus_ior)(
	void *_cpssp,
	uint32_t port,
	unsigned int bs,
	uint32_t *valp
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(ior)(cpssp, port, bs, valp);
}

static int
NAME_(host_bus_iow)(
	void *_cpssp,
	uint32_t port,
	unsigned int bs,
	uint32_t val
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(iow)(cpssp, port, bs, val);
}

static int
NAME_(host_bus_ior_info)(
	void *_cpssp,
	uint32_t port,
	unsigned int bs,
	int (**cf)(void *, uint32_t, unsigned int, uint32_t *),
	void **cs
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(ior_info)(cpssp, ORIG_HOST_BUS, port, bs, cf, cs);
}

static int
NAME_(host_bus_iow_info)(
	void *_cpssp,
	uint32_t port,
	unsigned int bs,
	int (**cf)(void *, uint32_t, unsigned int, uint32_t),
	void **cs
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(iow_info)(cpssp, ORIG_HOST_BUS, port, bs, cf, cs);
}

static int
NAME_(host_bus_inta_addr)(
	void *_cpssp
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(pci_out_inta_addr)(cpssp);
}

static int
NAME_(host_bus_inta_data)(
	void *_cpssp,
	uint8_t *valp
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(pci_out_inta_data)(cpssp, valp);
}

static int
NAME_(host_bus_mr)(
	void *_cpssp,
	unsigned int smm,
	uint32_t addr,
	unsigned int bs,
	uint32_t *valp
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(mem_read)(cpssp, ORIG_HOST_BUS,
			smm, addr, bs, valp);
}

static int
NAME_(host_bus_mw)(
	void *_cpssp,
	unsigned int smm,
	uint32_t addr,
	unsigned int bs,
	uint32_t val
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	return NAME_(mem_write)(cpssp, ORIG_HOST_BUS,
			smm, addr, bs, val);
}

/* Re-used as NAME_(host_bus_map_x_check). */
static int
NAME_(host_bus_map_r_check)(
	void *_cpssp,
	unsigned int smm,
	uint32_t pa
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	/* SMM? FIXME */
	return NAME_(pci_out_map_r_check)(cpssp, pa);
}

/* Re-used as NAME_(host_bus_map_x). */
static int
NAME_(host_bus_map_r)(
	void *_cpssp,
	unsigned int smm,
	uint32_t pa,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
	void **csp,
	char **haddr_p
)
{
	struct cpssp *cpssp = _cpssp;

	return NAME_(map_r)(cpssp, ORIG_HOST_BUS, smm, pa, cfp, csp, haddr_p);
}

static int
NAME_(host_bus_map_w_check)(
	void *_cpssp,
	unsigned int smm,
	uint32_t pa
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	/* SMM? FIXME */
	return NAME_(pci_out_map_w_check)(cpssp, pa);
}

static int
NAME_(host_bus_map_w)(
	void *_cpssp,
	unsigned int smm,
	uint32_t pa,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
	void **csp,
	char **haddr_p
)
{
	struct cpssp *cpssp = _cpssp;

	return NAME_(map_w)(cpssp, ORIG_HOST_BUS, smm, pa, cfp, csp, haddr_p);
}

static int
NAME_(host_bus_addr_type)(
	void *_cpssp,
	unsigned int smm,
	uint32_t addr,
	unsigned int type
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	cpssp->NAME.selected_smm = smm;
	cpssp->NAME.selected_addr = addr;
	cpssp->NAME.selected_type = type;

	return 0;
}

static int
NAME_(host_bus_read_data)(
	void *_cpssp,
	unsigned int bs,
	uint32_t *valp
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;
	int smm;
	unsigned int type;
	uint32_t addr;

	smm = cpssp->NAME.selected_smm;
	addr = cpssp->NAME.selected_addr;
	type = cpssp->NAME.selected_type;

	cpssp->NAME.selected_addr += 4;

	switch (type) {
	case SIG_HOST_BUS_IOR:
		return NAME_(host_bus_ior)(cpssp, addr, bs, valp);
	case SIG_HOST_BUS_MR:
		return NAME_(host_bus_mr)(cpssp, smm, addr, bs, valp);
	default:
		assert(0);
	}
}

static int
NAME_(host_bus_write_data)(
	void *_cpssp,
	unsigned int bs,
	uint32_t val
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;
	int smm;
	unsigned int type;
	uint32_t addr;

	smm = cpssp->NAME.selected_smm;
	addr = cpssp->NAME.selected_addr;
	type = cpssp->NAME.selected_type;

	cpssp->NAME.selected_addr += 4;

	switch (type) {
	case SIG_HOST_BUS_IOW:
		return NAME_(host_bus_iow)(cpssp, addr, bs, val);
	case SIG_HOST_BUS_MW:
		return NAME_(host_bus_mw)(cpssp, smm, addr, bs, val);
	default:
		assert(0);
	}
}

/* ----------------------------------------------------------------- */
/* PCI Bus Interface                                                 */
/* ----------------------------------------------------------------- */

static int
NAME_(pci_bus_mr)(
	void *_cpssp,
	uint32_t addr,
	unsigned int bs,
	uint32_t *valp
)
{
	struct cpssp *cpssp = _cpssp;

	return NAME_(mem_read)(cpssp, ORIG_PCI_BUS,
			0, addr, bs, valp);
}

static int
NAME_(pci_bus_mw)(
	void *_cpssp,
	uint32_t addr,
	unsigned int bs,
	uint32_t val
)
{
	struct cpssp *cpssp = _cpssp;

	return NAME_(mem_write)(cpssp, ORIG_PCI_BUS,
			0, addr, bs, val);
}

static int
NAME_(pci_bus_map_r_check)(
	void *_cpssp,
	uint32_t pa
)
{
	struct cpssp *cpssp = _cpssp;

	/* SMM? FIXME */
	return NAME_(host_out_map_r_check)(cpssp, 0, pa);
}

static int
NAME_(pci_bus_map_r)(
	void *_cpssp,
	uint32_t pa,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t *),
	void **csp,
	char **haddr_p
)
{
	struct cpssp *cpssp = _cpssp;

	return NAME_(map_r)(cpssp, ORIG_PCI_BUS, 0, pa, cfp, csp, haddr_p);
}

static int
NAME_(pci_bus_map_w_check)(
	void *_cpssp,
	uint32_t pa
)
{
	struct cpssp *cpssp = _cpssp;

	/* SMM? FIXME */
	return NAME_(host_out_map_w_check)(cpssp, 0, pa);
}

static int
NAME_(pci_bus_map_w)(
	void *_cpssp,
	uint32_t pa,
	int (**cfp)(void *, uint32_t, unsigned int, uint32_t),
	void **csp,
	char **haddr_p
)
{
	struct cpssp *cpssp = _cpssp;

	return NAME_(map_w)(cpssp, ORIG_PCI_BUS, 0, pa, cfp, csp, haddr_p);
}

static void
NAME_(pci_bus_unmap)(
	void *_cpssp,
	uint32_t pa,
	uint32_t len
)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;

	NAME_(host_out_unmap)(cpssp, pa, len);
}

static void
NAME_(power_set)(void *_cpssp, unsigned int val)
{
	/* FIXME */
}

static void
NAME_(n_reset_set)(void *_cpssp, unsigned int n_val)
{
	struct cpssp *cpssp = (struct cpssp *) _cpssp;
	int i;

	cpssp->NAME.cache_line_size = 0x00;
	cpssp->NAME.latency_timer = 0x00;

	/* Programable Attribute Map Registers */
	cpssp->NAME.pam0 = 0b00;
	for (i = 0; i < 12; i++) {
		cpssp->NAME.pam1[i] = 0b00;
	}

	/* DRAM Boundary Registers */
	for (i = 0; i < 8; i++) {
		cpssp->NAME.dbr[i] = 0x01;
	}

	/* Multi-Transaction Timer Register */
	cpssp->NAME.mtt = 0b00000;

	/* System Management RAM Control Register */
	/* 55 */
	cpssp->NAME.dbaseseg = 0b010;
	cpssp->NAME.smrame = 0b0;
	cpssp->NAME.dlck = 0b0;
	cpssp->NAME.dcls = 0b0;
	cpssp->NAME.dopen = 0b0;

	memset(cpssp->NAME.confsp, 0, sizeof(cpssp->NAME.confsp));
}

#endif /* BEHAVIOR */
