xref: /qemu/hw/display/bochs-display.c (revision 5e7bcdcfe69ce0fad66012b2cfb2035003c37eef)
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"
11765c9429SGerd Hoffmann #include "hw/hw.h"
12765c9429SGerd Hoffmann #include "hw/pci/pci.h"
13765c9429SGerd Hoffmann #include "hw/display/bochs-vbe.h"
14a0d098b7SGerd Hoffmann #include "hw/display/edid.h"
15765c9429SGerd Hoffmann 
16765c9429SGerd Hoffmann #include "qapi/error.h"
17765c9429SGerd Hoffmann 
18765c9429SGerd Hoffmann #include "ui/console.h"
19765c9429SGerd Hoffmann #include "ui/qemu-pixman.h"
20765c9429SGerd Hoffmann 
21765c9429SGerd Hoffmann typedef struct BochsDisplayMode {
22765c9429SGerd Hoffmann     pixman_format_code_t format;
23765c9429SGerd Hoffmann     uint32_t             bytepp;
24765c9429SGerd Hoffmann     uint32_t             width;
25765c9429SGerd Hoffmann     uint32_t             height;
26765c9429SGerd Hoffmann     uint32_t             stride;
27765c9429SGerd Hoffmann     uint64_t             offset;
28765c9429SGerd Hoffmann     uint64_t             size;
29765c9429SGerd Hoffmann } BochsDisplayMode;
30765c9429SGerd Hoffmann 
31765c9429SGerd Hoffmann typedef struct BochsDisplayState {
32765c9429SGerd Hoffmann     /* parent */
33765c9429SGerd Hoffmann     PCIDevice        pci;
34765c9429SGerd Hoffmann 
35765c9429SGerd Hoffmann     /* device elements */
36765c9429SGerd Hoffmann     QemuConsole      *con;
37765c9429SGerd Hoffmann     MemoryRegion     vram;
38765c9429SGerd Hoffmann     MemoryRegion     mmio;
39765c9429SGerd Hoffmann     MemoryRegion     vbe;
40765c9429SGerd Hoffmann     MemoryRegion     qext;
41a0d098b7SGerd Hoffmann     MemoryRegion     edid;
42765c9429SGerd Hoffmann 
43765c9429SGerd Hoffmann     /* device config */
44765c9429SGerd Hoffmann     uint64_t         vgamem;
45a0d098b7SGerd Hoffmann     bool             enable_edid;
46a0d098b7SGerd Hoffmann     qemu_edid_info   edid_info;
47a0d098b7SGerd Hoffmann     uint8_t          edid_blob[256];
48765c9429SGerd Hoffmann 
49765c9429SGerd Hoffmann     /* device registers */
50765c9429SGerd Hoffmann     uint16_t         vbe_regs[VBE_DISPI_INDEX_NB];
51765c9429SGerd Hoffmann     bool             big_endian_fb;
52765c9429SGerd Hoffmann 
53765c9429SGerd Hoffmann     /* device state */
54765c9429SGerd Hoffmann     BochsDisplayMode mode;
55765c9429SGerd Hoffmann } BochsDisplayState;
56765c9429SGerd Hoffmann 
57765c9429SGerd Hoffmann #define TYPE_BOCHS_DISPLAY "bochs-display"
58765c9429SGerd Hoffmann #define BOCHS_DISPLAY(obj) OBJECT_CHECK(BochsDisplayState, (obj), \
59765c9429SGerd Hoffmann                                         TYPE_BOCHS_DISPLAY)
60765c9429SGerd Hoffmann 
61765c9429SGerd Hoffmann static const VMStateDescription vmstate_bochs_display = {
62765c9429SGerd Hoffmann     .name = "bochs-display",
63765c9429SGerd Hoffmann     .fields = (VMStateField[]) {
64765c9429SGerd Hoffmann         VMSTATE_PCI_DEVICE(pci, BochsDisplayState),
65765c9429SGerd Hoffmann         VMSTATE_UINT16_ARRAY(vbe_regs, BochsDisplayState, VBE_DISPI_INDEX_NB),
66765c9429SGerd Hoffmann         VMSTATE_BOOL(big_endian_fb, BochsDisplayState),
67765c9429SGerd Hoffmann         VMSTATE_END_OF_LIST()
68765c9429SGerd Hoffmann     }
69765c9429SGerd Hoffmann };
70765c9429SGerd Hoffmann 
71765c9429SGerd Hoffmann static uint64_t bochs_display_vbe_read(void *ptr, hwaddr addr,
72765c9429SGerd Hoffmann                                        unsigned size)
73765c9429SGerd Hoffmann {
74765c9429SGerd Hoffmann     BochsDisplayState *s = ptr;
75765c9429SGerd Hoffmann     unsigned int index = addr >> 1;
76765c9429SGerd Hoffmann 
77765c9429SGerd Hoffmann     switch (index) {
78765c9429SGerd Hoffmann     case VBE_DISPI_INDEX_ID:
79765c9429SGerd Hoffmann         return VBE_DISPI_ID5;
80765c9429SGerd Hoffmann     case VBE_DISPI_INDEX_VIDEO_MEMORY_64K:
81f0353b0dSPhilippe Mathieu-Daudé         return s->vgamem / (64 * KiB);
82765c9429SGerd Hoffmann     }
83765c9429SGerd Hoffmann 
84765c9429SGerd Hoffmann     if (index >= ARRAY_SIZE(s->vbe_regs)) {
85765c9429SGerd Hoffmann         return -1;
86765c9429SGerd Hoffmann     }
87765c9429SGerd Hoffmann     return s->vbe_regs[index];
88765c9429SGerd Hoffmann }
89765c9429SGerd Hoffmann 
90765c9429SGerd Hoffmann static void bochs_display_vbe_write(void *ptr, hwaddr addr,
91765c9429SGerd Hoffmann                                     uint64_t val, unsigned size)
92765c9429SGerd Hoffmann {
93765c9429SGerd Hoffmann     BochsDisplayState *s = ptr;
94765c9429SGerd Hoffmann     unsigned int index = addr >> 1;
95765c9429SGerd Hoffmann 
96765c9429SGerd Hoffmann     if (index >= ARRAY_SIZE(s->vbe_regs)) {
97765c9429SGerd Hoffmann         return;
98765c9429SGerd Hoffmann     }
99765c9429SGerd Hoffmann     s->vbe_regs[index] = val;
100765c9429SGerd Hoffmann }
101765c9429SGerd Hoffmann 
102765c9429SGerd Hoffmann static const MemoryRegionOps bochs_display_vbe_ops = {
103765c9429SGerd Hoffmann     .read = bochs_display_vbe_read,
104765c9429SGerd Hoffmann     .write = bochs_display_vbe_write,
105765c9429SGerd Hoffmann     .valid.min_access_size = 1,
106765c9429SGerd Hoffmann     .valid.max_access_size = 4,
107765c9429SGerd Hoffmann     .impl.min_access_size = 2,
108765c9429SGerd Hoffmann     .impl.max_access_size = 2,
109765c9429SGerd Hoffmann     .endianness = DEVICE_LITTLE_ENDIAN,
110765c9429SGerd Hoffmann };
111765c9429SGerd Hoffmann 
112765c9429SGerd Hoffmann static uint64_t bochs_display_qext_read(void *ptr, hwaddr addr,
113765c9429SGerd Hoffmann                                         unsigned size)
114765c9429SGerd Hoffmann {
115765c9429SGerd Hoffmann     BochsDisplayState *s = ptr;
116765c9429SGerd Hoffmann 
117765c9429SGerd Hoffmann     switch (addr) {
118765c9429SGerd Hoffmann     case PCI_VGA_QEXT_REG_SIZE:
119765c9429SGerd Hoffmann         return PCI_VGA_QEXT_SIZE;
120765c9429SGerd Hoffmann     case PCI_VGA_QEXT_REG_BYTEORDER:
121765c9429SGerd Hoffmann         return s->big_endian_fb ?
122765c9429SGerd Hoffmann             PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN;
123765c9429SGerd Hoffmann     default:
124765c9429SGerd Hoffmann         return 0;
125765c9429SGerd Hoffmann     }
126765c9429SGerd Hoffmann }
127765c9429SGerd Hoffmann 
128765c9429SGerd Hoffmann static void bochs_display_qext_write(void *ptr, hwaddr addr,
129765c9429SGerd Hoffmann                                      uint64_t val, unsigned size)
130765c9429SGerd Hoffmann {
131765c9429SGerd Hoffmann     BochsDisplayState *s = ptr;
132765c9429SGerd Hoffmann 
133765c9429SGerd Hoffmann     switch (addr) {
134765c9429SGerd Hoffmann     case PCI_VGA_QEXT_REG_BYTEORDER:
135765c9429SGerd Hoffmann         if (val == PCI_VGA_QEXT_BIG_ENDIAN) {
136765c9429SGerd Hoffmann             s->big_endian_fb = true;
137765c9429SGerd Hoffmann         }
138765c9429SGerd Hoffmann         if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) {
139765c9429SGerd Hoffmann             s->big_endian_fb = false;
140765c9429SGerd Hoffmann         }
141765c9429SGerd Hoffmann         break;
142765c9429SGerd Hoffmann     }
143765c9429SGerd Hoffmann }
144765c9429SGerd Hoffmann 
145765c9429SGerd Hoffmann static const MemoryRegionOps bochs_display_qext_ops = {
146765c9429SGerd Hoffmann     .read = bochs_display_qext_read,
147765c9429SGerd Hoffmann     .write = bochs_display_qext_write,
148765c9429SGerd Hoffmann     .valid.min_access_size = 4,
149765c9429SGerd Hoffmann     .valid.max_access_size = 4,
150765c9429SGerd Hoffmann     .endianness = DEVICE_LITTLE_ENDIAN,
151765c9429SGerd Hoffmann };
152765c9429SGerd Hoffmann 
153765c9429SGerd Hoffmann static int bochs_display_get_mode(BochsDisplayState *s,
154765c9429SGerd Hoffmann                                    BochsDisplayMode *mode)
155765c9429SGerd Hoffmann {
156765c9429SGerd Hoffmann     uint16_t *vbe = s->vbe_regs;
157765c9429SGerd Hoffmann     uint32_t virt_width;
158765c9429SGerd Hoffmann 
159765c9429SGerd Hoffmann     if (!(vbe[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
160765c9429SGerd Hoffmann         return -1;
161765c9429SGerd Hoffmann     }
162765c9429SGerd Hoffmann 
163765c9429SGerd Hoffmann     memset(mode, 0, sizeof(*mode));
164765c9429SGerd Hoffmann     switch (vbe[VBE_DISPI_INDEX_BPP]) {
165765c9429SGerd Hoffmann     case 16:
166765c9429SGerd Hoffmann         /* best effort: support native endianess only */
167765c9429SGerd Hoffmann         mode->format = PIXMAN_r5g6b5;
168765c9429SGerd Hoffmann         mode->bytepp = 2;
169bc820db0SGerd Hoffmann         break;
170765c9429SGerd Hoffmann     case 32:
171765c9429SGerd Hoffmann         mode->format = s->big_endian_fb
172765c9429SGerd Hoffmann             ? PIXMAN_BE_x8r8g8b8
173765c9429SGerd Hoffmann             : PIXMAN_LE_x8r8g8b8;
174765c9429SGerd Hoffmann         mode->bytepp = 4;
175765c9429SGerd Hoffmann         break;
176765c9429SGerd Hoffmann     default:
177765c9429SGerd Hoffmann         return -1;
178765c9429SGerd Hoffmann     }
179765c9429SGerd Hoffmann 
180765c9429SGerd Hoffmann     mode->width  = vbe[VBE_DISPI_INDEX_XRES];
181765c9429SGerd Hoffmann     mode->height = vbe[VBE_DISPI_INDEX_YRES];
182765c9429SGerd Hoffmann     virt_width  = vbe[VBE_DISPI_INDEX_VIRT_WIDTH];
183765c9429SGerd Hoffmann     if (virt_width < mode->width) {
184765c9429SGerd Hoffmann         virt_width = mode->width;
185765c9429SGerd Hoffmann     }
186765c9429SGerd Hoffmann     mode->stride = virt_width * mode->bytepp;
187765c9429SGerd Hoffmann     mode->size   = (uint64_t)mode->stride * mode->height;
188765c9429SGerd Hoffmann     mode->offset = ((uint64_t)vbe[VBE_DISPI_INDEX_X_OFFSET] * mode->bytepp +
189765c9429SGerd Hoffmann                     (uint64_t)vbe[VBE_DISPI_INDEX_Y_OFFSET] * mode->stride);
190765c9429SGerd Hoffmann 
191765c9429SGerd Hoffmann     if (mode->width < 64 || mode->height < 64) {
192765c9429SGerd Hoffmann         return -1;
193765c9429SGerd Hoffmann     }
194765c9429SGerd Hoffmann     if (mode->offset + mode->size > s->vgamem) {
195765c9429SGerd Hoffmann         return -1;
196765c9429SGerd Hoffmann     }
197765c9429SGerd Hoffmann     return 0;
198765c9429SGerd Hoffmann }
199765c9429SGerd Hoffmann 
200765c9429SGerd Hoffmann static void bochs_display_update(void *opaque)
201765c9429SGerd Hoffmann {
202765c9429SGerd Hoffmann     BochsDisplayState *s = opaque;
20333ebad54SGerd Hoffmann     DirtyBitmapSnapshot *snap = NULL;
20433ebad54SGerd Hoffmann     bool full_update = false;
205765c9429SGerd Hoffmann     BochsDisplayMode mode;
206765c9429SGerd Hoffmann     DisplaySurface *ds;
207765c9429SGerd Hoffmann     uint8_t *ptr;
20833ebad54SGerd Hoffmann     bool dirty;
20933ebad54SGerd Hoffmann     int y, ys, ret;
210765c9429SGerd Hoffmann 
211765c9429SGerd Hoffmann     ret = bochs_display_get_mode(s, &mode);
212765c9429SGerd Hoffmann     if (ret < 0) {
213765c9429SGerd Hoffmann         /* no (valid) video mode */
214765c9429SGerd Hoffmann         return;
215765c9429SGerd Hoffmann     }
216765c9429SGerd Hoffmann 
217765c9429SGerd Hoffmann     if (memcmp(&s->mode, &mode, sizeof(mode)) != 0) {
218765c9429SGerd Hoffmann         /* video mode switch */
219765c9429SGerd Hoffmann         s->mode = mode;
220765c9429SGerd Hoffmann         ptr = memory_region_get_ram_ptr(&s->vram);
221765c9429SGerd Hoffmann         ds = qemu_create_displaysurface_from(mode.width,
222765c9429SGerd Hoffmann                                              mode.height,
223765c9429SGerd Hoffmann                                              mode.format,
224765c9429SGerd Hoffmann                                              mode.stride,
225765c9429SGerd Hoffmann                                              ptr + mode.offset);
226765c9429SGerd Hoffmann         dpy_gfx_replace_surface(s->con, ds);
22733ebad54SGerd Hoffmann         full_update = true;
228765c9429SGerd Hoffmann     }
229765c9429SGerd Hoffmann 
23033ebad54SGerd Hoffmann     if (full_update) {
231765c9429SGerd Hoffmann         dpy_gfx_update_full(s->con);
23233ebad54SGerd Hoffmann     } else {
23333ebad54SGerd Hoffmann         snap = memory_region_snapshot_and_clear_dirty(&s->vram,
23433ebad54SGerd Hoffmann                                                       mode.offset, mode.size,
23533ebad54SGerd Hoffmann                                                       DIRTY_MEMORY_VGA);
23633ebad54SGerd Hoffmann         ys = -1;
23733ebad54SGerd Hoffmann         for (y = 0; y < mode.height; y++) {
23833ebad54SGerd Hoffmann             dirty = memory_region_snapshot_get_dirty(&s->vram, snap,
23933ebad54SGerd Hoffmann                                                      mode.offset + mode.stride * y,
24033ebad54SGerd Hoffmann                                                      mode.stride);
24133ebad54SGerd Hoffmann             if (dirty && ys < 0) {
24233ebad54SGerd Hoffmann                 ys = y;
24333ebad54SGerd Hoffmann             }
24433ebad54SGerd Hoffmann             if (!dirty && ys >= 0) {
24533ebad54SGerd Hoffmann                 dpy_gfx_update(s->con, 0, ys,
24633ebad54SGerd Hoffmann                                mode.width, y - ys);
24733ebad54SGerd Hoffmann                 ys = -1;
24833ebad54SGerd Hoffmann             }
24933ebad54SGerd Hoffmann         }
25033ebad54SGerd Hoffmann         if (ys >= 0) {
25133ebad54SGerd Hoffmann             dpy_gfx_update(s->con, 0, ys,
25233ebad54SGerd Hoffmann                            mode.width, y - ys);
25333ebad54SGerd Hoffmann         }
25433ebad54SGerd Hoffmann     }
255765c9429SGerd Hoffmann }
256765c9429SGerd Hoffmann 
257765c9429SGerd Hoffmann static const GraphicHwOps bochs_display_gfx_ops = {
258765c9429SGerd Hoffmann     .gfx_update = bochs_display_update,
259765c9429SGerd Hoffmann };
260765c9429SGerd Hoffmann 
261765c9429SGerd Hoffmann static void bochs_display_realize(PCIDevice *dev, Error **errp)
262765c9429SGerd Hoffmann {
263765c9429SGerd Hoffmann     BochsDisplayState *s = BOCHS_DISPLAY(dev);
264765c9429SGerd Hoffmann     Object *obj = OBJECT(dev);
265f2581064SGerd Hoffmann     int ret;
266765c9429SGerd Hoffmann 
267765c9429SGerd Hoffmann     s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s);
268765c9429SGerd Hoffmann 
269f0353b0dSPhilippe Mathieu-Daudé     if (s->vgamem < 4 * MiB) {
270765c9429SGerd Hoffmann         error_setg(errp, "bochs-display: video memory too small");
271765c9429SGerd Hoffmann     }
272f0353b0dSPhilippe Mathieu-Daudé     if (s->vgamem > 256 * MiB) {
273765c9429SGerd Hoffmann         error_setg(errp, "bochs-display: video memory too big");
274765c9429SGerd Hoffmann     }
275765c9429SGerd Hoffmann     s->vgamem = pow2ceil(s->vgamem);
276765c9429SGerd Hoffmann 
277765c9429SGerd Hoffmann     memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem,
278765c9429SGerd Hoffmann                            &error_fatal);
279765c9429SGerd Hoffmann     memory_region_init_io(&s->vbe, obj, &bochs_display_vbe_ops, s,
280765c9429SGerd Hoffmann                           "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
281765c9429SGerd Hoffmann     memory_region_init_io(&s->qext, obj, &bochs_display_qext_ops, s,
282765c9429SGerd Hoffmann                           "qemu extended regs", PCI_VGA_QEXT_SIZE);
283765c9429SGerd Hoffmann 
284765c9429SGerd Hoffmann     memory_region_init(&s->mmio, obj, "bochs-display-mmio",
285765c9429SGerd Hoffmann                        PCI_VGA_MMIO_SIZE);
286765c9429SGerd Hoffmann     memory_region_add_subregion(&s->mmio, PCI_VGA_BOCHS_OFFSET, &s->vbe);
287765c9429SGerd Hoffmann     memory_region_add_subregion(&s->mmio, PCI_VGA_QEXT_OFFSET, &s->qext);
288765c9429SGerd Hoffmann 
289765c9429SGerd Hoffmann     pci_set_byte(&s->pci.config[PCI_REVISION_ID], 2);
290765c9429SGerd Hoffmann     pci_register_bar(&s->pci, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
291765c9429SGerd Hoffmann     pci_register_bar(&s->pci, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
29233ebad54SGerd Hoffmann 
293a0d098b7SGerd Hoffmann     if (s->enable_edid) {
294a0d098b7SGerd Hoffmann         qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info);
295a0d098b7SGerd Hoffmann         qemu_edid_region_io(&s->edid, obj, s->edid_blob, sizeof(s->edid_blob));
296a0d098b7SGerd Hoffmann         memory_region_add_subregion(&s->mmio, 0, &s->edid);
297a0d098b7SGerd Hoffmann     }
298a0d098b7SGerd Hoffmann 
299f2581064SGerd Hoffmann     if (pci_bus_is_express(pci_get_bus(dev))) {
300f2581064SGerd Hoffmann         ret = pcie_endpoint_cap_init(dev, 0x80);
301f2581064SGerd Hoffmann         assert(ret > 0);
302*5e7bcdcfSGerd Hoffmann     } else {
303*5e7bcdcfSGerd Hoffmann         dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS;
304f2581064SGerd Hoffmann     }
305f2581064SGerd Hoffmann 
30633ebad54SGerd Hoffmann     memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
307765c9429SGerd Hoffmann }
308765c9429SGerd Hoffmann 
309765c9429SGerd Hoffmann static bool bochs_display_get_big_endian_fb(Object *obj, Error **errp)
310765c9429SGerd Hoffmann {
311765c9429SGerd Hoffmann     BochsDisplayState *s = BOCHS_DISPLAY(obj);
312765c9429SGerd Hoffmann 
313765c9429SGerd Hoffmann     return s->big_endian_fb;
314765c9429SGerd Hoffmann }
315765c9429SGerd Hoffmann 
316765c9429SGerd Hoffmann static void bochs_display_set_big_endian_fb(Object *obj, bool value,
317765c9429SGerd Hoffmann                                             Error **errp)
318765c9429SGerd Hoffmann {
319765c9429SGerd Hoffmann     BochsDisplayState *s = BOCHS_DISPLAY(obj);
320765c9429SGerd Hoffmann 
321765c9429SGerd Hoffmann     s->big_endian_fb = value;
322765c9429SGerd Hoffmann }
323765c9429SGerd Hoffmann 
324765c9429SGerd Hoffmann static void bochs_display_init(Object *obj)
325765c9429SGerd Hoffmann {
326*5e7bcdcfSGerd Hoffmann     PCIDevice *dev = PCI_DEVICE(obj);
327*5e7bcdcfSGerd Hoffmann 
328765c9429SGerd Hoffmann     /* Expose framebuffer byteorder via QOM */
329765c9429SGerd Hoffmann     object_property_add_bool(obj, "big-endian-framebuffer",
330765c9429SGerd Hoffmann                              bochs_display_get_big_endian_fb,
331765c9429SGerd Hoffmann                              bochs_display_set_big_endian_fb,
332765c9429SGerd Hoffmann                              NULL);
333*5e7bcdcfSGerd Hoffmann 
334*5e7bcdcfSGerd Hoffmann     dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
335765c9429SGerd Hoffmann }
336765c9429SGerd Hoffmann 
337765c9429SGerd Hoffmann static void bochs_display_exit(PCIDevice *dev)
338765c9429SGerd Hoffmann {
339765c9429SGerd Hoffmann     BochsDisplayState *s = BOCHS_DISPLAY(dev);
340765c9429SGerd Hoffmann 
341765c9429SGerd Hoffmann     graphic_console_close(s->con);
342765c9429SGerd Hoffmann }
343765c9429SGerd Hoffmann 
344765c9429SGerd Hoffmann static Property bochs_display_properties[] = {
345f0353b0dSPhilippe Mathieu-Daudé     DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * MiB),
3460a719662SGerd Hoffmann     DEFINE_PROP_BOOL("edid", BochsDisplayState, enable_edid, true),
347a0d098b7SGerd Hoffmann     DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info),
348765c9429SGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
349765c9429SGerd Hoffmann };
350765c9429SGerd Hoffmann 
351765c9429SGerd Hoffmann static void bochs_display_class_init(ObjectClass *klass, void *data)
352765c9429SGerd Hoffmann {
353765c9429SGerd Hoffmann     DeviceClass *dc = DEVICE_CLASS(klass);
354765c9429SGerd Hoffmann     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
355765c9429SGerd Hoffmann 
356765c9429SGerd Hoffmann     k->class_id  = PCI_CLASS_DISPLAY_OTHER;
357765c9429SGerd Hoffmann     k->vendor_id = PCI_VENDOR_ID_QEMU;
358765c9429SGerd Hoffmann     k->device_id = PCI_DEVICE_ID_QEMU_VGA;
359765c9429SGerd Hoffmann 
360765c9429SGerd Hoffmann     k->realize   = bochs_display_realize;
3617c538789SGerd Hoffmann     k->romfile   = "vgabios-bochs-display.bin";
362765c9429SGerd Hoffmann     k->exit      = bochs_display_exit;
363765c9429SGerd Hoffmann     dc->vmsd     = &vmstate_bochs_display;
364765c9429SGerd Hoffmann     dc->props    = bochs_display_properties;
365765c9429SGerd Hoffmann     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
366765c9429SGerd Hoffmann }
367765c9429SGerd Hoffmann 
368765c9429SGerd Hoffmann static const TypeInfo bochs_display_type_info = {
369765c9429SGerd Hoffmann     .name           = TYPE_BOCHS_DISPLAY,
370765c9429SGerd Hoffmann     .parent         = TYPE_PCI_DEVICE,
371765c9429SGerd Hoffmann     .instance_size  = sizeof(BochsDisplayState),
372765c9429SGerd Hoffmann     .instance_init  = bochs_display_init,
373765c9429SGerd Hoffmann     .class_init     = bochs_display_class_init,
374765c9429SGerd Hoffmann     .interfaces     = (InterfaceInfo[]) {
375f2581064SGerd Hoffmann         { INTERFACE_PCIE_DEVICE },
376765c9429SGerd Hoffmann         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
377765c9429SGerd Hoffmann         { },
378765c9429SGerd Hoffmann     },
379765c9429SGerd Hoffmann };
380765c9429SGerd Hoffmann 
381765c9429SGerd Hoffmann static void bochs_display_register_types(void)
382765c9429SGerd Hoffmann {
383765c9429SGerd Hoffmann     type_register_static(&bochs_display_type_info);
384765c9429SGerd Hoffmann }
385765c9429SGerd Hoffmann 
386765c9429SGerd Hoffmann type_init(bochs_display_register_types)
387