Statistics
| Branch: | Revision:

root / hw / xenfb.c @ 11165820

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 <sys/mman.h>
33
#include <errno.h>
34
#include <stdio.h>
35
#include <string.h>
36
#include <time.h>
37

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

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

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

    
56
/* -------------------------------------------------------------------- */
57

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

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

    
72
#define UP_QUEUE 8
73

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

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

    
97
/* -------------------------------------------------------------------- */
98

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

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

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

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

    
118
    return 0;
119
}
120

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

    
130
/* -------------------------------------------------------------------- */
131

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

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

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

162
};
163

164
const unsigned char atkbd_unxlate_table[128] = {
165

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

175
};
176
#endif
177

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
406
/* -------------------------------------------------------------------- */
407

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
598

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

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

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

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

    
649
    if (!page)
650
        return 1;
651

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
856
    fb->refresh_period = -1;
857

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
953
/* -------------------------------------------------------------------- */
954

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

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

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

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

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

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

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