target-alpha: Fix compiler warning for gcc-4.3 (and older)
[qemu/kevin.git] / hw / xenfb.c
blob795a32626010f43ac860d49f7b3e53dfa022edbb
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 <stdbool.h>
33 #include <sys/mman.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <time.h>
39 #include <xs.h>
40 #include <xenctrl.h>
41 #include <xen/event_channel.h>
42 #include <xen/io/xenbus.h>
43 #include <xen/io/fbif.h>
44 #include <xen/io/kbdif.h>
45 #include <xen/io/protocols.h>
47 #include "hw.h"
48 #include "sysemu.h"
49 #include "console.h"
50 #include "qemu-char.h"
51 #include "xen_backend.h"
53 #ifndef BTN_LEFT
54 #define BTN_LEFT 0x110 /* from <linux/input.h> */
55 #endif
57 /* -------------------------------------------------------------------- */
59 struct common {
60 struct XenDevice xendev; /* must be first */
61 void *page;
62 DisplayState *ds;
65 struct XenInput {
66 struct common c;
67 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
68 int button_state; /* Last seen pointer button state */
69 int extended;
70 QEMUPutMouseEntry *qmouse;
73 #define UP_QUEUE 8
75 struct XenFB {
76 struct common c;
77 size_t fb_len;
78 int row_stride;
79 int depth;
80 int width;
81 int height;
82 int offset;
83 void *pixels;
84 int fbpages;
85 int feature_update;
86 int refresh_period;
87 int bug_trigger;
88 int have_console;
89 int do_resize;
91 struct {
92 int x,y,w,h;
93 } up_rects[UP_QUEUE];
94 int up_count;
95 int up_fullscreen;
98 /* -------------------------------------------------------------------- */
100 static int common_bind(struct common *c)
102 int mfn;
104 if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
105 return -1;
106 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
107 return -1;
109 c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
110 XC_PAGE_SIZE,
111 PROT_READ | PROT_WRITE, mfn);
112 if (c->page == NULL)
113 return -1;
115 xen_be_bind_evtchn(&c->xendev);
116 xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
117 mfn, c->xendev.remote_port, c->xendev.local_port);
119 return 0;
122 static void common_unbind(struct common *c)
124 xen_be_unbind_evtchn(&c->xendev);
125 if (c->page) {
126 munmap(c->page, XC_PAGE_SIZE);
127 c->page = NULL;
131 /* -------------------------------------------------------------------- */
133 #if 0
135 * These two tables are not needed any more, but left in here
136 * intentionally as documentation, to show how scancode2linux[]
137 * was generated.
139 * Tables to map from scancode to Linux input layer keycode.
140 * Scancodes are hardware-specific. These maps assumes a
141 * standard AT or PS/2 keyboard which is what QEMU feeds us.
143 const unsigned char atkbd_set2_keycode[512] = {
145 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
146 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
147 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
148 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
149 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
150 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
151 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
152 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
156 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
157 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
158 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
159 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
160 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
161 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
165 const unsigned char atkbd_unxlate_table[128] = {
167 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
168 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
169 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
170 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
171 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
172 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
173 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
174 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
177 #endif
180 * for (i = 0; i < 128; i++) {
181 * scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
182 * scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
185 static const unsigned char scancode2linux[512] = {
186 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
187 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
188 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
189 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
190 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
191 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
195 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
197 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
198 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
199 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
200 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
201 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
202 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
205 /* Send an event to the keyboard frontend driver */
206 static int xenfb_kbd_event(struct XenInput *xenfb,
207 union xenkbd_in_event *event)
209 struct xenkbd_page *page = xenfb->c.page;
210 uint32_t prod;
212 if (xenfb->c.xendev.be_state != XenbusStateConnected)
213 return 0;
214 if (!page)
215 return 0;
217 prod = page->in_prod;
218 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
219 errno = EAGAIN;
220 return -1;
223 xen_mb(); /* ensure ring space available */
224 XENKBD_IN_RING_REF(page, prod) = *event;
225 xen_wmb(); /* ensure ring contents visible */
226 page->in_prod = prod + 1;
227 return xen_be_send_notify(&xenfb->c.xendev);
230 /* Send a keyboard (or mouse button) event */
231 static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
233 union xenkbd_in_event event;
235 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
236 event.type = XENKBD_TYPE_KEY;
237 event.key.pressed = down ? 1 : 0;
238 event.key.keycode = keycode;
240 return xenfb_kbd_event(xenfb, &event);
243 /* Send a relative mouse movement event */
244 static int xenfb_send_motion(struct XenInput *xenfb,
245 int rel_x, int rel_y, int rel_z)
247 union xenkbd_in_event event;
249 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
250 event.type = XENKBD_TYPE_MOTION;
251 event.motion.rel_x = rel_x;
252 event.motion.rel_y = rel_y;
253 #if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
254 event.motion.rel_z = rel_z;
255 #endif
257 return xenfb_kbd_event(xenfb, &event);
260 /* Send an absolute mouse movement event */
261 static int xenfb_send_position(struct XenInput *xenfb,
262 int abs_x, int abs_y, int z)
264 union xenkbd_in_event event;
266 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
267 event.type = XENKBD_TYPE_POS;
268 event.pos.abs_x = abs_x;
269 event.pos.abs_y = abs_y;
270 #if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
271 event.pos.abs_z = z;
272 #endif
273 #if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
274 event.pos.rel_z = z;
275 #endif
277 return xenfb_kbd_event(xenfb, &event);
281 * Send a key event from the client to the guest OS
282 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
283 * We have to turn this into a Linux Input layer keycode.
285 * Extra complexity from the fact that with extended scancodes
286 * (like those produced by arrow keys) this method gets called
287 * twice, but we only want to send a single event. So we have to
288 * track the '0xe0' scancode state & collapse the extended keys
289 * as needed.
291 * Wish we could just send scancodes straight to the guest which
292 * already has code for dealing with this...
294 static void xenfb_key_event(void *opaque, int scancode)
296 struct XenInput *xenfb = opaque;
297 int down = 1;
299 if (scancode == 0xe0) {
300 xenfb->extended = 1;
301 return;
302 } else if (scancode & 0x80) {
303 scancode &= 0x7f;
304 down = 0;
306 if (xenfb->extended) {
307 scancode |= 0x80;
308 xenfb->extended = 0;
310 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
314 * Send a mouse event from the client to the guest OS
316 * The QEMU mouse can be in either relative, or absolute mode.
317 * Movement is sent separately from button state, which has to
318 * be encoded as virtual key events. We also don't actually get
319 * given any button up/down events, so have to track changes in
320 * the button state.
322 static void xenfb_mouse_event(void *opaque,
323 int dx, int dy, int dz, int button_state)
325 struct XenInput *xenfb = opaque;
326 int dw = ds_get_width(xenfb->c.ds);
327 int dh = ds_get_height(xenfb->c.ds);
328 int i;
330 if (xenfb->abs_pointer_wanted)
331 xenfb_send_position(xenfb,
332 dx * (dw - 1) / 0x7fff,
333 dy * (dh - 1) / 0x7fff,
334 dz);
335 else
336 xenfb_send_motion(xenfb, dx, dy, dz);
338 for (i = 0 ; i < 8 ; i++) {
339 int lastDown = xenfb->button_state & (1 << i);
340 int down = button_state & (1 << i);
341 if (down == lastDown)
342 continue;
344 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
345 return;
347 xenfb->button_state = button_state;
350 static int input_init(struct XenDevice *xendev)
352 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
354 if (!in->c.ds) {
355 xen_be_printf(xendev, 1, "ds not set (yet)\n");
356 return -1;
359 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
360 return 0;
363 static int input_connect(struct XenDevice *xendev)
365 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
366 int rc;
368 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
369 &in->abs_pointer_wanted) == -1)
370 in->abs_pointer_wanted = 0;
372 rc = common_bind(&in->c);
373 if (rc != 0)
374 return rc;
376 qemu_add_kbd_event_handler(xenfb_key_event, in);
377 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
378 in->abs_pointer_wanted,
379 "Xen PVFB Mouse");
380 return 0;
383 static void input_disconnect(struct XenDevice *xendev)
385 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
387 if (in->qmouse) {
388 qemu_remove_mouse_event_handler(in->qmouse);
389 in->qmouse = NULL;
391 qemu_add_kbd_event_handler(NULL, NULL);
392 common_unbind(&in->c);
395 static void input_event(struct XenDevice *xendev)
397 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
398 struct xenkbd_page *page = xenfb->c.page;
400 /* We don't understand any keyboard events, so just ignore them. */
401 if (page->out_prod == page->out_cons)
402 return;
403 page->out_cons = page->out_prod;
404 xen_be_send_notify(&xenfb->c.xendev);
407 /* -------------------------------------------------------------------- */
409 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
411 uint32_t *src32 = src;
412 uint64_t *src64 = src;
413 int i;
415 for (i = 0; i < count; i++)
416 dst[i] = (mode == 32) ? src32[i] : src64[i];
419 static int xenfb_map_fb(struct XenFB *xenfb)
421 struct xenfb_page *page = xenfb->c.page;
422 char *protocol = xenfb->c.xendev.protocol;
423 int n_fbdirs;
424 unsigned long *pgmfns = NULL;
425 unsigned long *fbmfns = NULL;
426 void *map, *pd;
427 int mode, ret = -1;
429 /* default to native */
430 pd = page->pd;
431 mode = sizeof(unsigned long) * 8;
433 if (!protocol) {
435 * Undefined protocol, some guesswork needed.
437 * Old frontends which don't set the protocol use
438 * one page directory only, thus pd[1] must be zero.
439 * pd[1] of the 32bit struct layout and the lower
440 * 32 bits of pd[0] of the 64bit struct layout have
441 * the same location, so we can check that ...
443 uint32_t *ptr32 = NULL;
444 uint32_t *ptr64 = NULL;
445 #if defined(__i386__)
446 ptr32 = (void*)page->pd;
447 ptr64 = ((void*)page->pd) + 4;
448 #elif defined(__x86_64__)
449 ptr32 = ((void*)page->pd) - 4;
450 ptr64 = (void*)page->pd;
451 #endif
452 if (ptr32) {
453 if (ptr32[1] == 0) {
454 mode = 32;
455 pd = ptr32;
456 } else {
457 mode = 64;
458 pd = ptr64;
461 #if defined(__x86_64__)
462 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
463 /* 64bit dom0, 32bit domU */
464 mode = 32;
465 pd = ((void*)page->pd) - 4;
466 #elif defined(__i386__)
467 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
468 /* 32bit dom0, 64bit domU */
469 mode = 64;
470 pd = ((void*)page->pd) + 4;
471 #endif
474 if (xenfb->pixels) {
475 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
476 xenfb->pixels = NULL;
479 xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
480 n_fbdirs = xenfb->fbpages * mode / 8;
481 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
483 pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
484 fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
486 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
487 map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
488 PROT_READ, pgmfns, n_fbdirs);
489 if (map == NULL)
490 goto out;
491 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
492 munmap(map, n_fbdirs * XC_PAGE_SIZE);
494 xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
495 PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
496 if (xenfb->pixels == NULL)
497 goto out;
499 ret = 0; /* all is fine */
501 out:
502 qemu_free(pgmfns);
503 qemu_free(fbmfns);
504 return ret;
507 static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
508 int width, int height, int depth,
509 size_t fb_len, int offset, int row_stride)
511 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
512 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
513 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
514 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
515 int max_width, max_height;
517 if (fb_len_lim > fb_len_max) {
518 xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
519 fb_len_lim, fb_len_max);
520 fb_len_lim = fb_len_max;
522 if (fb_len_lim && fb_len > fb_len_lim) {
523 xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
524 fb_len, fb_len_lim);
525 fb_len = fb_len_lim;
527 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
528 xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
529 depth);
530 return -1;
532 if (row_stride <= 0 || row_stride > fb_len) {
533 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", 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, "invalid frontend width %d limited to %d\n",
539 width, max_width);
540 width = max_width;
542 if (offset < 0 || offset >= fb_len) {
543 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
544 offset, fb_len - 1);
545 return -1;
547 max_height = (fb_len - offset) / row_stride;
548 if (height < 0 || height > max_height) {
549 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
550 height, max_height);
551 height = max_height;
553 xenfb->fb_len = fb_len;
554 xenfb->row_stride = row_stride;
555 xenfb->depth = depth;
556 xenfb->width = width;
557 xenfb->height = height;
558 xenfb->offset = offset;
559 xenfb->up_fullscreen = 1;
560 xenfb->do_resize = 1;
561 xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
562 width, height, depth, offset, row_stride);
563 return 0;
566 /* A convenient function for munging pixels between different depths */
567 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
568 for (line = y ; line < (y+h) ; line++) { \
569 SRC_T *src = (SRC_T *)(xenfb->pixels \
570 + xenfb->offset \
571 + (line * xenfb->row_stride) \
572 + (x * xenfb->depth / 8)); \
573 DST_T *dst = (DST_T *)(data \
574 + (line * linesize) \
575 + (x * bpp / 8)); \
576 int col; \
577 const int RSS = 32 - (RSB + GSB + BSB); \
578 const int GSS = 32 - (GSB + BSB); \
579 const int BSS = 32 - (BSB); \
580 const uint32_t RSM = (~0U) << (32 - RSB); \
581 const uint32_t GSM = (~0U) << (32 - GSB); \
582 const uint32_t BSM = (~0U) << (32 - BSB); \
583 const int RDS = 32 - (RDB + GDB + BDB); \
584 const int GDS = 32 - (GDB + BDB); \
585 const int BDS = 32 - (BDB); \
586 const uint32_t RDM = (~0U) << (32 - RDB); \
587 const uint32_t GDM = (~0U) << (32 - GDB); \
588 const uint32_t BDM = (~0U) << (32 - BDB); \
589 for (col = x ; col < (x+w) ; col++) { \
590 uint32_t spix = *src; \
591 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
592 (((spix << GSS) & GSM & GDM) >> GDS) | \
593 (((spix << BSS) & BSM & BDM) >> BDS); \
594 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
595 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
601 * This copies data from the guest framebuffer region, into QEMU's
602 * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
603 * uses something else we must convert and copy, otherwise we can
604 * supply the buffer directly and no thing here.
606 static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
608 int line, oops = 0;
609 int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
610 int linesize = ds_get_linesize(xenfb->c.ds);
611 uint8_t *data = ds_get_data(xenfb->c.ds);
613 if (!is_buffer_shared(xenfb->c.ds->surface)) {
614 switch (xenfb->depth) {
615 case 8:
616 if (bpp == 16) {
617 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
618 } else if (bpp == 32) {
619 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
620 } else {
621 oops = 1;
623 break;
624 case 24:
625 if (bpp == 16) {
626 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
627 } else if (bpp == 32) {
628 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
629 } else {
630 oops = 1;
632 break;
633 default:
634 oops = 1;
637 if (oops) /* should not happen */
638 xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
639 __FUNCTION__, xenfb->depth, bpp);
641 dpy_update(xenfb->c.ds, x, y, w, h);
644 #ifdef XENFB_TYPE_REFRESH_PERIOD
645 static int xenfb_queue_full(struct XenFB *xenfb)
647 struct xenfb_page *page = xenfb->c.page;
648 uint32_t cons, prod;
650 if (!page)
651 return 1;
653 prod = page->in_prod;
654 cons = page->in_cons;
655 return prod - cons == XENFB_IN_RING_LEN;
658 static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
660 uint32_t prod;
661 struct xenfb_page *page = xenfb->c.page;
663 prod = page->in_prod;
664 /* caller ensures !xenfb_queue_full() */
665 xen_mb(); /* ensure ring space available */
666 XENFB_IN_RING_REF(page, prod) = *event;
667 xen_wmb(); /* ensure ring contents visible */
668 page->in_prod = prod + 1;
670 xen_be_send_notify(&xenfb->c.xendev);
673 static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
675 union xenfb_in_event event;
677 memset(&event, 0, sizeof(event));
678 event.type = XENFB_TYPE_REFRESH_PERIOD;
679 event.refresh_period.period = period;
680 xenfb_send_event(xenfb, &event);
682 #endif
685 * Periodic update of display.
686 * Also transmit the refresh interval to the frontend.
688 * Never ever do any qemu display operations
689 * (resize, screen update) outside this function.
690 * Our screen might be inactive. When asked for
691 * an update we know it is active.
693 static void xenfb_update(void *opaque)
695 struct XenFB *xenfb = opaque;
696 int i;
698 if (xenfb->c.xendev.be_state != XenbusStateConnected)
699 return;
701 if (xenfb->feature_update) {
702 #ifdef XENFB_TYPE_REFRESH_PERIOD
703 struct DisplayChangeListener *l;
704 int period = 99999999;
705 int idle = 1;
707 if (xenfb_queue_full(xenfb))
708 return;
710 for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
711 if (l->idle)
712 continue;
713 idle = 0;
714 if (!l->gui_timer_interval) {
715 if (period > GUI_REFRESH_INTERVAL)
716 period = GUI_REFRESH_INTERVAL;
717 } else {
718 if (period > l->gui_timer_interval)
719 period = l->gui_timer_interval;
722 if (idle)
723 period = XENFB_NO_REFRESH;
725 if (xenfb->refresh_period != period) {
726 xenfb_send_refresh_period(xenfb, period);
727 xenfb->refresh_period = period;
728 xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
730 #else
731 ; /* nothing */
732 #endif
733 } else {
734 /* we don't get update notifications, thus use the
735 * sledge hammer approach ... */
736 xenfb->up_fullscreen = 1;
739 /* resize if needed */
740 if (xenfb->do_resize) {
741 xenfb->do_resize = 0;
742 switch (xenfb->depth) {
743 case 16:
744 case 32:
745 /* console.c supported depth -> buffer can be used directly */
746 qemu_free_displaysurface(xenfb->c.ds);
747 xenfb->c.ds->surface = qemu_create_displaysurface_from
748 (xenfb->width, xenfb->height, xenfb->depth,
749 xenfb->row_stride, xenfb->pixels + xenfb->offset);
750 break;
751 default:
752 /* we must convert stuff */
753 qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
754 break;
756 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
757 xenfb->width, xenfb->height, xenfb->depth,
758 is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
759 dpy_resize(xenfb->c.ds);
760 xenfb->up_fullscreen = 1;
763 /* run queued updates */
764 if (xenfb->up_fullscreen) {
765 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
766 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
767 } else if (xenfb->up_count) {
768 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
769 for (i = 0; i < xenfb->up_count; i++)
770 xenfb_guest_copy(xenfb,
771 xenfb->up_rects[i].x,
772 xenfb->up_rects[i].y,
773 xenfb->up_rects[i].w,
774 xenfb->up_rects[i].h);
775 } else {
776 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
778 xenfb->up_count = 0;
779 xenfb->up_fullscreen = 0;
782 /* QEMU display state changed, so refresh the framebuffer copy */
783 static void xenfb_invalidate(void *opaque)
785 struct XenFB *xenfb = opaque;
786 xenfb->up_fullscreen = 1;
789 static void xenfb_handle_events(struct XenFB *xenfb)
791 uint32_t prod, cons;
792 struct xenfb_page *page = xenfb->c.page;
794 prod = page->out_prod;
795 if (prod == page->out_cons)
796 return;
797 xen_rmb(); /* ensure we see ring contents up to prod */
798 for (cons = page->out_cons; cons != prod; cons++) {
799 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
800 int x, y, w, h;
802 switch (event->type) {
803 case XENFB_TYPE_UPDATE:
804 if (xenfb->up_count == UP_QUEUE)
805 xenfb->up_fullscreen = 1;
806 if (xenfb->up_fullscreen)
807 break;
808 x = MAX(event->update.x, 0);
809 y = MAX(event->update.y, 0);
810 w = MIN(event->update.width, xenfb->width - x);
811 h = MIN(event->update.height, xenfb->height - y);
812 if (w < 0 || h < 0) {
813 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
814 break;
816 if (x != event->update.x ||
817 y != event->update.y ||
818 w != event->update.width ||
819 h != event->update.height) {
820 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
822 if (w == xenfb->width && h > xenfb->height / 2) {
823 /* scroll detector: updated more than 50% of the lines,
824 * don't bother keeping track of the rectangles then */
825 xenfb->up_fullscreen = 1;
826 } else {
827 xenfb->up_rects[xenfb->up_count].x = x;
828 xenfb->up_rects[xenfb->up_count].y = y;
829 xenfb->up_rects[xenfb->up_count].w = w;
830 xenfb->up_rects[xenfb->up_count].h = h;
831 xenfb->up_count++;
833 break;
834 #ifdef XENFB_TYPE_RESIZE
835 case XENFB_TYPE_RESIZE:
836 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
837 event->resize.width,
838 event->resize.height,
839 event->resize.depth,
840 xenfb->fb_len,
841 event->resize.offset,
842 event->resize.stride) < 0)
843 break;
844 xenfb_invalidate(xenfb);
845 break;
846 #endif
849 xen_mb(); /* ensure we're done with ring contents */
850 page->out_cons = cons;
853 static int fb_init(struct XenDevice *xendev)
855 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
857 fb->refresh_period = -1;
859 #ifdef XENFB_TYPE_RESIZE
860 xenstore_write_be_int(xendev, "feature-resize", 1);
861 #endif
862 return 0;
865 static int fb_connect(struct XenDevice *xendev)
867 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
868 struct xenfb_page *fb_page;
869 int videoram;
870 int rc;
872 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
873 videoram = 0;
875 rc = common_bind(&fb->c);
876 if (rc != 0)
877 return rc;
879 fb_page = fb->c.page;
880 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
881 fb_page->width, fb_page->height, fb_page->depth,
882 fb_page->mem_length, 0, fb_page->line_length);
883 if (rc != 0)
884 return rc;
886 rc = xenfb_map_fb(fb);
887 if (rc != 0)
888 return rc;
890 #if 0 /* handled in xen_init_display() for now */
891 if (!fb->have_console) {
892 fb->c.ds = graphic_console_init(xenfb_update,
893 xenfb_invalidate,
894 NULL,
895 NULL,
896 fb);
897 fb->have_console = 1;
899 #endif
901 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
902 fb->feature_update = 0;
903 if (fb->feature_update)
904 xenstore_write_be_int(xendev, "request-update", 1);
906 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
907 fb->feature_update, videoram);
908 return 0;
911 static void fb_disconnect(struct XenDevice *xendev)
913 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
916 * FIXME: qemu can't un-init gfx display (yet?).
917 * Replacing the framebuffer with anonymous shared memory
918 * instead. This releases the guest pages and keeps qemu happy.
920 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
921 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
922 -1, 0);
923 common_unbind(&fb->c);
924 fb->feature_update = 0;
925 fb->bug_trigger = 0;
928 static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
930 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
933 * Set state to Connected *again* once the frontend switched
934 * to connected. We must trigger the watch a second time to
935 * workaround a frontend bug.
937 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
938 xendev->fe_state == XenbusStateConnected &&
939 xendev->be_state == XenbusStateConnected) {
940 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
941 xen_be_set_state(xendev, XenbusStateConnected);
942 fb->bug_trigger = 1; /* only once */
946 static void fb_event(struct XenDevice *xendev)
948 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
950 xenfb_handle_events(xenfb);
951 xen_be_send_notify(&xenfb->c.xendev);
954 /* -------------------------------------------------------------------- */
956 struct XenDevOps xen_kbdmouse_ops = {
957 .size = sizeof(struct XenInput),
958 .init = input_init,
959 .connect = input_connect,
960 .disconnect = input_disconnect,
961 .event = input_event,
964 struct XenDevOps xen_framebuffer_ops = {
965 .size = sizeof(struct XenFB),
966 .init = fb_init,
967 .connect = fb_connect,
968 .disconnect = fb_disconnect,
969 .event = fb_event,
970 .frontend_changed = fb_frontend_changed,
974 * FIXME/TODO: Kill this.
975 * Temporary needed while DisplayState reorganization is in flight.
977 void xen_init_display(int domid)
979 struct XenDevice *xfb, *xin;
980 struct XenFB *fb;
981 struct XenInput *in;
982 int i = 0;
984 wait_more:
985 i++;
986 main_loop_wait(10); /* miliseconds */
987 xfb = xen_be_find_xendev("vfb", domid, 0);
988 xin = xen_be_find_xendev("vkbd", domid, 0);
989 if (!xfb || !xin) {
990 if (i < 256)
991 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);