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