spiceqxl_io_port.c revision d514b0f3
1/* 2 * Copyright 2011 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * on the rights to use, copy, modify, merge, publish, distribute, sub 8 * license, and/or sell copies of the Software, and to permit persons to whom 9 * the Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22#ifdef HAVE_CONFIG_H 23#include "config.h" 24#endif 25 26#include <pthread.h> 27#include <sched.h> 28 29#include <spice.h> 30 31#include "qxl.h" 32#include "spiceqxl_io_port.h" 33 34/* TODO: taken from qemu qxl.c, try to remove duplication */ 35#undef SPICE_RING_PROD_ITEM 36#define SPICE_RING_PROD_ITEM(r, ret) { \ 37 typeof(r) start = r; \ 38 typeof(r) end = r + 1; \ 39 uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \ 40 typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ 41 if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ 42 abort(); \ 43 } \ 44 ret = &m_item->el; \ 45 } 46 47 48static int spiceqxl_io_port_debug_level = -1; 49 50static void __attribute__ ((format (printf, 2, 3))) dprint(int _level, const char *_fmt, ...) 51{ 52 if (spiceqxl_io_port_debug_level == -1) { 53 if (getenv("XSPICE_IO_PORT_DEBUG_LEVEL")) { 54 spiceqxl_io_port_debug_level = atoi( 55 getenv("XSPICE_IO_PORT_DEBUG_LEVEL")); 56 } else { 57 spiceqxl_io_port_debug_level = 0; 58 } 59 } 60 if (spiceqxl_io_port_debug_level >= _level) { 61 va_list ap; 62 va_start(ap, _fmt); 63 vfprintf(stderr, _fmt, ap); 64 va_end(ap); 65 } 66} 67 68void xspice_init_qxl_ram(qxl_screen_t *qxl) 69{ 70 QXLRam *ram = get_ram_header(qxl); 71 uint64_t *item; 72 73 ram->magic = QXL_RAM_MAGIC; 74 ram->int_pending = 0; 75 ram->int_mask = 0; 76 SPICE_RING_INIT(&ram->cmd_ring); 77 SPICE_RING_INIT(&ram->cursor_ring); 78 SPICE_RING_INIT(&ram->release_ring); 79 SPICE_RING_PROD_ITEM(&ram->release_ring, item); 80 *item = 0; 81} 82 83static void qxl_reset_state(qxl_screen_t *qxl) 84{ 85 QXLRam *ram = get_ram_header(qxl); 86 87 assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); 88 assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); 89 qxl->shadow_rom.update_id = 0; 90 *qxl->rom = qxl->shadow_rom; 91 xspice_init_qxl_ram(qxl); 92 qxl->num_free_res = 0; 93 qxl->last_release = NULL; 94 // TODO - dirty ? 95 //memset(&qxl->ssd.dirty, 0, sizeof(qxl->ssd.dirty)); 96} 97 98static void qxl_check_state(qxl_screen_t *qxl) 99{ 100 QXLRam *ram = get_ram_header(qxl); 101 102 assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); 103 assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); 104} 105 106static void qxl_soft_reset(qxl_screen_t *qxl) 107{ 108 dprint(1, "%s:\n", __FUNCTION__); 109 qxl_check_state(qxl); 110} 111 112static void qxl_reset_surfaces(qxl_screen_t *qxl) 113{ 114 dprint(1, "%s:\n", __FUNCTION__); 115 spice_qxl_destroy_surfaces(&qxl->display_sin); 116 // TODO - do we have guest_surfaces? 117 //memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); 118} 119 120static void qxl_hard_reset(qxl_screen_t *qxl) 121{ 122 dprint(1, "%s: start\n", __FUNCTION__); 123 124 spice_qxl_reset_cursor(&qxl->display_sin); 125 spice_qxl_reset_image_cache(&qxl->display_sin); 126 qxl_reset_surfaces(qxl); 127 128 qxl_reset_state(qxl); 129 qxl_soft_reset(qxl); 130 131 dprint(1, "%s: done\n", __FUNCTION__); 132} 133 134static void qxl_create_guest_primary(qxl_screen_t *qxl) 135{ 136 QXLDevSurfaceCreate surface; 137 QXLSurfaceCreate *sc = &qxl->guest_primary.surface; 138 139 dprint(1, "%s: %dx%d\n", __FUNCTION__, sc->width, sc->height); 140 141 surface.format = sc->format; 142 surface.height = sc->height; 143 surface.mem = sc->mem; 144 surface.position = sc->position; 145 surface.stride = sc->stride; 146 surface.width = sc->width; 147 surface.type = sc->type; 148 surface.flags = sc->flags; 149 150 surface.mouse_mode = TRUE; 151 surface.group_id = 0; 152 qxl->cmdflags = 0; 153 spice_qxl_create_primary_surface(&qxl->display_sin, 0, &surface); 154} 155 156static void qxl_destroy_primary(qxl_screen_t *qxl) 157{ 158 dprint(1, "%s\n", __FUNCTION__); 159 160 spice_qxl_destroy_primary_surface(&qxl->display_sin, 0); 161} 162 163 164static void qxl_set_mode(qxl_screen_t *qxl, int modenr) 165{ 166 struct QXLMode *mode = qxl->modes + modenr; 167 uint64_t devmem = pointer_to_u64(qxl->ram); 168 QXLSurfaceCreate surface = { 169 .width = mode->x_res, 170 .height = mode->y_res, 171 .stride = -mode->x_res * 4, 172 .format = SPICE_SURFACE_FMT_32_xRGB, 173 .flags = 0, 174 .mouse_mode = TRUE, 175 .mem = devmem + qxl->shadow_rom.draw_area_offset, 176 }; 177 178 dprint(1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%llx ]\n", __FUNCTION__, 179 modenr, mode->x_res, mode->y_res, mode->bits, (unsigned long long) devmem); 180 qxl_hard_reset(qxl); 181 182 qxl->guest_primary.surface = surface; 183 qxl_create_guest_primary(qxl); 184 185 qxl->cmdflags = QXL_COMMAND_FLAG_COMPAT; 186#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */ 187 if (mode->bits == 16) { 188 qxl->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP; 189 } 190#endif 191 qxl->shadow_rom.mode = modenr; 192 qxl->rom->mode = modenr; 193} 194 195/* called from Xorg thread - not worker thread! */ 196void ioport_write(qxl_screen_t *qxl, uint32_t io_port, uint32_t val) 197{ 198 QXLRam *header = get_ram_header(qxl); 199 200 if (!qxl->worker_running) { 201 return; 202 } 203 204 switch (io_port) { 205 case QXL_IO_UPDATE_AREA: 206 { 207 QXLRect update = *(QXLRect*)&header->update_area; 208 spice_qxl_update_area(&qxl->display_sin, header->update_surface, 209 &update, NULL, 0, 0); 210 break; 211 } 212 case QXL_IO_NOTIFY_CMD: 213 spice_qxl_wakeup(&qxl->display_sin); 214 break; 215 case QXL_IO_NOTIFY_CURSOR: 216 spice_qxl_wakeup(&qxl->display_sin); 217 break; 218 case QXL_IO_UPDATE_IRQ: 219 /* qxl_set_irq(d); */ 220 printf("QXL_IO_UPDATE_IRQ not implemented\n"); 221 break; 222 case QXL_IO_NOTIFY_OOM: 223 if (!SPICE_RING_IS_EMPTY(&header->release_ring)) { 224 break; 225 } 226 sched_yield(); 227 if (!SPICE_RING_IS_EMPTY(&header->release_ring)) { 228 break; 229 } 230 spice_qxl_oom(&qxl->display_sin); 231 break; 232 case QXL_IO_SET_MODE: 233 dprint(1, "QXL_SET_MODE %d\n", val); 234 qxl_set_mode(qxl, val); 235 break; 236 case QXL_IO_LOG: 237 fprintf(stderr, "qxl/guest: %s", header->log_buf); 238 break; 239 case QXL_IO_RESET: 240 dprint(1, "QXL_IO_RESET\n"); 241 qxl_hard_reset(qxl); 242 break; 243 case QXL_IO_MEMSLOT_ADD: 244 dprint(1, "QXL_IO_MEMSLOT_ADD - should not be called (this is Xspice)\n"); 245 break; 246 case QXL_IO_MEMSLOT_DEL: 247 dprint(1, "QXL_IO_MEMSLOT_DEL - should not be called (this is Xspice)\n"); 248 break; 249 case QXL_IO_CREATE_PRIMARY: 250 assert(val == 0); 251 dprint(1, "QXL_IO_CREATE_PRIMARY\n"); 252 qxl->guest_primary.surface = 253 *(QXLSurfaceCreate*)&header->create_surface; 254 qxl_create_guest_primary(qxl); 255 break; 256 case QXL_IO_DESTROY_PRIMARY: 257 assert(val == 0); 258 dprint(1, "QXL_IO_DESTROY_PRIMARY\n"); 259 qxl_destroy_primary(qxl); 260 break; 261 case QXL_IO_DESTROY_SURFACE_WAIT: 262 spice_qxl_destroy_surface_wait(&qxl->display_sin, val); 263 break; 264 case QXL_IO_DESTROY_ALL_SURFACES: 265 spice_qxl_destroy_surfaces(&qxl->display_sin); 266 break; 267 case QXL_IO_FLUSH_SURFACES_ASYNC: 268 fprintf(stderr, "ERROR: async callback Unimplemented\n"); 269 spice_qxl_flush_surfaces_async(&qxl->display_sin, 0); 270 break; 271 default: 272 fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); 273 abort(); 274 } 275} 276 277