diff --git a/hw/xbox/meson.build b/hw/xbox/meson.build index a22f3611c2..907ebdc4e8 100644 --- a/hw/xbox/meson.build +++ b/hw/xbox/meson.build @@ -8,6 +8,8 @@ specific_ss.add(files( 'nvnet.c', 'smbus_adm1032.c', 'smbus_cx25871.c', + 'smbus_fs454.c', + 'smbus_xcalibur.c', 'smbus_storage.c', 'smbus_xbox_smc.c', 'xbox.c', diff --git a/hw/xbox/smbus.h b/hw/xbox/smbus.h index 5e3b4f8229..568624ac2f 100644 --- a/hw/xbox/smbus.h +++ b/hw/xbox/smbus.h @@ -27,6 +27,8 @@ void smbus_xbox_smc_init(I2CBus *smbus, int address); void smbus_cx25871_init(I2CBus *smbus, int address); +void smbus_fs454_init(I2CBus *smbus, int address); +void smbus_xcalibur_init(I2CBus *smbus, int address); void smbus_adm1032_init(I2CBus *smbus, int address); bool xbox_smc_avpack_to_reg(const char *avpack, uint8_t *value); diff --git a/hw/xbox/smbus_fs454.c b/hw/xbox/smbus_fs454.c new file mode 100644 index 0000000000..73187ad7cc --- /dev/null +++ b/hw/xbox/smbus_fs454.c @@ -0,0 +1,119 @@ +/* + * QEMU SMBus Focus fs454 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 "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/qdev-properties.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/smbus_slave.h" +#include "smbus.h" +#include "qapi/error.h" + +#define TYPE_SMBUS_fs454 "smbus-fs454" +#define SMBUS_fs454(obj) OBJECT_CHECK(SMBusfs454Device, (obj), TYPE_SMBUS_fs454) + +// #define DEBUG +#ifdef DEBUG +# define DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define DPRINTF(format, ...) do { } while (0) +#endif + +typedef struct SMBusfs454Device { + SMBusDevice smbusdev; + uint8_t registers[256]; + uint8_t cmd; +} SMBusfs454Device; + +static void smbus_fs454_quick_cmd(SMBusDevice *dev, uint8_t read) +{ + DPRINTF("smbus_fs454_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); +} + +static int smbus_fs454_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len) +{ + SMBusfs454Device *cx = SMBUS_fs454(dev); + + cx->cmd = buf[0]; + uint8_t cmd = cx->cmd; + buf++; + len--; + + if (len < 1) return 0; + + DPRINTF("smbus_fs454_write_data: addr=0x%02x cmd=0x%02x val=0x%02x\n", + dev->i2c.address, cmd, buf[0]); + + memcpy(cx->registers + cmd, buf, MIN(len, 256 - cmd)); + + return 0; +} + +static uint8_t smbus_fs454_receive_byte(SMBusDevice *dev) +{ + SMBusfs454Device *cx = SMBUS_fs454(dev); + DPRINTF("smbus_fs454_receive_byte: addr=0x%02x cmd=0x%02x\n", + dev->i2c.address, cx->cmd); + return cx->registers[cx->cmd++]; +} + +static void smbus_fs454_realize(DeviceState *dev, Error **errp) +{ + SMBusfs454Device *cx = SMBUS_fs454(dev); + memset(cx->registers, 0, 256); + cx->cmd = 0; +} + +static void smbus_fs454_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); + + dc->realize = smbus_fs454_realize; + sc->quick_cmd = smbus_fs454_quick_cmd; + sc->receive_byte = smbus_fs454_receive_byte; + sc->write_data = smbus_fs454_write_data; +} + +static TypeInfo smbus_fs454_info = { + .name = TYPE_SMBUS_fs454, + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(SMBusfs454Device), + .class_init = smbus_fs454_class_initfn, +}; + +static void smbus_fs454_register_devices(void) +{ + type_register_static(&smbus_fs454_info); +} + +type_init(smbus_fs454_register_devices) + +void smbus_fs454_init(I2CBus *smbus, int address) +{ + DeviceState *dev; + dev = qdev_new(TYPE_SMBUS_fs454); + qdev_prop_set_uint8(dev, "address", address); + qdev_realize_and_unref(dev, (BusState *)smbus, &error_fatal); +} diff --git a/hw/xbox/smbus_xcalibur.c b/hw/xbox/smbus_xcalibur.c new file mode 100644 index 0000000000..a56a381d6b --- /dev/null +++ b/hw/xbox/smbus_xcalibur.c @@ -0,0 +1,119 @@ +/* + * QEMU SMBus Microsoft Xcalibur 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 "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/qdev-properties.h" +#include "hw/i2c/i2c.h" +#include "hw/i2c/smbus_slave.h" +#include "smbus.h" +#include "qapi/error.h" + +#define TYPE_SMBUS_xcalibur "smbus-xcalibur" +#define SMBUS_xcalibur(obj) OBJECT_CHECK(SMBusxcaliburDevice, (obj), TYPE_SMBUS_xcalibur) + +// #define DEBUG +#ifdef DEBUG +# define DPRINTF(format, ...) printf(format, ## __VA_ARGS__) +#else +# define DPRINTF(format, ...) do { } while (0) +#endif + +typedef struct SMBusxcaliburDevice { + SMBusDevice smbusdev; + uint8_t registers[256]; + uint8_t cmd; +} SMBusxcaliburDevice; + +static void smbus_xcalibur_quick_cmd(SMBusDevice *dev, uint8_t read) +{ + DPRINTF("smbus_xcalibur_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read); +} + +static int smbus_xcalibur_write_data(SMBusDevice *dev, uint8_t *buf, uint8_t len) +{ + SMBusxcaliburDevice *cx = SMBUS_xcalibur(dev); + + cx->cmd = buf[0]; + uint8_t cmd = cx->cmd; + buf++; + len--; + + if (len < 1) return 0; + + DPRINTF("smbus_xcalibur_write_data: addr=0x%02x cmd=0x%02x val=0x%02x\n", + dev->i2c.address, cmd, buf[0]); + + memcpy(cx->registers + cmd, buf, MIN(len, 256 - cmd)); + + return 0; +} + +static uint8_t smbus_xcalibur_receive_byte(SMBusDevice *dev) +{ + SMBusxcaliburDevice *cx = SMBUS_xcalibur(dev); + DPRINTF("smbus_xcalibur_receive_byte: addr=0x%02x cmd=0x%02x\n", + dev->i2c.address, cx->cmd); + return cx->registers[cx->cmd++]; +} + +static void smbus_xcalibur_realize(DeviceState *dev, Error **errp) +{ + SMBusxcaliburDevice *cx = SMBUS_xcalibur(dev); + memset(cx->registers, 0, 256); + cx->cmd = 0; +} + +static void smbus_xcalibur_class_initfn(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); + + dc->realize = smbus_xcalibur_realize; + sc->quick_cmd = smbus_xcalibur_quick_cmd; + sc->receive_byte = smbus_xcalibur_receive_byte; + sc->write_data = smbus_xcalibur_write_data; +} + +static TypeInfo smbus_xcalibur_info = { + .name = TYPE_SMBUS_xcalibur, + .parent = TYPE_SMBUS_DEVICE, + .instance_size = sizeof(SMBusxcaliburDevice), + .class_init = smbus_xcalibur_class_initfn, +}; + +static void smbus_xcalibur_register_devices(void) +{ + type_register_static(&smbus_xcalibur_info); +} + +type_init(smbus_xcalibur_register_devices) + +void smbus_xcalibur_init(I2CBus *smbus, int address) +{ + DeviceState *dev; + dev = qdev_new(TYPE_SMBUS_xcalibur); + qdev_prop_set_uint8(dev, "address", address); + qdev_realize_and_unref(dev, (BusState *)smbus, &error_fatal); +} diff --git a/hw/xbox/xbox.c b/hw/xbox/xbox.c index ec946f6112..9cd7f954b4 100644 --- a/hw/xbox/xbox.c +++ b/hw/xbox/xbox.c @@ -310,8 +310,20 @@ void xbox_init_common(MachineState *machine, /* smbus devices */ smbus_xbox_smc_init(smbus, 0x10); - smbus_cx25871_init(smbus, 0x45); - smbus_adm1032_init(smbus, 0x4c); + + const char *video_encoder = + object_property_get_str(qdev_get_machine(), "video-encoder", NULL); + + if (strcmp(video_encoder, "xcalibur") != 0) { + if (!strcmp(video_encoder, "conexant")) { + smbus_cx25871_init(smbus, 0x45); + } else if (!strcmp(video_encoder, "focus")) { + smbus_fs454_init(smbus, 0x6A); + } + smbus_adm1032_init(smbus, 0x4C); + } else { + smbus_xcalibur_init(smbus, 0x70); + } /* USB */ PCIDevice *usb1 = pci_new(PCI_DEVFN(3, 0), "pci-ohci"); @@ -445,6 +457,31 @@ static void machine_set_smc_version(Object *obj, const char *value, ms->smc_version = g_strdup(value); } +static char *machine_get_video_encoder(Object *obj, Error **errp) +{ + XboxMachineState *ms = XBOX_MACHINE(obj); + + return g_strdup(ms->video_encoder); +} + +static void machine_set_video_encoder(Object *obj, const char *value, + Error **errp) +{ + XboxMachineState *ms = XBOX_MACHINE(obj); + + if (strcmp(value, "conexant") != 0 && + strcmp(value, "focus") != 0 && + strcmp(value, "xcalibur") != 0 + ) { + error_setg(errp, "-machine video_encoder=%s: unsupported option", value); + error_append_hint(errp, "Valid options are: conexant (default), focus, xcalibur\n"); + return; + } + + g_free(ms->video_encoder); + ms->video_encoder = g_strdup(value); +} + static inline void xbox_machine_initfn(Object *obj) { object_property_add_str(obj, "bootrom", machine_get_bootrom, @@ -471,6 +508,12 @@ static inline void xbox_machine_initfn(Object *obj) "Set the SMC version number, default is P01"); object_property_set_str(obj, "smc-version", "P01", &error_fatal); + object_property_add_str(obj, "video-encoder", machine_get_video_encoder, + machine_set_video_encoder); + object_property_set_description(obj, "video-encoder", + "Set the encoder presented to the OS: conexant (default), focus, xcalibur"); + object_property_set_str(obj, "video-encoder", "conexant", &error_fatal); + } static void xbox_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/xbox/xbox.h b/hw/xbox/xbox.h index 665872faac..8e602d690e 100644 --- a/hw/xbox/xbox.h +++ b/hw/xbox/xbox.h @@ -46,6 +46,7 @@ typedef struct XboxMachineState { char *avpack; bool short_animation; char *smc_version; + char *video_encoder; } XboxMachineState; typedef struct XboxMachineClass {