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
bochs_display_vbe_read(void * ptr,hwaddr addr,unsigned size)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
bochs_display_vbe_write(void * ptr,hwaddr addr,uint64_t val,unsigned size)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
bochs_display_qext_read(void * ptr,hwaddr addr,unsigned size)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
bochs_display_qext_write(void * ptr,hwaddr addr,uint64_t val,unsigned size)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
bochs_display_get_mode(BochsDisplayState * s,BochsDisplayMode * mode)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
bochs_display_update(void * opaque)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
bochs_display_realize(PCIDevice * dev,Error ** errp)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
bochs_display_get_big_endian_fb(Object * obj,Error ** errp)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
bochs_display_set_big_endian_fb(Object * obj,bool value,Error ** errp)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
bochs_display_init(Object * obj)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
bochs_display_exit(PCIDevice * dev)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
bochs_display_class_init(ObjectClass * klass,const void * data)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
bochs_display_register_types(void)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