1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
/*
* QEMU simulated pvpanic device.
*
* Copyright Fujitsu, Corp. 2013
*
* Authors:
* Wen Congyang <wency@cn.fujitsu.com>
* Hu Tao <hutao@cn.fujitsu.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
*/
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "system/runstate.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/qdev-properties.h"
#include "hw/misc/pvpanic.h"
#include "qom/object.h"
#include "hw/isa/isa.h"
#include "hw/acpi/acpi_aml_interface.h"
OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE)
/*
* PVPanicISAState for ISA device and
* use ioport.
*/
struct PVPanicISAState {
ISADevice parent_obj;
uint16_t ioport;
PVPanicState pvpanic;
};
static void pvpanic_isa_initfn(Object *obj)
{
PVPanicISAState *s = PVPANIC_ISA_DEVICE(obj);
pvpanic_setup_io(&s->pvpanic, DEVICE(s), 1);
}
static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
{
ISADevice *d = ISA_DEVICE(dev);
PVPanicISAState *s = PVPANIC_ISA_DEVICE(dev);
PVPanicState *ps = &s->pvpanic;
FWCfgState *fw_cfg = fw_cfg_find();
uint16_t *pvpanic_port;
if (!fw_cfg) {
return;
}
pvpanic_port = g_malloc(sizeof(*pvpanic_port));
*pvpanic_port = cpu_to_le16(s->ioport);
fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
sizeof(*pvpanic_port));
isa_register_ioport(d, &ps->mr, s->ioport);
}
static void build_pvpanic_isa_aml(AcpiDevAmlIf *adev, Aml *scope)
{
Aml *crs, *field, *method;
PVPanicISAState *s = PVPANIC_ISA_DEVICE(adev);
Aml *dev = aml_device("PEVT");
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0001")));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, s->ioport, s->ioport, 1, 1)
);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(dev, aml_operation_region("PEOR", AML_SYSTEM_IO,
aml_int(s->ioport), 1));
field = aml_field("PEOR", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
aml_append(field, aml_named_field("PEPT", 8));
aml_append(dev, field);
/* device present, functioning, decoding, shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
method = aml_method("RDPT", 0, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
aml_append(method, aml_return(aml_local(0)));
aml_append(dev, method);
method = aml_method("WRPT", 1, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_arg(0), aml_name("PEPT")));
aml_append(dev, method);
aml_append(scope, dev);
}
static const Property pvpanic_isa_properties[] = {
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505),
DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events,
PVPANIC_EVENTS),
};
static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
dc->realize = pvpanic_isa_realizefn;
device_class_set_props(dc, pvpanic_isa_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
adevc->build_dev_aml = build_pvpanic_isa_aml;
}
static const TypeInfo pvpanic_isa_info = {
.name = TYPE_PVPANIC_ISA_DEVICE,
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(PVPanicISAState),
.instance_init = pvpanic_isa_initfn,
.class_init = pvpanic_isa_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
};
static void pvpanic_register_types(void)
{
type_register_static(&pvpanic_isa_info);
}
type_init(pvpanic_register_types)
|