1765c9429SGerd Hoffmann /* 2765c9429SGerd Hoffmann * QEMU PCI bochs display adapter. 3765c9429SGerd Hoffmann * 4765c9429SGerd Hoffmann * This work is licensed under the terms of the GNU GPL, version 2 or later. 5765c9429SGerd Hoffmann * See the COPYING file in the top-level directory. 6765c9429SGerd Hoffmann */ 70b8fa32fSMarkus Armbruster 8765c9429SGerd Hoffmann #include "qemu/osdep.h" 90b8fa32fSMarkus Armbruster #include "qemu/module.h" 10f0353b0dSPhilippe Mathieu-Daudé #include "qemu/units.h" 11edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h" 12a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 13d6454270SMarkus Armbruster #include "migration/vmstate.h" 14765c9429SGerd Hoffmann #include "hw/display/bochs-vbe.h" 15a0d098b7SGerd Hoffmann #include "hw/display/edid.h" 16765c9429SGerd Hoffmann 17765c9429SGerd Hoffmann #include "qapi/error.h" 18765c9429SGerd Hoffmann 19765c9429SGerd Hoffmann #include "ui/console.h" 20765c9429SGerd Hoffmann #include "ui/qemu-pixman.h" 21db1015e9SEduardo Habkost #include "qom/object.h" 22765c9429SGerd Hoffmann 23765c9429SGerd Hoffmann typedef struct BochsDisplayMode { 24765c9429SGerd Hoffmann pixman_format_code_t format; 25765c9429SGerd Hoffmann uint32_t bytepp; 26765c9429SGerd Hoffmann uint32_t width; 27765c9429SGerd Hoffmann uint32_t height; 28765c9429SGerd Hoffmann uint32_t stride; 29765c9429SGerd Hoffmann uint64_t offset; 30765c9429SGerd Hoffmann uint64_t size; 31765c9429SGerd Hoffmann } BochsDisplayMode; 32765c9429SGerd Hoffmann 33db1015e9SEduardo Habkost struct BochsDisplayState { 34765c9429SGerd Hoffmann /* parent */ 35765c9429SGerd Hoffmann PCIDevice pci; 36765c9429SGerd Hoffmann 37765c9429SGerd Hoffmann /* device elements */ 38765c9429SGerd Hoffmann QemuConsole *con; 39765c9429SGerd Hoffmann MemoryRegion vram; 40765c9429SGerd Hoffmann MemoryRegion mmio; 41765c9429SGerd Hoffmann MemoryRegion vbe; 42765c9429SGerd Hoffmann MemoryRegion qext; 43a0d098b7SGerd Hoffmann MemoryRegion edid; 44765c9429SGerd Hoffmann 45765c9429SGerd Hoffmann /* device config */ 46765c9429SGerd Hoffmann uint64_t vgamem; 47a0d098b7SGerd Hoffmann bool enable_edid; 48a0d098b7SGerd Hoffmann qemu_edid_info edid_info; 49a0d098b7SGerd Hoffmann uint8_t edid_blob[256]; 50765c9429SGerd Hoffmann 51765c9429SGerd Hoffmann /* device registers */ 52765c9429SGerd Hoffmann uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; 53765c9429SGerd Hoffmann bool big_endian_fb; 54765c9429SGerd Hoffmann 55765c9429SGerd Hoffmann /* device state */ 56765c9429SGerd Hoffmann BochsDisplayMode mode; 57db1015e9SEduardo Habkost }; 58765c9429SGerd Hoffmann 59765c9429SGerd Hoffmann #define TYPE_BOCHS_DISPLAY "bochs-display" 608063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(BochsDisplayState, BOCHS_DISPLAY) 61765c9429SGerd Hoffmann 62765c9429SGerd Hoffmann static const VMStateDescription vmstate_bochs_display = { 63765c9429SGerd Hoffmann .name = "bochs-display", 64f0613160SRichard Henderson .fields = (const VMStateField[]) { 65765c9429SGerd Hoffmann VMSTATE_PCI_DEVICE(pci, BochsDisplayState), 66765c9429SGerd Hoffmann VMSTATE_UINT16_ARRAY(vbe_regs, BochsDisplayState, VBE_DISPI_INDEX_NB), 67765c9429SGerd Hoffmann VMSTATE_BOOL(big_endian_fb, BochsDisplayState), 68765c9429SGerd Hoffmann VMSTATE_END_OF_LIST() 69765c9429SGerd Hoffmann } 70765c9429SGerd Hoffmann }; 71765c9429SGerd Hoffmann 72765c9429SGerd Hoffmann static uint64_t bochs_display_vbe_read(void *ptr, hwaddr addr, 73765c9429SGerd Hoffmann unsigned size) 74765c9429SGerd Hoffmann { 75765c9429SGerd Hoffmann BochsDisplayState *s = ptr; 76765c9429SGerd Hoffmann unsigned int index = addr >> 1; 77765c9429SGerd Hoffmann 78765c9429SGerd Hoffmann switch (index) { 79765c9429SGerd Hoffmann case VBE_DISPI_INDEX_ID: 80765c9429SGerd Hoffmann return VBE_DISPI_ID5; 81765c9429SGerd Hoffmann case VBE_DISPI_INDEX_VIDEO_MEMORY_64K: 82f0353b0dSPhilippe Mathieu-Daudé return s->vgamem / (64 * KiB); 83765c9429SGerd Hoffmann } 84765c9429SGerd Hoffmann 85765c9429SGerd Hoffmann if (index >= ARRAY_SIZE(s->vbe_regs)) { 86765c9429SGerd Hoffmann return -1; 87765c9429SGerd Hoffmann } 88765c9429SGerd Hoffmann return s->vbe_regs[index]; 89765c9429SGerd Hoffmann } 90765c9429SGerd Hoffmann 91765c9429SGerd Hoffmann static void bochs_display_vbe_write(void *ptr, hwaddr addr, 92765c9429SGerd Hoffmann uint64_t val, unsigned size) 93765c9429SGerd Hoffmann { 94765c9429SGerd Hoffmann BochsDisplayState *s = ptr; 95765c9429SGerd Hoffmann unsigned int index = addr >> 1; 96765c9429SGerd Hoffmann 97765c9429SGerd Hoffmann if (index >= ARRAY_SIZE(s->vbe_regs)) { 98765c9429SGerd Hoffmann return; 99765c9429SGerd Hoffmann } 100765c9429SGerd Hoffmann s->vbe_regs[index] = val; 101765c9429SGerd Hoffmann } 102765c9429SGerd Hoffmann 103765c9429SGerd Hoffmann static const MemoryRegionOps bochs_display_vbe_ops = { 104765c9429SGerd Hoffmann .read = bochs_display_vbe_read, 105765c9429SGerd Hoffmann .write = bochs_display_vbe_write, 106765c9429SGerd Hoffmann .valid.min_access_size = 1, 107765c9429SGerd Hoffmann .valid.max_access_size = 4, 108765c9429SGerd Hoffmann .impl.min_access_size = 2, 109765c9429SGerd Hoffmann .impl.max_access_size = 2, 110765c9429SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 111765c9429SGerd Hoffmann }; 112765c9429SGerd Hoffmann 113765c9429SGerd Hoffmann static uint64_t bochs_display_qext_read(void *ptr, hwaddr addr, 114765c9429SGerd Hoffmann unsigned size) 115765c9429SGerd Hoffmann { 116765c9429SGerd Hoffmann BochsDisplayState *s = ptr; 117765c9429SGerd Hoffmann 118765c9429SGerd Hoffmann switch (addr) { 119765c9429SGerd Hoffmann case PCI_VGA_QEXT_REG_SIZE: 120765c9429SGerd Hoffmann return PCI_VGA_QEXT_SIZE; 121765c9429SGerd Hoffmann case PCI_VGA_QEXT_REG_BYTEORDER: 122765c9429SGerd Hoffmann return s->big_endian_fb ? 123765c9429SGerd Hoffmann PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN; 124765c9429SGerd Hoffmann default: 125765c9429SGerd Hoffmann return 0; 126765c9429SGerd Hoffmann } 127765c9429SGerd Hoffmann } 128765c9429SGerd Hoffmann 129765c9429SGerd Hoffmann static void bochs_display_qext_write(void *ptr, hwaddr addr, 130765c9429SGerd Hoffmann uint64_t val, unsigned size) 131765c9429SGerd Hoffmann { 132765c9429SGerd Hoffmann BochsDisplayState *s = ptr; 133765c9429SGerd Hoffmann 134765c9429SGerd Hoffmann switch (addr) { 135765c9429SGerd Hoffmann case PCI_VGA_QEXT_REG_BYTEORDER: 136765c9429SGerd Hoffmann if (val == PCI_VGA_QEXT_BIG_ENDIAN) { 137765c9429SGerd Hoffmann s->big_endian_fb = true; 138765c9429SGerd Hoffmann } 139765c9429SGerd Hoffmann if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) { 140765c9429SGerd Hoffmann s->big_endian_fb = false; 141765c9429SGerd Hoffmann } 142765c9429SGerd Hoffmann break; 143765c9429SGerd Hoffmann } 144765c9429SGerd Hoffmann } 145765c9429SGerd Hoffmann 146765c9429SGerd Hoffmann static const MemoryRegionOps bochs_display_qext_ops = { 147765c9429SGerd Hoffmann .read = bochs_display_qext_read, 148765c9429SGerd Hoffmann .write = bochs_display_qext_write, 149765c9429SGerd Hoffmann .valid.min_access_size = 4, 150765c9429SGerd Hoffmann .valid.max_access_size = 4, 151765c9429SGerd Hoffmann .endianness = DEVICE_LITTLE_ENDIAN, 152765c9429SGerd Hoffmann }; 153765c9429SGerd Hoffmann 154765c9429SGerd Hoffmann static int bochs_display_get_mode(BochsDisplayState *s, 155765c9429SGerd Hoffmann BochsDisplayMode *mode) 156765c9429SGerd Hoffmann { 157765c9429SGerd Hoffmann uint16_t *vbe = s->vbe_regs; 158765c9429SGerd Hoffmann uint32_t virt_width; 159765c9429SGerd Hoffmann 160765c9429SGerd Hoffmann if (!(vbe[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { 161765c9429SGerd Hoffmann return -1; 162765c9429SGerd Hoffmann } 163765c9429SGerd Hoffmann 164765c9429SGerd Hoffmann memset(mode, 0, sizeof(*mode)); 165765c9429SGerd Hoffmann switch (vbe[VBE_DISPI_INDEX_BPP]) { 166765c9429SGerd Hoffmann case 16: 16733a52307SMichael Tokarev /* best effort: support native endianness only */ 168765c9429SGerd Hoffmann mode->format = PIXMAN_r5g6b5; 169765c9429SGerd Hoffmann mode->bytepp = 2; 170bc820db0SGerd Hoffmann break; 171765c9429SGerd Hoffmann case 32: 172765c9429SGerd Hoffmann mode->format = s->big_endian_fb 173765c9429SGerd Hoffmann ? PIXMAN_BE_x8r8g8b8 174765c9429SGerd Hoffmann : PIXMAN_LE_x8r8g8b8; 175765c9429SGerd Hoffmann mode->bytepp = 4; 176765c9429SGerd Hoffmann break; 177765c9429SGerd Hoffmann default: 178765c9429SGerd Hoffmann return -1; 179765c9429SGerd Hoffmann } 180765c9429SGerd Hoffmann 181765c9429SGerd Hoffmann mode->width = vbe[VBE_DISPI_INDEX_XRES]; 182765c9429SGerd Hoffmann mode->height = vbe[VBE_DISPI_INDEX_YRES]; 183765c9429SGerd Hoffmann virt_width = vbe[VBE_DISPI_INDEX_VIRT_WIDTH]; 184765c9429SGerd Hoffmann if (virt_width < mode->width) { 185765c9429SGerd Hoffmann virt_width = mode->width; 186765c9429SGerd Hoffmann } 187765c9429SGerd Hoffmann mode->stride = virt_width * mode->bytepp; 188765c9429SGerd Hoffmann mode->size = (uint64_t)mode->stride * mode->height; 189765c9429SGerd Hoffmann mode->offset = ((uint64_t)vbe[VBE_DISPI_INDEX_X_OFFSET] * mode->bytepp + 190765c9429SGerd Hoffmann (uint64_t)vbe[VBE_DISPI_INDEX_Y_OFFSET] * mode->stride); 191765c9429SGerd Hoffmann 192765c9429SGerd Hoffmann if (mode->width < 64 || mode->height < 64) { 193765c9429SGerd Hoffmann return -1; 194765c9429SGerd Hoffmann } 195765c9429SGerd Hoffmann if (mode->offset + mode->size > s->vgamem) { 196765c9429SGerd Hoffmann return -1; 197765c9429SGerd Hoffmann } 198765c9429SGerd Hoffmann return 0; 199765c9429SGerd Hoffmann } 200765c9429SGerd Hoffmann 201765c9429SGerd Hoffmann static void bochs_display_update(void *opaque) 202765c9429SGerd Hoffmann { 203765c9429SGerd Hoffmann BochsDisplayState *s = opaque; 20433ebad54SGerd Hoffmann DirtyBitmapSnapshot *snap = NULL; 20533ebad54SGerd Hoffmann bool full_update = false; 206765c9429SGerd Hoffmann BochsDisplayMode mode; 207765c9429SGerd Hoffmann DisplaySurface *ds; 208765c9429SGerd Hoffmann uint8_t *ptr; 20933ebad54SGerd Hoffmann bool dirty; 21033ebad54SGerd Hoffmann int y, ys, ret; 211765c9429SGerd Hoffmann 212765c9429SGerd Hoffmann ret = bochs_display_get_mode(s, &mode); 213765c9429SGerd Hoffmann if (ret < 0) { 214765c9429SGerd Hoffmann /* no (valid) video mode */ 215765c9429SGerd Hoffmann return; 216765c9429SGerd Hoffmann } 217765c9429SGerd Hoffmann 218765c9429SGerd Hoffmann if (memcmp(&s->mode, &mode, sizeof(mode)) != 0) { 219765c9429SGerd Hoffmann /* video mode switch */ 220765c9429SGerd Hoffmann s->mode = mode; 221765c9429SGerd Hoffmann ptr = memory_region_get_ram_ptr(&s->vram); 222765c9429SGerd Hoffmann ds = qemu_create_displaysurface_from(mode.width, 223765c9429SGerd Hoffmann mode.height, 224765c9429SGerd Hoffmann mode.format, 225765c9429SGerd Hoffmann mode.stride, 226765c9429SGerd Hoffmann ptr + mode.offset); 227765c9429SGerd Hoffmann dpy_gfx_replace_surface(s->con, ds); 22833ebad54SGerd Hoffmann full_update = true; 229765c9429SGerd Hoffmann } 230765c9429SGerd Hoffmann 23133ebad54SGerd Hoffmann if (full_update) { 232765c9429SGerd Hoffmann dpy_gfx_update_full(s->con); 23333ebad54SGerd Hoffmann } else { 23433ebad54SGerd Hoffmann snap = memory_region_snapshot_and_clear_dirty(&s->vram, 23533ebad54SGerd Hoffmann mode.offset, mode.size, 23633ebad54SGerd Hoffmann DIRTY_MEMORY_VGA); 23733ebad54SGerd Hoffmann ys = -1; 23833ebad54SGerd Hoffmann for (y = 0; y < mode.height; y++) { 23933ebad54SGerd Hoffmann dirty = memory_region_snapshot_get_dirty(&s->vram, snap, 24033ebad54SGerd Hoffmann mode.offset + mode.stride * y, 24133ebad54SGerd Hoffmann mode.stride); 24233ebad54SGerd Hoffmann if (dirty && ys < 0) { 24333ebad54SGerd Hoffmann ys = y; 24433ebad54SGerd Hoffmann } 24533ebad54SGerd Hoffmann if (!dirty && ys >= 0) { 24633ebad54SGerd Hoffmann dpy_gfx_update(s->con, 0, ys, 24733ebad54SGerd Hoffmann mode.width, y - ys); 24833ebad54SGerd Hoffmann ys = -1; 24933ebad54SGerd Hoffmann } 25033ebad54SGerd Hoffmann } 25133ebad54SGerd Hoffmann if (ys >= 0) { 25233ebad54SGerd Hoffmann dpy_gfx_update(s->con, 0, ys, 25333ebad54SGerd Hoffmann mode.width, y - ys); 25433ebad54SGerd Hoffmann } 2550d82411dSCameron Esfahani 2560d82411dSCameron Esfahani g_free(snap); 25733ebad54SGerd Hoffmann } 258765c9429SGerd Hoffmann } 259765c9429SGerd Hoffmann 260765c9429SGerd Hoffmann static const GraphicHwOps bochs_display_gfx_ops = { 261765c9429SGerd Hoffmann .gfx_update = bochs_display_update, 262765c9429SGerd Hoffmann }; 263765c9429SGerd Hoffmann 264765c9429SGerd Hoffmann static void bochs_display_realize(PCIDevice *dev, Error **errp) 265765c9429SGerd Hoffmann { 266765c9429SGerd Hoffmann BochsDisplayState *s = BOCHS_DISPLAY(dev); 267765c9429SGerd Hoffmann Object *obj = OBJECT(dev); 268f2581064SGerd Hoffmann int ret; 269765c9429SGerd Hoffmann 270f0353b0dSPhilippe Mathieu-Daudé if (s->vgamem < 4 * MiB) { 271765c9429SGerd Hoffmann error_setg(errp, "bochs-display: video memory too small"); 272ee29f6e9SMarkus Armbruster return; 273765c9429SGerd Hoffmann } 274f0353b0dSPhilippe Mathieu-Daudé if (s->vgamem > 256 * MiB) { 275765c9429SGerd Hoffmann error_setg(errp, "bochs-display: video memory too big"); 276ee29f6e9SMarkus Armbruster return; 277765c9429SGerd Hoffmann } 278765c9429SGerd Hoffmann s->vgamem = pow2ceil(s->vgamem); 279765c9429SGerd Hoffmann 280ee29f6e9SMarkus Armbruster s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s); 281ee29f6e9SMarkus Armbruster 282765c9429SGerd Hoffmann memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem, 283765c9429SGerd Hoffmann &error_fatal); 284765c9429SGerd Hoffmann memory_region_init_io(&s->vbe, obj, &bochs_display_vbe_ops, s, 285765c9429SGerd Hoffmann "bochs dispi interface", PCI_VGA_BOCHS_SIZE); 286765c9429SGerd Hoffmann memory_region_init_io(&s->qext, obj, &bochs_display_qext_ops, s, 287765c9429SGerd Hoffmann "qemu extended regs", PCI_VGA_QEXT_SIZE); 288765c9429SGerd Hoffmann 289f872c762SGerd Hoffmann memory_region_init_io(&s->mmio, obj, &unassigned_io_ops, NULL, 290f872c762SGerd Hoffmann "bochs-display-mmio", PCI_VGA_MMIO_SIZE); 291765c9429SGerd Hoffmann memory_region_add_subregion(&s->mmio, PCI_VGA_BOCHS_OFFSET, &s->vbe); 292765c9429SGerd Hoffmann memory_region_add_subregion(&s->mmio, PCI_VGA_QEXT_OFFSET, &s->qext); 293765c9429SGerd Hoffmann 294765c9429SGerd Hoffmann pci_set_byte(&s->pci.config[PCI_REVISION_ID], 2); 295765c9429SGerd Hoffmann pci_register_bar(&s->pci, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram); 296765c9429SGerd Hoffmann pci_register_bar(&s->pci, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio); 29733ebad54SGerd Hoffmann 298a0d098b7SGerd Hoffmann if (s->enable_edid) { 299a0d098b7SGerd Hoffmann qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info); 300a0d098b7SGerd Hoffmann qemu_edid_region_io(&s->edid, obj, s->edid_blob, sizeof(s->edid_blob)); 301a0d098b7SGerd Hoffmann memory_region_add_subregion(&s->mmio, 0, &s->edid); 302a0d098b7SGerd Hoffmann } 303a0d098b7SGerd Hoffmann 304f2581064SGerd Hoffmann if (pci_bus_is_express(pci_get_bus(dev))) { 305f2581064SGerd Hoffmann ret = pcie_endpoint_cap_init(dev, 0x80); 306f2581064SGerd Hoffmann assert(ret > 0); 3075e7bcdcfSGerd Hoffmann } else { 3085e7bcdcfSGerd Hoffmann dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS; 309f2581064SGerd Hoffmann } 310f2581064SGerd Hoffmann 31133ebad54SGerd Hoffmann memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA); 312765c9429SGerd Hoffmann } 313765c9429SGerd Hoffmann 314765c9429SGerd Hoffmann static bool bochs_display_get_big_endian_fb(Object *obj, Error **errp) 315765c9429SGerd Hoffmann { 316765c9429SGerd Hoffmann BochsDisplayState *s = BOCHS_DISPLAY(obj); 317765c9429SGerd Hoffmann 318765c9429SGerd Hoffmann return s->big_endian_fb; 319765c9429SGerd Hoffmann } 320765c9429SGerd Hoffmann 321765c9429SGerd Hoffmann static void bochs_display_set_big_endian_fb(Object *obj, bool value, 322765c9429SGerd Hoffmann Error **errp) 323765c9429SGerd Hoffmann { 324765c9429SGerd Hoffmann BochsDisplayState *s = BOCHS_DISPLAY(obj); 325765c9429SGerd Hoffmann 326765c9429SGerd Hoffmann s->big_endian_fb = value; 327765c9429SGerd Hoffmann } 328765c9429SGerd Hoffmann 329765c9429SGerd Hoffmann static void bochs_display_init(Object *obj) 330765c9429SGerd Hoffmann { 3315e7bcdcfSGerd Hoffmann PCIDevice *dev = PCI_DEVICE(obj); 3325e7bcdcfSGerd Hoffmann 333765c9429SGerd Hoffmann /* Expose framebuffer byteorder via QOM */ 334765c9429SGerd Hoffmann object_property_add_bool(obj, "big-endian-framebuffer", 335765c9429SGerd Hoffmann bochs_display_get_big_endian_fb, 336d2623129SMarkus Armbruster bochs_display_set_big_endian_fb); 3375e7bcdcfSGerd Hoffmann 3385e7bcdcfSGerd Hoffmann dev->cap_present |= QEMU_PCI_CAP_EXPRESS; 339765c9429SGerd Hoffmann } 340765c9429SGerd Hoffmann 341765c9429SGerd Hoffmann static void bochs_display_exit(PCIDevice *dev) 342765c9429SGerd Hoffmann { 343765c9429SGerd Hoffmann BochsDisplayState *s = BOCHS_DISPLAY(dev); 344765c9429SGerd Hoffmann 345765c9429SGerd Hoffmann graphic_console_close(s->con); 346765c9429SGerd Hoffmann } 347765c9429SGerd Hoffmann 348d432edd5SRichard Henderson static const Property bochs_display_properties[] = { 349f0353b0dSPhilippe Mathieu-Daudé DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * MiB), 3500a719662SGerd Hoffmann DEFINE_PROP_BOOL("edid", BochsDisplayState, enable_edid, true), 351a0d098b7SGerd Hoffmann DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info), 352765c9429SGerd Hoffmann }; 353765c9429SGerd Hoffmann 35412d1a768SPhilippe Mathieu-Daudé static void bochs_display_class_init(ObjectClass *klass, const void *data) 355765c9429SGerd Hoffmann { 356765c9429SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 357765c9429SGerd Hoffmann PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 358765c9429SGerd Hoffmann 359765c9429SGerd Hoffmann k->class_id = PCI_CLASS_DISPLAY_OTHER; 360765c9429SGerd Hoffmann k->vendor_id = PCI_VENDOR_ID_QEMU; 361765c9429SGerd Hoffmann k->device_id = PCI_DEVICE_ID_QEMU_VGA; 362765c9429SGerd Hoffmann 363765c9429SGerd Hoffmann k->realize = bochs_display_realize; 3647c538789SGerd Hoffmann k->romfile = "vgabios-bochs-display.bin"; 365765c9429SGerd Hoffmann k->exit = bochs_display_exit; 366765c9429SGerd Hoffmann dc->vmsd = &vmstate_bochs_display; 3674f67d30bSMarc-André Lureau device_class_set_props(dc, bochs_display_properties); 368765c9429SGerd Hoffmann set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 369765c9429SGerd Hoffmann } 370765c9429SGerd Hoffmann 371765c9429SGerd Hoffmann static const TypeInfo bochs_display_type_info = { 372765c9429SGerd Hoffmann .name = TYPE_BOCHS_DISPLAY, 373765c9429SGerd Hoffmann .parent = TYPE_PCI_DEVICE, 374765c9429SGerd Hoffmann .instance_size = sizeof(BochsDisplayState), 375765c9429SGerd Hoffmann .instance_init = bochs_display_init, 376765c9429SGerd Hoffmann .class_init = bochs_display_class_init, 377*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) { 378f2581064SGerd Hoffmann { INTERFACE_PCIE_DEVICE }, 379765c9429SGerd Hoffmann { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 380765c9429SGerd Hoffmann { }, 381765c9429SGerd Hoffmann }, 382765c9429SGerd Hoffmann }; 383765c9429SGerd Hoffmann 384765c9429SGerd Hoffmann static void bochs_display_register_types(void) 385765c9429SGerd Hoffmann { 386765c9429SGerd Hoffmann type_register_static(&bochs_display_type_info); 387765c9429SGerd Hoffmann } 388765c9429SGerd Hoffmann 389765c9429SGerd Hoffmann type_init(bochs_display_register_types) 390