Statistics
| Branch: | Revision:

root / hw / xenfb.c @ 8167ee88

History | View | Annotate | Download (30.1 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 <stdbool.h>
33
#include <sys/mman.h>
34
#include <errno.h>
35
#include <stdio.h>
36
#include <string.h>
37
#include <time.h>
38

    
39
#include <xs.h>
40
#include <xenctrl.h>
41
#include <xen/event_channel.h>
42
#include <xen/io/xenbus.h>
43
#include <xen/io/fbif.h>
44
#include <xen/io/kbdif.h>
45
#include <xen/io/protocols.h>
46

    
47
#include "hw.h"
48
#include "sysemu.h"
49
#include "console.h"
50
#include "qemu-char.h"
51
#include "xen_backend.h"
52

    
53
#ifndef BTN_LEFT
54
#define BTN_LEFT 0x110 /* from <linux/input.h> */
55
#endif
56

    
57
/* -------------------------------------------------------------------- */
58

    
59
struct common {
60
    struct XenDevice  xendev;  /* must be first */
61
    void              *page;
62
    DisplayState      *ds;
63
};
64

    
65
struct XenInput {
66
    struct common c;
67
    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
68
    int button_state;       /* Last seen pointer button state */
69
    int extended;
70
    QEMUPutMouseEntry *qmouse;
71
};
72

    
73
#define UP_QUEUE 8
74

    
75
struct XenFB {
76
    struct common     c;
77
    size_t            fb_len;
78
    int               row_stride;
79
    int               depth;
80
    int               width;
81
    int               height;
82
    int               offset;
83
    void              *pixels;
84
    int               fbpages;
85
    int               feature_update;
86
    int               refresh_period;
87
    int               bug_trigger;
88
    int               have_console;
89
    int               do_resize;
90

    
91
    struct {
92
        int x,y,w,h;
93
    } up_rects[UP_QUEUE];
94
    int               up_count;
95
    int               up_fullscreen;
96
};
97

    
98
/* -------------------------------------------------------------------- */
99

    
100
static int common_bind(struct common *c)
101
{
102
    int mfn;
103

    
104
    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
105
        return -1;
106
    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
107
        return -1;
108

    
109
    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
110
                                   XC_PAGE_SIZE,
111
                                   PROT_READ | PROT_WRITE, mfn);
112
    if (c->page == NULL)
113
        return -1;
114

    
115
    xen_be_bind_evtchn(&c->xendev);
116
    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
117
                  mfn, c->xendev.remote_port, c->xendev.local_port);
118

    
119
    return 0;
120
}
121

    
122
static void common_unbind(struct common *c)
123
{
124
    xen_be_unbind_evtchn(&c->xendev);
125
    if (c->page) {
126
        munmap(c->page, XC_PAGE_SIZE);
127
        c->page = NULL;
128
    }
129
}
130

    
131
/* -------------------------------------------------------------------- */
132

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

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

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

163
};
164

165
const unsigned char atkbd_unxlate_table[128] = {
166

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

176
};
177
#endif
178

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

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

    
205
/* Send an event to the keyboard frontend driver */
206
static int xenfb_kbd_event(struct XenInput *xenfb,
207
                           union xenkbd_in_event *event)
208
{
209
    struct xenkbd_page *page = xenfb->c.page;
210
    uint32_t prod;
211

    
212
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
213
        return 0;
214
    if (!page)
215
        return 0;
216

    
217
    prod = page->in_prod;
218
    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
219
        errno = EAGAIN;
220
        return -1;
221
    }
222

    
223
    xen_mb();                /* ensure ring space available */
224
    XENKBD_IN_RING_REF(page, prod) = *event;
225
    xen_wmb();                /* ensure ring contents visible */
226
    page->in_prod = prod + 1;
227
    return xen_be_send_notify(&xenfb->c.xendev);
228
}
229

    
230
/* Send a keyboard (or mouse button) event */
231
static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
232
{
233
    union xenkbd_in_event event;
234

    
235
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
236
    event.type = XENKBD_TYPE_KEY;
237
    event.key.pressed = down ? 1 : 0;
238
    event.key.keycode = keycode;
239

    
240
    return xenfb_kbd_event(xenfb, &event);
241
}
242

    
243
/* Send a relative mouse movement event */
244
static int xenfb_send_motion(struct XenInput *xenfb,
245
                             int rel_x, int rel_y, int rel_z)
246
{
247
    union xenkbd_in_event event;
248

    
249
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
250
    event.type = XENKBD_TYPE_MOTION;
251
    event.motion.rel_x = rel_x;
252
    event.motion.rel_y = rel_y;
253
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
254
    event.motion.rel_z = rel_z;
255
#endif
256

    
257
    return xenfb_kbd_event(xenfb, &event);
258
}
259

    
260
/* Send an absolute mouse movement event */
261
static int xenfb_send_position(struct XenInput *xenfb,
262
                               int abs_x, int abs_y, int z)
263
{
264
    union xenkbd_in_event event;
265

    
266
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
267
    event.type = XENKBD_TYPE_POS;
268
    event.pos.abs_x = abs_x;
269
    event.pos.abs_y = abs_y;
270
#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
271
    event.pos.abs_z = z;
272
#endif
273
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
274
    event.pos.rel_z = z;
275
#endif
276

    
277
    return xenfb_kbd_event(xenfb, &event);
278
}
279

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

    
299
    if (scancode == 0xe0) {
300
        xenfb->extended = 1;
301
        return;
302
    } else if (scancode & 0x80) {
303
        scancode &= 0x7f;
304
        down = 0;
305
    }
306
    if (xenfb->extended) {
307
        scancode |= 0x80;
308
        xenfb->extended = 0;
309
    }
310
    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
311
}
312

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

    
330
    if (xenfb->abs_pointer_wanted)
331
        xenfb_send_position(xenfb,
332
                            dx * (dw - 1) / 0x7fff,
333
                            dy * (dh - 1) / 0x7fff,
334
                            dz);
335
    else
336
        xenfb_send_motion(xenfb, dx, dy, dz);
337

    
338
    for (i = 0 ; i < 8 ; i++) {
339
        int lastDown = xenfb->button_state & (1 << i);
340
        int down = button_state & (1 << i);
341
        if (down == lastDown)
342
            continue;
343

    
344
        if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
345
            return;
346
    }
347
    xenfb->button_state = button_state;
348
}
349

    
350
static int input_init(struct XenDevice *xendev)
351
{
352
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
353

    
354
    if (!in->c.ds) {
355
        xen_be_printf(xendev, 1, "ds not set (yet)\n");
356
        return -1;
357
    }
358

    
359
    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
360
    return 0;
361
}
362

    
363
static int input_connect(struct XenDevice *xendev)
364
{
365
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
366
    int rc;
367

    
368
    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
369
                             &in->abs_pointer_wanted) == -1)
370
        in->abs_pointer_wanted = 0;
371

    
372
    rc = common_bind(&in->c);
373
    if (rc != 0)
374
        return rc;
375

    
376
    qemu_add_kbd_event_handler(xenfb_key_event, in);
377
    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
378
                                              in->abs_pointer_wanted,
379
                                              "Xen PVFB Mouse");
380
    return 0;
381
}
382

    
383
static void input_disconnect(struct XenDevice *xendev)
384
{
385
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
386

    
387
    if (in->qmouse) {
388
        qemu_remove_mouse_event_handler(in->qmouse);
389
        in->qmouse = NULL;
390
    }
391
    qemu_add_kbd_event_handler(NULL, NULL);
392
    common_unbind(&in->c);
393
}
394

    
395
static void input_event(struct XenDevice *xendev)
396
{
397
    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
398
    struct xenkbd_page *page = xenfb->c.page;
399

    
400
    /* We don't understand any keyboard events, so just ignore them. */
401
    if (page->out_prod == page->out_cons)
402
        return;
403
    page->out_cons = page->out_prod;
404
    xen_be_send_notify(&xenfb->c.xendev);
405
}
406

    
407
/* -------------------------------------------------------------------- */
408

    
409
static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
410
{
411
    uint32_t *src32 = src;
412
    uint64_t *src64 = src;
413
    int i;
414

    
415
    for (i = 0; i < count; i++)
416
        dst[i] = (mode == 32) ? src32[i] : src64[i];
417
}
418

    
419
static int xenfb_map_fb(struct XenFB *xenfb)
420
{
421
    struct xenfb_page *page = xenfb->c.page;
422
    char *protocol = xenfb->c.xendev.protocol;
423
    int n_fbdirs;
424
    unsigned long *pgmfns = NULL;
425
    unsigned long *fbmfns = NULL;
426
    void *map, *pd;
427
    int mode, ret = -1;
428

    
429
    /* default to native */
430
    pd = page->pd;
431
    mode = sizeof(unsigned long) * 8;
432

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

    
474
    if (xenfb->pixels) {
475
        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
476
        xenfb->pixels = NULL;
477
    }
478

    
479
    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
480
    n_fbdirs = xenfb->fbpages * mode / 8;
481
    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
482

    
483
    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
484
    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
485

    
486
    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
487
    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
488
                               PROT_READ, pgmfns, n_fbdirs);
489
    if (map == NULL)
490
        goto out;
491
    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
492
    munmap(map, n_fbdirs * XC_PAGE_SIZE);
493

    
494
    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
495
                                         PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
496
    if (xenfb->pixels == NULL)
497
        goto out;
498

    
499
    ret = 0; /* all is fine */
500

    
501
out:
502
    qemu_free(pgmfns);
503
    qemu_free(fbmfns);
504
    return ret;
505
}
506

    
507
static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
508
                              int width, int height, int depth,
509
                              size_t fb_len, int offset, int row_stride)
510
{
511
    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
512
    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
513
    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
514
    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
515
    int max_width, max_height;
516

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

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

    
599

    
600
/*
601
 * This copies data from the guest framebuffer region, into QEMU's
602
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
603
 * uses something else we must convert and copy, otherwise we can
604
 * supply the buffer directly and no thing here.
605
 */
606
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
607
{
608
    int line, oops = 0;
609
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
610
    int linesize = ds_get_linesize(xenfb->c.ds);
611
    uint8_t *data = ds_get_data(xenfb->c.ds);
612

    
613
    if (!is_buffer_shared(xenfb->c.ds->surface)) {
614
        switch (xenfb->depth) {
615
        case 8:
616
            if (bpp == 16) {
617
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
618
            } else if (bpp == 32) {
619
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
620
            } else {
621
                oops = 1;
622
            }
623
            break;
624
        case 24:
625
            if (bpp == 16) {
626
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
627
            } else if (bpp == 32) {
628
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
629
            } else {
630
                oops = 1;
631
            }
632
            break;
633
        default:
634
            oops = 1;
635
        }
636
    }
637
    if (oops) /* should not happen */
638
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
639
                      __FUNCTION__, xenfb->depth, bpp);
640

    
641
    dpy_update(xenfb->c.ds, x, y, w, h);
642
}
643

    
644
#ifdef XENFB_TYPE_REFRESH_PERIOD
645
static int xenfb_queue_full(struct XenFB *xenfb)
646
{
647
    struct xenfb_page *page = xenfb->c.page;
648
    uint32_t cons, prod;
649

    
650
    if (!page)
651
        return 1;
652

    
653
    prod = page->in_prod;
654
    cons = page->in_cons;
655
    return prod - cons == XENFB_IN_RING_LEN;
656
}
657

    
658
static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
659
{
660
    uint32_t prod;
661
    struct xenfb_page *page = xenfb->c.page;
662

    
663
    prod = page->in_prod;
664
    /* caller ensures !xenfb_queue_full() */
665
    xen_mb();                   /* ensure ring space available */
666
    XENFB_IN_RING_REF(page, prod) = *event;
667
    xen_wmb();                  /* ensure ring contents visible */
668
    page->in_prod = prod + 1;
669

    
670
    xen_be_send_notify(&xenfb->c.xendev);
671
}
672

    
673
static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
674
{
675
    union xenfb_in_event event;
676

    
677
    memset(&event, 0, sizeof(event));
678
    event.type = XENFB_TYPE_REFRESH_PERIOD;
679
    event.refresh_period.period = period;
680
    xenfb_send_event(xenfb, &event);
681
}
682
#endif
683

    
684
/*
685
 * Periodic update of display.
686
 * Also transmit the refresh interval to the frontend.
687
 *
688
 * Never ever do any qemu display operations
689
 * (resize, screen update) outside this function.
690
 * Our screen might be inactive.  When asked for
691
 * an update we know it is active.
692
 */
693
static void xenfb_update(void *opaque)
694
{
695
    struct XenFB *xenfb = opaque;
696
    int i;
697

    
698
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
699
        return;
700

    
701
    if (xenfb->feature_update) {
702
#ifdef XENFB_TYPE_REFRESH_PERIOD
703
        struct DisplayChangeListener *l;
704
        int period = 99999999;
705
        int idle = 1;
706

    
707
        if (xenfb_queue_full(xenfb))
708
            return;
709

    
710
        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
711
            if (l->idle)
712
                continue;
713
            idle = 0;
714
            if (!l->gui_timer_interval) {
715
                if (period > GUI_REFRESH_INTERVAL)
716
                    period = GUI_REFRESH_INTERVAL;
717
            } else {
718
                if (period > l->gui_timer_interval)
719
                    period = l->gui_timer_interval;
720
            }
721
        }
722
        if (idle)
723
            period = XENFB_NO_REFRESH;
724

    
725
        if (xenfb->refresh_period != period) {
726
            xenfb_send_refresh_period(xenfb, period);
727
            xenfb->refresh_period = period;
728
            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
729
        }
730
#else
731
        ; /* nothing */
732
#endif
733
    } else {
734
        /* we don't get update notifications, thus use the
735
         * sledge hammer approach ... */
736
        xenfb->up_fullscreen = 1;
737
    }
738

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

    
763
    /* run queued updates */
764
    if (xenfb->up_fullscreen) {
765
        xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
766
        xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
767
    } else if (xenfb->up_count) {
768
        xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
769
        for (i = 0; i < xenfb->up_count; i++)
770
            xenfb_guest_copy(xenfb,
771
                             xenfb->up_rects[i].x,
772
                             xenfb->up_rects[i].y,
773
                             xenfb->up_rects[i].w,
774
                             xenfb->up_rects[i].h);
775
    } else {
776
        xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
777
    }
778
    xenfb->up_count = 0;
779
    xenfb->up_fullscreen = 0;
780
}
781

    
782
/* QEMU display state changed, so refresh the framebuffer copy */
783
static void xenfb_invalidate(void *opaque)
784
{
785
    struct XenFB *xenfb = opaque;
786
    xenfb->up_fullscreen = 1;
787
}
788

    
789
static void xenfb_handle_events(struct XenFB *xenfb)
790
{
791
    uint32_t prod, cons;
792
    struct xenfb_page *page = xenfb->c.page;
793

    
794
    prod = page->out_prod;
795
    if (prod == page->out_cons)
796
        return;
797
    xen_rmb();                /* ensure we see ring contents up to prod */
798
    for (cons = page->out_cons; cons != prod; cons++) {
799
        union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
800
        int x, y, w, h;
801

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

    
853
static int fb_init(struct XenDevice *xendev)
854
{
855
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
856

    
857
    fb->refresh_period = -1;
858

    
859
#ifdef XENFB_TYPE_RESIZE
860
    xenstore_write_be_int(xendev, "feature-resize", 1);
861
#endif
862
    return 0;
863
}
864

    
865
static int fb_connect(struct XenDevice *xendev)
866
{
867
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
868
    struct xenfb_page *fb_page;
869
    int videoram;
870
    int rc;
871

    
872
    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
873
        videoram = 0;
874

    
875
    rc = common_bind(&fb->c);
876
    if (rc != 0)
877
        return rc;
878

    
879
    fb_page = fb->c.page;
880
    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
881
                            fb_page->width, fb_page->height, fb_page->depth,
882
                            fb_page->mem_length, 0, fb_page->line_length);
883
    if (rc != 0)
884
        return rc;
885

    
886
    rc = xenfb_map_fb(fb);
887
    if (rc != 0)
888
        return rc;
889

    
890
#if 0  /* handled in xen_init_display() for now */
891
    if (!fb->have_console) {
892
        fb->c.ds = graphic_console_init(xenfb_update,
893
                                        xenfb_invalidate,
894
                                        NULL,
895
                                        NULL,
896
                                        fb);
897
        fb->have_console = 1;
898
    }
899
#endif
900

    
901
    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
902
        fb->feature_update = 0;
903
    if (fb->feature_update)
904
        xenstore_write_be_int(xendev, "request-update", 1);
905

    
906
    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
907
                  fb->feature_update, videoram);
908
    return 0;
909
}
910

    
911
static void fb_disconnect(struct XenDevice *xendev)
912
{
913
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
914

    
915
    /*
916
     * FIXME: qemu can't un-init gfx display (yet?).
917
     *   Replacing the framebuffer with anonymous shared memory
918
     *   instead.  This releases the guest pages and keeps qemu happy.
919
     */
920
    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
921
                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
922
                      -1, 0);
923
    common_unbind(&fb->c);
924
    fb->feature_update = 0;
925
    fb->bug_trigger    = 0;
926
}
927

    
928
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
929
{
930
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
931

    
932
    /*
933
     * Set state to Connected *again* once the frontend switched
934
     * to connected.  We must trigger the watch a second time to
935
     * workaround a frontend bug.
936
     */
937
    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
938
        xendev->fe_state == XenbusStateConnected &&
939
        xendev->be_state == XenbusStateConnected) {
940
        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
941
        xen_be_set_state(xendev, XenbusStateConnected);
942
        fb->bug_trigger = 1; /* only once */
943
    }
944
}
945

    
946
static void fb_event(struct XenDevice *xendev)
947
{
948
    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
949

    
950
    xenfb_handle_events(xenfb);
951
    xen_be_send_notify(&xenfb->c.xendev);
952
}
953

    
954
/* -------------------------------------------------------------------- */
955

    
956
struct XenDevOps xen_kbdmouse_ops = {
957
    .size       = sizeof(struct XenInput),
958
    .init       = input_init,
959
    .connect    = input_connect,
960
    .disconnect = input_disconnect,
961
    .event      = input_event,
962
};
963

    
964
struct XenDevOps xen_framebuffer_ops = {
965
    .size       = sizeof(struct XenFB),
966
    .init       = fb_init,
967
    .connect    = fb_connect,
968
    .disconnect = fb_disconnect,
969
    .event      = fb_event,
970
    .frontend_changed = fb_frontend_changed,
971
};
972

    
973
/*
974
 * FIXME/TODO: Kill this.
975
 * Temporary needed while DisplayState reorganization is in flight.
976
 */
977
void xen_init_display(int domid)
978
{
979
    struct XenDevice *xfb, *xin;
980
    struct XenFB *fb;
981
    struct XenInput *in;
982
    int i = 0;
983

    
984
wait_more:
985
    i++;
986
    main_loop_wait(10); /* miliseconds */
987
    xfb = xen_be_find_xendev("vfb", domid, 0);
988
    xin = xen_be_find_xendev("vkbd", domid, 0);
989
    if (!xfb || !xin) {
990
        if (i < 256)
991
            goto wait_more;
992
        xen_be_printf(NULL, 1, "displaystate setup failed\n");
993
        return;
994
    }
995

    
996
    /* vfb */
997
    fb = container_of(xfb, struct XenFB, c.xendev);
998
    fb->c.ds = graphic_console_init(xenfb_update,
999
                                    xenfb_invalidate,
1000
                                    NULL,
1001
                                    NULL,
1002
                                    fb);
1003
    fb->have_console = 1;
1004

    
1005
    /* vkbd */
1006
    in = container_of(xin, struct XenInput, c.xendev);
1007
    in->c.ds = fb->c.ds;
1008

    
1009
    /* retry ->init() */
1010
    xen_be_check_state(xin);
1011
    xen_be_check_state(xfb);
1012
}