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