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/>.
29 #include <sys/types.h>
39 #include "ui/console.h"
40 #include "sysemu/char.h"
41 #include "hw/xen/xen_backend.h"
43 #include <xen/event_channel.h>
44 #include <xen/io/fbif.h>
45 #include <xen/io/kbdif.h>
46 #include <xen/io/protocols.h>
51 #define BTN_LEFT 0x110 /* from <linux/input.h> */
54 /* -------------------------------------------------------------------- */
57 struct XenDevice xendev
; /* must be first */
64 int abs_pointer_wanted
; /* Whether guest supports absolute pointer */
65 int button_state
; /* Last seen pointer button state */
67 QEMUPutMouseEntry
*qmouse
;
94 /* -------------------------------------------------------------------- */
96 static int common_bind(struct common
*c
)
100 if (xenstore_read_fe_uint64(&c
->xendev
, "page-ref", &mfn
) == -1)
102 assert(mfn
== (xen_pfn_t
)mfn
);
104 if (xenstore_read_fe_int(&c
->xendev
, "event-channel", &c
->xendev
.remote_port
) == -1)
107 c
->page
= xc_map_foreign_range(xen_xc
, c
->xendev
.dom
,
109 PROT_READ
| PROT_WRITE
, mfn
);
113 xen_be_bind_evtchn(&c
->xendev
);
114 xen_be_printf(&c
->xendev
, 1, "ring mfn %"PRIx64
", remote-port %d, local-port %d\n",
115 mfn
, c
->xendev
.remote_port
, c
->xendev
.local_port
);
120 static void common_unbind(struct common
*c
)
122 xen_be_unbind_evtchn(&c
->xendev
);
124 munmap(c
->page
, XC_PAGE_SIZE
);
129 /* -------------------------------------------------------------------- */
133 * These two tables are not needed any more, but left in here
134 * intentionally as documentation, to show how scancode2linux[]
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
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
;
210 if (xenfb
->c
.xendev
.be_state
!= XenbusStateConnected
)
215 prod
= page
->in_prod
;
216 if (prod
- page
->in_cons
== XENKBD_IN_RING_LEN
) {
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
;
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
271 #if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
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
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
;
297 if (scancode
== 0xe0) {
300 } else if (scancode
& 0x80) {
304 if (xenfb
->extended
) {
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
320 static void xenfb_mouse_event(void *opaque
,
321 int dx
, int dy
, int dz
, int button_state
)
323 struct XenInput
*xenfb
= opaque
;
324 DisplaySurface
*surface
= qemu_console_surface(xenfb
->c
.con
);
325 int dw
= surface_width(surface
);
326 int dh
= surface_height(surface
);
329 trace_xenfb_mouse_event(opaque
, dx
, dy
, dz
, button_state
,
330 xenfb
->abs_pointer_wanted
);
331 if (xenfb
->abs_pointer_wanted
)
332 xenfb_send_position(xenfb
,
333 dx
* (dw
- 1) / 0x7fff,
334 dy
* (dh
- 1) / 0x7fff,
337 xenfb_send_motion(xenfb
, dx
, dy
, dz
);
339 for (i
= 0 ; i
< 8 ; i
++) {
340 int lastDown
= xenfb
->button_state
& (1 << i
);
341 int down
= button_state
& (1 << i
);
342 if (down
== lastDown
)
345 if (xenfb_send_key(xenfb
, down
, BTN_LEFT
+i
) < 0)
348 xenfb
->button_state
= button_state
;
351 static int input_init(struct XenDevice
*xendev
)
353 xenstore_write_be_int(xendev
, "feature-abs-pointer", 1);
357 static int input_initialise(struct XenDevice
*xendev
)
359 struct XenInput
*in
= container_of(xendev
, struct XenInput
, c
.xendev
);
363 xen_be_printf(xendev
, 1, "ds not set (yet)\n");
367 rc
= common_bind(&in
->c
);
371 qemu_add_kbd_event_handler(xenfb_key_event
, in
);
375 static void input_connected(struct XenDevice
*xendev
)
377 struct XenInput
*in
= container_of(xendev
, struct XenInput
, c
.xendev
);
379 if (xenstore_read_fe_int(xendev
, "request-abs-pointer",
380 &in
->abs_pointer_wanted
) == -1) {
381 in
->abs_pointer_wanted
= 0;
385 qemu_remove_mouse_event_handler(in
->qmouse
);
387 trace_xenfb_input_connected(xendev
, in
->abs_pointer_wanted
);
388 in
->qmouse
= qemu_add_mouse_event_handler(xenfb_mouse_event
, in
,
389 in
->abs_pointer_wanted
,
393 static void input_disconnect(struct XenDevice
*xendev
)
395 struct XenInput
*in
= container_of(xendev
, struct XenInput
, c
.xendev
);
398 qemu_remove_mouse_event_handler(in
->qmouse
);
401 qemu_add_kbd_event_handler(NULL
, NULL
);
402 common_unbind(&in
->c
);
405 static void input_event(struct XenDevice
*xendev
)
407 struct XenInput
*xenfb
= container_of(xendev
, struct XenInput
, c
.xendev
);
408 struct xenkbd_page
*page
= xenfb
->c
.page
;
410 /* We don't understand any keyboard events, so just ignore them. */
411 if (page
->out_prod
== page
->out_cons
)
413 page
->out_cons
= page
->out_prod
;
414 xen_be_send_notify(&xenfb
->c
.xendev
);
417 /* -------------------------------------------------------------------- */
419 static void xenfb_copy_mfns(int mode
, int count
, xen_pfn_t
*dst
, void *src
)
421 uint32_t *src32
= src
;
422 uint64_t *src64
= src
;
425 for (i
= 0; i
< count
; i
++)
426 dst
[i
] = (mode
== 32) ? src32
[i
] : src64
[i
];
429 static int xenfb_map_fb(struct XenFB
*xenfb
)
431 struct xenfb_page
*page
= xenfb
->c
.page
;
432 char *protocol
= xenfb
->c
.xendev
.protocol
;
434 xen_pfn_t
*pgmfns
= NULL
;
435 xen_pfn_t
*fbmfns
= NULL
;
439 /* default to native */
441 mode
= sizeof(unsigned long) * 8;
445 * Undefined protocol, some guesswork needed.
447 * Old frontends which don't set the protocol use
448 * one page directory only, thus pd[1] must be zero.
449 * pd[1] of the 32bit struct layout and the lower
450 * 32 bits of pd[0] of the 64bit struct layout have
451 * the same location, so we can check that ...
453 uint32_t *ptr32
= NULL
;
454 uint32_t *ptr64
= NULL
;
455 #if defined(__i386__)
456 ptr32
= (void*)page
->pd
;
457 ptr64
= ((void*)page
->pd
) + 4;
458 #elif defined(__x86_64__)
459 ptr32
= ((void*)page
->pd
) - 4;
460 ptr64
= (void*)page
->pd
;
471 #if defined(__x86_64__)
472 } else if (strcmp(protocol
, XEN_IO_PROTO_ABI_X86_32
) == 0) {
473 /* 64bit dom0, 32bit domU */
475 pd
= ((void*)page
->pd
) - 4;
476 #elif defined(__i386__)
477 } else if (strcmp(protocol
, XEN_IO_PROTO_ABI_X86_64
) == 0) {
478 /* 32bit dom0, 64bit domU */
480 pd
= ((void*)page
->pd
) + 4;
485 munmap(xenfb
->pixels
, xenfb
->fbpages
* XC_PAGE_SIZE
);
486 xenfb
->pixels
= NULL
;
489 xenfb
->fbpages
= (xenfb
->fb_len
+ (XC_PAGE_SIZE
- 1)) / XC_PAGE_SIZE
;
490 n_fbdirs
= xenfb
->fbpages
* mode
/ 8;
491 n_fbdirs
= (n_fbdirs
+ (XC_PAGE_SIZE
- 1)) / XC_PAGE_SIZE
;
493 pgmfns
= g_malloc0(sizeof(xen_pfn_t
) * n_fbdirs
);
494 fbmfns
= g_malloc0(sizeof(xen_pfn_t
) * xenfb
->fbpages
);
496 xenfb_copy_mfns(mode
, n_fbdirs
, pgmfns
, pd
);
497 map
= xc_map_foreign_pages(xen_xc
, xenfb
->c
.xendev
.dom
,
498 PROT_READ
, pgmfns
, n_fbdirs
);
501 xenfb_copy_mfns(mode
, xenfb
->fbpages
, fbmfns
, map
);
502 munmap(map
, n_fbdirs
* XC_PAGE_SIZE
);
504 xenfb
->pixels
= xc_map_foreign_pages(xen_xc
, xenfb
->c
.xendev
.dom
,
505 PROT_READ
, fbmfns
, xenfb
->fbpages
);
506 if (xenfb
->pixels
== NULL
)
509 ret
= 0; /* all is fine */
517 static int xenfb_configure_fb(struct XenFB
*xenfb
, size_t fb_len_lim
,
518 int width
, int height
, int depth
,
519 size_t fb_len
, int offset
, int row_stride
)
521 size_t mfn_sz
= sizeof(*((struct xenfb_page
*)0)->pd
);
522 size_t pd_len
= sizeof(((struct xenfb_page
*)0)->pd
) / mfn_sz
;
523 size_t fb_pages
= pd_len
* XC_PAGE_SIZE
/ mfn_sz
;
524 size_t fb_len_max
= fb_pages
* XC_PAGE_SIZE
;
525 int max_width
, max_height
;
527 if (fb_len_lim
> fb_len_max
) {
528 xen_be_printf(&xenfb
->c
.xendev
, 0, "fb size limit %zu exceeds %zu, corrected\n",
529 fb_len_lim
, fb_len_max
);
530 fb_len_lim
= fb_len_max
;
532 if (fb_len_lim
&& fb_len
> fb_len_lim
) {
533 xen_be_printf(&xenfb
->c
.xendev
, 0, "frontend fb size %zu limited to %zu\n",
537 if (depth
!= 8 && depth
!= 16 && depth
!= 24 && depth
!= 32) {
538 xen_be_printf(&xenfb
->c
.xendev
, 0, "can't handle frontend fb depth %d\n",
542 if (row_stride
<= 0 || row_stride
> fb_len
) {
543 xen_be_printf(&xenfb
->c
.xendev
, 0, "invalid frontend stride %d\n", row_stride
);
546 max_width
= row_stride
/ (depth
/ 8);
547 if (width
< 0 || width
> max_width
) {
548 xen_be_printf(&xenfb
->c
.xendev
, 0, "invalid frontend width %d limited to %d\n",
552 if (offset
< 0 || offset
>= fb_len
) {
553 xen_be_printf(&xenfb
->c
.xendev
, 0, "invalid frontend offset %d (max %zu)\n",
557 max_height
= (fb_len
- offset
) / row_stride
;
558 if (height
< 0 || height
> max_height
) {
559 xen_be_printf(&xenfb
->c
.xendev
, 0, "invalid frontend height %d limited to %d\n",
563 xenfb
->fb_len
= fb_len
;
564 xenfb
->row_stride
= row_stride
;
565 xenfb
->depth
= depth
;
566 xenfb
->width
= width
;
567 xenfb
->height
= height
;
568 xenfb
->offset
= offset
;
569 xenfb
->up_fullscreen
= 1;
570 xenfb
->do_resize
= 1;
571 xen_be_printf(&xenfb
->c
.xendev
, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
572 width
, height
, depth
, offset
, row_stride
);
576 /* A convenient function for munging pixels between different depths */
577 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
578 for (line = y ; line < (y+h) ; line++) { \
579 SRC_T *src = (SRC_T *)(xenfb->pixels \
581 + (line * xenfb->row_stride) \
582 + (x * xenfb->depth / 8)); \
583 DST_T *dst = (DST_T *)(data \
584 + (line * linesize) \
587 const int RSS = 32 - (RSB + GSB + BSB); \
588 const int GSS = 32 - (GSB + BSB); \
589 const int BSS = 32 - (BSB); \
590 const uint32_t RSM = (~0U) << (32 - RSB); \
591 const uint32_t GSM = (~0U) << (32 - GSB); \
592 const uint32_t BSM = (~0U) << (32 - BSB); \
593 const int RDS = 32 - (RDB + GDB + BDB); \
594 const int GDS = 32 - (GDB + BDB); \
595 const int BDS = 32 - (BDB); \
596 const uint32_t RDM = (~0U) << (32 - RDB); \
597 const uint32_t GDM = (~0U) << (32 - GDB); \
598 const uint32_t BDM = (~0U) << (32 - BDB); \
599 for (col = x ; col < (x+w) ; col++) { \
600 uint32_t spix = *src; \
601 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
602 (((spix << GSS) & GSM & GDM) >> GDS) | \
603 (((spix << BSS) & BSM & BDM) >> BDS); \
604 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
605 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
611 * This copies data from the guest framebuffer region, into QEMU's
612 * displaysurface. qemu uses 16 or 32 bpp. In case the pv framebuffer
613 * uses something else we must convert and copy, otherwise we can
614 * supply the buffer directly and no thing here.
616 static void xenfb_guest_copy(struct XenFB
*xenfb
, int x
, int y
, int w
, int h
)
618 DisplaySurface
*surface
= qemu_console_surface(xenfb
->c
.con
);
620 int bpp
= surface_bits_per_pixel(surface
);
621 int linesize
= surface_stride(surface
);
622 uint8_t *data
= surface_data(surface
);
624 if (!is_buffer_shared(surface
)) {
625 switch (xenfb
->depth
) {
628 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
629 } else if (bpp
== 32) {
630 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
637 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
638 } else if (bpp
== 32) {
639 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
648 if (oops
) /* should not happen */
649 xen_be_printf(&xenfb
->c
.xendev
, 0, "%s: oops: convert %d -> %d bpp?\n",
650 __FUNCTION__
, xenfb
->depth
, bpp
);
652 dpy_gfx_update(xenfb
->c
.con
, x
, y
, w
, h
);
655 #ifdef XENFB_TYPE_REFRESH_PERIOD
656 static int xenfb_queue_full(struct XenFB
*xenfb
)
658 struct xenfb_page
*page
= xenfb
->c
.page
;
664 prod
= page
->in_prod
;
665 cons
= page
->in_cons
;
666 return prod
- cons
== XENFB_IN_RING_LEN
;
669 static void xenfb_send_event(struct XenFB
*xenfb
, union xenfb_in_event
*event
)
672 struct xenfb_page
*page
= xenfb
->c
.page
;
674 prod
= page
->in_prod
;
675 /* caller ensures !xenfb_queue_full() */
676 xen_mb(); /* ensure ring space available */
677 XENFB_IN_RING_REF(page
, prod
) = *event
;
678 xen_wmb(); /* ensure ring contents visible */
679 page
->in_prod
= prod
+ 1;
681 xen_be_send_notify(&xenfb
->c
.xendev
);
684 static void xenfb_send_refresh_period(struct XenFB
*xenfb
, int period
)
686 union xenfb_in_event event
;
688 memset(&event
, 0, sizeof(event
));
689 event
.type
= XENFB_TYPE_REFRESH_PERIOD
;
690 event
.refresh_period
.period
= period
;
691 xenfb_send_event(xenfb
, &event
);
696 * Periodic update of display.
697 * Also transmit the refresh interval to the frontend.
699 * Never ever do any qemu display operations
700 * (resize, screen update) outside this function.
701 * Our screen might be inactive. When asked for
702 * an update we know it is active.
704 static void xenfb_update(void *opaque
)
706 struct XenFB
*xenfb
= opaque
;
707 DisplaySurface
*surface
;
710 if (xenfb
->c
.xendev
.be_state
!= XenbusStateConnected
)
713 if (!xenfb
->feature_update
) {
714 /* we don't get update notifications, thus use the
715 * sledge hammer approach ... */
716 xenfb
->up_fullscreen
= 1;
719 /* resize if needed */
720 if (xenfb
->do_resize
) {
721 pixman_format_code_t format
;
723 xenfb
->do_resize
= 0;
724 switch (xenfb
->depth
) {
727 /* console.c supported depth -> buffer can be used directly */
728 format
= qemu_default_pixman_format(xenfb
->depth
, true);
729 surface
= qemu_create_displaysurface_from
730 (xenfb
->width
, xenfb
->height
, format
,
731 xenfb
->row_stride
, xenfb
->pixels
+ xenfb
->offset
);
734 /* we must convert stuff */
735 surface
= qemu_create_displaysurface(xenfb
->width
, xenfb
->height
);
738 dpy_gfx_replace_surface(xenfb
->c
.con
, surface
);
739 xen_be_printf(&xenfb
->c
.xendev
, 1, "update: resizing: %dx%d @ %d bpp%s\n",
740 xenfb
->width
, xenfb
->height
, xenfb
->depth
,
741 is_buffer_shared(surface
) ? " (shared)" : "");
742 xenfb
->up_fullscreen
= 1;
745 /* run queued updates */
746 if (xenfb
->up_fullscreen
) {
747 xen_be_printf(&xenfb
->c
.xendev
, 3, "update: fullscreen\n");
748 xenfb_guest_copy(xenfb
, 0, 0, xenfb
->width
, xenfb
->height
);
749 } else if (xenfb
->up_count
) {
750 xen_be_printf(&xenfb
->c
.xendev
, 3, "update: %d rects\n", xenfb
->up_count
);
751 for (i
= 0; i
< xenfb
->up_count
; i
++)
752 xenfb_guest_copy(xenfb
,
753 xenfb
->up_rects
[i
].x
,
754 xenfb
->up_rects
[i
].y
,
755 xenfb
->up_rects
[i
].w
,
756 xenfb
->up_rects
[i
].h
);
758 xen_be_printf(&xenfb
->c
.xendev
, 3, "update: nothing\n");
761 xenfb
->up_fullscreen
= 0;
764 static void xenfb_update_interval(void *opaque
, uint64_t interval
)
766 struct XenFB
*xenfb
= opaque
;
768 if (xenfb
->feature_update
) {
769 #ifdef XENFB_TYPE_REFRESH_PERIOD
770 if (xenfb_queue_full(xenfb
)) {
773 xenfb_send_refresh_period(xenfb
, interval
);
778 /* QEMU display state changed, so refresh the framebuffer copy */
779 static void xenfb_invalidate(void *opaque
)
781 struct XenFB
*xenfb
= opaque
;
782 xenfb
->up_fullscreen
= 1;
785 static void xenfb_handle_events(struct XenFB
*xenfb
)
787 uint32_t prod
, cons
, out_cons
;
788 struct xenfb_page
*page
= xenfb
->c
.page
;
790 prod
= page
->out_prod
;
791 out_cons
= page
->out_cons
;
792 if (prod
== out_cons
)
794 xen_rmb(); /* ensure we see ring contents up to prod */
795 for (cons
= out_cons
; cons
!= prod
; cons
++) {
796 union xenfb_out_event
*event
= &XENFB_OUT_RING_REF(page
, cons
);
797 uint8_t type
= event
->type
;
801 case XENFB_TYPE_UPDATE
:
802 if (xenfb
->up_count
== UP_QUEUE
)
803 xenfb
->up_fullscreen
= 1;
804 if (xenfb
->up_fullscreen
)
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");
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;
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
;
832 #ifdef XENFB_TYPE_RESIZE
833 case XENFB_TYPE_RESIZE
:
834 if (xenfb_configure_fb(xenfb
, xenfb
->fb_len
,
836 event
->resize
.height
,
839 event
->resize
.offset
,
840 event
->resize
.stride
) < 0)
842 xenfb_invalidate(xenfb
);
847 xen_mb(); /* ensure we're done with ring contents */
848 page
->out_cons
= cons
;
851 static int fb_init(struct XenDevice
*xendev
)
853 #ifdef XENFB_TYPE_RESIZE
854 xenstore_write_be_int(xendev
, "feature-resize", 1);
859 static int fb_initialise(struct XenDevice
*xendev
)
861 struct XenFB
*fb
= container_of(xendev
, struct XenFB
, c
.xendev
);
862 struct xenfb_page
*fb_page
;
866 if (xenstore_read_fe_int(xendev
, "videoram", &videoram
) == -1)
869 rc
= common_bind(&fb
->c
);
873 fb_page
= fb
->c
.page
;
874 rc
= xenfb_configure_fb(fb
, videoram
* 1024 * 1024U,
875 fb_page
->width
, fb_page
->height
, fb_page
->depth
,
876 fb_page
->mem_length
, 0, fb_page
->line_length
);
880 rc
= xenfb_map_fb(fb
);
884 #if 0 /* handled in xen_init_display() for now */
885 if (!fb
->have_console
) {
886 fb
->c
.ds
= graphic_console_init(xenfb_update
,
891 fb
->have_console
= 1;
895 if (xenstore_read_fe_int(xendev
, "feature-update", &fb
->feature_update
) == -1)
896 fb
->feature_update
= 0;
897 if (fb
->feature_update
)
898 xenstore_write_be_int(xendev
, "request-update", 1);
900 xen_be_printf(xendev
, 1, "feature-update=%d, videoram=%d\n",
901 fb
->feature_update
, videoram
);
905 static void fb_disconnect(struct XenDevice
*xendev
)
907 struct XenFB
*fb
= container_of(xendev
, struct XenFB
, c
.xendev
);
910 * FIXME: qemu can't un-init gfx display (yet?).
911 * Replacing the framebuffer with anonymous shared memory
912 * instead. This releases the guest pages and keeps qemu happy.
914 fb
->pixels
= mmap(fb
->pixels
, fb
->fbpages
* XC_PAGE_SIZE
,
915 PROT_READ
| PROT_WRITE
, MAP_SHARED
| MAP_ANON
,
917 if (fb
->pixels
== MAP_FAILED
) {
918 xen_be_printf(xendev
, 0,
919 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
922 common_unbind(&fb
->c
);
923 fb
->feature_update
= 0;
927 static void fb_frontend_changed(struct XenDevice
*xendev
, const char *node
)
929 struct XenFB
*fb
= container_of(xendev
, struct XenFB
, c
.xendev
);
932 * Set state to Connected *again* once the frontend switched
933 * to connected. We must trigger the watch a second time to
934 * workaround a frontend bug.
936 if (fb
->bug_trigger
== 0 && strcmp(node
, "state") == 0 &&
937 xendev
->fe_state
== XenbusStateConnected
&&
938 xendev
->be_state
== XenbusStateConnected
) {
939 xen_be_printf(xendev
, 2, "re-trigger connected (frontend bug)\n");
940 xen_be_set_state(xendev
, XenbusStateConnected
);
941 fb
->bug_trigger
= 1; /* only once */
945 static void fb_event(struct XenDevice
*xendev
)
947 struct XenFB
*xenfb
= container_of(xendev
, struct XenFB
, c
.xendev
);
949 xenfb_handle_events(xenfb
);
950 xen_be_send_notify(&xenfb
->c
.xendev
);
953 /* -------------------------------------------------------------------- */
955 struct XenDevOps xen_kbdmouse_ops
= {
956 .size
= sizeof(struct XenInput
),
958 .initialise
= input_initialise
,
959 .connected
= input_connected
,
960 .disconnect
= input_disconnect
,
961 .event
= input_event
,
964 struct XenDevOps xen_framebuffer_ops
= {
965 .size
= sizeof(struct XenFB
),
967 .initialise
= fb_initialise
,
968 .disconnect
= fb_disconnect
,
970 .frontend_changed
= fb_frontend_changed
,
973 static const GraphicHwOps xenfb_ops
= {
974 .invalidate
= xenfb_invalidate
,
975 .gfx_update
= xenfb_update
,
976 .update_interval
= xenfb_update_interval
,
980 * FIXME/TODO: Kill this.
981 * Temporary needed while DisplayState reorganization is in flight.
983 void xen_init_display(int domid
)
985 struct XenDevice
*xfb
, *xin
;
992 main_loop_wait(true);
993 xfb
= xen_be_find_xendev("vfb", domid
, 0);
994 xin
= xen_be_find_xendev("vkbd", domid
, 0);
1000 xen_be_printf(NULL
, 1, "displaystate setup failed\n");
1005 fb
= container_of(xfb
, struct XenFB
, c
.xendev
);
1006 fb
->c
.con
= graphic_console_init(NULL
, 0, &xenfb_ops
, fb
);
1007 fb
->have_console
= 1;
1010 in
= container_of(xin
, struct XenInput
, c
.xendev
);
1011 in
->c
.con
= fb
->c
.con
;
1013 /* retry ->init() */
1014 xen_be_check_state(xin
);
1015 xen_be_check_state(xfb
);