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