xbox: initial skeleton!

This commit is contained in:
espes 2012-10-20 18:12:34 +11:00
parent 8b4a3df808
commit d823f5802e
16 changed files with 2181 additions and 6 deletions

132
hw/acpi_mcpx.c Normal file
View File

@ -0,0 +1,132 @@
/*
* ACPI implementation
*
* Copyright (c) 2006 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
/*
* Copyright (C) 2012 espes
*
* Based on acpi.c, acpi_ich9.c, acpi_piix4.c
*/
#include "hw.h"
#include "pc.h"
#include "pci.h"
#include "qemu-timer.h"
#include "sysemu.h"
#include "acpi.h"
#include "acpi_mcpx.h"
#define DEBUG
#ifdef DEBUG
# define MCPX_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define MCPX_DPRINTF(format, ...) do { } while (0)
#endif
static void mcpx_pm_update_sci_gn(ACPIREGS *regs)
{
MCPX_PMRegs *pm = container_of(regs, MCPX_PMRegs, acpi_regs);
//pm_update_sci(pm);
}
#define MCPX_PMIO_PM1_STS 0x0
#define MCPX_PMIO_PM1_EN 0x2
#define MCPX_PMIO_PM1_CNT 0x4
#define MCPX_PMIO_PM_TMR 0x8
static void mcpx_pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
uint64_t val)
{
MCPX_PMRegs *pm = container_of(ioport, MCPX_PMRegs, ioport);
switch (addr) {
case MCPX_PMIO_PM1_STS:
acpi_pm1_evt_write_sts(&pm->acpi_regs, val);
//pm_update_sci(pm);
break;
case MCPX_PMIO_PM1_EN:
pm->acpi_regs.pm1.evt.en = val;
//pm_update_sci(pm);
break;
case MCPX_PMIO_PM1_CNT:
acpi_pm1_cnt_write(&pm->acpi_regs, val, 0);
break;
default:
break;
}
MCPX_DPRINTF("PM: write port=0x%04x val=0x%04x\n",
(unsigned int)addr, (unsigned int)val);
}
static void mcpx_pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width,
uint64_t *data)
{
MCPX_PMRegs *pm = container_of(ioport, MCPX_PMRegs, ioport);
uint32_t val;
switch (addr) {
case MCPX_PMIO_PM1_STS:
val = acpi_pm1_evt_get_sts(&pm->acpi_regs);
break;
case MCPX_PMIO_PM1_EN:
val = pm->acpi_regs.pm1.evt.en;
break;
case MCPX_PMIO_PM1_CNT:
val = pm->acpi_regs.pm1.cnt.cnt;
break;
case MCPX_PMIO_PM_TMR:
val = acpi_pm_tmr_get(&pm->acpi_regs);
break;
default:
val = 0;
break;
}
MCPX_DPRINTF("PM: read port=0x%04x val=0x%04x\n",
(unsigned int)addr, (unsigned int)val);
*data = val;
}
static const IORangeOps mcpx_iorange_ops = {
.read = mcpx_pm_ioport_read,
.write = mcpx_pm_ioport_write,
};
void mcpx_pm_iospace_update(MCPX_PMRegs *pm, uint32_t pm_io_base) {
MCPX_DPRINTF("PM: iospace update to 0x%x\n", pm_io_base);
//Disabled when 0
if (pm_io_base != 0) {
iorange_init(&pm->ioport, &mcpx_iorange_ops, pm_io_base, 256);
ioport_register(&pm->ioport);
}
}
void mcpx_pm_init(MCPX_PMRegs *pm/*, qemu_irq sci_irq*/) {
acpi_pm_tmr_init(&pm->acpi_regs, mcpx_pm_update_sci_gn);
acpi_pm1_cnt_init(&pm->acpi_regs);
//acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
//pm->irq = sci_irq;
}

36
hw/acpi_mcpx.h Normal file
View File

@ -0,0 +1,36 @@
/*
* QEMU MCPX PM Emulation
*
* Copyright (c) 2012 espes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#ifndef HW_ACPI_MCPX_H
#define HW_ACPI_MCPX_H
#include "acpi.h"
typedef struct MCPX_PMRegs {
IORange ioport;
ACPIREGS acpi_regs;
qemu_irq irq;
} MCPX_PMRegs;
void mcpx_pm_init(MCPX_PMRegs *pm /*, qemu_irq sci_irq*/);
void mcpx_pm_iospace_update(MCPX_PMRegs *pm, uint32_t pm_io_base);
#endif

206
hw/amd_smbus.c Normal file
View File

@ -0,0 +1,206 @@
#include "hw.h"
#include "pc.h"
#include "amd_smbus.h"
#include "smbus.h"
/* AMD756 SMBus address offsets */
#define SMB_ADDR_OFFSET 0xE0
#define SMB_IOSIZE 16
#define SMB_GLOBAL_STATUS 0x0
#define SMB_GLOBAL_ENABLE 0x2
#define SMB_HOST_ADDRESS 0x4
#define SMB_HOST_DATA 0x6
#define SMB_HOST_COMMAND 0x8
#define SMB_HOST_BLOCK_DATA 0x9
#define SMB_HAS_DATA 0xA
#define SMB_HAS_DEVICE_ADDRESS 0xC
#define SMB_HAS_HOST_ADDRESS 0xE
#define SMB_SNOOP_ADDRESS 0xF
/* AMD756 constants */
#define AMD756_QUICK 0x00
#define AMD756_BYTE 0x01
#define AMD756_BYTE_DATA 0x02
#define AMD756_WORD_DATA 0x03
#define AMD756_PROCESS_CALL 0x04
#define AMD756_BLOCK_DATA 0x05
/*
SMBUS event = I/O 28-29 bit 11
see E0 for the status bits and enabled in E2
*/
#define GS_ABRT_STS (1 << 0)
#define GS_COL_STS (1 << 1)
#define GS_PRERR_STS (1 << 2)
#define GS_HST_STS (1 << 3)
#define GS_HCYC_STS (1 << 4)
#define GS_TO_STS (1 << 5)
#define GS_SMB_STS (1 << 11)
#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
GS_HCYC_STS | GS_TO_STS )
#define GE_CYC_TYPE_MASK (7)
#define GE_HOST_STC (1 << 3)
#define GE_ABORT (1 << 5)
#define DEBUG
#ifdef DEBUG
# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define SMBUS_DPRINTF(format, ...) do { } while (0)
#endif
static void amd756_smb_transaction(AMD756SMBus *s)
{
uint8_t prot = s->smb_ctl & GE_CYC_TYPE_MASK;
uint8_t read = s->smb_addr & 0x01;
uint8_t cmd = s->smb_cmd;
uint8_t addr = (s->smb_addr >> 1) & 0x7f;
i2c_bus *bus = s->smbus;
SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
switch(prot) {
case AMD756_QUICK:
smbus_quick_command(bus, addr, read);
break;
case AMD756_BYTE:
if (read) {
s->smb_data0 = smbus_receive_byte(bus, addr);
} else {
smbus_send_byte(bus, addr, cmd);
}
break;
case AMD756_BYTE_DATA:
if (read) {
s->smb_data0 = smbus_read_byte(bus, addr, cmd);
} else {
smbus_write_byte(bus, addr, cmd, s->smb_data0);
}
break;
case AMD756_WORD_DATA:
if (read) {
uint16_t val;
val = smbus_read_word(bus, addr, cmd);
s->smb_data0 = val;
//s->smb_data1 = val >> 8;
} else {
smbus_write_word(bus, addr, cmd, s->smb_data0);
}
break;
case AMD756_BLOCK_DATA:
if (read) {
s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
} else {
smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
}
break;
default:
goto error;
}
s->smb_stat |= GS_HCYC_STS;
return;
error:
s->smb_stat |= GS_PRERR_STS;
}
void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
AMD756SMBus *s = opaque;
addr &= 0x3f;
SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
switch(addr) {
case SMB_GLOBAL_STATUS:
//s->smb_stat = 0;
if (val & GS_CLEAR_STS) {
s->smb_stat = 0;
s->smb_index = 0;
} else if (val & GS_HCYC_STS) {
s->smb_stat = GS_HCYC_STS;
s->smb_index = 0;
} else {
s->smb_stat = GS_HCYC_STS;
s->smb_index = 0;
}
break;
case SMB_GLOBAL_ENABLE:
s->smb_ctl = val;
if (val & GE_ABORT)
s->smb_stat |= GS_ABRT_STS;
if (val & GE_HOST_STC)
amd756_smb_transaction(s);
break;
case SMB_HOST_COMMAND:
s->smb_cmd = val;
break;
case SMB_HOST_ADDRESS:
s->smb_addr = val;
break;
case SMB_HOST_DATA:
s->smb_data0 = val;
break;
/*case SMBHSTDAT1:
s->smb_data1 = val;
break;*/
case SMB_HOST_BLOCK_DATA:
s->smb_data[s->smb_index++] = val;
if (s->smb_index > 31)
s->smb_index = 0;
break;
default:
break;
}
}
uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr)
{
AMD756SMBus *s = opaque;
uint32_t val;
addr &= 0x3f;
switch(addr) {
case SMB_GLOBAL_STATUS:
val = s->smb_stat;
break;
case SMB_GLOBAL_ENABLE:
//s->smb_index = 0;
val = s->smb_ctl & 0x1f;
break;
case SMB_HOST_COMMAND:
val = s->smb_cmd;
break;
case SMB_HOST_ADDRESS:
val = s->smb_addr;
break;
case SMB_HOST_DATA:
val = s->smb_data0;
break;
/*case SMBHSTDAT1:
val = s->smb_data1;
break;*/
case SMB_HOST_BLOCK_DATA:
val = s->smb_data[s->smb_index++];
if (s->smb_index > 31)
s->smb_index = 0;
break;
default:
val = 0;
break;
}
SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val);
return val;
}
void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb)
{
smb->smbus = i2c_init_bus(parent, "i2c");
smb->smb_stat = 0;
}

21
hw/amd_smbus.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef AMD_SMBUS_H
#define AMD_SMBUS_H
typedef struct AMD756SMBus {
i2c_bus *smbus;
uint8_t smb_stat;
uint8_t smb_ctl;
uint8_t smb_cmd;
uint8_t smb_addr;
uint8_t smb_data0;
//uint8_t smb_data1;
uint8_t smb_data[32];
uint8_t smb_index;
} AMD756SMBus;
void amd756_smbus_init(DeviceState *parent, AMD756SMBus *smb);
void amd756_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val);
uint32_t amd756_smb_ioport_readb(void *opaque, uint32_t addr);
#endif /* !AMD_SMBUS_H */

View File

@ -12,4 +12,6 @@ obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
obj-y += kvm/
obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
obj-$(CONFIG_XBOX) += xbox.o xbox_pci.o acpi_mcpx.o amd_smbus.o nv2a.o smbus_pic16lc.o smbus_cx25871.o smbus_adm1032.o
obj-y := $(addprefix ../,$(obj-y))

569
hw/nv2a.c Normal file
View File

@ -0,0 +1,569 @@
/*
* QEMU Geforce NV2A implementation
*
* Copyright (c) 2012 espes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "hw.h"
#include "pc.h"
#include "console.h"
#include "pci.h"
#include "vga_int.h"
#include "nv2a.h"
#define DEBUG_NV2A
#ifdef DEBUG_NV2A
# define NV2A_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define NV2A_DPRINTF(format, ...) do { } while (0)
#endif
#define NV_NUM_BLOCKS 20
#define NV_PMC 0 /* card master control */
#define NV_PBUS 1 /* bus control */
#define NV_PFIFO 2 /* MMIO and DMA FIFO submission to PGRAPH and VPE */
#define NV_PFIFO_CACHE 3
#define NV_PRMA 4 /* access to BAR0/BAR1 from real mode */
#define NV_PVIDEO 5 /* video overlay */
#define NV_PTIMER 6 /* time measurement and time-based alarms */
#define NV_PCOUNTER 7 /* performance monitoring counters */
#define NV_PVPE 8 /* MPEG2 decoding engine */
#define NV_PTV 9 /* TV encoder */
#define NV_PRMFB 10 /* aliases VGA memory window */
#define NV_PRMVIO 11 /* aliases VGA sequencer and graphics controller registers */
#define NV_PSTRAPS 12 /* straps readout / override */
#define NV_PGRAPH 13 /* accelerated 2d/3d drawing engine */
#define NV_PCRTC 14 /* more CRTC controls */
#define NV_PRMCIO 15 /* aliases VGA CRTC and attribute controller registers */
#define NV_PRAMDAC 16 /* RAMDAC, cursor, and PLL control */
#define NV_PRMDIO 17 /* aliases VGA palette registers */
#define NV_PRAMIN 18 /* RAMIN access */
#define NV_USER 19 /* PFIFO MMIO and DMA submission area */
typedef struct NV2AState {
PCIDevice dev;
VGACommonState vga;
MemoryRegion vram;
MemoryRegion mmio;
MemoryRegion block_mmio[NV_NUM_BLOCKS];
} NV2AState;
static uint64_t nv2a_pmc_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PMC: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pmc_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PMC: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pbus_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PBUS: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pbus_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PBUS: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pfifo_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PFIFO: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pfifo_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PFIFO: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_prma_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMA: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_prma_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMA: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pvideo_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PVIDEO: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pvideo_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PVIDEO: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_ptimer_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PTIMER: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_ptimer_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PTIMER: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pcounter_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PCOUNTER: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pcounter_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PCOUNTER: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pvpe_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PVPE: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pvpe_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PVPE: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_ptv_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PTV: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_ptv_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PTV: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_prmfb_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMFB: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_prmfb_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMFB: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_prmvio_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMVIO: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_prmvio_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMVIO: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pstraps_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PSTRAPS: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pstraps_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PSTRAPS: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pgraph_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PGRAPH: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pgraph_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PGRAPH: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pcrtc_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PCRTC: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pcrtc_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PCRTC: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_prmcio_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMCIO: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_prmcio_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMCIO: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pramdac_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRAMDAC: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pramdac_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRAMDAC: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_prmdio_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMDIO: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_prmdio_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRMDIO: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_pramin_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a PRAMIN: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_pramin_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a PRAMIN: [0x%llx] = 0x%02llx\n", addr, val);
}
static uint64_t nv2a_user_read(void *opaque,
target_phys_addr_t addr, unsigned int size)
{
NV2A_DPRINTF("nv2a USER: read [0x%llx]\n", addr);
return 0;
}
static void nv2a_user_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned int size)
{
NV2A_DPRINTF("nv2a USER: [0x%llx] = 0x%02llx\n", addr, val);
}
typedef struct NV2ABlockInfo {
const char* name;
target_phys_addr_t offset;
uint64_t size;
MemoryRegionOps ops;
} NV2ABlockInfo;
static const struct NV2ABlockInfo blocktable[] = {
[ NV_PMC ] = {
.name = "PMC",
.offset = 0x000000,
.size = 0x001000,
.ops = {
.read = nv2a_pmc_read,
.write = nv2a_pmc_write,
},
},
[ NV_PBUS ] = {
.name = "PBUS",
.offset = 0x001000,
.size = 0x001000,
.ops = {
.read = nv2a_pbus_read,
.write = nv2a_pbus_write,
},
},
[ NV_PFIFO ] = {
.name = "PFIFO",
.offset = 0x002000,
.size = 0x002000,
.ops = {
.read = nv2a_pfifo_read,
.write = nv2a_pfifo_write,
},
},
[ NV_PRMA ] = {
.name = "PRMA",
.offset = 0x007000,
.size = 0x001000,
.ops = {
.read = nv2a_prma_read,
.write = nv2a_prma_write,
},
},
[ NV_PVIDEO ] = {
.name = "PVIDEO",
.offset = 0x008000,
.size = 0x001000,
.ops = {
.read = nv2a_pvideo_read,
.write = nv2a_pvideo_write,
},
},
[ NV_PTIMER ] = {
.name = "PTIMER",
.offset = 0x009000,
.size = 0x001000,
.ops = {
.read = nv2a_ptimer_read,
.write = nv2a_ptimer_write,
},
},
[ NV_PCOUNTER ] = {
.name = "PCOUNTER",
.offset = 0x00a000,
.size = 0x001000,
.ops = {
.read = nv2a_pcounter_read,
.write = nv2a_pcounter_write,
},
},
[ NV_PVPE ] = {
.name = "PVPE",
.offset = 0x00b000,
.size = 0x001000,
.ops = {
.read = nv2a_pvpe_read,
.write = nv2a_pvpe_write,
},
},
[ NV_PTV ] = {
.name = "PTV",
.offset = 0x00d000,
.size = 0x001000,
.ops = {
.read = nv2a_ptv_read,
.write = nv2a_ptv_write,
},
},
[ NV_PRMFB ] = {
.name = "PRMFB",
.offset = 0x0a0000,
.size = 0x020000,
.ops = {
.read = nv2a_prmfb_read,
.write = nv2a_prmfb_write,
},
},
[ NV_PRMVIO ] = {
.name = "PRMVIO",
.offset = 0x0c0000,
.size = 0x001000,
.ops = {
.read = nv2a_prmvio_read,
.write = nv2a_prmvio_write,
},
},
[ NV_PSTRAPS ] = {
.name = "PSTRAPS",
.offset = 0x101000,
.size = 0x001000,
.ops = {
.read = nv2a_pstraps_read,
.write = nv2a_pstraps_write,
},
},
[ NV_PGRAPH ] = {
.name = "PGRAPH",
.offset = 0x400000,
.size = 0x002000,
.ops = {
.read = nv2a_pgraph_read,
.write = nv2a_pgraph_write,
},
},
[ NV_PCRTC ] = {
.name = "PCRTC",
.offset = 0x600000,
.size = 0x001000,
.ops = {
.read = nv2a_pcrtc_read,
.write = nv2a_pcrtc_write,
},
},
[ NV_PRMCIO ] = {
.name = "PRMCIO",
.offset = 0x601000,
.size = 0x001000,
.ops = {
.read = nv2a_prmcio_read,
.write = nv2a_prmcio_write,
},
},
[ NV_PRAMDAC ] = {
.name = "PRAMDAC",
.offset = 0x680000,
.size = 0x001000,
.ops = {
.read = nv2a_pramdac_read,
.write = nv2a_pramdac_write,
},
},
[ NV_PRMDIO ] = {
.name = "PRMDIO",
.offset = 0x681000,
.size = 0x001000,
.ops = {
.read = nv2a_prmdio_read,
.write = nv2a_prmdio_write,
},
},
[ NV_PRAMIN ] = {
.name = "PRAMIN",
.offset = 0x700000,
.size = 0x100000,
.ops = {
.read = nv2a_pramin_read,
.write = nv2a_pramin_write,
},
},
[ NV_USER ] = {
.name = "USER",
.offset = 0x800000,
.size = 0x800000,
.ops = {
.read = nv2a_user_read,
.write = nv2a_user_write,
},
},
};
static int nv2a_initfn(PCIDevice *dev)
{
int i;
NV2AState *d = DO_UPCAST(NV2AState, dev, dev);
//uint8_t *pci_conf = d->dev.config;
/* setup legacy VGA */
//d->vga.vram_size_mb = 16;
//vga_common_init(&d->vga);
memory_region_init(&d->mmio, "nv2a-mmio", 0x1000000);
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
memory_region_init_ram(&d->vram, "nv2a-vram", 128 * 0x100000);
pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, &d->vram);
for (i=0; i<sizeof(blocktable)/sizeof(blocktable[0]); i++) {
if (!blocktable[i].name) continue;
memory_region_init_io(&d->block_mmio[i], &blocktable[i].ops, d,
blocktable[i].name, blocktable[i].size);
memory_region_add_subregion(&d->mmio, blocktable[i].offset,
&d->block_mmio[i]);
}
return 0;
}
static void nv2a_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->vendor_id = PCI_VENDOR_ID_NVIDIA;
k->device_id = PCI_DEVICE_ID_NVIDIA_GEFORCE_NV2A;
k->revision = 161;
k->class_id = PCI_CLASS_DISPLAY_3D;
k->init = nv2a_initfn;
dc->desc = "GeForce NV2A Integrated Graphics";
}
static const TypeInfo nv2a_info = {
.name = "nv2a",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(NV2AState),
.class_init = nv2a_class_init,
};
static void nv2a_register(void)
{
type_register_static(&nv2a_info);
}
type_init(nv2a_register);
void nv2a_init(PCIBus *bus, int devfn)
{
pci_create_simple(bus, devfn, "nv2a");
}

27
hw/nv2a.h Normal file
View File

@ -0,0 +1,27 @@
/*
* QEMU Geforce NV2A implementation
*
* Copyright (c) 2012 espes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef HW_NV2A_H
#define HW_NV2A_H
void nv2a_init(PCIBus *bus, int devfn);
#endif

View File

@ -22,6 +22,7 @@
#define PCI_CLASS_NETWORK_ETHERNET 0x0200
#define PCI_CLASS_DISPLAY_VGA 0x0300
#define PCI_CLASS_DISPLAY_3D 0x0302
#define PCI_CLASS_DISPLAY_OTHER 0x0380
#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401
@ -31,6 +32,7 @@
#define PCI_CLASS_SYSTEM_OTHER 0x0880
#define PCI_CLASS_SERIAL_USB 0x0c03
#define PCI_CLASS_SERIAL_SMBUS 0x0c05
#define PCI_CLASS_BRIDGE_HOST 0x0600
#define PCI_CLASS_BRIDGE_ISA 0x0601
@ -128,3 +130,12 @@
#define PCI_VENDOR_ID_NEC 0x1033
#define PCI_DEVICE_ID_NEC_UPD720200 0x0194
#define PCI_VENDOR_ID_NVIDIA 0x10de
#define PCI_DEVICE_ID_NVIDIA_NFORCE_LPC 0x01b2
#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4
#define PCI_DEVICE_ID_NVIDIA_NFORCE_AGP 0x01b7
#define PCI_DEVICE_ID_NVIDIA_GEFORCE_NV2A 0x02a0
#define PCI_DEVICE_ID_NVIDIA_XBOX_PCHB 0x02a5

View File

@ -77,7 +77,14 @@ int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
int len);
void smbus_eeprom_init_single(i2c_bus *smbus, int address,
uint8_t *eeprom_buf);
void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int size);
void smbus_pic16lc_init(i2c_bus *smbus, int address);
void smbus_cx25871_init(i2c_bus *smbus, int address);
void smbus_adm1032_init(i2c_bus *smbus, int address);
#endif

86
hw/smbus_adm1032.c Normal file
View File

@ -0,0 +1,86 @@
/*
* QEMU SMBus ADM1032 Temperature Monitor
*
* Copyright (c) 2012 espes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "i2c.h"
#include "smbus.h"
#define DEBUG
static uint8_t tm_read_data(SMBusDevice *dev, uint8_t cmd, int n)
{
#ifdef DEBUG
printf("tm_read_data: addr=0x%02x cmd=0x%02x n=%d\n",
dev->i2c.address, cmd, n);
#endif
switch (cmd) {
case 0x0:
case 0x1:
return 50;
default:
break;
}
return 0;
}
static int tm_init(SMBusDevice *dev)
{
return 0;
}
static void smbus_adm1032_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
sc->init = tm_init;
sc->read_data = tm_read_data;
}
static TypeInfo smbus_adm1032_info = {
.name = "smbus-adm1032",
.parent = TYPE_SMBUS_DEVICE,
.instance_size = sizeof(SMBusDevice),
.class_init = smbus_adm1032_class_initfn,
};
static void smbus_adm1032_register_devices(void)
{
type_register_static(&smbus_adm1032_info);
}
type_init(smbus_adm1032_register_devices)
void smbus_adm1032_init(i2c_bus *smbus, int address)
{
DeviceState *tm;
tm = qdev_create((BusState *)smbus, "smbus-adm1032");
qdev_prop_set_uint8(tm, "address", address);
qdev_init_nofail(tm);
}

127
hw/smbus_cx25871.c Normal file
View File

@ -0,0 +1,127 @@
/*
* QEMU SMBus Conexant CX25871 Video Encoder
*
* Copyright (c) 2012 espes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "i2c.h"
#include "smbus.h"
typedef struct SMBusCX25871Device {
SMBusDevice smbusdev;
uint8_t registers[256];
} SMBusCX25871Device;
#define DEBUG
static void cx_quick_cmd(SMBusDevice *dev, uint8_t read)
{
#ifdef DEBUG
printf("cx_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
#endif
}
static void cx_send_byte(SMBusDevice *dev, uint8_t val)
{
SMBusCX25871Device *cx = (SMBusCX25871Device *) dev;
#ifdef DEBUG
printf("cx_send_byte: addr=0x%02x val=0x%02x\n",
dev->i2c.address, val);
#endif
}
static uint8_t cx_receive_byte(SMBusDevice *dev)
{
SMBusCX25871Device *cx = (SMBusCX25871Device *) dev;
#ifdef DEBUG
printf("cx_receive_byte: addr=0x%02x\n",
dev->i2c.address);
#endif
return 0;
}
static void cx_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
{
SMBusCX25871Device *cx = (SMBusCX25871Device *) dev;
#ifdef DEBUG
printf("cx_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
dev->i2c.address, cmd, buf[0]);
#endif
memcpy(cx->registers+cmd, buf, MIN(len, 256-cmd));
}
static uint8_t cx_read_data(SMBusDevice *dev, uint8_t cmd, int n)
{
SMBusCX25871Device *cx = (SMBusCX25871Device *) dev;
#ifdef DEBUG
printf("cx_read_data: addr=0x%02x cmd=0x%02x n=%d\n",
dev->i2c.address, cmd, n);
#endif
return cx->registers[cmd];
}
static int smbus_cx_init(SMBusDevice *dev)
{
SMBusCX25871Device *cx = (SMBusCX25871Device *)dev;
return 0;
}
static void smbus_cx25871_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
sc->init = smbus_cx_init;
sc->quick_cmd = cx_quick_cmd;
sc->send_byte = cx_send_byte;
sc->receive_byte = cx_receive_byte;
sc->write_data = cx_write_data;
sc->read_data = cx_read_data;
}
static TypeInfo smbus_cx25871_info = {
.name = "smbus-cx25871",
.parent = TYPE_SMBUS_DEVICE,
.instance_size = sizeof(SMBusCX25871Device),
.class_init = smbus_cx25871_class_initfn,
};
static void smbus_cx25871_register_devices(void)
{
type_register_static(&smbus_cx25871_info);
}
type_init(smbus_cx25871_register_devices)
void smbus_cx25871_init(i2c_bus *smbus, int address)
{
DeviceState *cx;
cx = qdev_create((BusState *)smbus, "smbus-cx25871");
qdev_prop_set_uint8(cx, "address", address);
qdev_init_nofail(cx);
}

View File

@ -26,7 +26,7 @@
#include "i2c.h"
#include "smbus.h"
//#define DEBUG
#define DEBUG
typedef struct SMBusEEPROMDevice {
SMBusDevice smbusdev;
@ -137,6 +137,16 @@ static void smbus_eeprom_register_types(void)
type_init(smbus_eeprom_register_types)
void smbus_eeprom_init_single(i2c_bus *smbus, int address,
uint8_t *eeprom_buf)
{
DeviceState *eeprom;
eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
qdev_prop_set_uint8(eeprom, "address", address);
qdev_prop_set_ptr(eeprom, "data", eeprom_buf);
qdev_init_nofail(eeprom);
}
void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int eeprom_spd_size)
{
@ -147,10 +157,7 @@ void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
}
for (i = 0; i < nb_eeprom; i++) {
DeviceState *eeprom;
eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
qdev_init_nofail(eeprom);
smbus_eeprom_init_single(smbus,
0x50 + i, eeprom_buf + (i * 256));
}
}

183
hw/smbus_pic16lc.c Normal file
View File

@ -0,0 +1,183 @@
/*
* QEMU SMBus PIC16LC System Monitor
*
* Copyright (c) 2011 espes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "i2c.h"
#include "smbus.h"
#define PIC16LC_REG_VER 0x01
#define PIC16LC_REG_POWER 0x02
#define PIC16LC_REG_POWER_RESET 0x01
#define PIC16LC_REG_POWER_CYCLE 0x40
#define PIC16LC_REG_POWER_SHUTDOWN 0x80
#define PIC16LC_REG_TRAYSTATE 0x03
#define PIC16LC_REG_AVPACK 0x04
#define PIC16LC_REG_AVPACK_SCART 0x00
#define PIC16LC_REG_AVPACK_HDTV 0x01
#define PIC16LC_REG_AVPACK_VGA_SOG 0x02
#define PIC16LC_REG_AVPACK_SVIDEO 0x04
#define PIC16LC_REG_AVPACK_COMPOSITE 0x06
#define PIC16LC_REG_AVPACK_VGA 0x07
#define PIC16LC_REG_FANMODE 0x05
#define PIC16LC_REG_FANSPEED 0x06
#define PIC16LC_REG_LEDMODE 0x07
#define PIC16LC_REG_LEDSEQ 0x08
#define PIC16LC_REG_CPUTEMP 0x09
#define PIC16LC_REG_BOARDTEMP 0x0a
#define PIC16LC_REG_TRAYEJECT 0x0c
#define PIC16LC_REG_INTACK 0x0d
#define PIC16LC_REG_INTSTATUS 0x11
#define PIC16LC_REG_INTSTATUS_POWER 0x01
#define PIC16LC_REG_INTSTATUS_TRAYCLOSED 0x02
#define PIC16LC_REG_INTSTATUS_TRAYOPENING 0x04
#define PIC16LC_REG_INTSTATUS_AVPACK_PLUG 0x08
#define PIC16LC_REG_INTSTATUS_AVPACK_UNPLUG 0x10
#define PIC16LC_REG_INTSTATUS_EJECT_BUTTON 0x20
#define PIC16LC_REG_INTSTATUS_TRAYCLOSING 0x40
#define PIC16LC_REG_RESETONEJECT 0x19
#define PIC16LC_REG_INTEN 0x1a
static const char* pic_version_string = "P01";
#define DEBUG
typedef struct SMBusPIC16LCDevice {
SMBusDevice smbusdev;
int versionStringIndex;
} SMBusPIC16LCDevice;
static void pic_quick_cmd(SMBusDevice *dev, uint8_t read)
{
#ifdef DEBUG
printf("pic_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
#endif
}
static void pic_send_byte(SMBusDevice *dev, uint8_t val)
{
SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev;
#ifdef DEBUG
printf("pic_send_byte: addr=0x%02x val=0x%02x\n",
dev->i2c.address, val);
#endif
}
static uint8_t pic_receive_byte(SMBusDevice *dev)
{
SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev;
#ifdef DEBUG
printf("pic_receive_byte: addr=0x%02x\n",
dev->i2c.address);
#endif
return 0;
}
static void pic_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
{
SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev;
#ifdef DEBUG
printf("pic_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
dev->i2c.address, cmd, buf[0]);
#endif
switch(cmd) {
case PIC16LC_REG_VER:
//pic version string reset
pic->versionStringIndex = buf[0];
break;
default:
break;
}
}
static uint8_t pic_read_data(SMBusDevice *dev, uint8_t cmd, int n)
{
SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *) dev;
#ifdef DEBUG
printf("pic_read_data: addr=0x%02x cmd=0x%02x n=%d\n",
dev->i2c.address, cmd, n);
#endif
switch(cmd) {
case PIC16LC_REG_VER:
return pic_version_string[
pic->versionStringIndex++%(sizeof(pic_version_string)-1)];
case PIC16LC_REG_AVPACK:
//pretend to ave a composite av pack plugged in
return PIC16LC_REG_AVPACK_COMPOSITE;
default:
break;
}
return 0;
}
static int smbus_pic_init(SMBusDevice *dev)
{
SMBusPIC16LCDevice *pic = (SMBusPIC16LCDevice *)dev;
pic->versionStringIndex = 0;
return 0;
}
static void smbus_pic_class_initfn(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
sc->init = smbus_pic_init;
sc->quick_cmd = pic_quick_cmd;
sc->send_byte = pic_send_byte;
sc->receive_byte = pic_receive_byte;
sc->write_data = pic_write_data;
sc->read_data = pic_read_data;
}
static TypeInfo smbus_pic_info = {
.name = "smbus-pic16lc",
.parent = TYPE_SMBUS_DEVICE,
.instance_size = sizeof(SMBusPIC16LCDevice),
.class_init = smbus_pic_class_initfn,
};
static void smbus_pic_register_devices(void)
{
type_register_static(&smbus_pic_info);
}
type_init(smbus_pic_register_devices)
void smbus_pic16lc_init(i2c_bus *smbus, int address)
{
DeviceState *pic;
pic = qdev_create((BusState *)smbus, "smbus-pic16lc");
qdev_prop_set_uint8(pic, "address", address);
qdev_init_nofail(pic);
}

276
hw/xbox.c Normal file
View File

@ -0,0 +1,276 @@
/*
* QEMU Xbox System Emulator
*
* Copyright (c) 2012 espes
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "arch_init.h"
#include "pc.h"
#include "pci.h"
#include "net.h"
#include "boards.h"
#include "ide.h"
#include "mc146818rtc.h"
#include "i8254.h"
#include "pcspk.h"
#include "kvm.h"
#include "sysemu.h"
#include "sysbus.h"
#include "smbus.h"
#include "blockdev.h"
#include "loader.h"
#include "exec-memory.h"
#include "xbox_pci.h"
#include "nv2a.h"
/* mostly from pc_memory_init */
static void xbox_memory_init(MemoryRegion *system_memory,
ram_addr_t mem_size,
MemoryRegion *rom_memory,
MemoryRegion **ram_memory)
{
MemoryRegion *ram;
MemoryRegion *ram_below_4g;
int ret;
char *filename;
int bios_size, isa_bios_size;
MemoryRegion *bios, *isa_bios;
MemoryRegion *map_bios;
uint32_t map_loc;
/* Allocate RAM. We allocate it as a single memory region and use
* aliases to address portions of it, mostly for backwards compatibility
* with older qemus that used qemu_ram_alloc().
*/
ram = g_malloc(sizeof(*ram));
memory_region_init_ram(ram, "pc.ram", mem_size);
vmstate_register_ram_global(ram);
*ram_memory = ram;
ram_below_4g = g_malloc(sizeof(*ram_below_4g));
memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
0, mem_size);
memory_region_add_subregion(system_memory, 0, ram_below_4g);
/* Load the bios. (mostly from pc_sysfw)
* Can't use it verbatim, since we need the bios repeated\
* over top 1MB of memory.
*/
if (bios_name == NULL) {
bios_name = "bios.bin";
}
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
bios_size = get_image_size(filename);
} else {
bios_size = -1;
}
bios = g_malloc(sizeof(*bios));
memory_region_init_ram(bios, "pc.bios", bios_size);
vmstate_register_ram_global(bios);
memory_region_set_readonly(bios, true);
ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
if (ret != 0) {
fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
exit(1);
}
if (filename) {
g_free(filename);
}
/* map the last 128KB of the BIOS in ISA space */
isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024)) {
isa_bios_size = 128 * 1024;
}
isa_bios = g_malloc(sizeof(*isa_bios));
memory_region_init_alias(isa_bios, "isa-bios", bios,
bios_size - isa_bios_size, isa_bios_size);
memory_region_add_subregion_overlap(rom_memory,
0x100000 - isa_bios_size,
isa_bios,
1);
memory_region_set_readonly(isa_bios, true);
/* map the bios repeated at the top of memory */
for (map_loc=(uint32_t)(-bios_size); map_loc >= 0xff000000; map_loc-=bios_size) {
map_bios = g_malloc(sizeof(*map_bios));
memory_region_init_alias(map_bios, NULL, bios, 0, bios_size);
memory_region_add_subregion(rom_memory, map_loc, map_bios);
memory_region_set_readonly(map_bios, true);
}
/*memory_region_add_subregion(rom_memory,
(uint32_t)(-bios_size),
bios);
*/
}
static void ioapic_init(GSIState *gsi_state)
{
DeviceState *dev;
SysBusDevice *d;
unsigned int i;
dev = qdev_create(NULL, "ioapic");
qdev_init_nofail(dev);
d = sysbus_from_qdev(dev);
sysbus_mmio_map(d, 0, 0xfec00000);
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
}
}
#define MAX_IDE_BUS 2
/* mostly from pc_init1 */
static void xbox_init(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
const char *cpu_model)
{
int i;
PCIBus *host_bus;
ISABus *isa_bus;
qemu_irq *cpu_irq;
qemu_irq *gsi;
qemu_irq *i8259;
GSIState *gsi_state;
PCIDevice *ide_dev;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BusState *idebus[MAX_IDE_BUS];
ISADevice *rtc_state;
ISADevice *pit;
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
DeviceState *xboxpci_host;
i2c_bus *smbus;
PCIBus *agp_bus;
pc_cpus_init(cpu_model);
pci_memory = g_new(MemoryRegion, 1);
memory_region_init(pci_memory, "pci", INT64_MAX);
/* allocate ram and load rom/bios */
xbox_memory_init(get_system_memory(), ram_size,
pci_memory, &ram_memory);
gsi_state = g_malloc0(sizeof(*gsi_state));
gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
/* init buses */
host_bus = xbox_pci_init(&xboxpci_host, gsi,
get_system_memory(), get_system_io(),
pci_memory, ram_memory);
/* bridges */
agp_bus = xbox_agp_init(xboxpci_host, host_bus);
isa_bus = mcpx_lpc_init(xboxpci_host, host_bus);
smbus = mcpx_smbus_init(xboxpci_host, host_bus);
/* irq shit */
isa_bus_irqs(isa_bus, gsi);
cpu_irq = pc_allocate_cpu_irq();
i8259 = i8259_init(isa_bus, cpu_irq[0]);
for (i = 0; i < ISA_NUM_IRQS; i++) {
gsi_state->i8259_irq[i] = i8259[i];
}
ioapic_init(gsi_state);
/* basic device init */
rtc_state = rtc_init(isa_bus, 2000, NULL);
pit = pit_init(isa_bus, 0x40, 0, NULL);
/* does apparently have a pc speaker, though not used? */
pcspk_init(isa_bus, pit);
/* TODO: ethernet */
/* TODO: USB */
/* hdd shit
* piix3's ide be right for now, maybe
*/
ide_drive_get(hd, MAX_IDE_BUS);
ide_dev = pci_piix4_ide_init(host_bus, hd, PCI_DEVFN(9, 0));
idebus[0] = qdev_get_child_bus(&ide_dev->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&ide_dev->qdev, "ide.1");
pc_cmos_init(ram_size, 0, boot_device,
NULL, idebus[0], idebus[1], rtc_state);
/* TODO: Populate SPD eeprom data. */
uint8_t *eeprom_buf = g_malloc0(256);
smbus_eeprom_init_single(smbus, 0x54, eeprom_buf);
smbus_pic16lc_init(smbus, 0x10);
smbus_cx25871_init(smbus, 0x45);
smbus_adm1032_init(smbus, 0x4c);
/* GPU! */
nv2a_init(agp_bus, PCI_DEVFN(0, 0));
}
static QEMUMachine xbox_machine = {
.name = "xbox",
.desc = "Microsoft Xbox",
.init = xbox_init,
};
static void xbox_machine_init(void) {
qemu_register_machine(&xbox_machine);
}
machine_init(xbox_machine_init);

404
hw/xbox_pci.c Normal file
View File

@ -0,0 +1,404 @@
/*
* QEMU Xbox PCI buses implementation
*
* Copyright (c) 2012 espes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "hw.h"
#include "range.h"
#include "isa.h"
#include "sysbus.h"
#include "pc.h"
#include "pci.h"
#include "pci_bridge.h"
#include "pci_internals.h"
#include "exec-memory.h"
#include "acpi_mcpx.h"
#include "amd_smbus.h"
#include "qemu-common.h"
#include "xbox_pci.h"
/*
* xbox chipset based on nForce 420, which was based on AMD-760
*
* http://support.amd.com/us/ChipsetMotherboard_TechDocs/24494.pdf
* http://support.amd.com/us/ChipsetMotherboard_TechDocs/24416.pdf
* http://support.amd.com/us/ChipsetMotherboard_TechDocs/24467.pdf
*
* http://support.amd.com/us/ChipsetMotherboard_TechDocs/24462.pdf
*
* - 'NV2A' combination northbridge/gpu
* - 'MCPX' combination southbridge/apu
*/
#define DEBUG
#ifdef DEBUG
# define XBOXPCI_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define XBOXPCI_DPRINTF(format, ...) do { } while (0)
#endif
PCIBus *xbox_pci_init(DeviceState **xbox_pci_hostp,
qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
MemoryRegion *pci_memory,
MemoryRegion *ram_memory)
{
DeviceState *dev;
PCIHostState *hostState;
PCIBus *hostBus;
PCIDevice *bridgeDev;
XBOX_PCIState *bridge;
/* pci host bus */
dev = qdev_create(NULL, "xbox-pcihost");
hostState = PCI_HOST_BRIDGE(dev);
hostState->address_space = address_space_mem;
hostBus = pci_bus_new(dev, NULL, pci_memory,
address_space_io, 0);
hostState->bus = hostBus;
//pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
// PIIX_NUM_PIRQS);
qdev_init_nofail(dev);
bridgeDev = pci_create_simple_multifunction(hostBus, PCI_DEVFN(0, 0),
true, "xbox-pci");
bridge = XBOX_PCI_DEVICE(bridgeDev);
bridge->ram_memory = ram_memory;
bridge->pci_address_space = pci_memory;
bridge->system_memory = address_space_mem;
/* PCI hole */
memory_region_init_alias(&bridge->pci_hole, "pci-hole",
bridge->pci_address_space,
ram_size,
0x100000000ULL - ram_size);
memory_region_add_subregion(bridge->system_memory, ram_size,
&bridge->pci_hole);
*xbox_pci_hostp = dev;
return hostBus;
}
PCIBus *xbox_agp_init(DeviceState *host, PCIBus *bus)
{
PCIDevice *d;
PCIBridge *br;
//DeviceState *qdev;
/* AGP bus */
d = pci_create_simple(bus, PCI_DEVFN(30, 0), "xbox-agp");
if (!d) {
return NULL;
}
br = DO_UPCAST(PCIBridge, dev, d);
//qdev = &br->dev.qdev;
//qdev_init_nofail(qdev);
return pci_bridge_get_sec_bus(br);
}
ISABus *mcpx_lpc_init(DeviceState *host, PCIBus *bus)
{
PCIDevice *d;
MCPX_LPCState *s;
//qemu_irq *sci_irq;
d = pci_create_simple_multifunction(bus, PCI_DEVFN(1, 0),
true, "mcpx-lpc");
s = MCPX_LPC_DEVICE(d);
//sci_irq = qemu_allocate_irqs(mcpx_set_sci, &s->irq_state, 1);
mcpx_pm_init(&s->pm /*, sci_irq[0]*/);
//mcpx_lpc_reset(&s->dev.qdev);
return s->isa_bus;
}
i2c_bus *mcpx_smbus_init(DeviceState *host, PCIBus *bus)
{
PCIDevice *d;
MCPX_SMBState *s;
d = pci_create_simple_multifunction(bus, PCI_DEVFN(1, 1),
true, "mcpx-smbus");
s = MCPX_SMBUS_DEVICE(d);
return s->smb.smbus;
}
static int mcpx_smbus_initfn(PCIDevice *dev)
{
MCPX_SMBState *s = MCPX_SMBUS_DEVICE(dev);
//presumably configurable, but can't find docs...
const uint32_t smb_io_base = 0xc000;
register_ioport_write(smb_io_base, 64, 1, amd756_smb_ioport_writeb, &s->smb);
register_ioport_read(smb_io_base, 64, 1, amd756_smb_ioport_readb, &s->smb);
amd756_smbus_init(&dev->qdev, &s->smb);
return 0;
}
static void mcpx_smbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = mcpx_smbus_initfn;
k->vendor_id = PCI_VENDOR_ID_NVIDIA;
k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS;
k->revision = 161;
k->class_id = PCI_CLASS_SERIAL_SMBUS;
dc->desc = "nForce PCI System Management";
dc->no_user = 1;
}
static const TypeInfo mcpx_smbus_info = {
.name = "mcpx-smbus",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = mcpx_smbus_class_init,
};
#define MCPX_LPC_PMBASE 0x84
#define MCPX_LPC_PMBASE_ADDRESS_MASK 0xff00
#define MCPX_LPC_PMBASE_DEFAULT 0x1
static int mcpx_lpc_initfn(PCIDevice *d)
{
MCPX_LPCState *lpc = MCPX_LPC_DEVICE(d);
ISABus *isa_bus;
isa_bus = isa_bus_new(&d->qdev, get_system_io());
lpc->isa_bus = isa_bus;
return 0;
}
static void mcpx_lpc_pmbase_update(MCPX_LPCState *s)
{
uint32_t pm_io_base = pci_get_long(s->dev.config + MCPX_LPC_PMBASE);
pm_io_base &= MCPX_LPC_PMBASE_ADDRESS_MASK;
mcpx_pm_iospace_update(&s->pm, pm_io_base);
}
static void mcpx_lpc_reset(DeviceState *dev)
{
PCIDevice *d = PCI_DEVICE(dev);
MCPX_LPCState *s = MCPX_LPC_DEVICE(d);
pci_set_long(s->dev.config + MCPX_LPC_PMBASE, MCPX_LPC_PMBASE_DEFAULT);
mcpx_lpc_pmbase_update(s);
}
static void mcpx_lpc_config_write(PCIDevice *dev,
uint32_t addr, uint32_t val, int len)
{
MCPX_LPCState *s = MCPX_LPC_DEVICE(dev);
pci_default_write_config(dev, addr, val, len);
if (ranges_overlap(addr, len, MCPX_LPC_PMBASE, 2)) {
mcpx_lpc_pmbase_update(s);
}
}
static int mcpx_lpc_post_load(void *opaque, int version_id)
{
MCPX_LPCState *s = opaque;
mcpx_lpc_pmbase_update(s);
return 0;
}
static const VMStateDescription vmstate_mcpx_lpc = {
.name = "MCPX LPC",
.version_id = 1,
.post_load = mcpx_lpc_post_load,
};
static void mcpx_lpc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = mcpx_lpc_initfn;
k->config_write = mcpx_lpc_config_write;
k->vendor_id = PCI_VENDOR_ID_NVIDIA;
k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_LPC;
k->revision = 212;
k->class_id = PCI_CLASS_BRIDGE_ISA;
dc->desc = "nForce LPC Bridge";
dc->no_user = 1;
dc->reset = mcpx_lpc_reset;
dc->vmsd = &vmstate_mcpx_lpc;
}
static const TypeInfo mcpx_lpc_info = {
.name = "mcpx-lpc",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = mcpx_lpc_class_init,
};
static void xbox_agp_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = pci_bridge_initfn;
k->exit = pci_bridge_exitfn;
k->config_write = pci_bridge_write_config;
k->is_bridge = 1;
k->vendor_id = PCI_VENDOR_ID_NVIDIA;
k->device_id = PCI_DEVICE_ID_NVIDIA_NFORCE_AGP;
k->revision = 161;
dc->desc = "nForce AGP to PCI Bridge";
dc->reset = pci_bridge_reset;
}
static const TypeInfo xbox_agp_info = {
.name = "xbox-agp",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIBridge),
.class_init = xbox_agp_class_init,
};
static int xbox_pci_initfn(PCIDevice *d)
{
//XBOX_PCIState *s = DO_UPCAST(XBOX_PCIState, dev, dev);
return 0;
}
static void xbox_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->no_hotplug = 1;
k->init = xbox_pci_initfn;
//k->config_write = xbox_pci_write_config;
k->vendor_id = PCI_VENDOR_ID_NVIDIA;
k->device_id = PCI_DEVICE_ID_NVIDIA_XBOX_PCHB;
k->revision = 161;
k->class_id = PCI_CLASS_BRIDGE_HOST;
dc->desc = "Xbox PCI Host";
dc->no_user = 1;
}
static const TypeInfo xbox_pci_info = {
.name = "xbox-pci",
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(XBOX_PCIState),
.class_init = xbox_pci_class_init,
};
#define CONFIG_ADDR 0xcf8
#define CONFIG_DATA 0xcfc
static int xbox_pcihost_initfn(SysBusDevice *dev)
{
PCIHostState *s = PCI_HOST_BRIDGE(dev);
memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
"pci-conf-idx", 4);
sysbus_add_io(dev, CONFIG_ADDR, &s->conf_mem);
sysbus_init_ioports(&s->busdev, CONFIG_ADDR, 4);
memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
"pci-conf-data", 4);
sysbus_add_io(dev, CONFIG_DATA, &s->data_mem);
sysbus_init_ioports(&s->busdev, CONFIG_DATA, 4);
return 0;
}
static void xbox_pcihost_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
k->init = xbox_pcihost_initfn;
dc->no_user = 1;
}
static const TypeInfo xbox_pcihost_info = {
.name = "xbox-pcihost",
.parent = TYPE_PCI_HOST_BRIDGE,
.instance_size = sizeof(PCIHostState),
.class_init = xbox_pcihost_class_init,
};
static void xboxpci_register_types(void)
{
type_register(&xbox_pcihost_info);
type_register(&xbox_pci_info);
type_register(&xbox_agp_info);
type_register(&mcpx_lpc_info);
type_register(&mcpx_smbus_info);
}
type_init(xboxpci_register_types)

81
hw/xbox_pci.h Normal file
View File

@ -0,0 +1,81 @@
/*
* QEMU Xbox PCI buses implementation
*
* Copyright (c) 2012 espes
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#ifndef HW_XBOX_PCI_H
#define HW_XBOX_PCI_H
#include "hw.h"
#include "isa.h"
#include "pci.h"
#include "pci_host.h"
#include "amd_smbus.h"
#include "acpi.h"
#include "acpi_mcpx.h"
typedef struct XBOX_PCIState {
PCIDevice dev;
MemoryRegion *ram_memory;
MemoryRegion *pci_address_space;
MemoryRegion *system_memory;
MemoryRegion pci_hole;
} XBOX_PCIState;
typedef struct MCPX_SMBState {
PCIDevice dev;
AMD756SMBus smb;
} MCPX_SMBState;
typedef struct MCPX_LPCState {
PCIDevice dev;
ISABus *isa_bus;
MCPX_PMRegs pm;
} MCPX_LPCState;
#define XBOX_PCI_DEVICE(obj) \
OBJECT_CHECK(XBOX_PCIState, (obj), "xbox-pci")
#define MCPX_SMBUS_DEVICE(obj) \
OBJECT_CHECK(MCPX_SMBState, (obj), "mcpx-smbus")
#define MCPX_LPC_DEVICE(obj) \
OBJECT_CHECK(MCPX_LPCState, (obj), "mcpx-lpc")
PCIBus *xbox_pci_init(DeviceState **xbox_pci_hostp,
qemu_irq *pic,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
MemoryRegion *pci_memory,
MemoryRegion *ram_memory);
PCIBus *xbox_agp_init(DeviceState *host, PCIBus *bus);
ISABus *mcpx_lpc_init(DeviceState *host, PCIBus *bus);
i2c_bus *mcpx_smbus_init(DeviceState *host, PCIBus *bus);
#endif