1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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>
37
38#include "hw/hw.h"
39#include "ui/console.h"
40#include "sysemu/char.h"
41#include "hw/xen/xen_backend.h"
42
43#include <xen/event_channel.h>
44#include <xen/io/fbif.h>
45#include <xen/io/kbdif.h>
46#include <xen/io/protocols.h>
47
48#ifndef BTN_LEFT
49#define BTN_LEFT 0x110
50#endif
51
52
53
54struct common {
55 struct XenDevice xendev;
56 void *page;
57 QemuConsole *con;
58};
59
60struct XenInput {
61 struct common c;
62 int abs_pointer_wanted;
63 int button_state;
64 int extended;
65 QEMUPutMouseEntry *qmouse;
66};
67
68#define UP_QUEUE 8
69
70struct XenFB {
71 struct common c;
72 size_t fb_len;
73 int row_stride;
74 int depth;
75 int width;
76 int height;
77 int offset;
78 void *pixels;
79 int fbpages;
80 int feature_update;
81 int bug_trigger;
82 int have_console;
83 int do_resize;
84
85 struct {
86 int x,y,w,h;
87 } up_rects[UP_QUEUE];
88 int up_count;
89 int up_fullscreen;
90};
91
92
93
94static int common_bind(struct common *c)
95{
96 uint64_t mfn;
97
98 if (xenstore_read_fe_uint64(&c->xendev, "page-ref", &mfn) == -1)
99 return -1;
100 assert(mfn == (xen_pfn_t)mfn);
101
102 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
103 return -1;
104
105 c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
106 XC_PAGE_SIZE,
107 PROT_READ | PROT_WRITE, mfn);
108 if (c->page == NULL)
109 return -1;
110
111 xen_be_bind_evtchn(&c->xendev);
112 xen_be_printf(&c->xendev, 1, "ring mfn %"PRIx64", remote-port %d, local-port %d\n",
113 mfn, c->xendev.remote_port, c->xendev.local_port);
114
115 return 0;
116}
117
118static void common_unbind(struct common *c)
119{
120 xen_be_unbind_evtchn(&c->xendev);
121 if (c->page) {
122 munmap(c->page, XC_PAGE_SIZE);
123 c->page = NULL;
124 }
125}
126
127
128
129#if 0
130
131
132
133
134
135
136
137
138
139const unsigned char atkbd_set2_keycode[512] = {
140
141 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
142 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
143 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
144 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
145 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
146 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
147 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
148 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
149
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
152 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
153 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
154 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
155 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
156 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
157 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
158
159};
160
161const unsigned char atkbd_unxlate_table[128] = {
162
163 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
164 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
165 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
166 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
167 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
168 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
169 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
170 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
171
172};
173#endif
174
175
176
177
178
179
180
181static const unsigned char scancode2linux[512] = {
182 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
183 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
184 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
185 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
186 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
187 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
188 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
189 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
190
191 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
193 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
194 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
195 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
196 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
197 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199};
200
201
202static int xenfb_kbd_event(struct XenInput *xenfb,
203 union xenkbd_in_event *event)
204{
205 struct xenkbd_page *page = xenfb->c.page;
206 uint32_t prod;
207
208 if (xenfb->c.xendev.be_state != XenbusStateConnected)
209 return 0;
210 if (!page)
211 return 0;
212
213 prod = page->in_prod;
214 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
215 errno = EAGAIN;
216 return -1;
217 }
218
219 xen_mb();
220 XENKBD_IN_RING_REF(page, prod) = *event;
221 xen_wmb();
222 page->in_prod = prod + 1;
223 return xen_be_send_notify(&xenfb->c.xendev);
224}
225
226
227static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
228{
229 union xenkbd_in_event event;
230
231 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
232 event.type = XENKBD_TYPE_KEY;
233 event.key.pressed = down ? 1 : 0;
234 event.key.keycode = keycode;
235
236 return xenfb_kbd_event(xenfb, &event);
237}
238
239
240static int xenfb_send_motion(struct XenInput *xenfb,
241 int rel_x, int rel_y, int rel_z)
242{
243 union xenkbd_in_event event;
244
245 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
246 event.type = XENKBD_TYPE_MOTION;
247 event.motion.rel_x = rel_x;
248 event.motion.rel_y = rel_y;
249#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
250 event.motion.rel_z = rel_z;
251#endif
252
253 return xenfb_kbd_event(xenfb, &event);
254}
255
256
257static int xenfb_send_position(struct XenInput *xenfb,
258 int abs_x, int abs_y, int z)
259{
260 union xenkbd_in_event event;
261
262 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
263 event.type = XENKBD_TYPE_POS;
264 event.pos.abs_x = abs_x;
265 event.pos.abs_y = abs_y;
266#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
267 event.pos.abs_z = z;
268#endif
269#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
270 event.pos.rel_z = z;
271#endif
272
273 return xenfb_kbd_event(xenfb, &event);
274}
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290static void xenfb_key_event(void *opaque, int scancode)
291{
292 struct XenInput *xenfb = opaque;
293 int down = 1;
294
295 if (scancode == 0xe0) {
296 xenfb->extended = 1;
297 return;
298 } else if (scancode & 0x80) {
299 scancode &= 0x7f;
300 down = 0;
301 }
302 if (xenfb->extended) {
303 scancode |= 0x80;
304 xenfb->extended = 0;
305 }
306 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
307}
308
309
310
311
312
313
314
315
316
317
318static void xenfb_mouse_event(void *opaque,
319 int dx, int dy, int dz, int button_state)
320{
321 struct XenInput *xenfb = opaque;
322 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
323 int dw = surface_width(surface);
324 int dh = surface_height(surface);
325 int i;
326
327 if (xenfb->abs_pointer_wanted)
328 xenfb_send_position(xenfb,
329 dx * (dw - 1) / 0x7fff,
330 dy * (dh - 1) / 0x7fff,
331 dz);
332 else
333 xenfb_send_motion(xenfb, dx, dy, dz);
334
335 for (i = 0 ; i < 8 ; i++) {
336 int lastDown = xenfb->button_state & (1 << i);
337 int down = button_state & (1 << i);
338 if (down == lastDown)
339 continue;
340
341 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
342 return;
343 }
344 xenfb->button_state = button_state;
345}
346
347static int input_init(struct XenDevice *xendev)
348{
349 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
350 return 0;
351}
352
353static int input_initialise(struct XenDevice *xendev)
354{
355 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
356 int rc;
357
358 if (!in->c.con) {
359 xen_be_printf(xendev, 1, "ds not set (yet)\n");
360 return -1;
361 }
362
363 rc = common_bind(&in->c);
364 if (rc != 0)
365 return rc;
366
367 qemu_add_kbd_event_handler(xenfb_key_event, in);
368 return 0;
369}
370
371static void input_connected(struct XenDevice *xendev)
372{
373 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
374
375 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
376 &in->abs_pointer_wanted) == -1) {
377 in->abs_pointer_wanted = 0;
378 }
379
380 if (in->qmouse) {
381 qemu_remove_mouse_event_handler(in->qmouse);
382 }
383 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
384 in->abs_pointer_wanted,
385 "Xen PVFB Mouse");
386}
387
388static void input_disconnect(struct XenDevice *xendev)
389{
390 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
391
392 if (in->qmouse) {
393 qemu_remove_mouse_event_handler(in->qmouse);
394 in->qmouse = NULL;
395 }
396 qemu_add_kbd_event_handler(NULL, NULL);
397 common_unbind(&in->c);
398}
399
400static void input_event(struct XenDevice *xendev)
401{
402 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
403 struct xenkbd_page *page = xenfb->c.page;
404
405
406 if (page->out_prod == page->out_cons)
407 return;
408 page->out_cons = page->out_prod;
409 xen_be_send_notify(&xenfb->c.xendev);
410}
411
412
413
414static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
415{
416 uint32_t *src32 = src;
417 uint64_t *src64 = src;
418 int i;
419
420 for (i = 0; i < count; i++)
421 dst[i] = (mode == 32) ? src32[i] : src64[i];
422}
423
424static int xenfb_map_fb(struct XenFB *xenfb)
425{
426 struct xenfb_page *page = xenfb->c.page;
427 char *protocol = xenfb->c.xendev.protocol;
428 int n_fbdirs;
429 xen_pfn_t *pgmfns = NULL;
430 xen_pfn_t *fbmfns = NULL;
431 void *map, *pd;
432 int mode, ret = -1;
433
434
435 pd = page->pd;
436 mode = sizeof(unsigned long) * 8;
437
438 if (!protocol) {
439
440
441
442
443
444
445
446
447
448 uint32_t *ptr32 = NULL;
449 uint32_t *ptr64 = NULL;
450#if defined(__i386__)
451 ptr32 = (void*)page->pd;
452 ptr64 = ((void*)page->pd) + 4;
453#elif defined(__x86_64__)
454 ptr32 = ((void*)page->pd) - 4;
455 ptr64 = (void*)page->pd;
456#endif
457 if (ptr32) {
458 if (ptr32[1] == 0) {
459 mode = 32;
460 pd = ptr32;
461 } else {
462 mode = 64;
463 pd = ptr64;
464 }
465 }
466#if defined(__x86_64__)
467 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
468
469 mode = 32;
470 pd = ((void*)page->pd) - 4;
471#elif defined(__i386__)
472 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
473
474 mode = 64;
475 pd = ((void*)page->pd) + 4;
476#endif
477 }
478
479 if (xenfb->pixels) {
480 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
481 xenfb->pixels = NULL;
482 }
483
484 xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
485 n_fbdirs = xenfb->fbpages * mode / 8;
486 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
487
488 pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
489 fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
490
491 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
492 map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
493 PROT_READ, pgmfns, n_fbdirs);
494 if (map == NULL)
495 goto out;
496 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
497 munmap(map, n_fbdirs * XC_PAGE_SIZE);
498
499 xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
500 PROT_READ, fbmfns, xenfb->fbpages);
501 if (xenfb->pixels == NULL)
502 goto out;
503
504 ret = 0;
505
506out:
507 g_free(pgmfns);
508 g_free(fbmfns);
509 return ret;
510}
511
512static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
513 int width, int height, int depth,
514 size_t fb_len, int offset, int row_stride)
515{
516 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
517 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
518 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
519 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
520 int max_width, max_height;
521
522 if (fb_len_lim > fb_len_max) {
523 xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
524 fb_len_lim, fb_len_max);
525 fb_len_lim = fb_len_max;
526 }
527 if (fb_len_lim && fb_len > fb_len_lim) {
528 xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
529 fb_len, fb_len_lim);
530 fb_len = fb_len_lim;
531 }
532 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
533 xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
534 depth);
535 return -1;
536 }
537 if (row_stride <= 0 || row_stride > fb_len) {
538 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
539 return -1;
540 }
541 max_width = row_stride / (depth / 8);
542 if (width < 0 || width > max_width) {
543 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
544 width, max_width);
545 width = max_width;
546 }
547 if (offset < 0 || offset >= fb_len) {
548 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
549 offset, fb_len - 1);
550 return -1;
551 }
552 max_height = (fb_len - offset) / row_stride;
553 if (height < 0 || height > max_height) {
554 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
555 height, max_height);
556 height = max_height;
557 }
558 xenfb->fb_len = fb_len;
559 xenfb->row_stride = row_stride;
560 xenfb->depth = depth;
561 xenfb->width = width;
562 xenfb->height = height;
563 xenfb->offset = offset;
564 xenfb->up_fullscreen = 1;
565 xenfb->do_resize = 1;
566 xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
567 width, height, depth, offset, row_stride);
568 return 0;
569}
570
571
572#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
573 for (line = y ; line < (y+h) ; line++) { \
574 SRC_T *src = (SRC_T *)(xenfb->pixels \
575 + xenfb->offset \
576 + (line * xenfb->row_stride) \
577 + (x * xenfb->depth / 8)); \
578 DST_T *dst = (DST_T *)(data \
579 + (line * linesize) \
580 + (x * bpp / 8)); \
581 int col; \
582 const int RSS = 32 - (RSB + GSB + BSB); \
583 const int GSS = 32 - (GSB + BSB); \
584 const int BSS = 32 - (BSB); \
585 const uint32_t RSM = (~0U) << (32 - RSB); \
586 const uint32_t GSM = (~0U) << (32 - GSB); \
587 const uint32_t BSM = (~0U) << (32 - BSB); \
588 const int RDS = 32 - (RDB + GDB + BDB); \
589 const int GDS = 32 - (GDB + BDB); \
590 const int BDS = 32 - (BDB); \
591 const uint32_t RDM = (~0U) << (32 - RDB); \
592 const uint32_t GDM = (~0U) << (32 - GDB); \
593 const uint32_t BDM = (~0U) << (32 - BDB); \
594 for (col = x ; col < (x+w) ; col++) { \
595 uint32_t spix = *src; \
596 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
597 (((spix << GSS) & GSM & GDM) >> GDS) | \
598 (((spix << BSS) & BSM & BDM) >> BDS); \
599 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
600 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
601 } \
602 }
603
604
605
606
607
608
609
610
611static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
612{
613 DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
614 int line, oops = 0;
615 int bpp = surface_bits_per_pixel(surface);
616 int linesize = surface_stride(surface);
617 uint8_t *data = surface_data(surface);
618
619 if (!is_buffer_shared(surface)) {
620 switch (xenfb->depth) {
621 case 8:
622 if (bpp == 16) {
623 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
624 } else if (bpp == 32) {
625 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
626 } else {
627 oops = 1;
628 }
629 break;
630 case 24:
631 if (bpp == 16) {
632 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
633 } else if (bpp == 32) {
634 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
635 } else {
636 oops = 1;
637 }
638 break;
639 default:
640 oops = 1;
641 }
642 }
643 if (oops)
644 xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
645 __FUNCTION__, xenfb->depth, bpp);
646
647 dpy_gfx_update(xenfb->c.con, x, y, w, h);
648}
649
650#ifdef XENFB_TYPE_REFRESH_PERIOD
651static int xenfb_queue_full(struct XenFB *xenfb)
652{
653 struct xenfb_page *page = xenfb->c.page;
654 uint32_t cons, prod;
655
656 if (!page)
657 return 1;
658
659 prod = page->in_prod;
660 cons = page->in_cons;
661 return prod - cons == XENFB_IN_RING_LEN;
662}
663
664static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
665{
666 uint32_t prod;
667 struct xenfb_page *page = xenfb->c.page;
668
669 prod = page->in_prod;
670
671 xen_mb();
672 XENFB_IN_RING_REF(page, prod) = *event;
673 xen_wmb();
674 page->in_prod = prod + 1;
675
676 xen_be_send_notify(&xenfb->c.xendev);
677}
678
679static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
680{
681 union xenfb_in_event event;
682
683 memset(&event, 0, sizeof(event));
684 event.type = XENFB_TYPE_REFRESH_PERIOD;
685 event.refresh_period.period = period;
686 xenfb_send_event(xenfb, &event);
687}
688#endif
689
690
691
692
693
694
695
696
697
698
699static void xenfb_update(void *opaque)
700{
701 struct XenFB *xenfb = opaque;
702 DisplaySurface *surface;
703 int i;
704
705 if (xenfb->c.xendev.be_state != XenbusStateConnected)
706 return;
707
708 if (!xenfb->feature_update) {
709
710
711 xenfb->up_fullscreen = 1;
712 }
713
714
715 if (xenfb->do_resize) {
716 pixman_format_code_t format;
717
718 xenfb->do_resize = 0;
719 switch (xenfb->depth) {
720 case 16:
721 case 32:
722
723 format = qemu_default_pixman_format(xenfb->depth, true);
724 surface = qemu_create_displaysurface_from
725 (xenfb->width, xenfb->height, format,
726 xenfb->row_stride, xenfb->pixels + xenfb->offset);
727 break;
728 default:
729
730 surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
731 break;
732 }
733 dpy_gfx_replace_surface(xenfb->c.con, surface);
734 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
735 xenfb->width, xenfb->height, xenfb->depth,
736 is_buffer_shared(surface) ? " (shared)" : "");
737 xenfb->up_fullscreen = 1;
738 }
739
740
741 if (xenfb->up_fullscreen) {
742 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
743 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
744 } else if (xenfb->up_count) {
745 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
746 for (i = 0; i < xenfb->up_count; i++)
747 xenfb_guest_copy(xenfb,
748 xenfb->up_rects[i].x,
749 xenfb->up_rects[i].y,
750 xenfb->up_rects[i].w,
751 xenfb->up_rects[i].h);
752 } else {
753 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
754 }
755 xenfb->up_count = 0;
756 xenfb->up_fullscreen = 0;
757}
758
759static void xenfb_update_interval(void *opaque, uint64_t interval)
760{
761 struct XenFB *xenfb = opaque;
762
763 if (xenfb->feature_update) {
764#ifdef XENFB_TYPE_REFRESH_PERIOD
765 if (xenfb_queue_full(xenfb)) {
766 return;
767 }
768 xenfb_send_refresh_period(xenfb, interval);
769#endif
770 }
771}
772
773
774static void xenfb_invalidate(void *opaque)
775{
776 struct XenFB *xenfb = opaque;
777 xenfb->up_fullscreen = 1;
778}
779
780static void xenfb_handle_events(struct XenFB *xenfb)
781{
782 uint32_t prod, cons;
783 struct xenfb_page *page = xenfb->c.page;
784
785 prod = page->out_prod;
786 if (prod == page->out_cons)
787 return;
788 xen_rmb();
789 for (cons = page->out_cons; cons != prod; cons++) {
790 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
791 int x, y, w, h;
792
793 switch (event->type) {
794 case XENFB_TYPE_UPDATE:
795 if (xenfb->up_count == UP_QUEUE)
796 xenfb->up_fullscreen = 1;
797 if (xenfb->up_fullscreen)
798 break;
799 x = MAX(event->update.x, 0);
800 y = MAX(event->update.y, 0);
801 w = MIN(event->update.width, xenfb->width - x);
802 h = MIN(event->update.height, xenfb->height - y);
803 if (w < 0 || h < 0) {
804 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
805 break;
806 }
807 if (x != event->update.x ||
808 y != event->update.y ||
809 w != event->update.width ||
810 h != event->update.height) {
811 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
812 }
813 if (w == xenfb->width && h > xenfb->height / 2) {
814
815
816 xenfb->up_fullscreen = 1;
817 } else {
818 xenfb->up_rects[xenfb->up_count].x = x;
819 xenfb->up_rects[xenfb->up_count].y = y;
820 xenfb->up_rects[xenfb->up_count].w = w;
821 xenfb->up_rects[xenfb->up_count].h = h;
822 xenfb->up_count++;
823 }
824 break;
825#ifdef XENFB_TYPE_RESIZE
826 case XENFB_TYPE_RESIZE:
827 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
828 event->resize.width,
829 event->resize.height,
830 event->resize.depth,
831 xenfb->fb_len,
832 event->resize.offset,
833 event->resize.stride) < 0)
834 break;
835 xenfb_invalidate(xenfb);
836 break;
837#endif
838 }
839 }
840 xen_mb();
841 page->out_cons = cons;
842}
843
844static int fb_init(struct XenDevice *xendev)
845{
846#ifdef XENFB_TYPE_RESIZE
847 xenstore_write_be_int(xendev, "feature-resize", 1);
848#endif
849 return 0;
850}
851
852static int fb_initialise(struct XenDevice *xendev)
853{
854 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
855 struct xenfb_page *fb_page;
856 int videoram;
857 int rc;
858
859 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
860 videoram = 0;
861
862 rc = common_bind(&fb->c);
863 if (rc != 0)
864 return rc;
865
866 fb_page = fb->c.page;
867 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
868 fb_page->width, fb_page->height, fb_page->depth,
869 fb_page->mem_length, 0, fb_page->line_length);
870 if (rc != 0)
871 return rc;
872
873 rc = xenfb_map_fb(fb);
874 if (rc != 0)
875 return rc;
876
877#if 0
878 if (!fb->have_console) {
879 fb->c.ds = graphic_console_init(xenfb_update,
880 xenfb_invalidate,
881 NULL,
882 NULL,
883 fb);
884 fb->have_console = 1;
885 }
886#endif
887
888 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
889 fb->feature_update = 0;
890 if (fb->feature_update)
891 xenstore_write_be_int(xendev, "request-update", 1);
892
893 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
894 fb->feature_update, videoram);
895 return 0;
896}
897
898static void fb_disconnect(struct XenDevice *xendev)
899{
900 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
901
902
903
904
905
906
907 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
908 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
909 -1, 0);
910 if (fb->pixels == MAP_FAILED) {
911 xen_be_printf(xendev, 0,
912 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
913 errno);
914 }
915 common_unbind(&fb->c);
916 fb->feature_update = 0;
917 fb->bug_trigger = 0;
918}
919
920static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
921{
922 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
923
924
925
926
927
928
929 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
930 xendev->fe_state == XenbusStateConnected &&
931 xendev->be_state == XenbusStateConnected) {
932 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
933 xen_be_set_state(xendev, XenbusStateConnected);
934 fb->bug_trigger = 1;
935 }
936}
937
938static void fb_event(struct XenDevice *xendev)
939{
940 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
941
942 xenfb_handle_events(xenfb);
943 xen_be_send_notify(&xenfb->c.xendev);
944}
945
946
947
948struct XenDevOps xen_kbdmouse_ops = {
949 .size = sizeof(struct XenInput),
950 .init = input_init,
951 .initialise = input_initialise,
952 .connected = input_connected,
953 .disconnect = input_disconnect,
954 .event = input_event,
955};
956
957struct XenDevOps xen_framebuffer_ops = {
958 .size = sizeof(struct XenFB),
959 .init = fb_init,
960 .initialise = fb_initialise,
961 .disconnect = fb_disconnect,
962 .event = fb_event,
963 .frontend_changed = fb_frontend_changed,
964};
965
966static const GraphicHwOps xenfb_ops = {
967 .invalidate = xenfb_invalidate,
968 .gfx_update = xenfb_update,
969 .update_interval = xenfb_update_interval,
970};
971
972
973
974
975
976void xen_init_display(int domid)
977{
978 struct XenDevice *xfb, *xin;
979 struct XenFB *fb;
980 struct XenInput *in;
981 int i = 0;
982
983wait_more:
984 i++;
985 main_loop_wait(true);
986 xfb = xen_be_find_xendev("vfb", domid, 0);
987 xin = xen_be_find_xendev("vkbd", domid, 0);
988 if (!xfb || !xin) {
989 if (i < 256) {
990 usleep(10000);
991 goto wait_more;
992 }
993 xen_be_printf(NULL, 1, "displaystate setup failed\n");
994 return;
995 }
996
997
998 fb = container_of(xfb, struct XenFB, c.xendev);
999 fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
1000 fb->have_console = 1;
1001
1002
1003 in = container_of(xin, struct XenInput, c.xendev);
1004 in->c.con = fb->c.con;
1005
1006
1007 xen_be_check_state(xin);
1008 xen_be_check_state(xfb);
1009}
1010