xen: Fix coding style errors
[qemu/ar7.git] / hw / display / xenfb.c
blobeaa1fce73c496a855a8488d09f1a6aae7fc4c598
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 "qemu/osdep.h"
29 #include "hw/hw.h"
30 #include "ui/console.h"
31 #include "sysemu/char.h"
32 #include "hw/xen/xen_backend.h"
34 #include <xen/event_channel.h>
35 #include <xen/io/fbif.h>
36 #include <xen/io/kbdif.h>
37 #include <xen/io/protocols.h>
39 #include "trace.h"
41 #ifndef BTN_LEFT
42 #define BTN_LEFT 0x110 /* from <linux/input.h> */
43 #endif
45 /* -------------------------------------------------------------------- */
47 struct common {
48 struct XenDevice xendev; /* must be first */
49 void *page;
50 QemuConsole *con;
53 struct XenInput {
54 struct common c;
55 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
56 int button_state; /* Last seen pointer button state */
57 int extended;
58 QEMUPutMouseEntry *qmouse;
61 #define UP_QUEUE 8
63 struct XenFB {
64 struct common c;
65 size_t fb_len;
66 int row_stride;
67 int depth;
68 int width;
69 int height;
70 int offset;
71 void *pixels;
72 int fbpages;
73 int feature_update;
74 int bug_trigger;
75 int have_console;
76 int do_resize;
78 struct {
79 int x,y,w,h;
80 } up_rects[UP_QUEUE];
81 int up_count;
82 int up_fullscreen;
85 /* -------------------------------------------------------------------- */
87 static int common_bind(struct common *c)
89 uint64_t val;
90 xen_pfn_t mfn;
92 if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &val) == -1)
93 return -1;
94 mfn = (xen_pfn_t)val;
95 assert(val == mfn);
97 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
98 return -1;
100 c->page = xenforeignmemory_map(xen_fmem, c->xendev.dom,
101 PROT_READ | PROT_WRITE, 1, &mfn, NULL);
102 if (c->page == NULL)
103 return -1;
105 xen_be_bind_evtchn(&c->xendev);
106 xen_be_printf(&c->xendev, 1,
107 "ring mfn %"PRI_xen_pfn", remote-port %d, local-port %d\n",
108 mfn, c->xendev.remote_port, c->xendev.local_port);
110 return 0;
113 static void common_unbind(struct common *c)
115 xen_be_unbind_evtchn(&c->xendev);
116 if (c->page) {
117 xenforeignmemory_unmap(xen_fmem, c->page, 1);
118 c->page = NULL;
122 /* -------------------------------------------------------------------- */
124 #if 0
126 * These two tables are not needed any more, but left in here
127 * intentionally as documentation, to show how scancode2linux[]
128 * was generated.
130 * Tables to map from scancode to Linux input layer keycode.
131 * Scancodes are hardware-specific. These maps assumes a
132 * standard AT or PS/2 keyboard which is what QEMU feeds us.
134 const unsigned char atkbd_set2_keycode[512] = {
136 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
137 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
138 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
139 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
140 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
141 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
142 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
143 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
146 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
147 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
148 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
149 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
150 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
151 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
152 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
156 const unsigned char atkbd_unxlate_table[128] = {
158 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
159 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
160 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
161 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
162 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
163 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
164 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
165 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
168 #endif
171 * for (i = 0; i < 128; i++) {
172 * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
173 * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
176 static const unsigned char scancode2linux[512] = {
177 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
178 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
179 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
180 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
181 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
182 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
183 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
187 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
188 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
189 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
190 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
191 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
192 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196 /* Send an event to the keyboard frontend driver */
197 static int xenfb_kbd_event(struct XenInput *xenfb,
198 union xenkbd_in_event *event)
200 struct xenkbd_page *page = xenfb->c.page;
201 uint32_t prod;
203 if (xenfb->c.xendev.be_state != XenbusStateConnected)
204 return 0;
205 if (!page)
206 return 0;
208 prod = page->in_prod;
209 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
210 errno = EAGAIN;
211 return -1;
214 xen_mb(); /* ensure ring space available */
215 XENKBD_IN_RING_REF(page, prod) = *event;
216 xen_wmb(); /* ensure ring contents visible */
217 page->in_prod = prod + 1;
218 return xen_be_send_notify(&xenfb->c.xendev);
221 /* Send a keyboard (or mouse button) event */
222 static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
224 union xenkbd_in_event event;
226 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
227 event.type = XENKBD_TYPE_KEY;
228 event.key.pressed = down ? 1 : 0;
229 event.key.keycode = keycode;
231 return xenfb_kbd_event(xenfb, &event);
234 /* Send a relative mouse movement event */
235 static int xenfb_send_motion(struct XenInput *xenfb,
236 int rel_x, int rel_y, int rel_z)
238 union xenkbd_in_event event;
240 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
241 event.type = XENKBD_TYPE_MOTION;
242 event.motion.rel_x = rel_x;
243 event.motion.rel_y = rel_y;
244 event.motion.rel_z = rel_z;
246 return xenfb_kbd_event(xenfb, &event);
249 /* Send an absolute mouse movement event */
250 static int xenfb_send_position(struct XenInput *xenfb,
251 int abs_x, int abs_y, int z)
253 union xenkbd_in_event event;
255 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
256 event.type = XENKBD_TYPE_POS;
257 event.pos.abs_x = abs_x;
258 event.pos.abs_y = abs_y;
259 event.pos.rel_z = z;
261 return xenfb_kbd_event(xenfb, &event);
265 * Send a key event from the client to the guest OS
266 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
267 * We have to turn this into a Linux Input layer keycode.
269 * Extra complexity from the fact that with extended scancodes
270 * (like those produced by arrow keys) this method gets called
271 * twice, but we only want to send a single event. So we have to
272 * track the '0xe0' scancode state & collapse the extended keys
273 * as needed.
275 * Wish we could just send scancodes straight to the guest which
276 * already has code for dealing with this...
278 static void xenfb_key_event(void *opaque, int scancode)
280 struct XenInput *xenfb = opaque;
281 int down = 1;
283 if (scancode == 0xe0) {
284 xenfb->extended = 1;
285 return;
286 } else if (scancode & 0x80) {
287 scancode &= 0x7f;
288 down = 0;
290 if (xenfb->extended) {
291 scancode |= 0x80;
292 xenfb->extended = 0;
294 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
298 * Send a mouse event from the client to the guest OS
300 * The QEMU mouse can be in either relative, or absolute mode.
301 * Movement is sent separately from button state, which has to
302 * be encoded as virtual key events. We also don't actually get
303 * given any button up/down events, so have to track changes in
304 * the button state.
306 static void xenfb_mouse_event(void *opaque,
307 int dx, int dy, int dz, int button_state)
309 struct XenInput *xenfb = opaque;
310 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
311 int dw = surface_width(surface);
312 int dh = surface_height(surface);
313 int i;
315 trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
316 xenfb->abs_pointer_wanted);
317 if (xenfb->abs_pointer_wanted)
318 xenfb_send_position(xenfb,
319 dx * (dw - 1) / 0x7fff,
320 dy * (dh - 1) / 0x7fff,
321 dz);
322 else
323 xenfb_send_motion(xenfb, dx, dy, dz);
325 for (i = 0 ; i < 8 ; i++) {
326 int lastDown = xenfb->button_state & (1 << i);
327 int down = button_state & (1 << i);
328 if (down == lastDown)
329 continue;
331 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
332 return;
334 xenfb->button_state = button_state;
337 static int input_init(struct XenDevice *xendev)
339 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
340 return 0;
343 static int input_initialise(struct XenDevice *xendev)
345 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
346 int rc;
348 if (!in->c.con) {
349 xen_be_printf(xendev, 1, "ds not set (yet)\n");
350 return -1;
353 rc = common_bind(&in->c);
354 if (rc != 0)
355 return rc;
357 qemu_add_kbd_event_handler(xenfb_key_event, in);
358 return 0;
361 static void input_connected(struct XenDevice *xendev)
363 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
365 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
366 &in->abs_pointer_wanted) == -1) {
367 in->abs_pointer_wanted = 0;
370 if (in->qmouse) {
371 qemu_remove_mouse_event_handler(in->qmouse);
373 trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
374 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
375 in->abs_pointer_wanted,
376 "Xen PVFB Mouse");
379 static void input_disconnect(struct XenDevice *xendev)
381 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
383 if (in->qmouse) {
384 qemu_remove_mouse_event_handler(in->qmouse);
385 in->qmouse = NULL;
387 qemu_add_kbd_event_handler(NULL, NULL);
388 common_unbind(&in->c);
391 static void input_event(struct XenDevice *xendev)
393 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
394 struct xenkbd_page *page = xenfb->c.page;
396 /* We don't understand any keyboard events, so just ignore them. */
397 if (page->out_prod == page->out_cons)
398 return;
399 page->out_cons = page->out_prod;
400 xen_be_send_notify(&xenfb->c.xendev);
403 /* -------------------------------------------------------------------- */
405 static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
407 uint32_t *src32 = src;
408 uint64_t *src64 = src;
409 int i;
411 for (i = 0; i < count; i++)
412 dst[i] = (mode == 32) ? src32[i] : src64[i];
415 static int xenfb_map_fb(struct XenFB *xenfb)
417 struct xenfb_page *page = xenfb->c.page;
418 char *protocol = xenfb->c.xendev.protocol;
419 int n_fbdirs;
420 xen_pfn_t *pgmfns = NULL;
421 xen_pfn_t *fbmfns = NULL;
422 void *map, *pd;
423 int mode, ret = -1;
425 /* default to native */
426 pd = page->pd;
427 mode = sizeof(unsigned long) * 8;
429 if (!protocol) {
431 * Undefined protocol, some guesswork needed.
433 * Old frontends which don't set the protocol use
434 * one page directory only, thus pd[1] must be zero.
435 * pd[1] of the 32bit struct layout and the lower
436 * 32 bits of pd[0] of the 64bit struct layout have
437 * the same location, so we can check that ...
439 uint32_t *ptr32 = NULL;
440 uint32_t *ptr64 = NULL;
441 #if defined(__i386__)
442 ptr32 = (void*)page->pd;
443 ptr64 = ((void*)page->pd) + 4;
444 #elif defined(__x86_64__)
445 ptr32 = ((void*)page->pd) - 4;
446 ptr64 = (void*)page->pd;
447 #endif
448 if (ptr32) {
449 if (ptr32[1] == 0) {
450 mode = 32;
451 pd = ptr32;
452 } else {
453 mode = 64;
454 pd = ptr64;
457 #if defined(__x86_64__)
458 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
459 /* 64bit dom0, 32bit domU */
460 mode = 32;
461 pd = ((void*)page->pd) - 4;
462 #elif defined(__i386__)
463 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
464 /* 32bit dom0, 64bit domU */
465 mode = 64;
466 pd = ((void*)page->pd) + 4;
467 #endif
470 if (xenfb->pixels) {
471 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
472 xenfb->pixels = NULL;
475 xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
476 n_fbdirs = xenfb->fbpages * mode / 8;
477 n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
479 pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
480 fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
482 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
483 map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
484 PROT_READ, n_fbdirs, pgmfns, NULL);
485 if (map == NULL)
486 goto out;
487 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
488 xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
490 xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
491 PROT_READ, xenfb->fbpages, fbmfns, NULL);
492 if (xenfb->pixels == NULL)
493 goto out;
495 ret = 0; /* all is fine */
497 out:
498 g_free(pgmfns);
499 g_free(fbmfns);
500 return ret;
503 static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
504 int width, int height, int depth,
505 size_t fb_len, int offset, int row_stride)
507 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
508 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
509 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
510 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
511 int max_width, max_height;
513 if (fb_len_lim > fb_len_max) {
514 xen_be_printf(&xenfb->c.xendev, 0,
515 "fb size limit %zu exceeds %zu, corrected\n",
516 fb_len_lim, fb_len_max);
517 fb_len_lim = fb_len_max;
519 if (fb_len_lim && fb_len > fb_len_lim) {
520 xen_be_printf(&xenfb->c.xendev, 0,
521 "frontend fb size %zu limited to %zu\n",
522 fb_len, fb_len_lim);
523 fb_len = fb_len_lim;
525 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
526 xen_be_printf(&xenfb->c.xendev, 0,
527 "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",
533 row_stride);
534 return -1;
536 max_width = row_stride / (depth / 8);
537 if (width < 0 || width > max_width) {
538 xen_be_printf(&xenfb->c.xendev, 0,
539 "invalid frontend width %d limited to %d\n",
540 width, max_width);
541 width = max_width;
543 if (offset < 0 || offset >= fb_len) {
544 xen_be_printf(&xenfb->c.xendev, 0,
545 "invalid frontend offset %d (max %zu)\n",
546 offset, fb_len - 1);
547 return -1;
549 max_height = (fb_len - offset) / row_stride;
550 if (height < 0 || height > max_height) {
551 xen_be_printf(&xenfb->c.xendev, 0,
552 "invalid frontend height %d limited to %d\n",
553 height, max_height);
554 height = max_height;
556 xenfb->fb_len = fb_len;
557 xenfb->row_stride = row_stride;
558 xenfb->depth = depth;
559 xenfb->width = width;
560 xenfb->height = height;
561 xenfb->offset = offset;
562 xenfb->up_fullscreen = 1;
563 xenfb->do_resize = 1;
564 xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
565 width, height, depth, offset, row_stride);
566 return 0;
569 /* A convenient function for munging pixels between different depths */
570 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
571 for (line = y ; line < (y+h) ; line++) { \
572 SRC_T *src = (SRC_T *)(xenfb->pixels \
573 + xenfb->offset \
574 + (line * xenfb->row_stride) \
575 + (x * xenfb->depth / 8)); \
576 DST_T *dst = (DST_T *)(data \
577 + (line * linesize) \
578 + (x * bpp / 8)); \
579 int col; \
580 const int RSS = 32 - (RSB + GSB + BSB); \
581 const int GSS = 32 - (GSB + BSB); \
582 const int BSS = 32 - (BSB); \
583 const uint32_t RSM = (~0U) << (32 - RSB); \
584 const uint32_t GSM = (~0U) << (32 - GSB); \
585 const uint32_t BSM = (~0U) << (32 - BSB); \
586 const int RDS = 32 - (RDB + GDB + BDB); \
587 const int GDS = 32 - (GDB + BDB); \
588 const int BDS = 32 - (BDB); \
589 const uint32_t RDM = (~0U) << (32 - RDB); \
590 const uint32_t GDM = (~0U) << (32 - GDB); \
591 const uint32_t BDM = (~0U) << (32 - BDB); \
592 for (col = x ; col < (x+w) ; col++) { \
593 uint32_t spix = *src; \
594 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
595 (((spix << GSS) & GSM & GDM) >> GDS) | \
596 (((spix << BSS) & BSM & BDM) >> BDS); \
597 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
598 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
604 * This copies data from the guest framebuffer region, into QEMU's
605 * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
606 * uses something else we must convert and copy, otherwise we can
607 * supply the buffer directly and no thing here.
609 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
611 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
612 int line, oops = 0;
613 int bpp = surface_bits_per_pixel(surface);
614 int linesize = surface_stride(surface);
615 uint8_t *data = surface_data(surface);
617 if (!is_buffer_shared(surface)) {
618 switch (xenfb->depth) {
619 case 8:
620 if (bpp == 16) {
621 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
622 } else if (bpp == 32) {
623 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
624 } else {
625 oops = 1;
627 break;
628 case 24:
629 if (bpp == 16) {
630 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
631 } else if (bpp == 32) {
632 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
633 } else {
634 oops = 1;
636 break;
637 default:
638 oops = 1;
641 if (oops) /* should not happen */
642 xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
643 __FUNCTION__, xenfb->depth, bpp);
645 dpy_gfx_update(xenfb->c.con, x, y, w, h);
648 #ifdef XENFB_TYPE_REFRESH_PERIOD
649 static int xenfb_queue_full(struct XenFB *xenfb)
651 struct xenfb_page *page = xenfb->c.page;
652 uint32_t cons, prod;
654 if (!page)
655 return 1;
657 prod = page->in_prod;
658 cons = page->in_cons;
659 return prod - cons == XENFB_IN_RING_LEN;
662 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
664 uint32_t prod;
665 struct xenfb_page *page = xenfb->c.page;
667 prod = page->in_prod;
668 /* caller ensures !xenfb_queue_full() */
669 xen_mb(); /* ensure ring space available */
670 XENFB_IN_RING_REF(page, prod) = *event;
671 xen_wmb(); /* ensure ring contents visible */
672 page->in_prod = prod + 1;
674 xen_be_send_notify(&xenfb->c.xendev);
677 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
679 union xenfb_in_event event;
681 memset(&event, 0, sizeof(event));
682 event.type = XENFB_TYPE_REFRESH_PERIOD;
683 event.refresh_period.period = period;
684 xenfb_send_event(xenfb, &event);
686 #endif
689 * Periodic update of display.
690 * Also transmit the refresh interval to the frontend.
692 * Never ever do any qemu display operations
693 * (resize, screen update) outside this function.
694 * Our screen might be inactive. When asked for
695 * an update we know it is active.
697 static void xenfb_update(void *opaque)
699 struct XenFB *xenfb = opaque;
700 DisplaySurface *surface;
701 int i;
703 if (xenfb->c.xendev.be_state != XenbusStateConnected)
704 return;
706 if (!xenfb->feature_update) {
707 /* we don't get update notifications, thus use the
708 * sledge hammer approach ... */
709 xenfb->up_fullscreen = 1;
712 /* resize if needed */
713 if (xenfb->do_resize) {
714 pixman_format_code_t format;
716 xenfb->do_resize = 0;
717 switch (xenfb->depth) {
718 case 16:
719 case 32:
720 /* console.c supported depth -> buffer can be used directly */
721 format = qemu_default_pixman_format(xenfb->depth, true);
722 surface = qemu_create_displaysurface_from
723 (xenfb->width, xenfb->height, format,
724 xenfb->row_stride, xenfb->pixels + xenfb->offset);
725 break;
726 default:
727 /* we must convert stuff */
728 surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
729 break;
731 dpy_gfx_replace_surface(xenfb->c.con, surface);
732 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
733 xenfb->width, xenfb->height, xenfb->depth,
734 is_buffer_shared(surface) ? " (shared)" : "");
735 xenfb->up_fullscreen = 1;
738 /* run queued updates */
739 if (xenfb->up_fullscreen) {
740 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
741 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
742 } else if (xenfb->up_count) {
743 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n",
744 xenfb->up_count);
745 for (i = 0; i < xenfb->up_count; i++)
746 xenfb_guest_copy(xenfb,
747 xenfb->up_rects[i].x,
748 xenfb->up_rects[i].y,
749 xenfb->up_rects[i].w,
750 xenfb->up_rects[i].h);
751 } else {
752 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
754 xenfb->up_count = 0;
755 xenfb->up_fullscreen = 0;
758 static void xenfb_update_interval(void *opaque, uint64_t interval)
760 struct XenFB *xenfb = opaque;
762 if (xenfb->feature_update) {
763 #ifdef XENFB_TYPE_REFRESH_PERIOD
764 if (xenfb_queue_full(xenfb)) {
765 return;
767 xenfb_send_refresh_period(xenfb, interval);
768 #endif
772 /* QEMU display state changed, so refresh the framebuffer copy */
773 static void xenfb_invalidate(void *opaque)
775 struct XenFB *xenfb = opaque;
776 xenfb->up_fullscreen = 1;
779 static void xenfb_handle_events(struct XenFB *xenfb)
781 uint32_t prod, cons, out_cons;
782 struct xenfb_page *page = xenfb->c.page;
784 prod = page->out_prod;
785 out_cons = page->out_cons;
786 if (prod - out_cons > XENFB_OUT_RING_LEN) {
787 return;
789 xen_rmb(); /* ensure we see ring contents up to prod */
790 for (cons = out_cons; cons != prod; cons++) {
791 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
792 uint8_t type = event->type;
793 int x, y, w, h;
795 switch (type) {
796 case XENFB_TYPE_UPDATE:
797 if (xenfb->up_count == UP_QUEUE)
798 xenfb->up_fullscreen = 1;
799 if (xenfb->up_fullscreen)
800 break;
801 x = MAX(event->update.x, 0);
802 y = MAX(event->update.y, 0);
803 w = MIN(event->update.width, xenfb->width - x);
804 h = MIN(event->update.height, xenfb->height - y);
805 if (w < 0 || h < 0) {
806 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
807 break;
809 if (x != event->update.x ||
810 y != event->update.y ||
811 w != event->update.width ||
812 h != event->update.height) {
813 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
815 if (w == xenfb->width && h > xenfb->height / 2) {
816 /* scroll detector: updated more than 50% of the lines,
817 * don't bother keeping track of the rectangles then */
818 xenfb->up_fullscreen = 1;
819 } else {
820 xenfb->up_rects[xenfb->up_count].x = x;
821 xenfb->up_rects[xenfb->up_count].y = y;
822 xenfb->up_rects[xenfb->up_count].w = w;
823 xenfb->up_rects[xenfb->up_count].h = h;
824 xenfb->up_count++;
826 break;
827 #ifdef XENFB_TYPE_RESIZE
828 case XENFB_TYPE_RESIZE:
829 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
830 event->resize.width,
831 event->resize.height,
832 event->resize.depth,
833 xenfb->fb_len,
834 event->resize.offset,
835 event->resize.stride) < 0)
836 break;
837 xenfb_invalidate(xenfb);
838 break;
839 #endif
842 xen_mb(); /* ensure we're done with ring contents */
843 page->out_cons = cons;
846 static int fb_init(struct XenDevice *xendev)
848 #ifdef XENFB_TYPE_RESIZE
849 xenstore_write_be_int(xendev, "feature-resize", 1);
850 #endif
851 return 0;
854 static int fb_initialise(struct XenDevice *xendev)
856 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
857 struct xenfb_page *fb_page;
858 int videoram;
859 int rc;
861 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
862 videoram = 0;
864 rc = common_bind(&fb->c);
865 if (rc != 0)
866 return rc;
868 fb_page = fb->c.page;
869 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
870 fb_page->width, fb_page->height, fb_page->depth,
871 fb_page->mem_length, 0, fb_page->line_length);
872 if (rc != 0)
873 return rc;
875 rc = xenfb_map_fb(fb);
876 if (rc != 0)
877 return rc;
879 #if 0 /* handled in xen_init_display() for now */
880 if (!fb->have_console) {
881 fb->c.ds = graphic_console_init(xenfb_update,
882 xenfb_invalidate,
883 NULL,
884 NULL,
885 fb);
886 fb->have_console = 1;
888 #endif
890 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
891 fb->feature_update = 0;
892 if (fb->feature_update)
893 xenstore_write_be_int(xendev, "request-update", 1);
895 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
896 fb->feature_update, videoram);
897 return 0;
900 static void fb_disconnect(struct XenDevice *xendev)
902 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
905 * FIXME: qemu can't un-init gfx display (yet?).
906 * Replacing the framebuffer with anonymous shared memory
907 * instead. This releases the guest pages and keeps qemu happy.
909 xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
910 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
911 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
912 -1, 0);
913 if (fb->pixels == MAP_FAILED) {
914 xen_be_printf(xendev, 0,
915 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
916 errno);
918 common_unbind(&fb->c);
919 fb->feature_update = 0;
920 fb->bug_trigger = 0;
923 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
925 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
928 * Set state to Connected *again* once the frontend switched
929 * to connected. We must trigger the watch a second time to
930 * workaround a frontend bug.
932 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
933 xendev->fe_state == XenbusStateConnected &&
934 xendev->be_state == XenbusStateConnected) {
935 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
936 xen_be_set_state(xendev, XenbusStateConnected);
937 fb->bug_trigger = 1; /* only once */
941 static void fb_event(struct XenDevice *xendev)
943 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
945 xenfb_handle_events(xenfb);
946 xen_be_send_notify(&xenfb->c.xendev);
949 /* -------------------------------------------------------------------- */
951 struct XenDevOps xen_kbdmouse_ops = {
952 .size = sizeof(struct XenInput),
953 .init = input_init,
954 .initialise = input_initialise,
955 .connected = input_connected,
956 .disconnect = input_disconnect,
957 .event = input_event,
960 struct XenDevOps xen_framebuffer_ops = {
961 .size = sizeof(struct XenFB),
962 .init = fb_init,
963 .initialise = fb_initialise,
964 .disconnect = fb_disconnect,
965 .event = fb_event,
966 .frontend_changed = fb_frontend_changed,
969 static const GraphicHwOps xenfb_ops = {
970 .invalidate = xenfb_invalidate,
971 .gfx_update = xenfb_update,
972 .update_interval = xenfb_update_interval,
976 * FIXME/TODO: Kill this.
977 * Temporary needed while DisplayState reorganization is in flight.
979 void xen_init_display(int domid)
981 struct XenDevice *xfb, *xin;
982 struct XenFB *fb;
983 struct XenInput *in;
984 int i = 0;
986 wait_more:
987 i++;
988 main_loop_wait(true);
989 xfb = xen_be_find_xendev("vfb", domid, 0);
990 xin = xen_be_find_xendev("vkbd", domid, 0);
991 if (!xfb || !xin) {
992 if (i < 256) {
993 usleep(10000);
994 goto wait_more;
996 xen_be_printf(NULL, 1, "displaystate setup failed\n");
997 return;
1000 /* vfb */
1001 fb = container_of(xfb, struct XenFB, c.xendev);
1002 fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
1003 fb->have_console = 1;
1005 /* vkbd */
1006 in = container_of(xin, struct XenInput, c.xendev);
1007 in->c.con = fb->c.con;
1009 /* retry ->init() */
1010 xen_be_check_state(xin);
1011 xen_be_check_state(xfb);