gtk: fix vc initialization
[qemu/agraf.git] / hw / xenfb.c
blob3462ded619a914889cff7f9315c7f4b9bc947ec2
1 /*
2 * xen paravirt framebuffer backend
4 * Copyright IBM, Corp. 2005-2006
5 * Copyright Red Hat, Inc. 2006-2008
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>
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.
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.
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/>.
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>
38 #include "hw/hw.h"
39 #include "ui/console.h"
40 #include "char/char.h"
41 #include "hw/xen_backend.h"
43 #include <xen/event_channel.h>
44 #include <xen/io/fbif.h>
45 #include <xen/io/kbdif.h>
46 #include <xen/io/protocols.h>
48 #ifndef BTN_LEFT
49 #define BTN_LEFT 0x110 /* from <linux/input.h> */
50 #endif
52 /* -------------------------------------------------------------------- */
54 struct common {
55 struct XenDevice xendev; /* must be first */
56 void *page;
57 DisplayState *ds;
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;
68 #define UP_QUEUE 8
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;
86 struct {
87 int x,y,w,h;
88 } up_rects[UP_QUEUE];
89 int up_count;
90 int up_fullscreen;
93 /* -------------------------------------------------------------------- */
95 static int common_bind(struct common *c)
97 int mfn;
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;
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;
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);
114 return 0;
117 static void common_unbind(struct common *c)
119 xen_be_unbind_evtchn(&c->xendev);
120 if (c->page) {
121 munmap(c->page, XC_PAGE_SIZE);
122 c->page = NULL;
126 /* -------------------------------------------------------------------- */
128 #if 0
130 * These two tables are not needed any more, but left in here
131 * intentionally as documentation, to show how scancode2linux[]
132 * was generated.
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.
138 const unsigned char atkbd_set2_keycode[512] = {
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,
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,
160 const unsigned char atkbd_unxlate_table[128] = {
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
172 #endif
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];
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,
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,
200 /* Send an event to the keyboard frontend driver */
201 static int xenfb_kbd_event(struct XenInput *xenfb,
202 union xenkbd_in_event *event)
204 struct xenkbd_page *page = xenfb->c.page;
205 uint32_t prod;
207 if (xenfb->c.xendev.be_state != XenbusStateConnected)
208 return 0;
209 if (!page)
210 return 0;
212 prod = page->in_prod;
213 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
214 errno = EAGAIN;
215 return -1;
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);
225 /* Send a keyboard (or mouse button) event */
226 static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
228 union xenkbd_in_event event;
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;
235 return xenfb_kbd_event(xenfb, &event);
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)
242 union xenkbd_in_event event;
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
252 return xenfb_kbd_event(xenfb, &event);
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)
259 union xenkbd_in_event event;
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
272 return xenfb_kbd_event(xenfb, &event);
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.
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.
286 * Wish we could just send scancodes straight to the guest which
287 * already has code for dealing with this...
289 static void xenfb_key_event(void *opaque, int scancode)
291 struct XenInput *xenfb = opaque;
292 int down = 1;
294 if (scancode == 0xe0) {
295 xenfb->extended = 1;
296 return;
297 } else if (scancode & 0x80) {
298 scancode &= 0x7f;
299 down = 0;
301 if (xenfb->extended) {
302 scancode |= 0x80;
303 xenfb->extended = 0;
305 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
309 * Send a mouse event from the client to the guest OS
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.
317 static void xenfb_mouse_event(void *opaque,
318 int dx, int dy, int dz, int button_state)
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;
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);
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;
339 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
340 return;
342 xenfb->button_state = button_state;
345 static int input_init(struct XenDevice *xendev)
347 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
348 return 0;
351 static int input_initialise(struct XenDevice *xendev)
353 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
354 int rc;
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;
368 rc = common_bind(&in->c);
369 if (rc != 0)
370 return rc;
372 qemu_add_kbd_event_handler(xenfb_key_event, in);
373 return 0;
376 static void input_connected(struct XenDevice *xendev)
378 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
380 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
381 &in->abs_pointer_wanted) == -1) {
382 in->abs_pointer_wanted = 0;
385 if (in->qmouse) {
386 qemu_remove_mouse_event_handler(in->qmouse);
388 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
389 in->abs_pointer_wanted,
390 "Xen PVFB Mouse");
393 static void input_disconnect(struct XenDevice *xendev)
395 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
397 if (in->qmouse) {
398 qemu_remove_mouse_event_handler(in->qmouse);
399 in->qmouse = NULL;
401 qemu_add_kbd_event_handler(NULL, NULL);
402 common_unbind(&in->c);
405 static void input_event(struct XenDevice *xendev)
407 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
408 struct xenkbd_page *page = xenfb->c.page;
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);
417 /* -------------------------------------------------------------------- */
419 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
421 uint32_t *src32 = src;
422 uint64_t *src64 = src;
423 int i;
425 for (i = 0; i < count; i++)
426 dst[i] = (mode == 32) ? src32[i] : src64[i];
429 static int xenfb_map_fb(struct XenFB *xenfb)
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;
439 /* default to native */
440 pd = page->pd;
441 mode = sizeof(unsigned long) * 8;
443 if (!protocol) {
445 * Undefined protocol, some guesswork needed.
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 ...
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;
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
484 if (xenfb->pixels) {
485 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
486 xenfb->pixels = NULL;
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;
493 pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
494 fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
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);
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;
509 ret = 0; /* all is fine */
511 out:
512 g_free(pgmfns);
513 g_free(fbmfns);
514 return ret;
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)
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;
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;
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;
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;
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;
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;
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;
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;
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;
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); \
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.
616 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
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);
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;
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;
642 break;
643 default:
644 oops = 1;
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);
651 dpy_gfx_update(xenfb->c.ds, x, y, w, h);
654 #ifdef XENFB_TYPE_REFRESH_PERIOD
655 static int xenfb_queue_full(struct XenFB *xenfb)
657 struct xenfb_page *page = xenfb->c.page;
658 uint32_t cons, prod;
660 if (!page)
661 return 1;
663 prod = page->in_prod;
664 cons = page->in_cons;
665 return prod - cons == XENFB_IN_RING_LEN;
668 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
670 uint32_t prod;
671 struct xenfb_page *page = xenfb->c.page;
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;
680 xen_be_send_notify(&xenfb->c.xendev);
683 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
685 union xenfb_in_event event;
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);
692 #endif
695 * Periodic update of display.
696 * Also transmit the refresh interval to the frontend.
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.
703 static void xenfb_update(void *opaque)
705 struct XenFB *xenfb = opaque;
706 int i;
708 if (xenfb->c.xendev.be_state != XenbusStateConnected)
709 return;
711 if (xenfb->feature_update) {
712 #ifdef XENFB_TYPE_REFRESH_PERIOD
713 struct DisplayChangeListener *l;
714 int period = 99999999;
715 int idle = 1;
717 if (xenfb_queue_full(xenfb))
718 return;
720 QLIST_FOREACH(l, &xenfb->c.ds->listeners, 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;
732 if (idle)
733 period = XENFB_NO_REFRESH;
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);
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;
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 false);
761 break;
762 default:
763 /* we must convert stuff */
764 qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
765 break;
767 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
768 xenfb->width, xenfb->height, xenfb->depth,
769 is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
770 dpy_gfx_resize(xenfb->c.ds);
771 xenfb->up_fullscreen = 1;
774 /* run queued updates */
775 if (xenfb->up_fullscreen) {
776 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
777 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
778 } else if (xenfb->up_count) {
779 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
780 for (i = 0; i < xenfb->up_count; i++)
781 xenfb_guest_copy(xenfb,
782 xenfb->up_rects[i].x,
783 xenfb->up_rects[i].y,
784 xenfb->up_rects[i].w,
785 xenfb->up_rects[i].h);
786 } else {
787 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
789 xenfb->up_count = 0;
790 xenfb->up_fullscreen = 0;
793 /* QEMU display state changed, so refresh the framebuffer copy */
794 static void xenfb_invalidate(void *opaque)
796 struct XenFB *xenfb = opaque;
797 xenfb->up_fullscreen = 1;
800 static void xenfb_handle_events(struct XenFB *xenfb)
802 uint32_t prod, cons;
803 struct xenfb_page *page = xenfb->c.page;
805 prod = page->out_prod;
806 if (prod == page->out_cons)
807 return;
808 xen_rmb(); /* ensure we see ring contents up to prod */
809 for (cons = page->out_cons; cons != prod; cons++) {
810 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
811 int x, y, w, h;
813 switch (event->type) {
814 case XENFB_TYPE_UPDATE:
815 if (xenfb->up_count == UP_QUEUE)
816 xenfb->up_fullscreen = 1;
817 if (xenfb->up_fullscreen)
818 break;
819 x = MAX(event->update.x, 0);
820 y = MAX(event->update.y, 0);
821 w = MIN(event->update.width, xenfb->width - x);
822 h = MIN(event->update.height, xenfb->height - y);
823 if (w < 0 || h < 0) {
824 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
825 break;
827 if (x != event->update.x ||
828 y != event->update.y ||
829 w != event->update.width ||
830 h != event->update.height) {
831 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
833 if (w == xenfb->width && h > xenfb->height / 2) {
834 /* scroll detector: updated more than 50% of the lines,
835 * don't bother keeping track of the rectangles then */
836 xenfb->up_fullscreen = 1;
837 } else {
838 xenfb->up_rects[xenfb->up_count].x = x;
839 xenfb->up_rects[xenfb->up_count].y = y;
840 xenfb->up_rects[xenfb->up_count].w = w;
841 xenfb->up_rects[xenfb->up_count].h = h;
842 xenfb->up_count++;
844 break;
845 #ifdef XENFB_TYPE_RESIZE
846 case XENFB_TYPE_RESIZE:
847 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
848 event->resize.width,
849 event->resize.height,
850 event->resize.depth,
851 xenfb->fb_len,
852 event->resize.offset,
853 event->resize.stride) < 0)
854 break;
855 xenfb_invalidate(xenfb);
856 break;
857 #endif
860 xen_mb(); /* ensure we're done with ring contents */
861 page->out_cons = cons;
864 static int fb_init(struct XenDevice *xendev)
866 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
868 fb->refresh_period = -1;
870 #ifdef XENFB_TYPE_RESIZE
871 xenstore_write_be_int(xendev, "feature-resize", 1);
872 #endif
873 return 0;
876 static int fb_initialise(struct XenDevice *xendev)
878 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
879 struct xenfb_page *fb_page;
880 int videoram;
881 int rc;
883 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
884 videoram = 0;
886 rc = common_bind(&fb->c);
887 if (rc != 0)
888 return rc;
890 fb_page = fb->c.page;
891 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
892 fb_page->width, fb_page->height, fb_page->depth,
893 fb_page->mem_length, 0, fb_page->line_length);
894 if (rc != 0)
895 return rc;
897 rc = xenfb_map_fb(fb);
898 if (rc != 0)
899 return rc;
901 #if 0 /* handled in xen_init_display() for now */
902 if (!fb->have_console) {
903 fb->c.ds = graphic_console_init(xenfb_update,
904 xenfb_invalidate,
905 NULL,
906 NULL,
907 fb);
908 fb->have_console = 1;
910 #endif
912 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
913 fb->feature_update = 0;
914 if (fb->feature_update)
915 xenstore_write_be_int(xendev, "request-update", 1);
917 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
918 fb->feature_update, videoram);
919 return 0;
922 static void fb_disconnect(struct XenDevice *xendev)
924 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
927 * FIXME: qemu can't un-init gfx display (yet?).
928 * Replacing the framebuffer with anonymous shared memory
929 * instead. This releases the guest pages and keeps qemu happy.
931 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
932 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
933 -1, 0);
934 common_unbind(&fb->c);
935 fb->feature_update = 0;
936 fb->bug_trigger = 0;
939 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
941 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
944 * Set state to Connected *again* once the frontend switched
945 * to connected. We must trigger the watch a second time to
946 * workaround a frontend bug.
948 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
949 xendev->fe_state == XenbusStateConnected &&
950 xendev->be_state == XenbusStateConnected) {
951 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
952 xen_be_set_state(xendev, XenbusStateConnected);
953 fb->bug_trigger = 1; /* only once */
957 static void fb_event(struct XenDevice *xendev)
959 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
961 xenfb_handle_events(xenfb);
962 xen_be_send_notify(&xenfb->c.xendev);
965 /* -------------------------------------------------------------------- */
967 struct XenDevOps xen_kbdmouse_ops = {
968 .size = sizeof(struct XenInput),
969 .init = input_init,
970 .initialise = input_initialise,
971 .connected = input_connected,
972 .disconnect = input_disconnect,
973 .event = input_event,
976 struct XenDevOps xen_framebuffer_ops = {
977 .size = sizeof(struct XenFB),
978 .init = fb_init,
979 .initialise = fb_initialise,
980 .disconnect = fb_disconnect,
981 .event = fb_event,
982 .frontend_changed = fb_frontend_changed,
986 * FIXME/TODO: Kill this.
987 * Temporary needed while DisplayState reorganization is in flight.
989 void xen_init_display(int domid)
991 struct XenDevice *xfb, *xin;
992 struct XenFB *fb;
993 struct XenInput *in;
994 int i = 0;
996 wait_more:
997 i++;
998 main_loop_wait(true);
999 xfb = xen_be_find_xendev("vfb", domid, 0);
1000 xin = xen_be_find_xendev("vkbd", domid, 0);
1001 if (!xfb || !xin) {
1002 if (i < 256) {
1003 usleep(10000);
1004 goto wait_more;
1006 xen_be_printf(NULL, 1, "displaystate setup failed\n");
1007 return;
1010 /* vfb */
1011 fb = container_of(xfb, struct XenFB, c.xendev);
1012 fb->c.ds = graphic_console_init(xenfb_update,
1013 xenfb_invalidate,
1014 NULL,
1015 NULL,
1016 fb);
1017 fb->have_console = 1;
1019 /* vkbd */
1020 in = container_of(xin, struct XenInput, c.xendev);
1021 in->c.ds = fb->c.ds;
1023 /* retry ->init() */
1024 xen_be_check_state(xin);
1025 xen_be_check_state(xfb);