Home | History | Annotate | Line # | Download | only in src
      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 
     48 static int spiceqxl_io_port_debug_level = -1;
     49 
     50 static 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 
     68 void 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 
     83 static 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 
     98 static 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 
    106 static void qxl_soft_reset(qxl_screen_t *qxl)
    107 {
    108     dprint(1, "%s:\n", __FUNCTION__);
    109     qxl_check_state(qxl);
    110 }
    111 
    112 static 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 
    120 static 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 
    134 static 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 
    156 static 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 
    164 static 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! */
    196 void 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