2 * xen paravirt framebuffer backend
4 * Copyright IBM, Corp. 2005-2006
5 * Copyright Red Hat, Inc. 2006-2008
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"
28 #include "qemu/units.h"
32 #include "ui/console.h"
33 #include "hw/xen/xen-legacy-backend.h"
35 #include <xen/event_channel.h>
36 #include <xen/io/fbif.h>
37 #include <xen/io/kbdif.h>
38 #include <xen/io/protocols.h>
43 #define BTN_LEFT 0x110 /* from <linux/input.h> */
46 /* -------------------------------------------------------------------- */
49 struct XenLegacyDevice xendev
; /* must be first */
55 int abs_pointer_wanted
; /* Whether guest supports absolute pointer */
56 int raw_pointer_wanted
; /* Whether guest supports raw (unscaled) pointer */
57 QemuInputHandlerState
*qkbd
;
58 QemuInputHandlerState
*qmou
;
59 int axis
[INPUT_AXIS__MAX
];
86 static const GraphicHwOps xenfb_ops
;
88 /* -------------------------------------------------------------------- */
90 static int common_bind(struct common
*c
)
95 if (xenstore_read_fe_uint64(&c
->xendev
, "page-ref", &val
) == -1)
100 if (xenstore_read_fe_int(&c
->xendev
, "event-channel", &c
->xendev
.remote_port
) == -1)
103 c
->page
= xenforeignmemory_map(xen_fmem
, c
->xendev
.dom
,
104 PROT_READ
| PROT_WRITE
, 1, &mfn
, NULL
);
108 xen_be_bind_evtchn(&c
->xendev
);
109 xen_pv_printf(&c
->xendev
, 1,
110 "ring mfn %"PRI_xen_pfn
", remote-port %d, local-port %d\n",
111 mfn
, c
->xendev
.remote_port
, c
->xendev
.local_port
);
116 static void common_unbind(struct common
*c
)
118 xen_pv_unbind_evtchn(&c
->xendev
);
120 xenforeignmemory_unmap(xen_fmem
, c
->page
, 1);
125 /* -------------------------------------------------------------------- */
126 /* Send an event to the keyboard frontend driver */
127 static int xenfb_kbd_event(struct XenInput
*xenfb
,
128 union xenkbd_in_event
*event
)
130 struct xenkbd_page
*page
= xenfb
->c
.page
;
133 if (xenfb
->c
.xendev
.be_state
!= XenbusStateConnected
)
138 prod
= page
->in_prod
;
139 if (prod
- page
->in_cons
== XENKBD_IN_RING_LEN
) {
144 xen_mb(); /* ensure ring space available */
145 XENKBD_IN_RING_REF(page
, prod
) = *event
;
146 xen_wmb(); /* ensure ring contents visible */
147 page
->in_prod
= prod
+ 1;
148 return xen_pv_send_notify(&xenfb
->c
.xendev
);
151 /* Send a keyboard (or mouse button) event */
152 static int xenfb_send_key(struct XenInput
*xenfb
, bool down
, int keycode
)
154 union xenkbd_in_event event
;
156 memset(&event
, 0, XENKBD_IN_EVENT_SIZE
);
157 event
.type
= XENKBD_TYPE_KEY
;
158 event
.key
.pressed
= down
? 1 : 0;
159 event
.key
.keycode
= keycode
;
161 return xenfb_kbd_event(xenfb
, &event
);
164 /* Send a relative mouse movement event */
165 static int xenfb_send_motion(struct XenInput
*xenfb
,
166 int rel_x
, int rel_y
, int rel_z
)
168 union xenkbd_in_event event
;
170 memset(&event
, 0, XENKBD_IN_EVENT_SIZE
);
171 event
.type
= XENKBD_TYPE_MOTION
;
172 event
.motion
.rel_x
= rel_x
;
173 event
.motion
.rel_y
= rel_y
;
174 event
.motion
.rel_z
= rel_z
;
176 return xenfb_kbd_event(xenfb
, &event
);
179 /* Send an absolute mouse movement event */
180 static int xenfb_send_position(struct XenInput
*xenfb
,
181 int abs_x
, int abs_y
, int z
)
183 union xenkbd_in_event event
;
185 memset(&event
, 0, XENKBD_IN_EVENT_SIZE
);
186 event
.type
= XENKBD_TYPE_POS
;
187 event
.pos
.abs_x
= abs_x
;
188 event
.pos
.abs_y
= abs_y
;
191 return xenfb_kbd_event(xenfb
, &event
);
195 * Send a key event from the client to the guest OS
196 * QEMU gives us a QCode.
197 * We have to turn this into a Linux Input layer keycode.
199 * Wish we could just send scancodes straight to the guest which
200 * already has code for dealing with this...
202 static void xenfb_key_event(DeviceState
*dev
, QemuConsole
*src
,
205 struct XenInput
*xenfb
= (struct XenInput
*)dev
;
206 InputKeyEvent
*key
= evt
->u
.key
.data
;
207 int qcode
= qemu_input_key_value_to_qcode(key
->key
);
210 if (qcode
< qemu_input_map_qcode_to_linux_len
) {
211 lnx
= qemu_input_map_qcode_to_linux
[qcode
];
214 trace_xenfb_key_event(xenfb
, lnx
, key
->down
);
215 xenfb_send_key(xenfb
, key
->down
, lnx
);
221 * Send a mouse event from the client to the guest OS
223 * The QEMU mouse can be in either relative, or absolute mode.
224 * Movement is sent separately from button state, which has to
225 * be encoded as virtual key events. We also don't actually get
226 * given any button up/down events, so have to track changes in
229 static void xenfb_mouse_event(DeviceState
*dev
, QemuConsole
*src
,
232 struct XenInput
*xenfb
= (struct XenInput
*)dev
;
234 InputMoveEvent
*move
;
236 DisplaySurface
*surface
;
240 case INPUT_EVENT_KIND_BTN
:
241 btn
= evt
->u
.btn
.data
;
242 switch (btn
->button
) {
243 case INPUT_BUTTON_LEFT
:
244 xenfb_send_key(xenfb
, btn
->down
, BTN_LEFT
);
246 case INPUT_BUTTON_RIGHT
:
247 xenfb_send_key(xenfb
, btn
->down
, BTN_LEFT
+ 1);
249 case INPUT_BUTTON_MIDDLE
:
250 xenfb_send_key(xenfb
, btn
->down
, BTN_LEFT
+ 2);
252 case INPUT_BUTTON_WHEEL_UP
:
257 case INPUT_BUTTON_WHEEL_DOWN
:
267 case INPUT_EVENT_KIND_ABS
:
268 move
= evt
->u
.abs
.data
;
269 if (xenfb
->raw_pointer_wanted
) {
270 xenfb
->axis
[move
->axis
] = move
->value
;
272 con
= qemu_console_lookup_by_index(0);
274 xen_pv_printf(&xenfb
->c
.xendev
, 0, "No QEMU console available");
277 surface
= qemu_console_surface(con
);
278 switch (move
->axis
) {
280 scale
= surface_width(surface
) - 1;
283 scale
= surface_height(surface
) - 1;
289 xenfb
->axis
[move
->axis
] = move
->value
* scale
/ 0x7fff;
293 case INPUT_EVENT_KIND_REL
:
294 move
= evt
->u
.rel
.data
;
295 xenfb
->axis
[move
->axis
] += move
->value
;
303 static void xenfb_mouse_sync(DeviceState
*dev
)
305 struct XenInput
*xenfb
= (struct XenInput
*)dev
;
307 trace_xenfb_mouse_event(xenfb
, xenfb
->axis
[INPUT_AXIS_X
],
308 xenfb
->axis
[INPUT_AXIS_Y
],
310 xenfb
->abs_pointer_wanted
);
311 if (xenfb
->abs_pointer_wanted
) {
312 xenfb_send_position(xenfb
, xenfb
->axis
[INPUT_AXIS_X
],
313 xenfb
->axis
[INPUT_AXIS_Y
],
316 xenfb_send_motion(xenfb
, xenfb
->axis
[INPUT_AXIS_X
],
317 xenfb
->axis
[INPUT_AXIS_Y
],
319 xenfb
->axis
[INPUT_AXIS_X
] = 0;
320 xenfb
->axis
[INPUT_AXIS_Y
] = 0;
325 static QemuInputHandler xenfb_keyboard
= {
326 .name
= "Xen PV Keyboard",
327 .mask
= INPUT_EVENT_MASK_KEY
,
328 .event
= xenfb_key_event
,
331 static QemuInputHandler xenfb_abs_mouse
= {
332 .name
= "Xen PV Mouse",
333 .mask
= INPUT_EVENT_MASK_BTN
| INPUT_EVENT_MASK_ABS
,
334 .event
= xenfb_mouse_event
,
335 .sync
= xenfb_mouse_sync
,
338 static QemuInputHandler xenfb_rel_mouse
= {
339 .name
= "Xen PV Mouse",
340 .mask
= INPUT_EVENT_MASK_BTN
| INPUT_EVENT_MASK_REL
,
341 .event
= xenfb_mouse_event
,
342 .sync
= xenfb_mouse_sync
,
345 static int input_init(struct XenLegacyDevice
*xendev
)
347 xenstore_write_be_int(xendev
, "feature-abs-pointer", 1);
348 xenstore_write_be_int(xendev
, "feature-raw-pointer", 1);
352 static int input_initialise(struct XenLegacyDevice
*xendev
)
354 struct XenInput
*in
= container_of(xendev
, struct XenInput
, c
.xendev
);
357 rc
= common_bind(&in
->c
);
364 static void input_connected(struct XenLegacyDevice
*xendev
)
366 struct XenInput
*in
= container_of(xendev
, struct XenInput
, c
.xendev
);
368 if (xenstore_read_fe_int(xendev
, "request-abs-pointer",
369 &in
->abs_pointer_wanted
) == -1) {
370 in
->abs_pointer_wanted
= 0;
372 if (xenstore_read_fe_int(xendev
, "request-raw-pointer",
373 &in
->raw_pointer_wanted
) == -1) {
374 in
->raw_pointer_wanted
= 0;
376 if (in
->raw_pointer_wanted
&& in
->abs_pointer_wanted
== 0) {
377 xen_pv_printf(xendev
, 0, "raw pointer set without abs pointer");
381 qemu_input_handler_unregister(in
->qkbd
);
384 qemu_input_handler_unregister(in
->qmou
);
386 trace_xenfb_input_connected(xendev
, in
->abs_pointer_wanted
);
388 in
->qkbd
= qemu_input_handler_register((DeviceState
*)in
, &xenfb_keyboard
);
389 in
->qmou
= qemu_input_handler_register((DeviceState
*)in
,
390 in
->abs_pointer_wanted
? &xenfb_abs_mouse
: &xenfb_rel_mouse
);
392 if (in
->raw_pointer_wanted
) {
393 qemu_input_handler_activate(in
->qkbd
);
394 qemu_input_handler_activate(in
->qmou
);
398 static void input_disconnect(struct XenLegacyDevice
*xendev
)
400 struct XenInput
*in
= container_of(xendev
, struct XenInput
, c
.xendev
);
403 qemu_input_handler_unregister(in
->qkbd
);
407 qemu_input_handler_unregister(in
->qmou
);
410 common_unbind(&in
->c
);
413 static void input_event(struct XenLegacyDevice
*xendev
)
415 struct XenInput
*xenfb
= container_of(xendev
, struct XenInput
, c
.xendev
);
416 struct xenkbd_page
*page
= xenfb
->c
.page
;
418 /* We don't understand any keyboard events, so just ignore them. */
419 if (page
->out_prod
== page
->out_cons
)
421 page
->out_cons
= page
->out_prod
;
422 xen_pv_send_notify(&xenfb
->c
.xendev
);
425 /* -------------------------------------------------------------------- */
427 static void xenfb_copy_mfns(int mode
, int count
, xen_pfn_t
*dst
, void *src
)
429 uint32_t *src32
= src
;
430 uint64_t *src64
= src
;
433 for (i
= 0; i
< count
; i
++)
434 dst
[i
] = (mode
== 32) ? src32
[i
] : src64
[i
];
437 static int xenfb_map_fb(struct XenFB
*xenfb
)
439 struct xenfb_page
*page
= xenfb
->c
.page
;
440 char *protocol
= xenfb
->c
.xendev
.protocol
;
442 xen_pfn_t
*pgmfns
= NULL
;
443 xen_pfn_t
*fbmfns
= NULL
;
447 /* default to native */
449 mode
= sizeof(unsigned long) * 8;
453 * Undefined protocol, some guesswork needed.
455 * Old frontends which don't set the protocol use
456 * one page directory only, thus pd[1] must be zero.
457 * pd[1] of the 32bit struct layout and the lower
458 * 32 bits of pd[0] of the 64bit struct layout have
459 * the same location, so we can check that ...
461 uint32_t *ptr32
= NULL
;
462 uint32_t *ptr64
= NULL
;
463 #if defined(__i386__)
464 ptr32
= (void*)page
->pd
;
465 ptr64
= ((void*)page
->pd
) + 4;
466 #elif defined(__x86_64__)
467 ptr32
= ((void*)page
->pd
) - 4;
468 ptr64
= (void*)page
->pd
;
479 #if defined(__x86_64__)
480 } else if (strcmp(protocol
, XEN_IO_PROTO_ABI_X86_32
) == 0) {
481 /* 64bit dom0, 32bit domU */
483 pd
= ((void*)page
->pd
) - 4;
484 #elif defined(__i386__)
485 } else if (strcmp(protocol
, XEN_IO_PROTO_ABI_X86_64
) == 0) {
486 /* 32bit dom0, 64bit domU */
488 pd
= ((void*)page
->pd
) + 4;
493 munmap(xenfb
->pixels
, xenfb
->fbpages
* XC_PAGE_SIZE
);
494 xenfb
->pixels
= NULL
;
497 xenfb
->fbpages
= DIV_ROUND_UP(xenfb
->fb_len
, XC_PAGE_SIZE
);
498 n_fbdirs
= xenfb
->fbpages
* mode
/ 8;
499 n_fbdirs
= DIV_ROUND_UP(n_fbdirs
, XC_PAGE_SIZE
);
501 pgmfns
= g_malloc0(sizeof(xen_pfn_t
) * n_fbdirs
);
502 fbmfns
= g_malloc0(sizeof(xen_pfn_t
) * xenfb
->fbpages
);
504 xenfb_copy_mfns(mode
, n_fbdirs
, pgmfns
, pd
);
505 map
= xenforeignmemory_map(xen_fmem
, xenfb
->c
.xendev
.dom
,
506 PROT_READ
, n_fbdirs
, pgmfns
, NULL
);
509 xenfb_copy_mfns(mode
, xenfb
->fbpages
, fbmfns
, map
);
510 xenforeignmemory_unmap(xen_fmem
, map
, n_fbdirs
);
512 xenfb
->pixels
= xenforeignmemory_map(xen_fmem
, xenfb
->c
.xendev
.dom
,
513 PROT_READ
, xenfb
->fbpages
, fbmfns
, NULL
);
514 if (xenfb
->pixels
== NULL
)
517 ret
= 0; /* all is fine */
525 static int xenfb_configure_fb(struct XenFB
*xenfb
, size_t fb_len_lim
,
526 int width
, int height
, int depth
,
527 size_t fb_len
, int offset
, int row_stride
)
529 size_t mfn_sz
= sizeof_field(struct xenfb_page
, pd
[0]);
530 size_t pd_len
= sizeof_field(struct xenfb_page
, pd
) / mfn_sz
;
531 size_t fb_pages
= pd_len
* XC_PAGE_SIZE
/ mfn_sz
;
532 size_t fb_len_max
= fb_pages
* XC_PAGE_SIZE
;
533 int max_width
, max_height
;
535 if (fb_len_lim
> fb_len_max
) {
536 xen_pv_printf(&xenfb
->c
.xendev
, 0,
537 "fb size limit %zu exceeds %zu, corrected\n",
538 fb_len_lim
, fb_len_max
);
539 fb_len_lim
= fb_len_max
;
541 if (fb_len_lim
&& fb_len
> fb_len_lim
) {
542 xen_pv_printf(&xenfb
->c
.xendev
, 0,
543 "frontend fb size %zu limited to %zu\n",
547 if (depth
!= 8 && depth
!= 16 && depth
!= 24 && depth
!= 32) {
548 xen_pv_printf(&xenfb
->c
.xendev
, 0,
549 "can't handle frontend fb depth %d\n",
553 if (row_stride
<= 0 || row_stride
> fb_len
) {
554 xen_pv_printf(&xenfb
->c
.xendev
, 0, "invalid frontend stride %d\n",
558 max_width
= row_stride
/ (depth
/ 8);
559 if (width
< 0 || width
> max_width
) {
560 xen_pv_printf(&xenfb
->c
.xendev
, 0,
561 "invalid frontend width %d limited to %d\n",
565 if (offset
< 0 || offset
>= fb_len
) {
566 xen_pv_printf(&xenfb
->c
.xendev
, 0,
567 "invalid frontend offset %d (max %zu)\n",
571 max_height
= (fb_len
- offset
) / row_stride
;
572 if (height
< 0 || height
> max_height
) {
573 xen_pv_printf(&xenfb
->c
.xendev
, 0,
574 "invalid frontend height %d limited to %d\n",
578 xenfb
->fb_len
= fb_len
;
579 xenfb
->row_stride
= row_stride
;
580 xenfb
->depth
= depth
;
581 xenfb
->width
= width
;
582 xenfb
->height
= height
;
583 xenfb
->offset
= offset
;
584 xenfb
->up_fullscreen
= 1;
585 xenfb
->do_resize
= 1;
586 xen_pv_printf(&xenfb
->c
.xendev
, 1,
587 "framebuffer %dx%dx%d offset %d stride %d\n",
588 width
, height
, depth
, offset
, row_stride
);
592 /* A convenient function for munging pixels between different depths */
593 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
594 for (line = y ; line < (y+h) ; line++) { \
595 SRC_T *src = (SRC_T *)(xenfb->pixels \
597 + (line * xenfb->row_stride) \
598 + (x * xenfb->depth / 8)); \
599 DST_T *dst = (DST_T *)(data \
600 + (line * linesize) \
603 const int RSS = 32 - (RSB + GSB + BSB); \
604 const int GSS = 32 - (GSB + BSB); \
605 const int BSS = 32 - (BSB); \
606 const uint32_t RSM = (~0U) << (32 - RSB); \
607 const uint32_t GSM = (~0U) << (32 - GSB); \
608 const uint32_t BSM = (~0U) << (32 - BSB); \
609 const int RDS = 32 - (RDB + GDB + BDB); \
610 const int GDS = 32 - (GDB + BDB); \
611 const int BDS = 32 - (BDB); \
612 const uint32_t RDM = (~0U) << (32 - RDB); \
613 const uint32_t GDM = (~0U) << (32 - GDB); \
614 const uint32_t BDM = (~0U) << (32 - BDB); \
615 for (col = x ; col < (x+w) ; col++) { \
616 uint32_t spix = *src; \
617 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
618 (((spix << GSS) & GSM & GDM) >> GDS) | \
619 (((spix << BSS) & BSM & BDM) >> BDS); \
620 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
621 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
627 * This copies data from the guest framebuffer region, into QEMU's
628 * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
629 * uses something else we must convert and copy, otherwise we can
630 * supply the buffer directly and no thing here.
632 static void xenfb_guest_copy(struct XenFB
*xenfb
, int x
, int y
, int w
, int h
)
634 DisplaySurface
*surface
= qemu_console_surface(xenfb
->con
);
636 int bpp
= surface_bits_per_pixel(surface
);
637 int linesize
= surface_stride(surface
);
638 uint8_t *data
= surface_data(surface
);
640 if (!is_buffer_shared(surface
)) {
641 switch (xenfb
->depth
) {
644 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
645 } else if (bpp
== 32) {
646 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
653 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
654 } else if (bpp
== 32) {
655 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
664 if (oops
) /* should not happen */
665 xen_pv_printf(&xenfb
->c
.xendev
, 0, "%s: oops: convert %d -> %d bpp?\n",
666 __func__
, xenfb
->depth
, bpp
);
668 dpy_gfx_update(xenfb
->con
, x
, y
, w
, h
);
671 #ifdef XENFB_TYPE_REFRESH_PERIOD
672 static int xenfb_queue_full(struct XenFB
*xenfb
)
674 struct xenfb_page
*page
= xenfb
->c
.page
;
680 prod
= page
->in_prod
;
681 cons
= page
->in_cons
;
682 return prod
- cons
== XENFB_IN_RING_LEN
;
685 static void xenfb_send_event(struct XenFB
*xenfb
, union xenfb_in_event
*event
)
688 struct xenfb_page
*page
= xenfb
->c
.page
;
690 prod
= page
->in_prod
;
691 /* caller ensures !xenfb_queue_full() */
692 xen_mb(); /* ensure ring space available */
693 XENFB_IN_RING_REF(page
, prod
) = *event
;
694 xen_wmb(); /* ensure ring contents visible */
695 page
->in_prod
= prod
+ 1;
697 xen_pv_send_notify(&xenfb
->c
.xendev
);
700 static void xenfb_send_refresh_period(struct XenFB
*xenfb
, int period
)
702 union xenfb_in_event event
;
704 memset(&event
, 0, sizeof(event
));
705 event
.type
= XENFB_TYPE_REFRESH_PERIOD
;
706 event
.refresh_period
.period
= period
;
707 xenfb_send_event(xenfb
, &event
);
712 * Periodic update of display.
713 * Also transmit the refresh interval to the frontend.
715 * Never ever do any qemu display operations
716 * (resize, screen update) outside this function.
717 * Our screen might be inactive. When asked for
718 * an update we know it is active.
720 static void xenfb_update(void *opaque
)
722 struct XenFB
*xenfb
= opaque
;
723 DisplaySurface
*surface
;
726 if (xenfb
->c
.xendev
.be_state
!= XenbusStateConnected
)
729 if (!xenfb
->feature_update
) {
730 /* we don't get update notifications, thus use the
731 * sledge hammer approach ... */
732 xenfb
->up_fullscreen
= 1;
735 /* resize if needed */
736 if (xenfb
->do_resize
) {
737 pixman_format_code_t format
;
739 xenfb
->do_resize
= 0;
740 switch (xenfb
->depth
) {
743 /* console.c supported depth -> buffer can be used directly */
744 format
= qemu_default_pixman_format(xenfb
->depth
, true);
745 surface
= qemu_create_displaysurface_from
746 (xenfb
->width
, xenfb
->height
, format
,
747 xenfb
->row_stride
, xenfb
->pixels
+ xenfb
->offset
);
750 /* we must convert stuff */
751 surface
= qemu_create_displaysurface(xenfb
->width
, xenfb
->height
);
754 dpy_gfx_replace_surface(xenfb
->con
, surface
);
755 xen_pv_printf(&xenfb
->c
.xendev
, 1,
756 "update: resizing: %dx%d @ %d bpp%s\n",
757 xenfb
->width
, xenfb
->height
, xenfb
->depth
,
758 is_buffer_shared(surface
) ? " (shared)" : "");
759 xenfb
->up_fullscreen
= 1;
762 /* run queued updates */
763 if (xenfb
->up_fullscreen
) {
764 xen_pv_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_pv_printf(&xenfb
->c
.xendev
, 3, "update: %d rects\n",
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
);
776 xen_pv_printf(&xenfb
->c
.xendev
, 3, "update: nothing\n");
779 xenfb
->up_fullscreen
= 0;
782 static void xenfb_update_interval(void *opaque
, uint64_t interval
)
784 struct XenFB
*xenfb
= opaque
;
786 if (xenfb
->feature_update
) {
787 #ifdef XENFB_TYPE_REFRESH_PERIOD
788 if (xenfb_queue_full(xenfb
)) {
791 xenfb_send_refresh_period(xenfb
, interval
);
796 /* QEMU display state changed, so refresh the framebuffer copy */
797 static void xenfb_invalidate(void *opaque
)
799 struct XenFB
*xenfb
= opaque
;
800 xenfb
->up_fullscreen
= 1;
803 static void xenfb_handle_events(struct XenFB
*xenfb
)
805 uint32_t prod
, cons
, out_cons
;
806 struct xenfb_page
*page
= xenfb
->c
.page
;
808 prod
= page
->out_prod
;
809 out_cons
= page
->out_cons
;
810 if (prod
- out_cons
> XENFB_OUT_RING_LEN
) {
813 xen_rmb(); /* ensure we see ring contents up to prod */
814 for (cons
= out_cons
; cons
!= prod
; cons
++) {
815 union xenfb_out_event
*event
= &XENFB_OUT_RING_REF(page
, cons
);
816 uint8_t type
= event
->type
;
820 case XENFB_TYPE_UPDATE
:
821 if (xenfb
->up_count
== UP_QUEUE
)
822 xenfb
->up_fullscreen
= 1;
823 if (xenfb
->up_fullscreen
)
825 x
= MAX(event
->update
.x
, 0);
826 y
= MAX(event
->update
.y
, 0);
827 w
= MIN(event
->update
.width
, xenfb
->width
- x
);
828 h
= MIN(event
->update
.height
, xenfb
->height
- y
);
829 if (w
< 0 || h
< 0) {
830 xen_pv_printf(&xenfb
->c
.xendev
, 1, "bogus update ignored\n");
833 if (x
!= event
->update
.x
||
834 y
!= event
->update
.y
||
835 w
!= event
->update
.width
||
836 h
!= event
->update
.height
) {
837 xen_pv_printf(&xenfb
->c
.xendev
, 1, "bogus update clipped\n");
839 if (w
== xenfb
->width
&& h
> xenfb
->height
/ 2) {
840 /* scroll detector: updated more than 50% of the lines,
841 * don't bother keeping track of the rectangles then */
842 xenfb
->up_fullscreen
= 1;
844 xenfb
->up_rects
[xenfb
->up_count
].x
= x
;
845 xenfb
->up_rects
[xenfb
->up_count
].y
= y
;
846 xenfb
->up_rects
[xenfb
->up_count
].w
= w
;
847 xenfb
->up_rects
[xenfb
->up_count
].h
= h
;
851 #ifdef XENFB_TYPE_RESIZE
852 case XENFB_TYPE_RESIZE
:
853 if (xenfb_configure_fb(xenfb
, xenfb
->fb_len
,
855 event
->resize
.height
,
858 event
->resize
.offset
,
859 event
->resize
.stride
) < 0)
861 xenfb_invalidate(xenfb
);
866 xen_mb(); /* ensure we're done with ring contents */
867 page
->out_cons
= cons
;
870 static int fb_init(struct XenLegacyDevice
*xendev
)
872 #ifdef XENFB_TYPE_RESIZE
873 xenstore_write_be_int(xendev
, "feature-resize", 1);
878 static int fb_initialise(struct XenLegacyDevice
*xendev
)
880 struct XenFB
*fb
= container_of(xendev
, struct XenFB
, c
.xendev
);
881 struct xenfb_page
*fb_page
;
885 if (xenstore_read_fe_int(xendev
, "videoram", &videoram
) == -1)
888 rc
= common_bind(&fb
->c
);
892 fb_page
= fb
->c
.page
;
893 rc
= xenfb_configure_fb(fb
, videoram
* MiB
,
894 fb_page
->width
, fb_page
->height
, fb_page
->depth
,
895 fb_page
->mem_length
, 0, fb_page
->line_length
);
899 rc
= xenfb_map_fb(fb
);
903 fb
->con
= graphic_console_init(NULL
, 0, &xenfb_ops
, fb
);
905 if (xenstore_read_fe_int(xendev
, "feature-update", &fb
->feature_update
) == -1)
906 fb
->feature_update
= 0;
907 if (fb
->feature_update
)
908 xenstore_write_be_int(xendev
, "request-update", 1);
910 xen_pv_printf(xendev
, 1, "feature-update=%d, videoram=%d\n",
911 fb
->feature_update
, videoram
);
915 static void fb_disconnect(struct XenLegacyDevice
*xendev
)
917 struct XenFB
*fb
= container_of(xendev
, struct XenFB
, c
.xendev
);
920 * FIXME: qemu can't un-init gfx display (yet?).
921 * Replacing the framebuffer with anonymous shared memory
922 * instead. This releases the guest pages and keeps qemu happy.
924 xenforeignmemory_unmap(xen_fmem
, fb
->pixels
, fb
->fbpages
);
925 fb
->pixels
= mmap(fb
->pixels
, fb
->fbpages
* XC_PAGE_SIZE
,
926 PROT_READ
| PROT_WRITE
, MAP_SHARED
| MAP_ANON
,
928 if (fb
->pixels
== MAP_FAILED
) {
929 xen_pv_printf(xendev
, 0,
930 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
933 common_unbind(&fb
->c
);
934 fb
->feature_update
= 0;
938 static void fb_frontend_changed(struct XenLegacyDevice
*xendev
,
941 struct XenFB
*fb
= container_of(xendev
, struct XenFB
, c
.xendev
);
944 * Set state to Connected *again* once the frontend switched
945 * to connected. We must trigger the watch a second time to
946 * workaround a frontend bug.
948 if (fb
->bug_trigger
== 0 && strcmp(node
, "state") == 0 &&
949 xendev
->fe_state
== XenbusStateConnected
&&
950 xendev
->be_state
== XenbusStateConnected
) {
951 xen_pv_printf(xendev
, 2, "re-trigger connected (frontend bug)\n");
952 xen_be_set_state(xendev
, XenbusStateConnected
);
953 fb
->bug_trigger
= 1; /* only once */
957 static void fb_event(struct XenLegacyDevice
*xendev
)
959 struct XenFB
*xenfb
= container_of(xendev
, struct XenFB
, c
.xendev
);
961 xenfb_handle_events(xenfb
);
962 xen_pv_send_notify(&xenfb
->c
.xendev
);
965 /* -------------------------------------------------------------------- */
967 struct XenDevOps xen_kbdmouse_ops
= {
968 .size
= sizeof(struct XenInput
),
970 .initialise
= input_initialise
,
971 .connected
= input_connected
,
972 .disconnect
= input_disconnect
,
973 .event
= input_event
,
976 struct XenDevOps xen_framebuffer_ops
= {
977 .size
= sizeof(struct XenFB
),
979 .initialise
= fb_initialise
,
980 .disconnect
= fb_disconnect
,
982 .frontend_changed
= fb_frontend_changed
,
985 static const GraphicHwOps xenfb_ops
= {
986 .invalidate
= xenfb_invalidate
,
987 .gfx_update
= xenfb_update
,
988 .update_interval
= xenfb_update_interval
,