hw: usb: hcd-ohci: check for processed TD before retire
[qemu/ar7.git] / hw / display / bochs-display.c
blob41587388c42dc156c30cc170e21795956a9110cd
1 /*
2 * QEMU PCI bochs display adapter.
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
8 #include "qemu/osdep.h"
9 #include "qemu/module.h"
10 #include "qemu/units.h"
11 #include "hw/pci/pci.h"
12 #include "hw/qdev-properties.h"
13 #include "migration/vmstate.h"
14 #include "hw/display/bochs-vbe.h"
15 #include "hw/display/edid.h"
17 #include "qapi/error.h"
19 #include "ui/console.h"
20 #include "ui/qemu-pixman.h"
21 #include "qom/object.h"
23 typedef struct BochsDisplayMode {
24 pixman_format_code_t format;
25 uint32_t bytepp;
26 uint32_t width;
27 uint32_t height;
28 uint32_t stride;
29 uint64_t offset;
30 uint64_t size;
31 } BochsDisplayMode;
33 struct BochsDisplayState {
34 /* parent */
35 PCIDevice pci;
37 /* device elements */
38 QemuConsole *con;
39 MemoryRegion vram;
40 MemoryRegion mmio;
41 MemoryRegion vbe;
42 MemoryRegion qext;
43 MemoryRegion edid;
45 /* device config */
46 uint64_t vgamem;
47 bool enable_edid;
48 qemu_edid_info edid_info;
49 uint8_t edid_blob[256];
51 /* device registers */
52 uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
53 bool big_endian_fb;
55 /* device state */
56 BochsDisplayMode mode;
58 typedef struct BochsDisplayState BochsDisplayState;
60 #define TYPE_BOCHS_DISPLAY "bochs-display"
61 DECLARE_INSTANCE_CHECKER(BochsDisplayState, BOCHS_DISPLAY,
62 TYPE_BOCHS_DISPLAY)
64 static const VMStateDescription vmstate_bochs_display = {
65 .name = "bochs-display",
66 .fields = (VMStateField[]) {
67 VMSTATE_PCI_DEVICE(pci, BochsDisplayState),
68 VMSTATE_UINT16_ARRAY(vbe_regs, BochsDisplayState, VBE_DISPI_INDEX_NB),
69 VMSTATE_BOOL(big_endian_fb, BochsDisplayState),
70 VMSTATE_END_OF_LIST()
74 static uint64_t bochs_display_vbe_read(void *ptr, hwaddr addr,
75 unsigned size)
77 BochsDisplayState *s = ptr;
78 unsigned int index = addr >> 1;
80 switch (index) {
81 case VBE_DISPI_INDEX_ID:
82 return VBE_DISPI_ID5;
83 case VBE_DISPI_INDEX_VIDEO_MEMORY_64K:
84 return s->vgamem / (64 * KiB);
87 if (index >= ARRAY_SIZE(s->vbe_regs)) {
88 return -1;
90 return s->vbe_regs[index];
93 static void bochs_display_vbe_write(void *ptr, hwaddr addr,
94 uint64_t val, unsigned size)
96 BochsDisplayState *s = ptr;
97 unsigned int index = addr >> 1;
99 if (index >= ARRAY_SIZE(s->vbe_regs)) {
100 return;
102 s->vbe_regs[index] = val;
105 static const MemoryRegionOps bochs_display_vbe_ops = {
106 .read = bochs_display_vbe_read,
107 .write = bochs_display_vbe_write,
108 .valid.min_access_size = 1,
109 .valid.max_access_size = 4,
110 .impl.min_access_size = 2,
111 .impl.max_access_size = 2,
112 .endianness = DEVICE_LITTLE_ENDIAN,
115 static uint64_t bochs_display_qext_read(void *ptr, hwaddr addr,
116 unsigned size)
118 BochsDisplayState *s = ptr;
120 switch (addr) {
121 case PCI_VGA_QEXT_REG_SIZE:
122 return PCI_VGA_QEXT_SIZE;
123 case PCI_VGA_QEXT_REG_BYTEORDER:
124 return s->big_endian_fb ?
125 PCI_VGA_QEXT_BIG_ENDIAN : PCI_VGA_QEXT_LITTLE_ENDIAN;
126 default:
127 return 0;
131 static void bochs_display_qext_write(void *ptr, hwaddr addr,
132 uint64_t val, unsigned size)
134 BochsDisplayState *s = ptr;
136 switch (addr) {
137 case PCI_VGA_QEXT_REG_BYTEORDER:
138 if (val == PCI_VGA_QEXT_BIG_ENDIAN) {
139 s->big_endian_fb = true;
141 if (val == PCI_VGA_QEXT_LITTLE_ENDIAN) {
142 s->big_endian_fb = false;
144 break;
148 static const MemoryRegionOps bochs_display_qext_ops = {
149 .read = bochs_display_qext_read,
150 .write = bochs_display_qext_write,
151 .valid.min_access_size = 4,
152 .valid.max_access_size = 4,
153 .endianness = DEVICE_LITTLE_ENDIAN,
156 static int bochs_display_get_mode(BochsDisplayState *s,
157 BochsDisplayMode *mode)
159 uint16_t *vbe = s->vbe_regs;
160 uint32_t virt_width;
162 if (!(vbe[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
163 return -1;
166 memset(mode, 0, sizeof(*mode));
167 switch (vbe[VBE_DISPI_INDEX_BPP]) {
168 case 16:
169 /* best effort: support native endianess only */
170 mode->format = PIXMAN_r5g6b5;
171 mode->bytepp = 2;
172 break;
173 case 32:
174 mode->format = s->big_endian_fb
175 ? PIXMAN_BE_x8r8g8b8
176 : PIXMAN_LE_x8r8g8b8;
177 mode->bytepp = 4;
178 break;
179 default:
180 return -1;
183 mode->width = vbe[VBE_DISPI_INDEX_XRES];
184 mode->height = vbe[VBE_DISPI_INDEX_YRES];
185 virt_width = vbe[VBE_DISPI_INDEX_VIRT_WIDTH];
186 if (virt_width < mode->width) {
187 virt_width = mode->width;
189 mode->stride = virt_width * mode->bytepp;
190 mode->size = (uint64_t)mode->stride * mode->height;
191 mode->offset = ((uint64_t)vbe[VBE_DISPI_INDEX_X_OFFSET] * mode->bytepp +
192 (uint64_t)vbe[VBE_DISPI_INDEX_Y_OFFSET] * mode->stride);
194 if (mode->width < 64 || mode->height < 64) {
195 return -1;
197 if (mode->offset + mode->size > s->vgamem) {
198 return -1;
200 return 0;
203 static void bochs_display_update(void *opaque)
205 BochsDisplayState *s = opaque;
206 DirtyBitmapSnapshot *snap = NULL;
207 bool full_update = false;
208 BochsDisplayMode mode;
209 DisplaySurface *ds;
210 uint8_t *ptr;
211 bool dirty;
212 int y, ys, ret;
214 ret = bochs_display_get_mode(s, &mode);
215 if (ret < 0) {
216 /* no (valid) video mode */
217 return;
220 if (memcmp(&s->mode, &mode, sizeof(mode)) != 0) {
221 /* video mode switch */
222 s->mode = mode;
223 ptr = memory_region_get_ram_ptr(&s->vram);
224 ds = qemu_create_displaysurface_from(mode.width,
225 mode.height,
226 mode.format,
227 mode.stride,
228 ptr + mode.offset);
229 dpy_gfx_replace_surface(s->con, ds);
230 full_update = true;
233 if (full_update) {
234 dpy_gfx_update_full(s->con);
235 } else {
236 snap = memory_region_snapshot_and_clear_dirty(&s->vram,
237 mode.offset, mode.size,
238 DIRTY_MEMORY_VGA);
239 ys = -1;
240 for (y = 0; y < mode.height; y++) {
241 dirty = memory_region_snapshot_get_dirty(&s->vram, snap,
242 mode.offset + mode.stride * y,
243 mode.stride);
244 if (dirty && ys < 0) {
245 ys = y;
247 if (!dirty && ys >= 0) {
248 dpy_gfx_update(s->con, 0, ys,
249 mode.width, y - ys);
250 ys = -1;
253 if (ys >= 0) {
254 dpy_gfx_update(s->con, 0, ys,
255 mode.width, y - ys);
258 g_free(snap);
262 static const GraphicHwOps bochs_display_gfx_ops = {
263 .gfx_update = bochs_display_update,
266 static void bochs_display_realize(PCIDevice *dev, Error **errp)
268 BochsDisplayState *s = BOCHS_DISPLAY(dev);
269 Object *obj = OBJECT(dev);
270 int ret;
272 if (s->vgamem < 4 * MiB) {
273 error_setg(errp, "bochs-display: video memory too small");
274 return;
276 if (s->vgamem > 256 * MiB) {
277 error_setg(errp, "bochs-display: video memory too big");
278 return;
280 s->vgamem = pow2ceil(s->vgamem);
282 s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s);
284 memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem,
285 &error_fatal);
286 memory_region_init_io(&s->vbe, obj, &bochs_display_vbe_ops, s,
287 "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
288 memory_region_init_io(&s->qext, obj, &bochs_display_qext_ops, s,
289 "qemu extended regs", PCI_VGA_QEXT_SIZE);
291 memory_region_init_io(&s->mmio, obj, &unassigned_io_ops, NULL,
292 "bochs-display-mmio", PCI_VGA_MMIO_SIZE);
293 memory_region_add_subregion(&s->mmio, PCI_VGA_BOCHS_OFFSET, &s->vbe);
294 memory_region_add_subregion(&s->mmio, PCI_VGA_QEXT_OFFSET, &s->qext);
296 pci_set_byte(&s->pci.config[PCI_REVISION_ID], 2);
297 pci_register_bar(&s->pci, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
298 pci_register_bar(&s->pci, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
300 if (s->enable_edid) {
301 qemu_edid_generate(s->edid_blob, sizeof(s->edid_blob), &s->edid_info);
302 qemu_edid_region_io(&s->edid, obj, s->edid_blob, sizeof(s->edid_blob));
303 memory_region_add_subregion(&s->mmio, 0, &s->edid);
306 if (pci_bus_is_express(pci_get_bus(dev))) {
307 ret = pcie_endpoint_cap_init(dev, 0x80);
308 assert(ret > 0);
309 } else {
310 dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS;
313 memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
316 static bool bochs_display_get_big_endian_fb(Object *obj, Error **errp)
318 BochsDisplayState *s = BOCHS_DISPLAY(obj);
320 return s->big_endian_fb;
323 static void bochs_display_set_big_endian_fb(Object *obj, bool value,
324 Error **errp)
326 BochsDisplayState *s = BOCHS_DISPLAY(obj);
328 s->big_endian_fb = value;
331 static void bochs_display_init(Object *obj)
333 PCIDevice *dev = PCI_DEVICE(obj);
335 /* Expose framebuffer byteorder via QOM */
336 object_property_add_bool(obj, "big-endian-framebuffer",
337 bochs_display_get_big_endian_fb,
338 bochs_display_set_big_endian_fb);
340 dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
343 static void bochs_display_exit(PCIDevice *dev)
345 BochsDisplayState *s = BOCHS_DISPLAY(dev);
347 graphic_console_close(s->con);
350 static Property bochs_display_properties[] = {
351 DEFINE_PROP_SIZE("vgamem", BochsDisplayState, vgamem, 16 * MiB),
352 DEFINE_PROP_BOOL("edid", BochsDisplayState, enable_edid, true),
353 DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info),
354 DEFINE_PROP_END_OF_LIST(),
357 static void bochs_display_class_init(ObjectClass *klass, void *data)
359 DeviceClass *dc = DEVICE_CLASS(klass);
360 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
362 k->class_id = PCI_CLASS_DISPLAY_OTHER;
363 k->vendor_id = PCI_VENDOR_ID_QEMU;
364 k->device_id = PCI_DEVICE_ID_QEMU_VGA;
366 k->realize = bochs_display_realize;
367 k->romfile = "vgabios-bochs-display.bin";
368 k->exit = bochs_display_exit;
369 dc->vmsd = &vmstate_bochs_display;
370 device_class_set_props(dc, bochs_display_properties);
371 set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
374 static const TypeInfo bochs_display_type_info = {
375 .name = TYPE_BOCHS_DISPLAY,
376 .parent = TYPE_PCI_DEVICE,
377 .instance_size = sizeof(BochsDisplayState),
378 .instance_init = bochs_display_init,
379 .class_init = bochs_display_class_init,
380 .interfaces = (InterfaceInfo[]) {
381 { INTERFACE_PCIE_DEVICE },
382 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
383 { },
387 static void bochs_display_register_types(void)
389 type_register_static(&bochs_display_type_info);
392 type_init(bochs_display_register_types)