Statistics
| Branch: | Revision:

root / hw / xenfb.c @ c9159fe9

History | View | Annotate | Download (30.4 kB)

1
/*
2
 *  xen paravirt framebuffer backend
3
 *
4
 *  Copyright IBM, Corp. 2005-2006
5
 *  Copyright Red Hat, Inc. 2006-2008
6
 *
7
 *  Authors:
8
 *       Anthony Liguori <aliguori@us.ibm.com>,
9
 *       Markus Armbruster <armbru@redhat.com>,
10
 *       Daniel P. Berrange <berrange@redhat.com>,
11
 *       Pat Campbell <plc@novell.com>,
12
 *       Gerd Hoffmann <kraxel@redhat.com>
13
 *
14
 *  This program is free software; you can redistribute it and/or modify
15
 *  it under the terms of the GNU General Public License as published by
16
 *  the Free Software Foundation; under version 2 of the License.
17
 *
18
 *  This program is distributed in the hope that it will be useful,
19
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 *  GNU General Public License for more details.
22
 *
23
 *  You should have received a copy of the GNU General Public License along
24
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
25
 */
26

    
27
#include <stdarg.h>
28
#include <stdlib.h>
29
#include <sys/types.h>
30
#include <fcntl.h>
31
#include <unistd.h>
32
#include <sys/mman.h>
33
#include <errno.h>
34
#include <stdio.h>
35
#include <string.h>
36
#include <time.h>
37

    
38
#include "hw.h"
39
#include "console.h"
40
#include "qemu-char.h"
41
#include "xen_backend.h"
42

    
43
#include <xen/event_channel.h>
44
#include <xen/io/fbif.h>
45
#include <xen/io/kbdif.h>
46
#include <xen/io/protocols.h>
47

    
48
#ifndef BTN_LEFT
49
#define BTN_LEFT 0x110 /* from <linux/input.h> */
50
#endif
51

    
52
/* -------------------------------------------------------------------- */
53

    
54
struct common {
55
    struct XenDevice  xendev;  /* must be first */
56
    void              *page;
57
    DisplayState      *ds;
58
};
59

    
60
struct XenInput {
61
    struct common c;
62
    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
63
    int button_state;       /* Last seen pointer button state */
64
    int extended;
65
    QEMUPutMouseEntry *qmouse;
66
};
67

    
68
#define UP_QUEUE 8
69

    
70
struct XenFB {
71
    struct common     c;
72
    size_t            fb_len;
73
    int               row_stride;
74
    int               depth;
75
    int               width;
76
    int               height;
77
    int               offset;
78
    void              *pixels;
79
    int               fbpages;
80
    int               feature_update;
81
    int               refresh_period;
82
    int               bug_trigger;
83
    int               have_console;
84
    int               do_resize;
85

    
86
    struct {
87
        int x,y,w,h;
88
    } up_rects[UP_QUEUE];
89
    int               up_count;
90
    int               up_fullscreen;
91
};
92

    
93
/* -------------------------------------------------------------------- */
94

    
95
static int common_bind(struct common *c)
96
{
97
    int mfn;
98

    
99
    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
100
        return -1;
101
    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
102
        return -1;
103

    
104
    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
105
                                   XC_PAGE_SIZE,
106
                                   PROT_READ | PROT_WRITE, mfn);
107
    if (c->page == NULL)
108
        return -1;
109

    
110
    xen_be_bind_evtchn(&c->xendev);
111
    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
112
                  mfn, c->xendev.remote_port, c->xendev.local_port);
113

    
114
    return 0;
115
}
116

    
117
static void common_unbind(struct common *c)
118
{
119
    xen_be_unbind_evtchn(&c->xendev);
120
    if (c->page) {
121
        munmap(c->page, XC_PAGE_SIZE);
122
        c->page = NULL;
123
    }
124
}
125

    
126
/* -------------------------------------------------------------------- */
127

    
128
#if 0
129
/*
130
 * These two tables are not needed any more, but left in here
131
 * intentionally as documentation, to show how scancode2linux[]
132
 * was generated.
133
 *
134
 * Tables to map from scancode to Linux input layer keycode.
135
 * Scancodes are hardware-specific.  These maps assumes a
136
 * standard AT or PS/2 keyboard which is what QEMU feeds us.
137
 */
138
const unsigned char atkbd_set2_keycode[512] = {
139

140
     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
141
     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
142
     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
143
     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
144
     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
145
     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
146
     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
147
    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
148

149
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
150
    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
151
    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
152
    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
153
    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
154
    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
155
      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
156
    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
157

158
};
159

160
const unsigned char atkbd_unxlate_table[128] = {
161

162
      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
163
     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
164
     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
165
     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
166
     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
167
    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
168
     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
169
     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
170

171
};
172
#endif
173

    
174
/*
175
 * for (i = 0; i < 128; i++) {
176
 *     scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
177
 *     scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
178
 * }
179
 */
180
static const unsigned char scancode2linux[512] = {
181
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
182
     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
183
     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
184
     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
185
     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
186
     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
187
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
188
     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
189

    
190
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
191
    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
192
    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
193
    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
194
      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
195
    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
196
      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
197
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
198
};
199

    
200
/* Send an event to the keyboard frontend driver */
201
static int xenfb_kbd_event(struct XenInput *xenfb,
202
                           union xenkbd_in_event *event)
203
{
204
    struct xenkbd_page *page = xenfb->c.page;
205
    uint32_t prod;
206

    
207
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
208
        return 0;
209
    if (!page)
210
        return 0;
211

    
212
    prod = page->in_prod;
213
    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
214
        errno = EAGAIN;
215
        return -1;
216
    }
217

    
218
    xen_mb();                /* ensure ring space available */
219
    XENKBD_IN_RING_REF(page, prod) = *event;
220
    xen_wmb();                /* ensure ring contents visible */
221
    page->in_prod = prod + 1;
222
    return xen_be_send_notify(&xenfb->c.xendev);
223
}
224

    
225
/* Send a keyboard (or mouse button) event */
226
static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
227
{
228
    union xenkbd_in_event event;
229

    
230
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
231
    event.type = XENKBD_TYPE_KEY;
232
    event.key.pressed = down ? 1 : 0;
233
    event.key.keycode = keycode;
234

    
235
    return xenfb_kbd_event(xenfb, &event);
236
}
237

    
238
/* Send a relative mouse movement event */
239
static int xenfb_send_motion(struct XenInput *xenfb,
240
                             int rel_x, int rel_y, int rel_z)
241
{
242
    union xenkbd_in_event event;
243

    
244
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
245
    event.type = XENKBD_TYPE_MOTION;
246
    event.motion.rel_x = rel_x;
247
    event.motion.rel_y = rel_y;
248
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
249
    event.motion.rel_z = rel_z;
250
#endif
251

    
252
    return xenfb_kbd_event(xenfb, &event);
253
}
254

    
255
/* Send an absolute mouse movement event */
256
static int xenfb_send_position(struct XenInput *xenfb,
257
                               int abs_x, int abs_y, int z)
258
{
259
    union xenkbd_in_event event;
260

    
261
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
262
    event.type = XENKBD_TYPE_POS;
263
    event.pos.abs_x = abs_x;
264
    event.pos.abs_y = abs_y;
265
#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
266
    event.pos.abs_z = z;
267
#endif
268
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
269
    event.pos.rel_z = z;
270
#endif
271

    
272
    return xenfb_kbd_event(xenfb, &event);
273
}
274

    
275
/*
276
 * Send a key event from the client to the guest OS
277
 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
278
 * We have to turn this into a Linux Input layer keycode.
279
 *
280
 * Extra complexity from the fact that with extended scancodes
281
 * (like those produced by arrow keys) this method gets called
282
 * twice, but we only want to send a single event. So we have to
283
 * track the '0xe0' scancode state & collapse the extended keys
284
 * as needed.
285
 *
286
 * Wish we could just send scancodes straight to the guest which
287
 * already has code for dealing with this...
288
 */
289
static void xenfb_key_event(void *opaque, int scancode)
290
{
291
    struct XenInput *xenfb = opaque;
292
    int down = 1;
293

    
294
    if (scancode == 0xe0) {
295
        xenfb->extended = 1;
296
        return;
297
    } else if (scancode & 0x80) {
298
        scancode &= 0x7f;
299
        down = 0;
300
    }
301
    if (xenfb->extended) {
302
        scancode |= 0x80;
303
        xenfb->extended = 0;
304
    }
305
    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
306
}
307

    
308
/*
309
 * Send a mouse event from the client to the guest OS
310
 *
311
 * The QEMU mouse can be in either relative, or absolute mode.
312
 * Movement is sent separately from button state, which has to
313
 * be encoded as virtual key events. We also don't actually get
314
 * given any button up/down events, so have to track changes in
315
 * the button state.
316
 */
317
static void xenfb_mouse_event(void *opaque,
318
                              int dx, int dy, int dz, int button_state)
319
{
320
    struct XenInput *xenfb = opaque;
321
    int dw = ds_get_width(xenfb->c.ds);
322
    int dh = ds_get_height(xenfb->c.ds);
323
    int i;
324

    
325
    if (xenfb->abs_pointer_wanted)
326
        xenfb_send_position(xenfb,
327
                            dx * (dw - 1) / 0x7fff,
328
                            dy * (dh - 1) / 0x7fff,
329
                            dz);
330
    else
331
        xenfb_send_motion(xenfb, dx, dy, dz);
332

    
333
    for (i = 0 ; i < 8 ; i++) {
334
        int lastDown = xenfb->button_state & (1 << i);
335
        int down = button_state & (1 << i);
336
        if (down == lastDown)
337
            continue;
338

    
339
        if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
340
            return;
341
    }
342
    xenfb->button_state = button_state;
343
}
344

    
345
static int input_init(struct XenDevice *xendev)
346
{
347
    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
348
    return 0;
349
}
350

    
351
static int input_initialise(struct XenDevice *xendev)
352
{
353
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
354
    int rc;
355

    
356
    if (!in->c.ds) {
357
        char *vfb = xenstore_read_str(NULL, "device/vfb");
358
        if (vfb == NULL) {
359
            /* there is no vfb, run vkbd on its own */
360
            in->c.ds = get_displaystate();
361
        } else {
362
            g_free(vfb);
363
            xen_be_printf(xendev, 1, "ds not set (yet)\n");
364
            return -1;
365
        }
366
    }
367

    
368
    rc = common_bind(&in->c);
369
    if (rc != 0)
370
        return rc;
371

    
372
    qemu_add_kbd_event_handler(xenfb_key_event, in);
373
    return 0;
374
}
375

    
376
static void input_connected(struct XenDevice *xendev)
377
{
378
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
379

    
380
    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
381
                             &in->abs_pointer_wanted) == -1) {
382
        in->abs_pointer_wanted = 0;
383
    }
384

    
385
    if (in->qmouse) {
386
        qemu_remove_mouse_event_handler(in->qmouse);
387
    }
388
    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
389
                                              in->abs_pointer_wanted,
390
                                              "Xen PVFB Mouse");
391
}
392

    
393
static void input_disconnect(struct XenDevice *xendev)
394
{
395
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
396

    
397
    if (in->qmouse) {
398
        qemu_remove_mouse_event_handler(in->qmouse);
399
        in->qmouse = NULL;
400
    }
401
    qemu_add_kbd_event_handler(NULL, NULL);
402
    common_unbind(&in->c);
403
}
404

    
405
static void input_event(struct XenDevice *xendev)
406
{
407
    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
408
    struct xenkbd_page *page = xenfb->c.page;
409

    
410
    /* We don't understand any keyboard events, so just ignore them. */
411
    if (page->out_prod == page->out_cons)
412
        return;
413
    page->out_cons = page->out_prod;
414
    xen_be_send_notify(&xenfb->c.xendev);
415
}
416

    
417
/* -------------------------------------------------------------------- */
418

    
419
static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
420
{
421
    uint32_t *src32 = src;
422
    uint64_t *src64 = src;
423
    int i;
424

    
425
    for (i = 0; i < count; i++)
426
        dst[i] = (mode == 32) ? src32[i] : src64[i];
427
}
428

    
429
static int xenfb_map_fb(struct XenFB *xenfb)
430
{
431
    struct xenfb_page *page = xenfb->c.page;
432
    char *protocol = xenfb->c.xendev.protocol;
433
    int n_fbdirs;
434
    unsigned long *pgmfns = NULL;
435
    unsigned long *fbmfns = NULL;
436
    void *map, *pd;
437
    int mode, ret = -1;
438

    
439
    /* default to native */
440
    pd = page->pd;
441
    mode = sizeof(unsigned long) * 8;
442

    
443
    if (!protocol) {
444
        /*
445
         * Undefined protocol, some guesswork needed.
446
         *
447
         * Old frontends which don't set the protocol use
448
         * one page directory only, thus pd[1] must be zero.
449
         * pd[1] of the 32bit struct layout and the lower
450
         * 32 bits of pd[0] of the 64bit struct layout have
451
         * the same location, so we can check that ...
452
         */
453
        uint32_t *ptr32 = NULL;
454
        uint32_t *ptr64 = NULL;
455
#if defined(__i386__)
456
        ptr32 = (void*)page->pd;
457
        ptr64 = ((void*)page->pd) + 4;
458
#elif defined(__x86_64__)
459
        ptr32 = ((void*)page->pd) - 4;
460
        ptr64 = (void*)page->pd;
461
#endif
462
        if (ptr32) {
463
            if (ptr32[1] == 0) {
464
                mode = 32;
465
                pd   = ptr32;
466
            } else {
467
                mode = 64;
468
                pd   = ptr64;
469
            }
470
        }
471
#if defined(__x86_64__)
472
    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
473
        /* 64bit dom0, 32bit domU */
474
        mode = 32;
475
        pd   = ((void*)page->pd) - 4;
476
#elif defined(__i386__)
477
    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
478
        /* 32bit dom0, 64bit domU */
479
        mode = 64;
480
        pd   = ((void*)page->pd) + 4;
481
#endif
482
    }
483

    
484
    if (xenfb->pixels) {
485
        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
486
        xenfb->pixels = NULL;
487
    }
488

    
489
    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
490
    n_fbdirs = xenfb->fbpages * mode / 8;
491
    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
492

    
493
    pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
494
    fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
495

    
496
    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
497
    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
498
                               PROT_READ, pgmfns, n_fbdirs);
499
    if (map == NULL)
500
        goto out;
501
    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
502
    munmap(map, n_fbdirs * XC_PAGE_SIZE);
503

    
504
    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
505
                                         PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
506
    if (xenfb->pixels == NULL)
507
        goto out;
508

    
509
    ret = 0; /* all is fine */
510

    
511
out:
512
    g_free(pgmfns);
513
    g_free(fbmfns);
514
    return ret;
515
}
516

    
517
static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
518
                              int width, int height, int depth,
519
                              size_t fb_len, int offset, int row_stride)
520
{
521
    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
522
    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
523
    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
524
    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
525
    int max_width, max_height;
526

    
527
    if (fb_len_lim > fb_len_max) {
528
        xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
529
                      fb_len_lim, fb_len_max);
530
        fb_len_lim = fb_len_max;
531
    }
532
    if (fb_len_lim && fb_len > fb_len_lim) {
533
        xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
534
                      fb_len, fb_len_lim);
535
        fb_len = fb_len_lim;
536
    }
537
    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
538
        xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
539
                      depth);
540
        return -1;
541
    }
542
    if (row_stride <= 0 || row_stride > fb_len) {
543
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
544
        return -1;
545
    }
546
    max_width = row_stride / (depth / 8);
547
    if (width < 0 || width > max_width) {
548
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
549
                      width, max_width);
550
        width = max_width;
551
    }
552
    if (offset < 0 || offset >= fb_len) {
553
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
554
                      offset, fb_len - 1);
555
        return -1;
556
    }
557
    max_height = (fb_len - offset) / row_stride;
558
    if (height < 0 || height > max_height) {
559
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
560
                      height, max_height);
561
        height = max_height;
562
    }
563
    xenfb->fb_len = fb_len;
564
    xenfb->row_stride = row_stride;
565
    xenfb->depth = depth;
566
    xenfb->width = width;
567
    xenfb->height = height;
568
    xenfb->offset = offset;
569
    xenfb->up_fullscreen = 1;
570
    xenfb->do_resize = 1;
571
    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
572
                  width, height, depth, offset, row_stride);
573
    return 0;
574
}
575

    
576
/* A convenient function for munging pixels between different depths */
577
#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
578
    for (line = y ; line < (y+h) ; line++) {                                \
579
        SRC_T *src = (SRC_T *)(xenfb->pixels                                \
580
                               + xenfb->offset                                \
581
                               + (line * xenfb->row_stride)                \
582
                               + (x * xenfb->depth / 8));                \
583
        DST_T *dst = (DST_T *)(data                                        \
584
                               + (line * linesize)                        \
585
                               + (x * bpp / 8));                        \
586
        int col;                                                        \
587
        const int RSS = 32 - (RSB + GSB + BSB);                                \
588
        const int GSS = 32 - (GSB + BSB);                                \
589
        const int BSS = 32 - (BSB);                                        \
590
        const uint32_t RSM = (~0U) << (32 - RSB);                        \
591
        const uint32_t GSM = (~0U) << (32 - GSB);                        \
592
        const uint32_t BSM = (~0U) << (32 - BSB);                        \
593
        const int RDS = 32 - (RDB + GDB + BDB);                                \
594
        const int GDS = 32 - (GDB + BDB);                                \
595
        const int BDS = 32 - (BDB);                                        \
596
        const uint32_t RDM = (~0U) << (32 - RDB);                        \
597
        const uint32_t GDM = (~0U) << (32 - GDB);                        \
598
        const uint32_t BDM = (~0U) << (32 - BDB);                        \
599
        for (col = x ; col < (x+w) ; col++) {                                \
600
            uint32_t spix = *src;                                        \
601
            *dst = (((spix << RSS) & RSM & RDM) >> RDS) |                \
602
                (((spix << GSS) & GSM & GDM) >> GDS) |                        \
603
                (((spix << BSS) & BSM & BDM) >> BDS);                        \
604
            src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);        \
605
            dst = (DST_T *) ((unsigned long) dst + bpp / 8);                \
606
        }                                                                \
607
    }
608

    
609

    
610
/*
611
 * This copies data from the guest framebuffer region, into QEMU's
612
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
613
 * uses something else we must convert and copy, otherwise we can
614
 * supply the buffer directly and no thing here.
615
 */
616
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
617
{
618
    int line, oops = 0;
619
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
620
    int linesize = ds_get_linesize(xenfb->c.ds);
621
    uint8_t *data = ds_get_data(xenfb->c.ds);
622

    
623
    if (!is_buffer_shared(xenfb->c.ds->surface)) {
624
        switch (xenfb->depth) {
625
        case 8:
626
            if (bpp == 16) {
627
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
628
            } else if (bpp == 32) {
629
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
630
            } else {
631
                oops = 1;
632
            }
633
            break;
634
        case 24:
635
            if (bpp == 16) {
636
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
637
            } else if (bpp == 32) {
638
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
639
            } else {
640
                oops = 1;
641
            }
642
            break;
643
        default:
644
            oops = 1;
645
        }
646
    }
647
    if (oops) /* should not happen */
648
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
649
                      __FUNCTION__, xenfb->depth, bpp);
650

    
651
    dpy_update(xenfb->c.ds, x, y, w, h);
652
}
653

    
654
#ifdef XENFB_TYPE_REFRESH_PERIOD
655
static int xenfb_queue_full(struct XenFB *xenfb)
656
{
657
    struct xenfb_page *page = xenfb->c.page;
658
    uint32_t cons, prod;
659

    
660
    if (!page)
661
        return 1;
662

    
663
    prod = page->in_prod;
664
    cons = page->in_cons;
665
    return prod - cons == XENFB_IN_RING_LEN;
666
}
667

    
668
static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
669
{
670
    uint32_t prod;
671
    struct xenfb_page *page = xenfb->c.page;
672

    
673
    prod = page->in_prod;
674
    /* caller ensures !xenfb_queue_full() */
675
    xen_mb();                   /* ensure ring space available */
676
    XENFB_IN_RING_REF(page, prod) = *event;
677
    xen_wmb();                  /* ensure ring contents visible */
678
    page->in_prod = prod + 1;
679

    
680
    xen_be_send_notify(&xenfb->c.xendev);
681
}
682

    
683
static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
684
{
685
    union xenfb_in_event event;
686

    
687
    memset(&event, 0, sizeof(event));
688
    event.type = XENFB_TYPE_REFRESH_PERIOD;
689
    event.refresh_period.period = period;
690
    xenfb_send_event(xenfb, &event);
691
}
692
#endif
693

    
694
/*
695
 * Periodic update of display.
696
 * Also transmit the refresh interval to the frontend.
697
 *
698
 * Never ever do any qemu display operations
699
 * (resize, screen update) outside this function.
700
 * Our screen might be inactive.  When asked for
701
 * an update we know it is active.
702
 */
703
static void xenfb_update(void *opaque)
704
{
705
    struct XenFB *xenfb = opaque;
706
    int i;
707

    
708
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
709
        return;
710

    
711
    if (xenfb->feature_update) {
712
#ifdef XENFB_TYPE_REFRESH_PERIOD
713
        struct DisplayChangeListener *l;
714
        int period = 99999999;
715
        int idle = 1;
716

    
717
        if (xenfb_queue_full(xenfb))
718
            return;
719

    
720
        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
721
            if (l->idle)
722
                continue;
723
            idle = 0;
724
            if (!l->gui_timer_interval) {
725
                if (period > GUI_REFRESH_INTERVAL)
726
                    period = GUI_REFRESH_INTERVAL;
727
            } else {
728
                if (period > l->gui_timer_interval)
729
                    period = l->gui_timer_interval;
730
            }
731
        }
732
        if (idle)
733
            period = XENFB_NO_REFRESH;
734

    
735
        if (xenfb->refresh_period != period) {
736
            xenfb_send_refresh_period(xenfb, period);
737
            xenfb->refresh_period = period;
738
            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
739
        }
740
#else
741
        ; /* nothing */
742
#endif
743
    } else {
744
        /* we don't get update notifications, thus use the
745
         * sledge hammer approach ... */
746
        xenfb->up_fullscreen = 1;
747
    }
748

    
749
    /* resize if needed */
750
    if (xenfb->do_resize) {
751
        xenfb->do_resize = 0;
752
        switch (xenfb->depth) {
753
        case 16:
754
        case 32:
755
            /* console.c supported depth -> buffer can be used directly */
756
            qemu_free_displaysurface(xenfb->c.ds);
757
            xenfb->c.ds->surface = qemu_create_displaysurface_from
758
                (xenfb->width, xenfb->height, xenfb->depth,
759
                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
760
            break;
761
        default:
762
            /* we must convert stuff */
763
            qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
764
            break;
765
        }
766
        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
767
                      xenfb->width, xenfb->height, xenfb->depth,
768
                      is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
769
        dpy_resize(xenfb->c.ds);
770
        xenfb->up_fullscreen = 1;
771
    }
772

    
773
    /* run queued updates */
774
    if (xenfb->up_fullscreen) {
775
        xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
776
        xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
777
    } else if (xenfb->up_count) {
778
        xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
779
        for (i = 0; i < xenfb->up_count; i++)
780
            xenfb_guest_copy(xenfb,
781
                             xenfb->up_rects[i].x,
782
                             xenfb->up_rects[i].y,
783
                             xenfb->up_rects[i].w,
784
                             xenfb->up_rects[i].h);
785
    } else {
786
        xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
787
    }
788
    xenfb->up_count = 0;
789
    xenfb->up_fullscreen = 0;
790
}
791

    
792
/* QEMU display state changed, so refresh the framebuffer copy */
793
static void xenfb_invalidate(void *opaque)
794
{
795
    struct XenFB *xenfb = opaque;
796
    xenfb->up_fullscreen = 1;
797
}
798

    
799
static void xenfb_handle_events(struct XenFB *xenfb)
800
{
801
    uint32_t prod, cons;
802
    struct xenfb_page *page = xenfb->c.page;
803

    
804
    prod = page->out_prod;
805
    if (prod == page->out_cons)
806
        return;
807
    xen_rmb();                /* ensure we see ring contents up to prod */
808
    for (cons = page->out_cons; cons != prod; cons++) {
809
        union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
810
        int x, y, w, h;
811

    
812
        switch (event->type) {
813
        case XENFB_TYPE_UPDATE:
814
            if (xenfb->up_count == UP_QUEUE)
815
                xenfb->up_fullscreen = 1;
816
            if (xenfb->up_fullscreen)
817
                break;
818
            x = MAX(event->update.x, 0);
819
            y = MAX(event->update.y, 0);
820
            w = MIN(event->update.width, xenfb->width - x);
821
            h = MIN(event->update.height, xenfb->height - y);
822
            if (w < 0 || h < 0) {
823
                xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
824
                break;
825
            }
826
            if (x != event->update.x ||
827
                y != event->update.y ||
828
                w != event->update.width ||
829
                h != event->update.height) {
830
                xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
831
            }
832
            if (w == xenfb->width && h > xenfb->height / 2) {
833
                /* scroll detector: updated more than 50% of the lines,
834
                 * don't bother keeping track of the rectangles then */
835
                xenfb->up_fullscreen = 1;
836
            } else {
837
                xenfb->up_rects[xenfb->up_count].x = x;
838
                xenfb->up_rects[xenfb->up_count].y = y;
839
                xenfb->up_rects[xenfb->up_count].w = w;
840
                xenfb->up_rects[xenfb->up_count].h = h;
841
                xenfb->up_count++;
842
            }
843
            break;
844
#ifdef XENFB_TYPE_RESIZE
845
        case XENFB_TYPE_RESIZE:
846
            if (xenfb_configure_fb(xenfb, xenfb->fb_len,
847
                                   event->resize.width,
848
                                   event->resize.height,
849
                                   event->resize.depth,
850
                                   xenfb->fb_len,
851
                                   event->resize.offset,
852
                                   event->resize.stride) < 0)
853
                break;
854
            xenfb_invalidate(xenfb);
855
            break;
856
#endif
857
        }
858
    }
859
    xen_mb();                /* ensure we're done with ring contents */
860
    page->out_cons = cons;
861
}
862

    
863
static int fb_init(struct XenDevice *xendev)
864
{
865
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
866

    
867
    fb->refresh_period = -1;
868

    
869
#ifdef XENFB_TYPE_RESIZE
870
    xenstore_write_be_int(xendev, "feature-resize", 1);
871
#endif
872
    return 0;
873
}
874

    
875
static int fb_initialise(struct XenDevice *xendev)
876
{
877
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
878
    struct xenfb_page *fb_page;
879
    int videoram;
880
    int rc;
881

    
882
    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
883
        videoram = 0;
884

    
885
    rc = common_bind(&fb->c);
886
    if (rc != 0)
887
        return rc;
888

    
889
    fb_page = fb->c.page;
890
    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
891
                            fb_page->width, fb_page->height, fb_page->depth,
892
                            fb_page->mem_length, 0, fb_page->line_length);
893
    if (rc != 0)
894
        return rc;
895

    
896
    rc = xenfb_map_fb(fb);
897
    if (rc != 0)
898
        return rc;
899

    
900
#if 0  /* handled in xen_init_display() for now */
901
    if (!fb->have_console) {
902
        fb->c.ds = graphic_console_init(xenfb_update,
903
                                        xenfb_invalidate,
904
                                        NULL,
905
                                        NULL,
906
                                        fb);
907
        fb->have_console = 1;
908
    }
909
#endif
910

    
911
    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
912
        fb->feature_update = 0;
913
    if (fb->feature_update)
914
        xenstore_write_be_int(xendev, "request-update", 1);
915

    
916
    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
917
                  fb->feature_update, videoram);
918
    return 0;
919
}
920

    
921
static void fb_disconnect(struct XenDevice *xendev)
922
{
923
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
924

    
925
    /*
926
     * FIXME: qemu can't un-init gfx display (yet?).
927
     *   Replacing the framebuffer with anonymous shared memory
928
     *   instead.  This releases the guest pages and keeps qemu happy.
929
     */
930
    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
931
                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
932
                      -1, 0);
933
    common_unbind(&fb->c);
934
    fb->feature_update = 0;
935
    fb->bug_trigger    = 0;
936
}
937

    
938
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
939
{
940
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
941

    
942
    /*
943
     * Set state to Connected *again* once the frontend switched
944
     * to connected.  We must trigger the watch a second time to
945
     * workaround a frontend bug.
946
     */
947
    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
948
        xendev->fe_state == XenbusStateConnected &&
949
        xendev->be_state == XenbusStateConnected) {
950
        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
951
        xen_be_set_state(xendev, XenbusStateConnected);
952
        fb->bug_trigger = 1; /* only once */
953
    }
954
}
955

    
956
static void fb_event(struct XenDevice *xendev)
957
{
958
    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
959

    
960
    xenfb_handle_events(xenfb);
961
    xen_be_send_notify(&xenfb->c.xendev);
962
}
963

    
964
/* -------------------------------------------------------------------- */
965

    
966
struct XenDevOps xen_kbdmouse_ops = {
967
    .size       = sizeof(struct XenInput),
968
    .init       = input_init,
969
    .initialise = input_initialise,
970
    .connected  = input_connected,
971
    .disconnect = input_disconnect,
972
    .event      = input_event,
973
};
974

    
975
struct XenDevOps xen_framebuffer_ops = {
976
    .size       = sizeof(struct XenFB),
977
    .init       = fb_init,
978
    .initialise = fb_initialise,
979
    .disconnect = fb_disconnect,
980
    .event      = fb_event,
981
    .frontend_changed = fb_frontend_changed,
982
};
983

    
984
/*
985
 * FIXME/TODO: Kill this.
986
 * Temporary needed while DisplayState reorganization is in flight.
987
 */
988
void xen_init_display(int domid)
989
{
990
    struct XenDevice *xfb, *xin;
991
    struct XenFB *fb;
992
    struct XenInput *in;
993
    int i = 0;
994

    
995
wait_more:
996
    i++;
997
    main_loop_wait(true);
998
    xfb = xen_be_find_xendev("vfb", domid, 0);
999
    xin = xen_be_find_xendev("vkbd", domid, 0);
1000
    if (!xfb || !xin) {
1001
        if (i < 256) {
1002
            usleep(10000);
1003
            goto wait_more;
1004
        }
1005
        xen_be_printf(NULL, 1, "displaystate setup failed\n");
1006
        return;
1007
    }
1008

    
1009
    /* vfb */
1010
    fb = container_of(xfb, struct XenFB, c.xendev);
1011
    fb->c.ds = graphic_console_init(xenfb_update,
1012
                                    xenfb_invalidate,
1013
                                    NULL,
1014
                                    NULL,
1015
                                    fb);
1016
    fb->have_console = 1;
1017

    
1018
    /* vkbd */
1019
    in = container_of(xin, struct XenInput, c.xendev);
1020
    in->c.ds = fb->c.ds;
1021

    
1022
    /* retry ->init() */
1023
    xen_be_check_state(xin);
1024
    xen_be_check_state(xfb);
1025
}