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