TCG/HPPA: use stack for TCG temps
[qemu/mdroth.git] / hw / xenfb.c
blob1db75fbe49d13536e7e5ab76a02f5103c83e5786
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 "console.h"
48 #include "qemu-char.h"
49 #include "xen_backend.h"
51 #ifndef BTN_LEFT
52 #define BTN_LEFT 0x110 /* from <linux/input.h> */
53 #endif
55 /* -------------------------------------------------------------------- */
57 struct common {
58 struct XenDevice xendev; /* must be first */
59 void *page;
60 DisplayState *ds;
63 struct XenInput {
64 struct common c;
65 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
66 int button_state; /* Last seen pointer button state */
67 int extended;
68 QEMUPutMouseEntry *qmouse;
71 #define UP_QUEUE 8
73 struct XenFB {
74 struct common c;
75 size_t fb_len;
76 int row_stride;
77 int depth;
78 int width;
79 int height;
80 int offset;
81 void *pixels;
82 int fbpages;
83 int feature_update;
84 int refresh_period;
85 int bug_trigger;
86 int have_console;
87 int do_resize;
89 struct {
90 int x,y,w,h;
91 } up_rects[UP_QUEUE];
92 int up_count;
93 int up_fullscreen;
96 /* -------------------------------------------------------------------- */
98 static int common_bind(struct common *c)
100 int mfn;
102 if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
103 return -1;
104 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
105 return -1;
107 c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
108 XC_PAGE_SIZE,
109 PROT_READ | PROT_WRITE, mfn);
110 if (c->page == NULL)
111 return -1;
113 xen_be_bind_evtchn(&c->xendev);
114 xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
115 mfn, c->xendev.remote_port, c->xendev.local_port);
117 return 0;
120 static void common_unbind(struct common *c)
122 xen_be_unbind_evtchn(&c->xendev);
123 if (c->page) {
124 munmap(c->page, XC_PAGE_SIZE);
125 c->page = NULL;
129 /* -------------------------------------------------------------------- */
131 #if 0
133 * These two tables are not needed any more, but left in here
134 * intentionally as documentation, to show how scancode2linux[]
135 * was generated.
137 * Tables to map from scancode to Linux input layer keycode.
138 * Scancodes are hardware-specific. These maps assumes a
139 * standard AT or PS/2 keyboard which is what QEMU feeds us.
141 const unsigned char atkbd_set2_keycode[512] = {
143 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
144 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
145 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
146 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
147 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
148 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
149 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
150 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
154 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
155 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
156 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
157 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
158 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
159 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
163 const unsigned char atkbd_unxlate_table[128] = {
165 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
166 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
167 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
168 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
169 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
170 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
171 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
172 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
175 #endif
178 * for (i = 0; i < 128; i++) {
179 * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
180 * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
183 static const unsigned char scancode2linux[512] = {
184 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
185 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
186 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
187 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
188 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
189 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
195 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
196 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
197 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
198 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
199 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
203 /* Send an event to the keyboard frontend driver */
204 static int xenfb_kbd_event(struct XenInput *xenfb,
205 union xenkbd_in_event *event)
207 struct xenkbd_page *page = xenfb->c.page;
208 uint32_t prod;
210 if (xenfb->c.xendev.be_state != XenbusStateConnected)
211 return 0;
212 if (!page)
213 return 0;
215 prod = page->in_prod;
216 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
217 errno = EAGAIN;
218 return -1;
221 xen_mb(); /* ensure ring space available */
222 XENKBD_IN_RING_REF(page, prod) = *event;
223 xen_wmb(); /* ensure ring contents visible */
224 page->in_prod = prod + 1;
225 return xen_be_send_notify(&xenfb->c.xendev);
228 /* Send a keyboard (or mouse button) event */
229 static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
231 union xenkbd_in_event event;
233 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
234 event.type = XENKBD_TYPE_KEY;
235 event.key.pressed = down ? 1 : 0;
236 event.key.keycode = keycode;
238 return xenfb_kbd_event(xenfb, &event);
241 /* Send a relative mouse movement event */
242 static int xenfb_send_motion(struct XenInput *xenfb,
243 int rel_x, int rel_y, int rel_z)
245 union xenkbd_in_event event;
247 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
248 event.type = XENKBD_TYPE_MOTION;
249 event.motion.rel_x = rel_x;
250 event.motion.rel_y = rel_y;
251 #if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
252 event.motion.rel_z = rel_z;
253 #endif
255 return xenfb_kbd_event(xenfb, &event);
258 /* Send an absolute mouse movement event */
259 static int xenfb_send_position(struct XenInput *xenfb,
260 int abs_x, int abs_y, int z)
262 union xenkbd_in_event event;
264 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
265 event.type = XENKBD_TYPE_POS;
266 event.pos.abs_x = abs_x;
267 event.pos.abs_y = abs_y;
268 #if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
269 event.pos.abs_z = z;
270 #endif
271 #if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
272 event.pos.rel_z = z;
273 #endif
275 return xenfb_kbd_event(xenfb, &event);
279 * Send a key event from the client to the guest OS
280 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
281 * We have to turn this into a Linux Input layer keycode.
283 * Extra complexity from the fact that with extended scancodes
284 * (like those produced by arrow keys) this method gets called
285 * twice, but we only want to send a single event. So we have to
286 * track the '0xe0' scancode state & collapse the extended keys
287 * as needed.
289 * Wish we could just send scancodes straight to the guest which
290 * already has code for dealing with this...
292 static void xenfb_key_event(void *opaque, int scancode)
294 struct XenInput *xenfb = opaque;
295 int down = 1;
297 if (scancode == 0xe0) {
298 xenfb->extended = 1;
299 return;
300 } else if (scancode & 0x80) {
301 scancode &= 0x7f;
302 down = 0;
304 if (xenfb->extended) {
305 scancode |= 0x80;
306 xenfb->extended = 0;
308 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
312 * Send a mouse event from the client to the guest OS
314 * The QEMU mouse can be in either relative, or absolute mode.
315 * Movement is sent separately from button state, which has to
316 * be encoded as virtual key events. We also don't actually get
317 * given any button up/down events, so have to track changes in
318 * the button state.
320 static void xenfb_mouse_event(void *opaque,
321 int dx, int dy, int dz, int button_state)
323 struct XenInput *xenfb = opaque;
324 int dw = ds_get_width(xenfb->c.ds);
325 int dh = ds_get_height(xenfb->c.ds);
326 int i;
328 if (xenfb->abs_pointer_wanted)
329 xenfb_send_position(xenfb,
330 dx * (dw - 1) / 0x7fff,
331 dy * (dh - 1) / 0x7fff,
332 dz);
333 else
334 xenfb_send_motion(xenfb, dx, dy, dz);
336 for (i = 0 ; i < 8 ; i++) {
337 int lastDown = xenfb->button_state & (1 << i);
338 int down = button_state & (1 << i);
339 if (down == lastDown)
340 continue;
342 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
343 return;
345 xenfb->button_state = button_state;
348 static int input_init(struct XenDevice *xendev)
350 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
352 if (!in->c.ds) {
353 xen_be_printf(xendev, 1, "ds not set (yet)\n");
354 return -1;
357 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
358 return 0;
361 static int input_connect(struct XenDevice *xendev)
363 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
364 int rc;
366 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
367 &in->abs_pointer_wanted) == -1)
368 in->abs_pointer_wanted = 0;
370 rc = common_bind(&in->c);
371 if (rc != 0)
372 return rc;
374 qemu_add_kbd_event_handler(xenfb_key_event, in);
375 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
376 in->abs_pointer_wanted,
377 "Xen PVFB Mouse");
378 return 0;
381 static void input_disconnect(struct XenDevice *xendev)
383 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
385 if (in->qmouse) {
386 qemu_remove_mouse_event_handler(in->qmouse);
387 in->qmouse = NULL;
389 qemu_add_kbd_event_handler(NULL, NULL);
390 common_unbind(&in->c);
393 static void input_event(struct XenDevice *xendev)
395 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
396 struct xenkbd_page *page = xenfb->c.page;
398 /* We don't understand any keyboard events, so just ignore them. */
399 if (page->out_prod == page->out_cons)
400 return;
401 page->out_cons = page->out_prod;
402 xen_be_send_notify(&xenfb->c.xendev);
405 /* -------------------------------------------------------------------- */
407 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
409 uint32_t *src32 = src;
410 uint64_t *src64 = src;
411 int i;
413 for (i = 0; i < count; i++)
414 dst[i] = (mode == 32) ? src32[i] : src64[i];
417 static int xenfb_map_fb(struct XenFB *xenfb)
419 struct xenfb_page *page = xenfb->c.page;
420 char *protocol = xenfb->c.xendev.protocol;
421 int n_fbdirs;
422 unsigned long *pgmfns = NULL;
423 unsigned long *fbmfns = NULL;
424 void *map, *pd;
425 int mode, ret = -1;
427 /* default to native */
428 pd = page->pd;
429 mode = sizeof(unsigned long) * 8;
431 if (!protocol) {
433 * Undefined protocol, some guesswork needed.
435 * Old frontends which don't set the protocol use
436 * one page directory only, thus pd[1] must be zero.
437 * pd[1] of the 32bit struct layout and the lower
438 * 32 bits of pd[0] of the 64bit struct layout have
439 * the same location, so we can check that ...
441 uint32_t *ptr32 = NULL;
442 uint32_t *ptr64 = NULL;
443 #if defined(__i386__)
444 ptr32 = (void*)page->pd;
445 ptr64 = ((void*)page->pd) + 4;
446 #elif defined(__x86_64__)
447 ptr32 = ((void*)page->pd) - 4;
448 ptr64 = (void*)page->pd;
449 #endif
450 if (ptr32) {
451 if (ptr32[1] == 0) {
452 mode = 32;
453 pd = ptr32;
454 } else {
455 mode = 64;
456 pd = ptr64;
459 #if defined(__x86_64__)
460 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
461 /* 64bit dom0, 32bit domU */
462 mode = 32;
463 pd = ((void*)page->pd) - 4;
464 #elif defined(__i386__)
465 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
466 /* 32bit dom0, 64bit domU */
467 mode = 64;
468 pd = ((void*)page->pd) + 4;
469 #endif
472 if (xenfb->pixels) {
473 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
474 xenfb->pixels = NULL;
477 xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
478 n_fbdirs = xenfb->fbpages * mode / 8;
479 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
481 pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
482 fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
484 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
485 map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
486 PROT_READ, pgmfns, n_fbdirs);
487 if (map == NULL)
488 goto out;
489 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
490 munmap(map, n_fbdirs * XC_PAGE_SIZE);
492 xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
493 PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
494 if (xenfb->pixels == NULL)
495 goto out;
497 ret = 0; /* all is fine */
499 out:
500 qemu_free(pgmfns);
501 qemu_free(fbmfns);
502 return ret;
505 static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
506 int width, int height, int depth,
507 size_t fb_len, int offset, int row_stride)
509 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
510 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
511 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
512 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
513 int max_width, max_height;
515 if (fb_len_lim > fb_len_max) {
516 xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
517 fb_len_lim, fb_len_max);
518 fb_len_lim = fb_len_max;
520 if (fb_len_lim && fb_len > fb_len_lim) {
521 xen_be_printf(&xenfb->c.xendev, 0, "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, "can't handle frontend fb depth %d\n",
527 depth);
528 return -1;
530 if (row_stride <= 0 || row_stride > fb_len) {
531 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
532 return -1;
534 max_width = row_stride / (depth / 8);
535 if (width < 0 || width > max_width) {
536 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
537 width, max_width);
538 width = max_width;
540 if (offset < 0 || offset >= fb_len) {
541 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
542 offset, fb_len - 1);
543 return -1;
545 max_height = (fb_len - offset) / row_stride;
546 if (height < 0 || height > max_height) {
547 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
548 height, max_height);
549 height = max_height;
551 xenfb->fb_len = fb_len;
552 xenfb->row_stride = row_stride;
553 xenfb->depth = depth;
554 xenfb->width = width;
555 xenfb->height = height;
556 xenfb->offset = offset;
557 xenfb->up_fullscreen = 1;
558 xenfb->do_resize = 1;
559 xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
560 width, height, depth, offset, row_stride);
561 return 0;
564 /* A convenient function for munging pixels between different depths */
565 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
566 for (line = y ; line < (y+h) ; line++) { \
567 SRC_T *src = (SRC_T *)(xenfb->pixels \
568 + xenfb->offset \
569 + (line * xenfb->row_stride) \
570 + (x * xenfb->depth / 8)); \
571 DST_T *dst = (DST_T *)(data \
572 + (line * linesize) \
573 + (x * bpp / 8)); \
574 int col; \
575 const int RSS = 32 - (RSB + GSB + BSB); \
576 const int GSS = 32 - (GSB + BSB); \
577 const int BSS = 32 - (BSB); \
578 const uint32_t RSM = (~0U) << (32 - RSB); \
579 const uint32_t GSM = (~0U) << (32 - GSB); \
580 const uint32_t BSM = (~0U) << (32 - BSB); \
581 const int RDS = 32 - (RDB + GDB + BDB); \
582 const int GDS = 32 - (GDB + BDB); \
583 const int BDS = 32 - (BDB); \
584 const uint32_t RDM = (~0U) << (32 - RDB); \
585 const uint32_t GDM = (~0U) << (32 - GDB); \
586 const uint32_t BDM = (~0U) << (32 - BDB); \
587 for (col = x ; col < (x+w) ; col++) { \
588 uint32_t spix = *src; \
589 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
590 (((spix << GSS) & GSM & GDM) >> GDS) | \
591 (((spix << BSS) & BSM & BDM) >> BDS); \
592 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
593 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
599 * This copies data from the guest framebuffer region, into QEMU's
600 * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
601 * uses something else we must convert and copy, otherwise we can
602 * supply the buffer directly and no thing here.
604 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
606 int line, oops = 0;
607 int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
608 int linesize = ds_get_linesize(xenfb->c.ds);
609 uint8_t *data = ds_get_data(xenfb->c.ds);
611 if (!is_buffer_shared(xenfb->c.ds->surface)) {
612 switch (xenfb->depth) {
613 case 8:
614 if (bpp == 16) {
615 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
616 } else if (bpp == 32) {
617 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
618 } else {
619 oops = 1;
621 break;
622 case 24:
623 if (bpp == 16) {
624 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
625 } else if (bpp == 32) {
626 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
627 } else {
628 oops = 1;
630 break;
631 default:
632 oops = 1;
635 if (oops) /* should not happen */
636 xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
637 __FUNCTION__, xenfb->depth, bpp);
639 dpy_update(xenfb->c.ds, x, y, w, h);
642 #ifdef XENFB_TYPE_REFRESH_PERIOD
643 static int xenfb_queue_full(struct XenFB *xenfb)
645 struct xenfb_page *page = xenfb->c.page;
646 uint32_t cons, prod;
648 if (!page)
649 return 1;
651 prod = page->in_prod;
652 cons = page->in_cons;
653 return prod - cons == XENFB_IN_RING_LEN;
656 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
658 uint32_t prod;
659 struct xenfb_page *page = xenfb->c.page;
661 prod = page->in_prod;
662 /* caller ensures !xenfb_queue_full() */
663 xen_mb(); /* ensure ring space available */
664 XENFB_IN_RING_REF(page, prod) = *event;
665 xen_wmb(); /* ensure ring contents visible */
666 page->in_prod = prod + 1;
668 xen_be_send_notify(&xenfb->c.xendev);
671 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
673 union xenfb_in_event event;
675 memset(&event, 0, sizeof(event));
676 event.type = XENFB_TYPE_REFRESH_PERIOD;
677 event.refresh_period.period = period;
678 xenfb_send_event(xenfb, &event);
680 #endif
683 * Periodic update of display.
684 * Also transmit the refresh interval to the frontend.
686 * Never ever do any qemu display operations
687 * (resize, screen update) outside this function.
688 * Our screen might be inactive. When asked for
689 * an update we know it is active.
691 static void xenfb_update(void *opaque)
693 struct XenFB *xenfb = opaque;
694 int i;
696 if (xenfb->c.xendev.be_state != XenbusStateConnected)
697 return;
699 if (xenfb->feature_update) {
700 #ifdef XENFB_TYPE_REFRESH_PERIOD
701 struct DisplayChangeListener *l;
702 int period = 99999999;
703 int idle = 1;
705 if (xenfb_queue_full(xenfb))
706 return;
708 for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
709 if (l->idle)
710 continue;
711 idle = 0;
712 if (!l->gui_timer_interval) {
713 if (period > GUI_REFRESH_INTERVAL)
714 period = GUI_REFRESH_INTERVAL;
715 } else {
716 if (period > l->gui_timer_interval)
717 period = l->gui_timer_interval;
720 if (idle)
721 period = XENFB_NO_REFRESH;
723 if (xenfb->refresh_period != period) {
724 xenfb_send_refresh_period(xenfb, period);
725 xenfb->refresh_period = period;
726 xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
728 #else
729 ; /* nothing */
730 #endif
731 } else {
732 /* we don't get update notifications, thus use the
733 * sledge hammer approach ... */
734 xenfb->up_fullscreen = 1;
737 /* resize if needed */
738 if (xenfb->do_resize) {
739 xenfb->do_resize = 0;
740 switch (xenfb->depth) {
741 case 16:
742 case 32:
743 /* console.c supported depth -> buffer can be used directly */
744 qemu_free_displaysurface(xenfb->c.ds);
745 xenfb->c.ds->surface = qemu_create_displaysurface_from
746 (xenfb->width, xenfb->height, xenfb->depth,
747 xenfb->row_stride, xenfb->pixels + xenfb->offset);
748 break;
749 default:
750 /* we must convert stuff */
751 qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
752 break;
754 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
755 xenfb->width, xenfb->height, xenfb->depth,
756 is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
757 dpy_resize(xenfb->c.ds);
758 xenfb->up_fullscreen = 1;
761 /* run queued updates */
762 if (xenfb->up_fullscreen) {
763 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
764 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
765 } else if (xenfb->up_count) {
766 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
767 for (i = 0; i < xenfb->up_count; i++)
768 xenfb_guest_copy(xenfb,
769 xenfb->up_rects[i].x,
770 xenfb->up_rects[i].y,
771 xenfb->up_rects[i].w,
772 xenfb->up_rects[i].h);
773 } else {
774 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
776 xenfb->up_count = 0;
777 xenfb->up_fullscreen = 0;
780 /* QEMU display state changed, so refresh the framebuffer copy */
781 static void xenfb_invalidate(void *opaque)
783 struct XenFB *xenfb = opaque;
784 xenfb->up_fullscreen = 1;
787 static void xenfb_handle_events(struct XenFB *xenfb)
789 uint32_t prod, cons;
790 struct xenfb_page *page = xenfb->c.page;
792 prod = page->out_prod;
793 if (prod == page->out_cons)
794 return;
795 xen_rmb(); /* ensure we see ring contents up to prod */
796 for (cons = page->out_cons; cons != prod; cons++) {
797 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
798 int x, y, w, h;
800 switch (event->type) {
801 case XENFB_TYPE_UPDATE:
802 if (xenfb->up_count == UP_QUEUE)
803 xenfb->up_fullscreen = 1;
804 if (xenfb->up_fullscreen)
805 break;
806 x = MAX(event->update.x, 0);
807 y = MAX(event->update.y, 0);
808 w = MIN(event->update.width, xenfb->width - x);
809 h = MIN(event->update.height, xenfb->height - y);
810 if (w < 0 || h < 0) {
811 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
812 break;
814 if (x != event->update.x ||
815 y != event->update.y ||
816 w != event->update.width ||
817 h != event->update.height) {
818 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
820 if (w == xenfb->width && h > xenfb->height / 2) {
821 /* scroll detector: updated more than 50% of the lines,
822 * don't bother keeping track of the rectangles then */
823 xenfb->up_fullscreen = 1;
824 } else {
825 xenfb->up_rects[xenfb->up_count].x = x;
826 xenfb->up_rects[xenfb->up_count].y = y;
827 xenfb->up_rects[xenfb->up_count].w = w;
828 xenfb->up_rects[xenfb->up_count].h = h;
829 xenfb->up_count++;
831 break;
832 #ifdef XENFB_TYPE_RESIZE
833 case XENFB_TYPE_RESIZE:
834 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
835 event->resize.width,
836 event->resize.height,
837 event->resize.depth,
838 xenfb->fb_len,
839 event->resize.offset,
840 event->resize.stride) < 0)
841 break;
842 xenfb_invalidate(xenfb);
843 break;
844 #endif
847 xen_mb(); /* ensure we're done with ring contents */
848 page->out_cons = cons;
851 static int fb_init(struct XenDevice *xendev)
853 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
855 fb->refresh_period = -1;
857 #ifdef XENFB_TYPE_RESIZE
858 xenstore_write_be_int(xendev, "feature-resize", 1);
859 #endif
860 return 0;
863 static int fb_connect(struct XenDevice *xendev)
865 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
866 struct xenfb_page *fb_page;
867 int videoram;
868 int rc;
870 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
871 videoram = 0;
873 rc = common_bind(&fb->c);
874 if (rc != 0)
875 return rc;
877 fb_page = fb->c.page;
878 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
879 fb_page->width, fb_page->height, fb_page->depth,
880 fb_page->mem_length, 0, fb_page->line_length);
881 if (rc != 0)
882 return rc;
884 rc = xenfb_map_fb(fb);
885 if (rc != 0)
886 return rc;
888 #if 0 /* handled in xen_init_display() for now */
889 if (!fb->have_console) {
890 fb->c.ds = graphic_console_init(xenfb_update,
891 xenfb_invalidate,
892 NULL,
893 NULL,
894 fb);
895 fb->have_console = 1;
897 #endif
899 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
900 fb->feature_update = 0;
901 if (fb->feature_update)
902 xenstore_write_be_int(xendev, "request-update", 1);
904 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
905 fb->feature_update, videoram);
906 return 0;
909 static void fb_disconnect(struct XenDevice *xendev)
911 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
914 * FIXME: qemu can't un-init gfx display (yet?).
915 * Replacing the framebuffer with anonymous shared memory
916 * instead. This releases the guest pages and keeps qemu happy.
918 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
919 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
920 -1, 0);
921 common_unbind(&fb->c);
922 fb->feature_update = 0;
923 fb->bug_trigger = 0;
926 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
928 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
931 * Set state to Connected *again* once the frontend switched
932 * to connected. We must trigger the watch a second time to
933 * workaround a frontend bug.
935 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
936 xendev->fe_state == XenbusStateConnected &&
937 xendev->be_state == XenbusStateConnected) {
938 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
939 xen_be_set_state(xendev, XenbusStateConnected);
940 fb->bug_trigger = 1; /* only once */
944 static void fb_event(struct XenDevice *xendev)
946 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
948 xenfb_handle_events(xenfb);
949 xen_be_send_notify(&xenfb->c.xendev);
952 /* -------------------------------------------------------------------- */
954 struct XenDevOps xen_kbdmouse_ops = {
955 .size = sizeof(struct XenInput),
956 .init = input_init,
957 .connect = input_connect,
958 .disconnect = input_disconnect,
959 .event = input_event,
962 struct XenDevOps xen_framebuffer_ops = {
963 .size = sizeof(struct XenFB),
964 .init = fb_init,
965 .connect = fb_connect,
966 .disconnect = fb_disconnect,
967 .event = fb_event,
968 .frontend_changed = fb_frontend_changed,
972 * FIXME/TODO: Kill this.
973 * Temporary needed while DisplayState reorganization is in flight.
975 void xen_init_display(int domid)
977 struct XenDevice *xfb, *xin;
978 struct XenFB *fb;
979 struct XenInput *in;
980 int i = 0;
982 wait_more:
983 i++;
984 main_loop_wait(true);
985 xfb = xen_be_find_xendev("vfb", domid, 0);
986 xin = xen_be_find_xendev("vkbd", domid, 0);
987 if (!xfb || !xin) {
988 if (i < 256) {
989 usleep(10000);
990 goto wait_more;
992 xen_be_printf(NULL, 1, "displaystate setup failed\n");
993 return;
996 /* vfb */
997 fb = container_of(xfb, struct XenFB, c.xendev);
998 fb->c.ds = graphic_console_init(xenfb_update,
999 xenfb_invalidate,
1000 NULL,
1001 NULL,
1002 fb);
1003 fb->have_console = 1;
1005 /* vkbd */
1006 in = container_of(xin, struct XenInput, c.xendev);
1007 in->c.ds = fb->c.ds;
1009 /* retry ->init() */
1010 xen_be_check_state(xin);
1011 xen_be_check_state(xfb);