win32: Avoid compiler warning (WIN32_LEAN_AND_MEAN redefined)
[qemu.git] / hw / xenfb.c
blobda5297b4989952d188ee0c6f8359bdb9a5619a9d
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 <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>
46 #include "hw.h"
47 #include "sysemu.h"
48 #include "console.h"
49 #include "qemu-char.h"
50 #include "xen_backend.h"
52 #ifndef BTN_LEFT
53 #define BTN_LEFT 0x110 /* from <linux/input.h> */
54 #endif
56 /* -------------------------------------------------------------------- */
58 struct common {
59 struct XenDevice xendev; /* must be first */
60 void *page;
61 DisplayState *ds;
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;
72 #define UP_QUEUE 8
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;
90 struct {
91 int x,y,w,h;
92 } up_rects[UP_QUEUE];
93 int up_count;
94 int up_fullscreen;
97 /* -------------------------------------------------------------------- */
99 static int common_bind(struct common *c)
101 int mfn;
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;
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;
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);
118 return 0;
121 static void common_unbind(struct common *c)
123 xen_be_unbind_evtchn(&c->xendev);
124 if (c->page) {
125 munmap(c->page, XC_PAGE_SIZE);
126 c->page = NULL;
130 /* -------------------------------------------------------------------- */
132 #if 0
134 * These two tables are not needed any more, but left in here
135 * intentionally as documentation, to show how scancode2linux[]
136 * was generated.
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.
142 const unsigned char atkbd_set2_keycode[512] = {
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,
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,
164 const unsigned char atkbd_unxlate_table[128] = {
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
176 #endif
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];
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,
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,
204 /* Send an event to the keyboard frontend driver */
205 static int xenfb_kbd_event(struct XenInput *xenfb,
206 union xenkbd_in_event *event)
208 struct xenkbd_page *page = xenfb->c.page;
209 uint32_t prod;
211 if (xenfb->c.xendev.be_state != XenbusStateConnected)
212 return 0;
213 if (!page)
214 return 0;
216 prod = page->in_prod;
217 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
218 errno = EAGAIN;
219 return -1;
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);
229 /* Send a keyboard (or mouse button) event */
230 static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
232 union xenkbd_in_event event;
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;
239 return xenfb_kbd_event(xenfb, &event);
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)
246 union xenkbd_in_event event;
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
256 return xenfb_kbd_event(xenfb, &event);
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)
263 union xenkbd_in_event event;
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
276 return xenfb_kbd_event(xenfb, &event);
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.
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.
290 * Wish we could just send scancodes straight to the guest which
291 * already has code for dealing with this...
293 static void xenfb_key_event(void *opaque, int scancode)
295 struct XenInput *xenfb = opaque;
296 int down = 1;
298 if (scancode == 0xe0) {
299 xenfb->extended = 1;
300 return;
301 } else if (scancode & 0x80) {
302 scancode &= 0x7f;
303 down = 0;
305 if (xenfb->extended) {
306 scancode |= 0x80;
307 xenfb->extended = 0;
309 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
313 * Send a mouse event from the client to the guest OS
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.
321 static void xenfb_mouse_event(void *opaque,
322 int dx, int dy, int dz, int button_state)
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;
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);
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;
343 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
344 return;
346 xenfb->button_state = button_state;
349 static int input_init(struct XenDevice *xendev)
351 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
353 if (!in->c.ds) {
354 xen_be_printf(xendev, 1, "ds not set (yet)\n");
355 return -1;
358 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
359 return 0;
362 static int input_connect(struct XenDevice *xendev)
364 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
365 int rc;
367 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
368 &in->abs_pointer_wanted) == -1)
369 in->abs_pointer_wanted = 0;
371 rc = common_bind(&in->c);
372 if (rc != 0)
373 return rc;
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;
382 static void input_disconnect(struct XenDevice *xendev)
384 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
386 if (in->qmouse) {
387 qemu_remove_mouse_event_handler(in->qmouse);
388 in->qmouse = NULL;
390 qemu_add_kbd_event_handler(NULL, NULL);
391 common_unbind(&in->c);
394 static void input_event(struct XenDevice *xendev)
396 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
397 struct xenkbd_page *page = xenfb->c.page;
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);
406 /* -------------------------------------------------------------------- */
408 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
410 uint32_t *src32 = src;
411 uint64_t *src64 = src;
412 int i;
414 for (i = 0; i < count; i++)
415 dst[i] = (mode == 32) ? src32[i] : src64[i];
418 static int xenfb_map_fb(struct XenFB *xenfb)
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;
428 /* default to native */
429 pd = page->pd;
430 mode = sizeof(unsigned long) * 8;
432 if (!protocol) {
434 * Undefined protocol, some guesswork needed.
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 ...
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;
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
473 if (xenfb->pixels) {
474 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
475 xenfb->pixels = NULL;
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;
482 pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
483 fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
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);
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;
498 ret = 0; /* all is fine */
500 out:
501 qemu_free(pgmfns);
502 qemu_free(fbmfns);
503 return ret;
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)
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;
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;
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;
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;
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;
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;
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;
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;
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;
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); \
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.
605 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
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);
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;
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;
631 break;
632 default:
633 oops = 1;
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);
640 dpy_update(xenfb->c.ds, x, y, w, h);
643 #ifdef XENFB_TYPE_REFRESH_PERIOD
644 static int xenfb_queue_full(struct XenFB *xenfb)
646 struct xenfb_page *page = xenfb->c.page;
647 uint32_t cons, prod;
649 if (!page)
650 return 1;
652 prod = page->in_prod;
653 cons = page->in_cons;
654 return prod - cons == XENFB_IN_RING_LEN;
657 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
659 uint32_t prod;
660 struct xenfb_page *page = xenfb->c.page;
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;
669 xen_be_send_notify(&xenfb->c.xendev);
672 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
674 union xenfb_in_event event;
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);
681 #endif
684 * Periodic update of display.
685 * Also transmit the refresh interval to the frontend.
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.
692 static void xenfb_update(void *opaque)
694 struct XenFB *xenfb = opaque;
695 int i;
697 if (xenfb->c.xendev.be_state != XenbusStateConnected)
698 return;
700 if (xenfb->feature_update) {
701 #ifdef XENFB_TYPE_REFRESH_PERIOD
702 struct DisplayChangeListener *l;
703 int period = 99999999;
704 int idle = 1;
706 if (xenfb_queue_full(xenfb))
707 return;
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;
721 if (idle)
722 period = XENFB_NO_REFRESH;
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);
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;
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;
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;
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");
777 xenfb->up_count = 0;
778 xenfb->up_fullscreen = 0;
781 /* QEMU display state changed, so refresh the framebuffer copy */
782 static void xenfb_invalidate(void *opaque)
784 struct XenFB *xenfb = opaque;
785 xenfb->up_fullscreen = 1;
788 static void xenfb_handle_events(struct XenFB *xenfb)
790 uint32_t prod, cons;
791 struct xenfb_page *page = xenfb->c.page;
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;
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;
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");
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++;
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
848 xen_mb(); /* ensure we're done with ring contents */
849 page->out_cons = cons;
852 static int fb_init(struct XenDevice *xendev)
854 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
856 fb->refresh_period = -1;
858 #ifdef XENFB_TYPE_RESIZE
859 xenstore_write_be_int(xendev, "feature-resize", 1);
860 #endif
861 return 0;
864 static int fb_connect(struct XenDevice *xendev)
866 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
867 struct xenfb_page *fb_page;
868 int videoram;
869 int rc;
871 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
872 videoram = 0;
874 rc = common_bind(&fb->c);
875 if (rc != 0)
876 return rc;
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;
885 rc = xenfb_map_fb(fb);
886 if (rc != 0)
887 return rc;
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;
898 #endif
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);
905 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
906 fb->feature_update, videoram);
907 return 0;
910 static void fb_disconnect(struct XenDevice *xendev)
912 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
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.
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;
927 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
929 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
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.
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 */
945 static void fb_event(struct XenDevice *xendev)
947 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
949 xenfb_handle_events(xenfb);
950 xen_be_send_notify(&xenfb->c.xendev);
953 /* -------------------------------------------------------------------- */
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,
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,
973 * FIXME/TODO: Kill this.
974 * Temporary needed while DisplayState reorganization is in flight.
976 void xen_init_display(int domid)
978 struct XenDevice *xfb, *xin;
979 struct XenFB *fb;
980 struct XenInput *in;
981 int i = 0;
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;
993 xen_be_printf(NULL, 1, "displaystate setup failed\n");
994 return;
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;
1006 /* vkbd */
1007 in = container_of(xin, struct XenInput, c.xendev);
1008 in->c.ds = fb->c.ds;
1010 /* retry ->init() */
1011 xen_be_check_state(xin);
1012 xen_be_check_state(xfb);